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

Re #1240 Power derived from UnaryOperation

parent 6e353b98
No related branches found
No related tags found
No related merge requests found
......@@ -7,7 +7,7 @@
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAlgorithms/BinaryOperation.h"
#include "MantidAlgorithms/UnaryOperation.h"
namespace Mantid
{
......@@ -47,31 +47,26 @@ namespace Mantid
File change history is stored at: <https://svn.mantidproject.org/mantid/trunk/Code/Mantid>
*/
class DLLExport Power : public BinaryOperation
class DLLExport Power : public UnaryOperation
{
public:
/// Default constructor
Power() : BinaryOperation() {};
/// Destructor
/// Default constructor
Power() : UnaryOperation() {};
/// Destructor
virtual ~Power() {};
/// Algorithm's name for identification overriding a virtual method
virtual const std::string name() const { return "Power";}
/// Algorithm's version for identification overriding a virtual method
virtual const int version() const { return 1;}
private:
// Overridden BinaryOperation methods
void performBinaryOperation(const MantidVec& lhsX, const MantidVec& lhsY, const MantidVec& lhsE,
const MantidVec& rhsY, const MantidVec& rhsE, MantidVec& YOut, MantidVec& EOut);
void performBinaryOperation(const MantidVec& lhsX, const MantidVec& lhsY, const MantidVec& lhsE,
const double& rhsY, const double& rhsE, MantidVec& YOut, MantidVec& EOut);
void setOutputUnits(const API::MatrixWorkspace_const_sptr lhs,const API::MatrixWorkspace_const_sptr rhs,API::MatrixWorkspace_sptr out);
//Helper method to peform the power calculation
inline double CalculatePower(double base, double exponent);
//Check that unsigned exponents are not being used
inline void CheckExponent(double exponent);
/// Algorithm's name for identification
virtual const std::string name() const { return "Power";}
/// Algorithm's version for identification
virtual const int version() const { return 1;}
private:
// Overridden UnaryOperation methods
void defineProperties();
void retrieveProperties();
void performUnaryOperation(const double& XIn, const double& YIn, const double& EIn, double& YOut, double& EOut);
inline double CalculatePower(const double base, const double exponent);
//Exponent to raise the base workspace to
double m_exponent;
};
}
......
......@@ -7,10 +7,8 @@
using namespace Mantid::API;
using namespace Mantid::Kernel;
namespace Mantid
{
namespace Algorithms
{
namespace Mantid {
namespace Algorithms {
// Register the class into the algorithm factory
DECLARE_ALGORITHM( Power)
......@@ -18,69 +16,25 @@ DECLARE_ALGORITHM( Power)
///////////////////////////////////
void Power::performBinaryOperation(const MantidVec& lhsX,
const MantidVec& lhsY, const MantidVec& lhsE, const MantidVec& rhsY,
const MantidVec& rhsE, MantidVec& YOut, MantidVec& EOut)
{
if (rhsY.size() > 1)
{
throw std::invalid_argument("RHSWorkspace must be single valued.");
}
const int bins = lhsE.size();
for (int j = 0; j < bins; ++j)
{
// Get references to the input Y's
const double& leftY = lhsY[j];
const double& rightY = rhsY[j];
const double& leftE = lhsE[j];
CheckExponent(rightY);
double yOut = CalculatePower(leftY, rightY);
EOut[j] = rightY * yOut * (leftE / leftY);
YOut[j] = yOut;
}
void Power::defineProperties() {
BoundedValidator<double> *mustBePositive = new BoundedValidator<double> ();
mustBePositive->setLower(0.0);
declareProperty("Exponent", 1.0, mustBePositive);
}
void Power::performBinaryOperation(const MantidVec& lhsX,
const MantidVec& lhsY, const MantidVec& lhsE, const double& rhsY,
const double& rhsE, MantidVec& YOut, MantidVec& EOut)
{
CheckExponent(rhsY);
const int bins = lhsE.size();
for (int j = 0; j < bins; ++j)
{
// Get reference to input Y
const double& leftY = lhsY[j];
const double& leftE = lhsE[j];
double yOut = CalculatePower(leftY, rhsY);
EOut[j] = rhsY * yOut * (leftE / leftY);
YOut[j] = yOut;
}
void Power::retrieveProperties() {
m_exponent = getProperty("Exponent");
}
inline void Power::CheckExponent(double exponent) {
if (exponent < 0)
{
throw std::invalid_argument("Cannot have exponent < 0");
}
}
inline double Power::CalculatePower(double base, double exponent)
{
return std::pow(base, exponent);
void Power::performUnaryOperation(const double& XIn, const double& YIn,
const double& EIn, double& YOut, double& EOut) {
YOut = CalculatePower(YIn, m_exponent);
EOut = m_exponent * YOut * (EIn / YIn);
}
void Power::setOutputUnits(const API::MatrixWorkspace_const_sptr lhs,
const API::MatrixWorkspace_const_sptr rhs,
API::MatrixWorkspace_sptr out)
inline double Power::CalculatePower(const double base, const double exponent)
{
//TODO
return std::pow(base, exponent);
}
}
......
......@@ -22,112 +22,125 @@ class PowerTest : public CxxTest::TestSuite
{
public:
void testInit()
{
Power alg;
TS_ASSERT_THROWS_NOTHING(alg.initialize());
TS_ASSERT(alg.isInitialized());
//Setting properties to input workspaces that don't exist throws
TSM_ASSERT_THROWS("Base must be numeric", alg.setPropertyValue("LHSWorkspace","n"), std::invalid_argument )
TSM_ASSERT_THROWS("Base must be numeric", alg.setPropertyValue("RHSWorkspace","n"), std::invalid_argument )
}
void testPowerCalculation()
{
WorkspaceSingleValue_sptr baseWs = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2);
WorkspaceSingleValue_sptr exponentWs = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2);
AnalysisDataService::Instance().add("baseWsp",baseWs);
AnalysisDataService::Instance().add("exponentWsp",exponentWs);
Power alg;
alg.initialize();
alg.setPropertyValue("OutputWorkspace","OutputWsp");
alg.setPropertyValue("RHSWorkspace", "exponentWsp");
alg.setPropertyValue("LHSWorkspace", "baseWsp");
alg.execute();
WorkspaceSingleValue_sptr output = boost::dynamic_pointer_cast<WorkspaceSingleValue>(AnalysisDataService::Instance().retrieve("OutputWsp"));
Mantid::MantidVec expectedValue(1,4);
TSM_ASSERT_EQUALS("Power has not been determined correctly", expectedValue, output->dataY());
AnalysisDataService::Instance().remove("exponentWs");
AnalysisDataService::Instance().remove("baseWs");
AnalysisDataService::Instance().remove("OutputWsp");
}
void testSignedExponent()
{
WorkspaceSingleValue_sptr baseWs = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2);
WorkspaceSingleValue_sptr exponentWs = WorkspaceCreationHelper::CreateWorkspaceSingleValue(-2);
AnalysisDataService::Instance().add("baseWs",baseWs);
AnalysisDataService::Instance().add("exponentWs",exponentWs);
Power alg;
alg.initialize();
alg.setPropertyValue("OutputWorkspace","OutputWs");
alg.setPropertyValue("RHSWorkspace", "exponentWs");
alg.setPropertyValue("LHSWorkspace", "baseWs");
alg.execute();
TSM_ASSERT_EQUALS("Algorithm should not run with a negative exponent", alg.isExecuted(),false);
AnalysisDataService::Instance().remove("exponentWs");
AnalysisDataService::Instance().remove("baseWs");
AnalysisDataService::Instance().remove("OutputWs");
}
void testMultivaluedWorkspaceAsExponent()
{
WorkspaceSingleValue_sptr baseWs = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2);
Workspace1D_sptr exponentWs = WorkspaceCreationHelper::Create1DWorkspaceRand(10);
AnalysisDataService::Instance().add("baseWs",baseWs);
AnalysisDataService::Instance().add("exponentWs",exponentWs);
Power alg;
alg.initialize();
alg.setPropertyValue("OutputWorkspace","OutputWs");
alg.setPropertyValue("RHSWorkspace", "exponentWs");
alg.setPropertyValue("LHSWorkspace", "baseWs");
alg.execute();
TSM_ASSERT_EQUALS("Exponent must be a single valued workspace", alg.isExecuted(),false);
AnalysisDataService::Instance().remove("exponentWs");
AnalysisDataService::Instance().remove("baseWs");
AnalysisDataService::Instance().remove("OutputWs");
}
void testPowerErrorCalculation()
{
//Workspace creation helper creates input error as sqrt of input value. So input error = 2.
//if x = p ^ y, then err_x = y * x * err_p / p
WorkspaceSingleValue_sptr baseWs = WorkspaceCreationHelper::CreateWorkspaceSingleValue(4);
WorkspaceSingleValue_sptr exponentWs = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2);
AnalysisDataService::Instance().add("baseWs",baseWs);
AnalysisDataService::Instance().add("exponentWs",exponentWs);
Power alg;
alg.initialize();
alg.setPropertyValue("OutputWorkspace","OutputWs");
alg.setPropertyValue("RHSWorkspace", "exponentWs");
alg.setPropertyValue("LHSWorkspace", "baseWs");
alg.execute();
WorkspaceSingleValue_sptr output = boost::dynamic_pointer_cast<WorkspaceSingleValue>(AnalysisDataService::Instance().retrieve("OutputWs"));
Mantid::MantidVec expectedErrorValue(1,16);
TSM_ASSERT_EQUALS("Power algorithm error has not been determined properly.", expectedErrorValue, output->dataE());
AnalysisDataService::Instance().remove("exponentWs");
AnalysisDataService::Instance().remove("baseWs");
AnalysisDataService::Instance().remove("OutputWs");
}
void testName()
{
Mantid::Algorithms::Power power;
TS_ASSERT_EQUALS ( power.name(), "Power" )
}
void testVersion()
{
Mantid::Algorithms::Power power;
TS_ASSERT_EQUALS( power.version(), 1 )
}
void testInit()
{
Mantid::Algorithms::Power power;
TS_ASSERT_THROWS_NOTHING( power.initialize() )
TS_ASSERT( power.isInitialized() )
const std::vector<Property*> props = power.getProperties();
TSM_ASSERT_EQUALS("There should only be 3 properties for this power algorithm", props.size(), 3);
TS_ASSERT_EQUALS( props[0]->name(), "InputWorkspace" )
TS_ASSERT( props[0]->isDefault() )
TS_ASSERT( dynamic_cast<WorkspaceProperty<MatrixWorkspace>* >(props[0]) )
TS_ASSERT_EQUALS( props[1]->name(), "OutputWorkspace" )
TS_ASSERT( props[1]->isDefault() )
TS_ASSERT( dynamic_cast<WorkspaceProperty<MatrixWorkspace>* >(props[1]) )
TS_ASSERT_EQUALS( props[2]->name(), "Exponent" )
TS_ASSERT( props[2]->isDefault() )
TS_ASSERT( dynamic_cast<PropertyWithValue<double>* >(props[2]) )
}
void testSetProperties()
{
WorkspaceSingleValue_sptr baseWs = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2);
AnalysisDataService::Instance().add("InputWS", baseWs);
Power power;
power.initialize();
TS_ASSERT_THROWS_NOTHING( power.setPropertyValue("InputWorkspace","InputWS") )
TS_ASSERT_THROWS_NOTHING( power.setPropertyValue("OutputWorkspace","WSCor") )
TS_ASSERT_THROWS_NOTHING( power.setPropertyValue("Exponent","2.0") )
AnalysisDataService::Instance().remove("InputWS");
AnalysisDataService::Instance().remove("WSCor");
}
void testNonNumericExponent()
{
Power power;
power.initialize();
TS_ASSERT_THROWS( power.setPropertyValue("Exponent","x"), std::invalid_argument )
}
void testNegativeExponent()
{
Power power;
power.initialize();
TS_ASSERT_THROWS( power.setPropertyValue("Exponent","-1"), std::invalid_argument )
}
void testPowerCalculation()
{
WorkspaceSingleValue_sptr baseWs = WorkspaceCreationHelper::CreateWorkspaceSingleValue(2);
AnalysisDataService::Instance().add("InputWS", baseWs);
Power power;
power.initialize();
power.setPropertyValue("InputWorkspace","InputWS");
power.setPropertyValue("OutputWorkspace","WSCor");
power.setPropertyValue("Exponent","2.0");
power.execute();
TS_ASSERT( power.isExecuted());
WorkspaceSingleValue_sptr output = boost::dynamic_pointer_cast<WorkspaceSingleValue>(AnalysisDataService::Instance().retrieve("WSCor"));
Mantid::MantidVec expectedValue(1,4);
TSM_ASSERT_EQUALS("Power has not been determined correctly", expectedValue, output->dataY());
AnalysisDataService::Instance().remove("InputWS");
AnalysisDataService::Instance().remove("WSCor");
}
void testPowerErrorCalculation()
{
//Workspace creation helper creates input error as sqrt of input value. So input error = 2.
//if x = p ^ y, then err_x = y * x * err_p / p
WorkspaceSingleValue_sptr baseWs = WorkspaceCreationHelper::CreateWorkspaceSingleValue(4);
AnalysisDataService::Instance().add("InputWS", baseWs);
Power power;
power.initialize();
power.setPropertyValue("InputWorkspace","InputWS");
power.setPropertyValue("OutputWorkspace","WSCor");
power.setPropertyValue("Exponent","2.0");
power.execute();
WorkspaceSingleValue_sptr output = boost::dynamic_pointer_cast<WorkspaceSingleValue>(AnalysisDataService::Instance().retrieve("WSCor"));
Mantid::MantidVec expectedValue(1,16);
TSM_ASSERT_EQUALS("Error has not been determined correctly", expectedValue, output->dataY());
AnalysisDataService::Instance().remove("InputWS");
AnalysisDataService::Instance().remove("WSCor");
}
};
#endif
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