diff --git a/Code/Mantid/Framework/API/src/WorkspaceHistory.cpp b/Code/Mantid/Framework/API/src/WorkspaceHistory.cpp index 59dde0755821678be4650b9287a4346da4f9d117..6742c3d2e1c06c49dc394238107fa0b142a31c01 100644 --- a/Code/Mantid/Framework/API/src/WorkspaceHistory.cpp +++ b/Code/Mantid/Framework/API/src/WorkspaceHistory.cpp @@ -276,7 +276,16 @@ void WorkspaceHistory::loadNexus(::NeXus::File * file) }; - file->openGroup("process", "NXprocess"); + // Warn but continue if the group does not exist. + try + { + file->openGroup("process", "NXprocess"); + } + catch (std::exception & ) + { + g_log.warning() << "Error opening the algorithm history field 'process'. Workspace will have no history." << "\n"; + return; + } std::map<std::string, std::string> entries; file->getEntries(entries); diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/LoadMD.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/LoadMD.h index 8a381f8cab63adfe2d035d665fc9eac19140ea13..924b38aed5d4c347dc221b6129f9d49ee6e3ad1e 100644 --- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/LoadMD.h +++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/LoadMD.h @@ -68,7 +68,12 @@ namespace MDEvents template<typename MDE, size_t nd> void doLoad(typename MDEventWorkspace<MDE, nd>::sptr ws); - void loadExperimentInfos(Mantid::API::IMDEventWorkspace_sptr ws); + void loadExperimentInfos(boost::shared_ptr<Mantid::API::MultipleExperimentInfos> ws); + + void loadSlab(std::string name, void * data, MDHistoWorkspace_sptr ws, NeXus::NXnumtype dataType); + void loadHisto(); + + void loadDimensions(); /// Open file handle ::NeXus::File * file; @@ -76,6 +81,12 @@ namespace MDEvents /// Name of that file std::string m_filename; + /// Number of dimensions in loaded file + size_t m_numDims; + + /// Each dimension object loaded. + std::vector<Mantid::Geometry::IMDDimension_sptr> m_dims; + }; diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspace.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspace.h index 91beb73b90ba0dc8575d0ee36cf8eaa69b21791f..224531b579fdb9f5ba1e096c51ecd54486cedae9 100644 --- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspace.h +++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspace.h @@ -44,12 +44,14 @@ namespace MDEvents Mantid::Geometry::MDHistoDimension_sptr dimT=Mantid::Geometry::MDHistoDimension_sptr()); MDHistoWorkspace(std::vector<Mantid::Geometry::MDHistoDimension_sptr> & dimensions); + MDHistoWorkspace(std::vector<Mantid::Geometry::IMDDimension_sptr> & dimensions); MDHistoWorkspace(const MDHistoWorkspace & other); virtual ~MDHistoWorkspace(); void init(std::vector<Mantid::Geometry::MDHistoDimension_sptr> & dimensions); + void init(std::vector<Mantid::Geometry::IMDDimension_sptr> & dimensions); void cacheValues(); diff --git a/Code/Mantid/Framework/MDEvents/src/LoadMD.cpp b/Code/Mantid/Framework/MDEvents/src/LoadMD.cpp index b0cf634ea4c825fb9822ffe69425a6c9083b42fd..3a5af831f77464e76709fb3083817684b0bc8683 100644 --- a/Code/Mantid/Framework/MDEvents/src/LoadMD.cpp +++ b/Code/Mantid/Framework/MDEvents/src/LoadMD.cpp @@ -35,6 +35,7 @@ and used by other algorithms, they should not be needed in daily use. #include "MantidNexusCPP/NeXusException.hpp" #include <boost/algorithm/string.hpp> #include <vector> +#include "MantidMDEvents/MDHistoWorkspace.h" using namespace Mantid::Kernel; using namespace Mantid::API; @@ -99,7 +100,7 @@ namespace Mantid "If not specified, a default of 40% of free physical memory is used."); setPropertySettings("Memory", new EnabledWhenProperty("FileBackEnd", IS_EQUAL_TO, "1") ); - declareProperty(new WorkspaceProperty<IMDEventWorkspace>("OutputWorkspace","",Direction::Output), "Name of the output MDEventWorkspace."); + declareProperty(new WorkspaceProperty<IMDWorkspace>("OutputWorkspace","",Direction::Output), "Name of the output MDEventWorkspace."); } @@ -138,9 +139,9 @@ namespace Mantid string_map_t entries = file.getEntries(); for(string_map_t::const_iterator it = entries.begin(); it != entries.end(); ++it) { - if ( (it->first == "MDEventWorkspace") && (it->second == "NXentry") ) + if ( (it->second == "NXentry") && + ((it->first == "MDEventWorkspace") || (it->first == "MDHistoWorkspace")) ) confidence = 95; - } file.close(); } @@ -154,11 +155,12 @@ namespace Mantid + //---------------------------------------------------------------------------------------------- /** Load the ExperimentInfo blocks, if any, in the NXS file * - * @param ws :: MDEventWorkspace to load + * @param ws :: MDEventWorkspace/MDHisto to load */ - void LoadMD::loadExperimentInfos(IMDEventWorkspace_sptr ws) + void LoadMD::loadExperimentInfos(boost::shared_ptr<Mantid::API::MultipleExperimentInfos> ws) { // First, find how many experimentX blocks there are std::map<std::string,std::string> entries; @@ -233,31 +235,123 @@ namespace Mantid file = new ::NeXus::File(m_filename, NXACC_READ); // The main entry - file->openGroup("MDEventWorkspace", "NXentry"); + std::map<std::string, std::string> entries; + file->getEntries(entries); + std::string entryName; + if (entries.find("MDEventWorkspace") != entries.end()) + entryName = "MDEventWorkspace"; + else if (entries.find("MDHistoWorkspace") != entries.end()) + entryName = "MDHistoWorkspace"; + else + throw std::runtime_error("Unexpected NXentry name. Expected 'MDEventWorkspace' or 'MDHistoWorkspace'."); + + // Open the entry + file->openGroup(entryName, "NXentry"); + + // How many dimensions? std::vector<int32_t> vecDims; file->readData("dimensions", vecDims); if (vecDims.empty()) throw std::runtime_error("LoadMD:: Error loading number of dimensions."); - size_t numDims = vecDims[0]; - if (numDims <= 0) + m_numDims = vecDims[0]; + if (m_numDims <= 0) throw std::runtime_error("LoadMD:: number of dimensions <= 0."); - //The type of event - std::string eventType; - file->getAttr("event_type", eventType); + // Now load all the dimension xml + this->loadDimensions(); + + if (entryName == "MDEventWorkspace") + { + //The type of event + std::string eventType; + file->getAttr("event_type", eventType); + + // Use the factory to make the workspace of the right type + IMDEventWorkspace_sptr ws = MDEventFactory::CreateMDWorkspace(m_numDims, eventType); + + // Now the ExperimentInfo + loadExperimentInfos(ws); + + // Wrapper to cast to MDEventWorkspace then call the function + CALL_MDEVENT_FUNCTION(this->doLoad, ws); + + // Save to output + setProperty("OutputWorkspace", boost::dynamic_pointer_cast<IMDWorkspace>(ws)); + } + else + { + // MDHistoWorkspace case. + this->loadHisto(); + } + } + + + /** Load a slab of double data into a bare array. + * Checks that the size is correct. + * + * @param data :: bare pointer to double array + * @param numPoints :: + * @param name + */ + void LoadMD::loadSlab(std::string name, void * data, MDHistoWorkspace_sptr ws, NeXus::NXnumtype dataType) + { + file->openData(name); + if (file->getInfo().type != dataType) + throw std::runtime_error("Unexpected data type for '" + name + "' data set.'"); + if (file->getInfo().dims[0] != static_cast<int>(ws->getNPoints())) + throw std::runtime_error("Inconsistency between the number of points in '" + name + "' and the number of bins defined by the dimensions."); + std::vector<int> start(1,0); + std::vector<int> size(1, static_cast<int>(ws->getNPoints())); + file->getSlab(data, start, size); + file->closeData(); + } - // Use the factory to make the workspace of the right type - IMDEventWorkspace_sptr ws = MDEventFactory::CreateMDWorkspace(numDims, eventType); + //---------------------------------------------------------------------------------------------- + /** Perform loading for a MDHistoWorkspace. + * The entry should be open already. + */ + void LoadMD::loadHisto() + { + // Create the initial MDHisto. + MDHistoWorkspace_sptr ws(new MDHistoWorkspace(m_dims)); // Now the ExperimentInfo loadExperimentInfos(ws); - // Wrapper to cast to MDEventWorkspace then call the function - CALL_MDEVENT_FUNCTION(this->doLoad, ws); + // Load the WorkspaceHistory "process" + ws->history().loadNexus(file); + + // Load each data slab + this->loadSlab("signal", ws->getSignalArray(), ws, ::NeXus::FLOAT64); + this->loadSlab("errors_squared", ws->getErrorSquaredArray(), ws, ::NeXus::FLOAT64); + this->loadSlab("num_events", ws->getNumEventsArray(), ws, ::NeXus::FLOAT64); + this->loadSlab("mask", ws->getMaskArray(), ws, ::NeXus::INT8); // Save to output - setProperty("OutputWorkspace", ws); + setProperty("OutputWorkspace", boost::dynamic_pointer_cast<IMDWorkspace>(ws)); + } + + + //---------------------------------------------------------------------------------------------- + /** Load all the dimensions into this->m_dims */ + void LoadMD::loadDimensions() + { + m_dims.clear(); + + // Load each dimension, as their XML representation + for (size_t d=0; d<m_numDims; d++) + { + std::ostringstream mess; + mess << "dimension" << d; + std::string dimXML; + file->getAttr(mess.str(), dimXML); + // Use the dimension factory to read the XML + IMDDimensionFactory factory = IMDDimensionFactory::createDimensionFactory(dimXML); + IMDDimension_sptr dim(factory.create()); + m_dims.push_back(dim); + } + } @@ -282,26 +376,16 @@ namespace Mantid Progress * prog = new Progress(this, 0.0, 1.0, 100); prog->report("Opening file."); - std::string title; file->getAttr("title", title); ws->setTitle("title"); - // TODO: notes, sample, logs, instrument, process, run_start + // Load the WorkspaceHistory "process" + ws->history().loadNexus(file); - // The workspace-specific data - // Load each dimension, as their XML representation + // Add each of the dimension for (size_t d=0; d<nd; d++) - { - std::ostringstream mess; - mess << "dimension" << d; - std::string dimXML; - file->getAttr(mess.str(), dimXML); - // Use the dimension factory to read the XML - IMDDimensionFactory factory = IMDDimensionFactory::createDimensionFactory(dimXML); - IMDDimension_sptr dim(factory.create()); - ws->addDimension(dim); - } + ws->addDimension(m_dims[d]); bool bMetadataOnly = getProperty("MetadataOnly"); if(!bMetadataOnly) diff --git a/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspace.cpp b/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspace.cpp index d6769ff903202dc05dc00a811edc7ccbbe460ee5..4f44cf90ceb9d69a68d61e46e0f0ee1a58a74661 100644 --- a/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspace.cpp +++ b/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspace.cpp @@ -51,6 +51,17 @@ namespace MDEvents this->init(dimensions); } + //---------------------------------------------------------------------------------------------- + /** Constructor given a vector of dimensions + * @param dimensions :: vector of MDHistoDimension; no limit to how many. + */ + MDHistoWorkspace::MDHistoWorkspace(std::vector<Mantid::Geometry::IMDDimension_sptr> & dimensions) + : IMDHistoWorkspace(), + numDimensions(0) + { + this->init(dimensions); + } + //---------------------------------------------------------------------------------------------- /** Copy constructor * @@ -101,8 +112,18 @@ namespace MDEvents void MDHistoWorkspace::init(std::vector<Mantid::Geometry::MDHistoDimension_sptr> & dimensions) { std::vector<IMDDimension_sptr> dim2; - for (size_t i=0; i<dimensions.size(); i++) dim2.push_back(boost::dynamic_pointer_cast<IMDDimension>(dimensions[i])); - MDGeometry::initGeometry(dim2); + for (size_t i=0; i<dimensions.size(); i++) + dim2.push_back(boost::dynamic_pointer_cast<IMDDimension>(dimensions[i])); + this->init(dim2); + } + + //---------------------------------------------------------------------------------------------- + /** Constructor helper method + * @param dimensions :: vector of IMDDimension; no limit to how many. + */ + void MDHistoWorkspace::init(std::vector<Mantid::Geometry::IMDDimension_sptr> & dimensions) + { + MDGeometry::initGeometry(dimensions); this->cacheValues(); // Allocate the linear arrays diff --git a/Code/Mantid/Framework/MDEvents/src/SaveMD.cpp b/Code/Mantid/Framework/MDEvents/src/SaveMD.cpp index 3039259e97915914091b8054356d43c243a4f88d..5f4f4cff702bbefba29ccc0f7e5f3c243f64c47f 100644 --- a/Code/Mantid/Framework/MDEvents/src/SaveMD.cpp +++ b/Code/Mantid/Framework/MDEvents/src/SaveMD.cpp @@ -147,6 +147,9 @@ namespace MDEvents // Write out some general information like # of dimensions file->writeData("dimensions", int32_t(nd)); file->putAttr("event_type", MDE::getTypeName()); + + // Save the algorithm history under "process" + ws->getHistory().saveNexus(file); } // Save each NEW ExperimentInfo to a spot in the file @@ -455,6 +458,9 @@ namespace MDEvents // The base entry. Named so as to distinguish from other workspace types. file->makeGroup("MDHistoWorkspace", "NXentry", true); + // Save the algorithm history under "process" + ws->getHistory().saveNexus(file); + // Save all the ExperimentInfos for (uint16_t i=0; i < ws->getNumExperimentInfo(); i++) { @@ -470,6 +476,9 @@ namespace MDEvents } } + // Write out some general information like # of dimensions + file->writeData("dimensions", int32_t(ws->getNumDims())); + // Save each dimension, as their XML representation for (size_t d=0; d<ws->getNumDims(); d++) {