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

Re #1240 Power Algorithm

parent 207fac3a
No related branches found
No related tags found
No related merge requests found
#ifndef MANTID_ALGORITHM_POWER_H_
#define MANTID_ALGORITHM_POWER_H_
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAlgorithms/BinaryOperation.h"
namespace Mantid
{
namespace Algorithms
{
/**
Provides the ability to raise the values in the workspace to a specified power.
Required Properties:
<UL>
<LI> InputWorkspace - The name of the workspace to correct</LI>
<LI> OutputWorkspace - The name of the corrected workspace (can be the same as the input one)</LI>
<LI> exponent - The exponent to use in the power calculation</LI>
</UL>
@author Owen Arnold, Tessella plc
@date 12/04/2010
Copyright &copy; 2010 STFC Rutherford Appleton 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://svn.mantidproject.org/mantid/trunk/Code/Mantid>
*/
class DLLExport Power : public BinaryOperation
{
public:
/// Default constructor
Power() : BinaryOperation() {};
/// Destructor
virtual ~Power() {};
/// Algorithm's name for identification overriding a virtual method
virtual const std::string name() const { return "Multiply";}
/// 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);
};
}
}
#endif
//----------------------------------------------------------------------
// Includes
//----------------------------------------------------------------------
#include "MantidAlgorithms/Power.h"
#include "MantidKernel/Exception.h"
using namespace Mantid::API;
using namespace Mantid::Kernel;
namespace Mantid
{
namespace Algorithms
{
// Register the class into the algorithm factory
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::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;
}
}
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::setOutputUnits(const API::MatrixWorkspace_const_sptr lhs,
const API::MatrixWorkspace_const_sptr rhs,
API::MatrixWorkspace_sptr out)
{
//TODO
}
}
}
#ifndef POWERTEST_H_
#define POWERTEST_H_
#include <cxxtest/TestSuite.h>
#include <cmath>
#include "WorkspaceCreationHelper.hh"
#include "MantidAlgorithms/Power.h"
#include "MantidAPI/AnalysisDataService.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidDataObjects/Workspace2D.h"
#include "MantidDataObjects/Workspace1D.h"
#include "MantidAPI/WorkspaceProperty.h"
#include "MantidAPI/WorkspaceOpOverloads.h"
using namespace Mantid::API;
using namespace Mantid::Kernel;
using namespace Mantid::Algorithms;
using namespace Mantid::DataObjects;
class MultiplyTest : 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");
}
};
#endif
......@@ -17,16 +17,17 @@ rm -f *.properties
echo "Generating the source file from the test header files..."
# Chaining all tests together can have effects that you don't think of
# - it's always a good idea to run your new/changed test on its own
cxxtestgen=../../../Third_Party/src/cxxtest/cxxtestgen.pl
if [ $# -eq 0 ]; then
cxxtestgen.pl --error-printer -o runner.cpp *.h
perl $cxxtestgen --error-printer -o runner.cpp *.h
else
cxxtestgen.pl --error-printer -o runner.cpp $*
perl $cxxtestgen --error-printer -o runner.cpp $*
fi
echo
echo "Compiling the test executable..."
g++ -O0 -g3 -o runner.exe runner.cpp -I ../inc -I ../../Kernel/inc -I ../../API/inc -I ../../DataObjects/inc -I ../../Geometry/inc -I ../../CurveFitting/inc \
-I ../../DataHandling/inc -I ../../Nexus/inc -I ../../../Third_Party/include \
-I ../../DataHandling/inc -I ../../Nexus/inc -I ../../../Third_Party/src/cxxtest \
-L ../../debug -L ../../Build \
-lMantidAlgorithms -lMantidKernel -lMantidGeometry -lMantidAPI -lMantidDataObjects -lMantidDataHandling -lMantidNexus -lMantidCurveFitting
echo
......
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