diff --git a/Vates/VatesAPI/src/MDHWInMemoryLoadingPresenter.cpp b/Vates/VatesAPI/src/MDHWInMemoryLoadingPresenter.cpp index 1387b7cff278409c7910e5cac56ebec10957d563..0c029f0654b46f1f5a847de1a0947f663b7e3e45 100644 --- a/Vates/VatesAPI/src/MDHWInMemoryLoadingPresenter.cpp +++ b/Vates/VatesAPI/src/MDHWInMemoryLoadingPresenter.cpp @@ -1,15 +1,19 @@ #include "MantidVatesAPI/MDHWInMemoryLoadingPresenter.h" #include "MantidAPI/AlgorithmManager.h" #include "MantidAPI/IMDHistoWorkspace.h" +#include "MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h" +#include "MantidKernel/MultiThreaded.h" +#include "MantidVatesAPI/FactoryChains.h" #include "MantidVatesAPI/MDLoadingView.h" #include "MantidVatesAPI/MetaDataExtractorUtils.h" -#include "MantidVatesAPI/FactoryChains.h" #include "MantidVatesAPI/ProgressAction.h" -#include "MantidVatesAPI/vtkDataSetFactory.h" #include "MantidVatesAPI/WorkspaceProvider.h" -#include "MantidGeometry/MDGeometry/MDGeometryXMLBuilder.h" +#include "MantidVatesAPI/vtkDataSetFactory.h" #include <qwt_double_interval.h> -#include <vtkUnstructuredGrid.h> + +#include "vtkStructuredGrid.h" +#include "vtkUnsignedCharArray.h" +#include "vtkUnstructuredGrid.h" namespace Mantid { namespace VATES { @@ -61,6 +65,43 @@ bool MDHWInMemoryLoadingPresenter::canReadFile() const { return bCanReadIt; } +namespace { +class CellVisibility { +public: + CellVisibility(vtkStructuredGrid *structuredGrid) + : MASKED_CELL_VALUE(vtkDataSetAttributes::HIDDENCELL | + vtkDataSetAttributes::REFINEDCELL), + InputCellGhostArray( + structuredGrid->GetCellGhostArray()->GetPointer(0)) {} + bool operator()(vtkIdType id) const { + return !(this->InputCellGhostArray[id] & this->MASKED_CELL_VALUE); + } + +private: + const unsigned char MASKED_CELL_VALUE; + const unsigned char *InputCellGhostArray; +}; + +void ComputeScalarRange(vtkStructuredGrid *grid, double *cellRange) { + CellVisibility isCellVisible(grid); + vtkDataArray *cellScalars = grid->GetCellData()->GetScalars(); + double minvalue = VTK_DOUBLE_MAX; + double maxvalue = VTK_DOUBLE_MIN; + int num = boost::numeric_cast<int>(grid->GetNumberOfCells()); +#if defined(_OPENMP) && _OPENMP >= 200805 + PRAGMA_OMP(parallel for reduction(min : minvalue) reduction(max : maxvalue)) +#endif + for (int id = 0; id < num; id++) { + if (isCellVisible(id)) { + double s = cellScalars->GetComponent(id, 0); + minvalue = std::min(minvalue, s); + maxvalue = std::max(maxvalue, s); + } + } + cellRange[0] = minvalue; + cellRange[1] = maxvalue; +} +} /* Executes the underlying algorithm to create the MVP model. @param factory : visualisation factory to use. @@ -87,20 +128,32 @@ MDHWInMemoryLoadingPresenter::execute(vtkDataSetFactory *factory, 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]); + + // vtkStructuredGrid::GetScalarRange(...) is slow and single-threaded. + // Until this is addressed in VTK, we are better of doing the calculation + // ourselves. + // 600x600x600 vtkStructuredGrid, every other cell blank + // structuredGrid->GetScalarRange(range) : 2.36625s + // structuredGrid->GetCellData()->GetScalars()->GetRange(range) : 1.01453s + // ComputeScalarRange(structuredGrid,range): 0.086104s + double range[2]; + if (auto structuredGrid = vtkStructuredGrid::SafeDownCast(visualDataSet)) { + ComputeScalarRange(structuredGrid, range); + } else { + // should never happen + visualDataSet->GetScalarRange(range); } + this->m_metadataJsonManager->setMinValue(range[0]); + this->m_metadataJsonManager->setMaxValue(range[1]); + + /*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. + */ this->extractMetadata(*m_cachedVisualHistoWs); // Transposed workpace is temporary, outside the ADS, and does not have a