Skip to content
Snippets Groups Projects
Commit 7a2e8c7d authored by Owen Arnold's avatar Owen Arnold
Browse files

refs #13517. TransposeMD created.

More optimization work needed yet.
parent 4749f34b
No related branches found
No related tags found
No related merge requests found
...@@ -109,6 +109,7 @@ set ( SRC_FILES ...@@ -109,6 +109,7 @@ set ( SRC_FILES
src/SmoothMD.cpp src/SmoothMD.cpp
src/ThresholdMD.cpp src/ThresholdMD.cpp
src/TransformMD.cpp src/TransformMD.cpp
src/TransposeMD.cpp
src/UnaryOperationMD.cpp src/UnaryOperationMD.cpp
src/UnitsConversionHelper.cpp src/UnitsConversionHelper.cpp
src/UserFunctionMD.cpp src/UserFunctionMD.cpp
...@@ -227,6 +228,7 @@ set ( INC_FILES ...@@ -227,6 +228,7 @@ set ( INC_FILES
inc/MantidMDAlgorithms/SmoothMD.h inc/MantidMDAlgorithms/SmoothMD.h
inc/MantidMDAlgorithms/ThresholdMD.h inc/MantidMDAlgorithms/ThresholdMD.h
inc/MantidMDAlgorithms/TransformMD.h inc/MantidMDAlgorithms/TransformMD.h
inc/MantidMDAlgorithms/TransposeMD.h
inc/MantidMDAlgorithms/UnaryOperationMD.h inc/MantidMDAlgorithms/UnaryOperationMD.h
inc/MantidMDAlgorithms/UnitsConversionHelper.h inc/MantidMDAlgorithms/UnitsConversionHelper.h
inc/MantidMDAlgorithms/Vector3DParameter.h inc/MantidMDAlgorithms/Vector3DParameter.h
...@@ -334,6 +336,7 @@ set ( TEST_FILES ...@@ -334,6 +336,7 @@ set ( TEST_FILES
TobyFitResolutionModelTest.h TobyFitResolutionModelTest.h
TobyFitYVectorTest.h TobyFitYVectorTest.h
TransformMDTest.h TransformMDTest.h
TransposeMDTest.h
UnaryOperationMDTest.h UnaryOperationMDTest.h
UnitsConversionHelperTest.h UnitsConversionHelperTest.h
WeightedMeanMDTest.h WeightedMeanMDTest.h
......
#ifndef MANTID_MDALGORITHMS_TRANSPOSEMD_H_
#define MANTID_MDALGORITHMS_TRANSPOSEMD_H_
#include "MantidMDAlgorithms/DllConfig.h"
#include "MantidAPI/Algorithm.h"
namespace Mantid {
namespace MDAlgorithms {
/** TransposeMD : Transpose an MDWorkspace. Allows dimensions to be collapsed down.
Copyright © 2015 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
National Laboratory & European Spallation Source
This file is part of Mantid.
Mantid is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Mantid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
File change history is stored at: <https://github.com/mantidproject/mantid>
Code Documentation is available at: <http://doxygen.mantidproject.org>
*/
class MANTID_MDALGORITHMS_DLL TransposeMD : public API::Algorithm {
public:
TransposeMD();
virtual ~TransposeMD();
virtual const std::string name() const;
virtual int version() const;
virtual const std::string category() const;
virtual const std::string summary() const;
private:
void init();
void exec();
};
} // namespace MDAlgorithms
} // namespace Mantid
#endif /* MANTID_MDALGORITHMS_TRANSPOSEMD_H_ */
#include "MantidMDAlgorithms/TransposeMD.h"
#include "MantidKernel/ArrayProperty.h"
#include "MantidKernel/ArrayBoundedValidator.h"
#include "MantidAPI/IMDHistoWorkspace.h"
#include "MantidAPI/IMDIterator.h"
#include "MantidDataObjects/CoordTransformAligned.h"
#include "MantidDataObjects/MDHistoWorkspace.h"
#include "MantidGeometry/MDGeometry/IMDDimension.h"
#include "MantidGeometry/MDGeometry/MDHistoDimension.h"
#include <vector>
#include <algorithm>
#include <numeric>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
namespace Mantid {
namespace MDAlgorithms {
using namespace Mantid::Kernel;
using namespace Mantid::API;
using namespace Mantid::DataObjects;
// Register the algorithm into the AlgorithmFactory
DECLARE_ALGORITHM(TransposeMD)
//----------------------------------------------------------------------------------------------
/** Constructor
*/
TransposeMD::TransposeMD() {}
//----------------------------------------------------------------------------------------------
/** Destructor
*/
TransposeMD::~TransposeMD() {}
//----------------------------------------------------------------------------------------------
/// Algorithms name for identification. @see Algorithm::name
const std::string TransposeMD::name() const { return "TransposeMD"; }
/// Algorithm's version for identification. @see Algorithm::version
int TransposeMD::version() const { return 1; }
/// Algorithm's category for identification. @see Algorithm::category
const std::string TransposeMD::category() const { return "MDAlgorithms"; }
/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary
const std::string TransposeMD::summary() const {
return "Transpose the dimensions of a MDWorkspace to create a new output "
"MDWorkspace";
}
//----------------------------------------------------------------------------------------------
/** Initialize the algorithm's properties.
*/
void TransposeMD::init() {
declareProperty(new WorkspaceProperty<IMDHistoWorkspace>("InputWorkspace", "",
Direction::Input),
"An input workspace.");
auto axisValidator = boost::make_shared<ArrayBoundedValidator<int>>();
axisValidator->clearUpper();
axisValidator->setLower(0);
declareProperty(new ArrayProperty<int>("Axes", std::vector<int>(0),
axisValidator, Direction::Input),
"Permutes the axes according to the indexes given. Zero "
"based indexing. Defaults to no transpose.");
declareProperty(new WorkspaceProperty<IMDHistoWorkspace>(
"OutputWorkspace", "", Direction::Output),
"An output workspace.");
}
//----------------------------------------------------------------------------------------------
/** Execute the algorithm.
*/
void TransposeMD::exec() {
IMDHistoWorkspace_sptr inWSProp = getProperty("InputWorkspace");
auto inWS = boost::dynamic_pointer_cast<MDHistoWorkspace>(inWSProp);
if (!inWS) {
throw std::invalid_argument(
"Expect the InputWorkspace to be a MDHistoWorkspace");
}
size_t nDimsInput = inWS->getNumDims();
size_t nDimsOutput = inWS->getNumDims(); // The assumed default.
std::vector<int> axesInts = this->getProperty("Axes");
std::vector<size_t> axes(axesInts.begin(), axesInts.end());
Property *axesProperty = this->getProperty("Axes");
if (!axesProperty->isDefault()) {
if (axes.size() > nDimsInput) {
throw std::invalid_argument(
"More axis specified than dimensions are avaiable in the input");
}
auto it = std::max_element(axes.begin(), axes.end());
if (*it > nDimsInput) {
throw std::invalid_argument("One of the axis indexes specified indexes a "
"dimension outside the real dimension range");
}
nDimsOutput = axes.size();
} else {
axes = std::vector<size_t>(nDimsOutput);
std::iota(axes.begin(), axes.end(), 0);
}
std::vector<coord_t> origin;
std::vector<Geometry::IMDDimension_sptr> targetGeometry;
for (size_t i = 0; i < nDimsOutput; ++i) {
// Clone the dimension corresponding to the axis requested.
auto cloneDim = Geometry::IMDDimension_sptr(
new Geometry::MDHistoDimension(inWS->getDimension(axes[i]).get()));
targetGeometry.push_back(cloneDim);
// Set the same origin as we have on the input workspace
origin.push_back(coord_t(cloneDim->getMinimum()));
}
// Make the output workspace in the right shape.
auto outWS = MDHistoWorkspace_sptr(new MDHistoWorkspace(targetGeometry));
// Configure the coordinate transform.
std::vector<coord_t> scaling(nDimsOutput, 1); // No scaling
CoordTransformAligned coordTransform(nDimsInput, nDimsOutput, axes, origin,
scaling);
IMDIterator * inIterator = inWS->createIterator();
do{
auto center = inIterator->getCenter();
const coord_t* incoords = center.getBareArray();
std::vector<coord_t> outcoords(nDimsOutput);
coordTransform.apply(incoords, &outcoords[0]);
size_t index = outWS->getLinearIndexAtCoord(&outcoords[0]);
outWS->setSignalAt(index, inIterator->getSignal());
outWS->setErrorSquaredAt(index, inIterator->getError()*inIterator->getError());
// TODO more otherwise
}while(inIterator->next());
this->setProperty("OutputWorkspace",
outWS);
}
} // namespace MDAlgorithms
} // namespace Mantid
#ifndef MANTID_MDALGORITHMS_TRANSPOSEMDTEST_H_
#define MANTID_MDALGORITHMS_TRANSPOSEMDTEST_H_
#include <cxxtest/TestSuite.h>
#include <vector>
#include "MantidMDAlgorithms/TransposeMD.h"
#include "MantidTestHelpers/MDEventsTestHelper.h"
#include "MantidGeometry/MDGeometry/MDTypes.h"
using Mantid::MDAlgorithms::TransposeMD;
using namespace Mantid::DataObjects;
using namespace Mantid::API;
class TransposeMDTest : public CxxTest::TestSuite {
public:
// This pair of boilerplate methods prevent the suite being created statically
// This means the constructor isn't called when running other tests
static TransposeMDTest *createSuite() { return new TransposeMDTest(); }
static void destroySuite(TransposeMDTest *suite) { delete suite; }
void test_Init() {
TransposeMD alg;
TS_ASSERT_THROWS_NOTHING(alg.initialize())
TS_ASSERT(alg.isInitialized())
}
void test_valid_axes_lower_limit_throws() {
TransposeMD transposeMD;
transposeMD.initialize();
std::vector<int> axes;
axes.push_back(1); // should be fine.
TS_ASSERT_THROWS_NOTHING(transposeMD.setProperty("Axes", axes));
axes.push_back(-1); // Not a valid axis
TS_ASSERT_THROWS(transposeMD.setProperty("Axes", axes),
std::invalid_argument &);
}
void test_too_many_dimension_indexes_throws() {
auto inputWS = MDEventsTestHelper::makeFakeMDHistoWorkspace(
1 /*signal*/, 2 /*numDims*/, 3 /*numBins in each dimension*/);
TransposeMD transposeMD;
transposeMD.setChild(true);
transposeMD.initialize();
transposeMD.setPropertyValue("OutputWorkspace", "dummy");
transposeMD.setProperty(
"Axes",
std::vector<int>(4, 1)); // 4-axis entries, but only 3 dimensions
transposeMD.setProperty("InputWorkspace", inputWS);
TS_ASSERT_THROWS(transposeMD.execute(), std::invalid_argument &);
}
void test_indexes_that_dont_exist_throws() {
auto inputWS = MDEventsTestHelper::makeFakeMDHistoWorkspace(
1 /*signal*/, 2 /*numDims*/, 3 /*numBins in each dimension*/);
TransposeMD transposeMD;
transposeMD.setChild(true);
transposeMD.initialize();
transposeMD.setPropertyValue("OutputWorkspace", "dummy");
transposeMD.setProperty("Axes",
std::vector<int>(1, 3)); // Invalid index of 3!
transposeMD.setProperty("InputWorkspace", inputWS);
TSM_ASSERT_THROWS(
"Axis values can only be 0-2 for this ws. 3 is not valid.",
transposeMD.execute(), std::invalid_argument &);
}
void test_no_transpose() {
auto inputWS = MDEventsTestHelper::makeFakeMDHistoWorkspace(
1 /*signal*/, 2 /*numDims*/, 3 /*numBins in each dimension*/);
// Set some values. If transposed then these should end up elsewhere.
inputWS->setSignalAt(0, 2);
inputWS->setSignalAt(1, 2);
TransposeMD transposeMD;
transposeMD.setChild(true);
transposeMD.initialize();
transposeMD.setPropertyValue("OutputWorkspace", "dummy");
transposeMD.setProperty("InputWorkspace", inputWS);
transposeMD.execute();
IMDHistoWorkspace_sptr outputWS =
transposeMD.getProperty("OutputWorkspace");
// Lets check that the workspaces are essentially the same.
TS_ASSERT_EQUALS(inputWS->getNumDims(), outputWS->getNumDims());
TS_ASSERT_EQUALS(inputWS->getDimension(0)->getName(),
outputWS->getDimension(0)->getName());
TS_ASSERT_EQUALS(inputWS->getDimension(1)->getName(),
outputWS->getDimension(1)->getName());
// Data should be the same too.
TS_ASSERT_EQUALS(inputWS->getSignalAt(0), outputWS->getSignalAt(0));
TS_ASSERT_EQUALS(inputWS->getSignalAt(1), outputWS->getSignalAt(1));
TS_ASSERT_EQUALS(inputWS->getSignalAt(2), outputWS->getSignalAt(2));
}
void test_transpose_all() {
auto inputWS = MDEventsTestHelper::makeFakeMDHistoWorkspace(
1 /*signal*/, 2 /*numDims*/, 3 /*numBins in each dimension*/);
// Set some values. If transposed then these should end up elsewhere.
inputWS->setSignalAt(0, 2);
inputWS->setSignalAt(1, 2);
TransposeMD transposeMD;
transposeMD.setChild(true);
transposeMD.initialize();
transposeMD.setPropertyValue("OutputWorkspace", "dummy");
transposeMD.setProperty("InputWorkspace", inputWS);
std::vector<int> axes;
axes.push_back(1);
axes.push_back(0);
transposeMD.setProperty("Axes", axes);
transposeMD.execute();
IMDHistoWorkspace_sptr outputWS =
transposeMD.getProperty("OutputWorkspace");
// Lets check the output workspace
TS_ASSERT_EQUALS(inputWS->getNumDims(), outputWS->getNumDims());
TS_ASSERT_EQUALS(inputWS->getDimension(0)->getName(),
outputWS->getDimension(axes[0])->getName());
TS_ASSERT_EQUALS(inputWS->getDimension(1)->getName(),
outputWS->getDimension(axes[1])->getName());
// Data should be transposed.
TS_ASSERT_EQUALS(inputWS->getSignalAt(0), outputWS->getSignalAt(0));
TS_ASSERT_EQUALS(inputWS->getSignalAt(1), outputWS->getSignalAt(1 * 3));
TS_ASSERT_EQUALS(inputWS->getSignalAt(2), outputWS->getSignalAt(2));
}
void test_collapse() {
size_t nbins[3] = {3, 3, 1}; // last dimension integrated out
Mantid::coord_t min[3] = {0, 0, 0};
Mantid::coord_t max[3] = {10, 10, 5};
auto inputWS = MDEventsTestHelper::makeFakeMDHistoWorkspaceGeneral(3 /*ndims*/, 1 /*signal*/,
1 /*errorSquared*/,
nbins /*numBins*/, min, max);
// Set some values. If transposed then these should end up elsewhere.
inputWS->setSignalAt(0, 2);
inputWS->setSignalAt(1, 2);
TransposeMD transposeMD;
transposeMD.setChild(true);
transposeMD.initialize();
transposeMD.setPropertyValue("OutputWorkspace", "dummy");
transposeMD.setProperty("InputWorkspace", inputWS);
std::vector<int> axes;
axes.push_back(0);
axes.push_back(1);
transposeMD.setProperty("Axes", axes); // 0 and 1, but 2 not specified!
transposeMD.execute();
IMDHistoWorkspace_sptr outputWS =
transposeMD.getProperty("OutputWorkspace");
// Lets check that output workspace
TS_ASSERT_EQUALS(inputWS->getNumDims(), outputWS->getNumDims() + 1);
TS_ASSERT_EQUALS(inputWS->getDimension(0)->getName(),
outputWS->getDimension(axes[0])->getName());
TS_ASSERT_EQUALS(inputWS->getDimension(1)->getName(),
outputWS->getDimension(axes[1])->getName());
// Otherwise the data should be the same. We simply clipped off the
// integrated dimension.
TS_ASSERT_EQUALS(inputWS->getSignalAt(0), outputWS->getSignalAt(0));
TS_ASSERT_EQUALS(inputWS->getSignalAt(1), outputWS->getSignalAt(1));
TS_ASSERT_EQUALS(inputWS->getSignalAt(2), outputWS->getSignalAt(2));
}
};
#endif /* MANTID_MDALGORITHMS_TRANSPOSEMDTEST_H_ */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment