From fd432644892431f5fcb94c4eb3115ddcd893ef8c Mon Sep 17 00:00:00 2001 From: Jose Borreguero <borreguero@gmail.com> Date: Fri, 3 Mar 2017 16:39:23 -0500 Subject: [PATCH] Refs #19057 New unit, with tests --- .../inc/MantidAlgorithms/ConvertUnits.h | 4 +- Framework/Algorithms/test/ConvertUnitsTest.h | 18 ++++ .../inc/MantidKernel/PhysicalConstants.h | 4 + Framework/Kernel/inc/MantidKernel/Unit.h | 16 +++ .../Kernel/inc/MantidKernel/UnitLabelTypes.h | 2 + Framework/Kernel/src/Unit.cpp | 34 ++++++ Framework/Kernel/src/UnitLabelTypes.cpp | 2 + Framework/Kernel/test/UnitTest.h | 101 ++++++++++++++++++ .../test/UnitsConversionHelperTest.h | 38 +++++++ .../python/mantid/kernel/UnitFactoryTest.py | 3 +- 10 files changed, 219 insertions(+), 3 deletions(-) diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnits.h b/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnits.h index aac896bdafd..d96c7e0f7d8 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnits.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnits.h @@ -22,8 +22,8 @@ namespace Algorithms { </LI> </UL> - Optional properties required for certain units (DeltaE & - DeltaE_inWavenumber): + Optional properties required for certain units (DeltaE, + DeltaE_inWavenumber, DeltaE_inFrequency): <UL> <LI> Emode - The energy mode (0=elastic, 1=direct geometry, 2=indirect geometry) </LI> diff --git a/Framework/Algorithms/test/ConvertUnitsTest.h b/Framework/Algorithms/test/ConvertUnitsTest.h index ccf1b324465..fbf30f448be 100644 --- a/Framework/Algorithms/test/ConvertUnitsTest.h +++ b/Framework/Algorithms/test/ConvertUnitsTest.h @@ -590,6 +590,24 @@ public: // Check EMode has been set TS_ASSERT_EQUALS(Mantid::Kernel::DeltaEMode::Indirect, output->getEMode()); + ConvertUnits conv3; + conv3.initialize(); + conv3.setProperty("InputWorkspace", ws); + conv3.setPropertyValue("OutputWorkspace", outputSpace); + conv3.setPropertyValue("Target", "DeltaE_inFrequency"); + conv3.setPropertyValue("Emode", "Direct"); + conv3.setPropertyValue("Efixed", "12.95"); + conv3.execute(); + + TS_ASSERT_THROWS_NOTHING( + output = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( + outputSpace)); + TS_ASSERT_EQUALS(output->getAxis(0)->unit()->unitID(), "DeltaE_inFrequency"); + TS_ASSERT_EQUALS(output->blocksize(), 1669); + // Check EMode has been set + TS_ASSERT_EQUALS(Mantid::Kernel::DeltaEMode::Direct, output->getEMode()); + + AnalysisDataService::Instance().remove(outputSpace); } diff --git a/Framework/Kernel/inc/MantidKernel/PhysicalConstants.h b/Framework/Kernel/inc/MantidKernel/PhysicalConstants.h index 3a6416de3eb..bfe5ade356d 100644 --- a/Framework/Kernel/inc/MantidKernel/PhysicalConstants.h +++ b/Framework/Kernel/inc/MantidKernel/PhysicalConstants.h @@ -70,6 +70,10 @@ static constexpr double meV = 1.602176487e-22; * <http://physics.nist.gov/cuu/Constants> on 02/04/2008. */ static constexpr double meVtoWavenumber = 8.06554465; +/** 1 meV in frequency (GHz). Division of energy by Plank's constant. Taken from + * <http://physics.nist.gov/cuu/Constants> on 03/11/2017. */ +static constexpr double meVtoFrequency = 0.2417989262; + /** 1 meV in Kelvin. Taken from <http://physics.nist.gov/cuu/Constants> on * 09/09/2011. */ static constexpr double meVtoKelvin = 11.604519; diff --git a/Framework/Kernel/inc/MantidKernel/Unit.h b/Framework/Kernel/inc/MantidKernel/Unit.h index 517fd3ea76b..83a5ba8af90 100644 --- a/Framework/Kernel/inc/MantidKernel/Unit.h +++ b/Framework/Kernel/inc/MantidKernel/Unit.h @@ -496,6 +496,22 @@ public: DeltaE_inWavenumber(); }; +//================================================================================================= +/// Energy transfer in units of frequency (GHz) +class MANTID_KERNEL_DLL DeltaE_inFrequency : public DeltaE { +public: + const std::string unitID() const override; ///< "DeltaE_inFrequency" + const std::string caption() const override { return "Energy transfer"; } + const UnitLabel label() const override; + + void init() override; + Unit *clone() const override; + double conversionTOFMin() const override; + double conversionTOFMax() const override; + /// Constructor + DeltaE_inFrequency(); +}; + //================================================================================================= /// Momentum in Angstrom^-1 class MANTID_KERNEL_DLL Momentum : public Unit { diff --git a/Framework/Kernel/inc/MantidKernel/UnitLabelTypes.h b/Framework/Kernel/inc/MantidKernel/UnitLabelTypes.h index d10f30dc2f3..559127e49e7 100644 --- a/Framework/Kernel/inc/MantidKernel/UnitLabelTypes.h +++ b/Framework/Kernel/inc/MantidKernel/UnitLabelTypes.h @@ -50,6 +50,8 @@ public: static const UnitLabel InverseAngstromSq; /// MilliElectronVolts static const UnitLabel MilliElectronVolts; + /// GHz + static const UnitLabel GHz; /// Metre static const UnitLabel Metre; /// Nanometre diff --git a/Framework/Kernel/src/Unit.cpp b/Framework/Kernel/src/Unit.cpp index 751e941ae6a..e0ea85e3e39 100644 --- a/Framework/Kernel/src/Unit.cpp +++ b/Framework/Kernel/src/Unit.cpp @@ -714,6 +714,7 @@ DeltaE::DeltaE() : Unit(), factorTo(DBL_MIN), factorFrom(DBL_MIN), t_other(DBL_MIN), t_otherFrom(DBL_MIN), unitScaling(DBL_MIN) { addConversion("DeltaE_inWavenumber", PhysicalConstants::meVtoWavenumber, 1.); + addConversion("DeltaE_inFrequency", PhysicalConstants::meVtoFrequency, 1.); } void DeltaE::init() { @@ -857,6 +858,39 @@ double DeltaE_inWavenumber::conversionTOFMax() const { return DeltaE::conversionTOFMax(); } +// ===================================================================================================== +/* Energy Transfer in units of frequency + * ===================================================================================================== + * + * This is identical to Energy Transfer in meV, with one division by Plank's constant, or multiplication + * by factor PhysicalConstants::meVtoFrequency + */ +DECLARE_UNIT(DeltaE_inFrequency) + +const UnitLabel DeltaE_inFrequency::label() const { return Symbol::GHz; } + +void DeltaE_inFrequency::init() { + DeltaE::init(); + // Change the unit scaling factor + unitScaling = PhysicalConstants::meVtoFrequency; +} + +Unit *DeltaE_inFrequency::clone() const { + return new DeltaE_inFrequency(*this); +} + +DeltaE_inFrequency::DeltaE_inFrequency() : DeltaE() { + addConversion("DeltaE", 1.0/PhysicalConstants::meVtoFrequency, 1.); +} + +double DeltaE_inFrequency::conversionTOFMin() const { + return DeltaE::conversionTOFMin(); +} + +double DeltaE_inFrequency::conversionTOFMax() const { + return DeltaE::conversionTOFMax(); +} + // ===================================================================================================== /* Momentum in Angstrom^-1. It is 2*Pi/wavelength * ===================================================================================================== diff --git a/Framework/Kernel/src/UnitLabelTypes.cpp b/Framework/Kernel/src/UnitLabelTypes.cpp index 37317c9ad31..ed063cdcd1f 100644 --- a/Framework/Kernel/src/UnitLabelTypes.cpp +++ b/Framework/Kernel/src/UnitLabelTypes.cpp @@ -21,6 +21,8 @@ const UnitLabel Symbol::InverseAngstromSq("Angstrom^-2", L"\u212b\u207b\u00b2", "\\AA^{-2}"); /// MilliElectronVolts const UnitLabel Symbol::MilliElectronVolts("meV"); +/// GHz + const UnitLabel Symbol::GHz("GHz"); /// Metre const UnitLabel Symbol::Metre("m"); /// Nanometre diff --git a/Framework/Kernel/test/UnitTest.h b/Framework/Kernel/test/UnitTest.h index bb5070d8f73..bf5eaa49c57 100644 --- a/Framework/Kernel/test/UnitTest.h +++ b/Framework/Kernel/test/UnitTest.h @@ -229,6 +229,9 @@ public: unit = DeltaE_inWavenumber().clone(); TS_ASSERT(dynamic_cast<DeltaE_inWavenumber *>(unit)); delete unit; + unit = DeltaE_inFrequency().clone(); + TS_ASSERT(dynamic_cast<DeltaE_inFrequency *>(unit)); + delete unit; unit = Momentum().clone(); TS_ASSERT(dynamic_cast<Momentum *>(unit)); delete unit; @@ -936,6 +939,103 @@ public: sample[3], rezult[3], 10 * FLT_EPSILON); } + //---------------------------------------------------------------------- + // Energy transfer in frequency tests + //---------------------------------------------------------------------- + + void testDeltaEf_unitID() { TS_ASSERT_EQUALS(dEf.unitID(), "DeltaE_inFrequency") } + + void testDeltaEf_caption() { + TS_ASSERT_EQUALS(dE.caption(), "Energy transfer") + } + + void testDeltaEf_label() { + TS_ASSERT_EQUALS(dEf.label().ascii(), "GHz") + TS_ASSERT_EQUALS(dEf.label().utf8(), L"GHz") + } + + void testDeltaEf_cast() { + Unit *u = NULL; + TS_ASSERT_THROWS_NOTHING(u = dynamic_cast<Unit *>(&dEf)); + TS_ASSERT_EQUALS(u->unitID(), "DeltaE_inFrequency"); + } + + void testDeltaEf_toTOF() { + std::vector<double> x(1, 0.26597881882), y(1, 1.0); //1.1meV = h*0.26597881882Ghz + std::vector<double> yy = y; + TS_ASSERT_THROWS_NOTHING(dEf.toTOF(x, y, 1.5, 2.5, 0.0, 1, 4.0, 0.0)) + TS_ASSERT_DELTA(x[0], 5071.066, 0.001) + TS_ASSERT(yy == y) + + x[0] = 0.26597881882; + TS_ASSERT_THROWS_NOTHING(dEf.toTOF(x, y, 1.5, 2.5, 0.0, 2, 4.0, 0.0)) + TS_ASSERT_DELTA(x[0], 4376.406, 0.001) + TS_ASSERT(yy == y) + + // emode = 0 + TS_ASSERT_THROWS(dEf.toTOF(x, y, 1.5, 2.5, 0.0, 0, 4.0, 0.0), + std::invalid_argument) + } + + void testDeltaEf_fromTOF() { + std::vector<double> x(1, 2001.0), y(1, 1.0); + std::vector<double> yy = y; + TS_ASSERT_THROWS_NOTHING(dEf.fromTOF(x, y, 1.5, 2.5, 0.0, 1, 4.0, 0.0)) + TS_ASSERT_DELTA(x[0], -95.4064, 0.0001) + TS_ASSERT(yy == y) + + x[0] = 3001.0; + TS_ASSERT_THROWS_NOTHING(dEf.fromTOF(x, y, 1.5, 2.5, 0.0, 2, 4.0, 0.0)) + TS_ASSERT_DELTA(x[0], 137.7866, 0.0001) + TS_ASSERT(yy == y) + + // emode = 0 + TS_ASSERT_THROWS(dEf.fromTOF(x, y, 1.5, 2.5, 0.0, 0, 4.0, 0.0), + std::invalid_argument) + } + + void testDE_fRange() { + std::vector<double> sample, rezult; + // Direct + dEf.initialize(2001.0, 1.0, 1.5, 1, 10., 0.0); + + std::string err_mess = + convert_units_check_range(dEf, sample, rezult, DBL_EPSILON); + TSM_ASSERT(" ERROR:" + err_mess, err_mess.size() == 0); + + TSM_ASSERT_DELTA( + "Direct energy transfer limits Failed for conversion t_min: ", + sample[0], rezult[0], 10 * FLT_EPSILON); + TSM_ASSERT_DELTA( + "Direct energy transfer limits Failed for conversion t_max: ", + sample[1] / rezult[1], 1., 0.05); + TSM_ASSERT_DELTA( + "Direct energy transfer limits Failed for conversion e_min: ", + sample[2], rezult[2], 10 * FLT_EPSILON); + TSM_ASSERT_DELTA( + "Direct energy transfer limits Failed for conversion e_max: ", + sample[3], rezult[3], 10 * FLT_EPSILON); + + // Indirect + dEf.initialize(2001.0, 1.0, 1.5, 2, 10., 0.0); + + err_mess = convert_units_check_range(dEf, sample, rezult); + TSM_ASSERT(" ERROR:" + err_mess, err_mess.size() == 0); + + TSM_ASSERT_DELTA( + "Indirect energy transfer limits Failed for conversion t_min: ", + sample[0], rezult[0], 10 * FLT_EPSILON); + TSM_ASSERT_DELTA( + "Indirect energy transfer limits Failed for conversion t_max: ", + sample[1] / rezult[1], 1., 0.05); + TSM_ASSERT_DELTA( + "Indirect energy transfer limits Failed for conversion e_min: ", + sample[2], rezult[2], 10 * FLT_EPSILON); + TSM_ASSERT_DELTA( + "Indirect energy transfer limits Failed for conversion e_max: ", + sample[3], rezult[3], 10 * FLT_EPSILON); + } + //---------------------------------------------------------------------- // Momentum tests //---------------------------------------------------------------------- @@ -1235,6 +1335,7 @@ private: Units::QSquared q2; Units::DeltaE dE; Units::DeltaE_inWavenumber dEk; + Units::DeltaE_inFrequency dEf; Units::Momentum k_i; Units::SpinEchoLength delta; Units::SpinEchoTime tau; diff --git a/Framework/MDAlgorithms/test/UnitsConversionHelperTest.h b/Framework/MDAlgorithms/test/UnitsConversionHelperTest.h index 3c1ffacd82d..bff5d0da36a 100644 --- a/Framework/MDAlgorithms/test/UnitsConversionHelperTest.h +++ b/Framework/MDAlgorithms/test/UnitsConversionHelperTest.h @@ -4,6 +4,7 @@ #include "MantidAPI/FrameworkManager.h" #include "MantidAPI/NumericAxis.h" #include "MantidKernel/UnitFactory.h" +#include "MantidKernel/PhysicalConstants.h" #include "MantidMDAlgorithms/MDWSDescription.h" #include "MantidMDAlgorithms/UnitsConversionHelper.h" #include "MantidTestHelpers/WorkspaceCreationHelper.h" @@ -89,6 +90,43 @@ public: TS_ASSERT_EQUALS(-100000, range.first); TS_ASSERT_EQUALS(0, range.second); } + + void testConvertFastFromInelasticWStoFrequency() { + UnitsConversionHelper Conv; + MDWSDescription WSD; + + // ws description currently needs min/max to be set properly + std::vector<double> min(2, -10), max(2, 10); + WSD.setMinMax(min, max); + + WSD.buildFromMatrixWS(ws2D, "|Q|", "Direct"); + WSD.m_PreprDetTable = detLoc; + + TS_ASSERT_THROWS_NOTHING(Conv.initialize(WSD, "DeltaE_inFrequency")); + + const auto &X = ws2D->readX(0); + size_t n_bins = X.size() - 1; + for (size_t i = 0; i < n_bins; i++) { + TS_ASSERT_DELTA(X[i]*Mantid::PhysicalConstants::meVtoFrequency, Conv.convertUnits(X[i]), 1.e-4); + } + + auto range = Conv.getConversionRange(0, 10); + TS_ASSERT_EQUALS(0, range.first); + TS_ASSERT_EQUALS(3, range.second); + + range = Conv.getConversionRange(-10, 3); + TS_ASSERT_EQUALS(-10, range.first); + TS_ASSERT_EQUALS(3, range.second); + + range = Conv.getConversionRange(-100000, 2); + TS_ASSERT_EQUALS(-100000, range.first); + TS_ASSERT_EQUALS(2, range.second); + + range = Conv.getConversionRange(0, -100000); + TS_ASSERT_EQUALS(-100000, range.first); + TS_ASSERT_EQUALS(0, range.second); + } + void testConvertToTofInelasticWS() { UnitsConversionHelper Conv; MDWSDescription WSD; diff --git a/Framework/PythonInterface/test/python/mantid/kernel/UnitFactoryTest.py b/Framework/PythonInterface/test/python/mantid/kernel/UnitFactoryTest.py index 448cddd9b79..53d9b21d8bb 100644 --- a/Framework/PythonInterface/test/python/mantid/kernel/UnitFactoryTest.py +++ b/Framework/PythonInterface/test/python/mantid/kernel/UnitFactoryTest.py @@ -24,7 +24,8 @@ class UnitFactoryTest(unittest.TestCase): # but allow for others to be added core_units = ['Empty', 'Label', 'TOF', 'Wavelength','Energy', 'Energy_inWavenumber', 'dSpacing', 'MomentumTransfer', - 'QSquared', 'DeltaE', 'DeltaE_inWavenumber', 'Momentum'] + 'QSquared', 'DeltaE', 'DeltaE_inWavenumber', + 'DeltaE_inFrequency', 'Momentum'] self.assertTrue(len(core_units) <= len(known_units)) for unit in core_units: -- GitLab