diff --git a/Framework/Geometry/inc/MantidGeometry/MDGeometry/GeneralFrame.h b/Framework/Geometry/inc/MantidGeometry/MDGeometry/GeneralFrame.h index 36d50272477132199609b1e96b98644f444fb0e2..f4098803b32fc201b7420ee9ce40253f7038073e 100644 --- a/Framework/Geometry/inc/MantidGeometry/MDGeometry/GeneralFrame.h +++ b/Framework/Geometry/inc/MantidGeometry/MDGeometry/GeneralFrame.h @@ -46,6 +46,8 @@ public: Kernel::UnitLabel getUnitLabel() const; const Kernel::MDUnit &getMDUnit() const; bool canConvertTo(const Kernel::MDUnit &otherUnit) const; + bool isQ() const; + bool isSameType(const MDFrame& frame) const; std::string name() const; virtual GeneralFrame *clone() const; Mantid::Kernel::SpecialCoordinateSystem diff --git a/Framework/Geometry/inc/MantidGeometry/MDGeometry/HKL.h b/Framework/Geometry/inc/MantidGeometry/MDGeometry/HKL.h index 8b38ca560612c0c4cea7a4410e058e28ed7f9567..a0d6d91668f210d2fed47b6b23c2a08fba0dcf8a 100644 --- a/Framework/Geometry/inc/MantidGeometry/MDGeometry/HKL.h +++ b/Framework/Geometry/inc/MantidGeometry/MDGeometry/HKL.h @@ -47,6 +47,8 @@ public: Kernel::UnitLabel getUnitLabel() const; const Kernel::MDUnit &getMDUnit() const; bool canConvertTo(const Kernel::MDUnit &otherUnit) const; + bool isQ() const; + bool isSameType(const MDFrame& frame) const; std::string name() const; HKL *clone() const; Mantid::Kernel::SpecialCoordinateSystem diff --git a/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDFrame.h b/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDFrame.h index 35f424eecc120c80cf85a1f0f6f7d9f15804d563..4c5a59f1b0eb030e0cd471a44ae30263c4cb9ed1 100644 --- a/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDFrame.h +++ b/Framework/Geometry/inc/MantidGeometry/MDGeometry/MDFrame.h @@ -40,6 +40,8 @@ public: virtual Mantid::Kernel::UnitLabel getUnitLabel() const = 0; virtual const Mantid::Kernel::MDUnit &getMDUnit() const = 0; virtual bool canConvertTo(const Mantid::Kernel::MDUnit &otherUnit) const = 0; + virtual bool isQ() const = 0; + virtual bool isSameType(const MDFrame& frame) const = 0; virtual std::string name() const = 0; virtual Mantid::Kernel::SpecialCoordinateSystem equivalientSpecialCoordinateSystem() const = 0; @@ -49,6 +51,8 @@ public: typedef std::unique_ptr<MDFrame> MDFrame_uptr; typedef std::unique_ptr<const MDFrame> MDFrame_const_uptr; +typedef std::shared_ptr<MDFrame> MDFrame_sptr; +typedef std::shared_ptr<const MDFrame> MDFrame_const_sptr; } // namespace Geometry } // namespace Mantid diff --git a/Framework/Geometry/inc/MantidGeometry/MDGeometry/QLab.h b/Framework/Geometry/inc/MantidGeometry/MDGeometry/QLab.h index a66782c34f8443c54d2719385412b1e4147cf7bd..8de9491dc9ead43d9ef47568934cda73ba38feec 100644 --- a/Framework/Geometry/inc/MantidGeometry/MDGeometry/QLab.h +++ b/Framework/Geometry/inc/MantidGeometry/MDGeometry/QLab.h @@ -41,6 +41,8 @@ public: Mantid::Kernel::UnitLabel getUnitLabel() const; const Mantid::Kernel::MDUnit &getMDUnit() const; bool canConvertTo(const Mantid::Kernel::MDUnit &otherUnit) const; + bool isQ() const; + bool isSameType(const MDFrame& frame) const; virtual std::string name() const; QLab *clone() const; Mantid::Kernel::SpecialCoordinateSystem diff --git a/Framework/Geometry/inc/MantidGeometry/MDGeometry/QSample.h b/Framework/Geometry/inc/MantidGeometry/MDGeometry/QSample.h index bc90b2e7fc5e69513fd439172f09d0921f7d8c83..24f2b0f0803311d01cc5541fc953649f3b9a61ae 100644 --- a/Framework/Geometry/inc/MantidGeometry/MDGeometry/QSample.h +++ b/Framework/Geometry/inc/MantidGeometry/MDGeometry/QSample.h @@ -42,6 +42,8 @@ public: Kernel::UnitLabel getUnitLabel() const; const Kernel::MDUnit &getMDUnit() const; bool canConvertTo(const Kernel::MDUnit &otherUnit) const; + bool isQ() const; + bool isSameType(const MDFrame& frame) const; std::string name() const; QSample *clone() const; Mantid::Kernel::SpecialCoordinateSystem diff --git a/Framework/Geometry/inc/MantidGeometry/MDGeometry/UnknownFrame.h b/Framework/Geometry/inc/MantidGeometry/MDGeometry/UnknownFrame.h index 2500e39c6f7de98158dfc38f4f65eb2e928e3298..9e593e23872968628316c8344a18d6a3f95e7614 100644 --- a/Framework/Geometry/inc/MantidGeometry/MDGeometry/UnknownFrame.h +++ b/Framework/Geometry/inc/MantidGeometry/MDGeometry/UnknownFrame.h @@ -41,6 +41,8 @@ public: virtual ~UnknownFrame(); std::string name() const; bool canConvertTo(const Mantid::Kernel::MDUnit &otherUnit) const; + bool isQ() const; + bool isSameType(const MDFrame& frame) const; Mantid::Kernel::UnitLabel getUnitLabel() const; const Mantid::Kernel::MDUnit &getMDUnit() const; Mantid::Kernel::SpecialCoordinateSystem diff --git a/Framework/Geometry/src/MDGeometry/GeneralFrame.cpp b/Framework/Geometry/src/MDGeometry/GeneralFrame.cpp index af098ed36d196b919561a2beccc335a30ffd4e52..502f4ebbdc3fe8be5f33c3e4e3198cccbdbb5955 100644 --- a/Framework/Geometry/src/MDGeometry/GeneralFrame.cpp +++ b/Framework/Geometry/src/MDGeometry/GeneralFrame.cpp @@ -42,5 +42,17 @@ GeneralFrame::equivalientSpecialCoordinateSystem() const { return Mantid::Kernel::SpecialCoordinateSystem::None; } +bool GeneralFrame::isQ() const { return false; } + +bool GeneralFrame::isSameType(const MDFrame &frame) const { + auto isSameType = true; + try { + dynamic_cast<const GeneralFrame &>(frame); + } catch (std::bad_cast &) { + isSameType = false; + } + return isSameType; +} + } // namespace Geometry } // namespace Mantid diff --git a/Framework/Geometry/src/MDGeometry/HKL.cpp b/Framework/Geometry/src/MDGeometry/HKL.cpp index b109b8b99fc40efe5e817f966113ee141be9cb04..3501e925cba6c479af8140a67666d3296cd934ee 100644 --- a/Framework/Geometry/src/MDGeometry/HKL.cpp +++ b/Framework/Geometry/src/MDGeometry/HKL.cpp @@ -69,5 +69,16 @@ HKL::equivalientSpecialCoordinateSystem() const { return Mantid::Kernel::SpecialCoordinateSystem::HKL; } +bool HKL::isQ() const { return true; } + +bool HKL::isSameType(const MDFrame &frame) const { + auto isSameType = true; + try { + dynamic_cast<const HKL &>(frame); + } catch (std::bad_cast &) { + isSameType = false; + } + return isSameType; +} } // namespace Geometry } // namespace Mantid diff --git a/Framework/Geometry/src/MDGeometry/QLab.cpp b/Framework/Geometry/src/MDGeometry/QLab.cpp index 85622c3f5c718b6963aca95e67d73ffd526d55e4..28f50d7dce6e44d94ab0ec5b8e20bf8397d4f627 100644 --- a/Framework/Geometry/src/MDGeometry/QLab.cpp +++ b/Framework/Geometry/src/MDGeometry/QLab.cpp @@ -40,5 +40,19 @@ QLab::equivalientSpecialCoordinateSystem() const { return Mantid::Kernel::SpecialCoordinateSystem::QLab; } +bool QLab::isQ() const { + return true; +} + +bool QLab::isSameType(const MDFrame& frame) const { + auto isSameType = true; + try { + dynamic_cast<const QLab&>(frame); + } catch (std::bad_cast&) { + isSameType = false; + } + return isSameType; +} + } // namespace Geometry } // namespace Mantid diff --git a/Framework/Geometry/src/MDGeometry/QSample.cpp b/Framework/Geometry/src/MDGeometry/QSample.cpp index 8a616e53010d0fc54de7e5617e0e9f954d9b63a4..6575ad0629532adc4679987e7e72d391bc796953 100644 --- a/Framework/Geometry/src/MDGeometry/QSample.cpp +++ b/Framework/Geometry/src/MDGeometry/QSample.cpp @@ -35,5 +35,17 @@ QSample::equivalientSpecialCoordinateSystem() const { return Mantid::Kernel::SpecialCoordinateSystem::QSample; } +bool QSample::isQ() const { return true; } + +bool QSample::isSameType(const MDFrame &frame) const { + auto isSameType = true; + try { + dynamic_cast<const QSample &>(frame); + } catch (std::bad_cast &) { + isSameType = false; + } + return isSameType; +} + } // namespace Geometry } // namespace Mantid diff --git a/Framework/Geometry/src/MDGeometry/UnknownFrame.cpp b/Framework/Geometry/src/MDGeometry/UnknownFrame.cpp index 29790a44322a47528ac00cc404c612962e1d4e14..6978a0fae51e3056471ede3e888713ab560c9918 100644 --- a/Framework/Geometry/src/MDGeometry/UnknownFrame.cpp +++ b/Framework/Geometry/src/MDGeometry/UnknownFrame.cpp @@ -35,5 +35,20 @@ UnknownFrame::equivalientSpecialCoordinateSystem() const { UnknownFrame *UnknownFrame::clone() const { return new UnknownFrame(std::unique_ptr<Kernel::MDUnit>(m_unit->clone())); } + +bool UnknownFrame::isQ() const{ + return false; +} + +bool UnknownFrame::isSameType(const MDFrame &frame) const { + auto isSameType = true; + try { + dynamic_cast<const UnknownFrame &>(frame); + } catch (std::bad_cast &) { + isSameType = false; + } + return isSameType; +} + } } diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/SlicingAlgorithm.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/SlicingAlgorithm.h index 72827e329c5224df45e81c4b7f9c6102811fb641..6f824da3cfaafb5f5422e6bc8261e057462102d5 100644 --- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/SlicingAlgorithm.h +++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/SlicingAlgorithm.h @@ -152,8 +152,18 @@ protected: bool m_NormalizeBasisVectors; private: - //Mantid::Geometry::MDFrame_uptr createMDFrameForNonAxisAligned(std::string units) const; - + Mantid::Geometry::MDFrame_uptr + createMDFrameForNonAxisAligned(std::string units, + Mantid::Kernel::VMD basisVector) const; + std::vector<Mantid::Kernel::VMD> getOldBasis(size_t dimension) const; + bool isProjectingOnFrame(const Mantid::Kernel::VMD &oldVector, + const Mantid::Kernel::VMD &basisVector) const; + std::vector<size_t> getIndicesWithProjection( + const Mantid::Kernel::VMD &basisVector, + const std::vector<Mantid::Kernel::VMD> &oldBasis) const; + Mantid::Geometry::MDFrame_uptr + extractMDFrameForNonAxisAligned(std::vector<size_t> indicesWithProjection, + std::string units) const; }; } // namespace DataObjects diff --git a/Framework/MDAlgorithms/src/MDEventWSWrapper.cpp b/Framework/MDAlgorithms/src/MDEventWSWrapper.cpp index a7586ccdb57fda588dfee283bad4f658a9022050..f288262e3067891cc48ba147582667dd4a901318 100644 --- a/Framework/MDAlgorithms/src/MDEventWSWrapper.cpp +++ b/Framework/MDAlgorithms/src/MDEventWSWrapper.cpp @@ -39,9 +39,10 @@ void MDEventWSWrapper::createEmptyEventWS(const MDWSDescription &description) { Mantid::coord_t(description.getDimMax()[d]), nBins); } else { + Mantid::Geometry::GeneralFrame frame(description.getDimNames()[d], + description.getDimUnits()[d]); dim = new Geometry::MDHistoDimension( - description.getDimNames()[d], description.getDimIDs()[d], - description.getDimUnits()[d], + description.getDimNames()[d], description.getDimIDs()[d], frame, Mantid::coord_t(description.getDimMin()[d]), Mantid::coord_t(description.getDimMax()[d]), nBins); } diff --git a/Framework/MDAlgorithms/src/SlicingAlgorithm.cpp b/Framework/MDAlgorithms/src/SlicingAlgorithm.cpp index aa6e472019c7d11a5a857bba679776c7dd07e9fa..123a988f17833a16f216a48b627f27ded3b2beb9 100644 --- a/Framework/MDAlgorithms/src/SlicingAlgorithm.cpp +++ b/Framework/MDAlgorithms/src/SlicingAlgorithm.cpp @@ -251,11 +251,11 @@ void SlicingAlgorithm::makeBasisVectorFromString(const std::string &str) { std::string units = Strings::strip(strs[0]); // Create the appropriate frame - //auto frame = createMDFrame(units); + auto frame = createMDFrameForNonAxisAligned(units, basis); // Create the output dimension MDHistoDimension_sptr out( - new MDHistoDimension(name, id, units, static_cast<coord_t>(min), + new MDHistoDimension(name, id, *frame, static_cast<coord_t>(min), static_cast<coord_t>(max), numBins)); // Put both in the algo for future use @@ -513,7 +513,7 @@ void SlicingAlgorithm::makeAlignedDimensionFromString(const std::string &str) { // Copy the dimension name, ID and units IMDDimension_const_sptr inputDim = m_inWS->getDimension(dim_index); - const auto& frame = inputDim->getMDFrame(); + const auto &frame = inputDim->getMDFrame(); m_binDimensions.push_back(MDHistoDimension_sptr( new MDHistoDimension(inputDim->getName(), inputDim->getDimensionId(), frame, min, max, numBins))); @@ -1006,18 +1006,97 @@ SlicingAlgorithm::getImplicitFunctionForChunk(const size_t *const chunkMin, } } -#if 0 /** - * Create an MDFrame for the Non-Axis-Aligned case - * 1. Check that Q-based frames are not mixed with non-Q-based frames - * 2. Select Q-based frame if available + * Create an MDFrame for the Non-Axis-Aligned case. Make sure that + * MDFrames onto which the basis vector projects are not mixed, e.g. no mixing + * of HKL and GenerFrame * @param units: the units + * @param basisVector: the basis vector * @returns the unique pointer */ -Mantid::Geometry::MDFrame_uptr SlicingAlgorithm::createMDFrameForNonAxisAligned(std::string units) const { +Mantid::Geometry::MDFrame_uptr SlicingAlgorithm::createMDFrameForNonAxisAligned( + std::string units, Mantid::Kernel::VMD basisVector) const { + // Get set of basis vectors + auto oldBasis = getOldBasis(m_inWS->getNumDims()); + // Get indices onto which the vector projects + auto indicesWithProjection = getIndicesWithProjection(basisVector, oldBasis); + + // Extract MDFrame + return extractMDFrameForNonAxisAligned(indicesWithProjection, units); +} + +std::vector<Mantid::Kernel::VMD> +SlicingAlgorithm::getOldBasis(size_t dimension) const { + std::vector<Mantid::Kernel::VMD> oldBasis; + for (size_t i = 0; i < dimension; ++i) { + Mantid::Kernel::VMD basisVector(dimension); + basisVector[i] = 1.0; + oldBasis.push_back(basisVector); + } + return oldBasis; +} + +/** + * Check if the two vectors are orthogonal or not + * @param oldVector: the old vector + * @param basisVector: the vector under investigation + * @returns true if there is a projection else false + */ +bool SlicingAlgorithm::isProjectingOnFrame( + const Mantid::Kernel::VMD &oldVector, + const Mantid::Kernel::VMD &basisVector) const { + return std::fabs(oldVector.scalar_prod(basisVector)) > 0.0; +} + +/** + * Get indices which have a projection contribution + * @param basisVector: the vector under investigation + * @param oldBasis: the old basis vectors + * @returns the indices of vectors onto which the basisVector projects + */ +std::vector<size_t> SlicingAlgorithm::getIndicesWithProjection( + const Mantid::Kernel::VMD &basisVector, + const std::vector<Mantid::Kernel::VMD> &oldBasis) const { + std::vector<size_t> indexWithProjection; + for (size_t index = 0; index < oldBasis.size(); ++index) { + if (isProjectingOnFrame(oldBasis[index], basisVector)) { + indexWithProjection.push_back(index); + } + } + return indexWithProjection; +} + +/** + * Extract the MDFrame. Make sure that all MDFrames are compatible -- if not + * throw + * @param indicesWithProjection: list of indices of dimensions which have a + * projection + * @param units: the units + */ +Mantid::Geometry::MDFrame_uptr +SlicingAlgorithm::extractMDFrameForNonAxisAligned( + std::vector<size_t> indicesWithProjection, std::string units) const { + if (indicesWithProjection.empty()) { + throw std::runtime_error("Slicing Algorithm: Chosen vector does not " + "project on any vector of the old basis."); + } + // Get a reference frame to perform pairwise comparison + const auto& referenceMDFrame = + m_inWS->getDimension(indicesWithProjection[0])->getMDFrame(); + + for (auto it = indicesWithProjection.begin(); + it != indicesWithProjection.end(); ++it) { + const auto& toCheckMDFrame = m_inWS->getDimension(*it)->getMDFrame(); + if (!referenceMDFrame.isSameType(toCheckMDFrame)) { + throw std::runtime_error("Slicing Algorithm: New basis yvector tries to " + "mix un-mixable MDFrame types."); + } + } + + Mantid::Geometry::MDFrame_uptr mdFrame(referenceMDFrame.clone()); + return mdFrame; } -#endif } // namespace Mantid } // namespace DataObjects diff --git a/Framework/MDAlgorithms/test/SlicingAlgorithmTest.h b/Framework/MDAlgorithms/test/SlicingAlgorithmTest.h index 762ffd5f2d12c660586fb3b8f01095fac3a46d4d..66f413e8876215ee1379cd730db1cf4015811894 100644 --- a/Framework/MDAlgorithms/test/SlicingAlgorithmTest.h +++ b/Framework/MDAlgorithms/test/SlicingAlgorithmTest.h @@ -4,9 +4,11 @@ #include "MantidKernel/VMD.h" #include "MantidGeometry/MDGeometry/IMDDimension.h" #include "MantidGeometry/MDGeometry/MDImplicitFunction.h" +#include "MantidGeometry/MDGeometry/QSample.h" #include "MantidMDAlgorithms/SlicingAlgorithm.h" #include "MantidTestHelpers/MDEventsTestHelper.h" - +#include "MantidKernel/MDUnit.h" +#include "MantidKernel/UnitLabel.h" #include <cxxtest/TestSuite.h> using namespace Mantid::API; @@ -48,6 +50,8 @@ public: IMDEventWorkspace_sptr ws3; IMDEventWorkspace_sptr ws4; IMDEventWorkspace_sptr ws5; + IMDEventWorkspace_sptr wsQSample; + IMDEventWorkspace_sptr wsMixedFrames; IMDEventWorkspace_sptr ws_names; SlicingAlgorithmTest() { @@ -57,6 +61,19 @@ public: ws3 = MDEventsTestHelper::makeMDEW<3>(5, 0.0, 10.0, 1); ws4 = MDEventsTestHelper::makeMDEW<4>(5, 0.0, 10.0, 1); ws5 = MDEventsTestHelper::makeMDEW<5>(5, 0.0, 10.0, 1); + // Workspace with QSample frames + Mantid::Geometry::QSample qSampleFrame; + wsQSample = MDEventsTestHelper::makeMDEWWithFrames<3>(5, 0.0, 10.0, + qSampleFrame, 1); + // Workspace with mixed frames + std::vector<Mantid::Geometry::MDFrame_sptr> frames; + frames.push_back(std::make_shared<Mantid::Geometry::QSample>()); + frames.push_back(std::make_shared<Mantid::Geometry::QSample>()); + frames.push_back(std::make_shared<Mantid::Geometry::QSample>()); + frames.push_back(std::make_shared<Mantid::Geometry::GeneralFrame>( + Mantid::Geometry::GeneralFrame::GeneralFrameDistance, "m")); + wsMixedFrames = MDEventsTestHelper::makeMDEWWithIndividualFrames<4>( + 5, 0.0, 10.0, frames, 1); /// Workspace with custom names ws_names = MDEventsTestHelper::makeAnyMDEW<MDEvent<3>, 3>( 3, 0.0, 10.0, 1, "", "[%dh,k,l]", "Q%d"); @@ -95,7 +112,7 @@ public: alg.makeAlignedDimensionFromString("Axis0, 11.0, 9.0")); } - void test_makeAlignedDimensionFromString() { + void test_makeAlignedDimensionFromString() { SlicingAlgorithmImpl alg; alg.m_inWS = ws; TSM_ASSERT_THROWS_NOTHING( @@ -112,6 +129,28 @@ public: TS_ASSERT_EQUALS(dim->getX(10), 9.0); } + void test_makeAlignedDimensionFromStringWithMDFrameSetToQSample() { + SlicingAlgorithmImpl alg; + alg.m_inWS = wsQSample; + TSM_ASSERT_THROWS_NOTHING( + "", alg.makeAlignedDimensionFromString("Axis2, 1.0, 9.0, 10")); + TS_ASSERT_EQUALS(alg.m_dimensionToBinFrom.size(), 1); + TS_ASSERT_EQUALS(alg.m_binDimensions.size(), 1); + + TS_ASSERT_EQUALS(alg.m_dimensionToBinFrom[0], 2); + + IMDDimension_sptr dim = alg.m_binDimensions[0]; + TS_ASSERT_EQUALS(dim->getName(), "Axis2"); + TS_ASSERT_EQUALS( + dim->getUnits(), + Mantid::Kernel::InverseAngstromsUnit().getUnitLabel().ascii()); + TSM_ASSERT_THROWS_NOTHING( + "Should be a QSample", + dynamic_cast<const Mantid::Geometry::QSample &>(dim->getMDFrame())) + TS_ASSERT_EQUALS(dim->getNBins(), 10); + TS_ASSERT_EQUALS(dim->getX(10), 9.0); + } + /// Dimension name is of style "[x,y,z]". Handle this. void test_makeAlignedDimensionFromString_NameWithCommas() { SlicingAlgorithmImpl alg; @@ -373,7 +412,8 @@ public: TS_ASSERT_EQUALS(alg.m_bases[0], basis); IMDDimension_sptr dim = alg.m_binDimensions[0]; TS_ASSERT_EQUALS(dim->getName(), "name"); - TS_ASSERT_EQUALS(dim->getUnits(), "units"); + TSM_ASSERT("The units selection is ignored", dim->getUnits() != "units"); + TSM_ASSERT("The unit is in m", dim->getUnits() == "m"); TS_ASSERT_EQUALS(dim->getNBins(), 20); TS_ASSERT_EQUALS(dim->getMinimum(), -5); TS_ASSERT_EQUALS(dim->getMaximum(), +5); @@ -397,6 +437,68 @@ public: } } + + void test_makeBasisVectorFromStringWithPureQSampleInput() { + // Test WITH and WITHOUT basis vector normalization + for (int normalize = 0; normalize < 2; normalize++) { + SlicingAlgorithmImpl alg; + alg.m_inWS = wsQSample; // All dimensions are QSample + // Set up data that comes from other properties + alg.m_minExtents.push_back(-5.0); + alg.m_maxExtents.push_back(+5.0); + alg.m_numBins.push_back(20); + alg.m_NormalizeBasisVectors = (normalize > 0); + + TS_ASSERT_EQUALS(alg.m_bases.size(), 0); + TSM_ASSERT_THROWS_NOTHING( + "", alg.makeBasisVectorFromString(" name, units , 1,2,3")); + TS_ASSERT_EQUALS(alg.m_bases.size(), 1); + TS_ASSERT_EQUALS(alg.m_binDimensions.size(), 1); + TS_ASSERT_EQUALS(alg.m_binningScaling.size(), 1); + TS_ASSERT_EQUALS(alg.m_transformScaling.size(), 1); + + VMD basis(1., 2., 3.); + if (alg.m_NormalizeBasisVectors) + basis.normalize(); + + TS_ASSERT_EQUALS(alg.m_bases[0], basis); + IMDDimension_sptr dim = alg.m_binDimensions[0]; + TS_ASSERT_EQUALS(dim->getName(), "name"); + TSM_ASSERT("The units selection is ignored", dim->getUnits() != "units"); + TS_ASSERT_EQUALS( + dim->getUnits(), + Mantid::Kernel::InverseAngstromsUnit().getUnitLabel().ascii()); + TSM_ASSERT_THROWS_NOTHING( + "Should be a QSample", + dynamic_cast<const Mantid::Geometry::QSample &>(dim->getMDFrame())) + + TS_ASSERT_EQUALS(dim->getNBins(), 20); + TS_ASSERT_EQUALS(dim->getMinimum(), -5); + TS_ASSERT_EQUALS(dim->getMaximum(), +5); + TS_ASSERT_DELTA(dim->getX(5), -2.5, 1e-5); + + if (alg.m_NormalizeBasisVectors) { + TSM_ASSERT_DELTA("Unit transformation scaling if normalizing", + alg.m_transformScaling[0], 1.0, 1e-5); + TSM_ASSERT_DELTA("A bin ranges from 0-0.5 in OUTPUT, which is 0.5 long " + "in the INPUT, " + "so the binningScaling is 2.", + alg.m_binningScaling[0], 2., 1e-5); + } else { + TSM_ASSERT_DELTA("Length sqrt(14) in INPUT = 1.0 in output", + alg.m_transformScaling[0], sqrt(1.0 / 14.0), 1e-5); + TSM_ASSERT_DELTA("A bin ranges from 0-0.5 in OUTPUT, which is " + "0.5/sqrt(14) long in the INPUT, " + "so the binningScaling is 2/sqrt(14)", + alg.m_binningScaling[0], 2. / sqrt(14.0), 1e-5); + } + } + } + + + + + /// Create a basis vector with a dimension with [commas,etc] in the name. void test_makeBasisVectorFromString_NameWithCommas() { SlicingAlgorithmImpl alg; @@ -424,7 +526,8 @@ public: IMDDimension_sptr dim = alg.m_binDimensions[0]; TS_ASSERT_EQUALS(dim->getName(), "[Dumb,Name]"); TS_ASSERT_EQUALS(dim->getDimensionId(), "[Dumb,Name]"); - TS_ASSERT_EQUALS(dim->getUnits(), "units"); + TSM_ASSERT("The units selection is ignored", dim->getUnits() != "units"); + TSM_ASSERT("The unit is in m", dim->getUnits() == "m"); TS_ASSERT_EQUALS(dim->getNBins(), 20); TS_ASSERT_EQUALS(dim->getMinimum(), -5); TS_ASSERT_EQUALS(dim->getMaximum(), +5); @@ -627,6 +730,23 @@ public: TS_ASSERT(!func->isPointContained(VMD(1.5, 1.5, 1.5, 11.5))); } + void test_createGeneralTransform_4D_to_4D_with_mixed_frames() { + SlicingAlgorithmImpl *alg = do_createGeneralTransform( + wsMixedFrames, "OutX, m, 1,0,0,0", "OutY, m, 0,1,0,0", "OutZ, m, 0,0,1,0", + "OutE,m, 0,0,0,1", VMD(1, 1, 1, 1), "0,10,0,10,0,10,0,10", "5,5,5,5"); + TS_ASSERT_EQUALS(alg->m_bases.size(), 4); + + // The implicit function + MDImplicitFunction *func(NULL); + TS_ASSERT_THROWS_NOTHING(func = + alg->getImplicitFunctionForChunk(NULL, NULL)); + TS_ASSERT(func); + TS_ASSERT_EQUALS(func->getNumPlanes(), 8); + TS_ASSERT(func->isPointContained(VMD(1.5, 1.5, 1.5, 1.5))); + TS_ASSERT(!func->isPointContained(VMD(1.5, 1.5, 1.5, -1.5))); + TS_ASSERT(!func->isPointContained(VMD(1.5, 1.5, 1.5, 11.5))); + } + /** 4D "left-handed" coordinate system * obtained by flipping the Y basis vector. */ void test_createGeneralTransform_4D_to_4D_LeftHanded() { diff --git a/Framework/SINQ/src/LoadFlexiNexus.cpp b/Framework/SINQ/src/LoadFlexiNexus.cpp index d589ce89c86d6df3055e64532ff7ba7071916091..644c05118e1e465dfc1b12ba359349b97d17997c 100644 --- a/Framework/SINQ/src/LoadFlexiNexus.cpp +++ b/Framework/SINQ/src/LoadFlexiNexus.cpp @@ -297,8 +297,9 @@ MDHistoDimension_sptr LoadFlexiNexus::makeDimension(NeXus::File *fin, int index, min = tmp; g_log.notice("WARNING: swapped axis values on " + name); } + Mantid::Geometry::GeneralFrame frame(name, ""); return MDHistoDimension_sptr( - new MDHistoDimension(name, name, "", min, max, length)); + new MDHistoDimension(name, name, frame, min, max, length)); } void LoadFlexiNexus::addMetaData(NeXus::File *fin, Workspace_sptr ws, ExperimentInfo_sptr info) { diff --git a/Framework/SINQ/test/LoadFlexiNexusTest.h b/Framework/SINQ/test/LoadFlexiNexusTest.h index ad43fde6f3a26ec322a66a43df263aa5be0a6d29..418b57ab0ad487126d0fe2783870dcb4974b5030 100644 --- a/Framework/SINQ/test/LoadFlexiNexusTest.h +++ b/Framework/SINQ/test/LoadFlexiNexusTest.h @@ -65,6 +65,8 @@ public: TS_ASSERT_DELTA(dimi->getMinimum(), -86, .1); TS_ASSERT_DELTA(dimi->getMaximum(), 84.65, .1); + + // test some meta data std::string title = data->getTitle(); size_t found = title.find("Selene"); diff --git a/Framework/TestHelpers/inc/MantidTestHelpers/MDEventsTestHelper.h b/Framework/TestHelpers/inc/MantidTestHelpers/MDEventsTestHelper.h index ea95ef80a6ed36f323cdfccca0604147933443ca..c2edb75dc8ff427f4f97ce48f83e79af5d3245c1 100644 --- a/Framework/TestHelpers/inc/MantidTestHelpers/MDEventsTestHelper.h +++ b/Framework/TestHelpers/inc/MantidTestHelpers/MDEventsTestHelper.h @@ -75,6 +75,26 @@ void addMDDimensionsWithFrames( out->initialize(); } +template <typename MDE, size_t nd> +void addMDDimensionsWithIndividualFrames( + boost::shared_ptr<Mantid::DataObjects::MDEventWorkspace<MDE, nd>> out, + Mantid::coord_t min, Mantid::coord_t max, + std::vector<Mantid::Geometry::MDFrame_sptr> frame, + std::string axisNameFormat, std::string axisIdFormat) { + for (size_t d = 0; d < nd; d++) { + char name[200]; + sprintf(name, axisNameFormat.c_str(), d); + char id[200]; + sprintf(id, axisIdFormat.c_str(), d); + + // Use the same frame for all dimensions + auto dim = boost::make_shared<Mantid::Geometry::MDHistoDimension>( + std::string(name), std::string(id), *frame[d], min, max, 10); + out->addDimension(dim); + } + out->initialize(); +} + template <typename MDE, size_t nd> void addData( boost::shared_ptr<Mantid::DataObjects::MDEventWorkspace<MDE, nd>> out, @@ -197,6 +217,47 @@ makeAnyMDEW(size_t splitInto, coord_t min, coord_t max, return out; } + +/** Create a test MDEventWorkspace<nd> . Dimensions are names Axis0, Axis1, etc. + * But you can set an MDFrame. The frames can be set individually. + * + * @param splitInto :: each dimension will split into this many subgrids + * @param min :: extent of each dimension (min) + * @param max :: extent of each dimension (max) + * @param frames:: the chosen frame + * @param numEventsPerBox :: will create one MDLeanEvent in the center of each + *sub-box. + * 0 = don't split box, don't add events + * @param wsName :: if specified, then add the workspace to the analysis data + *service + * @param axisNameFormat :: string for the axis name, processed via sprintf() + * @param axisIdFormat :: string for the axis ID, processed via sprintf() + * @return shared ptr to the created workspace + */ +template <typename MDE, size_t nd> +boost::shared_ptr<Mantid::DataObjects::MDEventWorkspace<MDE, nd>> +makeAnyMDEWWithIndividualFrames(size_t splitInto, coord_t min, coord_t max, + std::vector<Mantid::Geometry::MDFrame_sptr>frames, + size_t numEventsPerBox = 0, std::string wsName = "", + std::string axisNameFormat = "Axis%d", + std::string axisIdFormat = "Axis%d") { + // Create bare workspace + auto out = createOutputWorkspace<MDE, nd>(splitInto); + + // Add standard dimensions + addMDDimensionsWithIndividualFrames<MDE, nd>(out, min, max, frames, axisNameFormat, + axisIdFormat); + + // Add data + addData<MDE, nd>(out, splitInto, min, max, numEventsPerBox); + + // Add to ADS on option + if (!wsName.empty()) + Mantid::API::AnalysisDataService::Instance().addOrReplace(wsName, out); + + return out; +} + /** Create a test MDEventWorkspace<nd> . Dimensions are names Axis0, Axis1, etc. * But you can set an MDFrame. For now the same frame for all dimensions * is used. @@ -256,6 +317,18 @@ makeMDEWWithFrames(size_t splitInto, coord_t min, coord_t max, numEventsPerBox); } +/** Make a MDEventWorkspace with MDLeanEvents and individual MDFrames*/ +template <size_t nd> +boost::shared_ptr<MDEventWorkspace<MDLeanEvent<nd>, nd>> +makeMDEWWithIndividualFrames(size_t splitInto, coord_t min, coord_t max, + std::vector<Mantid::Geometry::MDFrame_sptr> frame, + size_t numEventsPerBox = 0) { + return makeAnyMDEWWithIndividualFrames<MDLeanEvent<nd>, nd>(splitInto, min, max, frame, + numEventsPerBox); +} + + + /** Make a MDEventWorkspace with MDEvents - updated to split dims by splitInto, * not 10 */ template <size_t nd>