From ba10bc8873c0da1c3fc2037e7ff7e75971917b35 Mon Sep 17 00:00:00 2001 From: Celine Durniak <c.durniak@fz-juelich.de> Date: Mon, 20 Jul 2015 14:48:39 +0200 Subject: [PATCH] source files, unit test and documentation to normalize by monitor counts in TOFTOF --- .../Framework/Algorithms/CMakeLists.txt | 3 + .../MonitorEfficiencyCorUser.h | 56 ++++++ .../src/MonitorEfficiencyCorUser.cpp | 173 ++++++++++++++++++ .../test/MonitorEfficiencyCorUserTest.h | 139 ++++++++++++++ .../MonitorEfficiencyCorUser-v1.rst | 59 ++++++ 5 files changed, 430 insertions(+) create mode 100644 Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/MonitorEfficiencyCorUser.h create mode 100644 Code/Mantid/Framework/Algorithms/src/MonitorEfficiencyCorUser.cpp create mode 100644 Code/Mantid/Framework/Algorithms/test/MonitorEfficiencyCorUserTest.h create mode 100644 Code/Mantid/docs/source/algorithms/MonitorEfficiencyCorUser-v1.rst diff --git a/Code/Mantid/Framework/Algorithms/CMakeLists.txt b/Code/Mantid/Framework/Algorithms/CMakeLists.txt index 88c34d71dd2..d06562cce9f 100644 --- a/Code/Mantid/Framework/Algorithms/CMakeLists.txt +++ b/Code/Mantid/Framework/Algorithms/CMakeLists.txt @@ -154,6 +154,7 @@ set ( SRC_FILES src/Minus.cpp src/ModeratorTzero.cpp src/ModeratorTzeroLinear.cpp + src/MonitorEfficiencyCorUser.cpp src/MonteCarloAbsorption.cpp src/MultipleScatteringCylinderAbsorption.cpp src/Multiply.cpp @@ -421,6 +422,7 @@ set ( INC_FILES inc/MantidAlgorithms/Minus.h inc/MantidAlgorithms/ModeratorTzero.h inc/MantidAlgorithms/ModeratorTzeroLinear.h + inc/MantidAlgorithms/MonitorEfficiencyCorUser.h inc/MantidAlgorithms/MonteCarloAbsorption.h inc/MantidAlgorithms/MultipleScatteringCylinderAbsorption.h inc/MantidAlgorithms/Multiply.h @@ -688,6 +690,7 @@ set ( TEST_FILES MinusTest.h ModeratorTzeroLinearTest.h ModeratorTzeroTest.h + MonitorEfficiencyCorUserTest.h MonteCarloAbsorptionTest.h MultipleScatteringCylinderAbsorptionTest.h MultiplyRangeTest.h diff --git a/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/MonitorEfficiencyCorUser.h b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/MonitorEfficiencyCorUser.h new file mode 100644 index 00000000000..3fe3c1b2245 --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/inc/MantidAlgorithms/MonitorEfficiencyCorUser.h @@ -0,0 +1,56 @@ +#ifndef MANTID_ALGORITHMS_MONITOREFFICIENCYCORUSER_H_ +#define MANTID_ALGORITHMS_MONITOREFFICIENCYCORUSER_H_ + +#include "MantidKernel/System.h" +#include "MantidAPI/Algorithm.h" + +namespace Mantid +{ + namespace Algorithms + { + +class DLLExport MonitorEfficiencyCorUser : public API::Algorithm +{ +public: + /// (Empty) Constructor + MonitorEfficiencyCorUser();// : Mantid::API::Algorithm() {} + /// Virtual destructor + virtual ~MonitorEfficiencyCorUser(); + /// Algorithm's name + virtual const std::string name() const { return "MonitorEfficiencyCorUser"; } + ///Summary of algorithms purpose + virtual const std::string summary() const {return "This algorithm normalises the counts by the monitor counts with additional efficiency correction according to the formula set in the instrument parameters file.";} + + /// Algorithm's version + virtual int version() const { return 1; } + /// Algorithm's category for identification + virtual const std::string category() const { return "MLZ;CorrectionFunctions\\NormalisationCorrections"; } + +private: + /// Initialisation code + void init(); + ///Execution code + void exec(); + + double calculateFormulaValue(const std::string&,double); + std::string getValFromInstrumentDef(const std::string&); + void applyMonEfficiency(const size_t numberOfChannels, + const MantidVec& yIn, const MantidVec& eIn, const double coeff, + MantidVec& yOut, MantidVec& eOut); + + /// The user selected (input) workspace + API::MatrixWorkspace_const_sptr m_inputWS; + /// The output workspace, maybe the same as the input one + API::MatrixWorkspace_sptr m_outputWS; + /// stores the incident energy of the neutrons + double m_Ei; + /// stores the total count of neutrons from the monitor + int m_monitorCounts; + +}; + +} // namespace Algorithms +} // namespace Mantid + + +#endif /*MONITOREFFICIENCYCORUSER_H_*/ diff --git a/Code/Mantid/Framework/Algorithms/src/MonitorEfficiencyCorUser.cpp b/Code/Mantid/Framework/Algorithms/src/MonitorEfficiencyCorUser.cpp new file mode 100644 index 00000000000..8aa2d99836f --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/src/MonitorEfficiencyCorUser.cpp @@ -0,0 +1,173 @@ +#include "MantidAlgorithms/MonitorEfficiencyCorUser.h" +#include "MantidAPI/WorkspaceValidators.h" +#include "MantidKernel/BoundedValidator.h" +#include "MantidKernel/CompositeValidator.h" +#include "MantidGeometry/muParser_Silent.h" +#include "MantidKernel/MultiThreaded.h" +#include <ctime> + +namespace Mantid { +namespace Algorithms { + +using namespace Kernel; +using namespace API; +using namespace Geometry; + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(MonitorEfficiencyCorUser) + + +//---------------------------------------------------------------------------------------------- +/** Constructor + */ +MonitorEfficiencyCorUser::MonitorEfficiencyCorUser() { +} + +//---------------------------------------------------------------------------------------------- +/** Destructor + */ +MonitorEfficiencyCorUser::~MonitorEfficiencyCorUser() { +} + +//---------------------------------------------------------------------------------------------- +/** Initialize the algorithm's properties. + */ + +void MonitorEfficiencyCorUser::init() +{ + declareProperty( + new WorkspaceProperty<>("InputWorkspace", "", Direction::Input,boost::make_shared<InstrumentValidator>() + ), "The workspace to correct for monitor efficiency"); + declareProperty( + new WorkspaceProperty<>("OutputWorkspace", "", Direction::Output), + "The name of the workspace in which to store the result."); +} + + +void MonitorEfficiencyCorUser::exec() +{ + m_inputWS = this->getProperty("InputWorkspace"); + + m_outputWS = this->getProperty("OutputWorkspace"); + + if ( m_inputWS->getInstrument()->getName() != "TOFTOF" ) + { std::string message("The input workspace does not come from TOFTOF"); + g_log.error(message); + throw std::invalid_argument(message); + } + + // If input and output workspaces are not the same, create a new workspace for the output + if (m_outputWS != this->m_inputWS) { + m_outputWS = API::WorkspaceFactory::Instance().create(m_inputWS); + } + double val; + Strings::convert(m_inputWS->run().getProperty("Ei")->value(),val); + m_Ei = val; + Strings::convert(m_inputWS->run().getProperty("monitor_counts")->value(),m_monitorCounts); + + // get Efficiency formula from the IDF - Parameters file + const std::string effFormula = getValFromInstrumentDef("formula_mon_eff"); + + // Calculate Efficiency for E = Ei + const double eff0 = m_monitorCounts*calculateFormulaValue(effFormula, m_Ei); + + const size_t numberOfChannels = this->m_inputWS->blocksize(); + // Calculate the number of spectra in this workspace + const int numberOfSpectra = static_cast<int>(this->m_inputWS->getNumberHistograms()); + API::Progress prog(this, 0.0, 1.0, numberOfSpectra); + int64_t numberOfSpectra_i = static_cast<int64_t>(numberOfSpectra); // cast to make openmp happy + + // Loop over the histograms (detector spectra) + PARALLEL_FOR2(m_outputWS,m_inputWS) + for (int64_t i = 0; i < numberOfSpectra_i; ++i) { + PARALLEL_START_INTERUPT_REGION + //MantidVec& xOut = m_outputWS->dataX(i); + MantidVec& yOut = m_outputWS->dataY(i); + MantidVec& eOut = m_outputWS->dataE(i); + const MantidVec& yIn = m_inputWS->readY(i); + const MantidVec& eIn = m_inputWS->readE(i); + m_outputWS->setX(i, m_inputWS->refX(i)); + + applyMonEfficiency(numberOfChannels, yIn, eIn, eff0, yOut, eOut); + + prog.report("Detector Efficiency correction..."); + PARALLEL_END_INTERUPT_REGION + } //end for i +PARALLEL_CHECK_INTERUPT_REGION + + setProperty("OutputWorkspace", m_outputWS); +} + + +/** + * Apply the monitor efficiency to a single spectrum + * @param numberOfChannels Number of channels in a spectra (nbins - 1) + * @param yIn spectrum counts + * @param eIn spectrum errors + * @param effVec efficiency values (to be divided by the counts) + * @param yOut corrected spectrum counts + * @param eOut corrected spectrum errors + */ +void MonitorEfficiencyCorUser::applyMonEfficiency( + const size_t numberOfChannels, const MantidVec& yIn, + const MantidVec& eIn, const double effVec, MantidVec& yOut, + MantidVec& eOut) { + + for (unsigned int j = 0; j < numberOfChannels; ++j) { + yOut[j] = yIn[j] / effVec; + eOut[j] = eIn[j] / effVec; + } + +} + + +/** + * Calculate the value of a formula + * @param formula :: Formula to correct + * @param energy :: value of the energy to use in the formula + * @return calculated corrected value of the monitor count + */ +double MonitorEfficiencyCorUser::calculateFormulaValue( + const std::string &formula, double energy) { + try { + mu::Parser p; + p.DefineVar("e", &energy); + p.SetExpr(formula); + double eff = p.Eval(); + g_log.debug() << "Formula: " << formula << " with: " << energy << "evaluated to: "<< eff << std::endl; + return eff; + + } catch (mu::Parser::exception_type &e) { + throw Kernel::Exception::InstrumentDefinitionError( + "Error calculating formula from string. Muparser error message is: " + + e.GetMsg()); + } +} + + +/** + * Returns the value associated to a parameter name in the IDF + * @param parameterName :: parameter name in the IDF + * @return the value associated to the parameter name + */ +std::string MonitorEfficiencyCorUser::getValFromInstrumentDef( + const std::string& parameterName) { + + const ParameterMap& pmap = m_inputWS->constInstrumentParameters(); + Instrument_const_sptr instrument = m_inputWS->getInstrument(); + Parameter_sptr par = pmap.getRecursive(instrument->getChild(0).get(), + parameterName); + if (par) { + std::string ret = par->asString(); + g_log.debug() << "Parsed parameter " << parameterName << ": " << ret + << "\n"; + return ret; + } else { + throw Kernel::Exception::InstrumentDefinitionError( + "There is no <" + parameterName + + "> in the instrument definition!"); + } +} + +} // namespace Algorithms +} // namespace Mantid diff --git a/Code/Mantid/Framework/Algorithms/test/MonitorEfficiencyCorUserTest.h b/Code/Mantid/Framework/Algorithms/test/MonitorEfficiencyCorUserTest.h new file mode 100644 index 00000000000..5eb7527dc66 --- /dev/null +++ b/Code/Mantid/Framework/Algorithms/test/MonitorEfficiencyCorUserTest.h @@ -0,0 +1,139 @@ +#ifndef MANTID_ALGORITHMS_MONITORTOREFFICIENCYCORUSERTEST_H_ +#define MANTID_ALGORITHMS_MONITOREFFICIENCYCORUSERTEST_H_ + +#include <cxxtest/TestSuite.h> + +#include "MantidAlgorithms/MonitorEfficiencyCorUser.h" +#include "MantidDataObjects/Workspace2D.h" +#include "MantidTestHelpers/WorkspaceCreationHelper.h" +#include "MantidTestHelpers/ComponentCreationHelper.h" + +using Mantid::Algorithms::MonitorEfficiencyCorUser; + +using namespace Mantid; +using namespace Mantid::API; +using namespace Kernel; + +class MonitorEfficiencyCorUserTest: public CxxTest::TestSuite { +public: + + static MonitorEfficiencyCorUserTest *createSuite() { + return new MonitorEfficiencyCorUserTest(); + } + static void destroySuite(MonitorEfficiencyCorUserTest *suite) { + delete suite; + } + + // constructor + MonitorEfficiencyCorUserTest() : + m_inWSName("input_workspace"), m_outWSName("output_workspace") { + m_Ei = 3.27; + m_monitor_counts = 1000.; + createInputWorkSpace(); + } + + // test init + void test_Init() { + TS_ASSERT_THROWS_NOTHING(alg.initialize()) + TS_ASSERT(alg.isInitialized()) + } + + void testName() + { + TS_ASSERT_EQUALS( alg.name(), "MonitorEfficiencyCorUser" ); + } + + void testVersion() + { + TS_ASSERT_EQUALS( alg.version(), 1 ); + } + + void test_exec() { + + if (!alg.isInitialized()) alg.initialize(); + TS_ASSERT_THROWS_NOTHING( + alg.setPropertyValue("InputWorkspace", m_inWSName)); + TS_ASSERT_THROWS_NOTHING( + alg.setPropertyValue("OutputWorkspace", m_outWSName)); + TS_ASSERT_THROWS_NOTHING(alg.execute(); ); + TS_ASSERT(alg.isExecuted()); + + // Retrieve the output workspace from data service. + MatrixWorkspace_sptr outWS; + TS_ASSERT_THROWS_NOTHING( + outWS = AnalysisDataService::Instance().retrieveWS< + MatrixWorkspace>(m_outWSName)); + TS_ASSERT(outWS); + if (!outWS) + return; + + // Retrieve the input workspace from data service. + MatrixWorkspace_sptr inWS; + TS_ASSERT_THROWS_NOTHING( + inWS = AnalysisDataService::Instance().retrieveWS< + MatrixWorkspace>(m_inWSName)); + TS_ASSERT(inWS); + if (!inWS) + return; + + // Test equality or proportionality between input and output workspaces + const size_t xsize = outWS->blocksize(); + double proportionality_coeff = m_monitor_counts*sqrt(m_Ei/25.3); + for(size_t i = 0; i < outWS->getNumberHistograms(); ++i) + { + for(size_t j = 0; j < xsize; ++j) + { // Same x-values +TS_ASSERT_DELTA(outWS->readX(i)[j], inWS->readX(i)[j], 1e-12); + // Output Y-values proportional to input + TS_ASSERT_DELTA(proportionality_coeff*outWS->readY(i)[j], inWS->readY(i)[j], 1e-12); + + // Output Err-values proportional to input + TS_ASSERT_DELTA(proportionality_coeff*outWS->readE(i)[j], inWS->readE(i)[j], 1e-12); + } + } + + + // Remove workspace from the data service. + AnalysisDataService::Instance().remove(m_outWSName); + AnalysisDataService::Instance().remove(m_inWSName); + } + +private: + double m_Ei; + int m_monitor_counts; + const std::string m_inWSName, m_outWSName; + MonitorEfficiencyCorUser alg; + + void createInputWorkSpace() { + int numHist = 1; + int numBins = 20; + + DataObjects::Workspace2D_sptr dataws = WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument( + numHist, numBins, false, false, true, "TOFTOF"); + + static const double arr[] = {-10. , -9.25, -8.5 , -7.75, -7. , -6.25, -5.5 , -4.75, + -4. , -3.25, -2.5 , -1.75, -1. , -0.25, 0.5 , 1.25, + 2. , 2.75, 3.5 , 4.25, 5. }; + + std::vector<double> vec (arr, arr + sizeof(arr) / sizeof(arr[0]) ); + + for (size_t wi = 0; wi < dataws->getNumberHistograms(); wi++) { + dataws->setX(wi, vec); + } + + + dataws->getAxis(0)->setUnit("TOF"); + dataws->mutableRun().addProperty("Ei", + boost::lexical_cast<std::string>(m_Ei)); + dataws->mutableRun().addProperty("monitor_counts", + boost::lexical_cast<std::string>(m_monitor_counts)); + + dataws->instrumentParameters().addString( + dataws->getInstrument()->getChild(0).get(), "formula_mon_eff", "sqrt(e/25.3)"); //TOFTOF + + API::AnalysisDataService::Instance().addOrReplace(m_inWSName, dataws); + } + +}; + +#endif /* MANTID_ALGORITHMS_MONITOREFFICIENCYCORUSERTEST_H_ */ diff --git a/Code/Mantid/docs/source/algorithms/MonitorEfficiencyCorUser-v1.rst b/Code/Mantid/docs/source/algorithms/MonitorEfficiencyCorUser-v1.rst new file mode 100644 index 00000000000..2205cca40d1 --- /dev/null +++ b/Code/Mantid/docs/source/algorithms/MonitorEfficiencyCorUser-v1.rst @@ -0,0 +1,59 @@ +.. algorithm:: + +.. summary:: + +.. alias:: + +.. properties:: + +Description +----------- + +Normalizes the counts by monitor counts with additional efficiency correction. + +Corrects the monitor efficiency according to the formula contained in TOFTOF's Parameters file. + +The values of the monitor counts and incident energy are stored in the SampleLogs of the input workspace. + +To date this algorithm only supports the TOFTOF instrument. + + +Restrictions +################################### + +A formula named "formula\_eff" must be defined in the instrument +parameters file. + +Usage +----- + +**Example** + +.. testcode:: ExMonitorEfficiencyCorUser + + import numpy as np + #Load data + + wsSample = LoadMLZ(Filename='TOFTOFTestdata.nxs') + + wsNorm = MonitorEfficiencyCorUser(wsSample) + # Check calculation of normalization coefficient + wsCheck = Divide(wsSample,wsNorm) + print 'Coefficient of proportionality between Input and Output of MonitorEfficiencyCorUser algorithm:' + print wsCheck.readY(102)[1] + monitor_counts = float(mtd['wsSample'].getRun().getLogData('monitor_counts').value) + Ei = float(mtd['wsSample'].getRun().getLogData('Ei').value) + print 'Coefficient from theoretical formula = monitor_counts * sqrt(Ei/25.3) ', monitor_counts*np.sqrt(Ei/25.3) + + +Output: + +.. testoutput:: ExMonitorEfficiencyCorUSer + + Coefficient of proportionality between Input and Output of MonitorEfficiencyCorUser algorithm: + 41038.4323645 + Coefficient from theoretical formula = monitor_counts * sqrt(Ei/25.3) 41038.4323645 + +.. categories:: + +.. sourcelink:: -- GitLab