Skip to content
Snippets Groups Projects
Commit f60ec333 authored by Steve Williams's avatar Steve Williams
Browse files

Correcting some error estimates: preventing negative errors and stopping...

Correcting some error estimates: preventing negative errors and stopping errors from being set to zero when the Y-value is zero. refs #841
parent b0375dcd
No related branches found
No related tags found
No related merge requests found
...@@ -23,24 +23,15 @@ namespace Mantid ...@@ -23,24 +23,15 @@ namespace Mantid
const double& leftY = lhsY[j]; const double& leftY = lhsY[j];
const double& rightY = rhsY[j]; const double& rightY = rhsY[j];
// Calculate result and store in local variable to avoid overwriting original data if // error dividing two uncorrelated numbers, re-arrange so that you don't get infinity if leftY==0 (when rightY=0 the Y value and the result will both be infinity)
// output workspace is same as one of the input ones // (Sa/a)2 + (Sb/b)2 = (Sc/c)2
const double Y = leftY/rightY; // (Sa c/a)2 + (Sb c/b)2 = (Sc)2
// = (Sa 1/b)2 + (Sb (a/b2))2
// (Sc)2 = (1/b)2( (Sa)2 + (Sb a/b)2 )
EOut[j] = sqrt( pow(lhsE[j], 2)+pow( leftY*rhsE[j]/rightY, 2) )/rightY;
if (fabs(rightY)>1.0e-12 && fabs(Y)>1.0e-12) // Copy the result last in case one of the input workspaces is also any output
{ YOut[j] = leftY/rightY;;
// gaussian errors
// (Sa/a)2 + (Sb/b)2 = (Sc/c)2
// So after taking proportions, squaring, summing,
// and taking the square root, you get a proportional error to the product c.
// Multiply that proportional error by c to get the actual standard deviation Sc.
const double lhsFactor = (lhsE[j]<1.0e-12|| fabs(leftY)<1.0e-12) ? 0.0 : pow((lhsE[j]/leftY),2);
const double rhsFactor = rhsE[j]<1.0e-12 ? 0.0 : pow((rhsE[j]/rightY),2);
EOut[j] = std::abs(Y) * sqrt(lhsFactor+rhsFactor);
}
// Now store the result
YOut[j] = Y;
} }
} }
...@@ -48,23 +39,17 @@ namespace Mantid ...@@ -48,23 +39,17 @@ namespace Mantid
const double& rhsY, const double& rhsE, MantidVec& YOut, MantidVec& EOut) const double& rhsY, const double& rhsE, MantidVec& YOut, MantidVec& EOut)
{ {
// Do the right-hand part of the error calculation just once // Do the right-hand part of the error calculation just once
const double rhsFactor = (rhsE<1.0e-12) ? 0.0 : pow((rhsE/rhsY),2); const double rhsFactor = pow(rhsE/rhsY,2);
const int bins = lhsE.size(); const int bins = lhsE.size();
for (int j=0; j<bins; ++j) for (int j=0; j<bins; ++j)
{ {
// Get reference to input Y // Get reference to input Y
const double& leftY = lhsY[j]; const double& leftY = lhsY[j];
// Calculate result into local variable
const double Y = leftY/rhsY;
if (fabs(Y)>1.0e-12)
{
const double lhsFactor = (lhsE[j]<1.0e-12 || fabs(leftY)<1.0e-12) ? 0.0 : pow((lhsE[j]/leftY),2);
EOut[j] = std::abs(Y) * sqrt(lhsFactor+rhsFactor);
}
// Copy result in // see comment in the function above for the error formula
YOut[j] = Y; EOut[j] = sqrt( pow(lhsE[j], 2)+pow( leftY, 2)*rhsFactor )/rhsY;
// Copy the result last in case one of the input workspaces is also any output
YOut[j] = leftY/rhsY;
} }
} }
......
...@@ -26,7 +26,7 @@ namespace Mantid ...@@ -26,7 +26,7 @@ namespace Mantid
{ {
std::transform(lhsY.begin(),lhsY.end(),YOut.begin(),std::bind2nd(std::minus<double>(),rhsY)); std::transform(lhsY.begin(),lhsY.end(),YOut.begin(),std::bind2nd(std::minus<double>(),rhsY));
// Only do E if non-zero, otherwise just copy // Only do E if non-zero, otherwise just copy
if (rhsE > 1.0e-12) if (rhsE != 0)
std::transform(lhsE.begin(),lhsE.end(),EOut.begin(),std::bind2nd(VectorHelper::SumGaussError<double>(),rhsE)); std::transform(lhsE.begin(),lhsE.end(),EOut.begin(),std::bind2nd(VectorHelper::SumGaussError<double>(),rhsE));
else else
EOut = lhsE; EOut = lhsE;
......
...@@ -23,48 +23,31 @@ namespace Mantid ...@@ -23,48 +23,31 @@ namespace Mantid
const double& leftY = lhsY[j]; const double& leftY = lhsY[j];
const double& rightY = rhsY[j]; const double& rightY = rhsY[j];
// Calculate result and store in local variable to avoid overwriting original data if // error multiplying two uncorrelated numbers, re-arrange so that you don't get infinity if leftY or rightY == 0
// output workspace is same as one of the input ones // (Sa/a)2 + (Sb/b)2 = (Sc/c)2
const double Y = leftY*rightY; // (Sc)2 = (Sa c/a)2 + (Sb c/b)2
// = (Sa b)2 + (Sb a)2
if (fabs(Y)>1.0e-12) EOut[j] = sqrt(pow(lhsE[j]*rightY, 2) + pow(rhsE[j]*leftY, 2));
{
// gaussian errors // Copy the result last in case one of the input workspaces is also any output
// (Sa/a)2 + (Sb/b)2 = (Sc/c)2 YOut[j] = leftY*rightY;
// So after taking proportions, squaring, summing,
// and taking the square root, you get a proportional error to the product c.
// Multiply that proportional error by c to get the actual standard deviation Sc.
const double lhsFactor = (lhsE[j]<1.0e-12 || fabs(leftY)<1.0e-12) ? 0.0 : pow((lhsE[j]/leftY),2);
const double rhsFactor = (rhsE[j]<1.0e-12 || fabs(rightY)<1.0e-12) ? 0.0 : pow((rhsE[j]/rightY),2);
EOut[j] = std::abs(Y) * sqrt(lhsFactor+rhsFactor);
}
// Now store the result
YOut[j] = Y;
} }
} }
void Multiply::performBinaryOperation(const MantidVec& lhsX, const MantidVec& lhsY, const MantidVec& lhsE, void Multiply::performBinaryOperation(const MantidVec& lhsX, const MantidVec& lhsY, const MantidVec& lhsE,
const double& rhsY, const double& rhsE, MantidVec& YOut, MantidVec& EOut) const double& rhsY, const double& rhsE, MantidVec& YOut, MantidVec& EOut)
{ {
// Do the right-hand part of the error calculation just once
const double rhsFactor = (rhsE<1.0e-12) ? 0.0 : pow((rhsE/rhsY),2);
const int bins = lhsE.size(); const int bins = lhsE.size();
for (int j=0; j<bins; ++j) for (int j=0; j<bins; ++j)
{ {
// Get reference to input Y // Get reference to input Y
const double& leftY = lhsY[j]; const double& leftY = lhsY[j];
// Calculate result into local variable
const double Y = leftY*rhsY;
if (fabs(Y)>1.0e-12) // see comment in the function above for the error formula
{ EOut[j] = sqrt(pow(lhsE[j]*rhsY, 2) + pow(rhsE*leftY, 2));
const double lhsFactor = (lhsE[j]<1.0e-12 || fabs(leftY)<1.0e-12) ? 0.0 : pow((lhsE[j]/leftY),2);
EOut[j] = std::abs(Y) * sqrt(lhsFactor+rhsFactor);
}
// Copy result in // Copy the result last in case one of the input workspaces is also any output
YOut[j] = Y; YOut[j] = leftY*rhsY;
} }
} }
......
...@@ -26,7 +26,7 @@ namespace Mantid ...@@ -26,7 +26,7 @@ namespace Mantid
{ {
std::transform(lhsY.begin(),lhsY.end(),YOut.begin(),std::bind2nd(std::plus<double>(),rhsY)); std::transform(lhsY.begin(),lhsY.end(),YOut.begin(),std::bind2nd(std::plus<double>(),rhsY));
// Only do E if non-zero, otherwise just copy // Only do E if non-zero, otherwise just copy
if (rhsE > 1.0e-12) if (rhsE != 0)
std::transform(lhsE.begin(),lhsE.end(),EOut.begin(),std::bind2nd(VectorHelper::SumGaussError<double>(),rhsE)); std::transform(lhsE.begin(),lhsE.end(),EOut.begin(),std::bind2nd(VectorHelper::SumGaussError<double>(),rhsE));
else else
EOut = lhsE; EOut = lhsE;
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
//---------------------------------------------------------------------- //----------------------------------------------------------------------
#include "MantidAlgorithms/PolynomialCorrection.h" #include "MantidAlgorithms/PolynomialCorrection.h"
#include "MantidKernel/ArrayProperty.h" #include "MantidKernel/ArrayProperty.h"
#include <cmath>
using namespace Mantid::API; using namespace Mantid::API;
using namespace Mantid::Kernel; using namespace Mantid::Kernel;
...@@ -41,7 +42,7 @@ namespace Algorithms ...@@ -41,7 +42,7 @@ namespace Algorithms
// Multiply the data and error by the correction factor // Multiply the data and error by the correction factor
YOut = YIn*factor; YOut = YIn*factor;
EOut = EIn*factor; EOut = EIn*std::abs(factor);
} }
} // namespace Algorithms } // namespace Algorithms
......
...@@ -72,7 +72,7 @@ public: ...@@ -72,7 +72,7 @@ public:
TS_ASSERT_EQUALS( (*(result->getAxis(1)))(0), -0.1 ) TS_ASSERT_EQUALS( (*(result->getAxis(1)))(0), -0.1 )
TS_ASSERT_DELTA( (*(result->getAxis(1)))(31), -0.038, 0.001 ) TS_ASSERT_DELTA( (*(result->getAxis(1)))(31), -0.038, 0.001 )
TS_ASSERT_EQUALS( (*(result->getAxis(1)))(100), 0.1 ) TS_ASSERT_EQUALS( (*(result->getAxis(1)))(100), 0.1 )
TS_ASSERT_EQUALS( result->readX(0).size(), 101 ) TS_ASSERT_EQUALS( result->readX(0).size(), 101 )
TS_ASSERT_EQUALS( result->readX(0).front(), -0.1 ) TS_ASSERT_EQUALS( result->readX(0).front(), -0.1 )
TS_ASSERT_DELTA( result->readX(0)[64], 0.028, 0.01 ) TS_ASSERT_DELTA( result->readX(0)[64], 0.028, 0.01 )
...@@ -80,9 +80,9 @@ public: ...@@ -80,9 +80,9 @@ public:
TS_ASSERT_DIFFERS( result->readY(0).front(), result->readY(0).front() ) // NaN TS_ASSERT_DIFFERS( result->readY(0).front(), result->readY(0).front() ) // NaN
TS_ASSERT_DELTA( result->readY(26)[73], 4438798, 1 ) TS_ASSERT_DELTA( result->readY(26)[73], 4438798, 1 )
TS_ASSERT_DELTA( result->readY(18)[36], 174005, 1 ) TS_ASSERT_DELTA( result->readY(18)[36], 174005, 1 )
TS_ASSERT_EQUALS( result->readE(0).front(), 0 ) TS_ASSERT_DELTA( result->readE(20)[67], 0.0, 1e-10 )
TS_ASSERT_EQUALS( result->readE(55)[50], 0 ) TS_ASSERT_DELTA( result->readE(27)[70], 0, 1e-10 )
TS_ASSERT_EQUALS( result->readE(97).back(), 0 ) TS_ASSERT_DELTA( result->readE(23)[34], 0.0, 1e-10 )
Mantid::API::AnalysisDataService::Instance().remove(inputWS); Mantid::API::AnalysisDataService::Instance().remove(inputWS);
Mantid::API::AnalysisDataService::Instance().remove(outputWS); Mantid::API::AnalysisDataService::Instance().remove(outputWS);
......
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