diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/IMDEventWorkspace.h b/Code/Mantid/Framework/API/inc/MantidAPI/IMDEventWorkspace.h index 723ce3d7a8f8..b02beb1fa264 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/IMDEventWorkspace.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/IMDEventWorkspace.h @@ -51,11 +51,6 @@ class MANTID_API_DLL IMDEventWorkspace : public API::IMDWorkspace, virtual void getBoxes(std::vector &boxes, size_t maxDepth, bool leafOnly) = 0; - /// TODO: The meaning of this method have changed! Helper method that makes a - /// table workspace with some box data - // virtual Mantid::API::ITableWorkspace_sptr makeBoxTable(size_t start, size_t - // num) = 0; - /// @return true if the workspace is file-backed virtual bool isFileBacked() const = 0; diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/IMDHistoWorkspace.h b/Code/Mantid/Framework/API/inc/MantidAPI/IMDHistoWorkspace.h index 942e14af6ee2..cc7c014a382a 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/IMDHistoWorkspace.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/IMDHistoWorkspace.h @@ -89,7 +89,7 @@ class DLLExport IMDHistoWorkspace : public IMDWorkspace, virtual double &operator[](const size_t &index) = 0; virtual void setCoordinateSystem( - const Mantid::Kernel::SpecialCoordinateSystem coordinateSystem) = 0; + const Kernel::SpecialCoordinateSystem coordinateSystem) = 0; virtual boost::shared_ptr clone() const = 0; diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/IMDWorkspace.h b/Code/Mantid/Framework/API/inc/MantidAPI/IMDWorkspace.h index c3bebd3e4f1d..35203727852c 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/IMDWorkspace.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/IMDWorkspace.h @@ -67,8 +67,7 @@ enum MDNormalization { Code Documentation is available at: */ -class MANTID_API_DLL IMDWorkspace : public Workspace, - public Mantid::API::MDGeometry { +class MANTID_API_DLL IMDWorkspace : public Workspace, public API::MDGeometry { public: IMDWorkspace(); IMDWorkspace(const IMDWorkspace &other); @@ -119,11 +118,11 @@ class MANTID_API_DLL IMDWorkspace : public Workspace, /// Clear existing masks virtual void clearMDMasking() = 0; /// - virtual Mantid::Kernel::SpecialCoordinateSystem + virtual Kernel::SpecialCoordinateSystem getSpecialCoordinateSystem() const = 0; /// if a workspace was filebacked, this should clear file-based status, delete /// file-based information and close related files. - virtual void clearFileBacked(bool /* loadFileContentsToMemory*/){}; + virtual void clearFileBacked(bool /* loadFileContentsToMemory*/) {} /// this is the method to build table workspace from any workspace. It does /// not have much sence and may be placed here erroneously virtual ITableWorkspace_sptr makeBoxTable(size_t /*start*/, size_t /* num*/) { diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/IPeaksWorkspace.h b/Code/Mantid/Framework/API/inc/MantidAPI/IPeaksWorkspace.h index 15bd48bf8b94..03e115047abb 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/IPeaksWorkspace.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/IPeaksWorkspace.h @@ -55,10 +55,6 @@ class MANTID_API_DLL IPeaksWorkspace : public ITableWorkspace, /// Destructor virtual ~IPeaksWorkspace(); - // boost::shared_ptr clone() = 0; - // void appendFile( std::string filename, Mantid::Geometry::Instrument_sptr - // inst) = 0; - //--------------------------------------------------------------------------------------------- /** @return the number of peaks */ @@ -99,14 +95,15 @@ class MANTID_API_DLL IPeaksWorkspace : public ITableWorkspace, //--------------------------------------------------------------------------------------------- /** Create an instance of a Peak - * @param QLabFrame :: Q of the center of the peak in the lab frame, in reciprocal space - * @param detectorDistance :: Optional distance between the sample and the detector. Calculated if not provided. + * @param QLabFrame :: Q of the center of the peak in the lab frame, in + * reciprocal space + * @param detectorDistance :: Optional distance between the sample and the + * detector. Calculated if not provided. * @return a pointer to a new Peak object. */ virtual IPeak *createPeak(Mantid::Kernel::V3D QLabFrame, boost::optional detectorDistance) const = 0; - /** * Create an instance of a peak using a V3D * @param HKL V3D @@ -136,16 +133,16 @@ class MANTID_API_DLL IPeaksWorkspace : public ITableWorkspace, * @param coordinateSystem : Special Q3D coordinate system to use. */ virtual void setCoordinateSystem( - const Mantid::Kernel::SpecialCoordinateSystem coordinateSystem) = 0; - + const Kernel::SpecialCoordinateSystem coordinateSystem) = 0; //--------------------------------------------------------------------------------------------- /** * Get the special coordinate system. * @returns special Q3D coordinate system to use being used by this * PeaksWorkspace object. Probably the one the workspace was generated with. */ - virtual Mantid::Kernel::SpecialCoordinateSystem + virtual Kernel::SpecialCoordinateSystem getSpecialCoordinateSystem() const = 0; + virtual std::vector> peakInfo(Kernel::V3D QFrame, bool labCoords) const = 0; virtual int peakInfoNumber(Kernel::V3D qLabFrame, bool labCoords) const = 0; diff --git a/Code/Mantid/Framework/API/inc/MantidAPI/Projection.h b/Code/Mantid/Framework/API/inc/MantidAPI/Projection.h index 7498bbd07435..5a8b4d3e20ae 100644 --- a/Code/Mantid/Framework/API/inc/MantidAPI/Projection.h +++ b/Code/Mantid/Framework/API/inc/MantidAPI/Projection.h @@ -72,7 +72,6 @@ class DLLExport Projection { /// Set the unit for a given dimension void setUnit(size_t nd, ProjectionUnit unit); - // We're guaranteed to have at least 2 axes V3D &U() { return m_dimensions[0]; } V3D &V() { return m_dimensions[1]; } V3D &W() { return m_dimensions[2]; } diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/PlotAsymmetryByLogValue.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/PlotAsymmetryByLogValue.h index e10891b09dc7..d743d1c93a7a 100644 --- a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/PlotAsymmetryByLogValue.h +++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/PlotAsymmetryByLogValue.h @@ -78,8 +78,14 @@ class DLLExport PlotAsymmetryByLogValue : public API::Algorithm { // Overridden Algorithm methods void init(); void exec(); + // Load run, apply dead time corrections and detector grouping + API::Workspace_sptr doLoad (int64_t runNumber ); + // Analyse loaded run + void doAnalysis (API::Workspace_sptr loadedWs, int64_t index); // Parse run names - void parseRunNames (std::string& firstFN, std::string& lastFN, std::string& fnBase, std::string& fnExt); + void parseRunNames (std::string& firstFN, std::string& lastFN, std::string& fnBase, std::string& fnExt, int& fnZeros); + // Resize vectors + void resizeVectors (size_t size); // Load dead-time corrections from specified file void loadCorrectionsFromFile (API::Workspace_sptr &customDeadTimes, std::string deadTimeFile ); // Apply dead-time corrections @@ -97,6 +103,12 @@ class DLLExport PlotAsymmetryByLogValue : public API::Algorithm { /// Populate output workspace with results void populateOutputWorkspace (API::MatrixWorkspace_sptr &outWS, int nplots); + /// Stores base name shared by all runs + std::string m_filenameBase; + /// Stores extension shared by all runs + std::string m_filenameExt; + /// Sotres number of zeros in run name + int m_filenameZeros; /// Stores property "Int" bool m_int; /// Store forward spectra @@ -105,6 +117,12 @@ class DLLExport PlotAsymmetryByLogValue : public API::Algorithm { std::vector m_backward_list; /// If true call LoadMuonNexus with Autogroup on bool m_autogroup; + /// Store type of dead time corrections + std::string m_dtcType; + /// Store red period + int m_red; + /// Store green period + int m_green; // Mantid vectors to store results // Red mantid vectors MantidVec m_redX, m_redY, m_redE; diff --git a/Code/Mantid/Framework/Algorithms/src/PlotAsymmetryByLogValue.cpp b/Code/Mantid/Framework/Algorithms/src/PlotAsymmetryByLogValue.cpp index 260a5244b6e2..981b88bad533 100644 --- a/Code/Mantid/Framework/Algorithms/src/PlotAsymmetryByLogValue.cpp +++ b/Code/Mantid/Framework/Algorithms/src/PlotAsymmetryByLogValue.cpp @@ -162,13 +162,13 @@ void PlotAsymmetryByLogValue::exec() { // Get log value m_logName = getPropertyValue("LogValue"); // Get green and red periods - int red = getProperty("Red"); - int green = getProperty("Green"); + m_red = getProperty("Red"); + m_green = getProperty("Green"); // Get type of computation std::string stype = getProperty("Type"); m_int = stype == "Integral"; // Get type of dead-time corrections - const std::string dtcType = getPropertyValue("DeadTimeCorrType"); + m_dtcType = getPropertyValue("DeadTimeCorrType"); // Get runs std::string firstFN = getProperty("FirstRun"); std::string lastFN = getProperty("LastRun"); @@ -176,139 +176,30 @@ void PlotAsymmetryByLogValue::exec() { m_logFunc = getPropertyValue("Function"); // Parse run names and get the number of runs - std::string fnBase, fnExt; - parseRunNames( firstFN, lastFN, fnBase, fnExt); + parseRunNames( firstFN, lastFN, m_filenameBase, m_filenameExt, m_filenameZeros); size_t is = atoi(firstFN.c_str()); // starting run number size_t ie = atoi(lastFN.c_str()); // last run number - int w = static_cast(firstFN.size()); - - // Dead-time corrections: if user specifies a file, load corrections now - Workspace_sptr customDeadTimes; - if (dtcType == "FromSpecifiedFile") { - loadCorrectionsFromFile (customDeadTimes, getPropertyValue("DeadTimeCorrFile")); - } + // Resize vectors that will store results + resizeVectors(ie-is+1); Progress progress(this, 0, 1, ie - is + 2); // Loop through runs for (size_t i = is; i <= ie; i++) { - // Get complete run name - std::ostringstream fn, fnn; - fnn << std::setw(w) << std::setfill('0') << i; - fn << fnBase << fnn.str() << fnExt; - - // Load run - IAlgorithm_sptr load = createChildAlgorithm("LoadMuonNexus"); - load->setPropertyValue("Filename", fn.str()); - load->execute(); - Workspace_sptr loadedWs = load->getProperty("OutputWorkspace"); - - // Check if dead-time corrections have to be applied - if (dtcType != "None") { - if (dtcType == "FromSpecifiedFile") { - applyDeadtimeCorr (loadedWs, customDeadTimes); - } else { - Workspace_sptr deadTimes = load->getProperty("DeadTimeTable"); - applyDeadtimeCorr (loadedWs, deadTimes); - } - } - - // If m_autogroup, group detectors - if (m_autogroup) { - Workspace_sptr loadedDetGrouping = load->getProperty("DetectorGroupingTable"); - if (!loadedDetGrouping) - throw std::runtime_error("No grouping info in the file.\n\nPlease " - "specify grouping manually"); - groupDetectors(loadedWs,loadedDetGrouping); - } - - // Check if workspace is a workspace group - WorkspaceGroup_sptr loadedGroup = - boost::dynamic_pointer_cast(loadedWs); - - // If it is not, we only have 'red' data - if (!loadedGroup) { - Workspace2D_sptr loadedWs2D = - boost::dynamic_pointer_cast(loadedWs); - - double Y, E; - calcIntAsymmetry(loadedWs2D, Y, E); - m_redX.push_back(getLogValue(*loadedWs2D)); - m_redY.push_back(Y); - m_redE.push_back(E); - - } else { - - DataObjects::Workspace2D_sptr ws_red; - DataObjects::Workspace2D_sptr ws_green; - // Run through the periods of the loaded file and save the - // selected ones - for (int mi = 0; mi < loadedGroup->getNumberOfEntries(); mi++) { - - Workspace2D_sptr memberWs = - boost::dynamic_pointer_cast(loadedGroup->getItem(mi)); - int period = mi + 1; - if ( period == red ){ - ws_red = memberWs; - } - if ( green!= EMPTY_INT() ){ - if ( period == green ){ - ws_green = memberWs; - } - } - } - - // Check ws_red - if (!ws_red){ - throw std::invalid_argument("Red period is out of range"); - } - // Check ws_green - if ( (green!=EMPTY_INT()) && (!ws_green) ){ - throw std::invalid_argument("Green period is out of range"); - } + // Load run, apply dead time corrections and detector grouping + Workspace_sptr loadedWs = doLoad(i); - if ( green==EMPTY_INT() ){ - double Y, E; - calcIntAsymmetry(ws_red, Y, E); - m_redX.push_back(getLogValue(*ws_red)); - m_redY.push_back(Y); - m_redE.push_back(E); + // Analyse loadedWs + doAnalysis (loadedWs, i-is); - } else{ - - double YR, ER; - double YG, EG; - double logValue = getLogValue(*ws_red); - calcIntAsymmetry(ws_red, YR, ER); - calcIntAsymmetry(ws_green, YG, EG); - // Red data - m_redX.push_back(logValue); - m_redY.push_back(YR); - m_redE.push_back(ER); - // Green data - m_greenX.push_back(logValue); - m_greenY.push_back(YG); - m_greenE.push_back(EG); - // Sum - m_sumX.push_back(logValue); - m_sumY.push_back(YR+YG); - m_sumE.push_back(sqrt(ER * ER + EG * EG)); - // move to last for safety since some grouping takes place in the - // calcIntAsymmetry call below - calcIntAsymmetry(ws_red, ws_green, YR, ER); - m_diffX.push_back(logValue); - m_diffY.push_back(YR); - m_diffE.push_back(ER); - } - } // else loadedGroup progress.report(); } // Create the 2D workspace for the output - int nplots = m_greenX.size() ? 4 : 1; + int nplots = (m_green!= EMPTY_INT()) ? 4 : 1; size_t npoints = ie - is + 1; MatrixWorkspace_sptr outWS = WorkspaceFactory::Instance().create( "Workspace2D", @@ -322,6 +213,49 @@ void PlotAsymmetryByLogValue::exec() { setProperty("OutputWorkspace", outWS); } +/** Loads one run and applies dead-time corrections and detector grouping if required +* @param runNumber :: [input] Run number specifying run to load +*/ +Workspace_sptr PlotAsymmetryByLogValue::doLoad (int64_t runNumber ) { + + // Get complete run name + std::ostringstream fn, fnn; + fnn << std::setw(m_filenameZeros) << std::setfill('0') << runNumber; + fn << m_filenameBase << fnn.str() << m_filenameExt; + + // Load run + IAlgorithm_sptr load = createChildAlgorithm("LoadMuonNexus"); + load->setPropertyValue("Filename", fn.str()); + load->execute(); + Workspace_sptr loadedWs = load->getProperty("OutputWorkspace"); + + // Check if dead-time corrections have to be applied + if (m_dtcType != "None") { + if (m_dtcType == "FromSpecifiedFile") { + + // If user specifies a file, load corrections now + Workspace_sptr customDeadTimes; + loadCorrectionsFromFile (customDeadTimes, getPropertyValue("DeadTimeCorrFile")); + applyDeadtimeCorr (loadedWs, customDeadTimes); + } else { + // Load corrections from run + Workspace_sptr deadTimes = load->getProperty("DeadTimeTable"); + applyDeadtimeCorr (loadedWs, deadTimes); + } + } + + // If m_autogroup, group detectors + if (m_autogroup) { + Workspace_sptr loadedDetGrouping = load->getProperty("DetectorGroupingTable"); + if (!loadedDetGrouping) + throw std::runtime_error("No grouping info in the file.\n\nPlease " + "specify grouping manually"); + groupDetectors(loadedWs,loadedDetGrouping); + } + + return loadedWs; +} + /** Load dead-time corrections from specified file * @param customDeadTimes :: [input/output] Output workspace to store corrections * @param deadTimeFile :: [input] File to read corrections from @@ -373,8 +307,9 @@ void PlotAsymmetryByLogValue::populateOutputWorkspace (MatrixWorkspace_sptr &out * @param lastFN :: [input/output] Last run's name * @param fnBase :: [output] Runs base name * @param fnExt :: [output] Runs extension +* @param fnZeros :: [output] Number of zeros in run's name */ -void PlotAsymmetryByLogValue::parseRunNames (std::string& firstFN, std::string& lastFN, std::string& fnBase, std::string& fnExt) +void PlotAsymmetryByLogValue::parseRunNames (std::string& firstFN, std::string& lastFN, std::string& fnBase, std::string& fnExt, int& fnZeros) { // Parse first run's name @@ -440,6 +375,8 @@ void PlotAsymmetryByLogValue::parseRunNames (std::string& firstFN, std::string& fnBase = firstBase; fnExt = firstExt; } + fnZeros = static_cast(firstFN.size()); + } /** Apply dead-time corrections. The calculation is done by ApplyDeadTimeCorr algorithm @@ -487,6 +424,95 @@ void PlotAsymmetryByLogValue::groupDetectors (Workspace_sptr &loadedWs, Workspac loadedWs = outWS.retrieve(); } + +/** Performs asymmetry analysis on a loaded workspace +* @param loadedWs :: [input] Workspace to apply analysis to +* @param index :: [input] Vector index where results will be stored +*/ +void PlotAsymmetryByLogValue::doAnalysis (Workspace_sptr loadedWs, int64_t index ) { + + // Check if workspace is a workspace group + WorkspaceGroup_sptr loadedGroup = + boost::dynamic_pointer_cast(loadedWs); + + // If it is not, we only have 'red' data + if (!loadedGroup) { + Workspace2D_sptr loadedWs2D = + boost::dynamic_pointer_cast(loadedWs); + + double Y, E; + calcIntAsymmetry(loadedWs2D, Y, E); + m_redX[index]=getLogValue(*loadedWs2D); + m_redY[index]=Y; + m_redE[index]=E; + + } else { + + DataObjects::Workspace2D_sptr ws_red; + DataObjects::Workspace2D_sptr ws_green; + // Run through the periods of the loaded file and save the + // selected ones + for (int mi = 0; mi < loadedGroup->getNumberOfEntries(); mi++) { + + Workspace2D_sptr memberWs = + boost::dynamic_pointer_cast(loadedGroup->getItem(mi)); + int period = mi + 1; + if ( period == m_red ){ + ws_red = memberWs; + } + if ( m_green!= EMPTY_INT() ){ + if ( period == m_green ){ + ws_green = memberWs; + } + } + } + + // Check ws_red + if (!ws_red){ + throw std::invalid_argument("Red period is out of range"); + } + // Check ws_green + if ( (m_green!=EMPTY_INT()) && (!ws_green) ){ + throw std::invalid_argument("Green period is out of range"); + } + + if ( m_green==EMPTY_INT() ){ + double Y, E; + calcIntAsymmetry(ws_red, Y, E); + m_redX[index] = getLogValue(*ws_red); + m_redY[index] = Y; + m_redE[index] = E; + + } else{ + + double YR, ER; + double YG, EG; + double logValue = getLogValue(*ws_red); + calcIntAsymmetry(ws_red, YR, ER); + calcIntAsymmetry(ws_green, YG, EG); + // Red data + m_redX[index] = logValue; + m_redY[index] = YR; + m_redE[index] = ER; + // Green data + m_greenX[index] = logValue; + m_greenY[index] = YG; + m_greenE[index] = EG; + // Sum + m_sumX[index] = logValue; + m_sumY[index] = YR+YG; + m_sumE[index] = sqrt(ER * ER + EG * EG); + // move to last for safety since some grouping takes place in the + // calcIntAsymmetry call below + calcIntAsymmetry(ws_red, ws_green, YR, ER); + m_diffX[index] = logValue; + m_diffY[index] = YR; + m_diffE[index] = ER; + } + } // else loadedGroup + +} + /** Calculate the integral asymmetry for a workspace. * The calculation is done by MuonAsymmetryCalc and SimpleIntegration * algorithms. @@ -666,6 +692,28 @@ PlotAsymmetryByLogValue::groupDetectors(API::MatrixWorkspace_sptr &ws, ws = group->getProperty("OutputWorkspace"); } +/** Resize vectors that will store results. + * @param size :: The size of the vectors + */ +void PlotAsymmetryByLogValue::resizeVectors(size_t size) { + + // Red vectors + m_redX.resize(size); + m_redY.resize(size); + m_redE.resize(size); + // Green vectors + m_greenX.resize(size); + m_greenY.resize(size); + m_greenE.resize(size); + // Diff vectors + m_diffX.resize(size); + m_diffY.resize(size); + m_diffE.resize(size); + // Sum vectors + m_sumX.resize(size); + m_sumY.resize(size); + m_sumE.resize(size); +} /** * Get log value from a workspace. Convert to double if possible. * diff --git a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp index 8eca6314f4b8..ffbfaac2167d 100644 --- a/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp +++ b/Code/Mantid/Framework/DataHandling/src/LoadNexusProcessed.cpp @@ -37,6 +37,8 @@ #include "MantidDataObjects/PeakShapeSphericalFactory.h" #include "MantidDataObjects/PeakShapeEllipsoidFactory.h" +#include + namespace Mantid { namespace DataHandling { @@ -714,7 +716,8 @@ LoadNexusProcessed::loadEventEntry(NXData &wksp_cls, NXDouble &xbins, boost::shared_array indices = indices_data.sharedBuffer(); // Create all the event lists PARALLEL_FOR_NO_WSP_CHECK() - for (int64_t j = 0; j < static_cast(m_filtered_spec_idxs.size()); j++) { + for (int64_t j = 0; j < static_cast(m_filtered_spec_idxs.size()); + j++) { PARALLEL_START_INTERUPT_REGION size_t wi = m_filtered_spec_idxs[j] - 1; int64_t index_start = indices[wi]; @@ -754,8 +757,8 @@ LoadNexusProcessed::loadEventEntry(NXData &wksp_cls, NXDouble &xbins, } } - progress(progressStart + progressRange * - (1.0 / static_cast(numspec))); + progress(progressStart + + progressRange * (1.0 / static_cast(numspec))); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION @@ -1005,8 +1008,8 @@ API::Workspace_sptr LoadNexusProcessed::loadPeaksEntry(NXEntry &entry) { // Get information from all but data group std::string parameterStr; - // Hop to the right point - m_cppFile->openPath(entry.path()); + // Hop to the right point /mantid_workspace_1 + m_cppFile->openPath(entry.path()); // This is try { // This loads logs, sample, and instrument. peakWS->loadExperimentInfoNexus(m_cppFile, parameterStr); @@ -1015,7 +1018,30 @@ API::Workspace_sptr LoadNexusProcessed::loadPeaksEntry(NXEntry &entry) { g_log.information(e.what()); } - // std::vector p; + // Coordinates - Older versions did not have the separate field but used a log + // value + uint32_t loadCoord(0); + m_cppFile->openGroup("peaks_workspace", "NXentry"); + try { + m_cppFile->readData("coordinate_system", loadCoord); + peakWS->setCoordinateSystem( + static_cast(loadCoord)); + } catch (::NeXus::Exception &) { + // Check for a log value + auto logs = peakWS->logs(); + if (logs->hasProperty("CoordinateSystem")) { + auto *prop = dynamic_cast *>( + logs->getProperty("CoordinateSystem")); + if (prop) { + int value((*prop)()); + peakWS->setCoordinateSystem( + static_cast(value)); + } + } + } + // peaks_workspace + m_cppFile->closeGroup(); + for (int r = 0; r < numberPeaks; r++) { Kernel::V3D v3d; v3d[2] = 1.0; @@ -1137,9 +1163,12 @@ API::Workspace_sptr LoadNexusProcessed::loadPeaksEntry(NXEntry &entry) { // Read shape information using namespace Mantid::DataObjects; - PeakShapeFactory_sptr peakFactoryEllipsoid = boost::make_shared(); - PeakShapeFactory_sptr peakFactorySphere = boost::make_shared(); - PeakShapeFactory_sptr peakFactoryNone = boost::make_shared(); + PeakShapeFactory_sptr peakFactoryEllipsoid = + boost::make_shared(); + PeakShapeFactory_sptr peakFactorySphere = + boost::make_shared(); + PeakShapeFactory_sptr peakFactoryNone = + boost::make_shared(); peakFactoryEllipsoid->setSuccessor(peakFactorySphere); peakFactorySphere->setSuccessor(peakFactoryNone); @@ -1157,16 +1186,16 @@ API::Workspace_sptr LoadNexusProcessed::loadPeaksEntry(NXEntry &entry) { boost::trim_right(shapeJSON); // Make the shape - Mantid::Geometry::PeakShape* peakShape = peakFactoryEllipsoid->create(shapeJSON); + Mantid::Geometry::PeakShape *peakShape = + peakFactoryEllipsoid->create(shapeJSON); // Set the shape peakWS->getPeak(i).setPeakShape(peakShape); - } } } -return boost::static_pointer_cast(peakWS); + return boost::static_pointer_cast(peakWS); } //------------------------------------------------------------------------------------------------- @@ -1179,18 +1208,15 @@ return boost::static_pointer_cast(peakWS); * @param progressRange progress made after loading an entry * @param mtd_entry Nexus entry for "mantid_workspace_..." * @param xlength bins in the "X" axis (xbins) - * @param workspaceType Takes values like "Workspace2D", "RebinnedOutput", etc. + * @param workspaceType Takes values like "Workspace2D", "RebinnedOutput", + *etc. * * @return workspace object containing loaded data */ -API::MatrixWorkspace_sptr -LoadNexusProcessed::loadNonEventEntry(NXData &wksp_cls, - NXDouble &xbins, - const double &progressStart, - const double &progressRange, - const NXEntry &mtd_entry, - const int xlength, - std::string &workspaceType) { +API::MatrixWorkspace_sptr LoadNexusProcessed::loadNonEventEntry( + NXData &wksp_cls, NXDouble &xbins, const double &progressStart, + const double &progressRange, const NXEntry &mtd_entry, const int xlength, + std::string &workspaceType) { // Filter the list of spectra to process, applying min/max/list options NXDataSetTyped data = wksp_cls.openDoubleData(); int64_t nchannels = data.dim1(); @@ -1212,8 +1238,8 @@ LoadNexusProcessed::loadNonEventEntry(NXData &wksp_cls, API::MatrixWorkspace_sptr local_workspace = boost::dynamic_pointer_cast( - WorkspaceFactory::Instance().create(workspaceType, total_specs, xlength, - nchannels)); + WorkspaceFactory::Instance().create(workspaceType, total_specs, + xlength, nchannels)); try { local_workspace->setTitle(mtd_entry.getString("title")); } catch (std::runtime_error &) { @@ -1264,16 +1290,16 @@ LoadNexusProcessed::loadNonEventEntry(NXData &wksp_cls, for (; hist_index < read_stop;) { progress(progressBegin + - progressScaler * static_cast(hist_index) / - static_cast(read_stop), + 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); + loadBlock(data, errors, fracarea, hasFracArea, finalblock, nchannels, + hist_index, wsIndex, local_workspace); } } // if spectrum list property is set read each spectrum separately by @@ -1283,8 +1309,8 @@ LoadNexusProcessed::loadNonEventEntry(NXData &wksp_cls, for (; itr != m_spec_list.end(); ++itr) { int64_t specIndex = (*itr) - 1; progress(progressBegin + - progressScaler * static_cast(specIndex) / - static_cast(m_spec_list.size()), + progressScaler * static_cast(specIndex) / + static_cast(m_spec_list.size()), "Reading workspace data..."); loadBlock(data, errors, fracarea, hasFracArea, static_cast(1), nchannels, specIndex, wsIndex, @@ -1294,8 +1320,8 @@ LoadNexusProcessed::loadNonEventEntry(NXData &wksp_cls, } else { for (; hist_index < read_stop;) { progress(progressBegin + - progressScaler * static_cast(hist_index) / - static_cast(read_stop), + progressScaler * static_cast(hist_index) / + static_cast(read_stop), "Reading workspace data..."); loadBlock(data, errors, fracarea, hasFracArea, blocksize, nchannels, hist_index, wsIndex, local_workspace); @@ -1322,8 +1348,8 @@ LoadNexusProcessed::loadNonEventEntry(NXData &wksp_cls, for (; hist_index < read_stop;) { progress(progressBegin + - progressScaler * static_cast(hist_index) / - static_cast(read_stop), + 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); @@ -1340,8 +1366,8 @@ LoadNexusProcessed::loadNonEventEntry(NXData &wksp_cls, for (; itr != m_spec_list.end(); ++itr) { int64_t specIndex = (*itr) - 1; progress(progressBegin + - progressScaler * static_cast(specIndex) / - static_cast(read_stop), + progressScaler * static_cast(specIndex) / + static_cast(read_stop), "Reading workspace data..."); loadBlock(data, errors, fracarea, hasFracArea, xbins, 1, nchannels, specIndex, wsIndex, local_workspace); @@ -1350,8 +1376,8 @@ LoadNexusProcessed::loadNonEventEntry(NXData &wksp_cls, } else { for (; hist_index < read_stop;) { progress(progressBegin + - progressScaler * static_cast(hist_index) / - static_cast(read_stop), + 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); @@ -1372,7 +1398,8 @@ LoadNexusProcessed::loadNonEventEntry(NXData &wksp_cls, * * @param root :: The opened root node * @param entry_name :: The entry name - * @param progressStart :: The percentage value to start the progress reporting + * @param progressStart :: The percentage value to start the progress + *reporting * for this entry * @param progressRange :: The percentage range that the progress reporting * should cover @@ -1457,7 +1484,8 @@ API::Workspace_sptr LoadNexusProcessed::loadEntry(NXRoot &root, label->setLabel(ax.attributes("caption"), ax.attributes("label")); } - // If this doesn't throw then it is a numeric access so grab the data so we + // 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) @@ -1593,7 +1621,8 @@ void LoadNexusProcessed::readInstrumentGroup( //------------------------------------------------------------------------------------------------- /** - * Loads the information contained in non-Spectra (ie, Text or Numeric) axis in + * 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 @@ -1713,7 +1742,8 @@ void LoadNexusProcessed::getWordsInString(const std::string &words4, //------------------------------------------------------------------------------------------------- /** - * Read the bin masking information from the mantid_workspace_i/workspace group. + * 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 */ @@ -1742,7 +1772,8 @@ LoadNexusProcessed::readBinMasking(NXData &wksp_cls, } /** - * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given + * 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 @@ -1797,7 +1828,8 @@ void LoadNexusProcessed::loadBlock(NXDataSetTyped &data, } /** - * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given + * 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 @@ -1855,7 +1887,8 @@ void LoadNexusProcessed::loadBlock(NXDataSetTyped &data, } /** - * Perform a call to nxgetslab, via the NexusClasses wrapped methods for a given + * 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 @@ -1993,7 +2026,7 @@ LoadNexusProcessed::calculateWorkspaceSize(const std::size_t numberofspectra, if (gen_filtered_list) { m_filtered_spec_idxs.resize(total_specs); size_t j = 0; - for(int64_t si = m_spec_min; si < m_spec_max; si++, j++) + for (int64_t si = m_spec_min; si < m_spec_max; si++, j++) m_filtered_spec_idxs[j] = si; } } else { @@ -2018,8 +2051,7 @@ LoadNexusProcessed::calculateWorkspaceSize(const std::size_t numberofspectra, // example: min: 2, max: 8, list: 3,4,5,10,12; // result: 2,3,...,7,8,10,12 m_filtered_spec_idxs.insert(m_filtered_spec_idxs.end(), - m_spec_list.begin(), - m_spec_list.end()); + m_spec_list.begin(), m_spec_list.end()); } } } else { @@ -2029,8 +2061,8 @@ LoadNexusProcessed::calculateWorkspaceSize(const std::size_t numberofspectra, if (gen_filtered_list) { m_filtered_spec_idxs.resize(total_specs, 0); - for(int64_t j = 0; j < total_specs; j++) - m_filtered_spec_idxs[j] = m_spec_min+j; + for (int64_t j = 0; j < total_specs; j++) + m_filtered_spec_idxs[j] = m_spec_min + j; } } return total_specs; diff --git a/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h b/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h index 0f5665b67381..c2b5c23bab10 100644 --- a/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h +++ b/Code/Mantid/Framework/DataHandling/test/LoadNexusProcessedTest.h @@ -2,26 +2,34 @@ #define LOADNEXUSPROCESSEDTEST_H_ #include "MantidAPI/AlgorithmManager.h" +#include "MantidAPI/FileFinder.h" #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/MatrixWorkspace.h" #include "MantidAPI/WorkspaceGroup.h" -#include "MantidDataHandling/LoadInstrument.h" #include "MantidDataObjects/EventWorkspace.h" +#include "MantidDataObjects/PeakShapeSpherical.h" +#include "MantidDataObjects/Peak.h" +#include "MantidDataObjects/PeaksWorkspace.h" +#include "MantidGeometry/IDTypes.h" #include "MantidGeometry/Instrument.h" +#include "MantidGeometry/Instrument/InstrumentDefinitionParser.h" #include "MantidDataHandling/LoadNexusProcessed.h" #include "MantidDataHandling/SaveNexusProcessed.h" #include "MantidDataHandling/Load.h" +#include "MantidDataHandling/LoadInstrument.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" + #include "SaveNexusProcessedTest.h" + +#include + #include -#include + +#include + #include -#include -#include "MantidGeometry/IDTypes.h" -#include "MantidTestHelpers/WorkspaceCreationHelper.h" -#include "MantidDataObjects/PeakShapeSpherical.h" -#include "MantidDataObjects/Peak.h" -#include "MantidDataObjects/PeaksWorkspace.h" +using namespace Mantid::Geometry; using namespace Mantid::Kernel; using namespace Mantid::DataObjects; using namespace Mantid::API; @@ -813,9 +821,111 @@ class LoadNexusProcessedTest: public CxxTest::TestSuite Workspace_sptr ws = loadAlg.getProperty("OutputWorkspace"); auto peakWS = boost::dynamic_pointer_cast(ws); TS_ASSERT(peakWS); + } + void test_coordinates_saved_and_loaded_on_peaks_workspace() + { + auto peaksTestWS = WorkspaceCreationHelper::createPeaksWorkspace(); + // Loading a peaks workspace without a instrument from an IDF doesn't work ... + const std::string filename = FileFinder::Instance().getFullPath( + "IDFs_for_UNIT_TESTING/MINITOPAZ_Definition.xml"); + InstrumentDefinitionParser parser; + parser.initialize(filename, "MINITOPAZ", Strings::loadFile(filename)); + auto instrument = parser.parseXML(NULL); + peaksTestWS->populateInstrumentParameters(); + peaksTestWS->setInstrument(instrument); + + const SpecialCoordinateSystem appliedCoordinateSystem = QSample; + peaksTestWS->setCoordinateSystem(appliedCoordinateSystem); + + SaveNexusProcessed saveAlg; + saveAlg.setChild(true); + saveAlg.initialize(); + saveAlg.setProperty("InputWorkspace", peaksTestWS); + saveAlg.setPropertyValue("Filename", "LoadAndSaveNexusProcessedCoordinateSystem.nxs"); + saveAlg.execute(); + std::string filePath = saveAlg.getPropertyValue("Filename"); + + LoadNexusProcessed loadAlg; + loadAlg.setChild(true); + loadAlg.initialize(); + loadAlg.setPropertyValue("Filename", filePath); + loadAlg.setPropertyValue("OutputWorkspace", "__unused"); + loadAlg.execute(); + + Mantid::API::Workspace_sptr loadedWS = loadAlg.getProperty("OutputWorkspace"); + auto loadedPeaksWS = + boost::dynamic_pointer_cast(loadedWS); + Poco::File testFile(filePath); + if(testFile.exists()) + { + testFile.remove(); + } + + TS_ASSERT_EQUALS(appliedCoordinateSystem, loadedPeaksWS->getSpecialCoordinateSystem()); + } + + // backwards compatability check + void test_coordinates_saved_and_loaded_on_peaks_workspace_from_expt_info() + { + auto peaksTestWS = WorkspaceCreationHelper::createPeaksWorkspace(); + // Loading a peaks workspace without a instrument from an IDF doesn't work ... + const std::string filename = FileFinder::Instance().getFullPath( + "IDFs_for_UNIT_TESTING/MINITOPAZ_Definition.xml"); + InstrumentDefinitionParser parser; + parser.initialize(filename, "MINITOPAZ", Strings::loadFile(filename)); + auto instrument = parser.parseXML(NULL); + peaksTestWS->populateInstrumentParameters(); + peaksTestWS->setInstrument(instrument); + + // simulate old-style file with "CoordinateSystem" log + const SpecialCoordinateSystem appliedCoordinateSystem = QSample; + peaksTestWS->logs()->addProperty("CoordinateSystem", + static_cast(appliedCoordinateSystem)); + + SaveNexusProcessed saveAlg; + saveAlg.setChild(true); + saveAlg.initialize(); + saveAlg.setProperty("InputWorkspace", peaksTestWS); + saveAlg.setPropertyValue("Filename", "LoadAndSaveNexusProcessedCoordinateSystemOldFormat.nxs"); + saveAlg.execute(); + std::string filePath = saveAlg.getPropertyValue("Filename"); + + // Remove the coordinate_system entry so it falls back on the log. NeXus + // can't do this so use the HDF5 API directly + auto fid = H5Fopen(filePath.c_str(), H5F_ACC_RDWR, H5P_DEFAULT); + auto mantid_id = H5Gopen(fid, "mantid_workspace_1", H5P_DEFAULT); + auto peaks_id = H5Gopen(mantid_id, "peaks_workspace", H5P_DEFAULT); + if (peaks_id > 0) { + H5Ldelete(peaks_id, "coordinate_system", H5P_DEFAULT); + H5Gclose(peaks_id); + H5Gclose(mantid_id); + } else { + TS_FAIL("Cannot unlink coordinate_system group. Test file has unexpected " + "structure."); + } + H5Fclose(fid); + + LoadNexusProcessed loadAlg; + loadAlg.setChild(true); + loadAlg.initialize(); + loadAlg.setPropertyValue("Filename", filePath); + loadAlg.setPropertyValue("OutputWorkspace", "__unused"); + loadAlg.execute(); + + Mantid::API::Workspace_sptr loadedWS = loadAlg.getProperty("OutputWorkspace"); + auto loadedPeaksWS = + boost::dynamic_pointer_cast(loadedWS); + Poco::File testFile(filePath); + if(testFile.exists()) + { + testFile.remove(); + } + + TS_ASSERT_EQUALS(appliedCoordinateSystem, loadedPeaksWS->getSpecialCoordinateSystem()); } + void testTableWorkspace_vectorColumn() { // Create a table we will save diff --git a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/PeaksWorkspace.h b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/PeaksWorkspace.h index 4c4efe464c89..4a4d217689ee 100644 --- a/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/PeaksWorkspace.h +++ b/Code/Mantid/Framework/DataObjects/inc/MantidDataObjects/PeaksWorkspace.h @@ -109,11 +109,11 @@ class DLLExport PeaksWorkspace : public Mantid::API::IPeaksWorkspace { const Peak &getPeak(int peakNum) const; API::IPeak *createPeak(Kernel::V3D QFrame, - boost::optional detectorDistance = boost::optional()) const; + boost::optional detectorDistance = + boost::optional()) const; std::vector> peakInfo(Kernel::V3D qFrame, bool labCoords) const; - Peak *createPeakHKL(Kernel::V3D HKL) const; int peakInfoNumber(Kernel::V3D qFrame, bool labCoords) const; @@ -129,12 +129,11 @@ class DLLExport PeaksWorkspace : public Mantid::API::IPeaksWorkspace { API::ITableWorkspace_sptr createDetectorTable() const; /// Set the special coordinate system. - virtual void setCoordinateSystem( - const Mantid::Kernel::SpecialCoordinateSystem coordinateSystem); + virtual void + setCoordinateSystem(const Kernel::SpecialCoordinateSystem coordinateSystem); /// Get the special coordinate system. - virtual Mantid::Kernel::SpecialCoordinateSystem - getSpecialCoordinateSystem() const; + Kernel::SpecialCoordinateSystem getSpecialCoordinateSystem() const; // ====================================== ITableWorkspace Methods // ================================== @@ -183,15 +182,6 @@ class DLLExport PeaksWorkspace : public Mantid::API::IPeaksWorkspace { void saveNexus(::NeXus::File *file) const; private: - /** Vector of Peak contained within. */ - std::vector peaks; - - /** Column shared pointers. */ - std::vector> columns; - - /** Column names */ - std::vector columnNames; - /// Initialize the table structure void initColumns(); /// Adds a new PeakColumn of the given type @@ -275,6 +265,18 @@ class DLLExport PeaksWorkspace : public Mantid::API::IPeaksWorkspace { // ====================================== End ITableWorkspace Methods // ================================== + /** Vector of Peak contained within. */ + std::vector peaks; + + /** Column shared pointers. */ + std::vector> columns; + + /** Column names */ + std::vector columnNames; + + /// Coordinates + Kernel::SpecialCoordinateSystem m_coordSystem; + // adapter for logs() function, which create reference to this class itself // and does not allow to delete the shared pointers, // returned by logs() function when they go out of scope diff --git a/Code/Mantid/Framework/DataObjects/src/PeaksWorkspace.cpp b/Code/Mantid/Framework/DataObjects/src/PeaksWorkspace.cpp index 83aabf18e3fd..4259cce7f869 100644 --- a/Code/Mantid/Framework/DataObjects/src/PeaksWorkspace.cpp +++ b/Code/Mantid/Framework/DataObjects/src/PeaksWorkspace.cpp @@ -38,15 +38,16 @@ namespace DataObjects { /// Register the workspace as a type DECLARE_WORKSPACE(PeaksWorkspace); -// Kernel::Logger& PeaksWorkspace::g_log = -// Kernel::Logger::get("PeaksWorkspace"); - //--------------------------------------------------------------------------------------------- /** Constructor. Create a table with all the required columns. * * @return PeaksWorkspace object */ -PeaksWorkspace::PeaksWorkspace() : IPeaksWorkspace() { initColumns(); } +PeaksWorkspace::PeaksWorkspace() + : IPeaksWorkspace(), peaks(), columns(), columnNames(), + m_coordSystem(None) { + initColumns(); +} //--------------------------------------------------------------------------------------------- /** Virtual constructor. Clone method to duplicate the peaks workspace. @@ -65,7 +66,8 @@ PeaksWorkspace *PeaksWorkspace::clone() const { * @return */ PeaksWorkspace::PeaksWorkspace(const PeaksWorkspace &other) - : IPeaksWorkspace(other), peaks(other.peaks) { + : IPeaksWorkspace(other), peaks(other.peaks), columns(), columnNames(), + m_coordSystem(other.m_coordSystem) { initColumns(); } @@ -199,11 +201,13 @@ const Peak &PeaksWorkspace::getPeak(const int peakNum) const { //--------------------------------------------------------------------------------------------- /** Creates an instance of a Peak BUT DOES NOT ADD IT TO THE WORKSPACE * @param QLabFrame :: Q of the center of the peak, in reciprocal space - * @param detectorDistance :: optional distance between the sample and the detector. You do NOT need to explicitly provide this distance. + * @param detectorDistance :: optional distance between the sample and the + * detector. You do NOT need to explicitly provide this distance. * @return a pointer to a new Peak object. */ -API::IPeak *PeaksWorkspace::createPeak(Kernel::V3D QLabFrame, - boost::optional detectorDistance) const { +API::IPeak * +PeaksWorkspace::createPeak(Kernel::V3D QLabFrame, + boost::optional detectorDistance) const { return new Peak(this->getInstrument(), QLabFrame, detectorDistance); } @@ -395,31 +399,33 @@ PeaksWorkspace::peakInfo(Kernel::V3D qFrame, bool labCoords) const { * @param HKL : reciprocal lattice vector coefficients * @return Fully formed peak. */ -Peak *PeaksWorkspace::createPeakHKL(V3D HKL) const -{ - /* - The following allows us to add peaks where we have a single UB to work from. - */ +Peak *PeaksWorkspace::createPeakHKL(V3D HKL) const { + /* + The following allows us to add peaks where we have a single UB to work from. + */ - Geometry::OrientedLattice lattice = this->sample().getOrientedLattice(); - Geometry::Goniometer goniometer = this->run().getGoniometer(); + Geometry::OrientedLattice lattice = this->sample().getOrientedLattice(); + Geometry::Goniometer goniometer = this->run().getGoniometer(); - // Calculate qLab from q HKL. As per Busing and Levy 1967, q_lab_frame = 2pi * Goniometer * UB * HKL - V3D qLabFrame = goniometer.getR() * lattice.getUB() * HKL * 2 * M_PI; + // Calculate qLab from q HKL. As per Busing and Levy 1967, q_lab_frame = 2pi * + // Goniometer * UB * HKL + V3D qLabFrame = goniometer.getR() * lattice.getUB() * HKL * 2 * M_PI; - // create a peak using the qLab frame - auto peak = new Peak(this->getInstrument(), qLabFrame); // This should calculate the detector positions too. + // create a peak using the qLab frame + auto peak = + new Peak(this->getInstrument(), + qLabFrame); // This should calculate the detector positions too. - // We need to set HKL separately to keep things consistent. - peak->setHKL(HKL[0], HKL[1], HKL[2]); + // We need to set HKL separately to keep things consistent. + peak->setHKL(HKL[0], HKL[1], HKL[2]); - // Set the goniometer - peak->setGoniometerMatrix(goniometer.getR()); + // Set the goniometer + peak->setGoniometerMatrix(goniometer.getR()); - // Take the run number from this - peak->setRunNumber(this->getRunNumber()); + // Take the run number from this + peak->setRunNumber(this->getRunNumber()); - return peak; + return peak; } /** @@ -652,9 +658,8 @@ void PeaksWorkspace::saveNexus(::NeXus::File *file) const { } const std::string shapeJSON = p.getPeakShape().toJSON(); shapes[i] = shapeJSON; - if(shapeJSON.size() > maxShapeJSONLength) - { - maxShapeJSONLength = shapeJSON.size(); + if (shapeJSON.size() > maxShapeJSONLength) { + maxShapeJSONLength = shapeJSON.size(); } } @@ -665,6 +670,9 @@ void PeaksWorkspace::saveNexus(::NeXus::File *file) const { file->makeGroup("peaks_workspace", "NXentry", true); // For when peaksWorkspace can be loaded + // Coordinate system + file->writeData("coordinate_system", static_cast(m_coordSystem)); + // Detectors column file->writeData("column_1", detectorID); file->openData("column_1"); @@ -801,7 +809,8 @@ void PeaksWorkspace::saveNexus(::NeXus::File *file) const { std::string rowStr = shapes[ii]; for (size_t ic = 0; ic < rowStr.size(); ic++) toNexus[ii * maxShapeJSONLength + ic] = rowStr[ic]; - for (size_t ic = rowStr.size(); ic < static_cast(maxShapeJSONLength); ic++) + for (size_t ic = rowStr.size(); + ic < static_cast(maxShapeJSONLength); ic++) toNexus[ii * maxShapeJSONLength + ic] = ' '; } @@ -813,7 +822,6 @@ void PeaksWorkspace::saveNexus(::NeXus::File *file) const { file->putAttr("interpret_as", specifyString); file->closeData(); - // QLab & QSample are calculated and do not need to be saved file->closeGroup(); // end of peaks workpace @@ -824,25 +832,16 @@ void PeaksWorkspace::saveNexus(::NeXus::File *file) const { * @param coordinateSystem : Option to set. */ void PeaksWorkspace::setCoordinateSystem( - const Mantid::Kernel::SpecialCoordinateSystem coordinateSystem) { - this->mutableRun().addProperty("CoordinateSystem", (int)coordinateSystem, - true); + const Kernel::SpecialCoordinateSystem coordinateSystem) { + m_coordSystem = coordinateSystem; } /** * @return the special Q3D coordinate system. */ -Mantid::Kernel::SpecialCoordinateSystem +Kernel::SpecialCoordinateSystem PeaksWorkspace::getSpecialCoordinateSystem() const { - Mantid::Kernel::SpecialCoordinateSystem result = None; - try { - Property *prop = this->run().getProperty("CoordinateSystem"); - PropertyWithValue *p = dynamic_cast *>(prop); - int temp = *p; - result = (SpecialCoordinateSystem)temp; - } catch (Mantid::Kernel::Exception::NotFoundError &) { - } - return result; + return m_coordSystem; } // prevent shared pointer from deleting this diff --git a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/LoadMD.h b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/LoadMD.h index dbf60ce1b9dd..1377fd4dc122 100644 --- a/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/LoadMD.h +++ b/Code/Mantid/Framework/MDAlgorithms/inc/MantidMDAlgorithms/LoadMD.h @@ -75,6 +75,8 @@ class DLLExport LoadMD : public API::IFileLoader { void loadDimensions(); + void loadCoordinateSystem(); + /// Load all the affine matricies void loadAffineMatricies(API::IMDWorkspace_sptr ws); /// Load a given affine matrix @@ -91,6 +93,8 @@ class DLLExport LoadMD : public API::IFileLoader { /// Each dimension object loaded. std::vector m_dims; + /// Coordinate system + Kernel::SpecialCoordinateSystem m_coordSystem; /// load only the box structure with empty boxes but do not tload boxes events bool m_BoxStructureAndMethadata; }; diff --git a/Code/Mantid/Framework/MDAlgorithms/src/LoadMD.cpp b/Code/Mantid/Framework/MDAlgorithms/src/LoadMD.cpp index 022116b59415..d50f3f3a3686 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/LoadMD.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/LoadMD.cpp @@ -40,7 +40,8 @@ DECLARE_NEXUS_FILELOADER_ALGORITHM(LoadMD); /** Constructor */ LoadMD::LoadMD() - : m_numDims(0), // uninitialized incorrect value + : m_numDims(0), // uninitialized incorrect value + m_coordSystem(None), m_BoxStructureAndMethadata(true) // this is faster but rarely needed. {} @@ -168,6 +169,8 @@ void LoadMD::exec() { // Now load all the dimension xml this->loadDimensions(); + // Coordinate system + this->loadCoordinateSystem(); if (entryName == "MDEventWorkspace") { // The type of event @@ -233,6 +236,9 @@ void LoadMD::loadHisto() { // Now the ExperimentInfo MDBoxFlatTree::loadExperimentInfos(m_file.get(), m_filename, ws); + // Coordinate system + ws->setCoordinateSystem(m_coordSystem); + // Load the WorkspaceHistory "process" ws->history().loadNexus(m_file.get()); @@ -267,6 +273,30 @@ void LoadMD::loadDimensions() { } } +/** Load the coordinate system **/ +void LoadMD::loadCoordinateSystem() { + // Current version stores the coordinate system + // in its own field. The first version stored it + // as a log value so fallback on that if it can't + // be found. + try { + uint32_t readCoord(0); + m_file->readData("coordinate_system", readCoord); + m_coordSystem = static_cast(readCoord); + } catch (::NeXus::Exception &) { + auto pathOnEntry = m_file->getPath(); + try { + m_file->openPath(pathOnEntry + "/experiment0/logs/CoordinateSystem"); + int readCoord(0); + m_file->readData("value", readCoord); + m_coordSystem = static_cast(readCoord); + } catch (::NeXus::Exception &) { + } + // return to where we started + m_file->openPath(pathOnEntry); + } +} + //---------------------------------------------------------------------------------------------- /** Do the loading. * @@ -302,6 +332,9 @@ void LoadMD::doLoad(typename MDEventWorkspace::sptr ws) { for (size_t d = 0; d < nd; d++) ws->addDimension(m_dims[d]); + // Coordinate system + ws->setCoordinateSystem(m_coordSystem); + // ----------------------------------------- Box Structure // ------------------------------ prog->report("Reading box structure from HDD."); diff --git a/Code/Mantid/Framework/MDAlgorithms/src/SaveMD.cpp b/Code/Mantid/Framework/MDAlgorithms/src/SaveMD.cpp index 8d7503fa945e..e515be24ad82 100644 --- a/Code/Mantid/Framework/MDAlgorithms/src/SaveMD.cpp +++ b/Code/Mantid/Framework/MDAlgorithms/src/SaveMD.cpp @@ -235,6 +235,10 @@ void SaveMD::doSaveHisto(Mantid::MDEvents::MDHistoWorkspace_sptr ws) { // The base entry. Named so as to distinguish from other workspace types. file->makeGroup("MDHistoWorkspace", "NXentry", true); + // Write out the coordinate system + file->writeData("coordinate_system", + static_cast(ws->getSpecialCoordinateSystem())); + // Save the algorithm history under "process" ws->getHistory().saveNexus(file); diff --git a/Code/Mantid/Framework/MDAlgorithms/test/LoadMDTest.h b/Code/Mantid/Framework/MDAlgorithms/test/LoadMDTest.h index 0fc5b9c92601..179d58265ca6 100644 --- a/Code/Mantid/Framework/MDAlgorithms/test/LoadMDTest.h +++ b/Code/Mantid/Framework/MDAlgorithms/test/LoadMDTest.h @@ -17,6 +17,8 @@ #include "MantidAPI/ExperimentInfo.h" #include "MantidMDAlgorithms/LoadMD.h" +#include + using namespace Mantid; using namespace Mantid::MDEvents; using namespace Mantid::MDAlgorithms; @@ -531,44 +533,122 @@ class LoadMDTest : public CxxTest::TestSuite } /// More of an integration test as it uses both load and save. - void test_save_and_load_special_coordinates() - { - MDEventWorkspace1Lean::sptr ws = MDEventsTestHelper::makeMDEW<1>(10, 0.0, 10.0, 2); - // Set the special coordinate system + void test_save_and_load_special_coordinates_MDEventWorkspace() { + MDEventWorkspace1Lean::sptr mdeventWS = + MDEventsTestHelper::makeMDEW<1>(10, 0.0, 10.0, 2); + const SpecialCoordinateSystem appliedCoordinateSystem = QSample; + mdeventWS->setCoordinateSystem(appliedCoordinateSystem); + + auto loadedWS = testSaveAndLoadWorkspace(mdeventWS, "MDEventWorkspace"); + // Check that the special coordinate system is the same before the save-load + // cycle. + TS_ASSERT_EQUALS(appliedCoordinateSystem, + loadedWS->getSpecialCoordinateSystem()); + } + + // backwards-compatability check for coordinate in log + void test_load_coordinate_system_MDEventWorkspace_from_experiment_info() { + MDEventWorkspace1Lean::sptr mdeventWS = + MDEventsTestHelper::makeMDEW<1>(10, 0.0, 10.0, 2); const SpecialCoordinateSystem appliedCoordinateSystem = QSample; - ws->setCoordinateSystem(appliedCoordinateSystem); + mdeventWS->setCoordinateSystem(appliedCoordinateSystem); + + // Create a log in the first experiment info to simulated an old version of + // the file + auto expt0 = mdeventWS->getExperimentInfo(0); + expt0->mutableRun().addProperty("CoordinateSystem", + static_cast(appliedCoordinateSystem)); + + const bool rmCoordField(true); + auto loadedWS = + testSaveAndLoadWorkspace(mdeventWS, "MDEventWorkspace", rmCoordField); + // Check that the special coordinate system is the same before the save-load + // cycle. + TS_ASSERT_EQUALS(appliedCoordinateSystem, + loadedWS->getSpecialCoordinateSystem()); + } - const std::string inputWSName = "SaveMDSpecialCoordinatesTest"; - const std::string fileName = inputWSName + ".nxs"; - AnalysisDataService::Instance().addOrReplace(inputWSName, ws); + void test_save_and_load_special_coordinates_MDHistoWorkspace() { + auto mdhistoWS = MDEventsTestHelper::makeFakeMDHistoWorkspace( + 2.5, 2, 10, 10.0, 3.5, "", 4.5); + const SpecialCoordinateSystem appliedCoordinateSystem = QSample; + mdhistoWS->setCoordinateSystem(appliedCoordinateSystem); + + auto loadedWS = testSaveAndLoadWorkspace(mdhistoWS, "MDHistoWorkspace"); + // Check that the special coordinate system is the same before the save-load + // cycle. + TS_ASSERT_EQUALS(appliedCoordinateSystem, + loadedWS->getSpecialCoordinateSystem()); + } + // backwards-compatability check for coordinate in log + void test_load_coordinate_system_MDHistoWorkspace_from_experiment_info() { + auto mdhistoWS = MDEventsTestHelper::makeFakeMDHistoWorkspace( + 2.5, 2, 10, 10.0, 3.5, "", 4.5); + const SpecialCoordinateSystem appliedCoordinateSystem = QSample; + mdhistoWS->setCoordinateSystem(appliedCoordinateSystem); + + // Create a log in the first experiment info to simulated an old version of + // the file + auto expt0 = mdhistoWS->getExperimentInfo(0); + expt0->mutableRun().addProperty("CoordinateSystem", + static_cast(appliedCoordinateSystem)); + + const bool rmCoordField(true); + auto loadedWS = + testSaveAndLoadWorkspace(mdhistoWS, "MDHistoWorkspace", rmCoordField); + // Check that the special coordinate system is the same before the save-load + // cycle. + TS_ASSERT_EQUALS(appliedCoordinateSystem, + loadedWS->getSpecialCoordinateSystem()); + } + + Mantid::API::IMDWorkspace_sptr + testSaveAndLoadWorkspace(Mantid::API::IMDWorkspace_sptr inputWS, + const char *rootGroup, + const bool rmCoordField = false) { + const std::string fileName = "SaveMDSpecialCoordinatesTest.nxs"; SaveMD saveAlg; + saveAlg.setChild(true); saveAlg.initialize(); - saveAlg.isInitialized(); - saveAlg.setPropertyValue("InputWorkspace", inputWSName); + saveAlg.setProperty("InputWorkspace", inputWS); saveAlg.setPropertyValue("Filename", fileName); saveAlg.execute(); TS_ASSERT( saveAlg.isExecuted() ); std::string this_fileName = saveAlg.getProperty("Filename"); + if (rmCoordField) { + // Remove the coordinate_system entry so it falls back on the log. NeXus + // can't do this + // so use the HDF5 API directly + auto fid = H5Fopen(fileName.c_str(), H5F_ACC_RDWR, H5P_DEFAULT); + auto gid = H5Gopen(fid, rootGroup, H5P_DEFAULT); + if (gid > 0) { + H5Ldelete(gid, "coordinate_system", H5P_DEFAULT); + H5Gclose(gid); + } else { + TS_FAIL("Cannot open MDEventWorkspace group. Test file has unexpected " + "structure."); + } + H5Fclose(fid); + } + LoadMD loadAlg; + loadAlg.setChild(true); loadAlg.initialize(); loadAlg.isInitialized(); loadAlg.setPropertyValue("Filename", fileName); loadAlg.setProperty("FileBackEnd", false); - loadAlg.setPropertyValue("OutputWorkspace", "reloaded_again"); + loadAlg.setPropertyValue("OutputWorkspace", "_unused_for_child"); loadAlg.execute(); TS_ASSERT( loadAlg.isExecuted() ); - // Check that the special coordinate system is the same before the save-load cycle. - TS_ASSERT_EQUALS(appliedCoordinateSystem, ws->getSpecialCoordinateSystem()); - if (Poco::File(this_fileName).exists()) { Poco::File(this_fileName).remove(); } - AnalysisDataService::Instance().remove(inputWSName); - AnalysisDataService::Instance().remove("OutputWorkspace"); + + return loadAlg.getProperty("OutputWorkspace"); } void test_loadAffine() diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/Integrate3DEvents.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/Integrate3DEvents.h index 473b1b8103e1..d70da28336da 100644 --- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/Integrate3DEvents.h +++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/Integrate3DEvents.h @@ -55,19 +55,19 @@ namespace MDEvents { */ typedef Mantid::Kernel::Matrix DblMatrix; -typedef boost::unordered_map> EventListMap; +typedef boost::unordered_map > > EventListMap; typedef boost::unordered_map PeakQMap; class DLLExport Integrate3DEvents { public: /// Construct object to store events around peaks and integrate peaks - Integrate3DEvents(std::vector const &peak_q_list, DblMatrix const &UBinv, + Integrate3DEvents(std::vector > const &peak_q_list, DblMatrix const &UBinv, double radius); ~Integrate3DEvents(); /// Add event Q's to lists of events near peaks - void addEvents(std::vector const &event_qs); + void addEvents(std::vector > const &event_qs); /// Find the net integrated intensity of a peak, using ellipsoidal volumes boost::shared_ptr ellipseIntegrateEvents(Mantid::Kernel::V3D const &peak_q, bool specify_size, @@ -78,12 +78,12 @@ class DLLExport Integrate3DEvents { private: /// Calculate the number of events in an ellipsoid centered at 0,0,0 - static int numInEllipsoid(std::vector const &events, + static double numInEllipsoid(std::vector > const &events, std::vector const &directions, std::vector const &sizes); /// Calculate the 3x3 covariance matrix of a list of Q-vectors at 0,0,0 - static void makeCovarianceMatrix(std::vector const &events, + static void makeCovarianceMatrix(std::vector > const &events, DblMatrix &matrix, double radius); /// Calculate the eigen vectors of a 3x3 real symmetric matrix @@ -91,7 +91,7 @@ class DLLExport Integrate3DEvents { std::vector &eigen_vectors); /// Calculate the standard deviation of 3D events in a specified direction - static double stdDev(std::vector const &events, Mantid::Kernel::V3D const &direction, + static double stdDev(std::vector > const &events, Mantid::Kernel::V3D const &direction, double radius); /// Form a map key as 10^12*h + 10^6*k + l from the integers h, k, l @@ -101,11 +101,11 @@ class DLLExport Integrate3DEvents { int64_t getHklKey(Mantid::Kernel::V3D const &q_vector); /// Add an event to the vector of events for the closest h,k,l - void addEvent(Mantid::Kernel::V3D event_Q); + void addEvent(std::pair event_Q); /// Find the net integrated intensity of a list of Q's using ellipsoids boost::shared_ptr ellipseIntegrateEvents( - std::vector const &ev_list, std::vector const &directions, + std::vector > const &ev_list, std::vector const &directions, std::vector const &sigmas, bool specify_size, double peak_radius, double back_inner_radius, double back_outer_radius, std::vector &axes_radii, double &inti, double &sigi); diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventWorkspace.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventWorkspace.h index 4aaa6769320a..aa134a84b56d 100644 --- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventWorkspace.h +++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDEventWorkspace.h @@ -32,7 +32,13 @@ namespace MDEvents { * */ TMDE_CLASS class DLLExport MDEventWorkspace : public API::IMDEventWorkspace { + public: + /// Typedef for a shared pointer of this kind of event workspace + typedef boost::shared_ptr> sptr; + /// Typedef to access the MDEventType. + typedef MDE MDEventType; + MDEventWorkspace(); MDEventWorkspace(const MDEventWorkspace &other); virtual ~MDEventWorkspace(); @@ -119,9 +125,6 @@ class DLLExport MDEventWorkspace : public API::IMDEventWorkspace { size_t addEvents(const std::vector &events); - // void addManyEvents(const std::vector & events, - // Mantid::Kernel::ProgressBase * prog); - std::vector> getMinimumExtents(size_t depth = 2); @@ -149,13 +152,10 @@ class DLLExport MDEventWorkspace : public API::IMDEventWorkspace { /// Clear masking void clearMDMasking(); - /// Get the special coordinate system. - virtual Mantid::Kernel::SpecialCoordinateSystem - getSpecialCoordinateSystem() const; - - /// Set the special coordinate system. - void setCoordinateSystem( - const Mantid::Kernel::SpecialCoordinateSystem coordinateSystem); + /// Get the coordinate system. + Kernel::SpecialCoordinateSystem getSpecialCoordinateSystem() const; + /// Set the coordinate system. + void setCoordinateSystem(const Kernel::SpecialCoordinateSystem coordSystem); /// make the workspace file backed if it has not been already file backed; virtual void setFileBacked(const std::string &fileName); /// if workspace was file-backed, this should clear file-backed information @@ -167,14 +167,10 @@ class DLLExport MDEventWorkspace : public API::IMDEventWorkspace { MDBoxBase *data; /// Box controller in use - Mantid::API::BoxController_sptr m_BoxController; + API::BoxController_sptr m_BoxController; // boost::shared_ptr m_BoxController; private: -public: - /// Typedef for a shared pointer of this kind of event workspace - typedef boost::shared_ptr> sptr; - /// Typedef to access the MDEventType. - typedef MDE MDEventType; + Kernel::SpecialCoordinateSystem m_coordSystem; }; } // namespace MDEvents diff --git a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspace.h b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspace.h index 1bc89a29dc24..b43bb81ba1b6 100644 --- a/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspace.h +++ b/Code/Mantid/Framework/MDEvents/inc/MantidMDEvents/MDHistoWorkspace.h @@ -147,12 +147,11 @@ class DLLExport MDHistoWorkspace : public API::IMDHistoWorkspace { const coord_t *getBinWidths() const { return m_boxLength; } /// Get the special coordinate system. - virtual Mantid::Kernel::SpecialCoordinateSystem - getSpecialCoordinateSystem() const; + virtual Kernel::SpecialCoordinateSystem getSpecialCoordinateSystem() const; /// Set the special coordinate system. - void setCoordinateSystem( - const Mantid::Kernel::SpecialCoordinateSystem coordinateSystem); + void + setCoordinateSystem(const Kernel::SpecialCoordinateSystem coordinateSystem); void setTo(signal_t signal, signal_t errorSquared, signal_t numEvents); @@ -161,7 +160,7 @@ class DLLExport MDHistoWorkspace : public API::IMDHistoWorkspace { coord_t *getVertexesArray(size_t linearIndex, size_t &numVertices) const; - Mantid::Kernel::VMD getCenter(size_t linearIndex) const; + Kernel::VMD getCenter(size_t linearIndex) const; /// Returns the (normalized) signal at a given coordinates signal_t @@ -422,6 +421,8 @@ class DLLExport MDHistoWorkspace : public API::IMDHistoWorkspace { /// the number of events, contributed into the workspace; mutable uint64_t m_nEventsContributed; + Kernel::SpecialCoordinateSystem m_coordSystem; + protected: /// Linear array of masks for each bin bool *m_masks; diff --git a/Code/Mantid/Framework/MDEvents/src/Integrate3DEvents.cpp b/Code/Mantid/Framework/MDEvents/src/Integrate3DEvents.cpp index acdee6cc6b26..be5badfbf2b9 100644 --- a/Code/Mantid/Framework/MDEvents/src/Integrate3DEvents.cpp +++ b/Code/Mantid/Framework/MDEvents/src/Integrate3DEvents.cpp @@ -33,16 +33,16 @@ using Mantid::Kernel::V3D; * an event to be stored in the list associated with * that peak. */ -Integrate3DEvents::Integrate3DEvents(std::vector const &peak_q_list, +Integrate3DEvents::Integrate3DEvents(std::vector> const &peak_q_list, DblMatrix const &UBinv, double radius) { this->UBinv = UBinv; this->radius = radius; int64_t hkl_key; - for (auto it = peak_q_list.begin(); it != peak_q_list.end(); ++it) { - hkl_key = getHklKey(*it); + for (size_t it = 0; it != peak_q_list.size(); ++it) { + hkl_key = getHklKey(peak_q_list[it].second); if (hkl_key != 0) // only save if hkl != (0,0,0) - peak_qs[hkl_key] = *it; + peak_qs[hkl_key] = peak_q_list[it].second; } } @@ -67,7 +67,7 @@ Integrate3DEvents::~Integrate3DEvents() {} * @param event_qs List of event Q vectors to add to lists of Q's associated * with peaks. */ -void Integrate3DEvents::addEvents(std::vector const &event_qs) { +void Integrate3DEvents::addEvents(std::vector > const &event_qs) { for (size_t i = 0; i < event_qs.size(); i++) { addEvent(event_qs[i]); } @@ -120,7 +120,12 @@ Mantid::Geometry::PeakShape_const_sptr Integrate3DEvents::ellipseIntegrateEvents return boost::make_shared(); } - std::vector &some_events = event_lists[hkl_key]; + std::vector > &some_events = event_lists[hkl_key]; + for (size_t it = 0; it != some_events.size(); ++it) { + hkl_key = getHklKey(some_events[it].second); + if (hkl_key != 0) // only save if hkl != (0,0,0) + peak_qs[hkl_key] = some_events[it].second; + } if (some_events.size() < 3) // if there are not enough events to { // find covariance matrix, return @@ -170,18 +175,18 @@ Mantid::Geometry::PeakShape_const_sptr Integrate3DEvents::ellipseIntegrateEvents * of the three axes of the ellisoid. * @return Then number of events that are in or on the specified ellipsoid. */ -int Integrate3DEvents::numInEllipsoid(std::vector const &events, +double Integrate3DEvents::numInEllipsoid(std::vector> const &events, std::vector const &directions, std::vector const &sizes) { - int count = 0; + double count = 0; for (size_t i = 0; i < events.size(); i++) { double sum = 0; for (size_t k = 0; k < 3; k++) { - double comp = events[i].scalar_prod(directions[k]) / sizes[k]; + double comp = events[i].second.scalar_prod(directions[k]) / sizes[k]; sum += comp * comp; } if (sum <= 1) - count++; + count += events[i].first; } return count; @@ -209,14 +214,16 @@ int Integrate3DEvents::numInEllipsoid(std::vector const &events, * peak center (0,0,0) will be used for * calculating the covariance matrix. */ -void Integrate3DEvents::makeCovarianceMatrix(std::vector const &events, + +void Integrate3DEvents::makeCovarianceMatrix(std::vector > const &events, DblMatrix &matrix, double radius) { for (int row = 0; row < 3; row++) { for (int col = 0; col < 3; col++) { double sum = 0; for (size_t i = 0; i < events.size(); i++) { - if (events[i].norm() <= radius) { - sum += events[i][row] * events[i][col]; + auto event = events[i].second; + if (event.norm() <= radius) { + sum += event[row] * event[col]; } } if (events.size() > 1) @@ -275,7 +282,7 @@ void Integrate3DEvents::getEigenVectors(DblMatrix const &cov_matrix, * @param radius Maximun size of event vectors that will be used * in calculating the standard deviation. */ -double Integrate3DEvents::stdDev(std::vector const &events, +double Integrate3DEvents::stdDev(std::vector > const &events, V3D const &direction, double radius) { double sum = 0; double sum_sq = 0; @@ -283,8 +290,9 @@ double Integrate3DEvents::stdDev(std::vector const &events, int count = 0; for (size_t i = 0; i < events.size(); i++) { - if (events[i].norm() <= radius) { - double dot_prod = events[i].scalar_prod(direction); + auto event = events[i].second; + if (event.norm() <= radius) { + double dot_prod = event.scalar_prod(direction); sum += dot_prod; sum_sq += dot_prod * dot_prod; count++; @@ -343,8 +351,8 @@ int64_t Integrate3DEvents::getHklKey(V3D const &q_vector) { * @param event_Q The Q-vector for the event that may be added to the * event_lists map, if it is close enough to some peak */ -void Integrate3DEvents::addEvent(V3D event_Q) { - int64_t hkl_key = getHklKey(event_Q); +void Integrate3DEvents::addEvent(std::pair event_Q) { + int64_t hkl_key = getHklKey(event_Q.second); if (hkl_key == 0) // don't keep events associated with 0,0,0 return; @@ -353,8 +361,8 @@ void Integrate3DEvents::addEvent(V3D event_Q) { if (peak_it != peak_qs.end()) { if (!peak_it->second.nullVector()) { - event_Q = event_Q - peak_it->second; - if (event_Q.norm() < radius) { + event_Q.second = event_Q.second - peak_it->second; + if (event_Q.second.norm() < radius) { event_lists[hkl_key].push_back(event_Q); } } @@ -397,7 +405,7 @@ void Integrate3DEvents::addEvent(V3D event_Q) { * */ PeakShapeEllipsoid_const_sptr Integrate3DEvents::ellipseIntegrateEvents( - std::vector const &ev_list, std::vector const &directions, + std::vector > const &ev_list, std::vector const &directions, std::vector const &sigmas, bool specify_size, double peak_radius, double back_inner_radius, double back_outer_radius, std::vector &axes_radii, double &inti, double &sigi) { diff --git a/Code/Mantid/Framework/MDEvents/src/IntegrateEllipsoids.cpp b/Code/Mantid/Framework/MDEvents/src/IntegrateEllipsoids.cpp index 211fc8d3e2f8..ddc312d7ea57 100644 --- a/Code/Mantid/Framework/MDEvents/src/IntegrateEllipsoids.cpp +++ b/Code/Mantid/Framework/MDEvents/src/IntegrateEllipsoids.cpp @@ -76,7 +76,7 @@ void qListFromEventWS(Integrate3DEvents &integrator, Progress &prog, double errorSq(1.); // ignorable garbage const std::vector &raw_events = events.getWeightedEventsNoTime(); - std::vector qList; + std::vector > qList; for (auto event = raw_events.begin(); event != raw_events.end(); ++event) { double val = unitConverter.convertUnits(event->tof()); qConverter->calcMatrixCoord(val, locCoord, signal, errorSq); @@ -84,7 +84,7 @@ void qListFromEventWS(Integrate3DEvents &integrator, Progress &prog, buffer[dim] = locCoord[dim]; } V3D qVec(buffer[0], buffer[1], buffer[2]); - qList.push_back(qVec); + qList.push_back(std::make_pair(event->m_weight, qVec)); } // end of loop over events in list integrator.addEvents(qList); @@ -125,7 +125,7 @@ void qListFromHistoWS(Integrate3DEvents &integrator, Progress &prog, double signal(1.); // ignorable garbage double errorSq(1.); // ignorable garbage - std::vector qList; + std::vector > qList; // TODO. we should be able to do this in an OMP loop. for (size_t j = 0; j < yVals.size(); ++j) { @@ -149,10 +149,8 @@ void qListFromHistoWS(Integrate3DEvents &integrator, Progress &prog, V3D qVec(buffer[0], buffer[1], buffer[2]); int yValCounts = int(yVal); // we deliberately truncate. // Account for counts in histograms by increasing the qList with the - // same q-poin - for (int k = 0; k < yValCounts; ++k) { - qList.push_back(qVec); // Not ideal to control the size dynamically? - } + // same q-point + qList.push_back(std::make_pair(yValCounts,qVec)); // Not ideal to control the size dynamically? } integrator.addEvents(qList); // We would have to put a lock around this. prog.report(); @@ -299,6 +297,7 @@ void IntegrateEllipsoids::exec() { size_t n_peaks = peak_ws->getNumberPeaks(); size_t indexed_count = 0; std::vector peak_q_list; + std::vector > qList; std::vector hkl_vectors; for (size_t i = 0; i < n_peaks; i++) // Note: we skip un-indexed peaks { @@ -307,6 +306,7 @@ void IntegrateEllipsoids::exec() { // just check for (0,0,0) { peak_q_list.push_back(V3D(peaks[i].getQLabFrame())); + qList.push_back(std::make_pair(1., V3D(peaks[i].getQLabFrame()))); V3D miller_ind((double)boost::math::iround(hkl[0]), (double)boost::math::iround(hkl[1]), (double)boost::math::iround(hkl[2])); @@ -345,7 +345,7 @@ void IntegrateEllipsoids::exec() { } // make the integrator - Integrate3DEvents integrator(peak_q_list, UBinv, radius); + Integrate3DEvents integrator(qList, UBinv, radius); // get the events and add // them to the inegrator @@ -379,10 +379,11 @@ void IntegrateEllipsoids::exec() { double inti; double sigi; std::vector principalaxis1,principalaxis2,principalaxis3; + V3D peak_q; for (size_t i = 0; i < n_peaks; i++) { V3D hkl(peaks[i].getH(), peaks[i].getK(), peaks[i].getL()); if (Geometry::IndexingUtils::ValidIndex(hkl, 1.0)) { - V3D peak_q(peaks[i].getQLabFrame()); + peak_q = peaks[i].getQLabFrame(); std::vector axes_radii; Mantid::Geometry::PeakShape_const_sptr shape = integrator.ellipseIntegrateEvents( @@ -451,10 +452,11 @@ void IntegrateEllipsoids::exec() { back_inner_radius = peak_radius; back_outer_radius = peak_radius * 1.25992105; // A factor of 2 ^ (1/3) will make the background // shell volume equal to the peak region volume. + V3D peak_q; for (size_t i = 0; i < n_peaks; i++) { V3D hkl(peaks[i].getH(), peaks[i].getK(), peaks[i].getL()); if (Geometry::IndexingUtils::ValidIndex(hkl, 1.0)) { - V3D peak_q(peaks[i].getQLabFrame()); + peak_q = peaks[i].getQLabFrame(); std::vector axes_radii; integrator.ellipseIntegrateEvents(peak_q, specify_size, peak_radius, back_inner_radius, back_outer_radius, diff --git a/Code/Mantid/Framework/MDEvents/src/MDBoxFlatTree.cpp b/Code/Mantid/Framework/MDEvents/src/MDBoxFlatTree.cpp index 04bf88b25efc..52782b30ed61 100644 --- a/Code/Mantid/Framework/MDEvents/src/MDBoxFlatTree.cpp +++ b/Code/Mantid/Framework/MDEvents/src/MDBoxFlatTree.cpp @@ -745,6 +745,9 @@ MDBoxFlatTree::createOrOpenMDWSgroup(const std::string &fileName, int &nDims, * dimensions etc.*/ void MDBoxFlatTree::saveWSGenericInfo(::NeXus::File *const file, API::IMDWorkspace_const_sptr ws) { + // Write out the coordinate system + file->writeData("coordinate_system", + static_cast(ws->getSpecialCoordinateSystem())); // Save the algorithm history under "process" ws->getHistory().saveNexus(file); diff --git a/Code/Mantid/Framework/MDEvents/src/MDEventWorkspace.cpp b/Code/Mantid/Framework/MDEvents/src/MDEventWorkspace.cpp index 5c1f60e4a847..03e4c2b0d716 100644 --- a/Code/Mantid/Framework/MDEvents/src/MDEventWorkspace.cpp +++ b/Code/Mantid/Framework/MDEvents/src/MDEventWorkspace.cpp @@ -34,7 +34,7 @@ namespace MDEvents { /** Default constructor */ TMDE(MDEventWorkspace)::MDEventWorkspace() - : m_BoxController(new BoxController(nd)) { + : data(NULL), m_BoxController(new BoxController(nd)), m_coordSystem(None) { // First box is at depth 0, and has this default boxController data = new MDBox(m_BoxController.get(), 0); } @@ -781,48 +781,21 @@ TMDE(void MDEventWorkspace)::clearMDMasking() { } /** -Set the special coordinate system (if any) to use. -@param coordinateSystem : Special coordinate system to use. +Get the coordinate system (if any) to use. +@return An enumeration specifying the coordinate system if any. */ -TMDE(void MDEventWorkspace)::setCoordinateSystem( - const Mantid::Kernel::SpecialCoordinateSystem coordinateSystem) { - // If there isn't an experiment info, create one. - uint16_t nexpts = this->getNumExperimentInfo(); - ExperimentInfo_sptr expInfo; - if (nexpts == 0) { - expInfo = boost::make_shared(); - this->addExperimentInfo(expInfo); - } - else { - // The last experiment info should always be the one that refers - // to latest converting workspace to use this - expInfo = this->getExperimentInfo(static_cast(nexpts - 1)); - } - expInfo->mutableRun().addProperty("CoordinateSystem", (int)coordinateSystem, true); +TMDE(Kernel::SpecialCoordinateSystem + MDEventWorkspace)::getSpecialCoordinateSystem() const { + return m_coordSystem; } /** -Get the special coordinate system (if any) to use. -@return Special coordinate system if any. +Set the coordinate system (if any) to use. +@param coordSystem : Coordinate system to use. */ -TMDE(Mantid::Kernel::SpecialCoordinateSystem - MDEventWorkspace)::getSpecialCoordinateSystem() const { - Mantid::Kernel::SpecialCoordinateSystem result = None; - try { - auto nInfos = this->getNumExperimentInfo(); - if (nInfos > 0) { - // The last experiment info should always be the one that refers - // to latest converting workspace to use this - auto *prop = this->getExperimentInfo(static_cast(nInfos - 1)) - ->run() - .getProperty("CoordinateSystem"); - auto *p = dynamic_cast *>(prop); - int temp = *p; - result = static_cast(temp); - } - } catch (Mantid::Kernel::Exception::NotFoundError &) { - } - return result; +TMDE(void MDEventWorkspace)::setCoordinateSystem( + const Kernel::SpecialCoordinateSystem coordSystem) { + m_coordSystem = coordSystem; } } // namespace MDEvents diff --git a/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspace.cpp b/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspace.cpp index 6bda2b2a2d1f..f83adb37808c 100644 --- a/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspace.cpp +++ b/Code/Mantid/Framework/MDEvents/src/MDHistoWorkspace.cpp @@ -31,7 +31,8 @@ MDHistoWorkspace::MDHistoWorkspace(Mantid::Geometry::MDHistoDimension_sptr dimX, Mantid::Geometry::MDHistoDimension_sptr dimZ, Mantid::Geometry::MDHistoDimension_sptr dimT) : IMDHistoWorkspace(), numDimensions(0), - m_nEventsContributed(std::numeric_limits::quiet_NaN()) { + m_nEventsContributed(std::numeric_limits::quiet_NaN()), + m_coordSystem(None) { std::vector dimensions; if (dimX) dimensions.push_back(dimX); @@ -51,7 +52,8 @@ MDHistoWorkspace::MDHistoWorkspace(Mantid::Geometry::MDHistoDimension_sptr dimX, MDHistoWorkspace::MDHistoWorkspace( std::vector &dimensions) : IMDHistoWorkspace(), numDimensions(0), m_numEvents(NULL), - m_nEventsContributed(std::numeric_limits::quiet_NaN()) { + m_nEventsContributed(std::numeric_limits::quiet_NaN()), + m_coordSystem(None) { this->init(dimensions); } @@ -62,7 +64,8 @@ MDHistoWorkspace::MDHistoWorkspace( MDHistoWorkspace::MDHistoWorkspace( std::vector &dimensions) : IMDHistoWorkspace(), numDimensions(0), m_numEvents(NULL), - m_nEventsContributed(std::numeric_limits::quiet_NaN()) { + m_nEventsContributed(std::numeric_limits::quiet_NaN()), + m_coordSystem(None) { this->init(dimensions); } @@ -1183,39 +1186,20 @@ uint64_t MDHistoWorkspace::sumNContribEvents() const { } /** -Set the special coordinate system (if any) to use. -@param coordinateSystem : Special coordinate system to use. +Get the special coordinate system (if any) to use. */ -void MDHistoWorkspace::setCoordinateSystem( - const Mantid::Kernel::SpecialCoordinateSystem coordinateSystem) { - // If there isn't an experiment info, create one. - if (this->getNumExperimentInfo() == 0) { - ExperimentInfo_sptr expInfo = - boost::shared_ptr(new ExperimentInfo()); - this->addExperimentInfo(expInfo); - } - this->getExperimentInfo(0)->mutableRun().addProperty( - "CoordinateSystem", (int)coordinateSystem, true); +Kernel::SpecialCoordinateSystem +MDHistoWorkspace::getSpecialCoordinateSystem() const { + return m_coordSystem; } /** -Get the special coordinate system (if any) to use. +Set the special coordinate system (if any) to use. +@param coordinateSystem : Special coordinate system to use. */ -Mantid::Kernel::SpecialCoordinateSystem -MDHistoWorkspace::getSpecialCoordinateSystem() const { - Mantid::Kernel::SpecialCoordinateSystem result = None; - try { - auto nInfos = this->getNumExperimentInfo(); - if (nInfos > 0) { - Property *prop = - this->getExperimentInfo(0)->run().getProperty("CoordinateSystem"); - PropertyWithValue *p = dynamic_cast *>(prop); - int temp = *p; - result = (SpecialCoordinateSystem)temp; - } - } catch (Mantid::Kernel::Exception::NotFoundError &) { - } - return result; +void MDHistoWorkspace::setCoordinateSystem( + const Kernel::SpecialCoordinateSystem coordinateSystem) { + m_coordSystem = coordinateSystem; } /** diff --git a/Code/Mantid/Framework/MDEvents/test/Integrate3DEventsTest.h b/Code/Mantid/Framework/MDEvents/test/Integrate3DEventsTest.h index 56c313eced2b..687180da6092 100644 --- a/Code/Mantid/Framework/MDEvents/test/Integrate3DEventsTest.h +++ b/Code/Mantid/Framework/MDEvents/test/Integrate3DEventsTest.h @@ -35,14 +35,14 @@ class Integrate3DEventsTest : public CxxTest::TestSuite double sigi_some[] = { 27.4773, 26.533, 24.5561 }; // synthesize three peaks - std::vector peak_q_list; + std::vector > peak_q_list; V3D peak_1( 10, 0, 0 ); V3D peak_2( 0, 5, 0 ); V3D peak_3( 0, 0, 4 ); - peak_q_list.push_back( peak_1 ); - peak_q_list.push_back( peak_2 ); - peak_q_list.push_back( peak_3 ); + peak_q_list.push_back( std::make_pair( 1., peak_1 ) ); + peak_q_list.push_back( std::make_pair( 1., peak_2 ) ); + peak_q_list.push_back( std::make_pair( 1., peak_3 ) ); // synthesize a UB-inverse to map DblMatrix UBinv(3,3,false); // Q to h,k,l UBinv.setRow( 0, V3D( .1, 0, 0 ) ); @@ -55,31 +55,31 @@ class Integrate3DEventsTest : public CxxTest::TestSuite // around peak 1, 704 events around // peak 2, and 603 events around // peak 3. - std::vector event_Qs; + std::vector > event_Qs; for ( int i = -100; i <= 100; i++ ) { - event_Qs.push_back( V3D( peak_1 + V3D( (double)i/100.0, 0, 0 ) ) ); - event_Qs.push_back( V3D( peak_2 + V3D( (double)i/100.0, 0, 0 ) ) ); - event_Qs.push_back( V3D( peak_3 + V3D( (double)i/100.0, 0, 0 ) ) ); + event_Qs.push_back ( std::make_pair( 1., V3D( peak_1 + V3D( (double)i/100.0, 0, 0 ) ) ) ); + event_Qs.push_back ( std::make_pair( 1., V3D( peak_2 + V3D( (double)i/100.0, 0, 0 ) ) ) ); + event_Qs.push_back ( std::make_pair( 1., V3D( peak_3 + V3D( (double)i/100.0, 0, 0 ) ) ) ); - event_Qs.push_back( V3D( peak_1 + V3D( 0, (double)i/200.0, 0 ) ) ); - event_Qs.push_back( V3D( peak_2 + V3D( 0, (double)i/200.0, 0 ) ) ); - event_Qs.push_back( V3D( peak_3 + V3D( 0, (double)i/200.0, 0 ) ) ); + event_Qs.push_back ( std::make_pair( 1., V3D( peak_1 + V3D( 0, (double)i/200.0, 0 ) ) ) ); + event_Qs.push_back ( std::make_pair( 1., V3D( peak_2 + V3D( 0, (double)i/200.0, 0 ) ) ) ); + event_Qs.push_back ( std::make_pair( 1., V3D( peak_3 + V3D( 0, (double)i/200.0, 0 ) ) ) ); - event_Qs.push_back( V3D( peak_1 + V3D( 0, 0, (double)i/300.0 ) ) ); - event_Qs.push_back( V3D( peak_2 + V3D( 0, 0, (double)i/300.0 ) ) ); - event_Qs.push_back( V3D( peak_3 + V3D( 0, 0, (double)i/300.0 ) ) ); + event_Qs.push_back ( std::make_pair( 1., V3D( peak_1 + V3D( 0, 0, (double)i/300.0 ) ) ) ); + event_Qs.push_back ( std::make_pair( 1., V3D( peak_2 + V3D( 0, 0, (double)i/300.0 ) ) ) ); + event_Qs.push_back ( std::make_pair( 1., V3D( peak_3 + V3D( 0, 0, (double)i/300.0 ) ) ) ); } for ( int i = -50; i <= 50; i++ ) { - event_Qs.push_back( V3D( peak_1 + V3D( 0, (double)i/147.0, 0 ) ) ); - event_Qs.push_back( V3D( peak_2 + V3D( 0, (double)i/147.0, 0 ) ) ); + event_Qs.push_back ( std::make_pair( 1., V3D( peak_1 + V3D( 0, (double)i/147.0, 0 ) ) ) ); + event_Qs.push_back ( std::make_pair( 1., V3D( peak_2 + V3D( 0, (double)i/147.0, 0 ) ) ) ); } for ( int i = -25; i <= 25; i++ ) { - event_Qs.push_back( V3D( peak_1 + V3D( 0, 0, (double)i/61.0 ) ) ); + event_Qs.push_back ( std::make_pair(1., V3D( peak_1 + V3D( 0, 0, (double)i/61.0 ) ) ) ); } double radius = 1.3; @@ -98,7 +98,7 @@ class Integrate3DEventsTest : public CxxTest::TestSuite double sigi; for ( size_t i = 0; i < peak_q_list.size(); i++ ) { - auto shape = integrator.ellipseIntegrateEvents( peak_q_list[i], specify_size, + auto shape = integrator.ellipseIntegrateEvents( peak_q_list[i].second, specify_size, peak_radius, back_inner_radius, back_outer_radius, new_sigma, inti, sigi ); TS_ASSERT_DELTA( inti, inti_all[i], 0.1); @@ -114,7 +114,7 @@ class Integrate3DEventsTest : public CxxTest::TestSuite specify_size = false; for ( size_t i = 0; i < peak_q_list.size(); i++ ) { - integrator.ellipseIntegrateEvents( peak_q_list[i], specify_size, + integrator.ellipseIntegrateEvents( peak_q_list[i].second, specify_size, peak_radius, back_inner_radius, back_outer_radius, new_sigma, inti, sigi ); TS_ASSERT_DELTA( inti, inti_some[i], 0.1); diff --git a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/Projection.cpp b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/Projection.cpp index 3d8630d87a16..02342cff2624 100644 --- a/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/Projection.cpp +++ b/Code/Mantid/Framework/PythonInterface/mantid/api/src/Exports/Projection.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include using namespace Mantid::API; @@ -16,19 +18,6 @@ using namespace boost::python; GCC_DIAG_OFF(strict-aliasing) namespace { -std::string indexToName(size_t i) { - switch (i) { - case 0: - return "u"; - case 1: - return "v"; - case 2: - return "w"; - default: - return "d" + boost::lexical_cast(i); - } -} - std::string getUnit(Projection &p, size_t nd) { return (p.getUnit(nd) == RLU ? "r" : "a"); } @@ -42,20 +31,46 @@ void setUnit(Projection &p, size_t nd, std::string unit) { throw std::runtime_error("Invalid unit"); } -ITableWorkspace_sptr toWorkspace(Projection &p) { - ITableWorkspace_sptr ws = WorkspaceFactory::Instance().createTable(); - auto colName = ws->addColumn("str", "name"); - auto colValue = ws->addColumn("str", "value"); - auto colType = ws->addColumn("str", "type"); - auto colOffset = ws->addColumn("double", "offset"); +//This is a bit strange, but it works. The users want x = proj.createWorkspace() +//to behave like the simpleapi, i.e. put a workspace named 'x' into the ADS for +//them. To do that kind of black magic we have to introspect from the Python +//side, so that's what we do. +object createWorkspace() { + //Create a namespace for us to add a function to + object main = import("__main__"); + object global(main.attr("__dict__")); + //Add a function to the namespace + object result = exec( + "def createWorkspace(proj, OutputWorkspace=None):\n" + " '''Create a TableWorkspace using this projection'''\n" + " import inspect\n" + " from mantid import api, kernel\n" + " ws = api.WorkspaceFactory.createTable('TableWorkspace')\n" + " ws.addColumn('str', 'name')\n" + " ws.addColumn('str', 'value')\n" + " ws.addColumn('str', 'type')\n" + " ws.addColumn('double', 'offset')\n" + " for (name, i) in zip('uvw', range(3)):\n" + " ws.addRow({\n" + " 'name': name,\n" + " 'value': str(proj.getAxis(i)).lstrip('[').rstrip(']'),\n" + " 'type': proj.getType(i),\n" + " 'offset': proj.getOffset(i)\n" + " })\n" + + " if OutputWorkspace is None:\n" + " lhs = kernel.funcreturns.process_frame(inspect.currentframe().f_back)\n" + " if lhs[0] > 0:\n" + " OutputWorkspace = lhs[1][0]\n" - for (size_t i = 0; i < 3; ++i) { - TableRow row = ws->appendRow(); - row << indexToName(i) << p.getAxis(i).toString() << getUnit(p, i) - << p.getOffset(i); - } + " if OutputWorkspace:\n" + " mtd[OutputWorkspace] = ws\n" - return ws; + " return ws\n" + "\n", global, global); + //extract the function object from the namespace and return it so it can be + //bound by Boost::Python. + return global["createWorkspace"]; } void projSetAxis(Projection &self, size_t nd, const object& data) { @@ -210,8 +225,8 @@ void export_Projection() ) ) .def( - "toWorkspace", - toWorkspace, + "createWorkspace", + createWorkspace(), "Create a TableWorkspace representing the projection" ) ; diff --git a/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/ProjectionTest.py b/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/ProjectionTest.py index efce9a516774..0fb3d55fde9d 100644 --- a/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/ProjectionTest.py +++ b/Code/Mantid/Framework/PythonInterface/test/python/mantid/api/ProjectionTest.py @@ -1,6 +1,7 @@ import unittest from mantid.api import Projection from mantid.kernel import V3D +from mantid.simpleapi import mtd class ProjectionTest(unittest.TestCase): @@ -54,5 +55,21 @@ def test_uvw(self): self.assertEqual(p.v, V3D(7,8,9)) self.assertEqual(p.w, V3D(4,6,0)) + def test_ads(self): + p = Projection(); + p.setAxis(0, V3D(0,1,2)) + p.setAxis(1, V3D(3,-4,5)) + p.setAxis(2, V3D(6,7,8.5)) + p.setOffset(1, 0.15) + p.setType(2, 'a') + proj_test_ads = p.createWorkspace() + proj_test_ads3 = p.createWorkspace(OutputWorkspace='proj_test_ads2') + self.assertTrue('proj_test_ads' in mtd, msg='Workspace not added to ADS successfully') + self.assertTrue('proj_test_ads2' in mtd, msg='Workspace not added to ADS successfully') + + self.assertEqual(proj_test_ads.row(0), {'name':'u', 'value':'0,1,2', 'type':'r', 'offset':0.0}) + self.assertEqual(proj_test_ads.row(1), {'name':'v', 'value':'3,-4,5', 'type':'r', 'offset':0.15}) + self.assertEqual(proj_test_ads.row(2), {'name':'w', 'value':'6,7,8.5', 'type':'a', 'offset':0.0}) + if __name__ == '__main__': unittest.main() diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectDataReduction.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectDataReduction.h index 234d7e0df8f4..350ccbece7a7 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectDataReduction.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Indirect/IndirectDataReduction.h @@ -122,7 +122,6 @@ namespace MantidQt * THis method is used to ensure that the tabs are always loaded and their * layouts setup for the sake of screenshoting them for documentation. * - * @param T Tab type, must be subclass of IndirectDataReductionTab * @param name Name to be displayed on tab */ template diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingPresenter.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingPresenter.h index bd61d9d68e1a..044783b4f90f 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingPresenter.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingPresenter.h @@ -51,8 +51,8 @@ namespace CustomInterfaces /// Load new data and update the view accordingly void load(); - /// Updates the list of logs user can choose from - void updateAvailableLogs(); + /// Updates the list of logs and number of periods + void updateAvailableInfo(); private: /// View which the object works with diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.h index 439423305fa1..c7c9ea26d321 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.h @@ -55,12 +55,19 @@ namespace CustomInterfaces std::string log() const; std::string deadTimeType() const; std::string deadTimeFile() const; + std::string detectorGroupingType() const; + std::string getForwardGrouping() const; + std::string getBackwardGrouping() const; + std::string redPeriod() const; + std::string greenPeriod() const; + bool subtractIsChecked() const; std::string calculationType() const; boost::optional< std::pair > timeRange() const; void setDataCurve(const QwtData& data); void displayError(const std::string &error); void setAvailableLogs(const std::vector &logs); + void setAvailablePeriods(const std::vector &periods); void setWaitingCursor(); void restoreCursor(); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.ui b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.ui index 9780978e28ef..dfb8c5c30abf 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.ui +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/ALCDataLoadingView.ui @@ -1,409 +1,571 @@ - ALCDataLoadingView - - - - 0 - 0 - 943 - 435 - - - - Form - - - - - - Qt::Horizontal - - - - - - - Data - - - - QFormLayout::ExpandingFieldsGrow + ALCDataLoadingView + + + + 0 + 0 + 943 + 435 + + + + Form + + + + + + Qt::Horizontal - - - - First - - - - - - - Last - - - - - - - Log - - - - - - - - 0 - 0 - - - - - - - false - - - - - - - - 0 - 0 - - - - - - - false - - - - - - - false - - - QComboBox::AdjustToContents - - - - - - - - - - Dead Time Correction - - - - - - - - None - - - true - - - deadTimeCorrType - - - - - - - From Data File - - - deadTimeCorrType - - - - - - - From Custom File - - - deadTimeCorrType - - - + + + + + + Data + + + + QFormLayout::ExpandingFieldsGrow + + + + + First + + + + + + + Last + + + + + + + Log + + + + + + + + 0 + 0 + + + + + + + false + + + + + + + + 0 + 0 + + + + + + + false + + + + + + + false + + + QComboBox::AdjustToContents + + + + + + + + + + Dead Time Correction + + + + + + + + None + + + true + + + deadTimeCorrType + + + + + + + From Data File + + + deadTimeCorrType + + + + + + + From Custom File + + + deadTimeCorrType + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + + + + + + + false + + + false + + + + + + + + + + + + Grouping + + + + + + + + Auto + + + true + + + detectorGroupingType + + + + + + + Custom + + + detectorGroupingType + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Forward + + + false + + + + + + + false + + + + + + + Backward + + + false + + + + + + + false + + + + + + + + + + + + Periods + + + + + + + + + + + + Subtract + + + + + + + false + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Calculation + + + + + + + + Type: + + + + + + + Integral + + + true + + + calculationType + + + + + + + Differential + + + calculationType + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Time limit: + + + + + + + false + + + + 100 + 0 + + + + + 0 + + + + + From [µ] + + + + + + + + + + Max [µ] + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + - + - Qt::Horizontal + Qt::Vertical - 40 - 20 + 20 + 40 + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Load + + + + + - - - - - - - - 0 - 0 - - - - - - - false - - - false - - - - - - - - - - - - Calculation - - - - - - - - Type: - - - - - - - Integral - - - true - - - calculationType - - - - - - - Differential - - - calculationType - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Time limit: - - - - - - - false - - - - 100 - 0 - - - - - 0 - - - - - From [µ] - - - - - - - - - - Max [µ] - + + + + Loaded data + + + + + + + 300 + 0 + + - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Load - + + - - - - - - - - Loaded data - - - - - - - 300 - 0 - - - - - - - - - - - - QwtPlot - QFrame -
qwt_plot.h
-
- - MantidQt::MantidWidgets::MWRunFiles - QWidget -
MantidQtMantidWidgets/MWRunFiles.h
-
-
- - log - integral - differential - timeLimit - minTime - maxTime - load - - - - - timeLimit - toggled(bool) - timeLimits - setEnabled(bool) - - - 94 - 193 - - - 264 - 205 - - - - - fromCustomFile - toggled(bool) - deadTimeFile - setEnabled(bool) - - - - - - + + + + + + QwtPlot + QFrame +
qwt_plot.h
+
+ + MantidQt::MantidWidgets::MWRunFiles + QWidget +
MantidQtMantidWidgets/MWRunFiles.h
+
+
+ + log + integral + differential + timeLimit + minTime + maxTime + load + + + + + timeLimit + toggled(bool) + timeLimits + setEnabled(bool) + + + 94 + 193 + + + 264 + 205 + + + + + fromCustomFile + toggled(bool) + deadTimeFile + setEnabled(bool) + + + customGroupingButton + toggled(bool) + labelForward + setEnabled(bool) + + + customGroupingButton + toggled(bool) + labelBackward + setEnabled(bool) + + + customGroupingButton + toggled(bool) + forwardEdit + setEnabled(bool) + + + customGroupingButton + toggled(bool) + backwardEdit + setEnabled(bool) + + + subtractCheckbox + toggled(bool) + greenPeriod + setEnabled(bool) + + + + + + +
diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/IALCDataLoadingView.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/IALCDataLoadingView.h index cb4ce9f9643b..bf6bbc99ad8a 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/IALCDataLoadingView.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/Muon/IALCDataLoadingView.h @@ -59,6 +59,24 @@ namespace CustomInterfaces /// @return dead time correction file virtual std::string deadTimeFile() const = 0; + /// @return detector grouping type + virtual std::string detectorGroupingType() const = 0; + + /// @return forward grouping + virtual std::string getForwardGrouping() const = 0; + + /// @return backward grouping + virtual std::string getBackwardGrouping() const = 0; + + /// @return red period + virtual std::string redPeriod() const = 0; + + /// @return green period + virtual std::string greenPeriod() const = 0; + + /// @return subtract checkbox + virtual bool subtractIsChecked() const =0; + /// @return Selected calculation type - "Integral" or "Differential" virtual std::string calculationType() const = 0; @@ -81,6 +99,10 @@ namespace CustomInterfaces /// @param logs :: New list of log names virtual void setAvailableLogs(const std::vector& logs) = 0; + /// Update the list of periods user can select + /// @param periods :: New list of periods + virtual void setAvailablePeriods(const std::vector& periods) = 0; + /// Set waiting cursor for long operation virtual void setWaitingCursor() = 0; diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/Quasi.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/Quasi.cpp index 7cb65da529e0..b6c99479cf4f 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/Quasi.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Indirect/Quasi.cpp @@ -243,12 +243,22 @@ namespace MantidQt for(size_t histIndex = 0; histIndex < outputWorkspace->getNumberHistograms(); histIndex++) { QString specName = QString::fromStdString(axis->label(histIndex)); + QColor curveColour; - if(specName.contains("fit")) - m_uiForm.ppPlot->addSpectrum(specName, outputWorkspace, histIndex, Qt::red); + if(specName.contains("fit.1")) + curveColour = Qt::red; + else if(specName.contains("fit.2")) + curveColour = Qt::magenta; - if(specName.contains("diff")) - m_uiForm.ppPlot->addSpectrum(specName, outputWorkspace, histIndex, Qt::green); + else if(specName.contains("diff.1")) + curveColour = Qt::green; + else if(specName.contains("diff.2")) + curveColour = Qt::cyan; + + else + continue; + + m_uiForm.ppPlot->addSpectrum(specName, outputWorkspace, histIndex, curveColour); } } diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingPresenter.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingPresenter.cpp index 4e98e7c4483a..4205e4ba18f5 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingPresenter.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingPresenter.cpp @@ -28,7 +28,7 @@ namespace CustomInterfaces m_view->initialize(); connect(m_view, SIGNAL(loadRequested()), SLOT(load())); - connect(m_view, SIGNAL(firstRunSelected()), SLOT(updateAvailableLogs())); + connect(m_view, SIGNAL(firstRunSelected()), SLOT(updateAvailableInfo())); } void ALCDataLoadingPresenter::load() @@ -44,6 +44,7 @@ namespace CustomInterfaces alg->setProperty("LogValue", m_view->log()); alg->setProperty("Type", m_view->calculationType()); alg->setProperty("DeadTimeCorrType",m_view->deadTimeType()); + alg->setProperty("Red",m_view->redPeriod()); // If time limiting requested, set min/max times if (auto timeRange = m_view->timeRange()) @@ -51,19 +52,42 @@ namespace CustomInterfaces alg->setProperty("TimeMin", timeRange->first); alg->setProperty("TimeMax", timeRange->second); } + + // If corrections from custom file requested, set file property if (m_view->deadTimeType() == "FromSpecifiedFile") { alg->setProperty("DeadTimeCorrFile",m_view->deadTimeFile()); } + // If custom grouping requested, set forward/backward groupings + if ( m_view->detectorGroupingType() == "Custom" ) { + alg->setProperty("ForwardSpectra",m_view->getForwardGrouping()); + alg->setProperty("BackwardSpectra",m_view->getBackwardGrouping()); + } + + // If Subtract checkbox is selected, set green period + if ( m_view->subtractIsChecked() ) { + alg->setProperty("Green",m_view->greenPeriod()); + } + alg->setPropertyValue("OutputWorkspace", "__NotUsed"); alg->execute(); m_loadedData = alg->getProperty("OutputWorkspace"); - assert(m_loadedData); // If errors are properly caught, shouldn't happen - assert(m_loadedData->getNumberHistograms() == 1); // PlotAsymmetryByLogValue guarantees that + // If errors are properly caught, shouldn't happen + assert(m_loadedData); + // If subtract is not checked, only one spectrum, + // else four spectra + if ( !m_view->subtractIsChecked() ) { + assert(m_loadedData->getNumberHistograms() == 1); + } else { + assert(m_loadedData->getNumberHistograms() == 4); + } + // Plot spectrum 0. It is either red period (if subtract is unchecked) or + // red - green (if subtract is checked) m_view->setDataCurve(*(ALCHelper::curveDataFromWs(m_loadedData, 0))); + } catch(std::exception& e) { @@ -73,7 +97,7 @@ namespace CustomInterfaces m_view->restoreCursor(); } - void ALCDataLoadingPresenter::updateAvailableLogs() + void ALCDataLoadingPresenter::updateAvailableInfo() { Workspace_sptr loadedWs; @@ -95,9 +119,11 @@ namespace CustomInterfaces catch(...) { m_view->setAvailableLogs(std::vector()); // Empty logs list + m_view->setAvailablePeriods(std::vector()); // Empty period list return; } + // Set logs MatrixWorkspace_const_sptr ws = MuonAnalysisHelper::firstPeriod(loadedWs); std::vector logs; @@ -106,8 +132,16 @@ namespace CustomInterfaces { logs.push_back((*it)->name()); } - m_view->setAvailableLogs(logs); + + // Set periods + size_t numPeriods = MuonAnalysisHelper::numPeriods(loadedWs); + std::vector periods; + for (size_t i=0; i(i)+1)); + } + m_view->setAvailablePeriods(periods); } } // namespace CustomInterfaces diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingView.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingView.cpp index a49de5f85cc4..5dc2f6910a3d 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingView.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/Muon/ALCDataLoadingView.cpp @@ -85,6 +85,37 @@ namespace CustomInterfaces } } + std::string ALCDataLoadingView::detectorGroupingType() const + { + std::string checkedButton = m_ui.detectorGroupingType->checkedButton()->text().toStdString(); + return checkedButton; + } + + std::string ALCDataLoadingView::getForwardGrouping() const + { + return m_ui.forwardEdit->text().toStdString(); + } + + std::string ALCDataLoadingView::getBackwardGrouping() const + { + return m_ui.backwardEdit->text().toStdString(); + } + + std::string ALCDataLoadingView::redPeriod() const + { + return m_ui.redPeriod->currentText().toStdString(); + } + + std::string ALCDataLoadingView::greenPeriod() const + { + return m_ui.greenPeriod->currentText().toStdString(); + } + + bool ALCDataLoadingView::subtractIsChecked() const + { + return m_ui.subtractCheckbox->isChecked(); + } + boost::optional< std::pair > ALCDataLoadingView::timeRange() const { if (m_ui.timeLimit->isChecked()) @@ -121,6 +152,20 @@ namespace CustomInterfaces } } + void ALCDataLoadingView::setAvailablePeriods(const std::vector& periods) + { + // Clear previous list + m_ui.redPeriod->clear(); + m_ui.greenPeriod->clear(); + + // Add new items + for (auto it=periods.begin(); it!=periods.end(); ++it) + { + m_ui.redPeriod->addItem(QString::fromStdString(*it)); + m_ui.greenPeriod->addItem(QString::fromStdString(*it)); + } + } + void ALCDataLoadingView::setWaitingCursor() { QApplication::setOverrideCursor(Qt::WaitCursor); diff --git a/Code/Mantid/MantidQt/CustomInterfaces/test/ALCDataLoadingPresenterTest.h b/Code/Mantid/MantidQt/CustomInterfaces/test/ALCDataLoadingPresenterTest.h index f1a4c14eb447..b0f54ee8d647 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/test/ALCDataLoadingPresenterTest.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/test/ALCDataLoadingPresenterTest.h @@ -36,11 +36,18 @@ class MockALCDataLoadingView : public IALCDataLoadingView MOCK_CONST_METHOD0(timeRange, boost::optional()); MOCK_CONST_METHOD0(deadTimeType, std::string()); MOCK_CONST_METHOD0(deadTimeFile, std::string()); + MOCK_CONST_METHOD0(detectorGroupingType, std::string()); + MOCK_CONST_METHOD0(getForwardGrouping, std::string()); + MOCK_CONST_METHOD0(getBackwardGrouping, std::string()); + MOCK_CONST_METHOD0(redPeriod, std::string()); + MOCK_CONST_METHOD0(greenPeriod, std::string()); + MOCK_CONST_METHOD0(subtractIsChecked, bool()); MOCK_METHOD0(initialize, void()); MOCK_METHOD1(setDataCurve, void(const QwtData&)); MOCK_METHOD1(displayError, void(const std::string&)); MOCK_METHOD1(setAvailableLogs, void(const std::vector&)); + MOCK_METHOD1(setAvailablePeriods, void(const std::vector&)); MOCK_METHOD0(setWaitingCursor, void()); MOCK_METHOD0(restoreCursor, void()); @@ -80,6 +87,9 @@ class ALCDataLoadingPresenterTest : public CxxTest::TestSuite ON_CALL(*m_view, log()).WillByDefault(Return("sample_magn_field")); ON_CALL(*m_view, timeRange()).WillByDefault(Return(boost::none)); ON_CALL(*m_view, deadTimeType()).WillByDefault(Return("None")); + ON_CALL(*m_view, detectorGroupingType()).WillByDefault(Return("Auto")); + ON_CALL(*m_view, redPeriod()).WillByDefault(Return("1")); + ON_CALL(*m_view, subtractIsChecked()).WillByDefault(Return(false)); } void tearDown() @@ -215,6 +225,41 @@ class ALCDataLoadingPresenterTest : public CxxTest::TestSuite EXPECT_CALL(*m_view, restoreCursor()).Times(1); m_view->requestLoading(); } + + void test_customGrouping () + { + // Change grouping type to 'Custom' + ON_CALL(*m_view, detectorGroupingType()).WillByDefault(Return("Custom")); + // Set grouping, the same as the default + ON_CALL(*m_view, getForwardGrouping()).WillByDefault(Return("33-64")); + ON_CALL(*m_view, getBackwardGrouping()).WillByDefault(Return("1-32")); + EXPECT_CALL(*m_view, getForwardGrouping()).Times(1); + EXPECT_CALL(*m_view, getBackwardGrouping()).Times(1); + EXPECT_CALL(*m_view, restoreCursor()).Times(1); + EXPECT_CALL(*m_view, setDataCurve(AllOf(Property(&QwtData::size, 3), QwtDataX(0, 1350, 1E-8), + QwtDataX(1, 1360, 1E-8), QwtDataX(2, 1370, 1E-8), + QwtDataY(0, 0.150, 1E-3), QwtDataY(1, 0.143, 1E-3), + QwtDataY(2, 0.128, 1E-3)))); + + m_view->requestLoading(); + } + + void test_customPeriods () + { + // Change red period to 2 + // Change green period to 1 + // Check Subtract, greenPeriod() should be called once + ON_CALL(*m_view, subtractIsChecked()).WillByDefault(Return(true)); + ON_CALL(*m_view, redPeriod()).WillByDefault(Return("2")); + ON_CALL(*m_view, greenPeriod()).WillByDefault(Return("1")); + EXPECT_CALL(*m_view, greenPeriod()).Times(1); + // Check results + EXPECT_CALL(*m_view, setDataCurve(AllOf(Property(&QwtData::size, 3), QwtDataX(0, 1350, 1E-8), + QwtDataX(1, 1360, 1E-8), QwtDataX(2, 1370, 1E-8), + QwtDataY(0, 0.012884, 1E-6), QwtDataY(1, 0.022489, 1E-6), + QwtDataY(2, 0.038717, 1E-6)))); + m_view->requestLoading(); + } }; diff --git a/Code/Mantid/docs/source/algorithms/CutMD-v1.rst b/Code/Mantid/docs/source/algorithms/CutMD-v1.rst index 3e882bbb8e87..4f1dea9a34b7 100644 --- a/Code/Mantid/docs/source/algorithms/CutMD-v1.rst +++ b/Code/Mantid/docs/source/algorithms/CutMD-v1.rst @@ -22,7 +22,6 @@ Usage .. testcode:: Example4D from mantid.api import Projection - from mantid.kernel import VMD to_cut = CreateMDWorkspace(Dimensions=4, Extents=[-1,1,-1,1,-1,1,-10,10], Names="H,K,L,E", Units="U,U,U,V") # Add two fake peaks so that we can see the effect of the basis transformation @@ -36,9 +35,10 @@ Usage #Since we only specify u and v, w is automatically calculated to be the cross product of u and v projection = Projection([1,1,0], [-1,1,0]) + proj_ws = projection.createWorkspace() # Apply the cut - out_md = CutMD(to_cut, Projection=projection.toWorkspace(), P1Bin=[0.1], P2Bin=[0.1], P3Bin=[0.1], P4Bin=[-5,5], NoPix=True) + out_md = CutMD(to_cut, Projection=proj_ws, P1Bin=[0.1], P2Bin=[0.1], P3Bin=[0.1], P4Bin=[-5,5], NoPix=True) print 'number of dimensions', out_md.getNumDims() print 'number of dimensions not integrated', len(out_md.getNonIntegratedDimensions()) dim_dE = out_md.getDimension(3)