From 8eb00720bc915118ba8694bc20558068376f2946 Mon Sep 17 00:00:00 2001 From: Owen Arnold <owen.arnold@stfc.ac.uk> Date: Tue, 1 Sep 2015 09:27:03 +0100 Subject: [PATCH] refs #13517. Use TransposeMD in VSI We transpose any MDHistoWorkspace loaded from memory if needed. --- .../MDAlgorithms/src/TransposeMD.cpp | 3 +- .../MDHWInMemoryLoadingPresenter.h | 10 + .../src/MDHWInMemoryLoadingPresenter.cpp | 349 ++++++++++-------- .../test/MDHWInMemoryLoadingPresenterTest.h | 2 +- .../docs/source/algorithms/Transpose-v1.rst | 4 +- .../docs/source/algorithms/Transpose3D-v1.rst | 2 +- 6 files changed, 222 insertions(+), 148 deletions(-) diff --git a/Code/Mantid/Framework/MDAlgorithms/src/TransposeMD.cpp b/Code/Mantid/Framework/MDAlgorithms/src/TransposeMD.cpp index 3402730f519..ec48630ce7e 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/TransposeMD.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/TransposeMD.cpp @@ -120,6 +120,7 @@ void TransposeMD::exec() { // Make the output workspace in the right shape. auto outWS = MDHistoWorkspace_sptr(new MDHistoWorkspace(targetGeometry)); + outWS->copyExperimentInfos(*inWS); // Configure the coordinate transform. std::vector<coord_t> scaling(nDimsOutput, 1); // No scaling @@ -150,7 +151,7 @@ void TransposeMD::exec() { size_t index = outWS->getLinearIndexAtCoord(&outcoords[0]); outWS->setSignalAt(index, inIterator->getSignal()); - const double error = inIterator->getError(); + const signal_t error = inIterator->getError(); outWS->setErrorSquaredAt(index, error * error); outWS->setNumEventsAt(index, inIterator->getNumEvents()); outWS->setMDMaskAt(index, inIterator->getIsMasked()); diff --git a/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/MDHWInMemoryLoadingPresenter.h b/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/MDHWInMemoryLoadingPresenter.h index 1934847aa17..c56d65686d8 100644 --- a/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/MDHWInMemoryLoadingPresenter.h +++ b/Code/Mantid/Vates/VatesAPI/inc/MantidVatesAPI/MDHWInMemoryLoadingPresenter.h @@ -3,11 +3,15 @@ #include "MantidVatesAPI/MDHWLoadingPresenter.h" #include <boost/scoped_ptr.hpp> +#include <boost/shared_ptr.hpp> #include <vector> class vtkDataSet; namespace Mantid { + namespace API{ + class IMDHistoWorkspace; + } namespace VATES { /** @@ -53,12 +57,18 @@ namespace Mantid virtual int getSpecialCoordinates(); std::vector<int> getExtents(); private: + /// Transpose a workspace to push integrated dimensions to the last + boost::shared_ptr<Mantid::API::IMDHistoWorkspace> transposeWs(boost::shared_ptr<Mantid::API::IMDHistoWorkspace>& histoWs); /// Repository for accessing workspaces. At this level, does not specify how or where from. boost::scoped_ptr<WorkspaceProvider> m_repository; /// The name of the workspace. const std::string m_wsName; + /// The type name of the workspace std::string m_wsTypeName; + /// The workspace special coordinate system int m_specialCoords; + /// Cached visual histogram workspace. Post transpose. Avoids repeating transpose. + boost::shared_ptr<Mantid::API::IMDHistoWorkspace> m_cachedVisualHistoWs; }; } } diff --git a/Code/Mantid/Vates/VatesAPI/src/MDHWInMemoryLoadingPresenter.cpp b/Code/Mantid/Vates/VatesAPI/src/MDHWInMemoryLoadingPresenter.cpp index ca524ac4cf2..f438c62ee1b 100644 --- a/Code/Mantid/Vates/VatesAPI/src/MDHWInMemoryLoadingPresenter.cpp +++ b/Code/Mantid/Vates/VatesAPI/src/MDHWInMemoryLoadingPresenter.cpp @@ -1,4 +1,6 @@ #include "MantidVatesAPI/MDHWInMemoryLoadingPresenter.h" +#include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/IAlgorithm.h" #include "MantidAPI/IMDHistoWorkspace.h" #include "MantidVatesAPI/MDLoadingView.h" #include "MantidVatesAPI/MetaDataExtractorUtils.h" @@ -9,160 +11,219 @@ #include <qwt_double_interval.h> #include <vtkUnstructuredGrid.h> -namespace Mantid -{ - namespace VATES - { +namespace Mantid { +namespace VATES { + +/* +Constructor +@param view : MVP view +@param repository : Object for accessing the workspaces +@param wsName : Name of the workspace to use. +@throw invalid_argument if the workspace name is empty +@throw invalid_argument if the repository is null +@throw invalid_arument if view is null +*/ +MDHWInMemoryLoadingPresenter::MDHWInMemoryLoadingPresenter( + MDLoadingView *view, WorkspaceProvider *repository, std::string wsName) + : MDHWLoadingPresenter(view), m_repository(repository), m_wsName(wsName), + m_wsTypeName(""), m_specialCoords(-1) { + if (m_wsName.empty()) { + throw std::invalid_argument("The workspace name is empty."); + } + if (NULL == repository) { + throw std::invalid_argument("The repository is NULL"); + } + if (NULL == m_view) { + throw std::invalid_argument("View is NULL."); + } +} +/* +Indicates whether this presenter is capable of handling the type of file that is +attempted to be loaded. +@return false if the file cannot be read. +*/ +bool MDHWInMemoryLoadingPresenter::canReadFile() const { + bool bCanReadIt = true; + if (!m_repository->canProvideWorkspace(m_wsName)) { + // The workspace does not exist. + bCanReadIt = false; + } else if (NULL == + boost::dynamic_pointer_cast<Mantid::API::IMDHistoWorkspace>( + m_repository->fetchWorkspace(m_wsName)).get()) { + // The workspace can be found, but is not an IMDHistoWorkspace. + bCanReadIt = false; + } else { + // The workspace is present, and is of the correct type. + bCanReadIt = true; + } + return bCanReadIt; +} + +/** + * @brief MDHWInMemoryLoadingPresenter::transposeWs + * + * vtkDataSets are usually provided in 3D, trying to create these where one of those dimensions + * might be integrated out leads to empty datasets. To avoid this we reorder the dimensions in our workspace + * prior to visualisation by transposing if if needed. + * + * @param histoWs : An input workspace that may integrated dimensions anywhere. + * @return A workspace that can be directly rendered from. Integrated dimensions are always last. + */ +Mantid::API::IMDHistoWorkspace_sptr MDHWInMemoryLoadingPresenter::transposeWs( + Mantid::API::IMDHistoWorkspace_sptr &histoWs) { + using namespace Mantid::API; + + if (!m_cachedVisualHistoWs) { /* - Constructor - @param view : MVP view - @param repository : Object for accessing the workspaces - @param wsName : Name of the workspace to use. - @throw invalid_argument if the workspace name is empty - @throw invalid_argument if the repository is null - @throw invalid_arument if view is null - */ - MDHWInMemoryLoadingPresenter::MDHWInMemoryLoadingPresenter(MDLoadingView* view, WorkspaceProvider* repository, std::string wsName) : MDHWLoadingPresenter(view), - m_repository(repository), m_wsName(wsName), m_wsTypeName(""), m_specialCoords(-1) - { - if(m_wsName.empty()) - { - throw std::invalid_argument("The workspace name is empty."); - } - if(NULL == repository) - { - throw std::invalid_argument("The repository is NULL"); - } - if(NULL == m_view) - { - throw std::invalid_argument("View is NULL."); - } - } - - /* - Indicates whether this presenter is capable of handling the type of file that is attempted to be loaded. - @return false if the file cannot be read. - */ - bool MDHWInMemoryLoadingPresenter::canReadFile() const - { - bool bCanReadIt = true; - if(!m_repository->canProvideWorkspace(m_wsName)) - { - //The workspace does not exist. - bCanReadIt = false; - } - else if(NULL == boost::dynamic_pointer_cast<Mantid::API::IMDHistoWorkspace>(m_repository->fetchWorkspace(m_wsName)).get()) - { - //The workspace can be found, but is not an IMDHistoWorkspace. - bCanReadIt = false; - } - else - { - //The workspace is present, and is of the correct type. - bCanReadIt = true; + Construct dimension indexes list for transpose. We do this by forcing + integrated + dimensions to be the last in the list. All other orderings are kept. + */ + std::vector<int> integratedDims; + std::vector<int> nonIntegratedDims; + for (int i = 0; i < int(histoWs->getNumDims()); ++i) { + auto dim = histoWs->getDimension(i); + if (dim->getIsIntegrated()) { + integratedDims.push_back(i); + } else { + nonIntegratedDims.push_back(i); } - return bCanReadIt; } + std::vector<int> orderedDims; + orderedDims = nonIntegratedDims; + orderedDims.insert(orderedDims.end(), integratedDims.begin(), + integratedDims.end()); /* - Executes the underlying algorithm to create the MVP model. - @param factory : visualisation factory to use. - @param : Handler for GUI updates while algorithm progresses. - @param drawingProgressUpdate : Handler for GUI updates while vtkDataSetFactory::create occurs. - */ - vtkDataSet* MDHWInMemoryLoadingPresenter::execute(vtkDataSetFactory* factory, ProgressAction&, ProgressAction& drawingProgressUpdate) - { - using namespace Mantid::API; - using namespace Mantid::Geometry; - - Workspace_sptr ws = m_repository->fetchWorkspace(m_wsName); - IMDHistoWorkspace_sptr histoWs = boost::dynamic_pointer_cast<Mantid::API::IMDHistoWorkspace>(ws); - - //factory->setRecursionDepth(this->m_view->getRecursionDepth()); - vtkDataSet* visualDataSet = factory->oneStepCreate(histoWs, drawingProgressUpdate);//HACK: progressUpdate should be argument for drawing! - - /*extractMetaData needs to be re-run here because the first execution of this from ::executeLoadMetadata will not have ensured that all dimensions - have proper range extents set. - */ - - // Update the meta data min and max values with the values of the visual data set. This is necessary since we want the full data range of the visual - // data set and not of the actual underlying data set. - double* range = visualDataSet->GetScalarRange(); - if (range) - { - this->m_metadataJsonManager->setMinValue(range[0]); - this->m_metadataJsonManager->setMaxValue(range[1]); - } + If there has been any reordering above, then the dimension indexes will + no longer be sorted. We use that to determine if we can avoid transposing the workspace. + */ + if (!std::is_sorted(orderedDims.begin(), orderedDims.end())) { + IAlgorithm_sptr alg = AlgorithmManager::Instance().create("TransposeMD"); + alg->setChild(true); + alg->initialize(); + alg->setProperty("InputWorkspace", histoWs); + alg->setPropertyValue("OutputWorkspace", "dummy"); + alg->setProperty("Axes", orderedDims); + alg->execute(); + IMDHistoWorkspace_sptr visualHistoWs = + alg->getProperty("OutputWorkspace"); + m_cachedVisualHistoWs = visualHistoWs; + } else { + // No need to transpose anything. + m_cachedVisualHistoWs = histoWs; + } + } + return m_cachedVisualHistoWs; +} - this->extractMetadata(histoWs); +/* +Executes the underlying algorithm to create the MVP model. +@param factory : visualisation factory to use. +@param : Handler for GUI updates while algorithm progresses. +@param drawingProgressUpdate : Handler for GUI updates while +vtkDataSetFactory::create occurs. +*/ +vtkDataSet * +MDHWInMemoryLoadingPresenter::execute(vtkDataSetFactory *factory, + ProgressAction &, + ProgressAction &drawingProgressUpdate) { + using namespace Mantid::API; + using namespace Mantid::Geometry; + + Workspace_sptr ws = m_repository->fetchWorkspace(m_wsName); + IMDHistoWorkspace_sptr histoWs = + boost::dynamic_pointer_cast<Mantid::API::IMDHistoWorkspace>(ws); + + auto visualHistoWs = transposeWs(histoWs); + + // factory->setRecursionDepth(this->m_view->getRecursionDepth()); + vtkDataSet *visualDataSet = factory->oneStepCreate( + visualHistoWs, drawingProgressUpdate); // HACK: progressUpdate should be + // argument for drawing! + + /*extractMetaData needs to be re-run here because the first execution of this + from ::executeLoadMetadata will not have ensured that all dimensions + have proper range extents set. + */ + + // Update the meta data min and max values with the values of the visual data + // set. This is necessary since we want the full data range of the visual + // data set and not of the actual underlying data set. + double *range = visualDataSet->GetScalarRange(); + if (range) { + this->m_metadataJsonManager->setMinValue(range[0]); + this->m_metadataJsonManager->setMaxValue(range[1]); + } - this->appendMetadata(visualDataSet, histoWs->getName()); - return visualDataSet; - } + this->extractMetadata(visualHistoWs); - /** - Executes any meta-data loading required. - */ - void MDHWInMemoryLoadingPresenter::executeLoadMetadata() - { - using namespace Mantid::API; - - Workspace_sptr ws = m_repository->fetchWorkspace(m_wsName); - IMDHistoWorkspace_sptr histoWs = boost::dynamic_pointer_cast<Mantid::API::IMDHistoWorkspace>(ws); - m_wsTypeName = histoWs->id(); - m_specialCoords = histoWs->getSpecialCoordinateSystem(); - - // Set the minimum and maximum of the workspace data. - QwtDoubleInterval minMaxContainer = m_metaDataExtractor->getMinAndMax(histoWs); - m_metadataJsonManager->setMinValue(minMaxContainer.minValue()); - m_metadataJsonManager->setMaxValue(minMaxContainer.maxValue()); - - // Set the instrument which is associated with the workspace. - m_metadataJsonManager->setInstrument(m_metaDataExtractor->extractInstrument(histoWs)); - - // Set the special coordinates - m_metadataJsonManager->setSpecialCoordinates(m_specialCoords); - - //Call base-class extraction method. - this->extractMetadata(histoWs); - } + this->appendMetadata(visualDataSet, histoWs->getName()); + return visualDataSet; +} - ///Destructor - MDHWInMemoryLoadingPresenter::~MDHWInMemoryLoadingPresenter() - { - delete m_view; - } +/** + Executes any meta-data loading required. +*/ +void MDHWInMemoryLoadingPresenter::executeLoadMetadata() { + using namespace Mantid::API; - /* - * Getter for the workspace type name. - * @return Workspace Type Name - */ - std::string MDHWInMemoryLoadingPresenter::getWorkspaceTypeName() - { - return m_wsTypeName; - } + Workspace_sptr ws = m_repository->fetchWorkspace(m_wsName); + IMDHistoWorkspace_sptr histoWs = + boost::dynamic_pointer_cast<Mantid::API::IMDHistoWorkspace>(ws); + m_wsTypeName = histoWs->id(); + m_specialCoords = histoWs->getSpecialCoordinateSystem(); - /** - * Getter for the special coordinates. - * @return the special coordinates value - */ - int MDHWInMemoryLoadingPresenter::getSpecialCoordinates() - { - return m_specialCoords; - } - - std::vector<int> MDHWInMemoryLoadingPresenter::getExtents() - { - using namespace Mantid::API; - Workspace_sptr ws = m_repository->fetchWorkspace(m_wsName); - IMDHistoWorkspace_sptr histoWs = boost::dynamic_pointer_cast<Mantid::API::IMDHistoWorkspace>(ws); - std::vector<int> extents(6, 0); - extents[1] = static_cast<int>(histoWs->getXDimension()->getNBins()); - extents[3] = static_cast<int>(histoWs->getYDimension()->getNBins()); - extents[5] = static_cast<int>(histoWs->getZDimension()->getNBins()); - return extents; - } - - } + histoWs = transposeWs(histoWs); + + // Set the minimum and maximum of the workspace data. + QwtDoubleInterval minMaxContainer = + m_metaDataExtractor->getMinAndMax(histoWs); + m_metadataJsonManager->setMinValue(minMaxContainer.minValue()); + m_metadataJsonManager->setMaxValue(minMaxContainer.maxValue()); + + // Set the instrument which is associated with the workspace. + m_metadataJsonManager->setInstrument( + m_metaDataExtractor->extractInstrument(histoWs)); + + // Set the special coordinates + m_metadataJsonManager->setSpecialCoordinates(m_specialCoords); + + // Call base-class extraction method. + this->extractMetadata(histoWs); +} + +/// Destructor +MDHWInMemoryLoadingPresenter::~MDHWInMemoryLoadingPresenter() { delete m_view; } + +/* + * Getter for the workspace type name. + * @return Workspace Type Name + */ +std::string MDHWInMemoryLoadingPresenter::getWorkspaceTypeName() { + return m_wsTypeName; +} + +/** + * Getter for the special coordinates. + * @return the special coordinates value + */ +int MDHWInMemoryLoadingPresenter::getSpecialCoordinates() { + return m_specialCoords; +} + +std::vector<int> MDHWInMemoryLoadingPresenter::getExtents() { + using namespace Mantid::API; + Workspace_sptr ws = m_repository->fetchWorkspace(m_wsName); + IMDHistoWorkspace_sptr histoWs = + boost::dynamic_pointer_cast<Mantid::API::IMDHistoWorkspace>(ws); + histoWs = transposeWs(histoWs); + std::vector<int> extents(6, 0); + extents[1] = static_cast<int>(histoWs->getXDimension()->getNBins()); + extents[3] = static_cast<int>(histoWs->getYDimension()->getNBins()); + extents[5] = static_cast<int>(histoWs->getZDimension()->getNBins()); + return extents; +} +} } diff --git a/Code/Mantid/Vates/VatesAPI/test/MDHWInMemoryLoadingPresenterTest.h b/Code/Mantid/Vates/VatesAPI/test/MDHWInMemoryLoadingPresenterTest.h index 1b61f8ac85a..461b007f8f7 100644 --- a/Code/Mantid/Vates/VatesAPI/test/MDHWInMemoryLoadingPresenterTest.h +++ b/Code/Mantid/Vates/VatesAPI/test/MDHWInMemoryLoadingPresenterTest.h @@ -32,7 +32,7 @@ private: }; // Helper method. Generates and returns a valid IMDHistoWorkspace - static Mantid::API::Workspace_sptr getGoodWorkspace() + Mantid::API::Workspace_sptr getGoodWorkspace() { Mantid::DataObjects::MDHistoWorkspace_sptr ws = makeFakeMDHistoWorkspace(1.0, 4, 5, 1.0, 0.1,"MD_HISTO_WS"); return ws; diff --git a/Code/Mantid/docs/source/algorithms/Transpose-v1.rst b/Code/Mantid/docs/source/algorithms/Transpose-v1.rst index 44218c1a7f5..15f8b725124 100644 --- a/Code/Mantid/docs/source/algorithms/Transpose-v1.rst +++ b/Code/Mantid/docs/source/algorithms/Transpose-v1.rst @@ -10,7 +10,7 @@ Description ----------- This algorithm transposes a workspace, so that an N1 x N2 workspace -becomes N2 x N1. +becomes N2 x N1. The X-vector values for the new workspace are taken from the axis values of the old workspace, which is generaly the spectra number but can be @@ -22,6 +22,8 @@ other values, if say the workspace has gone through The new axis values are taken from the previous X-vector values for the first specrum in the workspace. For this reason, use with ragged workspaces is undefined. + +For transposing multidimensional workspaces use :ref:`TransposeMD <algm-TransposeMD>`. Usage ----- diff --git a/Code/Mantid/docs/source/algorithms/Transpose3D-v1.rst b/Code/Mantid/docs/source/algorithms/Transpose3D-v1.rst index 0b31bfbfb50..ddb63add8e1 100644 --- a/Code/Mantid/docs/source/algorithms/Transpose3D-v1.rst +++ b/Code/Mantid/docs/source/algorithms/Transpose3D-v1.rst @@ -8,7 +8,7 @@ .. warning:: - This algorithm is currently under review and may change or disappear in a future release of Mantid. + For transposing multidimensional workspaces now use :ref:`TransposeMD <algm-TransposeMD>`. This algorithm is currently under review and may change or disappear in a future release of Mantid. -- GitLab