Skip to content
Snippets Groups Projects
MDHWInMemoryLoadingPresenter.cpp 7.95 KiB
Newer Older
#include "MantidVatesAPI/MDHWInMemoryLoadingPresenter.h"
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/IAlgorithm.h"
Harry Jeffery's avatar
Harry Jeffery committed
#include "MantidAPI/IMDHistoWorkspace.h"
#include "MantidVatesAPI/MDLoadingView.h"
#include "MantidVatesAPI/MetaDataExtractorUtils.h"
#include "MantidVatesAPI/ProgressAction.h"
#include "MantidVatesAPI/vtkDataSetFactory.h"
#include "MantidVatesAPI/WorkspaceProvider.h"
#include "MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h"
#include <qwt_double_interval.h>
#include <vtkUnstructuredGrid.h>

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) {
     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);
    std::vector<int> orderedDims;
    orderedDims = nonIntegratedDims;
    orderedDims.insert(orderedDims.end(), integratedDims.begin(),
                       integratedDims.end());
     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;
}
/*
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->extractMetadata(visualHistoWs);
  this->appendMetadata(visualDataSet, histoWs->getName());
  return visualDataSet;
}
/**
 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();
  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;
}
}