diff --git a/Code/Mantid/Framework/Algorithms/CMakeLists.txt b/Code/Mantid/Framework/Algorithms/CMakeLists.txt index 5f996cca86517aaca1fc36c712e58c9828ba7544..b115e93ceec264607465dff2a0f82a6aea250136 100644 --- a/Code/Mantid/Framework/Algorithms/CMakeLists.txt +++ b/Code/Mantid/Framework/Algorithms/CMakeLists.txt @@ -20,7 +20,7 @@ set ( SRC_FILES src/BinaryOperation.cpp src/CalMuonDeadTime.cpp src/CalculateEfficiency.cpp - src/CalculateFlatBackground.cpp + src/CalculateFlatBackground.cpp src/CalculateTransmission.cpp src/CalculateTransmissionBeamSpreader.cpp src/CalculateZscore.cpp @@ -34,6 +34,7 @@ set ( SRC_FILES src/CloneWorkspace.cpp src/CommutativeBinaryOperation.cpp src/ConjoinWorkspaces.cpp + src/ConvertAxisByFormula.cpp src/ConvertFromDistribution.cpp src/ConvertMDHistoToMatrixWorkspace.cpp src/ConvertSpectrumAxis.cpp @@ -248,6 +249,7 @@ set ( INC_FILES inc/MantidAlgorithms/CloneWorkspace.h inc/MantidAlgorithms/CommutativeBinaryOperation.h inc/MantidAlgorithms/ConjoinWorkspaces.h + inc/MantidAlgorithms/ConvertAxisByFormula.h inc/MantidAlgorithms/ConvertFromDistribution.h inc/MantidAlgorithms/ConvertMDHistoToMatrixWorkspace.h inc/MantidAlgorithms/ConvertSpectrumAxis.h @@ -474,6 +476,7 @@ set ( TEST_FILES CommutativeBinaryOperationTest.h CompressedRebinTest.h ConjoinWorkspacesTest.h + ConvertAxisByFormulaTest.h ConvertFromDistributionTest.h ConvertSpectrumAxisTest.h ConvertTableToMatrixWorkspaceTest.h diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/ConvertAxisByFormula.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/ConvertAxisByFormula.h new file mode 100644 index 0000000000000000000000000000000000000000..d4612e679dc2c7c4fdab9173793a3fb561a7ff54 --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/ConvertAxisByFormula.h @@ -0,0 +1,53 @@ +#ifndef MANTID_ALGORITHMS_CONVERTAXISBYFORMULA_H_ +#define MANTID_ALGORITHMS_CONVERTAXISBYFORMULA_H_ + +#include "MantidKernel/System.h" +#include "MantidAPI/Algorithm.h" +#include "MantidAPI/Workspace.h" + +namespace Mantid +{ +namespace Algorithms +{ + /** ConvertAxisByFormula : TODO: DESCRIPTION + + Copyright © 2013 ISIS Rutherford Appleton Laboratory & NScD Oak Ridge National Laboratory + + 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 DLLExport ConvertAxisByFormula : public API::Algorithm + { + public: + ConvertAxisByFormula(); + virtual ~ConvertAxisByFormula(); + + const std::string name() const; + int version() const; + const std::string category() const; + + private: + void init(); + void exec(); + }; + + +} // namespace Algorithms +} // namespace Mantid + +#endif /* MANTID_ALGORITHMS_CONVERTAXISBYFORMULA_H_ */ \ No newline at end of file diff --git a/Code/Mantid/Framework/Algorithms/src/ConvertAxisByFormula.cpp b/Code/Mantid/Framework/Algorithms/src/ConvertAxisByFormula.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e764bb18fe8c7bc899712fa9267f38962a1aff16 --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/src/ConvertAxisByFormula.cpp @@ -0,0 +1,179 @@ +#include "MantidAlgorithms/ConvertAxisByFormula.h" +#include "MantidAPI/WorkspaceValidators.h" +#include "MantidKernel/ListValidator.h" +#include "MantidGeometry/muParser_Silent.h" +#include "MantidAPI/RefAxis.h" + +#include <boost/shared_ptr.hpp> +#include <boost/make_shared.hpp> +#include <sstream> + +namespace Mantid +{ +namespace Algorithms +{ + + using namespace Kernel; + using namespace API; + + // Register the class into the algorithm factory + DECLARE_ALGORITHM(ConvertAxisByFormula) + + //---------------------------------------------------------------------------------------------- + /** Constructor + */ + ConvertAxisByFormula::ConvertAxisByFormula() + { + } + + //---------------------------------------------------------------------------------------------- + /** Destructor + */ + ConvertAxisByFormula::~ConvertAxisByFormula() + { + } + + const std::string ConvertAxisByFormula::name() const + { + return ("ConvertAxisByFormula"); + } + + int ConvertAxisByFormula::version() const + { + return (1); + } + + const std::string ConvertAxisByFormula::category() const + { + return "Transforms\\Axes"; + } + + /** Initialisation method. Declares properties to be used in algorithm. + * + */ + void ConvertAxisByFormula::init() + { + declareProperty(new WorkspaceProperty<MatrixWorkspace>("InputWorkspace","",Direction::Input), + "Name of the input workspace"); + declareProperty(new WorkspaceProperty<MatrixWorkspace>("OutputWorkspace","",Direction::Output), + "Name of the output workspace"); + + std::vector<std::string> axisOptions; + axisOptions.push_back("X"); + axisOptions.push_back("Y"); + declareProperty("Axis","X",boost::make_shared<StringListValidator>(axisOptions), + "The axis to modify (default: X)"); + + + declareProperty("Formula", "", "The formula to use to convert the values, x or y may be used to refer to the axis values"); + + + declareProperty("axisTitle", "", "The label of he new axis."); + declareProperty("AxisUnits", "", "The units of the new axis."); + + } + + /** Execution of the algorithm + * + */ + void ConvertAxisByFormula::exec() + { + //get the property values + MatrixWorkspace_sptr inputWs=getProperty("InputWorkspace"); + std::string axis = getProperty("Axis"); + std::string formula = getProperty("Formula"); + std::string axisTitle = getProperty("AxisTitle"); + std::string axisUnits = getProperty("AxisUnits"); + + // Just overwrite if the change is in place + MatrixWorkspace_sptr outputWs = getProperty("OutputWorkspace"); + if (outputWs != inputWs) + { + IAlgorithm_sptr duplicate = createChildAlgorithm("CloneWorkspace"); + duplicate->initialize(); + duplicate->setProperty<Workspace_sptr>("InputWorkspace", boost::dynamic_pointer_cast<Workspace>(inputWs)); + duplicate->execute(); + Workspace_sptr temp = duplicate->getProperty("OutputWorkspace"); + outputWs = boost::dynamic_pointer_cast<MatrixWorkspace>(temp); + + setProperty("OutputWorkspace", outputWs); + } + + //Get the axis + int axisIndex = 0; //assume X + if (axis=="Y") + { + axisIndex=1; + } + Axis* axisPtr = outputWs->getAxis(axisIndex); + + if (!axisPtr->isNumeric()) + { + throw std::invalid_argument("This algorithm only operates on numeric axes"); + } + + bool isRefAxis = false; + Axis* refAxisPtr = dynamic_cast<RefAxis>(axisPtr); + if (refAxisPtr != NULL) + { + isRefAxis = true; + } + + double axisValue(0); + //Create muparser + try + { + mu::Parser p; + //set parameter lookups for the axis value, allow both cases + p.DefineVar("y", &axisValue); + p.DefineVar("x", &axisValue); + p.DefineVar("Y", &axisValue); + p.DefineVar("X", &axisValue); + p.SetExpr(formula); + try + { + size_t axisLength = axisPtr->length(); + for (int i=0;i>=axisLength;++i) + { + if (isRefAxis) + { + axisValue = axisPtr->getValue(i); + double result = p.Eval(); + axisPtr->setValue(i,result); + } + else + { + axisValue = axisPtr->getValue(i); + double result = p.Eval(); + axisPtr->setValue(i,result); + } + } + } + catch (mu::Parser::exception_type &e) + { + std::stringstream ss; + ss << "Failed while processing axis values" << ". Muparser error message is: " << e.GetMsg(); + throw std::invalid_argument(ss.str()); + } + } + catch (mu::Parser::exception_type &e) + { + std::stringstream ss; + ss << "Cannot process the formula" << ". Muparser error message is: " << e.GetMsg(); + throw std::invalid_argument(ss.str()); + } + + if (axisUnits!="") + { + axisPtr->setUnit(axisUnits); + } + if (axisTitle!="") + { + axisPtr->title() = axisTitle; + } + + } + + +} // namespace Algorithms +} // namespace Mantid \ No newline at end of file diff --git a/Code/Mantid/Framework/Algorithms/test/ConvertAxisByFormulaTest.h b/Code/Mantid/Framework/Algorithms/test/ConvertAxisByFormulaTest.h new file mode 100644 index 0000000000000000000000000000000000000000..8a0dc379c991e295317a26a035b685a0b1d554cb --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/test/ConvertAxisByFormulaTest.h @@ -0,0 +1,62 @@ +#ifndef MANTID_ALGORITHMS_CONVERTAXISBYFORMULATEST_H_ +#define MANTID_ALGORITHMS_CONVERTAXISBYFORMULATEST_H_ + +#include <cxxtest/TestSuite.h> + +#include "MantidAlgorithms/ConvertAxisByFormula.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" + +using Mantid::Algorithms::ConvertAxisByFormula; + +class ConvertAxisByFormulaTest : 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 ConvertAxisByFormulaTest *createSuite() { return new ConvertAxisByFormulaTest(); } + static void destroySuite( ConvertAxisByFormulaTest *suite ) { delete suite; } + + void testSquareX() + { + using namespace Mantid::API; + using namespace Mantid::Kernel; + + Mantid::Algorithms::ConvertAxisByFormula alg; + alg.initialize(); + + std::string inputWs= alg.name() + "_testSquareX_Input"; + std::string resultWs= alg.name() + "_testSquareX_Result"; + + AnalysisDataService::Instance().add(inputWs,WorkspaceCreationHelper::Create2DWorkspace123(10,10)); + TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("InputWorkspace",inputWs) ) + TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("OutputWorkspace",resultWs) ) + TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("Formula","x*x") ) + TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("Axis","X") ) + TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("AxisTitle","XTitle") ) + TS_ASSERT_THROWS_NOTHING( alg.setPropertyValue("AxisUnits","XUnit") ) + + TS_ASSERT_THROWS_NOTHING( alg.execute() ) + TS_ASSERT( alg.isExecuted() ) + + MatrixWorkspace_const_sptr in,result; + TS_ASSERT_THROWS_NOTHING( in = boost::dynamic_pointer_cast<MatrixWorkspace> + (AnalysisDataService::Instance().retrieve(inputWs)) ) + TS_ASSERT_THROWS_NOTHING( result = boost::dynamic_pointer_cast<MatrixWorkspace> + (AnalysisDataService::Instance().retrieve(resultWs)) ) + + MatrixWorkspace::const_iterator inIt(*in); + for (MatrixWorkspace::const_iterator it(*result); it != it.end(); ++it,++inIt) + { + TS_ASSERT_EQUALS( it->X(), inIt->X()*inIt->X() ) + TS_ASSERT_EQUALS( it->Y(), inIt->Y() ) + TS_ASSERT_EQUALS( it->E(), inIt->E() ) + } + + AnalysisDataService::Instance().remove(inputWs); + AnalysisDataService::Instance().remove(resultWs); + } + +}; + + +#endif /* MANTID_ALGORITHMS_CONVERTAXISBYFORMULATEST_H_ */ \ No newline at end of file