diff --git a/Framework/API/inc/MantidAPI/ExperimentInfo.h b/Framework/API/inc/MantidAPI/ExperimentInfo.h index 663416ad2dbb3c991c0ec63c2ff7b8d6c2de782f..7325cf488d9b868b3aa951fa4368b5a95ac9aa0c 100644 --- a/Framework/API/inc/MantidAPI/ExperimentInfo.h +++ b/Framework/API/inc/MantidAPI/ExperimentInfo.h @@ -12,6 +12,7 @@ #include "MantidGeometry/Instrument_fwd.h" #include "MantidKernel/DeltaEMode.h" +#include "MantidKernel/Unit.h" #include "MantidKernel/V3D.h" #include "MantidKernel/cow_ptr.h" @@ -110,6 +111,12 @@ public: double getEFixed(const std::shared_ptr<const Geometry::IDetector> &detector = std::shared_ptr<const Geometry::IDetector>{ nullptr}) const; + double getEFixedGivenEMode( + const std::shared_ptr<const Geometry::IDetector> &detector, + const Kernel::DeltaEMode::Type emode) const; + double getEFixedForIndirect( + const std::shared_ptr<const Geometry::IDetector> &detector, + const std::vector<std::string> ¶meterNames) const; /// Set the efixed value for a given detector ID void setEFixed(const detid_t detID, const double value); diff --git a/Framework/API/inc/MantidAPI/SpectrumInfo.h b/Framework/API/inc/MantidAPI/SpectrumInfo.h index 1ba9f3a6b4e610f4fd3551e57a45a7b2471d75d3..0bb3ea26da472fd0e17425b68c8316f2f14cdb37 100644 --- a/Framework/API/inc/MantidAPI/SpectrumInfo.h +++ b/Framework/API/inc/MantidAPI/SpectrumInfo.h @@ -8,6 +8,8 @@ #include "MantidAPI/DllConfig.h" #include "MantidAPI/SpectrumInfoIterator.h" +#include "MantidKernel/DeltaEMode.h" +#include "MantidKernel/Unit.h" #include "MantidKernel/V3D.h" #include "MantidKernel/cow_ptr.h" @@ -70,6 +72,11 @@ public: double azimuthal(const size_t index) const; std::pair<double, double> geographicalAngles(const size_t index) const; Kernel::V3D position(const size_t index) const; + Kernel::UnitParametersMap + diffractometerConstants(const size_t index, + std::vector<detid_t> &uncalibratedDets) const; + Kernel::UnitParametersMap diffractometerConstants(const size_t index) const; + double difcUncalibrated(const size_t index) const; bool hasDetectors(const size_t index) const; bool hasUniqueDetector(const size_t index) const; @@ -86,6 +93,14 @@ public: Kernel::V3D samplePosition() const; double l1() const; + void getDetectorValues(const Kernel::Unit &inputUnit, + const Kernel::Unit &outputUnit, + const Kernel::DeltaEMode::Type emode, + const bool signedTheta, int64_t wsIndex, + Kernel::UnitParametersMap &pmap) const; + void createDetectorIdLogMessages(const std::vector<detid_t> &detids, + int64_t wsIndex) const; + SpectrumInfoIterator<SpectrumInfo> begin(); SpectrumInfoIterator<SpectrumInfo> end(); const SpectrumInfoIterator<const SpectrumInfo> cbegin() const; diff --git a/Framework/API/src/ExperimentInfo.cpp b/Framework/API/src/ExperimentInfo.cpp index f37808dbdc7f59f86120cf56d440707835edacd5..2192b7154392dc9896766721bdd8c49855685b4b 100644 --- a/Framework/API/src/ExperimentInfo.cpp +++ b/Framework/API/src/ExperimentInfo.cpp @@ -676,39 +676,70 @@ double ExperimentInfo::getEFixed( const std::shared_ptr<const Geometry::IDetector> &detector) const { populateIfNotLoaded(); Kernel::DeltaEMode::Type emode = getEMode(); - if (emode == Kernel::DeltaEMode::Direct) { - try { - return this->run().getPropertyValueAsType<double>("Ei"); - } catch (Kernel::Exception::NotFoundError &) { - throw std::runtime_error( - "Experiment logs do not contain an Ei value. Have you run GetEi?"); - } - } else if (emode == Kernel::DeltaEMode::Indirect) { - if (!detector) - throw std::runtime_error("ExperimentInfo::getEFixed - Indirect mode " - "efixed requested without a valid detector."); + return getEFixedGivenEMode(detector, emode); +} + +double ExperimentInfo::getEFixedForIndirect( + const std::shared_ptr<const Geometry::IDetector> &detector, + const std::vector<std::string> ¶meterNames) const { + double efixed = 0.; + for (auto ¶meterName : parameterNames) { Parameter_sptr par = - constInstrumentParameters().getRecursive(detector.get(), "Efixed"); + constInstrumentParameters().getRecursive(detector.get(), parameterName); if (par) { - return par->value<double>(); + efixed = par->value<double>(); } else { - std::vector<double> efixedVec = detector->getNumberParameter("Efixed"); + std::vector<double> efixedVec = + detector->getNumberParameter(parameterName); if (efixedVec.empty()) { int detid = detector->getID(); IDetector_const_sptr detectorSingle = getInstrument()->getDetector(detid); - efixedVec = detectorSingle->getNumberParameter("Efixed"); + efixedVec = detectorSingle->getNumberParameter(parameterName); } if (!efixedVec.empty()) { - return efixedVec.at(0); - } else { - std::ostringstream os; - os << "ExperimentInfo::getEFixed - Indirect mode efixed requested but " - "detector has no Efixed parameter attached. ID=" - << detector->getID(); - throw std::runtime_error(os.str()); + efixed = efixedVec.at(0); + } + } + } + if (efixed == 0.) { + std::ostringstream os; + os << "ExperimentInfo::getEFixed - Indirect mode efixed requested but " + "detector has no Efixed parameter attached. ID=" + << detector->getID(); + throw std::runtime_error(os.str()); + } + return efixed; +} + +/** + * Easy access to the efixed value for this run & detector + * @param detector :: The detector object to ask for the efixed mode. Only + * required for Indirect mode + * @param emode :: enum value indicating whether elastic, direct or indirect + * @return The current efixed value + */ +double ExperimentInfo::getEFixedGivenEMode( + const std::shared_ptr<const Geometry::IDetector> &detector, + const Kernel::DeltaEMode::Type emode) const { + if (emode == Kernel::DeltaEMode::Direct) { + double efixed = 0.; + for (auto ¶meterName : {"Ei", "EnergyRequested", "EnergyEstimate"}) { + if (run().hasProperty(parameterName)) { + efixed = run().getPropertyValueAsType<double>(parameterName); + break; } } + if (efixed == 0.) { + throw std::runtime_error("Experiment logs do not contain an Ei " + "value. Have you run GetEi?"); + } + return efixed; + } else if (emode == Kernel::DeltaEMode::Indirect) { + if (!detector) + throw std::runtime_error("ExperimentInfo::getEFixed - Indirect mode " + "efixed requested without a valid detector."); + return getEFixedForIndirect(detector, {"Efixed", "EFixed-val"}); } else { throw std::runtime_error("ExperimentInfo::getEFixed - EFixed requested for " "elastic mode, don't know what to do!"); diff --git a/Framework/API/src/IFunction.cpp b/Framework/API/src/IFunction.cpp index a69fe78f87fb4154727c4f6c5233181a6765e29b..9cc5aec67eadb004a3c8d4e5020c9a6c9173cfe6 100644 --- a/Framework/API/src/IFunction.cpp +++ b/Framework/API/src/IFunction.cpp @@ -1143,12 +1143,12 @@ void IFunction::setMatrixWorkspace( if (centreUnit) { g_log.debug() << "For FitParameter " << parameterName(i) - << " centre of peak before any unit convertion is " + << " centre of peak before any unit conversion is " << centreValue << '\n'; centreValue = convertValue(centreValue, centreUnit, workspace, wi); g_log.debug() << "For FitParameter " << parameterName(i) - << " centre of peak after any unit convertion is " + << " centre of peak after any unit conversion is " << centreValue << '\n'; } @@ -1165,11 +1165,11 @@ void IFunction::setMatrixWorkspace( fitParam.getLookUpTable().getYUnit(); // from table g_log.debug() << "The FitParameter " << parameterName(i) << " = " - << paramValue << " before y-unit convertion\n"; + << paramValue << " before y-unit conversion\n"; paramValue /= convertValue(1.0, resultUnit, workspace, wi); g_log.debug() << "The FitParameter " << parameterName(i) << " = " - << paramValue << " after y-unit convertion\n"; + << paramValue << " after y-unit conversion\n"; } else { // so from formula @@ -1195,12 +1195,12 @@ void IFunction::setMatrixWorkspace( p.SetExpr(resultUnitStr); g_log.debug() << "The FitParameter " << parameterName(i) << " = " << paramValue - << " before result-unit convertion (using " + << " before result-unit conversion (using " << resultUnitStr << ")\n"; paramValue *= p.Eval(); g_log.debug() << "The FitParameter " << parameterName(i) << " = " - << paramValue << " after result-unit convertion\n"; + << paramValue << " after result-unit conversion\n"; } catch (mu::Parser::exception_type &e) { g_log.error() << "Cannot convert formula unit to workspace unit" @@ -1308,31 +1308,25 @@ void IFunction::convertValue(std::vector<double> &values, if (sample == nullptr) { g_log.error() << "No sample defined instrument. Cannot convert units for function\n" - << "Ignore convertion."; + << "Ignore conversion."; return; } const auto &spectrumInfo = ws->spectrumInfo(); double l1 = spectrumInfo.l1(); // If this is a monitor then l1+l2 = source-detector distance and twoTheta=0 - double l2 = spectrumInfo.l2(wsIndex); - double twoTheta(0.0); - if (!spectrumInfo.isMonitor(wsIndex)) - twoTheta = spectrumInfo.twoTheta(wsIndex); - auto emode = static_cast<int>(ws->getEMode()); - double efixed(0.0); + auto emode = ws->getEMode(); + + Kernel::UnitParametersMap pmap{}; + spectrumInfo.getDetectorValues(*wsUnit, *outUnit, emode, false, wsIndex, + pmap); + std::vector<double> emptyVec; try { - std::shared_ptr<const Geometry::IDetector> det( - &spectrumInfo.detector(wsIndex), NoDeleting()); - efixed = ws->getEFixed(det); + wsUnit->toTOF(values, emptyVec, l1, emode, pmap); + outUnit->fromTOF(values, emptyVec, l1, emode, pmap); } catch (std::exception &) { - // assume elastic - efixed = 0.0; - emode = 0; + throw std::runtime_error("Unable to perform unit conversion to " + + outUnit->unitID()); } - - std::vector<double> emptyVec; - wsUnit->toTOF(values, emptyVec, l1, l2, twoTheta, emode, efixed, 0.0); - outUnit->fromTOF(values, emptyVec, l1, l2, twoTheta, emode, efixed, 0.0); } } diff --git a/Framework/API/src/SpectrumInfo.cpp b/Framework/API/src/SpectrumInfo.cpp index 50b1ec904cc1b8b1f61947003bf88726b2884748..3cc369cac7d7cd38730aeeaa6f2ef4f8f7b4d06e 100644 --- a/Framework/API/src/SpectrumInfo.cpp +++ b/Framework/API/src/SpectrumInfo.cpp @@ -8,17 +8,23 @@ #include "MantidAPI/ExperimentInfo.h" #include "MantidAPI/SpectrumInfoIterator.h" #include "MantidBeamline/SpectrumInfo.h" +#include "MantidGeometry/Instrument.h" #include "MantidGeometry/Instrument/DetectorGroup.h" #include "MantidGeometry/Instrument/DetectorInfo.h" #include "MantidKernel/Exception.h" +#include "MantidKernel/Logger.h" #include "MantidKernel/MultiThreaded.h" #include "MantidTypes/SpectrumDefinition.h" #include <algorithm> #include <memory> +using namespace Mantid::Kernel; + namespace Mantid { namespace API { +/// static logger object +Kernel::Logger g_log("ExperimentInfo"); SpectrumInfo::SpectrumInfo(const Beamline::SpectrumInfo &spectrumInfo, const ExperimentInfo &experimentInfo, @@ -140,7 +146,175 @@ Kernel::V3D SpectrumInfo::position(const size_t index) const { return newPos / static_cast<double>(spectrumDefinition(index).size()); } -/// Returns true if the spectrum is associated with detectors in the instrument. +/** Calculate average diffractometer constants (DIFA, DIFC, TZERO) of detectors + * associated with this spectrum. Use calibrated values where possible, filling + * in with uncalibrated values where they're missing + * @param index Index of the spectrum that constants are required for + * @param warningDets A vector containing the det ids where an uncalibrated + * value was used in the situation where some dets have calibrated values and + * some don't + * @return map containing the average constants + */ +UnitParametersMap +SpectrumInfo::diffractometerConstants(const size_t index, + std::vector<detid_t> &warningDets) const { + if (m_detectorInfo.isScanning()) { + throw std::runtime_error("Retrieval of diffractometer constants not " + "implemented for scanning instrument"); + } + auto spectrumDef = checkAndGetSpectrumDefinition(index); + std::vector<size_t> detectorIndicesOnly; + std::vector<detid_t> calibratedDets; + std::vector<detid_t> uncalibratedDets; + std::transform(spectrumDef.begin(), spectrumDef.end(), + std::back_inserter(detectorIndicesOnly), + [](auto const &pair) { return pair.first; }); + double difa{0.}, difc{0.}, tzero{0.}; + for (const auto &detIndex : detectorIndicesOnly) { + auto newDiffConstants = m_detectorInfo.diffractometerConstants( + detIndex, calibratedDets, uncalibratedDets); + difa += std::get<0>(newDiffConstants); + difc += std::get<1>(newDiffConstants); + tzero += std::get<2>(newDiffConstants); + } + + if (calibratedDets.size() > 0 && uncalibratedDets.size() > 0) { + warningDets.insert(warningDets.end(), uncalibratedDets.begin(), + uncalibratedDets.end()); + }; + // if no calibration is found then return difc only based on the average + // of the detector L2 and twoThetas. + if (calibratedDets.size() == 0) { + return {{UnitParams::difc, difcUncalibrated(index)}}; + } + return {{UnitParams::difa, + difa / static_cast<double>(spectrumDefinition(index).size())}, + {UnitParams::difc, + difc / static_cast<double>(spectrumDefinition(index).size())}, + {UnitParams::tzero, + tzero / static_cast<double>(spectrumDefinition(index).size())}}; +} + +/** Calculate average diffractometer constants (DIFA, DIFC, TZERO) of + * detectors associated with this spectrum. Use calibrated values where + * possible, filling in with uncalibrated values where they're missing + * @param index Index of the spectrum that constants are required for + * @return map containing the average constants + */ +UnitParametersMap +SpectrumInfo::diffractometerConstants(const size_t index) const { + std::vector<int> warningDets; + return diffractometerConstants(index, warningDets); +} + +/** Calculate average uncalibrated DIFC value of detectors associated with + * this spectrum + * @param index Index of the spectrum that DIFC is required for + * @return The average DIFC + */ +double SpectrumInfo::difcUncalibrated(const size_t index) const { + // calculate difc based on the average of the detector L2 and twoThetas. + // This will be different to the average of the per detector difcs. This is + // for backwards compatibility because Mantid always used to calculate + // spectrum level difc's this way + return 1. / Kernel::Units::tofToDSpacingFactor(l1(), l2(index), + twoTheta(index), 0.); +} + +/** Get the detector values relevant to unit conversion for a workspace index + * @param inputUnit :: The input unit (Empty implies "all") + * @param outputUnit :: The output unit (Empty implies "all") + * @param emode :: The energy mode + * @param signedTheta :: Return twotheta with sign or without + * @param wsIndex :: The workspace index + * @param pmap :: a map containing values for conversion parameters that are +required by unit classes to perform their conversions eg efixed. It can +contain values on the way in if a look up isn't desired here eg if value +supplied in parameters to the calling algorithm + */ +void SpectrumInfo::getDetectorValues(const Kernel::Unit &inputUnit, + const Kernel::Unit &outputUnit, + const Kernel::DeltaEMode::Type emode, + const bool signedTheta, int64_t wsIndex, + UnitParametersMap &pmap) const { + if (!hasDetectors(wsIndex)) + return; + pmap[UnitParams::l2] = l2(wsIndex); + + if (!isMonitor(wsIndex)) { + // The scattering angle for this detector (in radians). + try { + if (signedTheta) + pmap[UnitParams::twoTheta] = signedTwoTheta(wsIndex); + else + pmap[UnitParams::twoTheta] = twoTheta(wsIndex); + } catch (const std::runtime_error &e) { + g_log.warning(e.what()); + } + if (emode != Kernel::DeltaEMode::Elastic && + pmap.find(UnitParams::efixed) == pmap.end()) { + std::shared_ptr<const Geometry::IDetector> det(&detector(wsIndex), + Mantid::NoDeleting()); + try { + pmap[UnitParams::efixed] = + m_experimentInfo.getEFixedGivenEMode(det, emode); + g_log.debug() << "Detector: " << det->getID() + << " EFixed: " << pmap[UnitParams::efixed] << "\n"; + } catch (std::runtime_error) { + // let the unit classes work out if this is a problem + } + } + + std::vector<detid_t> warnDetIds; + try { + std::set<std::string> diffConstUnits = {"dSpacing", "MomentumTransfer", + "Empty"}; + if ((emode == Kernel::DeltaEMode::Elastic) && + (diffConstUnits.count(inputUnit.unitID()) || + diffConstUnits.count(outputUnit.unitID()))) { + auto diffConstsMap = diffractometerConstants(wsIndex, warnDetIds); + pmap.insert(diffConstsMap.begin(), diffConstsMap.end()); + if (warnDetIds.size() > 0) { + createDetectorIdLogMessages(warnDetIds, wsIndex); + } + } else { + pmap[UnitParams::difc] = difcUncalibrated(wsIndex); + } + } catch (const std::runtime_error &e) { + g_log.warning(e.what()); + } + } else { + pmap[UnitParams::twoTheta] = 0.0; + pmap[UnitParams::efixed] = DBL_MIN; + // Energy transfer is meaningless for a monitor, so set l2 to 0. + if (outputUnit.unitID().find("DeltaE") != std::string::npos) { + pmap[UnitParams::l2] = 0.0; + } + pmap[UnitParams::difc] = 0; + } +} + +void SpectrumInfo::createDetectorIdLogMessages( + const std::vector<detid_t> &detids, int64_t wsIndex) const { + std::string detIDstring; + auto iter = detids.begin(); + auto itEnd = detids.end(); + for (; iter != itEnd; ++iter) { + detIDstring += std::to_string(*iter) + ","; + } + + if (!detIDstring.empty()) { + detIDstring.pop_back(); // Drop last comma + } + g_log.warning( + "Incomplete set of calibrated diffractometer constants found for " + "workspace index" + + std::to_string(wsIndex) + ". Using uncalibrated values for detectors " + + detIDstring); +} + +/// Returns true if the spectrum is associated with detectors in the +/// instrument. bool SpectrumInfo::hasDetectors(const size_t index) const { // Workspaces can contain invalid detector IDs. Those IDs will be silently // ignored here until this is fixed. diff --git a/Framework/Algorithms/inc/MantidAlgorithms/AlignDetectors.h b/Framework/Algorithms/inc/MantidAlgorithms/AlignDetectors.h index b2dba6d8716db4b3252f7a350b47245f59f04e81..c2fc047d5333b6088d9b62f3916de7fb7f3b4800 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/AlignDetectors.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/AlignDetectors.h @@ -7,6 +7,7 @@ #pragma once #include "MantidAPI/Algorithm.h" +#include "MantidAPI/DeprecatedAlgorithm.h" #include "MantidAPI/ITableWorkspace_fwd.h" #include "MantidAlgorithms/DllConfig.h" #include "MantidDataObjects/OffsetsWorkspace.h" @@ -39,7 +40,8 @@ class ConversionFactors; @author Russell Taylor, Tessella Support Services plc @date 18/08/2008 */ -class MANTID_ALGORITHMS_DLL AlignDetectors : public API::Algorithm { +class MANTID_ALGORITHMS_DLL AlignDetectors : public API::Algorithm, + public API::DeprecatedAlgorithm { public: AlignDetectors(); @@ -69,9 +71,7 @@ private: void exec() override; void align(const ConversionFactors &converter, API::Progress &progress, - API::MatrixWorkspace &outputWS); - void align(const ConversionFactors &converter, API::Progress &progress, - DataObjects::EventWorkspace &outputWS); + API::MatrixWorkspace_sptr &outputWS); void loadCalFile(const API::MatrixWorkspace_sptr &inputWS, const std::string &filename); diff --git a/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnits.h b/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnits.h index aef3ddfa017ab62fa36e41e4a8270af7d220f1f9..ddf1e23f7ddf2683ad6a01d8ca84e03eb0eae29f 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnits.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/ConvertUnits.h @@ -103,13 +103,6 @@ protected: convertQuickly(const API::MatrixWorkspace_const_sptr &inputWS, const double &factor, const double &power); - /// Internal function to gather detector specific L2, theta and efixed values - bool getDetectorValues(const API::SpectrumInfo &spectrumInfo, - const Kernel::Unit &outputUnit, int emode, - const API::MatrixWorkspace &ws, const bool signedTheta, - int64_t wsIndex, double &efixed, double &l2, - double &twoTheta); - /// Convert the workspace units using TOF as an intermediate step in the /// conversion virtual API::MatrixWorkspace_sptr diff --git a/Framework/Algorithms/inc/MantidAlgorithms/CreateDetectorTable.h b/Framework/Algorithms/inc/MantidAlgorithms/CreateDetectorTable.h index 3f13c9c229b45d4df5db2c770447b58f6093a236..bfd4aaf2033ace55bbc8b770c87d792f5613145f 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/CreateDetectorTable.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/CreateDetectorTable.h @@ -68,9 +68,10 @@ void populateTable(Mantid::API::ITableWorkspace_sptr &t, const Mantid::Geometry::PointingAlong &beamAxisIndex, const double sampleDist, const bool isScanning, const bool include_data, const bool calcQ, - Kernel::Logger &logger); + const bool includeDiffConstants, Kernel::Logger &logger); std::vector<std::pair<std::string, std::string>> -createColumns(const bool isScanning, const bool includeData, const bool calcQ); +createColumns(const bool isScanning, const bool includeData, const bool calcQ, + const bool hasDiffConstants); } // namespace Algorithms } // namespace Mantid diff --git a/Framework/Algorithms/inc/MantidAlgorithms/PDCalibration.h b/Framework/Algorithms/inc/MantidAlgorithms/PDCalibration.h index e4affc14c7eab18ad1b6a29457044ab7041dc17b..16a284bb66c5dad6a9009706297c44cc36db6f0c 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/PDCalibration.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/PDCalibration.h @@ -44,7 +44,7 @@ private: void createCalTableFromExisting(); void createCalTableNew(); void createInformationWorkspaces(); - std::function<double(double)> + std::tuple<double, double, double> getDSpacingToTof(const std::set<detid_t> &detIds); std::vector<double> dSpacingWindows(const std::vector<double> ¢res, const double widthMax); diff --git a/Framework/Algorithms/inc/MantidAlgorithms/RemoveBackground.h b/Framework/Algorithms/inc/MantidAlgorithms/RemoveBackground.h index 0b4cbfa584c6d44cc0a73a4f0109126e2d7bf5a5..66183e705f52cfb9c1cc38f5d6cd4348d10edb34 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/RemoveBackground.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/RemoveBackground.h @@ -9,6 +9,7 @@ #include "MantidAPI/Algorithm.h" #include "MantidAlgorithms/DllConfig.h" #include "MantidGeometry/IComponent.h" +#include "MantidKernel/DeltaEMode.h" #include "MantidKernel/cow_ptr.h" namespace Mantid { @@ -46,7 +47,8 @@ public: BackgroundHelper(const BackgroundHelper &) = delete; void initialize(const API::MatrixWorkspace_const_sptr &bkgWS, - const API::MatrixWorkspace_sptr &sourceWS, int emode, + const API::MatrixWorkspace_sptr &sourceWS, + Kernel::DeltaEMode::Type emode, Kernel::Logger *pLog = nullptr, int nThreads = 1, bool inPlace = true, bool nullifyNegative = false); void removeBackground(int nHist, HistogramData::HistogramX &x_data, @@ -81,16 +83,11 @@ private: // workspace double m_ErrSq; // energy conversion mode - int m_Emode; - // incident for direct or analysis for indirect energy for units conversion - double m_Efix; + Kernel::DeltaEMode::Type m_Emode; // if true, negative signals are nullified bool m_nullifyNegative; // removing negative values from ws with background removed previously. bool m_previouslyRemovedBkgMode; - - // get Ei attached to direct or indirect instrument workspace - double getEi(const API::MatrixWorkspace_const_sptr &inputWS) const; }; class MANTID_ALGORITHMS_DLL RemoveBackground : public API::Algorithm { diff --git a/Framework/Algorithms/inc/MantidAlgorithms/RemoveBins.h b/Framework/Algorithms/inc/MantidAlgorithms/RemoveBins.h index b3862afea157cd89bf1012e731ef06ec3753c539..4e4b15b3ef576f84d2e81f4795f5c635d5384d09 100644 --- a/Framework/Algorithms/inc/MantidAlgorithms/RemoveBins.h +++ b/Framework/Algorithms/inc/MantidAlgorithms/RemoveBins.h @@ -72,8 +72,6 @@ private: void crop(const double &start, const double &end); void transformRangeUnit(const int index, double &startX, double &endX); - void calculateDetectorPosition(const int index, double &l1, double &l2, - double &twoTheta); int findIndex(const double &value, const HistogramData::HistogramX &vec); void RemoveFromEnds(int start, int end, HistogramData::HistogramY &Y, HistogramData::HistogramE &E); diff --git a/Framework/Algorithms/src/AddPeak.cpp b/Framework/Algorithms/src/AddPeak.cpp index 63be9394c4754b16ef801b5e7dd3060afa14b3e2..32b45a3b594478ed60e56bf64f66b322345ec63c 100644 --- a/Framework/Algorithms/src/AddPeak.cpp +++ b/Framework/Algorithms/src/AddPeak.cpp @@ -83,6 +83,9 @@ void AddPeak::exec() { double Qz = 1.0 - cos(theta2); double l1 = detectorInfo.l1(); double l2 = detectorInfo.l2(detectorIndex); + std::vector<int> emptyWarningVec; + auto [difa, difc, tzero] = detectorInfo.diffractometerConstants( + detectorIndex, emptyWarningVec, emptyWarningVec); Mantid::Kernel::Unit_sptr unit = runWS->getAxis(0)->unit(); if (unit->unitID() != "TOF") { @@ -112,7 +115,13 @@ void AddPeak::exec() { } std::vector<double> xdata(1, tof); std::vector<double> ydata; - unit->toTOF(xdata, ydata, l1, l2, theta2, emode, efixed, 0.0); + unit->toTOF(xdata, ydata, l1, emode, + {{Kernel::UnitParams::l2, l2}, + {Kernel::UnitParams::twoTheta, theta2}, + {Kernel::UnitParams::efixed, efixed}, + {Kernel::UnitParams::difa, difa}, + {Kernel::UnitParams::difc, difc}, + {Kernel::UnitParams::tzero, tzero}}); tof = xdata[0]; } diff --git a/Framework/Algorithms/src/AlignDetectors.cpp b/Framework/Algorithms/src/AlignDetectors.cpp index 7b2e08c9c10e5e4e359ed34618e036d174f04d0f..b9981513252d6e6b6a7cab8a61cf23804988e187 100644 --- a/Framework/Algorithms/src/AlignDetectors.cpp +++ b/Framework/Algorithms/src/AlignDetectors.cpp @@ -17,7 +17,6 @@ #include "MantidDataObjects/EventWorkspace.h" #include "MantidDataObjects/OffsetsWorkspace.h" #include "MantidKernel/CompositeValidator.h" -#include "MantidKernel/Diffraction.h" #include "MantidKernel/PhysicalConstants.h" #include "MantidKernel/UnitFactory.h" #include "MantidKernel/V3D.h" @@ -49,8 +48,8 @@ public: this->generateDetidToRow(table); } - std::function<double(double)> - getConversionFunc(const std::set<detid_t> &detIds) const { + std::tuple<double, double, double> + getDiffConstants(const std::set<detid_t> &detIds) const { const std::set<size_t> rows = this->getRow(detIds); double difc = 0.; double difa = 0.; @@ -67,7 +66,7 @@ public: tzero = norm * tzero; } - return Kernel::Diffraction::getTofToDConversionFunc(difc, difa, tzero); + return {difc, difa, tzero}; } private: @@ -87,6 +86,16 @@ private: rows.insert(rowIter->second); } } + if (rows.empty()) { + std::string detIdsStr = std::accumulate( + std::begin(detIds), std::end(detIds), std::string{}, + [](const std::string &a, const detid_t &b) { + return a.empty() ? std::to_string(b) : a + ',' + std::to_string(b); + }); + throw Exception::NotFoundError( + "None of the detectors were found in the calibration table", + detIdsStr); + } return rows; } @@ -110,8 +119,11 @@ const std::string AlignDetectors::summary() const { "values to account for small errors in the detector positions."; } -/// (Empty) Constructor -AlignDetectors::AlignDetectors() : m_numberOfSpectra(0) {} +/// Constructor +AlignDetectors::AlignDetectors() : m_numberOfSpectra(0) { + useAlgorithm("ConvertUnits"); + deprecatedDate("2021-01-04"); +} void AlignDetectors::init() { auto wsValidator = std::make_shared<CompositeValidator>(); @@ -262,60 +274,58 @@ void AlignDetectors::exec() { Progress progress(this, 0.0, 1.0, m_numberOfSpectra); - auto eventW = std::dynamic_pointer_cast<EventWorkspace>(outputWS); - if (eventW) { - align(converter, progress, *eventW); - } else { - align(converter, progress, *outputWS); - } + align(converter, progress, outputWS); } void AlignDetectors::align(const ConversionFactors &converter, - Progress &progress, MatrixWorkspace &outputWS) { - PARALLEL_FOR_IF(Kernel::threadSafe(outputWS)) + Progress &progress, MatrixWorkspace_sptr &outputWS) { + auto eventW = std::dynamic_pointer_cast<EventWorkspace>(outputWS); + PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS)) for (int64_t i = 0; i < m_numberOfSpectra; ++i) { PARALLEL_START_INTERUPT_REGION try { // Get the input spectrum number at this workspace index - auto &spec = outputWS.getSpectrum(size_t(i)); - auto toDspacing = converter.getConversionFunc(spec.getDetectorIDs()); - - auto &x = outputWS.mutableX(i); - std::transform(x.begin(), x.end(), x.begin(), toDspacing); - } catch (const Exception::NotFoundError &) { - // Zero the data in this case - outputWS.setHistogram(i, BinEdges(outputWS.x(i).size()), - Counts(outputWS.y(i).size())); + auto &spec = outputWS->getSpectrum(size_t(i)); + auto [difc, difa, tzero] = + converter.getDiffConstants(spec.getDetectorIDs()); + + auto &x = outputWS->dataX(i); + Kernel::Units::dSpacing dSpacingUnit; + std::vector<double> yunused; + dSpacingUnit.fromTOF( + x, yunused, -1., 0, + UnitParametersMap{{Kernel::UnitParams::difa, difa}, + {Kernel::UnitParams::difc, difc}, + {Kernel::UnitParams::tzero, tzero}}); + + if (eventW) { + Kernel::Units::TOF tofUnit; + tofUnit.initialize(0, 0, {}); + // EventWorkspace part, modifying the EventLists. + eventW->getSpectrum(i).convertUnitsViaTof(&tofUnit, &dSpacingUnit); + } + } catch (const std::runtime_error &) { + if (!eventW) { + // Zero the data in this case (detectors not found in cal table or + // conversion fails) + outputWS->setHistogram(i, BinEdges(outputWS->x(i).size()), + Counts(outputWS->y(i).size())); + } } progress.report(); PARALLEL_END_INTERUPT_REGION } PARALLEL_CHECK_INTERUPT_REGION -} - -void AlignDetectors::align(const ConversionFactors &converter, - Progress &progress, EventWorkspace &outputWS) { - PARALLEL_FOR_NO_WSP_CHECK() - for (int64_t i = 0; i < m_numberOfSpectra; ++i) { - PARALLEL_START_INTERUPT_REGION - - auto toDspacing = converter.getConversionFunc( - outputWS.getSpectrum(size_t(i)).getDetectorIDs()); - outputWS.getSpectrum(i).convertTof(toDspacing); - - progress.report(); - PARALLEL_END_INTERUPT_REGION - } - PARALLEL_CHECK_INTERUPT_REGION - - if (outputWS.getTofMin() < 0.) { - std::stringstream msg; - msg << "Something wrong with the calibration. Negative minimum d-spacing " - "created. d_min = " - << outputWS.getTofMin() << " d_max " << outputWS.getTofMax(); - g_log.warning(msg.str()); + if (eventW) { + if (eventW->getTofMin() < 0.) { + std::stringstream msg; + msg << "Something wrong with the calibration. Negative minimum d-spacing " + "created. d_min = " + << eventW->getTofMin() << " d_max " << eventW->getTofMax(); + g_log.warning(msg.str()); + } + eventW->clearMRU(); } - outputWS.clearMRU(); } Parallel::ExecutionMode AlignDetectors::getParallelExecutionMode( diff --git a/Framework/Algorithms/src/CalculatePlaczekSelfScattering.cpp b/Framework/Algorithms/src/CalculatePlaczekSelfScattering.cpp index 3417c43b262daedffa95b5c09e2977d3113e7a34..c4fdc58b3727dc7b607352d10f29d3981c848582 100644 --- a/Framework/Algorithms/src/CalculatePlaczekSelfScattering.cpp +++ b/Framework/Algorithms/src/CalculatePlaczekSelfScattering.cpp @@ -163,12 +163,23 @@ void CalculatePlaczekSelfScattering::exec() { auto &y = outputWS->mutableY(specIndex); auto &x = outputWS->mutableX(specIndex); if (!specInfo.isMonitor(specIndex) && !(specInfo.l2(specIndex) == 0.0)) { - const double pathLength = specInfo.l1() + specInfo.l2(specIndex); - const double f = specInfo.l1() / pathLength; - const double sinThetaBy2 = sin(specInfo.twoTheta(specIndex) / 2.0); Kernel::Units::Wavelength wavelength; - wavelength.initialize(specInfo.l1(), specInfo.l2(specIndex), - specInfo.twoTheta(specIndex), 0, 1.0, 1.0); + Kernel::Units::TOF tof; + Kernel::UnitParametersMap pmap{}; + double l1 = specInfo.l1(); + specInfo.getDetectorValues(wavelength, tof, Kernel::DeltaEMode::Elastic, + false, specIndex, pmap); + double l2 = 0., twoTheta = 0.; + if (pmap.find(Kernel::UnitParams::l2) != pmap.end()) { + l2 = pmap[Kernel::UnitParams::l2]; + } + if (pmap.find(Kernel::UnitParams::twoTheta) != pmap.end()) { + twoTheta = pmap[Kernel::UnitParams::twoTheta]; + } + + const double sinThetaBy2 = sin(twoTheta / 2.0); + const double f = l1 / (l1 + l2); + wavelength.initialize(specInfo.l1(), 0, pmap); for (size_t xIndex = 0; xIndex < xLambda.size() - 1; xIndex++) { const double term1 = (f - 1.0) * phi1[xIndex]; const double term2 = f * (1.0 - eps1[xIndex]); diff --git a/Framework/Algorithms/src/CompareWorkspaces.cpp b/Framework/Algorithms/src/CompareWorkspaces.cpp index 1a4bb7af11e11801fdee5f976865f2659fb38027..f56514c5d18c0cc2bec147dc77858127a0bddb44 100644 --- a/Framework/Algorithms/src/CompareWorkspaces.cpp +++ b/Framework/Algorithms/src/CompareWorkspaces.cpp @@ -902,10 +902,12 @@ bool CompareWorkspaces::checkInstrument( const Geometry::ParameterMap &ws1_parmap = ws1->constInstrumentParameters(); const Geometry::ParameterMap &ws2_parmap = ws2->constInstrumentParameters(); - if (ws1_parmap != ws2_parmap) { + const bool checkAllData = getProperty("CheckAllData"); + auto errorStr = ws1_parmap.diff(ws2_parmap, !checkAllData); + if (!errorStr.empty()) { g_log.debug() << "Here information to help understand parameter map differences:\n"; - g_log.debug() << ws1_parmap.diff(ws2_parmap); + g_log.debug() << errorStr; recordMismatch( "Instrument ParameterMap mismatch (differences in ordering ignored)"); return false; diff --git a/Framework/Algorithms/src/ConvertSpectrumAxis.cpp b/Framework/Algorithms/src/ConvertSpectrumAxis.cpp index 0d535494a53ef4773218cbecec91e52eadcc7a1e..e8babeb8a12b5fcdb00cb395d9ebed628e63671c 100644 --- a/Framework/Algorithms/src/ConvertSpectrumAxis.cpp +++ b/Framework/Algorithms/src/ConvertSpectrumAxis.cpp @@ -94,35 +94,38 @@ void ConvertSpectrumAxis::exec() { std::vector<double> emptyVector; const double l1 = spectrumInfo.l1(); const std::string emodeStr = getProperty("EMode"); - int emode = 0; - if (emodeStr == "Direct") - emode = 1; - else if (emodeStr == "Indirect") - emode = 2; - const double delta = 0.0; - double efixed; + auto emode = Kernel::DeltaEMode::fromString(emodeStr); + size_t nfailures = 0; for (size_t i = 0; i < nHist; i++) { std::vector<double> xval{inputWS->x(i).front(), inputWS->x(i).back()}; - double twoTheta, l1val, l2; - if (!spectrumInfo.isMonitor(i)) { - twoTheta = spectrumInfo.twoTheta(i); - l2 = spectrumInfo.l2(i); - l1val = l1; - efixed = - getEfixed(spectrumInfo.detector(i), inputWS, emode); // get efixed - } else { - twoTheta = 0.0; - l2 = l1; - l1val = 0.0; - efixed = DBL_MIN; + UnitParametersMap pmap{}; + + double efixedProp = getProperty("Efixed"); + if (efixedProp != EMPTY_DBL()) { + pmap[UnitParams::efixed] = efixedProp; + g_log.debug() << "Detector: " << spectrumInfo.detector(i).getID() + << " Efixed: " << efixedProp << "\n"; + } + + spectrumInfo.getDetectorValues(*fromUnit, *toUnit, emode, false, i, pmap); + double value = 0.; + try { + fromUnit->toTOF(xval, emptyVector, l1, emode, pmap); + toUnit->fromTOF(xval, emptyVector, l1, emode, pmap); + value = (xval.front() + xval.back()) / 2; + } catch (std::runtime_error &) { + nfailures++; + g_log.warning() << "Unable to calculate new spectrum axis value for " + "workspace index " + << i; + value = inputWS->getAxis(1)->getValue(i); } - fromUnit->toTOF(xval, emptyVector, l1val, l2, twoTheta, emode, efixed, - delta); - toUnit->fromTOF(xval, emptyVector, l1val, l2, twoTheta, emode, efixed, - delta); - double value = (xval.front() + xval.back()) / 2; indexMap.emplace(value, i); } + if (nfailures == nHist) { + throw std::runtime_error( + "Unable to convert spectrum axis values on all spectra"); + } } else { // Set up binding to memeber funtion. Avoids condition as part of loop over // nHistograms. diff --git a/Framework/Algorithms/src/ConvertUnits.cpp b/Framework/Algorithms/src/ConvertUnits.cpp index 08ece60bd6c1c6e0c43f4bd325a85bcbc2c2f9c1..2b95f1f70b61a03a0f474452108448102bc2acd8 100644 --- a/Framework/Algorithms/src/ConvertUnits.cpp +++ b/Framework/Algorithms/src/ConvertUnits.cpp @@ -14,6 +14,7 @@ #include "MantidDataObjects/Workspace2D.h" #include "MantidDataObjects/WorkspaceCreation.h" #include "MantidGeometry/Instrument.h" +#include "MantidGeometry/Instrument/DetectorInfo.h" #include "MantidHistogramData/Histogram.h" #include "MantidKernel/BoundedValidator.h" #include "MantidKernel/CompositeValidator.h" @@ -387,65 +388,6 @@ ConvertUnits::convertQuickly(const API::MatrixWorkspace_const_sptr &inputWS, return outputWS; } -/** Get the L2, theta and efixed values for a workspace index - * @param spectrumInfo :: SpectrumInfo of the workspace - * @param outputUnit :: The output unit - * @param emode :: The energy mode - * @param ws :: The workspace - * @param signedTheta :: Return twotheta with sign or without - * @param wsIndex :: The workspace index - * @param efixed :: the returned fixed energy - * @param l2 :: The returned sample - detector distance - * @param twoTheta :: the returned two theta angle - * @returns true if lookup successful, false on error - */ -bool ConvertUnits::getDetectorValues(const API::SpectrumInfo &spectrumInfo, - const Kernel::Unit &outputUnit, int emode, - const MatrixWorkspace &ws, - const bool signedTheta, int64_t wsIndex, - double &efixed, double &l2, - double &twoTheta) { - if (!spectrumInfo.hasDetectors(wsIndex)) - return false; - - l2 = spectrumInfo.l2(wsIndex); - - if (!spectrumInfo.isMonitor(wsIndex)) { - // The scattering angle for this detector (in radians). - try { - if (signedTheta) - twoTheta = spectrumInfo.signedTwoTheta(wsIndex); - else - twoTheta = spectrumInfo.twoTheta(wsIndex); - } catch (const std::runtime_error &e) { - g_log.warning(e.what()); - twoTheta = std::numeric_limits<double>::quiet_NaN(); - } - // If an indirect instrument, try getting Efixed from the geometry - if (emode == 2 && efixed == EMPTY_DBL()) // indirect - { - if (spectrumInfo.hasUniqueDetector(wsIndex)) { - const auto &det = spectrumInfo.detector(wsIndex); - auto par = ws.constInstrumentParameters().getRecursive(&det, "Efixed"); - if (par) { - efixed = par->value<double>(); - g_log.debug() << "Detector: " << det.getID() << " EFixed: " << efixed - << "\n"; - } - } - // Non-unique detector (i.e., DetectorGroup): use single provided value - } - } else { - twoTheta = 0.0; - efixed = DBL_MIN; - // Energy transfer is meaningless for a monitor, so set l2 to 0. - if (outputUnit.unitID().find("DeltaE") != std::string::npos) { - l2 = 0.0; - } - } - return true; -} - /** Convert the workspace units using TOF as an intermediate step in the * conversion * @param fromUnit :: The unit of the input workspace @@ -472,44 +414,18 @@ ConvertUnits::convertViaTOF(Kernel::Unit_const_sptr fromUnit, /// @todo No implementation for any of these in the geometry yet so using /// properties const std::string emodeStr = getProperty("EMode"); - // Convert back to an integer representation - int emode = 0; - if (emodeStr == "Direct") - emode = 1; - else if (emodeStr == "Indirect") - emode = 2; + DeltaEMode::Type emode = DeltaEMode::fromString(emodeStr); // Not doing anything with the Y vector in to/fromTOF yet, so just pass // empty // vector std::vector<double> emptyVec; - const bool needEfixed = - (outputUnit->unitID().find("DeltaE") != std::string::npos || - outputUnit->unitID().find("Wave") != std::string::npos); double efixedProp = getProperty("Efixed"); - if (emode == 1) { - //... direct efixed gather - if (efixedProp == EMPTY_DBL()) { - // try and get the value from the run parameters - const API::Run &run = inputWS->run(); - if (run.hasProperty("Ei")) { - try { - efixedProp = run.getPropertyValueAsType<double>("Ei"); - } catch (Kernel::Exception::NotFoundError &) { - throw std::runtime_error("Cannot retrieve Ei value from the logs"); - } - } else { - if (needEfixed) { - throw std::invalid_argument( - "Could not retrieve incident energy from run object"); - } else { - efixedProp = 0.0; - } - } + if (efixedProp == EMPTY_DBL() && emode == DeltaEMode::Type::Direct) { + try { + efixedProp = inputWS->getEFixedGivenEMode(nullptr, emode); + } catch (std::runtime_error &) { } - } else if (emode == 0 && efixedProp == EMPTY_DBL()) // Elastic - { - efixedProp = 0.0; } std::vector<std::string> parameters = @@ -518,25 +434,27 @@ ConvertUnits::convertViaTOF(Kernel::Unit_const_sptr fromUnit, (!parameters.empty()) && find(parameters.begin(), parameters.end(), "Always") != parameters.end(); - auto localFromUnit = std::unique_ptr<Unit>(fromUnit->clone()); - auto localOutputUnit = std::unique_ptr<Unit>(outputUnit->clone()); + auto checkFromUnit = std::unique_ptr<Unit>(fromUnit->clone()); + auto checkOutputUnit = std::unique_ptr<Unit>(outputUnit->clone()); // Perform Sanity Validation before creating workspace - double checkefixed = efixedProp; - double checkl2; - double checktwoTheta; + const double checkdelta = 0.0; + UnitParametersMap pmap = {{UnitParams::delta, checkdelta}}; + if (efixedProp != EMPTY_DBL()) { + pmap[UnitParams::efixed] = efixedProp; + } size_t checkIndex = 0; - if (getDetectorValues(spectrumInfo, *outputUnit, emode, *inputWS, signedTheta, - checkIndex, checkefixed, checkl2, checktwoTheta)) { - const double checkdelta = 0.0; - // copy the X values for the check - auto checkXValues = inputWS->readX(checkIndex); + spectrumInfo.getDetectorValues(*fromUnit, *outputUnit, emode, signedTheta, + checkIndex, pmap); + // copy the X values for the check + auto checkXValues = inputWS->readX(checkIndex); + try { // Convert the input unit to time-of-flight - localFromUnit->toTOF(checkXValues, emptyVec, l1, checkl2, checktwoTheta, - emode, checkefixed, checkdelta); + checkFromUnit->toTOF(checkXValues, emptyVec, l1, emode, pmap); // Convert from time-of-flight to the desired unit - localOutputUnit->fromTOF(checkXValues, emptyVec, l1, checkl2, checktwoTheta, - emode, checkefixed, checkdelta); + checkOutputUnit->fromTOF(checkXValues, emptyVec, l1, emode, pmap); + } catch ( + std::runtime_error) { // if it's a detector specific problem then ignore } // create the output workspace @@ -547,32 +465,38 @@ ConvertUnits::convertViaTOF(Kernel::Unit_const_sptr fromUnit, auto &outSpectrumInfo = outputWS->mutableSpectrumInfo(); // Loop over the histograms (detector spectra) + PARALLEL_FOR_IF(Kernel::threadSafe(*outputWS)) for (int64_t i = 0; i < numberOfSpectra_i; ++i) { + PARALLEL_START_INTERUPT_REGION double efixed = efixedProp; // Now get the detector object for this histogram - double l2; - double twoTheta; - if (getDetectorValues(outSpectrumInfo, *outputUnit, emode, *outputWS, - signedTheta, i, efixed, l2, twoTheta)) { + /// @todo Don't yet consider hold-off (delta) + const double delta = 0.0; - /// @todo Don't yet consider hold-off (delta) - const double delta = 0.0; + auto localFromUnit = std::unique_ptr<Unit>(fromUnit->clone()); + auto localOutputUnit = std::unique_ptr<Unit>(outputUnit->clone()); - // TODO toTOF and fromTOF need to be reimplemented outside of kernel - localFromUnit->toTOF(outputWS->dataX(i), emptyVec, l1, l2, twoTheta, - emode, efixed, delta); + // TODO toTOF and fromTOF need to be reimplemented outside of kernel + UnitParametersMap pmap = {{UnitParams::delta, delta}}; + if (efixedProp != EMPTY_DBL()) { + pmap[UnitParams::efixed] = efixed; + } + outSpectrumInfo.getDetectorValues(*fromUnit, *outputUnit, emode, + signedTheta, i, pmap); + try { + localFromUnit->toTOF(outputWS->dataX(i), emptyVec, l1, emode, pmap); // Convert from time-of-flight to the desired unit - localOutputUnit->fromTOF(outputWS->dataX(i), emptyVec, l1, l2, twoTheta, - emode, efixed, delta); + localOutputUnit->fromTOF(outputWS->dataX(i), emptyVec, l1, emode, pmap); // EventWorkspace part, modifying the EventLists. if (m_inputEvents) { eventWS->getSpectrum(i).convertUnitsViaTof(localFromUnit.get(), localOutputUnit.get()); } - } else { - // Get to here if exception thrown when calculating distance to detector + } catch (std::runtime_error) { + // Get to here if exception thrown in unit conversion eg when calculating + // distance to detector failedDetectorCount++; // Since you usually (always?) get to here when there's no attached // detectors, this call is @@ -584,7 +508,9 @@ ConvertUnits::convertViaTOF(Kernel::Unit_const_sptr fromUnit, } prog.report("Convert to " + m_outputUnit->unitID()); + PARALLEL_END_INTERUPT_REGION } // loop over spectra + PARALLEL_CHECK_INTERUPT_REGION if (failedDetectorCount != 0) { g_log.information() << "Unable to calculate sample-detector distance for " diff --git a/Framework/Algorithms/src/ConvertUnitsUsingDetectorTable.cpp b/Framework/Algorithms/src/ConvertUnitsUsingDetectorTable.cpp index 70aa822f32761b32e4c3fe32679a568eb982070c..01e5ac7d1a1705f50efe4a49659265931a6bc585 100644 --- a/Framework/Algorithms/src/ConvertUnitsUsingDetectorTable.cpp +++ b/Framework/Algorithms/src/ConvertUnitsUsingDetectorTable.cpp @@ -162,16 +162,14 @@ MatrixWorkspace_sptr ConvertUnitsUsingDetectorTable::convertViaTOF( // Convert the input unit to time-of-flight auto checkFromUnit = std::unique_ptr<Unit>(fromUnit->clone()); auto checkOutputUnit = std::unique_ptr<Unit>(outputUnit->clone()); - double checkdelta = 0; + UnitParametersMap pmap{{UnitParams::l2, l2Column[detectorRow]}, + {UnitParams::twoTheta, twoThetaColumn[detectorRow]}, + {UnitParams::efixed, efixedColumn[detectorRow]}}; checkFromUnit->toTOF(checkXValues, emptyVec, l1Column[detectorRow], - l2Column[detectorRow], twoThetaColumn[detectorRow], - emodeColumn[detectorRow], efixedColumn[detectorRow], - checkdelta); + emodeColumn[detectorRow], pmap); // Convert from time-of-flight to the desired unit checkOutputUnit->fromTOF(checkXValues, emptyVec, l1Column[detectorRow], - l2Column[detectorRow], twoThetaColumn[detectorRow], - emodeColumn[detectorRow], - efixedColumn[detectorRow], checkdelta); + emodeColumn[detectorRow], pmap); } // create the output workspace @@ -229,16 +227,16 @@ MatrixWorkspace_sptr ConvertUnitsUsingDetectorTable::convertViaTOF( auto localFromUnit = std::unique_ptr<Unit>(fromUnit->clone()); auto localOutputUnit = std::unique_ptr<Unit>(outputUnit->clone()); /// @todo Don't yet consider hold-off (delta) - const double delta = 0.0; std::vector<double> values(outputWS->x(wsid).begin(), outputWS->x(wsid).end()); + UnitParametersMap pmap{{UnitParams::l2, l2}, + {UnitParams::twoTheta, twoTheta}, + {UnitParams::efixed, efixed}}; // Convert the input unit to time-of-flight - localFromUnit->toTOF(values, emptyVec, l1, l2, twoTheta, emode, efixed, - delta); + localFromUnit->toTOF(values, emptyVec, l1, emode, pmap); // Convert from time-of-flight to the desired unit - localOutputUnit->fromTOF(values, emptyVec, l1, l2, twoTheta, emode, - efixed, delta); + localOutputUnit->fromTOF(values, emptyVec, l1, emode, pmap); outputWS->mutableX(wsid) = std::move(values); diff --git a/Framework/Algorithms/src/CreateDetectorTable.cpp b/Framework/Algorithms/src/CreateDetectorTable.cpp index a466b80a733a5c3e0b757e64283fb12139007ddd..23029e752fc2fc86ef37da5f5c6e6575489e0367 100644 --- a/Framework/Algorithms/src/CreateDetectorTable.cpp +++ b/Framework/Algorithms/src/CreateDetectorTable.cpp @@ -147,8 +147,15 @@ createDetectorTableWorkspace(const MatrixWorkspace_sptr &ws, calcQ = false; } + bool hasDiffConstants{false}; + auto emode = ws->getEMode(); + if (emode == DeltaEMode::Elastic) { + hasDiffConstants = true; + } + // Prepare column names - auto colNames = createColumns(isScanning, includeData, calcQ); + auto colNames = + createColumns(isScanning, includeData, calcQ, hasDiffConstants); const int ncols = static_cast<int>(colNames.size()); const int nrows = indices.empty() @@ -175,13 +182,14 @@ createDetectorTableWorkspace(const MatrixWorkspace_sptr &ws, populateTable(t, ws, nrows, indices, spectrumInfo, signedThetaParamRetrieved, showSignedTwoTheta, beamAxisIndex, sampleDist, isScanning, - includeData, calcQ, logger); + includeData, calcQ, hasDiffConstants, logger); return t; } std::vector<std::pair<std::string, std::string>> -createColumns(const bool isScanning, const bool includeData, const bool calcQ) { +createColumns(const bool isScanning, const bool includeData, const bool calcQ, + const bool hasDiffConstants) { std::vector<std::pair<std::string, std::string>> colNames; colNames.emplace_back("double", "Index"); colNames.emplace_back("int", "Spectrum No"); @@ -200,6 +208,12 @@ createColumns(const bool isScanning, const bool includeData, const bool calcQ) { } colNames.emplace_back("double", "Phi"); colNames.emplace_back("str", "Monitor"); + if (hasDiffConstants) { + colNames.emplace_back("double", "DIFA"); + colNames.emplace_back("double", "DIFC"); + colNames.emplace_back("double", "DIFC - Uncalibrated"); + colNames.emplace_back("double", "TZERO"); + } return colNames; } @@ -209,7 +223,8 @@ void populateTable(ITableWorkspace_sptr &t, const MatrixWorkspace_sptr &ws, bool signedThetaParamRetrieved, bool showSignedTwoTheta, const PointingAlong &beamAxisIndex, const double sampleDist, const bool isScanning, const bool includeData, - const bool calcQ, Logger &logger) { + const bool calcQ, const bool includeDiffConstants, + Logger &logger) { PARALLEL_FOR_IF(Mantid::Kernel::threadSafe(*ws)) for (int row = 0; row < nrows; ++row) { TableRow colValues = t->getRow(row); @@ -307,7 +322,22 @@ void populateTable(ITableWorkspace_sptr &t, const MatrixWorkspace_sptr &ws, colValues << phi // rtp << isMonitorDisplay; // monitor + + if (includeDiffConstants) { + if (isMonitor) { + colValues << 0. << 0. << 0. << 0.; + } else { + auto diffConsts = spectrumInfo.diffractometerConstants(wsIndex); + auto difcValueUncalibrated = spectrumInfo.difcUncalibrated(wsIndex); + // map will create an entry with zero value if not present already + colValues << diffConsts[UnitParams::difa] + << diffConsts[UnitParams::difc] << difcValueUncalibrated + << diffConsts[UnitParams::tzero]; + } + } } catch (const std::exception &) { + colValues.row(row); + colValues << static_cast<double>(wsIndex); // spectrumNo=-1, detID=0 colValues << -1 << "0"; // Y/E @@ -320,7 +350,10 @@ void populateTable(ITableWorkspace_sptr &t, const MatrixWorkspace_sptr &ws, } colValues << 0.0 // rtp << "n/a"; // monitor - } // End catch for no spectrum + if (includeDiffConstants) { + colValues << 0.0 << 0.0 << 0.0 << 0.0; + } + } // End catch for no spectrum } } diff --git a/Framework/Algorithms/src/GetAllEi.cpp b/Framework/Algorithms/src/GetAllEi.cpp index e7a6d1fc263167074aa4493945fef0db21f36a2e..498fd7852c1d1fd127650526198f38119a695a35 100644 --- a/Framework/Algorithms/src/GetAllEi.cpp +++ b/Framework/Algorithms/src/GetAllEi.cpp @@ -255,7 +255,6 @@ void GetAllEi::exec() { (0.5 * 1.e+6) / chopSpeed; // 0.5 because some choppers open twice. // Would be nice to have it 1 or 0.5 depending on chopper type, but // it looks like not enough information on what chopper is available on ws; - double unused(0.0); auto destUnit = Kernel::UnitFactory::Instance().create("Energy"); std::vector<double> guess_opening; @@ -267,9 +266,8 @@ void GetAllEi::exec() { boost::lexical_cast<std::string>(TOF_range.first) + ':' + boost::lexical_cast<std::string>(TOF_range.second)); } else { - destUnit->initialize(mon1Distance, 0., 0., - static_cast<int>(Kernel::DeltaEMode::Elastic), 0., - unused); + destUnit->initialize(mon1Distance, + static_cast<int>(Kernel::DeltaEMode::Elastic), {}); printDebugModeInfo(guess_opening, TOF_range, destUnit); } std::pair<double, double> Mon1_Erange = @@ -286,9 +284,8 @@ void GetAllEi::exec() { // convert to energy std::vector<double> guess_ei; guess_ei.reserve(guess_opening.size()); - destUnit->initialize(mon1Distance, 0., 0., - static_cast<int>(Kernel::DeltaEMode::Elastic), 0., - unused); + destUnit->initialize(mon1Distance, + static_cast<int>(Kernel::DeltaEMode::Elastic), {}); for (double time : guess_opening) { double eGuess = destUnit->singleFromTOF(time); if (eGuess > eMin && eGuess < eMax) { diff --git a/Framework/Algorithms/src/PDCalibration.cpp b/Framework/Algorithms/src/PDCalibration.cpp index 09813e1df37cde7aae5dce9bf99025a7c0cf8aad..61829c36ffa897165ca65a1a7d003bb17aedec8f 100644 --- a/Framework/Algorithms/src/PDCalibration.cpp +++ b/Framework/Algorithms/src/PDCalibration.cpp @@ -29,10 +29,10 @@ #include "MantidKernel/ArrayProperty.h" #include "MantidKernel/BoundedValidator.h" #include "MantidKernel/CompositeValidator.h" -#include "MantidKernel/Diffraction.h" #include "MantidKernel/ListValidator.h" #include "MantidKernel/MandatoryValidator.h" #include "MantidKernel/RebinParamsValidator.h" +#include "MantidKernel/Unit.h" #include <algorithm> #include <cassert> @@ -120,11 +120,13 @@ public: * * @param peaksInD :: peak centers, in d-spacing * @param peaksInDWindows :: left and right fit ranges for each peak - * @param toTof :: function converting from d-spacing to TOF + * @param difa :: difa diffractometer constant (quadratic term) + * @param difc :: difc diffractometer constant (linear term) + * @param tzero :: tzero diffractometer constant (constant term) */ void setPositions(const std::vector<double> &peaksInD, const std::vector<double> &peaksInDWindows, - const std::function<double(double)> &toTof) { + const double difa, const double difc, const double tzero) { // clear out old values inDPos.clear(); inTofPos.clear(); @@ -136,9 +138,16 @@ public: inTofWindows.assign(peaksInDWindows.begin(), peaksInDWindows.end()); // convert the bits that matter to TOF - std::transform(inTofPos.begin(), inTofPos.end(), inTofPos.begin(), toTof); - std::transform(inTofWindows.begin(), inTofWindows.end(), - inTofWindows.begin(), toTof); + Kernel::Units::dSpacing dSpacingUnit; + std::vector<double> yunused; + dSpacingUnit.toTOF(inTofPos, yunused, -1, 0, + {{Kernel::UnitParams::difa, difa}, + {Kernel::UnitParams::difc, difc}, + {Kernel::UnitParams::tzero, tzero}}); + dSpacingUnit.toTOF(inTofWindows, yunused, -1, 0, + {{Kernel::UnitParams::difa, difa}, + {Kernel::UnitParams::difc, difc}, + {Kernel::UnitParams::tzero, tzero}}); } std::size_t wkspIndex; @@ -581,8 +590,10 @@ void PDCalibration::exec() { // object to hold the information about the peak positions, detid, and wksp // index PDCalibration::FittedPeaks peaks(m_uncalibratedWS, wkspIndex); - auto toTof = getDSpacingToTof(peaks.detid); - peaks.setPositions(m_peaksInDspacing, windowsInDSpacing, toTof); + auto [difc, difa, tzero] = getDSpacingToTof( + peaks.detid); // doesn't matter which one - all have same difc etc. + peaks.setPositions(m_peaksInDspacing, windowsInDSpacing, difa, difc, + tzero); // includes peaks that aren't used in the fit // The following data structures will hold information for the peaks @@ -690,15 +701,18 @@ void PDCalibration::exec() { // and the peak positions using the GSAS formula with optimized difc, // difa, and tzero double chisq = 0.; - // `converter` if a function that returns a d-spacing for an input TOF - auto converter = - Kernel::Diffraction::getTofToDConversionFunc(difc, difa, t0); + Mantid::Kernel::Units::dSpacing dSpacingUnit; + dSpacingUnit.initialize( + -1., 0, + Kernel::UnitParametersMap{{Kernel::UnitParams::difa, difa}, + {Kernel::UnitParams::difc, difc}, + {Kernel::UnitParams::tzero, t0}}); for (std::size_t i = 0; i < numPeaks; ++i) { if (std::isnan(tof_vec_full[i])) continue; // Find d-spacing using the GSAS formula with optimized difc, difa, // t0 for the TOF of the current peak's center. - const double dspacing = converter(tof_vec_full[i]); + const double dspacing = dSpacingUnit.singleFromTOF(tof_vec_full[i]); // `temp` is residual between the nominal position in d-spacing for // the current peak, and the fitted position in d-spacing const double temp = m_peaksInDspacing[i] - dspacing; @@ -706,7 +720,7 @@ void PDCalibration::exec() { m_peakPositionTable->cell<double>(rowIndexOutputPeaks, i + 1) = dspacing; m_peakWidthTable->cell<double>(rowIndexOutputPeaks, i + 1) = - WIDTH_TO_FWHM * converter(width_vec_full[i]); + WIDTH_TO_FWHM * dSpacingUnit.singleFromTOF(width_vec_full[i]); m_peakHeightTable->cell<double>(rowIndexOutputPeaks, i + 1) = height_vec_full[i]; } @@ -804,13 +818,17 @@ double gsl_costFunction(const gsl_vector *v, void *peaks) { if (numParams > 2) difa = gsl_vector_get(v, 2); } - auto converter = - Kernel::Diffraction::getDToTofConversionFunc(difc, difa, tzero); + Mantid::Kernel::Units::dSpacing dSpacingUnit; + dSpacingUnit.initialize( + -1., 0, + Kernel::UnitParametersMap{{Kernel::UnitParams::difa, difa}, + {Kernel::UnitParams::difc, difc}, + {Kernel::UnitParams::tzero, tzero}}); // calculate the sum of the residuals from observed peaks double errsum = 0.0; for (size_t i = 0; i < numPeaks; ++i) { - const double tofCalib = converter(dspace[i]); + const double tofCalib = dSpacingUnit.singleToTOF(dspace[i]); const double errsum_i = std::fabs(tofObs[i] - tofCalib) * weights[i]; errsum += errsum_i; } @@ -1056,9 +1074,8 @@ PDCalibration::dSpacingWindows(const std::vector<double> ¢res, * * @param detIds :: set of detector IDs */ -std::function<double(double)> +std::tuple<double, double, double> PDCalibration::getDSpacingToTof(const std::set<detid_t> &detIds) { - // to start this is the old calibration values double difc = 0.; double difa = 0.; @@ -1076,7 +1093,7 @@ PDCalibration::getDSpacingToTof(const std::set<detid_t> &detIds) { tzero = norm * tzero; } - return Kernel::Diffraction::getDToTofConversionFunc(difc, difa, tzero); + return {difc, difa, tzero}; } void PDCalibration::setCalibrationValues(const detid_t detid, const double difc, @@ -1111,8 +1128,9 @@ vector<double> PDCalibration::getTOFminmax(const double difc, const double difa, const double tzero) { vector<double> tofminmax(2); - tofminmax[0] = Kernel::Diffraction::calcTofMin(difc, difa, tzero, m_tofMin); - tofminmax[1] = Kernel::Diffraction::calcTofMax(difc, difa, tzero, m_tofMax); + Kernel::Units::dSpacing dSpacingUnit; + tofminmax[0] = dSpacingUnit.calcTofMin(difc, difa, tzero, m_tofMin); + tofminmax[1] = dSpacingUnit.calcTofMax(difc, difa, tzero, m_tofMax); return tofminmax; } @@ -1433,9 +1451,9 @@ PDCalibration::createTOFPeakCenterFitWindowWorkspaces( PDCalibration::FittedPeaks peaks(dataws, static_cast<size_t>(iws)); // toTof is a function that converts from d-spacing to TOF for a particular // pixel - auto toTof = getDSpacingToTof(peaks.detid); + auto [difc, difa, tzero] = getDSpacingToTof(peaks.detid); // setpositions initializes peaks.inTofPos and peaks.inTofWindows - peaks.setPositions(m_peaksInDspacing, windowsInDSpacing, toTof); + peaks.setPositions(m_peaksInDspacing, windowsInDSpacing, difa, difc, tzero); peak_pos_ws->setPoints(iws, peaks.inTofPos); peak_window_ws->setPoints(iws, peaks.inTofWindows); prog.report(); diff --git a/Framework/Algorithms/src/RemoveBackground.cpp b/Framework/Algorithms/src/RemoveBackground.cpp index 2bda22e3fd52666972c504dfc20f01c0cea27587..f8e6c5268b7e64a2931efb4e7212d9b31d992c08 100644 --- a/Framework/Algorithms/src/RemoveBackground.cpp +++ b/Framework/Algorithms/src/RemoveBackground.cpp @@ -106,9 +106,8 @@ void RemoveBackground::exec() { "workspace"); } - int eMode; // in convert units emode is still integer const std::string emodeStr = getProperty("EMode"); - eMode = static_cast<int>(Kernel::DeltaEMode::fromString(emodeStr)); + auto eMode = Kernel::DeltaEMode::fromString(emodeStr); // Removing background in-place bool inPlace = (inputWS == outputWS); @@ -155,7 +154,7 @@ void RemoveBackground::exec() { BackgroundHelper::BackgroundHelper() : m_WSUnit(), m_bgWs(), m_wkWS(), m_spectrumInfo(nullptr), m_pgLog(nullptr), m_inPlace(true), m_singleValueBackground(false), m_NBg(0), m_dtBg(1), - m_ErrSq(0), m_Emode(0), m_Efix(0), m_nullifyNegative(false), + m_ErrSq(0), m_Emode(DeltaEMode::Elastic), m_nullifyNegative(false), m_previouslyRemovedBkgMode(false) {} /** Initialization method: @@ -172,7 +171,8 @@ or target workspace has to be cloned. */ void BackgroundHelper::initialize(const API::MatrixWorkspace_const_sptr &bkgWS, const API::MatrixWorkspace_sptr &sourceWS, - int emode, Kernel::Logger *pLog, int nThreads, + Kernel::DeltaEMode::Type emode, + Kernel::Logger *pLog, int nThreads, bool inPlace, bool nullifyNegative) { m_bgWs = bkgWS; m_wkWS = sourceWS; @@ -224,8 +224,6 @@ void BackgroundHelper::initialize(const API::MatrixWorkspace_const_sptr &bkgWS, if (m_NBg < 1.e-7 && m_ErrSq < 1.e-7) m_previouslyRemovedBkgMode = true; } - - m_Efix = this->getEi(sourceWS); } /**Method removes background from vectors which represent a histogram data for a * single spectra @@ -257,10 +255,8 @@ void BackgroundHelper::removeBackground(int nHist, HistogramX &x_data, } try { - double twoTheta = m_spectrumInfo->twoTheta(nHist); double L1 = m_spectrumInfo->l1(); - double L2 = m_spectrumInfo->l2(nHist); - double delta(std::numeric_limits<double>::quiet_NaN()); + // get access to source workspace in case if target is different from source auto &XValues = m_wkWS->x(nHist); auto &YValues = m_wkWS->y(nHist); @@ -268,7 +264,10 @@ void BackgroundHelper::removeBackground(int nHist, HistogramX &x_data, // use thread-specific unit conversion class to avoid multithreading issues Kernel::Unit *unitConv = m_WSUnit[threadNum].get(); - unitConv->initialize(L1, L2, twoTheta, m_Emode, m_Efix, delta); + Kernel::UnitParametersMap pmap{}; + m_spectrumInfo->getDetectorValues(*unitConv, Kernel::Units::TOF{}, m_Emode, + false, nHist, pmap); + unitConv->initialize(L1, m_Emode, pmap); x_data[0] = XValues[0]; double tof1 = unitConv->singleToTOF(x_data[0]); @@ -315,46 +314,6 @@ void BackgroundHelper::removeBackground(int nHist, HistogramX &x_data, << nHist; } } -/** Method returns the efixed or Ei value stored in properties of the input - *workspace. - * Indirect instruments can have eFxed and Direct instruments can have Ei - *defined as the properties of the workspace. - * - * This method provide guess for efixed for all other kind of instruments. - *Correct indirect instrument will overwrite - * this value while wrongly defined or different types of instruments will - *provide the value of "Ei" property (log value) - * or undefined if "Ei" property is not found. - * - */ -double -BackgroundHelper::getEi(const API::MatrixWorkspace_const_sptr &inputWS) const { - double Efi = std::numeric_limits<double>::quiet_NaN(); - - // is Ei on workspace properties? (it can be defined for some reason if - // detectors do not have one, and then it would exist as Ei) - bool EiFound(false); - try { - Efi = inputWS->run().getPropertyValueAsType<double>("Ei"); - EiFound = true; - } catch (Kernel::Exception::NotFoundError &) { - } - // try to get Efixed as property on a workspace, obtained for indirect - // instrument - // bool eFixedFound(false); - if (!EiFound) { - try { - Efi = inputWS->run().getPropertyValueAsType<double>("eFixed"); - // eFixedFound = true; - } catch (Kernel::Exception::NotFoundError &) { - } - } - - // if (!(EiFound||eFixedFound)) - // g_log.debug()<<" Ei/eFixed requested but have not been found\n"; - - return Efi; -} } // namespace Algorithms } // namespace Mantid diff --git a/Framework/Algorithms/src/RemoveBins.cpp b/Framework/Algorithms/src/RemoveBins.cpp index 1024f935fe3ade67750e3642ea2a1cc9a942481c..c27b740c4d319ae078b4d86cf9e9908eab298100 100644 --- a/Framework/Algorithms/src/RemoveBins.cpp +++ b/Framework/Algorithms/src/RemoveBins.cpp @@ -268,16 +268,36 @@ void RemoveBins::transformRangeUnit(const int index, double &startX, startX = factor * std::pow(m_startX, power); endX = factor * std::pow(m_endX, power); } else { - double l1, l2, theta; - this->calculateDetectorPosition(index, l1, l2, theta); + double l1 = m_spectrumInfo->l1(); + + Kernel::UnitParametersMap pmap{}; + m_spectrumInfo->getDetectorValues(*m_rangeUnit, *inputUnit, + Kernel::DeltaEMode::Elastic, false, index, + pmap); + double l2 = 0.; + if (pmap.find(UnitParams::l2) != pmap.end()) { + l2 = pmap[UnitParams::l2]; + } + double theta = 0.; + if (pmap.find(UnitParams::twoTheta) != pmap.end()) { + l2 = pmap[UnitParams::twoTheta]; + } + g_log.debug() << "Detector for index " << index << " has L1+L2=" << l1 + l2 + << " & 2theta= " << theta << '\n'; std::vector<double> endPoints; endPoints.emplace_back(startX); endPoints.emplace_back(endX); - std::vector<double> emptyVec; - m_rangeUnit->toTOF(endPoints, emptyVec, l1, l2, theta, 0, 0.0, 0.0); - inputUnit->fromTOF(endPoints, emptyVec, l1, l2, theta, 0, 0.0, 0.0); - startX = endPoints.front(); - endX = endPoints.back(); + try { + std::vector<double> emptyVec; + // assume elastic + m_rangeUnit->toTOF(endPoints, emptyVec, l1, 0, pmap); + inputUnit->fromTOF(endPoints, emptyVec, l1, 0, pmap); + startX = endPoints.front(); + endX = endPoints.back(); + } catch (std::exception &) { + throw std::runtime_error("Unable to retrieve detector properties " + "required for unit conversion"); + } } if (startX > endX) { @@ -290,25 +310,6 @@ void RemoveBins::transformRangeUnit(const int index, double &startX, << startX << "-" << endX << " in workspace's unit\n"; } -/** Retrieves the detector postion for a given spectrum - * @param index :: The workspace index of the spectrum - * @param l1 :: Returns the source-sample distance - * @param l2 :: Returns the sample-detector distance - * @param twoTheta :: Returns the detector's scattering angle - */ -void RemoveBins::calculateDetectorPosition(const int index, double &l1, - double &l2, double &twoTheta) { - l1 = m_spectrumInfo->l1(); - l2 = m_spectrumInfo->l2(index); - if (m_spectrumInfo->isMonitor(index)) - twoTheta = 0.0; - else - twoTheta = m_spectrumInfo->twoTheta(index); - - g_log.debug() << "Detector for index " << index << " has L1+L2=" << l1 + l2 - << " & 2theta= " << twoTheta << '\n'; -} - /** Finds the index in an ordered vector which follows the given value * @param value :: The value to search for * @param vec :: The vector to search diff --git a/Framework/Algorithms/src/RemoveLowResTOF.cpp b/Framework/Algorithms/src/RemoveLowResTOF.cpp index e829ec0fbe4b4f2f7050f77dab66506c5b86227c..50a2e71bc50c5dafbc75a890a3edb752523d9e09 100644 --- a/Framework/Algorithms/src/RemoveLowResTOF.cpp +++ b/Framework/Algorithms/src/RemoveLowResTOF.cpp @@ -246,17 +246,9 @@ double RemoveLowResTOF::calcTofMin(const std::size_t workspaceIndex, const double l1 = spectrumInfo.l1(); - // Get a vector of detector IDs - std::vector<detid_t> detNumbers; - const auto &detSet = m_inputWS->getSpectrum(workspaceIndex).getDetectorIDs(); - detNumbers.assign(detSet.begin(), detSet.end()); - double tmin = 0.; if (isEmpty(m_wavelengthMin)) { - std::map<detid_t, double> offsets; // just an empty offsets map - double dspmap = Conversion::tofToDSpacingFactor( - l1, spectrumInfo.l2(workspaceIndex), - spectrumInfo.twoTheta(workspaceIndex), detNumbers, offsets); + double dspmap = 1. / spectrumInfo.difcUncalibrated(workspaceIndex); // this is related to the reference tof double sqrtdmin = @@ -274,7 +266,7 @@ double RemoveLowResTOF::calcTofMin(const std::size_t workspaceIndex, // unfortunately there isn't a good way to convert a single value std::vector<double> X(1), temp(1); X[0] = m_wavelengthMin; - wavelength->toTOF(X, temp, l1, l2, 0., 0, 0., 0.); + wavelength->toTOF(X, temp, l1, 0, {{UnitParams::l2, l2}}); tmin = X[0]; } diff --git a/Framework/Algorithms/test/ConvertSpectrumAxisTest.h b/Framework/Algorithms/test/ConvertSpectrumAxisTest.h index fcab91851b1cd6322fa37ee7400e873442b0c2f6..c6d9e4adffe41aa3befdbc1cef83233d619dcea8 100644 --- a/Framework/Algorithms/test/ConvertSpectrumAxisTest.h +++ b/Framework/Algorithms/test/ConvertSpectrumAxisTest.h @@ -142,7 +142,7 @@ public: TS_ASSERT_THROWS_NOTHING(conv.setPropertyValue("Target", "DeltaE")); TS_ASSERT_THROWS_NOTHING(conv.setPropertyValue("EMode", "Indirect")); conv.setRethrows(true); - TS_ASSERT_THROWS(conv.execute(), const std::logic_error &); + TS_ASSERT_THROWS(conv.execute(), const std::runtime_error &); TS_ASSERT_THROWS_NOTHING(conv.setPropertyValue("Efixed", "1.845")); TS_ASSERT_THROWS_NOTHING(conv.execute()); diff --git a/Framework/Algorithms/test/ConvertUnitsTest.h b/Framework/Algorithms/test/ConvertUnitsTest.h index 43d01300fddd4c214419e9ccce2b587076b4d866..c3d4574daedf96ee859af1a1796fd02c019adb53 100644 --- a/Framework/Algorithms/test/ConvertUnitsTest.h +++ b/Framework/Algorithms/test/ConvertUnitsTest.h @@ -13,6 +13,7 @@ #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/Axis.h" #include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAlgorithms/ConvertToDistribution.h" #include "MantidAlgorithms/ConvertUnits.h" #include "MantidDataHandling/LoadInstrument.h" @@ -674,7 +675,11 @@ public: outputSpace)); TS_ASSERT_EQUALS(output->getAxis(0)->unit()->unitID(), "MomentumTransfer"); TS_ASSERT_EQUALS(Mantid::Kernel::DeltaEMode::Direct, output->getEMode()); - TS_ASSERT(std::isnan(output->x(0)[0])); + + // conversion fails due to error in two theta calculation and leaves + // spectrum masked and zeroed + TS_ASSERT_EQUALS(output->y(0)[0], 0); + TS_ASSERT(output->spectrumInfo().isMasked(0)); } void setup_Event() { @@ -762,6 +767,13 @@ public: ws->getAxis(0)->setUnit("TOF"); ws->sortAll(sortType, nullptr); + // 0th detector unfortunately has difc=0 which doesn't support conversion to + // d spacing so give it a more helpful difc value + auto instrument = ws->getInstrument(); + auto det = instrument->getDetector(100); + auto ¶mMap = ws->instrumentParameters(); + paramMap.addDouble(det->getComponentID(), "DIFC", 1000); + if (sortType == TOF_SORT) { // Only threadsafe if all the event lists are sorted TS_ASSERT(ws->threadSafe()); diff --git a/Framework/Algorithms/test/CreateDetectorTableTest.h b/Framework/Algorithms/test/CreateDetectorTableTest.h index 4a29716697918406535cc650580481f477abcdb4..66cf1963246414d8f299e2b8c2c31d8742e6f393 100644 --- a/Framework/Algorithms/test/CreateDetectorTableTest.h +++ b/Framework/Algorithms/test/CreateDetectorTableTest.h @@ -82,7 +82,7 @@ public: } // Check the results - TS_ASSERT_EQUALS(ws->columnCount(), 7); + TS_ASSERT_EQUALS(ws->columnCount(), 11); TS_ASSERT_EQUALS(ws->rowCount(), 2); // Remove workspace from the data service. @@ -117,7 +117,7 @@ public: } // Check the results - TS_ASSERT_EQUALS(ws->columnCount(), 9); + TS_ASSERT_EQUALS(ws->columnCount(), 13); TS_ASSERT_EQUALS(ws->rowCount(), 1); // Remove workspace from the data service. diff --git a/Framework/Algorithms/test/PDCalibrationTest.h b/Framework/Algorithms/test/PDCalibrationTest.h index 3fdd6915205d138fb527b5fd20e1b3492fdb8047..6ca3bad06bd963e3284630e2d15b976875474b4e 100644 --- a/Framework/Algorithms/test/PDCalibrationTest.h +++ b/Framework/Algorithms/test/PDCalibrationTest.h @@ -21,7 +21,7 @@ #include "MantidDataHandling/MoveInstrumentComponent.h" #include "MantidDataHandling/RotateInstrumentComponent.h" #include "MantidDataObjects/TableColumn.h" -#include "MantidKernel/Diffraction.h" +#include "MantidKernel/Unit.h" using Mantid::Algorithms::ConvertToMatrixWorkspace; using Mantid::Algorithms::CreateSampleWorkspace; @@ -161,10 +161,13 @@ public: void test_exec_difc() { // setup the peak postions based on transformation from detID=155 - std::vector<double> dValues(PEAK_TOFS.size()); - std::transform( - PEAK_TOFS.begin(), PEAK_TOFS.end(), dValues.begin(), - Mantid::Kernel::Diffraction::getTofToDConversionFunc(DIFC_155, 0., 0.)); + using Mantid::Kernel::UnitParams; + std::vector<double> dValues(PEAK_TOFS); + Mantid::Kernel::Units::dSpacing dSpacingUnit; + std::vector<double> unusedy; + dSpacingUnit.fromTOF( + dValues, unusedy, -1., 0, + Mantid::Kernel::UnitParametersMap{{UnitParams::difc, DIFC_155}}); const std::string prefix{"PDCalibration_difc"}; @@ -219,12 +222,16 @@ public: } void test_exec_difc_tzero() { + using Mantid::Kernel::UnitParams; // setup the peak postions based on transformation from detID=155 const double TZERO = 20.; - std::vector<double> dValues(PEAK_TOFS.size()); - std::transform(PEAK_TOFS.begin(), PEAK_TOFS.end(), dValues.begin(), - Mantid::Kernel::Diffraction::getTofToDConversionFunc( - DIFC_155, 0., TZERO)); + std::vector<double> dValues(PEAK_TOFS); + Mantid::Kernel::Units::dSpacing dSpacingUnit; + std::vector<double> unusedy; + dSpacingUnit.fromTOF( + dValues, unusedy, -1., 0, + Mantid::Kernel::UnitParametersMap{{UnitParams::difc, DIFC_155}, + {UnitParams::tzero, TZERO}}); const std::string prefix{"PDCalibration_difc_tzero"}; @@ -282,13 +289,17 @@ public: } void test_exec_difc_tzero_difa() { + using Mantid::Kernel::UnitParams; // setup the peak postions based on transformation from detID=155 // allow refining DIFA, but don't set the transformation to require it const double TZERO = 20.; - std::vector<double> dValues(PEAK_TOFS.size()); - std::transform(PEAK_TOFS.begin(), PEAK_TOFS.end(), dValues.begin(), - Mantid::Kernel::Diffraction::getTofToDConversionFunc( - DIFC_155, 0., TZERO)); + std::vector<double> dValues(PEAK_TOFS); + Mantid::Kernel::Units::dSpacing dSpacingUnit; + std::vector<double> unusedy; + dSpacingUnit.fromTOF( + dValues, unusedy, -1., 0, + Mantid::Kernel::UnitParametersMap{{UnitParams::difc, DIFC_155}, + {UnitParams::tzero, TZERO}}); const std::string prefix{"PDCalibration_difc_tzero_difa"}; @@ -348,6 +359,7 @@ public: // Crop workspace so that final peak is evaluated over a range that includes // the last bin (stop regression out of range bug for histo workspaces) void test_exec_difc_histo() { + using Mantid::Kernel::UnitParams; // convert to histo ConvertToMatrixWorkspace convMatWS; convMatWS.initialize(); @@ -365,10 +377,13 @@ public: cropWS.execute(); // setup the peak postions based on transformation from detID=155 - std::vector<double> dValues(PEAK_TOFS.size()); - std::transform( - PEAK_TOFS.begin(), PEAK_TOFS.end(), dValues.begin(), - Mantid::Kernel::Diffraction::getTofToDConversionFunc(DIFC_155, 0., 0.)); + std::vector<double> dValues(PEAK_TOFS); + + Mantid::Kernel::Units::dSpacing dSpacingUnit; + std::vector<double> unusedy; + dSpacingUnit.fromTOF( + dValues, unusedy, -1., 0, + Mantid::Kernel::UnitParametersMap{{UnitParams::difc, DIFC_155}}); const std::string prefix{"PDCalibration_difc"}; @@ -414,13 +429,16 @@ public: } void test_exec_fit_diff_constants_with_chisq() { + using Mantid::Kernel::UnitParams; // setup the peak postions based on transformation from detID=155 // allow refining DIFA, but don't set the transformation to require it // setup the peak postions based on transformation from detID=155 - std::vector<double> dValues(PEAK_TOFS.size()); - std::transform( - PEAK_TOFS.begin(), PEAK_TOFS.end(), dValues.begin(), - Mantid::Kernel::Diffraction::getTofToDConversionFunc(DIFC_155, 0., 0.)); + std::vector<double> dValues(PEAK_TOFS); + Mantid::Kernel::Units::dSpacing dSpacingUnit; + std::vector<double> unusedy; + dSpacingUnit.fromTOF( + dValues, unusedy, -1., 0, + Mantid::Kernel::UnitParametersMap{{UnitParams::difc, DIFC_155}}); const std::string prefix{"PDCalibration_difc"}; @@ -468,6 +486,7 @@ public: } void test_exec_grouped_detectors() { + using Mantid::Kernel::UnitParams; // group detectors GroupDetectors2 groupDet; groupDet.initialize(); @@ -477,10 +496,12 @@ public: groupDet.execute(); // setup the peak postions based on transformation from detID=155 - std::vector<double> dValues(PEAK_TOFS.size()); - std::transform( - PEAK_TOFS.begin(), PEAK_TOFS.end(), dValues.begin(), - Mantid::Kernel::Diffraction::getTofToDConversionFunc(DIFC_155, 0., 0.)); + std::vector<double> dValues(PEAK_TOFS); + Mantid::Kernel::Units::dSpacing dSpacingUnit; + std::vector<double> unusedy; + dSpacingUnit.fromTOF( + dValues, unusedy, -1., 0, + Mantid::Kernel::UnitParametersMap{{UnitParams::difc, DIFC_155}}); const std::string prefix{"PDCalibration_difc"}; @@ -532,11 +553,14 @@ public: PDCalibrationTestPerformance() { FrameworkManager::Instance(); } void setUp() override { + using Mantid::Kernel::UnitParams; // setup the peak postions based on transformation from detID=155 std::vector<double> dValues(PEAK_TOFS.size()); - std::transform( - PEAK_TOFS.begin(), PEAK_TOFS.end(), dValues.begin(), - Mantid::Kernel::Diffraction::getTofToDConversionFunc(DIFC_155, 0., 0.)); + Mantid::Kernel::Units::dSpacing dSpacingUnit; + std::vector<double> unusedy; + dSpacingUnit.fromTOF( + dValues, unusedy, -1., 0, + Mantid::Kernel::UnitParametersMap{{UnitParams::difc, DIFC_155}}); createSampleWS(); pdc.initialize(); pdc.setProperty("InputWorkspace", "PDCalibrationTest_WS"); diff --git a/Framework/Algorithms/test/RemoveBackgroundTest.h b/Framework/Algorithms/test/RemoveBackgroundTest.h index a1f956fb63d79c7295a363f713d66e87f7f6a46a..de315e85e9bcba1912955871abee4169ff5f6c77 100644 --- a/Framework/Algorithms/test/RemoveBackgroundTest.h +++ b/Framework/Algorithms/test/RemoveBackgroundTest.h @@ -95,13 +95,14 @@ public: std::vector<double>(1, 10.)); TSM_ASSERT_THROWS( "Should throw if background workspace is not in TOF units", - bgRemoval.initialize(bkgWS, SourceWS, 0), + bgRemoval.initialize(bkgWS, SourceWS, Kernel::DeltaEMode::Elastic), const std::invalid_argument &); bkgWS = WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument(2, 15); - TSM_ASSERT_THROWS("Should throw if background is not 1 or equal to source", - bgRemoval.initialize(bkgWS, SourceWS, 0), - const std::invalid_argument &); + TSM_ASSERT_THROWS( + "Should throw if background is not 1 or equal to source", + bgRemoval.initialize(bkgWS, SourceWS, Kernel::DeltaEMode::Elastic), + const std::invalid_argument &); } void testBackgroundHelper() { @@ -110,7 +111,7 @@ public: API::AnalysisDataService::Instance().addOrReplace("TestWS", clone); - int emode = static_cast<int>(Kernel::DeltaEMode().fromString("Direct")); + auto emode = Kernel::DeltaEMode().fromString("Direct"); bgRemoval.initialize(BgWS, SourceWS, emode); auto &dataX = clone->mutableX(0); diff --git a/Framework/Algorithms/test/RemoveSpectraTest.h b/Framework/Algorithms/test/RemoveSpectraTest.h index dd158032d81b0124329189a56e102e775e786756..33ddd35a7e81f8beab5b13c7b6aed754fb053fe2 100644 --- a/Framework/Algorithms/test/RemoveSpectraTest.h +++ b/Framework/Algorithms/test/RemoveSpectraTest.h @@ -11,6 +11,7 @@ #include "MantidAPI/AlgorithmManager.h" #include "MantidAPI/AnalysisDataService.h" #include "MantidAPI/MatrixWorkspace.h" +#include "MantidAPI/SpectrumInfo.h" #include "MantidAPI/WorkspaceFactory.h" #include "MantidAlgorithms/RemoveSpectra.h" #include "MantidHistogramData/LinearGenerator.h" @@ -89,6 +90,7 @@ public: AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(wsName); TS_ASSERT_EQUALS(inputWS->x(94).front(), 19900.0); TS_ASSERT_EQUALS(inputWS->x(144).front(), 19900.0); + TS_ASSERT(!inputWS->spectrumInfo().hasDetectors(144)); RemoveSpectra alg; alg.initialize(); @@ -102,13 +104,13 @@ public: MatrixWorkspace_sptr outputWS = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( ouputWsName); - // Removed specs are workspace indices 140 and 144/specNum 141 and 145 + // Removed specs are workspace indices 94 and 144/specNum 95 and 145 TS_ASSERT_EQUALS(outputWS->getNumberHistograms(), 147); TS_ASSERT_DELTA(outputWS->x(93).front(), 0.41157, 0.0001); // was 93 TS_ASSERT_DELTA(outputWS->x(94).front(), 0.05484, 0.0001); // was 95 TS_ASSERT_DELTA(outputWS->x(95).front(), -0.15111, 0.0001); // was 96 - TS_ASSERT_DIFFERS(outputWS->x(143).front(), - 19900.0); // Would be 144 if 94 wasn't also removed + TS_ASSERT(outputWS->spectrumInfo().hasDetectors( + 143)); // Would be 144 if 144 wasn't also removed } private: diff --git a/Framework/Crystal/src/AnvredCorrection.cpp b/Framework/Crystal/src/AnvredCorrection.cpp index 614c2ca3904f43f4969a08208f7bda7563f05ad8..f2b7cb13e805b56ffb8065629973429191c9953e 100644 --- a/Framework/Crystal/src/AnvredCorrection.cpp +++ b/Framework/Crystal/src/AnvredCorrection.cpp @@ -179,12 +179,14 @@ void AnvredCorrection::exec() { if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i)) continue; - // This is the scattered beam direction Instrument_const_sptr inst = m_inputWS->getInstrument(); - double L2 = spectrumInfo.l2(i); - // Two-theta = polar angle = scattering angle = between +Z vector and the - // scattered beam - double scattering = spectrumInfo.twoTheta(i); + UnitParametersMap pmap{}; + Mantid::Kernel::Units::Wavelength wl; + Mantid::Kernel::Units::TOF tof; + spectrumInfo.getDetectorValues(tof, wl, Kernel::DeltaEMode::Elastic, false, + i, pmap); + double L2 = pmap.at(UnitParams::l2); + double scattering = pmap.at(UnitParams::twoTheta); double depth = 0.2; @@ -196,7 +198,6 @@ void AnvredCorrection::exec() { if (m_useScaleFactors) scale_init(det, inst, L2, depth, pathlength, bankName); - Mantid::Kernel::Units::Wavelength wl; auto points = m_inputWS->points(i); // share bin boundaries @@ -213,10 +214,9 @@ void AnvredCorrection::exec() { // Loop through the bins in the current spectrum for (int64_t j = 0; j < specSize; j++) { - double lambda = - (unitStr == "TOF") - ? wl.convertSingleFromTOF(points[j], L1, L2, scattering, 0, 0, 0) - : points[j]; + double lambda = (unitStr == "TOF") + ? wl.convertSingleFromTOF(points[j], L1, 0, pmap) + : points[j]; if (m_returnTransmissionOnly) { Y[j] = 1.0 / this->getEventWeight(lambda, scattering); @@ -280,18 +280,18 @@ void AnvredCorrection::execEvent() { if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i)) continue; - // This is the scattered beam direction - double L2 = spectrumInfo.l2(i); - // Two-theta = polar angle = scattering angle = between +Z vector and the - // scattered beam - double scattering = spectrumInfo.twoTheta(i); + UnitParametersMap pmap{}; + Mantid::Kernel::Units::Wavelength wl; + Mantid::Kernel::Units::TOF tof; + spectrumInfo.getDetectorValues(tof, wl, Kernel::DeltaEMode::Elastic, false, + i, pmap); + double L2 = pmap.at(UnitParams::l2); + double scattering = pmap.at(UnitParams::twoTheta); EventList el = eventW->getSpectrum(i); el.switchTo(WEIGHTED_NOTIME); std::vector<WeightedEventNoTime> events = el.getWeightedEventsNoTime(); - Mantid::Kernel::Units::Wavelength wl; - double depth = 0.2; double pathlength = 0.0; std::string bankName; @@ -306,7 +306,7 @@ void AnvredCorrection::execEvent() { double lambda = ev.tof(); if ("TOF" == unitStr) - lambda = wl.convertSingleFromTOF(lambda, L1, L2, scattering, 0, 0, 0); + lambda = wl.convertSingleFromTOF(lambda, L1, 0, pmap); double value = this->getEventWeight(lambda, scattering); diff --git a/Framework/Crystal/src/CentroidPeaks.cpp b/Framework/Crystal/src/CentroidPeaks.cpp index 0625243a671c72a6358b47cf53edc572fce943cc..85d239310be23896a62da0c851fa52ab35b01a44 100644 --- a/Framework/Crystal/src/CentroidPeaks.cpp +++ b/Framework/Crystal/src/CentroidPeaks.cpp @@ -168,7 +168,8 @@ void CentroidPeaks::integrate() { double scattering = peak.getScattering(); double L1 = peak.getL1(); double L2 = peak.getL2(); - wl.fromTOF(timeflight, timeflight, L1, L2, scattering, 0, 0, 0); + wl.fromTOF(timeflight, timeflight, L1, 0, + {{UnitParams::l2, L2}, {UnitParams::twoTheta, scattering}}); const double lambda = timeflight[0]; timeflight.clear(); @@ -289,7 +290,8 @@ void CentroidPeaks::integrateEvent() { double scattering = peak.getScattering(); double L1 = peak.getL1(); double L2 = peak.getL2(); - wl.fromTOF(timeflight, timeflight, L1, L2, scattering, 0, 0, 0); + wl.fromTOF(timeflight, timeflight, L1, 0, + {{UnitParams::l2, L2}, {UnitParams::twoTheta, scattering}}); const double lambda = timeflight[0]; timeflight.clear(); diff --git a/Framework/Crystal/src/FindSXPeaksHelper.cpp b/Framework/Crystal/src/FindSXPeaksHelper.cpp index c36783614c4aea3d79324b8f9ae16dce75733388..729f5db9d39239624e1815e20c9ffdc35aae0b52 100644 --- a/Framework/Crystal/src/FindSXPeaksHelper.cpp +++ b/Framework/Crystal/src/FindSXPeaksHelper.cpp @@ -94,9 +94,17 @@ SXPeak::SXPeak(double t, double phi, double intensity, m_detId = spectrumInfo.detector(m_wsIndex).getID(); m_nPixels = 1; + Mantid::Kernel::Units::TOF tof; const auto unit = Mantid::Kernel::UnitFactory::Instance().create("dSpacing"); - unit->initialize(l1, l2, m_twoTheta, 0, 0, 0); - m_dSpacing = unit->singleFromTOF(m_tof); + Kernel::UnitParametersMap pmap{}; + spectrumInfo.getDetectorValues(tof, *unit, Kernel::DeltaEMode::Elastic, false, + m_wsIndex, pmap); + unit->initialize(l1, 0, pmap); + try { + m_dSpacing = unit->singleFromTOF(m_tof); + } catch (std::exception &) { + m_dSpacing = 0; + } const auto samplePos = spectrumInfo.samplePosition(); const auto sourcePos = spectrumInfo.sourcePosition(); @@ -365,9 +373,12 @@ double PeakFindingStrategy::convertToTOF(const double xValue, return xValue; } else { const auto unit = UnitFactory::Instance().create("dSpacing"); + Mantid::Kernel::Units::TOF tof; + Kernel::UnitParametersMap pmap{}; + m_spectrumInfo.getDetectorValues(*unit, tof, Kernel::DeltaEMode::Elastic, + false, workspaceIndex, pmap); // we're using d-spacing, convert the point to TOF - unit->initialize(m_spectrumInfo.l1(), m_spectrumInfo.l2(workspaceIndex), - m_spectrumInfo.twoTheta(workspaceIndex), 0, 0, 0); + unit->initialize(m_spectrumInfo.l1(), 0, pmap); return unit->singleToTOF(xValue); } } diff --git a/Framework/Crystal/src/LoadIsawPeaks.cpp b/Framework/Crystal/src/LoadIsawPeaks.cpp index 47bcd6780c3f014e13d9d2ed2e798ddbe244fe21..75d27e0deb8fb43ae54209b45bcd178779dbac40 100644 --- a/Framework/Crystal/src/LoadIsawPeaks.cpp +++ b/Framework/Crystal/src/LoadIsawPeaks.cpp @@ -525,8 +525,9 @@ void LoadIsawPeaks::appendFile(const PeaksWorkspace_sptr &outWS, double tof = peak.getTOF(); Kernel::Units::Wavelength wl; - wl.initialize(peak.getL1(), peak.getL2(), peak.getScattering(), 0, - peak.getInitialEnergy(), 0.0); + wl.initialize(peak.getL1(), 0, + {{UnitParams::l2, peak.getL2()}, + {UnitParams::twoTheta, peak.getScattering()}}); peak.setWavelength(wl.singleFromTOF(tof)); // Add the peak to workspace diff --git a/Framework/Crystal/src/LoadIsawSpectrum.cpp b/Framework/Crystal/src/LoadIsawSpectrum.cpp index 5c9b438d279353051a08789051159926b6614d66..03720f3dc4fa9ff58b2d689a71a1b89abaace71a 100644 --- a/Framework/Crystal/src/LoadIsawSpectrum.cpp +++ b/Framework/Crystal/src/LoadIsawSpectrum.cpp @@ -160,7 +160,11 @@ void LoadIsawSpectrum::exec() { Mantid::Kernel::Unit_sptr unit = UnitFactory::Instance().create("Wavelength"); - unit->toTOF(xdata, ydata, l1, l2, theta2, 0, 0.0, 0.0); + unit->toTOF(xdata, ydata, l1, 0, + { + {UnitParams::l2, l2}, + {UnitParams::twoTheta, theta2}, + }); double one = xdata[0]; double spect1 = spectrumCalc(one, iSpec, time, spectra, i); diff --git a/Framework/Crystal/src/NormaliseVanadium.cpp b/Framework/Crystal/src/NormaliseVanadium.cpp index 77871cba04ce1044b3292644a46abf8549b32b46..97ea0dcbbdb4d8d85a5347927f7e74152e8df287 100644 --- a/Framework/Crystal/src/NormaliseVanadium.cpp +++ b/Framework/Crystal/src/NormaliseVanadium.cpp @@ -86,17 +86,15 @@ void NormaliseVanadium::exec() { if (!spectrumInfo.hasDetectors(i)) continue; - // This is the scattered beam direction - double L2 = spectrumInfo.l2(i); - // Two-theta = polar angle = scattering angle = between +Z vector and the - // scattered beam - double scattering = spectrumInfo.twoTheta(i); - Mantid::Kernel::Units::Wavelength wl; + Mantid::Kernel::Units::TOF tof; + UnitParametersMap pmap{}; + spectrumInfo.getDetectorValues(tof, wl, Kernel::DeltaEMode::Elastic, false, + i, pmap); auto timeflight = inSpec.points(); if (unitStr == "TOF") wl.fromTOF(timeflight.mutableRawData(), timeflight.mutableRawData(), L1, - L2, scattering, 0, 0, 0); + 0, pmap); // Loop through the bins in the current spectrum double lambp = 0; diff --git a/Framework/Crystal/src/PeakHKLErrors.cpp b/Framework/Crystal/src/PeakHKLErrors.cpp index 374410e132f7f59b303002d722c577bbb88bbe2a..c65b2a42db0c34af26d839f5dd3c43a0997119fa 100644 --- a/Framework/Crystal/src/PeakHKLErrors.cpp +++ b/Framework/Crystal/src/PeakHKLErrors.cpp @@ -662,8 +662,10 @@ Peak PeakHKLErrors::createNewPeak(const DataObjects::Peak &peak_old, Wavelength wl; - wl.initialize(L0, peak.getL2(), peak.getScattering(), 0, - peak_old.getInitialEnergy(), 0.0); + wl.initialize(L0, 0, + {{UnitParams::l2, peak.getL2()}, + {UnitParams::twoTheta, peak.getScattering()}, + {UnitParams::efixed, peak_old.getInitialEnergy()}}); peak.setWavelength(wl.singleFromTOF(T)); peak.setIntensity(peak_old.getIntensity()); diff --git a/Framework/Crystal/src/SCDCalibratePanels.cpp b/Framework/Crystal/src/SCDCalibratePanels.cpp index 9762c35f20a2411d6443604b68aa2409f2d94fe8..a878f1a59d0998b17f922410897941665ab4613c 100644 --- a/Framework/Crystal/src/SCDCalibratePanels.cpp +++ b/Framework/Crystal/src/SCDCalibratePanels.cpp @@ -379,8 +379,9 @@ void SCDCalibratePanels::findT0( Units::Wavelength wl; - wl.initialize(peak.getL1(), peak.getL2(), peak.getScattering(), 0, - peak.getInitialEnergy(), 0.0); + wl.initialize(peak.getL1(), 0, + {{UnitParams::l2, peak.getL2()}, + {UnitParams::twoTheta, peak.getScattering()}}); peak.setWavelength(wl.singleFromTOF(peak.getTOF() + mT0)); } } diff --git a/Framework/Crystal/src/SCDCalibratePanels2.cpp b/Framework/Crystal/src/SCDCalibratePanels2.cpp index 71b39d29fa93b1f9cdbbeb42d0ef850ec0f66f53..e54bd2694719f49c2fa2cea9d3699d1b1ac56264 100644 --- a/Framework/Crystal/src/SCDCalibratePanels2.cpp +++ b/Framework/Crystal/src/SCDCalibratePanels2.cpp @@ -685,8 +685,10 @@ void SCDCalibratePanels2::adjustT0(double dT0, IPeaksWorkspace_sptr &pws) { for (int i = 0; i < pws->getNumberPeaks(); ++i) { IPeak &pk = pws->getPeak(i); Units::Wavelength wl; - wl.initialize(pk.getL1(), pk.getL2(), pk.getScattering(), 0, - pk.getInitialEnergy(), 0.0); + wl.initialize(pk.getL1(), 0, + {{UnitParams::l2, pk.getL2()}, + {UnitParams::twoTheta, pk.getScattering()}, + {UnitParams::efixed, pk.getInitialEnergy()}}); pk.setWavelength(wl.singleFromTOF(pk.getTOF() + dT0)); } } diff --git a/Framework/Crystal/src/SCDCalibratePanels2ObjFunc.cpp b/Framework/Crystal/src/SCDCalibratePanels2ObjFunc.cpp index 64c88ab9e87f734e8988da45e599809c525fcbbc..cba4f70f11e2cfd71a74b7fbc81485ab4743bfb4 100644 --- a/Framework/Crystal/src/SCDCalibratePanels2ObjFunc.cpp +++ b/Framework/Crystal/src/SCDCalibratePanels2ObjFunc.cpp @@ -137,8 +137,10 @@ void SCDCalibratePanels2ObjFunc::function1D(double *out, const double *xValues, pk.setDetectorID(pk.getDetectorID()); // calculate&set wavelength based on new instrument Units::Wavelength wl; - wl.initialize(pk.getL1(), pk.getL2(), pk.getScattering(), 0, - pk.getInitialEnergy(), 0.0); + wl.initialize(pk.getL1(), 0, + {{UnitParams::l2, pk.getL2()}, + {UnitParams::twoTheta, pk.getScattering()}, + {UnitParams::efixed, pk.getInitialEnergy()}}); pk.setWavelength(wl.singleFromTOF(tof)); V3D qv = pk.getQSampleFrame(); diff --git a/Framework/Crystal/src/SCDPanelErrors.cpp b/Framework/Crystal/src/SCDPanelErrors.cpp index 6dbd04977f117af09ae71df9bd3d88461943c0e9..5a303969a0d35da3aa12f728336e059501be1c7f 100644 --- a/Framework/Crystal/src/SCDPanelErrors.cpp +++ b/Framework/Crystal/src/SCDPanelErrors.cpp @@ -213,8 +213,9 @@ void SCDPanelErrors::eval(double xshift, double yshift, double zshift, hkl, peak.getGoniometerMatrix()); Units::Wavelength wl; - wl.initialize(peak2.getL1(), peak2.getL2(), peak2.getScattering(), 0, - peak2.getInitialEnergy(), 0.0); + wl.initialize(peak2.getL1(), 0, + {{UnitParams::l2, peak2.getL2()}, + {UnitParams::twoTheta, peak2.getScattering()}}); peak2.setWavelength(wl.singleFromTOF(peak.getTOF() + tShift)); V3D Q3 = peak2.getQSampleFrame(); out[i * 3] = Q3[0] - Q2[0]; diff --git a/Framework/Crystal/src/SaveHKL.cpp b/Framework/Crystal/src/SaveHKL.cpp index 179739523c40d13efa27bfccff96bd1556a82dc1..0e7fd62c1d82a556919013a8fa47211debc10a47 100644 --- a/Framework/Crystal/src/SaveHKL.cpp +++ b/Framework/Crystal/src/SaveHKL.cpp @@ -435,7 +435,8 @@ void SaveHKL::exec() { double l2 = p.getL2(); Mantid::Kernel::Unit_sptr unit = UnitFactory::Instance().create("Wavelength"); - unit->toTOF(xdata, ydata, l1, l2, theta2, 0, 0.0, 0.0); + unit->toTOF(xdata, ydata, l1, 0, + {{UnitParams::l2, l2}, {UnitParams::twoTheta, theta2}}); double one = xdata[0]; double spect1 = spectrumCalc(one, iSpec, time, spectra, bank); relSigSpect = std::sqrt((1.0 / spect) + (1.0 / spect1)); diff --git a/Framework/Crystal/test/FindSXPeaksHelperTest.h b/Framework/Crystal/test/FindSXPeaksHelperTest.h index 95070d6b9284ae8b18840842f66abdaca4590972..eb1144aca50fd44d82a3b31f89efd28bb06b97a8 100644 --- a/Framework/Crystal/test/FindSXPeaksHelperTest.h +++ b/Framework/Crystal/test/FindSXPeaksHelperTest.h @@ -140,13 +140,13 @@ public: auto backgroundStrategy = std::make_unique<AbsoluteBackgroundStrategy>(3.); auto workspace = WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument( - 1 /*nhist*/, 15 /*nbins*/); - auto &mutableY = workspace->mutableY(0); + 2 /*nhist*/, 15 /*nbins*/); + const int workspaceIndex = 1; + auto &mutableY = workspace->mutableY(workspaceIndex); doAddDoublePeakToData(mutableY); - const int workspaceIndex = 0; - const auto &x = workspace->x(0); - const auto &y = workspace->y(0); + const auto &x = workspace->x(workspaceIndex); + const auto &y = workspace->y(workspaceIndex); const auto &spectrumInfo = workspace->spectrumInfo(); // WHEN @@ -398,13 +398,13 @@ private: // GIVEN auto workspace = WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument( - 1 /*nhist*/, 15 /*nbins*/); - auto &mutableY = workspace->mutableY(0); + 2 /*nhist*/, 15 /*nbins*/); + const int workspaceIndex = 1; + auto &mutableY = workspace->mutableY(workspaceIndex); doAddDoublePeakToData(mutableY); - const int workspaceIndex = 0; - const auto &x = workspace->x(0); - const auto &y = workspace->y(0); + const auto &x = workspace->x(workspaceIndex); + const auto &y = workspace->y(workspaceIndex); const auto &spectrumInfo = workspace->spectrumInfo(); // WHEN diff --git a/Framework/Crystal/test/IntegratePeakTimeSlicesTest.h b/Framework/Crystal/test/IntegratePeakTimeSlicesTest.h index 239cd875bb4df32ed30ecc2a87eceda48adc8234..48f83a775038f1a280541460964fe1d27debb2e0 100644 --- a/Framework/Crystal/test/IntegratePeakTimeSlicesTest.h +++ b/Framework/Crystal/test/IntegratePeakTimeSlicesTest.h @@ -115,7 +115,9 @@ public: std::vector<double> x; x.emplace_back(PeakTime); - wl.fromTOF(x, x, L1, L2, ScatAng, 0, 0, 0); + wl.fromTOF(x, x, L1, 0, + {{Kernel::UnitParams::l2, L2}, + {Kernel::UnitParams::twoTheta, ScatAng}}); double wavelength = x[0]; Peak peak(instP, pixelp->getID(), wavelength); @@ -250,7 +252,9 @@ private: x.emplace_back(time); const auto ScatAng = detectorInfo.twoTheta(detInfoIndex) / 180 * M_PI; - Q.fromTOF(x, x, L1, L2, ScatAng, 0, 0, 0.0); + Q.fromTOF(x, x, L1, 0, + {{Kernel::UnitParams::l2, L2}, + {Kernel::UnitParams::twoTheta, ScatAng}}); return x[0] / 2 / M_PI; } diff --git a/Framework/Crystal/test/SCDCalibratePanels2Test.h b/Framework/Crystal/test/SCDCalibratePanels2Test.h index 3b8dbd3a2463ed8c318295dfef3a4ee62e8ae334..f5516fcfe30d21dc2c1f45f88156f5629cb5be2a 100644 --- a/Framework/Crystal/test/SCDCalibratePanels2Test.h +++ b/Framework/Crystal/test/SCDCalibratePanels2Test.h @@ -449,9 +449,10 @@ private: for (int i = 0; i < pws->getNumberPeaks(); ++i) { tof = pws->getPeak(i).getTOF(); pws->getPeak(i).setInstrument(pws->getInstrument()); - wl.initialize(pws->getPeak(i).getL1(), pws->getPeak(i).getL2(), - pws->getPeak(i).getScattering(), 0, - pws->getPeak(i).getInitialEnergy(), 0.0); + wl.initialize(pws->getPeak(i).getL1(), 0, + {{UnitParams::l2, pws->getPeak(i).getL2()}, + {UnitParams::twoTheta, pws->getPeak(i).getScattering()}, + {UnitParams::efixed, pws->getPeak(i).getInitialEnergy()}}); pws->getPeak(i).setDetectorID(pws->getPeak(i).getDetectorID()); pws->getPeak(i).setWavelength(wl.singleFromTOF(tof)); } diff --git a/Framework/CurveFitting/src/Algorithms/PawleyFit.cpp b/Framework/CurveFitting/src/Algorithms/PawleyFit.cpp index 9ba22ff2e156ede21ef0a299cc9fbce372152985..e153fc4da3a3a9ff19629550ad233e457e484c10 100644 --- a/Framework/CurveFitting/src/Algorithms/PawleyFit.cpp +++ b/Framework/CurveFitting/src/Algorithms/PawleyFit.cpp @@ -51,8 +51,7 @@ double PawleyFit::getTransformedCenter(double d, const Unit_sptr &unit) const { return d; } - return UnitConversion::run(*m_dUnit, *unit, d, 0, 0, 0, DeltaEMode::Elastic, - 0); + return UnitConversion::run(*m_dUnit, *unit, d, 0, DeltaEMode::Elastic); } /** diff --git a/Framework/CurveFitting/src/Functions/PawleyFunction.cpp b/Framework/CurveFitting/src/Functions/PawleyFunction.cpp index 3d47ea64dab25bcba73ba9571dbe5b8a6f617687..a842433a1d9636fa233f8290b956061977ffac5b 100644 --- a/Framework/CurveFitting/src/Functions/PawleyFunction.cpp +++ b/Framework/CurveFitting/src/Functions/PawleyFunction.cpp @@ -398,8 +398,7 @@ void PawleyFunction::setUnitCell(const std::string &unitCellString) { /// Transform d value to workspace unit double PawleyFunction::getTransformedCenter(double d) const { if ((m_dUnit && m_wsUnit) && m_dUnit != m_wsUnit) { - return UnitConversion::run(*m_dUnit, *m_wsUnit, d, 0, 0, 0, - DeltaEMode::Elastic, 0); + return UnitConversion::run(*m_dUnit, *m_wsUnit, d, 0, DeltaEMode::Elastic); } return d; diff --git a/Framework/DataHandling/CMakeLists.txt b/Framework/DataHandling/CMakeLists.txt index b0ce8cf67d0929c1b87b24f5d5cc1db4c583badb..8987e354d4688cd0b5f5c8e319618539ac094a4a 100644 --- a/Framework/DataHandling/CMakeLists.txt +++ b/Framework/DataHandling/CMakeLists.txt @@ -1,5 +1,6 @@ set(SRC_FILES src/AppendGeometryToSNSNexus.cpp + src/ApplyDiffCal.cpp src/BankPulseTimes.cpp src/CheckMantidVersion.cpp src/CompressEvents.cpp @@ -212,6 +213,7 @@ set(SRC_FILES set(INC_FILES inc/MantidDataHandling/AppendGeometryToSNSNexus.h + inc/MantidDataHandling/ApplyDiffCal.h inc/MantidDataHandling/BankPulseTimes.h inc/MantidDataHandling/CheckMantidVersion.h inc/MantidDataHandling/CompressEvents.h @@ -427,6 +429,7 @@ set(INC_FILES set(TEST_FILES AppendGeometryToSNSNexusTest.h + ApplyDiffCalTest.h CheckMantidVersionTest.h CompressEventsTest.h CreateChunkingFromInstrumentTest.h diff --git a/Framework/DataHandling/inc/MantidDataHandling/ApplyDiffCal.h b/Framework/DataHandling/inc/MantidDataHandling/ApplyDiffCal.h new file mode 100644 index 0000000000000000000000000000000000000000..c5953cd4c0b6c6595da384bd8df57d3b48ed1cc1 --- /dev/null +++ b/Framework/DataHandling/inc/MantidDataHandling/ApplyDiffCal.h @@ -0,0 +1,44 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2020 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS +// SPDX - License - Identifier: GPL - 3.0 + +#pragma once + +#include "MantidAPI/Algorithm.h" +#include "MantidAPI/ITableWorkspace_fwd.h" +#include "MantidAPI/Workspace_fwd.h" +#include "MantidGeometry/Instrument.h" +#include "MantidKernel/System.h" + +namespace Mantid { +namespace DataHandling { + +/** ApplyDiffCal : + */ +class DLLExport ApplyDiffCal : public API::Algorithm { +public: + const std::string name() const override; + int version() const override; + const std::vector<std::string> seeAlso() const override { + return {"AlignDetectors", "ConvertDiffCal", "ConvertUnits", "LoadDiffCal"}; + } + const std::string category() const override; + const std::string summary() const override; + /// Cross-check properties with each other @see IAlgorithm::validateInputs + std::map<std::string, std::string> validateInputs() override; + +private: + void init() override; + void exec() override; + + void loadCalFile(const Mantid::API::Workspace_sptr &inputWS, + const std::string &filename); + void getCalibrationWS(const Mantid::API::Workspace_sptr &inputWS); + + Mantid::API::ITableWorkspace_sptr m_calibrationWS; +}; + +} // namespace DataHandling +} // namespace Mantid diff --git a/Framework/DataHandling/inc/MantidDataHandling/LoadGSS.h b/Framework/DataHandling/inc/MantidDataHandling/LoadGSS.h index cefa59b10e4c8305ff0a36a3a76e287513ddc6d0..5d4d94eb89058abe94e476e40ec37f6b797d37a0 100644 --- a/Framework/DataHandling/inc/MantidDataHandling/LoadGSS.h +++ b/Framework/DataHandling/inc/MantidDataHandling/LoadGSS.h @@ -68,7 +68,8 @@ private: const double &primaryflightpath, const std::vector<int> &detectorids, const std::vector<double> &totalflightpaths, - const std::vector<double> &twothetas); + const std::vector<double> &twothetas, + const std::vector<double> &difcs); }; } // namespace DataHandling } // namespace Mantid diff --git a/Framework/DataHandling/src/ApplyDiffCal.cpp b/Framework/DataHandling/src/ApplyDiffCal.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1986daa0aabaec588f5c46c18c6774c0acc6db1 --- /dev/null +++ b/Framework/DataHandling/src/ApplyDiffCal.cpp @@ -0,0 +1,227 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2020 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS +// SPDX - License - Identifier: GPL - 3.0 + +#include "MantidDataHandling/ApplyDiffCal.h" + +#include "MantidAPI/FileProperty.h" +#include "MantidAPI/ITableWorkspace.h" +#include "MantidAPI/Progress.h" +#include "MantidAPI/Run.h" +#include "MantidAPI/TableRow.h" +#include "MantidAPI/Workspace.h" +#include "MantidDataObjects/MaskWorkspace.h" +#include "MantidDataObjects/OffsetsWorkspace.h" +#include "MantidDataObjects/Workspace2D.h" +#include "MantidKernel/EnabledWhenProperty.h" + +using namespace Mantid::API; +using namespace Mantid::DataObjects; + +namespace Mantid { +namespace DataHandling { + +using Mantid::Kernel::Direction; +using Mantid::Kernel::PropertyWithValue; + +namespace { +namespace PropertyNames { +const std::string CAL_FILE("Filename"); +const std::string GROUP_FILE("GroupFilename"); +const std::string MAKE_CAL("MakeCalWorkspace"); +const std::string MAKE_GRP("MakeGroupingWorkspace"); +const std::string MAKE_MSK("MakeMaskWorkspace"); +} // namespace PropertyNames +} // namespace + +// Register the algorithm into the AlgorithmFactory +DECLARE_ALGORITHM(ApplyDiffCal) + +/// Algorithms name for identification. @see Algorithm::name +const std::string ApplyDiffCal::name() const { return "ApplyDiffCal"; } + +/// Algorithm's version for identification. @see Algorithm::version +int ApplyDiffCal::version() const { return 1; } + +/// Algorithm's category for identification. @see Algorithm::category +const std::string ApplyDiffCal::category() const { + return "DataHandling\\Instrument;Diffraction\\DataHandling"; +} + +/// Algorithm's summary for use in the GUI and help. @see Algorithm::summary +const std::string ApplyDiffCal::summary() const { + return "Applies a calibration to a workspace for powder diffraction"; +} + +/** Initialize the algorithm's properties. + */ +void ApplyDiffCal::init() { + declareProperty(std::make_unique<WorkspaceProperty<API::Workspace>>( + "InstrumentWorkspace", "", Direction::InOut), + "Set the workspace whose instrument should be updated"); + const std::vector<std::string> exts{".h5", ".hd5", ".hdf", ".cal"}; + declareProperty( + std::make_unique<FileProperty>("CalibrationFile", "", + FileProperty::OptionalLoad, exts), + "Optional: The .cal file containing the position correction factors. " + "Either this, CalibrationWorkspace or OffsetsWorkspace needs to be " + "specified."); + declareProperty( + std::make_unique<WorkspaceProperty<ITableWorkspace>>( + "CalibrationWorkspace", "", Direction::Input, PropertyMode::Optional), + "Optional: Set the Diffraction Calibration workspace"); + declareProperty( + std::make_unique<WorkspaceProperty<OffsetsWorkspace>>( + "OffsetsWorkspace", "", Direction::Input, PropertyMode::Optional), + "Optional: A OffsetsWorkspace containing the calibration offsets. Either " + "this, CalibrationWorkspace or CalibrationFile needs to be specified."); + declareProperty("ClearCalibration", false, + "Remove any existing calibration from the workspace"); + setPropertySettings( + "CalibrationFile", + std::make_unique<Kernel::EnabledWhenProperty>( + "ClearCalibration", Kernel::ePropertyCriterion::IS_EQUAL_TO, "0")); + setPropertySettings( + "CalibrationWorkspace", + std::make_unique<Kernel::EnabledWhenProperty>( + "ClearCalibration", Kernel::ePropertyCriterion::IS_EQUAL_TO, "0")); + setPropertySettings( + "OffsetsWorkspace", + std::make_unique<Kernel::EnabledWhenProperty>( + "ClearCalibration", Kernel::ePropertyCriterion::IS_EQUAL_TO, "0")); +} + +std::map<std::string, std::string> ApplyDiffCal::validateInputs() { + std::map<std::string, std::string> result; + + // Check workspace type has ExperimentInfo fields + using API::ExperimentInfo_sptr; + using API::Workspace_sptr; + Workspace_sptr inputWS = getProperty("InstrumentWorkspace"); + if (!std::dynamic_pointer_cast<ExperimentInfo>(inputWS)) { + result["InstrumentWorkspace"] = "InputWorkspace type invalid. " + "Expected MatrixWorkspace, " + "PeaksWorkspace."; + } + + int numWays = 0; + + const std::string calFileName = getProperty("CalibrationFile"); + if (!calFileName.empty()) + numWays += 1; + + ITableWorkspace_const_sptr calibrationWS = + getProperty("CalibrationWorkspace"); + if (bool(calibrationWS)) + numWays += 1; + + OffsetsWorkspace_const_sptr offsetsWS = getProperty("OffsetsWorkspace"); + if (bool(offsetsWS)) + numWays += 1; + + bool clearCalibration = getProperty("ClearCalibration"); + std::string message; + if ((clearCalibration) && (numWays > 0)) { + message = + "You cannot supply a calibration input when clearing the calibration."; + } + if (!clearCalibration) { + if (numWays == 0) { + message = "You must specify only one of CalibrationFile, " + "CalibrationWorkspace, OffsetsWorkspace."; + } + if (numWays > 1) { + message = "You must specify one of CalibrationFile, " + "CalibrationWorkspace, OffsetsWorkspace."; + } + } + + if (!message.empty()) { + result["CalibrationFile"] = message; + result["CalibrationWorkspace"] = message; + } + + return result; +} + +void ApplyDiffCal::loadCalFile(const Workspace_sptr &inputWS, + const std::string &filename) { + IAlgorithm_sptr alg = createChildAlgorithm("LoadDiffCal"); + alg->setProperty("InputWorkspace", inputWS); + alg->setPropertyValue("Filename", filename); + alg->setProperty<bool>("MakeCalWorkspace", true); + alg->setProperty<bool>("MakeGroupingWorkspace", false); + alg->setProperty<bool>("MakeMaskWorkspace", false); + alg->setPropertyValue("WorkspaceName", "temp"); + alg->executeAsChildAlg(); + + m_calibrationWS = alg->getProperty("OutputCalWorkspace"); +} + +void ApplyDiffCal::getCalibrationWS(const Workspace_sptr &inputWS) { + m_calibrationWS = getProperty("CalibrationWorkspace"); + if (m_calibrationWS) + return; // nothing more to do + + OffsetsWorkspace_sptr offsetsWS = getProperty("OffsetsWorkspace"); + if (offsetsWS) { + auto alg = createChildAlgorithm("ConvertDiffCal"); + alg->setProperty("OffsetsWorkspace", offsetsWS); + alg->executeAsChildAlg(); + m_calibrationWS = alg->getProperty("OutputWorkspace"); + m_calibrationWS->setTitle(offsetsWS->getTitle()); + return; + } + + const std::string calFileName = getPropertyValue("CalibrationFile"); + if (!calFileName.empty()) { + progress(0.0, "Reading calibration file"); + loadCalFile(std::move(inputWS), calFileName); + return; + } + + throw std::runtime_error("Failed to determine calibration information"); +} + +//---------------------------------------------------------------------------------------------- +/** Execute the algorithm. + */ +void ApplyDiffCal::exec() { + + Workspace_sptr InstrumentWorkspace = getProperty("InstrumentWorkspace"); + // validateInputs guarantees this will be an ExperimentInfo object + auto experimentInfo = + std::dynamic_pointer_cast<API::ExperimentInfo>(InstrumentWorkspace); + auto instrument = experimentInfo->getInstrument(); + auto ¶mMap = experimentInfo->instrumentParameters(); + bool clearCalibration = getProperty("ClearCalibration"); + if (clearCalibration) { + paramMap.clearParametersByName("DIFC"); + paramMap.clearParametersByName("DIFA"); + paramMap.clearParametersByName("TZERO"); + } else { + this->getCalibrationWS(InstrumentWorkspace); + + Column_const_sptr detIdColumn = m_calibrationWS->getColumn("detid"); + Column_const_sptr difcColumn = m_calibrationWS->getColumn("difc"); + Column_const_sptr difaColumn = m_calibrationWS->getColumn("difa"); + Column_const_sptr tzeroColumn = m_calibrationWS->getColumn("tzero"); + + for (size_t i = 0; i < m_calibrationWS->rowCount(); ++i) { + auto detid = static_cast<detid_t>((*detIdColumn)[i]); + double difc = (*difcColumn)[i]; + double difa = (*difaColumn)[i]; + double tzero = (*tzeroColumn)[i]; + + auto det = instrument->getDetector(detid); + paramMap.addDouble(det->getComponentID(), "DIFC", difc); + paramMap.addDouble(det->getComponentID(), "DIFA", difa); + paramMap.addDouble(det->getComponentID(), "TZERO", tzero); + } + } +} + +} // namespace DataHandling +} // namespace Mantid diff --git a/Framework/DataHandling/src/LoadDiffCal.cpp b/Framework/DataHandling/src/LoadDiffCal.cpp index b28e4399d40daf2556a1b481fc85c4b27187cd6f..d10d84a0bc90876f3edda6fcada3a14afdc43069 100644 --- a/Framework/DataHandling/src/LoadDiffCal.cpp +++ b/Framework/DataHandling/src/LoadDiffCal.cpp @@ -17,9 +17,9 @@ #include "MantidDataObjects/MaskWorkspace.h" #include "MantidDataObjects/TableWorkspace.h" #include "MantidDataObjects/Workspace2D.h" -#include "MantidKernel/Diffraction.h" #include "MantidKernel/Exception.h" #include "MantidKernel/OptionalBool.h" +#include "MantidKernel/Unit.h" #include <H5Cpp.h> #include <cmath> @@ -315,8 +315,9 @@ void LoadDiffCal::makeCalWorkspace(const std::vector<int32_t> &detids, newrow << offsets[i]; // calculate tof range for information + Kernel::Units::dSpacing dspacingUnit; const double tofMinRow = - Kernel::Diffraction::calcTofMin(difc[i], difa[i], tzero[i], tofMin); + dspacingUnit.calcTofMin(difc[i], difa[i], tzero[i], tofMin); std::stringstream msg; if (tofMinRow != tofMin) { msg << "TofMin shifted from " << tofMin << " to " << tofMinRow << " "; @@ -324,7 +325,7 @@ void LoadDiffCal::makeCalWorkspace(const std::vector<int32_t> &detids, newrow << tofMinRow; if (useTofMax) { const double tofMaxRow = - Kernel::Diffraction::calcTofMax(difc[i], difa[i], tzero[i], tofMax); + dspacingUnit.calcTofMax(difc[i], difa[i], tzero[i], tofMax); newrow << tofMaxRow; if (tofMaxRow != tofMax) { diff --git a/Framework/DataHandling/src/LoadGSS.cpp b/Framework/DataHandling/src/LoadGSS.cpp index 3c3ab417877438854a4f41dd2c4cdda117c8b04e..b4c8a2b97e952636a54bb16abe1220a0d4e66dc9 100644 --- a/Framework/DataHandling/src/LoadGSS.cpp +++ b/Framework/DataHandling/src/LoadGSS.cpp @@ -458,7 +458,7 @@ API::MatrixWorkspace_sptr LoadGSS::loadGSASFile(const std::string &filename, // build instrument geometry createInstrumentGeometry(outputWorkspace, instrumentname, primaryflightpath, - detectorIDs, totalflightpaths, twothetas); + detectorIDs, totalflightpaths, twothetas, difcs); return outputWorkspace; } @@ -491,7 +491,7 @@ void LoadGSS::createInstrumentGeometry( const MatrixWorkspace_sptr &workspace, const std::string &instrumentname, const double &primaryflightpath, const std::vector<int> &detectorids, const std::vector<double> &totalflightpaths, - const std::vector<double> &twothetas) { + const std::vector<double> &twothetas, const std::vector<double> &difcs) { // Check Input if (detectorids.size() != totalflightpaths.size() || totalflightpaths.size() != twothetas.size()) { @@ -560,7 +560,13 @@ void LoadGSS::createInstrumentGeometry( } // ENDFOR (i: spectrum) workspace->setInstrument(instrument); -} + auto ¶mMap = workspace->instrumentParameters(); + for (size_t i = 0; i < workspace->getNumberHistograms(); i++) { + auto detector = workspace->getDetector(i); + paramMap.addDouble(detector->getComponentID(), "DIFC", difcs[i]); + } +} } // namespace DataHandling + } // namespace Mantid diff --git a/Framework/DataHandling/src/SaveGDA.cpp b/Framework/DataHandling/src/SaveGDA.cpp index f7230ebd141d08c739f1f5ce47d2ef924931698a..85efe73401507cc1eb32019b11c955f78c18354e 100644 --- a/Framework/DataHandling/src/SaveGDA.cpp +++ b/Framework/DataHandling/src/SaveGDA.cpp @@ -162,7 +162,7 @@ void SaveGDA::exec() { const auto ws = inputWS->getItem(i); const auto matrixWS = std::dynamic_pointer_cast<MatrixWorkspace>(ws); - const auto &d = matrixWS->x(0); + auto x = matrixWS->dataX(0); const size_t bankIndex(groupingScheme[i] - 1); if (bankIndex >= calibParams.size()) { throw Kernel::Exception::IndexError(bankIndex, calibParams.size(), @@ -173,14 +173,15 @@ void SaveGDA::exec() { // For historic reasons, TOF is scaled by 32 in MAUD const static double tofScale = 32; std::vector<double> tofScaled; - tofScaled.reserve(d.size()); - std::transform(d.begin(), d.end(), std::back_inserter(tofScaled), - [&bankCalibParams](const double dVal) { - return (dVal * bankCalibParams.difc + - dVal * dVal * bankCalibParams.difa + - bankCalibParams.tzero) * - tofScale; - }); + tofScaled.reserve(x.size()); + Kernel::Units::dSpacing dSpacingUnit; + std::vector<double> yunused; + dSpacingUnit.toTOF(x, yunused, 0., Kernel::DeltaEMode::Elastic, + {{Kernel::UnitParams::difa, bankCalibParams.difa}, + {Kernel::UnitParams::difc, bankCalibParams.difc}, + {Kernel::UnitParams::tzero, bankCalibParams.tzero}}); + std::transform(x.begin(), x.end(), std::back_inserter(tofScaled), + [](const double tofVal) { return tofVal * tofScale; }); const auto averageDeltaTByT = computeAverageDeltaTByT(tofScaled); const auto &intensity = matrixWS->y(0); diff --git a/Framework/DataHandling/src/SaveGSS.cpp b/Framework/DataHandling/src/SaveGSS.cpp index 05372a28b137c90e88869100422d63a072b0bb12..829162614267c65bc228197fd30b1c3e98b2d633 100644 --- a/Framework/DataHandling/src/SaveGSS.cpp +++ b/Framework/DataHandling/src/SaveGSS.cpp @@ -361,11 +361,10 @@ void SaveGSS::generateBankHeader(std::stringstream &out, const auto l1 = spectrumInfo.l1(); const auto l2 = spectrumInfo.l2(specIndex); const auto twoTheta = spectrumInfo.twoTheta(specIndex); - const auto difc = (2.0 * PhysicalConstants::NeutronMass * - sin(twoTheta * 0.5) * (l1 + l2)) / - (PhysicalConstants::h * 1.e4); + auto diffConstants = spectrumInfo.diffractometerConstants(specIndex); out << "# Total flight path " << (l1 + l2) << "m, tth " - << (twoTheta * 180. / M_PI) << "deg, DIFC " << difc << "\n"; + << (twoTheta * 180. / M_PI) << "deg, DIFC " + << diffConstants[Kernel::UnitParams::difc] << "\n"; } out << "# Data for spectrum :" << specIndex << "\n"; } diff --git a/Framework/DataHandling/test/ApplyDiffCalTest.h b/Framework/DataHandling/test/ApplyDiffCalTest.h new file mode 100644 index 0000000000000000000000000000000000000000..d1a7f7dd19dff7dcbe2f9bc7d4e069973c9d601a --- /dev/null +++ b/Framework/DataHandling/test/ApplyDiffCalTest.h @@ -0,0 +1,131 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2020 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS +// SPDX - License - Identifier: GPL - 3.0 + +#pragma once + +#include <cxxtest/TestSuite.h> + +#include "MantidAPI/AnalysisDataService.h" +#include "MantidAPI/TableRow.h" +#include "MantidDataHandling/ApplyDiffCal.h" +#include "MantidDataObjects/TableWorkspace.h" +#include "MantidDataObjects/Workspace2D.h" +#include "MantidTestHelpers/ComponentCreationHelper.h" + +using namespace Mantid::API; +using namespace Mantid::DataHandling; +using namespace Mantid::DataObjects; + +namespace { +const size_t NUM_BANK = 5; +} // namespace + +class ApplyDiffCalTest : public CxxTest::TestSuite { +public: + void testName() { + ApplyDiffCal appDiffCal; + TS_ASSERT_EQUALS(appDiffCal.name(), "ApplyDiffCal") + } + + void testInit() { + ApplyDiffCal appDiffCal; + appDiffCal.initialize(); + TS_ASSERT(appDiffCal.isInitialized()) + } + + void testExec() { + auto calWSIn = createCalibration(5 * 9); // nine components per bank + + Mantid::Geometry::Instrument_sptr inst = createInstrument(); + + std::string testWorkspaceName = "TestApplyDiffCalWorkspace"; + AnalysisDataService::Instance().add(testWorkspaceName, + std::make_shared<Workspace2D>()); + auto instrumentWS = + AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>( + testWorkspaceName); + instrumentWS->setInstrument(inst); + + ApplyDiffCal appDiffCal; + TS_ASSERT_THROWS_NOTHING(appDiffCal.initialize()); + TS_ASSERT(appDiffCal.isInitialized()); + TS_ASSERT_THROWS_NOTHING( + appDiffCal.setProperty("InstrumentWorkspace", testWorkspaceName)); + TS_ASSERT_THROWS_NOTHING( + appDiffCal.setProperty("CalibrationWorkspace", calWSIn)); + TS_ASSERT_THROWS_NOTHING(appDiffCal.execute();); + TS_ASSERT(appDiffCal.isExecuted()); + + auto instFromWS = instrumentWS->getInstrument(); + auto det = instFromWS->getDetector(3); + auto pmap = instFromWS->getParameterMap(); + auto par = pmap->getRecursive(det.get(), "DIFC"); + double difc{0.}; + if (par) + difc = par->value<double>(); + TS_ASSERT_EQUALS(difc, 102); + par = pmap->getRecursive(det.get(), "DIFA"); + double difa{0.}; + if (par) + difa = par->value<double>(); + TS_ASSERT_EQUALS(difa, 4); + par = pmap->getRecursive(det.get(), "TZERO"); + double tzero{0.}; + if (par) + tzero = par->value<double>(); + TS_ASSERT_EQUALS(tzero, 2); + + ApplyDiffCal appDiffCalClear; + pmap->addDouble(det->getComponentID(), "extraparam", 1.23); + TS_ASSERT_THROWS_NOTHING(appDiffCalClear.initialize()); + TS_ASSERT(appDiffCalClear.isInitialized()); + TS_ASSERT_THROWS_NOTHING( + appDiffCalClear.setProperty("InstrumentWorkspace", testWorkspaceName)); + TS_ASSERT_THROWS_NOTHING( + appDiffCalClear.setProperty("ClearCalibration", true)); + TS_ASSERT_THROWS_NOTHING(appDiffCalClear.execute();); + TS_ASSERT(appDiffCalClear.isExecuted()); + + instFromWS = instrumentWS->getInstrument(); + det = instFromWS->getDetector(3); + pmap = instFromWS->getParameterMap(); + par = pmap->getRecursive(det.get(), "DIFC"); + TS_ASSERT(!par); + par = pmap->getRecursive(det.get(), "extraparam"); + TS_ASSERT(par); + } + + void TestClear() {} + +private: + Mantid::Geometry::Instrument_sptr createInstrument() { + auto instr = + ComponentCreationHelper::createTestInstrumentCylindrical(NUM_BANK); + auto pmap = std::make_shared<Mantid::Geometry::ParameterMap>(); + instr = std::make_shared<Mantid::Geometry::Instrument>(instr, pmap); + return instr; + } + + TableWorkspace_sptr createCalibration(const size_t numRows) { + TableWorkspace_sptr wksp = std::make_shared<TableWorkspace>(); + wksp->addColumn("int", "detid"); + wksp->addColumn("double", "difc"); + wksp->addColumn("double", "difa"); + wksp->addColumn("double", "tzero"); + wksp->addColumn("double", "tofmin"); + + for (size_t i = 0; i < numRows; ++i) { + TableRow row = wksp->appendRow(); + + row << static_cast<int>(i + 1) // detid + << static_cast<double>(100 + i) // difc + << static_cast<double>(i * i) // difa + << static_cast<double>(i) // tzero + << 0.; // tofmin + } + return wksp; + } +}; diff --git a/Framework/DataHandling/test/LoadGSSTest.h b/Framework/DataHandling/test/LoadGSSTest.h index f38231405fcb5a3be28e826b3360c4a2a93c00d9..7bdeb7771e5537bba34abce60b7bfe79afceb5d3 100644 --- a/Framework/DataHandling/test/LoadGSSTest.h +++ b/Framework/DataHandling/test/LoadGSSTest.h @@ -97,6 +97,8 @@ public: TS_ASSERT_DELTA(spectrumInfo.twoTheta(0) * 180. / M_PI, 58.308, 1e-4); TS_ASSERT_DELTA(spectrumInfo.l2(1), 2.060, 1e-4); TS_ASSERT_DELTA(spectrumInfo.twoTheta(1) * 180. / M_PI, 154.257, 1e-4); + auto diffConsts = spectrumInfo.diffractometerConstants(1); + TS_ASSERT_DELTA(diffConsts[Kernel::UnitParams::difc], 10398.8, 1e-4); } void test_load_gss_ExtendedHeader_gsa() { diff --git a/Framework/DataObjects/test/EventListTest.h b/Framework/DataObjects/test/EventListTest.h index 697a6012932ea1bf4d4f6ea06515966dd7782ba0..468a1985c71160bc15a2ef1211d931341536f97f 100644 --- a/Framework/DataObjects/test/EventListTest.h +++ b/Framework/DataObjects/test/EventListTest.h @@ -1486,8 +1486,8 @@ public: void test_convertUnitsViaTof_allTypes() { DummyUnit1 fromUnit; DummyUnit2 toUnit; - fromUnit.initialize(1, 2, 3, 4, 5, 6); - toUnit.initialize(1, 2, 3, 4, 5, 6); + fromUnit.initialize(1, 2, {}); + toUnit.initialize(1, 2, {}); // Go through each possible EventType as the input for (int this_type = 0; this_type < 3; this_type++) { this->fake_uniform_data(); diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/DetectorInfo.h b/Framework/Geometry/inc/MantidGeometry/Instrument/DetectorInfo.h index b4c07f743e3d0fddcdc376ee9a38956fdd330659..9c84b45c7d59ff28917e4a8eed7255cfcf4f4e1a 100644 --- a/Framework/Geometry/inc/MantidGeometry/Instrument/DetectorInfo.h +++ b/Framework/Geometry/inc/MantidGeometry/Instrument/DetectorInfo.h @@ -76,6 +76,11 @@ public: double signedTwoTheta(const std::pair<size_t, size_t> &index) const; double azimuthal(const size_t index) const; double azimuthal(const std::pair<size_t, size_t> &index) const; + std::tuple<double, double, double> + diffractometerConstants(const size_t index, + std::vector<detid_t> &calibratedDets, + std::vector<detid_t> &uncalibratedDets) const; + double difcUncalibrated(const size_t index) const; std::pair<double, double> geographicalAngles(const size_t index) const; std::pair<double, double> geographicalAngles(const std::pair<size_t, size_t> &index) const; @@ -125,6 +130,7 @@ private: const Geometry::IDetector &getDetector(const size_t index) const; std::shared_ptr<const Geometry::IDetector> getDetectorPtr(const size_t index) const; + void clearPositionDependentParameters(const size_t index); /// Pointer to the actual DetectorInfo object (non-wrapping part). std::unique_ptr<Beamline::DetectorInfo> m_detectorInfo; diff --git a/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterMap.h b/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterMap.h index 7fb23a1ee2a58b78525a34e7f10a99df196d1f86..56f998a6edc9d959a50f6bf1131369f7cd799700 100644 --- a/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterMap.h +++ b/Framework/Geometry/inc/MantidGeometry/Instrument/ParameterMap.h @@ -82,8 +82,10 @@ public: static const std::string &pQuat(); static const std::string &scale(); - const std::string diff(const ParameterMap &rhs, - const bool &firstDiffOnly = false) const; + const std::string + diff(const ParameterMap &rhs, const bool &firstDiffOnly = false, + const bool relative = false, + const double doubleTolerance = Kernel::Tolerance) const; /// Inquality comparison operator bool operator!=(const ParameterMap &rhs) const; @@ -346,6 +348,8 @@ private: /// the parameter map component_map_cit positionOf(const IComponent *comp, const char *name, const char *type) const; + /// calculate relative error for use in diff + bool relErr(double x1, double x2, double errorVal) const; /// internal list of parameter files loaded std::vector<std::string> m_parameterFileNames; diff --git a/Framework/Geometry/src/Instrument.cpp b/Framework/Geometry/src/Instrument.cpp index edc2af5db14cdab499025a96e950815031801e98..3b2694bcd2c9f9db9a8d4fa9d75c451422b37a82 100644 --- a/Framework/Geometry/src/Instrument.cpp +++ b/Framework/Geometry/src/Instrument.cpp @@ -20,6 +20,7 @@ #include "MantidKernel/Exception.h" #include "MantidKernel/Logger.h" #include "MantidKernel/PhysicalConstants.h" +#include "MantidKernel/Unit.h" #include <memory> #include <nexus/NeXusFile.hpp> @@ -858,9 +859,6 @@ void Instrument::appendPlottable( } } -const double CONSTANT = (PhysicalConstants::h * 1e10) / - (2.0 * PhysicalConstants::NeutronMass * 1e6); - //------------------------------------------------------------------------------------------------ /** Get several instrument parameters used in tof to D-space conversion * @@ -1365,50 +1363,9 @@ namespace Conversion { */ double tofToDSpacingFactor(const double l1, const double l2, const double twoTheta, const double offset) { - if (offset <= - -1.) // not physically possible, means result is negative d-spacing - { - std::stringstream msg; - msg << "Encountered offset of " << offset - << " which converts data to negative d-spacing\n"; - throw std::logic_error(msg.str()); - } - - auto sinTheta = std::sin(twoTheta / 2); - - const double numerator = (1.0 + offset); - sinTheta *= (l1 + l2); - - return (numerator * CONSTANT) / sinTheta; + return Kernel::Units::tofToDSpacingFactor(l1, l2, twoTheta, offset); } -/** Calculate the conversion factor from tof -> d-spacing - * for a LIST of detector ids assigned to a single spectrum. - * @brief tofToDSpacingFactor - * @param l1 - * @param l2 - * @param twoTheta scattering angle - * @param detectors - * @param offsets - * @return - */ -double tofToDSpacingFactor(const double l1, const double l2, - const double twoTheta, - const std::vector<detid_t> &detectors, - const std::map<detid_t, double> &offsets) { - double factor = 0.; - double offset; - for (auto detector : detectors) { - auto off_iter = offsets.find(detector); - if (off_iter != offsets.cend()) { - offset = offsets.find(detector)->second; - } else { - offset = 0.; - } - factor += tofToDSpacingFactor(l1, l2, twoTheta, offset); - } - return factor / static_cast<double>(detectors.size()); -} } // namespace Conversion } // namespace Geometry } // Namespace Mantid diff --git a/Framework/Geometry/src/Instrument/DetectorInfo.cpp b/Framework/Geometry/src/Instrument/DetectorInfo.cpp index bda1593cc5337214038980dd845685ba4038dda0..3ce2a14be114a8e950ce07c1de3db782342d1273 100644 --- a/Framework/Geometry/src/Instrument/DetectorInfo.cpp +++ b/Framework/Geometry/src/Instrument/DetectorInfo.cpp @@ -15,6 +15,7 @@ #include "MantidKernel/EigenConversionHelpers.h" #include "MantidKernel/Exception.h" #include "MantidKernel/MultiThreaded.h" +#include "MantidKernel/Unit.h" namespace Mantid { namespace Geometry { @@ -308,6 +309,37 @@ double DetectorInfo::azimuthal(const std::pair<size_t, size_t> &index) const { return atan2(dotVertical, dotHorizontal); } +std::tuple<double, double, double> DetectorInfo::diffractometerConstants( + const size_t index, std::vector<detid_t> &calibratedDets, + std::vector<detid_t> &uncalibratedDets) const { + auto det = m_instrument->getDetector((*m_detectorIDs)[index]); + auto pmap = m_instrument->getParameterMap(); + auto par = pmap->get(det.get(), "DIFC"); + if (par) { + double difc = par->value<double>(); + calibratedDets.push_back((*m_detectorIDs)[index]); + double difa = 0., tzero = 0.; + par = pmap->get(det.get(), "DIFA"); + if (par) + difa = par->value<double>(); + par = pmap->get(det.get(), "TZERO"); + if (par) + tzero = par->value<double>(); + return {difa, difc, tzero}; + } else { + // if calibrated difc not available, revert to uncalibrated difc with other + // two constants=0 + uncalibratedDets.push_back((*m_detectorIDs)[index]); + double difc = difcUncalibrated(index); + return {0., difc, 0.}; + } +} + +double DetectorInfo::difcUncalibrated(const size_t index) const { + return 1. / Kernel::Units::tofToDSpacingFactor(l1(), l2(index), + twoTheta(index), 0.); +} + std::pair<double, double> DetectorInfo::geographicalAngles(const size_t index) const { const auto samplePos = samplePosition(); @@ -383,15 +415,28 @@ void DetectorInfo::clearMaskFlags() { /// Set the absolute position of the detector with given index. Not thread safe. void DetectorInfo::setPosition(const size_t index, const Kernel::V3D &position) { + + clearPositionDependentParameters(index); m_detectorInfo->setPosition(index, Kernel::toVector3d(position)); } /// Set the absolute position of the detector with given index. Not thread safe. void DetectorInfo::setPosition(const std::pair<size_t, size_t> &index, const Kernel::V3D &position) { + clearPositionDependentParameters(index.first); m_detectorInfo->setPosition(index, Kernel::toVector3d(position)); } +// Clear any parameters whose value is only valid for specific positions +// Currently diffractometer constants +void DetectorInfo::clearPositionDependentParameters(const size_t index) { + auto det = m_instrument->getDetector((*m_detectorIDs)[index]); + auto pmap = m_instrument->getParameterMap(); + pmap->clearParametersByName("DIFA", det.get()); + pmap->clearParametersByName("DIFC", det.get()); + pmap->clearParametersByName("TZERO", det.get()); +} + /// Set the absolute rotation of the detector with given index. Not thread safe. void DetectorInfo::setRotation(const size_t index, const Kernel::Quat &rotation) { diff --git a/Framework/Geometry/src/Instrument/ParameterMap.cpp b/Framework/Geometry/src/Instrument/ParameterMap.cpp index 05b2d805e4184250a3493d3a58e5165e3c63c7de..4b6ff507b1822e2670b6cc0456d6790071efe6ab 100644 --- a/Framework/Geometry/src/Instrument/ParameterMap.cpp +++ b/Framework/Geometry/src/Instrument/ParameterMap.cpp @@ -138,36 +138,7 @@ bool ParameterMap::operator!=(const ParameterMap &rhs) const { * @return true if the objects are considered equal, false otherwise */ bool ParameterMap::operator==(const ParameterMap &rhs) const { - if (this == &rhs) - return true; // True for the same object - - // Quick size check - if (this->size() != rhs.size()) - return false; - - // The map is unordered and the key is only valid at runtime. The - // asString method turns the ComponentIDs to full-qualified name identifiers - // so we will use the same approach to compare them - - auto thisEnd = this->m_map.cend(); - auto rhsEnd = rhs.m_map.cend(); - for (auto thisIt = this->m_map.begin(); thisIt != thisEnd; ++thisIt) { - const IComponent *comp = static_cast<IComponent *>(thisIt->first); - const std::string fullName = comp->getFullName(); - const auto ¶m = thisIt->second; - bool match(false); - for (auto rhsIt = rhs.m_map.cbegin(); rhsIt != rhsEnd; ++rhsIt) { - const IComponent *rhsComp = static_cast<IComponent *>(rhsIt->first); - const std::string rhsFullName = rhsComp->getFullName(); - if (fullName == rhsFullName && (*param) == (*rhsIt->second)) { - match = true; - break; - } - } - if (!match) - return false; - } - return true; + return diff(rhs, true, false, 0.).empty(); } /** Get the component description by name @@ -217,6 +188,31 @@ ParameterMap::getShortDescription(const std::string &compName, } return result; } + +//------------------------------------------------------------------------------------------------ +/** Function which calculates relative error between two values and analyses if +this error is within the limits +* requested. When the absolute value of the difference is smaller then the value +of the error requested, +* absolute error is used instead of relative error. + +@param x1 -- first value to check difference +@param x2 -- second value to check difference +@param errorVal -- the value of the error, to check against. Should be large +then 0 + +@returns true if error or false if the value is within the limits requested +*/ +bool ParameterMap::relErr(double x1, double x2, double errorVal) const { + double num = std::fabs(x1 - x2); + // how to treat x1<0 and x2 > 0 ? probably this way + double den = 0.5 * (std::fabs(x1) + std::fabs(x2)); + if (den < errorVal) + return (num > errorVal); + + return (num / den > errorVal); +} + /** * Output information that helps understanding the mismatch between two * parameter maps. @@ -226,10 +222,15 @@ ParameterMap::getShortDescription(const std::string &compName, * true * @param rhs A reference to a ParameterMap object to compare it to * @param firstDiffOnly If true return only first difference found + * @param relative Indicates whether to treat the error as relative or absolute + * @param doubleTolerance The tolerance to use when comparing parameter values + * of type double * @return diff as a string */ const std::string ParameterMap::diff(const ParameterMap &rhs, - const bool &firstDiffOnly) const { + const bool &firstDiffOnly, + const bool relative, + const double doubleTolerance) const { if (this == &rhs) return std::string(""); // True for the same object @@ -240,25 +241,41 @@ const std::string ParameterMap::diff(const ParameterMap &rhs, std::to_string(rhs.size()); } - // Run this same loops as in operator== // The map is unordered and the key is only valid at runtime. The // asString method turns the ComponentIDs to full-qualified name identifiers // so we will use the same approach to compare them + std::unordered_multimap<std::string, Parameter_sptr> thisMap, rhsMap; + for (auto &mappair : this->m_map) { + thisMap.emplace(mappair.first->getFullName(), mappair.second); + } + for (auto &mappair : rhs.m_map) { + rhsMap.emplace(mappair.first->getFullName(), mappair.second); + } + std::stringstream strOutput; - auto thisEnd = this->m_map.cend(); - auto rhsEnd = rhs.m_map.cend(); - for (auto thisIt = this->m_map.cbegin(); thisIt != thisEnd; ++thisIt) { - const IComponent *comp = static_cast<IComponent *>(thisIt->first); - const std::string fullName = comp->getFullName(); + for (auto thisIt = thisMap.cbegin(); thisIt != thisMap.cend(); ++thisIt) { + const std::string fullName = thisIt->first; const auto ¶m = thisIt->second; bool match(false); - for (auto rhsIt = rhs.m_map.cbegin(); rhsIt != rhsEnd; ++rhsIt) { - const IComponent *rhsComp = static_cast<IComponent *>(rhsIt->first); - const std::string rhsFullName = rhsComp->getFullName(); - if (fullName == rhsFullName && (*param) == (*rhsIt->second)) { - match = true; - break; + for (auto rhsIt = rhsMap.cbegin(); rhsIt != rhsMap.cend(); ++rhsIt) { + const std::string rhsFullName = rhsIt->first; + const auto &rhsParam = rhsIt->second; + if ((fullName == rhsFullName) && (param->name() == (rhsParam->name()))) { + if ((param->type() == rhsParam->type()) && + (rhsParam->type() == "double")) { + if (relative) { + if (!relErr(param->value<double>(), rhsParam->value<double>(), + doubleTolerance)) + match = true; + } else if (std::abs(param->value<double>() - + rhsParam->value<double>()) <= doubleTolerance) + match = true; + } else if (param->asString() == rhsParam->asString()) { + match = true; + } + if (match) + break; } } @@ -270,9 +287,8 @@ const std::string ParameterMap::diff(const ParameterMap &rhs, << " and value: " << (*param).asString() << '\n'; bool componentWithSameNameRHS = false; bool parameterWithSameNameRHS = false; - for (auto rhsIt = rhs.m_map.cbegin(); rhsIt != rhsEnd; ++rhsIt) { - const IComponent *rhsComp = static_cast<IComponent *>(rhsIt->first); - const std::string rhsFullName = rhsComp->getFullName(); + for (auto rhsIt = rhsMap.cbegin(); rhsIt != rhsMap.cend(); ++rhsIt) { + const std::string rhsFullName = rhsIt->first; if (fullName == rhsFullName) { componentWithSameNameRHS = true; if ((*param).name() == (*rhsIt->second).name()) { diff --git a/Framework/Kernel/CMakeLists.txt b/Framework/Kernel/CMakeLists.txt index fc5097d760f22c9ea93d187de70bcb52d0c847fb..483280d511355d8dea2950fc4798dc96a95c8b57 100644 --- a/Framework/Kernel/CMakeLists.txt +++ b/Framework/Kernel/CMakeLists.txt @@ -23,7 +23,6 @@ set(SRC_FILES src/DateTimeValidator.cpp src/DateValidator.cpp src/DeltaEMode.cpp - src/Diffraction.cpp src/DirectoryValidator.cpp src/DiskBuffer.cpp src/DllOpen.cpp @@ -173,7 +172,6 @@ set(INC_FILES inc/MantidKernel/DateTimeValidator.h inc/MantidKernel/DateValidator.h inc/MantidKernel/DeltaEMode.h - inc/MantidKernel/Diffraction.h inc/MantidKernel/DirectoryValidator.h inc/MantidKernel/DiskBuffer.h inc/MantidKernel/DllConfig.h @@ -343,7 +341,6 @@ set(TEST_FILES DateTimeValidatorTest.h DateValidatorTest.h DeltaEModeTest.h - DiffractionTest.h DirectoryValidatorTest.h DiskBufferISaveableTest.h DiskBufferTest.h diff --git a/Framework/Kernel/inc/MantidKernel/Diffraction.h b/Framework/Kernel/inc/MantidKernel/Diffraction.h deleted file mode 100644 index a75c1f0e910896d0bb35e1fe91d0b513bcfd3e04..0000000000000000000000000000000000000000 --- a/Framework/Kernel/inc/MantidKernel/Diffraction.h +++ /dev/null @@ -1,36 +0,0 @@ -// Mantid Repository : https://github.com/mantidproject/mantid -// -// Copyright © 2017 ISIS Rutherford Appleton Laboratory UKRI, -// NScD Oak Ridge National Laboratory, European Spallation Source, -// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS -// SPDX - License - Identifier: GPL - 3.0 + -#pragma once - -#include "MantidKernel/DllConfig.h" -#include <functional> - -namespace Mantid { -namespace Kernel { -namespace Diffraction { - -/** Diffraction : Collection of functions useful in diffraction scattering - */ - -MANTID_KERNEL_DLL double calcTofMin(const double difc, const double difa, - const double tzero, - const double tofmin = 0.); - -MANTID_KERNEL_DLL double calcTofMax(const double difc, const double difa, - const double tzero, const double tofmax); - -MANTID_KERNEL_DLL std::function<double(double)> -getTofToDConversionFunc(const double difc, const double difa, - const double tzero); - -MANTID_KERNEL_DLL std::function<double(double)> -getDToTofConversionFunc(const double difc, const double difa, - const double tzero); - -} // namespace Diffraction -} // namespace Kernel -} // namespace Mantid diff --git a/Framework/Kernel/inc/MantidKernel/Unit.h b/Framework/Kernel/inc/MantidKernel/Unit.h index 3e6cee072f9471861147d6f1d5ffed68d2c7bac4..8537b8b815aede803274b7ef2e4f9b5df7a6553f 100644 --- a/Framework/Kernel/inc/MantidKernel/Unit.h +++ b/Framework/Kernel/inc/MantidKernel/Unit.h @@ -12,6 +12,7 @@ #include "MantidKernel/UnitLabel.h" #include <utility> +#include <unordered_map> #include <vector> #ifndef Q_MOC_RUN #include <memory> @@ -22,6 +23,12 @@ namespace Mantid { namespace Kernel { +enum class UnitParams { l2, twoTheta, efixed, delta, difa, difc, tzero }; + +// list of parameter names and values - some code may relay on map behaviour +// where [] creates element with value 0 if param name not present +using UnitParametersMap = std::unordered_map<UnitParams, double>; + /** The base units (abstract) class. All concrete units should inherit from this class and provide implementations of the caption(), label(), toTOF() and fromTOF() methods. They also need to declare (but NOT define) @@ -75,87 +82,90 @@ public: * @param ydata :: Not currently used (ConvertUnits passes an empty * vector) * @param _l1 :: The source-sample distance (in metres) - * @param _l2 :: The sample-detector distance (in metres) - * @param _twoTheta :: The scattering angle (in radians) * @param _emode :: The energy mode (0=elastic, 1=direct geometry, * 2=indirect geometry) - * @param _efixed :: Value of fixed energy: EI (emode=1) or EF (emode=2) - * (in - * meV) - * @param _delta :: Not currently used + * @param params :: Map containing optional parameters eg + * The sample-detector distance (in metres) + * The scattering angle (in radians) + * Fixed energy: EI (emode=1) or EF (emode=2)(in meV) + * Delta (not currently used) */ void toTOF(std::vector<double> &xdata, std::vector<double> &ydata, - const double &_l1, const double &_l2, const double &_twoTheta, - const int &_emode, const double &_efixed, const double &_delta); + const double &_l1, const int &_emode, + std::initializer_list<std::pair<const UnitParams, double>> params); + void toTOF(std::vector<double> &xdata, std::vector<double> &ydata, + const double &_l1, const int &_emode, + const UnitParametersMap ¶ms); /** Convert from the concrete unit to time-of-flight. TOF is in microseconds. * @param xvalue :: A single X-value to convert * @param l1 :: The source-sample distance (in metres) - * @param l2 :: The sample-detector distance (in metres) - * @param twoTheta :: The scattering angle (in radians) * @param emode :: The energy mode (0=elastic, 1=direct geometry, * 2=indirect geometry) - * @param efixed :: Value of fixed energy: EI (emode=1) or EF (emode=2) (in - * meV) - * @param delta :: Not currently used + * @param params :: Map containing optional parameters eg + * The sample-detector distance (in metres) + * The scattering angle (in radians) + * Fixed energy: EI (emode=1) or EF (emode=2)(in meV) + * Delta (not currently used) * @return the value in TOF units. */ double convertSingleToTOF(const double xvalue, const double &l1, - const double &l2, const double &twoTheta, - const int &emode, const double &efixed, - const double &delta); + const int &emode, const UnitParametersMap ¶ms); /** Convert from time-of-flight to the concrete unit. TOF is in microseconds. * @param xdata :: The array of X data to be converted * @param ydata :: Not currently used (ConvertUnits passes an empty * vector) * @param _l1 :: The source-sample distance (in metres) - * @param _l2 :: The sample-detector distance (in metres) - * @param _twoTheta :: The scattering angle (in radians) * @param _emode :: The energy mode (0=elastic, 1=direct geometry, * 2=indirect geometry) - * @param _efixed :: Value of fixed energy: EI (emode=1) or EF (emode=2) - * (in - * meV) - * @param _delta :: Not currently used + * @param params :: Map containing optional parameters eg + * The sample-detector distance (in metres) + * The scattering angle (in radians) + * Fixed energy: EI (emode=1) or EF (emode=2)(in meV) + * Delta (not currently used) */ + void + fromTOF(std::vector<double> &xdata, std::vector<double> &ydata, + const double &_l1, const int &_emode, + std::initializer_list<std::pair<const UnitParams, double>> params); + void fromTOF(std::vector<double> &xdata, std::vector<double> &ydata, - const double &_l1, const double &_l2, const double &_twoTheta, - const int &_emode, const double &_efixed, const double &_delta); + const double &_l1, const int &_emode, + const UnitParametersMap ¶ms); /** Convert from the time-of-flight to the concrete unit. TOF is in * microseconds. * @param xvalue :: A single X-value to convert * @param l1 :: The source-sample distance (in metres) - * @param l2 :: The sample-detector distance (in metres) - * @param twoTheta :: The scattering angle (in radians) * @param emode :: The energy mode (0=elastic, 1=direct geometry, * 2=indirect geometry) - * @param efixed :: Value of fixed energy: EI (emode=1) or EF (emode=2) (in - * meV) - * @param delta :: Not currently used + * @param params :: Map containing optional parameters eg + * The sample-detector distance (in metres) + * The scattering angle (in radians) + * Fixed energy: EI (emode=1) or EF (emode=2)(in meV) + * Delta (not currently used) * @return the value in these units. */ double convertSingleFromTOF(const double xvalue, const double &l1, - const double &l2, const double &twoTheta, - const int &emode, const double &efixed, - const double &delta); + const int &emode, + const UnitParametersMap ¶ms); /** Initialize the unit to perform conversion using singleToTof() and *singleFromTof() * * @param _l1 :: The source-sample distance (in metres) - * @param _l2 :: The sample-detector distance (in metres) - * @param _twoTheta :: The scattering angle (in radians) * @param _emode :: The energy mode (0=elastic, 1=direct geometry, *2=indirect geometry) - * @param _efixed :: Value of fixed energy: EI (emode=1) or EF (emode=2) - *(in meV) - * @param _delta :: Not currently used + * @param params :: map containing other optional parameters: + * The sample-detector distance (in metres) + * The scattering angle (in radians) + * Fixed energy: EI (emode=1) or EF (emode=2) (in meV) + * Diffractometer constants (DIFA, DIFC, TZERO) + * Delta: unused */ - void initialize(const double &_l1, const double &_l2, const double &_twoTheta, - const int &_emode, const double &_efixed, - const double &_delta); + void initialize(const double &_l1, const int &_emode, + const UnitParametersMap ¶ms); /** Finalize the initialization. This will be overridden by subclasses as * needed. */ @@ -194,21 +204,25 @@ protected: void addConversion(std::string to, const double &factor, const double &power = 1.0) const; + // validate the contents of the unit parameters map. Throw + // std::invalid_argument if it's a global error or std::runtime_error if it's + // a detector specific error + virtual void validateUnitParams(const int emode, + const UnitParametersMap ¶ms); + /// The unit values have been initialized bool initialized; /// l1 :: The source-sample distance (in metres) double l1; - /// l2 :: The sample-detector distance (in metres) - double l2; - /// twoTheta :: The scattering angle (in radians) - double twoTheta; /// emode :: The energy mode (0=elastic, 1=direct geometry, 2=indirect /// geometry) int emode; + /// additional parameters + /// l2 :: distance from sample to detector (in metres) + /// twoTheta :: scattering angle in radians /// efixed :: Value of fixed energy: EI (emode=1) or EF (emode=2) (in meV) - double efixed; - /// delta :: Not currently used - double delta; + /// difc :: diffractometer constant DIFC + const UnitParametersMap *m_params; private: /// A 'quick conversion' requires the constant by which to multiply the input @@ -318,6 +332,9 @@ public: Wavelength(); protected: + void validateUnitParams(const int emode, + const UnitParametersMap ¶ms) override; + double efixed; double sfpTo; ///< Extra correction factor in to conversion double factorTo; ///< Constant factor for to conversion double sfpFrom; ///< Extra correction factor in from conversion @@ -368,10 +385,16 @@ public: Energy_inWavenumber(); protected: + void validateUnitParams(const int emode, + const UnitParametersMap ¶ms) override; double factorTo; ///< Constant factor for to conversion double factorFrom; ///< Constant factor for from conversion }; +MANTID_KERNEL_DLL double tofToDSpacingFactor(const double l1, const double l2, + const double twoTheta, + const double offset); + //================================================================================================= /// d-Spacing in Angstrom class MANTID_KERNEL_DLL dSpacing : public Unit { @@ -379,20 +402,27 @@ public: const std::string unitID() const override; ///< "dSpacing" const std::string caption() const override { return "d-Spacing"; } const UnitLabel label() const override; - double singleToTOF(const double x) const override; double singleFromTOF(const double tof) const override; void init() override; Unit *clone() const override; double conversionTOFMin() const override; double conversionTOFMax() const override; + double calcTofMin(const double difc, const double difa, const double tzero, + const double tofmin = 0.); + double calcTofMax(const double difc, const double difa, const double tzero, + const double tofmax = 0.); /// Constructor dSpacing(); protected: - double factorTo; ///< Constant factor for to conversion - double factorFrom; ///< Constant factor for from conversion + void validateUnitParams(const int emode, + const UnitParametersMap ¶ms) override; + std::string toDSpacingError; + double difa; + double difc; + double tzero; }; //================================================================================================= @@ -416,6 +446,9 @@ public: dSpacingPerpendicular(); protected: + void validateUnitParams(const int emode, + const UnitParametersMap ¶ms) override; + double twoTheta; double factorTo; ///< Constant factor for to conversion double sfpTo; ///< Extra correction factor in to conversion double factorFrom; ///< Constant factor for from conversion @@ -440,13 +473,14 @@ public: MomentumTransfer(); protected: - double factorTo; ///< Constant factor for to conversion - double factorFrom; ///< Constant factor for from conversion + void validateUnitParams(const int emode, + const UnitParametersMap ¶ms) override; + double difc; }; //================================================================================================= /// Momentum transfer squared in Angstrom^-2 -class MANTID_KERNEL_DLL QSquared : public Unit { +class MANTID_KERNEL_DLL QSquared : public MomentumTransfer { public: const std::string unitID() const override; ///< "QSquared" const std::string caption() const override { return "Q2"; } @@ -454,17 +488,12 @@ public: double singleToTOF(const double x) const override; double singleFromTOF(const double tof) const override; - void init() override; Unit *clone() const override; double conversionTOFMin() const override; double conversionTOFMax() const override; /// Constructor QSquared(); - -protected: - double factorTo; ///< Constant factor for to conversion - double factorFrom; ///< Constant factor for from conversion }; //================================================================================================= @@ -487,6 +516,9 @@ public: DeltaE(); protected: + void validateUnitParams(const int emode, + const UnitParametersMap ¶ms) override; + double efixed; double factorTo; ///< Constant factor for to conversion double factorFrom; ///< Constant factor for from conversion double t_other; ///< Energy mode dependent factor in to conversion @@ -545,6 +577,9 @@ public: Momentum(); protected: + void validateUnitParams(const int emode, + const UnitParametersMap ¶ms) override; + double efixed; double sfpTo; ///< Extra correction factor in to conversion double factorTo; ///< Constant factor for to conversion double sfpFrom; ///< Extra correction factor in from conversion @@ -569,6 +604,9 @@ public: /// Constructor SpinEchoLength(); + +private: + double efixed; }; //================================================================================================= @@ -588,6 +626,9 @@ public: /// Constructor SpinEchoTime(); + +private: + double efixed; }; //================================================================================================= diff --git a/Framework/Kernel/inc/MantidKernel/UnitConversion.h b/Framework/Kernel/inc/MantidKernel/UnitConversion.h index 327c4f8bdb53af2dfb6fe7cf83c5f42fefa18b13..dc11da623d116314b49a73370ef9a4668641eab9 100644 --- a/Framework/Kernel/inc/MantidKernel/UnitConversion.h +++ b/Framework/Kernel/inc/MantidKernel/UnitConversion.h @@ -8,6 +8,7 @@ #include "MantidKernel/DeltaEMode.h" #include "MantidKernel/DllConfig.h" +#include "MantidKernel/Unit.h" #include <string> namespace Mantid { @@ -27,10 +28,14 @@ public: const double srcValue, const double l1, const double l2, const double theta, const DeltaEMode::Type emode, const double efixed); + static double run(const std::string &src, const std::string &dest, + const double srcValue, const double l1, + const DeltaEMode::Type emode, + const UnitParametersMap ¶ms = {}); /// Convert a single value between the given units static double run(Unit &srcUnit, Unit &destUnit, const double srcValue, - const double l1, const double l2, const double theta, - const DeltaEMode::Type emode, const double efixed); + const double l1, const DeltaEMode::Type emode, + const UnitParametersMap ¶ms = {}); /// Convert to ElasticQ from Energy static double convertToElasticQ(const double theta, const double efixed); @@ -42,9 +47,8 @@ private: /// Convert through TOF static double convertViaTOF(Unit &srcUnit, Unit &destUnit, const double srcValue, const double l1, - const double l2, const double theta, const DeltaEMode::Type emode, - const double efixed); + const UnitParametersMap ¶ms); }; } // namespace Kernel diff --git a/Framework/Kernel/src/Diffraction.cpp b/Framework/Kernel/src/Diffraction.cpp deleted file mode 100644 index 1c9e4d64d88f5ece2e7ed09f879887d8db9bf1cd..0000000000000000000000000000000000000000 --- a/Framework/Kernel/src/Diffraction.cpp +++ /dev/null @@ -1,173 +0,0 @@ -// Mantid Repository : https://github.com/mantidproject/mantid -// -// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, -// NScD Oak Ridge National Laboratory, European Spallation Source, -// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS -// SPDX - License - Identifier: GPL - 3.0 + -#include "MantidKernel/Diffraction.h" -#include <algorithm> -#include <cmath> - -namespace Mantid { -namespace Kernel { -namespace Diffraction { - -double calcTofMin(const double difc, const double difa, const double tzero, - const double tofmin) { - if (difa == 0.) { - if (tzero != 0.) { - // check for negative d-spacing - return std::max<double>(tzero, tofmin); - } - } else if (difa > 0.) { - // check for imaginary part in quadratic equation - return std::max<double>(tzero - .25 * difc * difc / difa, tofmin); - } - - // everything else is fine so just return supplied tofmin - return tofmin; -} - -/** - * Returns the maximum TOF that can be used or tofmax. Whichever is smaller. In - * the case when this is a negative number, just return 0. - */ -double calcTofMax(const double difc, const double difa, const double tzero, - const double tofmax) { - if (difa < 0.) { - // check for imaginary part in quadratic equation - if (tzero > 0.) { - // rather than calling abs multiply difa by -1 - return std::min<double>(tzero + .25 * difc * difc / difa, tofmax); - } else { - return 0.; - } - } - - // everything else is fine so just return supplied tofmax - return tofmax; -} - -// ---------------------------------------------------------------------------- -// convert from d-spacing to time-of-flight -namespace { // anonymous namespace -/// Applies the equation d=(TOF-tzero)/difc -struct tof_to_d_difc_only { - explicit tof_to_d_difc_only(const double difc) : factor(1. / difc) {} - - double operator()(const double tof) const { return factor * tof; } - - /// 1./difc - double factor; -}; - -/// Applies the equation d=(TOF-tzero)/difc -struct tof_to_d_difc_and_tzero { - explicit tof_to_d_difc_and_tzero(const double difc, const double tzero) - : factor(1. / difc), offset(-1. * tzero / difc) {} - - double operator()(const double tof) const { return factor * tof + offset; } - - /// 1./difc - double factor; - /// -tzero/difc - double offset; -}; - -struct tof_to_d { - explicit tof_to_d(const double difc, const double difa, const double tzero) { - factor1 = -0.5 * difc / difa; - factor2 = 1. / difa; - factor3 = (factor1 * factor1) - (tzero / difa); - } - - double operator()(const double tof) const { - double second = std::sqrt((tof * factor2) + factor3); - if (second < factor1) - return factor1 - second; - else { - return factor1 + second; - } - } - - /// -0.5*difc/difa - double factor1; - /// 1/difa - double factor2; - /// (0.5*difc/difa)^2 - (tzero/difa) - double factor3; -}; -} // anonymous namespace - -std::function<double(double)> getTofToDConversionFunc(const double difc, - const double difa, - const double tzero) { - if (difa == 0.) { - if (tzero == 0.) { - return tof_to_d_difc_only(difc); - } else { - return tof_to_d_difc_and_tzero(difc, tzero); - } - } else { // difa != 0. - return tof_to_d(difc, difa, tzero); - } -} - -// ---------------------------------------------------------------------------- -// convert from d-spacing to time-of-flight -namespace { // anonymous namespace -struct d_to_tof_difc_only { - explicit d_to_tof_difc_only(const double difc) { this->difc = difc; } - - double operator()(const double dspacing) const { return difc * dspacing; } - - double difc; -}; - -struct d_to_tof_difc_and_tzero { - explicit d_to_tof_difc_and_tzero(const double difc, const double tzero) { - this->difc = difc; - this->tzero = tzero; - } - - double operator()(const double dspacing) const { - return difc * dspacing + tzero; - } - - double difc; - double tzero; -}; - -struct d_to_tof { - explicit d_to_tof(const double difc, const double difa, const double tzero) { - this->difc = difc; - this->difa = difa; - this->tzero = tzero; - } - - double operator()(const double dspacing) const { - return difc * dspacing + difa * dspacing * dspacing + tzero; - } - - double difc; - double difa; - double tzero; -}; -} // anonymous namespace - -std::function<double(double)> getDToTofConversionFunc(const double difc, - const double difa, - const double tzero) { - if (difa == 0.) { - if (tzero == 0.) - return d_to_tof_difc_only(difc); - else - return d_to_tof_difc_and_tzero(difc, tzero); - } else { - return d_to_tof(difc, difa, tzero); - } -} - -} // namespace Diffraction -} // namespace Kernel -} // namespace Mantid diff --git a/Framework/Kernel/src/Unit.cpp b/Framework/Kernel/src/Unit.cpp index b74bedb91b19f2fd20cfc04efc09c58d8ed36e5f..5c831c7b9b1bf4a4f284c06bc472f4f4614b1e51 100644 --- a/Framework/Kernel/src/Unit.cpp +++ b/Framework/Kernel/src/Unit.cpp @@ -8,21 +8,41 @@ // Includes //---------------------------------------------------------------------- #include "MantidKernel/Unit.h" +#include "MantidKernel/Logger.h" #include "MantidKernel/PhysicalConstants.h" #include "MantidKernel/UnitFactory.h" #include "MantidKernel/UnitLabelTypes.h" #include <cfloat> +#include <sstream> namespace Mantid { namespace Kernel { +namespace { +// static logger object +Logger g_log("Unit"); + +bool ParamPresent(const UnitParametersMap ¶ms, UnitParams param) { + return params.find(param) != params.end(); +} + +bool ParamPresentAndSet(const UnitParametersMap *params, UnitParams param, + double &var) { + auto it = params->find(param); + if (it != params->end()) { + var = it->second; + return true; + } else { + return false; + } +} +} // namespace + /** * Default constructor * Gives the unit an empty UnitLabel */ -Unit::Unit() - : initialized(false), l1(0), l2(0), twoTheta(0), emode(0), efixed(0), - delta(0) {} +Unit::Unit() : initialized(false), l1(0), emode(0) {} bool Unit::operator==(const Unit &u) const { return unitID() == u.unitID(); } @@ -108,36 +128,43 @@ void Unit::addConversion(std::string to, const double &factor, *singleFromTof() * * @param _l1 :: The source-sample distance (in metres) - * @param _l2 :: The sample-detector distance (in metres) - * @param _twoTheta :: The scattering angle (in radians) * @param _emode :: The energy mode (0=elastic, 1=direct geometry, *2=indirect geometry) - * @param _efixed :: Value of fixed energy: EI (emode=1) or EF (emode=2) (in - *meV) - * @param _delta :: Not currently used + * @param params :: Map containing optional parameters eg + * The sample-detector distance (in metres) + * The scattering angle (in radians) + * Fixed energy: EI (emode=1) or EF (emode=2)(in meV) + * Delta (not currently used) */ -void Unit::initialize(const double &_l1, const double &_l2, - const double &_twoTheta, const int &_emode, - const double &_efixed, const double &_delta) { +void Unit::initialize(const double &_l1, const int &_emode, + const UnitParametersMap ¶ms) { l1 = _l1; - l2 = _l2; - twoTheta = _twoTheta; + validateUnitParams(_emode, params); emode = _emode; - efixed = _efixed; - delta = _delta; + m_params = ¶ms; initialized = true; this->init(); } +void Unit::validateUnitParams(const int, const UnitParametersMap &) {} + //--------------------------------------------------------------------------------------- /** Perform the conversion to TOF on a vector of data */ + +void Unit::toTOF( + std::vector<double> &xdata, std::vector<double> &ydata, const double &_l1, + const int &_emode, + std::initializer_list<std::pair<const UnitParams, double>> params) { + UnitParametersMap paramsMap(params); + toTOF(xdata, ydata, _l1, _emode, paramsMap); +} + void Unit::toTOF(std::vector<double> &xdata, std::vector<double> &ydata, - const double &_l1, const double &_l2, const double &_twoTheta, - const int &_emode, const double &_efixed, - const double &_delta) { + const double &_l1, const int &_emode, + const UnitParametersMap ¶ms) { UNUSED_ARG(ydata); - this->initialize(_l1, _l2, _twoTheta, _emode, _efixed, _delta); + this->initialize(_l1, _emode, params); size_t numX = xdata.size(); for (size_t i = 0; i < numX; i++) xdata[i] = this->singleToTOF(xdata[i]); @@ -146,29 +173,32 @@ void Unit::toTOF(std::vector<double> &xdata, std::vector<double> &ydata, /** Convert a single value to TOF @param xvalue @param l1 -@param l2 -@param twoTheta @param emode -@param efixed -@param delta +@param params (eg efixed or delta) */ double Unit::convertSingleToTOF(const double xvalue, const double &l1, - const double &l2, const double &twoTheta, - const int &emode, const double &efixed, - const double &delta) { - this->initialize(l1, l2, twoTheta, emode, efixed, delta); + const int &emode, + const UnitParametersMap ¶ms) { + this->initialize(l1, emode, params); return this->singleToTOF(xvalue); } //--------------------------------------------------------------------------------------- /** Perform the conversion to TOF on a vector of data */ +void Unit::fromTOF( + std::vector<double> &xdata, std::vector<double> &ydata, const double &_l1, + const int &_emode, + std::initializer_list<std::pair<const UnitParams, double>> params) { + UnitParametersMap paramsMap(params); + fromTOF(xdata, ydata, _l1, _emode, paramsMap); +} + void Unit::fromTOF(std::vector<double> &xdata, std::vector<double> &ydata, - const double &_l1, const double &_l2, - const double &_twoTheta, const int &_emode, - const double &_efixed, const double &_delta) { + const double &_l1, const int &_emode, + const UnitParametersMap ¶ms) { UNUSED_ARG(ydata); - this->initialize(_l1, _l2, _twoTheta, _emode, _efixed, _delta); + this->initialize(_l1, _emode, params); size_t numX = xdata.size(); for (size_t i = 0; i < numX; i++) xdata[i] = this->singleFromTOF(xdata[i]); @@ -177,17 +207,13 @@ void Unit::fromTOF(std::vector<double> &xdata, std::vector<double> &ydata, /** Convert a single value from TOF @param xvalue @param l1 -@param l2 -@param twoTheta @param emode -@param efixed -@param delta +@param params (eg efixed or delta) */ double Unit::convertSingleFromTOF(const double xvalue, const double &l1, - const double &l2, const double &twoTheta, - const int &emode, const double &efixed, - const double &delta) { - this->initialize(l1, l2, twoTheta, emode, efixed, delta); + const int &emode, + const UnitParametersMap ¶ms) { + this->initialize(l1, emode, params); return this->singleFromTOF(xvalue); } @@ -302,7 +328,7 @@ double TOF::conversionTOFMax() const { return DBL_MAX; } DECLARE_UNIT(Wavelength) Wavelength::Wavelength() - : Unit(), sfpTo(DBL_MIN), factorTo(DBL_MIN), sfpFrom(DBL_MIN), + : Unit(), efixed(0.), sfpTo(DBL_MIN), factorTo(DBL_MIN), sfpFrom(DBL_MIN), factorFrom(DBL_MIN), do_sfpFrom(false) { const double AngstromsSquared = 1e20; const double factor = @@ -316,13 +342,31 @@ Wavelength::Wavelength() const UnitLabel Wavelength::label() const { return Symbol::Angstrom; } +void Wavelength::validateUnitParams(const int emode, + const UnitParametersMap ¶ms) { + if (!ParamPresent(params, UnitParams::l2)) { + throw std::runtime_error("An l2 value must be supplied in the extra " + "parameters when initialising " + + this->unitID() + " for conversion via TOF"); + } + if ((emode != 0) && (!ParamPresent(params, UnitParams::efixed))) { + throw std::runtime_error("An efixed value must be supplied in the extra " + "parameters when initialising " + + this->unitID() + " for conversion via TOF"); + } +} + void Wavelength::init() { // ------------ Factors to convert TO TOF --------------------- + double l2 = 0.0; double ltot = 0.0; double TOFisinMicroseconds = 1e6; double toAngstroms = 1e10; sfpTo = 0.0; + ParamPresentAndSet(m_params, UnitParams::efixed, efixed); + ParamPresentAndSet(m_params, UnitParams::l2, l2); + if (emode == 1) { ltot = l2; sfpTo = @@ -432,6 +476,8 @@ Energy::Energy() : Unit(), factorTo(DBL_MIN), factorFrom(DBL_MIN) { } void Energy::init() { + double l2 = 0.0; + ParamPresentAndSet(m_params, UnitParams::l2, l2); { const double TOFinMicroseconds = 1e6; factorTo = @@ -490,7 +536,18 @@ Energy_inWavenumber::Energy_inWavenumber() addConversion("Momentum", 2 * M_PI / factor, 0.5); } +void Energy_inWavenumber::validateUnitParams(const int, + const UnitParametersMap ¶ms) { + if (!ParamPresent(params, UnitParams::l2)) { + throw std::runtime_error("An l2 value must be supplied in the extra " + "parameters when initialising " + + this->unitID() + " for conversion via TOF"); + } +} + void Energy_inWavenumber::init() { + double l2 = 0.0; + ParamPresentAndSet(m_params, UnitParams::l2, l2); { const double TOFinMicroseconds = 1e6; factorTo = sqrt(PhysicalConstants::NeutronMass * @@ -541,39 +598,188 @@ Unit *Energy_inWavenumber::clone() const { * * Conversion uses Bragg's Law: 2d sin(theta) = n * lambda */ -DECLARE_UNIT(dSpacing) -const UnitLabel dSpacing::label() const { return Symbol::Angstrom; } +const double CONSTANT = (PhysicalConstants::h * 1e10) / + (2.0 * PhysicalConstants::NeutronMass * 1e6); + +/** + * Calculate and return conversion factor from tof to d-spacing. + * @param l1 + * @param l2 + * @param twoTheta scattering angle + * @param offset + * @return + */ +double tofToDSpacingFactor(const double l1, const double l2, + const double twoTheta, const double offset) { + if (offset <= + -1.) // not physically possible, means result is negative d-spacing + { + std::stringstream msg; + msg << "Encountered offset of " << offset + << " which converts data to negative d-spacing\n"; + throw std::logic_error(msg.str()); + } + + auto sinTheta = std::sin(twoTheta / 2); + + const double numerator = (1.0 + offset); + sinTheta *= (l1 + l2); + + return (numerator * CONSTANT) / sinTheta; +} + +DECLARE_UNIT(dSpacing) -dSpacing::dSpacing() : Unit(), factorTo(DBL_MIN), factorFrom(DBL_MIN) { +dSpacing::dSpacing() + : Unit(), toDSpacingError(""), difa(0), difc(DBL_MIN), tzero(0) { const double factor = 2.0 * M_PI; addConversion("MomentumTransfer", factor, -1.0); addConversion("QSquared", (factor * factor), -2.0); } +const UnitLabel dSpacing::label() const { return Symbol::Angstrom; } + +Unit *dSpacing::clone() const { return new dSpacing(*this); } + +void dSpacing::validateUnitParams(const int, const UnitParametersMap ¶ms) { + double difc = 0.; + if (!ParamPresentAndSet(¶ms, UnitParams::difc, difc)) { + if (!ParamPresent(params, UnitParams::twoTheta) || + (!ParamPresent(params, UnitParams::l2))) + throw std::runtime_error("A difc value or L2/two theta must be supplied " + "in the extra parameters when initialising " + + this->unitID() + " for conversion via TOF"); + } else { + // check validations only applicable to fromTOF + toDSpacingError = ""; + double difa = 0.; + ParamPresentAndSet(¶ms, UnitParams::difa, difa); + if ((difa == 0) && (difc == 0)) { + toDSpacingError = "Cannot convert to d spacing with DIFA=0 and DIFC=0"; + }; + // singleFromTOF currently assuming difc not negative + if (difc < 0.) { + toDSpacingError = + "A positive difc value must be supplied in the extra parameters when " + "initialising " + + this->unitID() + " for conversion via TOF"; + } + } +} + void dSpacing::init() { // First the crux of the conversion - factorTo = - (2.0 * PhysicalConstants::NeutronMass * sin(twoTheta / 2.0) * (l1 + l2)) / - PhysicalConstants::h; + difa = 0.; + difc = 0.; + tzero = 0.; + ParamPresentAndSet(m_params, UnitParams::difa, difa); + ParamPresentAndSet(m_params, UnitParams::tzero, tzero); + + if (!ParamPresentAndSet(m_params, UnitParams::difc, difc)) { + // also support inputs as L2, two theta + double l2; + if (ParamPresentAndSet(m_params, UnitParams::l2, l2)) { + double twoTheta; + if (ParamPresentAndSet(m_params, UnitParams::twoTheta, twoTheta)) { + if (difa != 0.) { + g_log.warning("Supplied difa ignored"); + difa = 0.; + } + difc = 1. / tofToDSpacingFactor(l1, l2, twoTheta, 0.); + if (tzero != 0.) { + g_log.warning("Supplied tzero ignored"); + tzero = 0.; + } + } + } + } +} - // Now adjustments for the scale of units used - const double TOFisinMicroseconds = 1e6; - const double toAngstroms = 1e10; - factorTo *= TOFisinMicroseconds / toAngstroms; - factorFrom = factorTo; - if (factorFrom == 0.0) - factorFrom = DBL_MIN; // Protect against divide by zero +double dSpacing::singleToTOF(const double x) const { + if (!isInitialized()) + throw std::runtime_error("dSpacingBase::singleToTOF called before object " + "has been initialized."); + return difa * x * x + difc * x + tzero; } -double dSpacing::singleToTOF(const double x) const { return x * factorTo; } double dSpacing::singleFromTOF(const double tof) const { - return tof / factorFrom; + if (!isInitialized()) + throw std::runtime_error("dSpacingBase::singleFromTOF called before object " + "has been initialized."); + if (!toDSpacingError.empty()) + throw std::runtime_error(toDSpacingError); + // handle special cases first... + if (tof == tzero) { + if (difa != 0) + return -difc / difa; + } + if ((difc * difc - 4 * difa * (tzero - tof)) < 0) { + throw std::runtime_error( + "Cannot convert to d spacing. Quadratic doesn't have real roots"); + } + if ((difa > 0) && ((tzero - tof) > 0)) { + throw std::runtime_error("Cannot convert to d spacing. Quadratic doesn't " + "have a positive root"); + } + // and then solve quadratic using Muller formula + double sqrtTerm; + if (difa == 0) { + // avoid costly sqrt even though formula reduces to this + sqrtTerm = difc; + } else { + sqrtTerm = sqrt(difc * difc - 4 * difa * (tzero - tof)); + } + if (sqrtTerm < difc) + return (tof - tzero) / (0.5 * (difc - sqrtTerm)); + else + return (tof - tzero) / (0.5 * (difc + sqrtTerm)); +} +double dSpacing::conversionTOFMin() const { + // quadratic only has a min if difa is positive + if (difa > 0) { + // min of the quadratic is at d=-difc/(2*difa) + return std::max(0., tzero - difc * difc / (4 * difa)); + } else { + // no min so just pick value closest to zero that works + double TOFmin = singleToTOF(0.); + if (TOFmin < std::numeric_limits<double>::min()) { + TOFmin = 0.; + } + return TOFmin; + } +} +double dSpacing::conversionTOFMax() const { + // quadratic only has a max if difa is negative + if (difa < 0) { + return std::min(DBL_MAX, tzero - difc * difc / (4 * difa)); + } else { + // no max so just pick value closest to DBL_MAX that works + double TOFmax = singleToTOF(DBL_MAX); + if (std::isinf(TOFmax)) { + TOFmax = DBL_MAX; + } + return TOFmax; + } } -double dSpacing::conversionTOFMin() const { return 0; } -double dSpacing::conversionTOFMax() const { return DBL_MAX / factorTo; } -Unit *dSpacing::clone() const { return new dSpacing(*this); } +double dSpacing::calcTofMin(const double difc, const double difa, + const double tzero, const double tofmin) { + Kernel::UnitParametersMap params{{Kernel::UnitParams::difa, difa}, + {Kernel::UnitParams::difc, difc}, + {Kernel::UnitParams::tzero, tzero}}; + initialize(-1., 0, params); + return std::max(conversionTOFMin(), tofmin); +} + +double dSpacing::calcTofMax(const double difc, const double difa, + const double tzero, const double tofmax) { + Kernel::UnitParametersMap params{{Kernel::UnitParams::difa, difa}, + {Kernel::UnitParams::difc, difc}, + {Kernel::UnitParams::tzero, tzero}}; + initialize(-1, 0, params); + return std::min(conversionTOFMax(), tofmax); +} // ================================================================================================== /* D-SPACING Perpendicular @@ -590,7 +796,26 @@ const UnitLabel dSpacingPerpendicular::label() const { dSpacingPerpendicular::dSpacingPerpendicular() : Unit(), factorTo(DBL_MIN), factorFrom(DBL_MIN) {} +void dSpacingPerpendicular::validateUnitParams( + const int, const UnitParametersMap ¶ms) { + if (!ParamPresent(params, UnitParams::l2)) { + throw std::runtime_error( + "A l2 value must be supplied in the extra parameters when " + "initialising " + + this->unitID() + " for conversion via TOF"); + } + if (!ParamPresent(params, UnitParams::twoTheta)) { + throw std::runtime_error( + "A two theta value must be supplied in the extra parameters when " + "initialising " + + this->unitID() + " for conversion via TOF"); + } +} + void dSpacingPerpendicular::init() { + double l2 = 0.0; + ParamPresentAndSet(m_params, UnitParams::l2, l2); + ParamPresentAndSet(m_params, UnitParams::twoTheta, twoTheta); factorTo = (PhysicalConstants::NeutronMass * (l1 + l2)) / PhysicalConstants::h; @@ -642,47 +867,50 @@ const UnitLabel MomentumTransfer::label() const { return Symbol::InverseAngstrom; } -MomentumTransfer::MomentumTransfer() - : Unit(), factorTo(DBL_MIN), factorFrom(DBL_MIN) { +MomentumTransfer::MomentumTransfer() : Unit() { addConversion("QSquared", 1.0, 2.0); const double factor = 2.0 * M_PI; addConversion("dSpacing", factor, -1.0); } +void MomentumTransfer::validateUnitParams(const int, + const UnitParametersMap ¶ms) { + double difc = 0.; + if (!ParamPresentAndSet(¶ms, UnitParams::difc, difc)) { + if (!ParamPresent(params, UnitParams::twoTheta) || + (!ParamPresent(params, UnitParams::l2))) + throw std::runtime_error("A difc value or L2/two theta must be supplied " + "in the extra parameters when initialising " + + this->unitID() + " for conversion via TOF"); + }; +} + void MomentumTransfer::init() { // First the crux of the conversion - factorTo = (4.0 * M_PI * PhysicalConstants::NeutronMass * (l1 + l2) * - sin(twoTheta / 2.0)) / - PhysicalConstants::h; - // Now adjustments for the scale of units used - const double TOFisinMicroseconds = 1e6; - const double toAngstroms = 1e10; - factorTo *= TOFisinMicroseconds / toAngstroms; - // First the crux of the conversion - factorFrom = (4.0 * M_PI * PhysicalConstants::NeutronMass * (l1 + l2) * - sin(twoTheta / 2.0)) / - PhysicalConstants::h; - - // Now adjustments for the scale of units used - factorFrom *= TOFisinMicroseconds / toAngstroms; + difc = 0.; + + if (!ParamPresentAndSet(m_params, UnitParams::difc, difc)) { + // also support inputs as L2, two theta + double l2; + if (ParamPresentAndSet(m_params, UnitParams::l2, l2)) { + double twoTheta; + if (ParamPresentAndSet(m_params, UnitParams::twoTheta, twoTheta)) { + difc = 1. / tofToDSpacingFactor(l1, l2, twoTheta, 0.); + } + } + } } double MomentumTransfer::singleToTOF(const double x) const { - double temp = x; - if (temp == 0.0) - temp = DBL_MIN; // Protect against divide by zero - return factorTo / temp; + return 2. * M_PI * difc / x; } // double MomentumTransfer::singleFromTOF(const double tof) const { - double temp = tof; - if (temp == 0.0) - temp = DBL_MIN; // Protect against divide by zero - return factorFrom / temp; + return 2. * M_PI * difc / tof; } double MomentumTransfer::conversionTOFMin() const { - return factorFrom / DBL_MAX; + return 2. * M_PI * difc / DBL_MAX; } double MomentumTransfer::conversionTOFMax() const { return DBL_MAX; } @@ -696,55 +924,27 @@ DECLARE_UNIT(QSquared) const UnitLabel QSquared::label() const { return Symbol::InverseAngstromSq; } -QSquared::QSquared() : Unit(), factorTo(DBL_MIN), factorFrom(DBL_MIN) { +QSquared::QSquared() : MomentumTransfer() { addConversion("MomentumTransfer", 1.0, 0.5); const double factor = 2.0 * M_PI; addConversion("dSpacing", factor, -0.5); } -void QSquared::init() { - // First the crux of the conversion - factorTo = (4.0 * M_PI * PhysicalConstants::NeutronMass * (l1 + l2) * - sin(twoTheta / 2.0)) / - PhysicalConstants::h; - // Now adjustments for the scale of units used - const double TOFisinMicroseconds = 1e6; - const double toAngstroms = 1e10; - factorTo *= TOFisinMicroseconds / toAngstroms; - - // First the crux of the conversion - factorFrom = (4.0 * M_PI * PhysicalConstants::NeutronMass * (l1 + l2) * - sin(twoTheta / 2.0)) / - PhysicalConstants::h; - // Now adjustments for the scale of units used - factorFrom *= TOFisinMicroseconds / toAngstroms; - factorFrom = factorFrom * factorFrom; -} - double QSquared::singleToTOF(const double x) const { - double temp = x; - if (temp == 0.0) - temp = DBL_MIN; // Protect against divide by zero - return factorTo / sqrt(temp); + return MomentumTransfer::singleToTOF(sqrt(x)); } double QSquared::singleFromTOF(const double tof) const { - double temp = tof; - if (temp == 0.0) - temp = DBL_MIN; // Protect against divide by zero - return factorFrom / (temp * temp); + return pow(MomentumTransfer::singleFromTOF(tof), 2); } double QSquared::conversionTOFMin() const { - if (factorTo > 0) - return factorTo / sqrt(DBL_MAX); - else - return -sqrt(DBL_MAX); + return 2 * M_PI * difc / sqrt(DBL_MAX); } double QSquared::conversionTOFMax() const { - if (factorTo > 0) - return sqrt(DBL_MAX); - else - return factorTo / sqrt(DBL_MAX); + double tofmax = 2 * M_PI * difc / sqrt(DBL_MIN); + if (std::isinf(tofmax)) + tofmax = DBL_MAX; + return tofmax; } Unit *QSquared::clone() const { return new QSquared(*this); } @@ -764,11 +964,38 @@ DeltaE::DeltaE() addConversion("DeltaE_inFrequency", PhysicalConstants::meVtoFrequency, 1.); } -void DeltaE::init() { - // Efixed must be set to something - if (efixed == 0.0) +void DeltaE::validateUnitParams(const int emode, + const UnitParametersMap ¶ms) { + if (emode != 1 && emode != 2) { throw std::invalid_argument( - "efixed must be set for energy transfer calculation"); + "emode must be equal to 1 or 2 for energy transfer calculation"); + } + // Efixed must be set to something + double efixed; + if (!ParamPresentAndSet(¶ms, UnitParams::efixed, efixed)) { + if (emode == 1) { // direct, efixed=ei + throw std::invalid_argument( + "efixed must be set for energy transfer calculation"); + } else { + throw std::runtime_error( + "efixed must be set for energy transfer calculation"); + } + } + if (efixed <= 0) { + throw std::runtime_error("efixed must be greater than zero"); + } + if (!ParamPresent(params, UnitParams::l2)) { + throw std::runtime_error( + "A l2 value must be supplied in the extra parameters when " + "initialising " + + this->unitID() + " for conversion via TOF"); + } +} + +void DeltaE::init() { + double l2 = 0.0; + ParamPresentAndSet(m_params, UnitParams::l2, l2); + ParamPresentAndSet(m_params, UnitParams::efixed, efixed); const double TOFinMicroseconds = 1e6; factorTo = sqrt(PhysicalConstants::NeutronMass / (2.0 * PhysicalConstants::meV)) * @@ -781,9 +1008,6 @@ void DeltaE::init() { // t_other is t2 t_other = (factorTo * l2) / sqrt(efixed); factorTo *= l1; - } else { - throw std::invalid_argument( - "emode must be equal to 1 or 2 for energy transfer calculation"); } //------------ from conversion ------------------ @@ -876,8 +1100,8 @@ Unit *DeltaE::clone() const { return new DeltaE(*this); } /* Energy Transfer in units of wavenumber * ===================================================================================================== * - * This is identical to the above (Energy Transfer in meV) with one division by - *meVtoWavenumber. + * This is identical to the above (Energy Transfer in meV) with one division + *by meVtoWavenumber. */ DECLARE_UNIT(DeltaE_inWavenumber) @@ -948,7 +1172,7 @@ DECLARE_UNIT(Momentum) const UnitLabel Momentum::label() const { return Symbol::InverseAngstrom; } Momentum::Momentum() - : Unit(), sfpTo(DBL_MIN), factorTo(DBL_MIN), sfpFrom(DBL_MIN), + : Unit(), efixed(0.), sfpTo(DBL_MIN), factorTo(DBL_MIN), sfpFrom(DBL_MIN), factorFrom(DBL_MIN), do_sfpFrom(false) { const double AngstromsSquared = 1e20; @@ -964,13 +1188,31 @@ Momentum::Momentum() // } +void Momentum::validateUnitParams(const int emode, + const UnitParametersMap ¶ms) { + if (!ParamPresent(params, UnitParams::l2)) { + throw std::runtime_error( + "An l2 value must be supplied in the extra parameters when " + "initialising momentum for conversion via TOF"); + } + if ((emode != 0) && (!ParamPresent(params, UnitParams::efixed))) { + throw std::runtime_error( + "An efixed value must be supplied in the extra parameters when " + "initialising momentum for conversion via TOF"); + } +} + void Momentum::init() { // ------------ Factors to convert TO TOF --------------------- + double l2 = 0.0; double ltot = 0.0; double TOFisinMicroseconds = 1e6; double toAngstroms = 1e10; sfpTo = 0.0; + ParamPresentAndSet(m_params, UnitParams::l2, l2); + ParamPresentAndSet(m_params, UnitParams::efixed, efixed); + if (emode == 1) { ltot = l2; sfpTo = @@ -1065,6 +1307,7 @@ const UnitLabel SpinEchoLength::label() const { return Symbol::Nanometre; } SpinEchoLength::SpinEchoLength() : Wavelength() {} void SpinEchoLength::init() { + ParamPresentAndSet(m_params, UnitParams::efixed, efixed); // Efixed must be set to something if (efixed == 0.0) throw std::invalid_argument( @@ -1113,9 +1356,10 @@ DECLARE_UNIT(SpinEchoTime) const UnitLabel SpinEchoTime::label() const { return Symbol::Nanosecond; } -SpinEchoTime::SpinEchoTime() : Wavelength() {} +SpinEchoTime::SpinEchoTime() : Wavelength(), efixed(0.) {} void SpinEchoTime::init() { + ParamPresentAndSet(m_params, UnitParams::efixed, efixed); // Efixed must be set to something if (efixed == 0.0) throw std::invalid_argument( diff --git a/Framework/Kernel/src/UnitConversion.cpp b/Framework/Kernel/src/UnitConversion.cpp index 3f9a4694fabd87f43d0d6748ac09a8dc07cb8314..727fd58efa4934424e2ddec38a0a832747942fe8 100644 --- a/Framework/Kernel/src/UnitConversion.cpp +++ b/Framework/Kernel/src/UnitConversion.cpp @@ -32,8 +32,23 @@ double UnitConversion::run(const std::string &src, const std::string &dest, const DeltaEMode::Type emode, const double efixed) { Unit_sptr srcUnit = UnitFactory::Instance().create(src); Unit_sptr destUnit = UnitFactory::Instance().create(dest); - return UnitConversion::run(*srcUnit, *destUnit, srcValue, l1, l2, theta, - emode, efixed); + if ((srcUnit->unitID() == "dSpacing") || (destUnit->unitID() == "dSpacing")) { + throw std::runtime_error( + "This signature is deprecated for d Spacing unit conversions"); + } + UnitParametersMap params{{UnitParams::l2, l2}, + {UnitParams::twoTheta, theta}, + {UnitParams::efixed, efixed}}; + return UnitConversion::run(*srcUnit, *destUnit, srcValue, l1, emode, params); +} // namespace Kernel + +double UnitConversion::run(const std::string &src, const std::string &dest, + const double srcValue, const double l1, + const DeltaEMode::Type emode, + const UnitParametersMap ¶ms) { + Unit_sptr srcUnit = UnitFactory::Instance().create(src); + Unit_sptr destUnit = UnitFactory::Instance().create(dest); + return UnitConversion::run(*srcUnit, *destUnit, srcValue, l1, emode, params); } /** @@ -42,22 +57,22 @@ double UnitConversion::run(const std::string &src, const std::string &dest, * @param destUnit :: The destination unit * @param srcValue :: The value to convert * @param l1 :: The source-sample distance (in metres) - * @param l2 :: The sample-detector distance (in metres) - * @param theta :: The scattering angle (in radians) * @param emode :: The energy mode enumeration - * @param efixed :: Value of fixed energy: EI (emode=1) or EF (emode=2) (in - * meV) + * @param params :: Map containing optional parameters eg + * The sample-detector distance (in metres) + * The scattering angle (in radians) + * Fixed energy: EI (emode=1) or EF (emode=2)(in meV) + * Delta (not currently used) * @return The value converted to the destination unit */ double UnitConversion::run(Unit &srcUnit, Unit &destUnit, const double srcValue, - const double l1, const double l2, const double theta, - const DeltaEMode::Type emode, const double efixed) { + const double l1, const DeltaEMode::Type emode, + const UnitParametersMap ¶ms) { double factor(0.0), power(0.0); if (srcUnit.quickConversion(destUnit, factor, power)) { return convertQuickly(srcValue, factor, power); } else { - return convertViaTOF(srcUnit, destUnit, srcValue, l1, l2, theta, emode, - efixed); + return convertViaTOF(srcUnit, destUnit, srcValue, l1, emode, params); } } @@ -83,18 +98,18 @@ double UnitConversion::convertQuickly(const double srcValue, * @param destUnit :: The destination unit * @param srcValue :: The value to convert * @param l1 :: The source-sample distance (in metres) - * @param l2 :: The sample-detector distance (in metres) - * @param theta :: The scattering angle (in radians) * @param emode :: The energy mode enumeration - * @param efixed :: Value of fixed energy: EI (emode=1) or EF (emode=2) (in - * meV) + * @param params :: Map containing optional parameters eg + * The sample-detector distance (in metres) + * The scattering angle (in radians) + * Fixed energy: EI (emode=1) or EF (emode=2)(in meV) + * Delta (not currently used) * @return The value converted to the destination unit */ double UnitConversion::convertViaTOF(Unit &srcUnit, Unit &destUnit, const double srcValue, const double l1, - const double l2, const double theta, const DeltaEMode::Type emode, - const double efixed) { + const UnitParametersMap ¶ms) { // Translate the emode to the int formulation int emodeAsInt(0); switch (emode) { @@ -113,11 +128,9 @@ double UnitConversion::convertViaTOF(Unit &srcUnit, Unit &destUnit, std::to_string(emode)); }; - const double unused(0.0); - const double tof = srcUnit.convertSingleToTOF(srcValue, l1, l2, theta, - emodeAsInt, efixed, unused); - return destUnit.convertSingleFromTOF(tof, l1, l2, theta, emodeAsInt, efixed, - unused); + const double tof = + srcUnit.convertSingleToTOF(srcValue, l1, emodeAsInt, params); + return destUnit.convertSingleFromTOF(tof, l1, emodeAsInt, params); } /** diff --git a/Framework/Kernel/test/UnitTest.h b/Framework/Kernel/test/UnitTest.h index a0bf000969f0186294ad8ee7ed8839dc1e87fb69..1adabc83dcad0287836e17ded84486a2fcfed829 100644 --- a/Framework/Kernel/test/UnitTest.h +++ b/Framework/Kernel/test/UnitTest.h @@ -100,6 +100,17 @@ std::string convert_units_check_range(const Unit &aUnit, return error_mess; } +namespace { // anonymous +const double DIFC = 2100.; // sensible value +const double TZERO = 10.; +// intentionally goofy - reduces tzero by 1 +const double DIFA1 = .25 * DIFC * DIFC; +// intentionally goofy - reduces tzero by .01 +const double DIFA2 = 25 * DIFC * DIFC; +// intentionally goofy +const double DIFA3 = -.25 * DIFC * DIFC; +} // namespace + class UnitTest : public CxxTest::TestSuite { class UnitTester : public Unit { @@ -253,7 +264,11 @@ public: void test_copy_constructor_on_concrete_type() { Units::TOF first; - first.initialize(1.0, 1.0, 1.0, 2, 1.0, 1.0); + first.initialize(1.0, 2, + {{UnitParams::l2, 1.0}, + {UnitParams::twoTheta, 1.0}, + {UnitParams::efixed, 1.0}, + {UnitParams::delta, 1.0}}); Units::TOF second(first); TS_ASSERT_EQUALS(first.isInitialized(), second.isInitialized()); TS_ASSERT_EQUALS(first.unitID(), second.unitID()) @@ -264,7 +279,11 @@ public: void test_copy_assignment_operator_on_concrete_type() { Units::TOF first; - first.initialize(1.0, 1.0, 1.0, 2, 1.0, 1.0); + first.initialize(1.0, 2, + {{UnitParams::l2, 1.0}, + {UnitParams::twoTheta, 1.0}, + {UnitParams::efixed, 1.0}, + {UnitParams::delta, 1.0}}); Units::TOF second; second = first; TS_ASSERT_EQUALS(first.isInitialized(), second.isInitialized()); @@ -291,7 +310,7 @@ public: std::vector<double> x(20, 9.9), y(20, 8.8); std::vector<double> xx = x; std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(tof.toTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + TS_ASSERT_THROWS_NOTHING(tof.toTOF(x, y, 1.0, 1, {})) // Check vectors are unchanged TS_ASSERT(xx == x) TS_ASSERT(yy == y) @@ -301,7 +320,7 @@ public: std::vector<double> x(20, 9.9), y(20, 8.8); std::vector<double> xx = x; std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(tof.fromTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + TS_ASSERT_THROWS_NOTHING(tof.fromTOF(x, y, 1.0, 1, {})) // Check vectors are unchanged TS_ASSERT(xx == x) TS_ASSERT(yy == y) @@ -342,23 +361,28 @@ public: void testWavelength_toTOF() { std::vector<double> x(1, 1.5), y(1, 1.5); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(lambda.toTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + TS_ASSERT_THROWS_NOTHING(lambda.toTOF( + x, y, 1.0, 1, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 1.0}})) TS_ASSERT_DELTA(x[0], 2665.4390, 0.0001) // 758.3352 TS_ASSERT(yy == y) - TS_ASSERT_DELTA(lambda.convertSingleToTOF(1.5, 1.0, 1.0, 1.0, 1, 1.0, 1.0), - 2665.4390, 0.0001); + TS_ASSERT_DELTA( + lambda.convertSingleToTOF( + 1.5, 1.0, 1, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 1.0}}), + 2665.4390, 0.0001); } void testWavelength_fromTOF() { std::vector<double> x(1, 1000.5), y(1, 1.5); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(lambda.fromTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + TS_ASSERT_THROWS_NOTHING(lambda.fromTOF( + x, y, 1.0, 1, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 1.0}})) TS_ASSERT_DELTA(x[0], -5.0865, 0.0001) // 1.979006 TS_ASSERT(yy == y) TS_ASSERT_DELTA( - lambda.convertSingleFromTOF(1000.5, 1.0, 1.0, 1.0, 1, 1.0, 1.0), + lambda.convertSingleFromTOF( + 1000.5, 1.0, 1, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 1.0}}), -5.0865, 0.0001); } @@ -369,8 +393,9 @@ public: double input = 1.1; double result = factor * std::pow(input, power); std::vector<double> x(1, input); - lambda.toTOF(x, x, 99.0, 99.0, 99.0, 99, 99.0, 99.0); - energy.fromTOF(x, x, 99.0, 99.0, 99.0, 99, 99.0, 99.0); + lambda.toTOF(x, x, 99.0, 99, + {{UnitParams::l2, 99.0}, {UnitParams::efixed, 1.0}}); + energy.fromTOF(x, x, 99.0, 99, {{UnitParams::l2, 99.0}}); TS_ASSERT_DELTA(x[0], result, 1.0e-10) TS_ASSERT(lambda.quickConversion(energyk, factor, power)) @@ -378,8 +403,10 @@ public: TS_ASSERT_EQUALS(result2 / result, Mantid::PhysicalConstants::meVtoWavenumber) std::vector<double> x2(1, input); - lambda.toTOF(x2, x2, 99.0, 99.0, 99.0, 99, 99.0, 99.0); - energyk.fromTOF(x2, x2, 99.0, 99.0, 99.0, 99, 99.0, 99.0); + lambda.toTOF(x2, x2, 99.0, 99, + {{UnitParams::l2, 99.0}, {UnitParams::efixed, 99.0}}); + + energyk.fromTOF(x2, x2, 99.0, 99, {{UnitParams::l2, 99.0}}); TS_ASSERT_DELTA(x2[0], result2, 1.0e-10) } @@ -417,7 +444,8 @@ public: void testEnergy_toTOF() { std::vector<double> x(1, 4.0), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(energy.toTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + TS_ASSERT_THROWS_NOTHING( + energy.toTOF(x, y, 1.0, 1, {{UnitParams::l2, 1.0}})) TS_ASSERT_DELTA(x[0], 2286.271, 0.001) TS_ASSERT(yy == y) } @@ -425,7 +453,8 @@ public: void testEnergy_fromTOF() { std::vector<double> x(1, 4.0), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(energy.fromTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + TS_ASSERT_THROWS_NOTHING( + energy.fromTOF(x, y, 1.0, 1, {{UnitParams::l2, 1.0}})) TS_ASSERT_DELTA(x[0], 1306759.0, 1.0) TS_ASSERT(yy == y) } @@ -438,15 +467,16 @@ public: double result = factor * std::pow(input, power); TS_ASSERT_EQUALS(result / input, Mantid::PhysicalConstants::meVtoWavenumber) std::vector<double> x(1, input); - energy.toTOF(x, x, 99.0, 99.0, 99.0, 99, 99.0, 99.0); - energyk.fromTOF(x, x, 99.0, 99.0, 99.0, 99, 99.0, 99.0); + energy.toTOF(x, x, 99.0, 99, {{UnitParams::l2, 99.0}}); + energyk.fromTOF(x, x, 99.0, 99, {{UnitParams::l2, 99.0}}); TS_ASSERT_DELTA(x[0], result, 1.0e-12) TS_ASSERT(energy.quickConversion(lambda, factor, power)) result = factor * std::pow(input, power); std::vector<double> x2(1, input); - energy.toTOF(x2, x2, 99.0, 99.0, 99.0, 99, 99.0, 99.0); - lambda.fromTOF(x2, x2, 99.0, 99.0, 99.0, 99, 99.0, 99.0); + energy.toTOF(x2, x2, 99.0, 99, {{UnitParams::l2, 99.0}}); + lambda.fromTOF(x2, x2, 99.0, 99, + {{UnitParams::l2, 99.0}, {UnitParams::efixed, 99.0}}); TS_ASSERT_DELTA(x2[0], result, 1.0e-15) } void testEnergyRange() { @@ -492,7 +522,8 @@ public: void testEnergy_inWavenumber_toTOF() { std::vector<double> x(1, 4.0), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(energyk.toTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + TS_ASSERT_THROWS_NOTHING( + energyk.toTOF(x, y, 1.0, 1, {{UnitParams::l2, 1.0}})) TS_ASSERT_DELTA(x[0], 6492.989, 0.001) TS_ASSERT(yy == y) } @@ -500,7 +531,8 @@ public: void testEnergy_inWavenumber_fromTOF() { std::vector<double> x(1, 4.0), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(energyk.fromTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + TS_ASSERT_THROWS_NOTHING( + energyk.fromTOF(x, y, 1.0, 1, {{UnitParams::l2, 1.0}})) TS_ASSERT_DELTA(x[0], 10539725, 1.0) TS_ASSERT(yy == y) } @@ -513,15 +545,16 @@ public: double result = factor * std::pow(input, power); TS_ASSERT_EQUALS(input / result, Mantid::PhysicalConstants::meVtoWavenumber) std::vector<double> x(1, input); - energyk.toTOF(x, x, 99.0, 99.0, 99.0, 99, 99.0, 99.0); - energy.fromTOF(x, x, 99.0, 99.0, 99.0, 99, 99.0, 99.0); + energyk.toTOF(x, x, 99.0, 99, {{UnitParams::l2, 99.0}}); + energy.fromTOF(x, x, 99.0, 99, {{UnitParams::l2, 99.0}}); TS_ASSERT_DELTA(x[0], result, 1.0e-14) TS_ASSERT(energyk.quickConversion(lambda, factor, power)) result = factor * std::pow(input, power); std::vector<double> x2(1, input); - energyk.toTOF(x2, x2, 99.0, 99.0, 99.0, 99, 99.0, 99.0); - lambda.fromTOF(x2, x2, 99.0, 99.0, 99.0, 99, 99.0, 99.0); + energyk.toTOF(x2, x2, 99.0, 99, {{UnitParams::l2, 99.0}}); + lambda.fromTOF(x2, x2, 99.0, 99, + {{UnitParams::l2, 99.0}, {UnitParams::efixed, 99.0}}); TS_ASSERT_DELTA(x2[0], result, 1.0e-15) } @@ -547,19 +580,62 @@ public: void testdSpacing_toTOF() { std::vector<double> x(1, 1.0), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(d.toTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + double difc = 2.0 * Mantid::PhysicalConstants::NeutronMass * sin(0.5) * + (1.0 + 1.0) * 1e-4 / Mantid::PhysicalConstants::h; + TS_ASSERT_THROWS_NOTHING(d.toTOF(x, y, 1.0, 1, {{UnitParams::difc, difc}})) + TS_ASSERT_DELTA(x[0], 484.7537, 0.0001) + TS_ASSERT(yy == y) + } + + void testdSpacing_toTOFWithL2TwoTheta() { + std::vector<double> x(1, 1.0), y(1, 1.0); + std::vector<double> yy = y; + TS_ASSERT_THROWS_NOTHING(d.toTOF( + x, y, 1.0, 1, {{UnitParams::l2, 1.0}, {UnitParams::twoTheta, 1.0}})) TS_ASSERT_DELTA(x[0], 484.7537, 0.0001) TS_ASSERT(yy == y) } + void testdSpacing_toTOFWithDIFATZERO() { + std::vector<double> x(1, 2.0), y(1, 1.0); + std::vector<double> yy = y; + TS_ASSERT_THROWS_NOTHING(d.toTOF(x, y, 1.0, 1, + {{UnitParams::difc, 3.0}, + {UnitParams::difa, 2.0}, + {UnitParams::tzero, 1.0}})) + TS_ASSERT_DELTA(x[0], 6.0 + 8.0 + 1.0, 0.0001) + TS_ASSERT(yy == y) + } + void testdSpacing_fromTOF() { std::vector<double> x(1, 1001.1), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(d.fromTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + double difc = 2.0 * Mantid::PhysicalConstants::NeutronMass * sin(0.5) * + (1.0 + 1.0) * 1e-4 / Mantid::PhysicalConstants::h; + TS_ASSERT_THROWS_NOTHING( + d.fromTOF(x, y, 1.0, 1, {{UnitParams::difc, difc}})) TS_ASSERT_DELTA(x[0], 2.065172, 0.000001) TS_ASSERT(yy == y) } + void testdSpacing_fromTOFWithDIFATZERO() { + std::vector<double> x(1, 2.0), y(1, 1.0); + std::vector<double> yy = y; + TS_ASSERT_THROWS_NOTHING(d.fromTOF(x, y, 1.0, 1, + {{UnitParams::difc, 2.0}, + {UnitParams::difa, 3.0}, + {UnitParams::tzero, 1.0}})) + TS_ASSERT_DELTA(x[0], 1.0 / 3.0, 0.0001) + TS_ASSERT(yy == y) + x[0] = 1.0; + TS_ASSERT_THROWS_NOTHING(d.fromTOF(x, y, 1.0, 1, + {{UnitParams::difc, 3.0}, + {UnitParams::difa, -2.0}, + {UnitParams::tzero, 1.0}})) + TS_ASSERT_DELTA(x[0], 1.5, 0.0001) + TS_ASSERT(yy == y) + } + void testdSpacing_quickConversions() { // Test it gives the same answer as going 'the long way' // To MomentumTransfer @@ -568,8 +644,10 @@ public: double input = 1.1; double result = factor * std::pow(input, power); std::vector<double> x(1, input); - d.toTOF(x, x, 99.0, 99.0, 1.0, 0, 99.0, 99.0); - q.fromTOF(x, x, 99.0, 99.0, 1.0, 0, 99.0, 99.0); + double difc = 2.0 * Mantid::PhysicalConstants::NeutronMass * sin(0.5) * + (99.0 + 99.0) * 1e-4 / Mantid::PhysicalConstants::h; + d.toTOF(x, x, 99.0, 0, {{UnitParams::difc, difc}}); + q.fromTOF(x, x, 99.0, 0, {{UnitParams::difc, difc}}); TS_ASSERT_DELTA(x[0], result, 1.0e-12) // To QSquared @@ -577,13 +655,17 @@ public: input = 1.1; result = factor * std::pow(input, power); x[0] = input; - d.toTOF(x, x, 99.0, 99.0, 1.0, 0, 99.0, 99.0); - q2.fromTOF(x, x, 99.0, 99.0, 1.0, 0, 99.0, 99.0); + d.toTOF(x, x, 99.0, 0, {{UnitParams::difc, difc}}); + q2.fromTOF(x, x, 99.0, 0, {{UnitParams::difc, difc}}); TS_ASSERT_DELTA(x[0], result, 1.0e-12) } void testdSpacingRange() { std::vector<double> sample, rezult; + double difc = 2.0 * Mantid::PhysicalConstants::NeutronMass * + sin(0.5 * M_PI / 180) * (99.0 + 99.0) * 1e-4 / + Mantid::PhysicalConstants::h; + d.initialize(99.0, 0, {{UnitParams::difc, difc}}); std::string err_mess = convert_units_check_range(d, sample, rezult); TSM_ASSERT(" ERROR:" + err_mess, err_mess.size() == 0); @@ -600,6 +682,52 @@ public: } } + void test_calcTofMin() { + const double TMIN = 300.; + + // just difc + TS_ASSERT_EQUALS(d.calcTofMin(DIFC, 0., 0.), 0.); + TS_ASSERT_EQUALS(d.calcTofMin(DIFC, 0., 0., TMIN), TMIN); + // difc + tzero + TS_ASSERT_EQUALS(d.calcTofMin(DIFC, 0., TZERO, 0.), TZERO); + TS_ASSERT_EQUALS(d.calcTofMin(DIFC, 0., TZERO, TMIN), TMIN); + + // difc + difa + tzero + TS_ASSERT_EQUALS(d.calcTofMin(DIFC, DIFA1, 0., 0.), 0.); + TS_ASSERT_EQUALS(d.calcTofMin(DIFC, DIFA1, 0., TMIN), TMIN); + TS_ASSERT_EQUALS(d.calcTofMin(DIFC, DIFA1, TZERO, 0.), TZERO - 1.); + TS_ASSERT_EQUALS(d.calcTofMin(DIFC, DIFA1, TZERO, TMIN), TMIN); + + TS_ASSERT_EQUALS(d.calcTofMin(DIFC, DIFA2, 0., 0.), 0.); + TS_ASSERT_EQUALS(d.calcTofMin(DIFC, DIFA2, 0., TMIN), TMIN); + TS_ASSERT_EQUALS(d.calcTofMin(DIFC, DIFA2, TZERO, 0.), TZERO - .01); + TS_ASSERT_EQUALS(d.calcTofMin(DIFC, DIFA2, TZERO, TMIN), TMIN); + } + + void test_calcTofMax() { + const double TMAX = 16666.7; + const double TSUPERMAX = std::numeric_limits<double>::max(); + + // just difc + TS_ASSERT_EQUALS(d.calcTofMax(DIFC, 0., 0., TMAX), TMAX); + TS_ASSERT_EQUALS(d.calcTofMax(DIFC, 0., 0., TSUPERMAX), TSUPERMAX); + // difc + tzero + TS_ASSERT_EQUALS(d.calcTofMax(DIFC, 0., TZERO, TMAX), TMAX); + TS_ASSERT_EQUALS(d.calcTofMax(DIFC, 0., TZERO, TSUPERMAX), TSUPERMAX); + + // difc + difa + tzero + TS_ASSERT_EQUALS(d.calcTofMax(DIFC, DIFA1, 0., TMAX), TMAX); + TS_ASSERT_EQUALS(d.calcTofMax(DIFC, DIFA1, 0., TSUPERMAX), TSUPERMAX); + TS_ASSERT_EQUALS(d.calcTofMax(DIFC, DIFA1, TZERO, TMAX), TMAX); + TS_ASSERT_EQUALS(d.calcTofMax(DIFC, DIFA1, TZERO, TSUPERMAX), TSUPERMAX); + + TS_ASSERT_DELTA(d.calcTofMax(DIFC, DIFA3, 0., TMAX), 1., 1E-10); + TS_ASSERT_DELTA(d.calcTofMax(DIFC, DIFA3, 0., TSUPERMAX), 1., 1E-10); + TS_ASSERT_DELTA(d.calcTofMax(DIFC, DIFA3, TZERO, TMAX), TZERO + 1., 1E-10); + TS_ASSERT_DELTA(d.calcTofMax(DIFC, DIFA3, TZERO, TSUPERMAX), TZERO + 1., + 1E-10); + } + //---------------------------------------------------------------------- // d-SpacingPerpebdicular tests //---------------------------------------------------------------------- @@ -626,7 +754,8 @@ public: void testdSpacingPerpendicular_toTOF() { std::vector<double> x(1, 1.0), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(dp.toTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + TS_ASSERT_THROWS_NOTHING(dp.toTOF( + x, y, 1.0, 1, {{UnitParams::l2, 1.0}, {UnitParams::twoTheta, 1.0}})) TS_ASSERT_DELTA(x[0], 434.5529, 0.0001) TS_ASSERT(yy == y) } @@ -634,7 +763,8 @@ public: void testdSpacingPerpendicular_fromTOF() { std::vector<double> x(1, 1001.1), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(dp.fromTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + TS_ASSERT_THROWS_NOTHING(dp.fromTOF( + x, y, 1.0, 1, {{UnitParams::l2, 1.0}, {UnitParams::twoTheta, 1.0}})) TS_ASSERT_DELTA(x[0], 2.045075, 0.000001) TS_ASSERT(yy == y) } @@ -684,7 +814,9 @@ public: void testQTransfer_toTOF() { std::vector<double> x(1, 1.1), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(q.toTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + double difc = 2.0 * Mantid::PhysicalConstants::NeutronMass * sin(0.5) * + (1.0 + 1.0) * 1e-4 / Mantid::PhysicalConstants::h; + TS_ASSERT_THROWS_NOTHING(q.toTOF(x, y, 1.0, 1, {{UnitParams::difc, difc}})) TS_ASSERT_DELTA(x[0], 2768.9067, 0.0001) TS_ASSERT(yy == y) } @@ -692,7 +824,10 @@ public: void testQTransfer_fromTOF() { std::vector<double> x(1, 1.1), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(q.fromTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + double difc = 2.0 * Mantid::PhysicalConstants::NeutronMass * sin(0.5) * + (1.0 + 1.0) * 1e-4 / Mantid::PhysicalConstants::h; + TS_ASSERT_THROWS_NOTHING( + q.fromTOF(x, y, 1.0, 1, {{UnitParams::difc, difc}})) TS_ASSERT_DELTA(x[0], 2768.9067, 0.0001) TS_ASSERT(yy == y) } @@ -705,8 +840,10 @@ public: double input = 1.1; double result = factor * std::pow(input, power); std::vector<double> x(1, input); - q.toTOF(x, x, 99.0, 99.0, 99.0, 99, 99.0, 99.0); - q2.fromTOF(x, x, 99.0, 99.0, 99.0, 99, 99.0, 99.0); + double difc = 2.0 * Mantid::PhysicalConstants::NeutronMass * sin(1.0 / 2) * + (99.0 + 99.0) * 1e-4 / Mantid::PhysicalConstants::h; + q.toTOF(x, x, 99.0, 99, {{UnitParams::difc, difc}}); + q2.fromTOF(x, x, 99.0, 99, {{UnitParams::difc, difc}}); TS_ASSERT_DELTA(x[0], result, 1.0e-30) // To dSpacing @@ -714,8 +851,8 @@ public: input = 1.1; result = factor * std::pow(input, power); x[0] = input; - q.toTOF(x, x, 99.0, 99.0, 1.0, 99, 99.0, 99.0); - d.fromTOF(x, x, 99.0, 99.0, 1.0, 99, 99.0, 99.0); + q.toTOF(x, x, 99.0, 99, {{UnitParams::difc, difc}}); + d.fromTOF(x, x, 99.0, 99, {{UnitParams::difc, difc}}); TS_ASSERT_DELTA(x[0], result, 1.0e-12) } void testMomentumTransferRange() { @@ -759,7 +896,9 @@ public: void testQ2_toTOF() { std::vector<double> x(1, 4.0), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(q2.toTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + double difc = 2.0 * Mantid::PhysicalConstants::NeutronMass * sin(1.0 / 2) * + (1.0 + 1.0) * 1e-4 / Mantid::PhysicalConstants::h; + TS_ASSERT_THROWS_NOTHING(q2.toTOF(x, y, 1.0, 1, {{UnitParams::difc, difc}})) TS_ASSERT_DELTA(x[0], 1522.899, 0.001) TS_ASSERT(yy == y) } @@ -767,7 +906,10 @@ public: void testQ2_fromTOF() { std::vector<double> x(1, 200.0), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(q2.fromTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + double difc = 2.0 * Mantid::PhysicalConstants::NeutronMass * sin(1.0 / 2) * + (1.0 + 1.0) * 1e-4 / Mantid::PhysicalConstants::h; + TS_ASSERT_THROWS_NOTHING( + q2.fromTOF(x, y, 1.0, 1, {{UnitParams::difc, difc}})) TS_ASSERT_DELTA(x[0], 231.9220, 0.0001) TS_ASSERT(yy == y) } @@ -780,8 +922,10 @@ public: double input = 1.1; double result = factor * std::pow(input, power); std::vector<double> x(1, input); - q2.toTOF(x, x, 99.0, 99.0, 99.0, 99, 99.0, 99.0); - q.fromTOF(x, x, 99.0, 99.0, 99.0, 99, 99.0, 99.0); + double difc = 2.0 * Mantid::PhysicalConstants::NeutronMass * sin(1.0 / 2) * + (99.0 + 99.0) * 1e-4 / Mantid::PhysicalConstants::h; + q2.toTOF(x, x, 99.0, 99, {{UnitParams::difc, difc}}); + q.fromTOF(x, x, 99.0, 99, {{UnitParams::difc, difc}}); TS_ASSERT_DELTA(x[0], result, 1.0e-30) // To dSpacing @@ -789,16 +933,19 @@ public: input = 1.1; result = factor * std::pow(input, power); x[0] = input; - q2.toTOF(x, x, 99.0, 99.0, 1.0, 99, 99.0, 99.0); - d.fromTOF(x, x, 99.0, 99.0, 1.0, 99, 99.0, 99.0); + q2.toTOF(x, x, 99.0, 99, {{UnitParams::difc, difc}}); + d.fromTOF(x, x, 99.0, 99, {{UnitParams::difc, difc}}); TS_ASSERT_DELTA(x[0], result, 1.0e-15) } void testQ2Range() { std::vector<double> sample, rezult; - q2.initialize(1.1, 1.1, 99.0, 0, 99.0, 0); - std::string err_mess = - convert_units_check_range(q2, sample, rezult, -DBL_EPSILON); + double difc = 2.0 * Mantid::PhysicalConstants::NeutronMass * sin(1.0 / 2) * + (1.1 + 1.1) * 1e-4 / Mantid::PhysicalConstants::h; + q2.initialize(1.1, 0, + {{UnitParams::difc, difc}, {UnitParams::efixed, 99.0}}); + + std::string err_mess = convert_units_check_range(q2, sample, rezult); TSM_ASSERT(" ERROR:" + err_mess, err_mess.size() == 0); for (size_t i = 0; i < sample.size(); i++) { @@ -838,40 +985,49 @@ public: void testDeltaE_toTOF() { std::vector<double> x(1, 1.1), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(dE.toTOF(x, y, 1.5, 2.5, 0.0, 1, 4.0, 0.0)) + TS_ASSERT_THROWS_NOTHING(dE.toTOF( + x, y, 1.5, 1, {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}})) TS_ASSERT_DELTA(x[0], 5071.066, 0.001) TS_ASSERT(yy == y) x[0] = 1.1; - TS_ASSERT_THROWS_NOTHING(dE.toTOF(x, y, 1.5, 2.5, 0.0, 2, 4.0, 0.0)) + TS_ASSERT_THROWS_NOTHING(dE.toTOF( + x, y, 1.5, 2, {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}})) TS_ASSERT_DELTA(x[0], 4376.406, 0.001) TS_ASSERT(yy == y) // emode = 0 - TS_ASSERT_THROWS(dE.toTOF(x, y, 1.5, 2.5, 0.0, 0, 4.0, 0.0), - const std::invalid_argument &) + TS_ASSERT_THROWS( + dE.toTOF(x, y, 1.5, 0, + {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}}), + const std::invalid_argument &) } void testDeltaE_fromTOF() { std::vector<double> x(1, 2001.0), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(dE.fromTOF(x, y, 1.5, 2.5, 0.0, 1, 4.0, 0.0)) + TS_ASSERT_THROWS_NOTHING(dE.fromTOF( + x, y, 1.5, 1, {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}})) TS_ASSERT_DELTA(x[0], -394.5692, 0.0001) TS_ASSERT(yy == y) x[0] = 3001.0; - TS_ASSERT_THROWS_NOTHING(dE.fromTOF(x, y, 1.5, 2.5, 0.0, 2, 4.0, 0.0)) + TS_ASSERT_THROWS_NOTHING(dE.fromTOF( + x, y, 1.5, 2, {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}})) TS_ASSERT_DELTA(x[0], 569.8397, 0.0001) TS_ASSERT(yy == y) // emode = 0 - TS_ASSERT_THROWS(dE.fromTOF(x, y, 1.5, 2.5, 0.0, 0, 4.0, 0.0), - const std::invalid_argument &) + TS_ASSERT_THROWS( + dE.fromTOF(x, y, 1.5, 0, + {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}}), + const std::invalid_argument &) } void testDERange() { std::vector<double> sample, rezult; // Direct - dE.initialize(2001.0, 1.0, 1.5, 1, 10., 0.0); + dE.initialize(2001.0, 1, + {{UnitParams::l2, 1.0}, {UnitParams::efixed, 10.0}}); std::string err_mess = convert_units_check_range(dE, sample, rezult, DBL_EPSILON); @@ -891,7 +1047,8 @@ public: sample[3], rezult[3], 10 * FLT_EPSILON); // Indirect - dE.initialize(2001.0, 1.0, 1.5, 2, 10., 0.0); + dE.initialize(2001.0, 2, + {{UnitParams::l2, 1.0}, {UnitParams::efixed, 10.0}}); err_mess = convert_units_check_range(dE, sample, rezult); TSM_ASSERT(" ERROR:" + err_mess, err_mess.size() == 0); @@ -936,40 +1093,49 @@ public: void testDeltaEk_toTOF() { std::vector<double> x(1, 1.1), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(dEk.toTOF(x, y, 1.5, 2.5, 0.0, 1, 4.0, 0.0)) + TS_ASSERT_THROWS_NOTHING(dEk.toTOF( + x, y, 1.5, 1, {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}})) TS_ASSERT_DELTA(x[0], 4622.5452, 0.01) TS_ASSERT(yy == y) x[0] = 1.1; - TS_ASSERT_THROWS_NOTHING(dEk.toTOF(x, y, 1.5, 2.5, 0.0, 2, 4.0, 0.0)) + TS_ASSERT_THROWS_NOTHING(dEk.toTOF( + x, y, 1.5, 2, {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}})) TS_ASSERT_DELTA(x[0], 4544.0378, 0.001) TS_ASSERT(yy == y) // emode = 0 - TS_ASSERT_THROWS(dEk.toTOF(x, y, 1.5, 2.5, 0.0, 0, 4.0, 0.0), - const std::invalid_argument &) + TS_ASSERT_THROWS( + dEk.toTOF(x, y, 1.5, 0, + {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}}), + const std::invalid_argument &) } void testDeltaEk_fromTOF() { std::vector<double> x(1, 2001.0), y(1, 1.0); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(dEk.fromTOF(x, y, 1.5, 2.5, 0.0, 1, 4.0, 0.0)) + TS_ASSERT_THROWS_NOTHING(dEk.fromTOF( + x, y, 1.5, 1, {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}})) TS_ASSERT_DELTA(x[0], -3182.416, 0.001) TS_ASSERT(yy == y) x[0] = 3001.0; - TS_ASSERT_THROWS_NOTHING(dEk.fromTOF(x, y, 1.5, 2.5, 0.0, 2, 4.0, 0.0)) + TS_ASSERT_THROWS_NOTHING(dEk.fromTOF( + x, y, 1.5, 2, {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}})) TS_ASSERT_DELTA(x[0], 4596.068, 0.001) TS_ASSERT(yy == y) // emode = 0 - TS_ASSERT_THROWS(dEk.fromTOF(x, y, 1.5, 2.5, 0.0, 0, 4.0, 0.0), - const std::invalid_argument &) + TS_ASSERT_THROWS( + dEk.fromTOF(x, y, 1.5, 0, + {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}}), + const std::invalid_argument &) } void testDE_kRange() { std::vector<double> sample, rezult; // Direct - dEk.initialize(2001.0, 1.0, 1.5, 1, 10., 0.0); + dEk.initialize(2001.0, 1, + {{UnitParams::l2, 1.0}, {UnitParams::efixed, 10.0}}); std::string err_mess = convert_units_check_range(dEk, sample, rezult); TSM_ASSERT(" ERROR:" + err_mess, err_mess.size() == 0); @@ -988,7 +1154,8 @@ public: sample[3], rezult[3], 10 * FLT_EPSILON); // Indirect - dEk.initialize(2001.0, 1.0, 1.5, 2, 10., 0.0); + dEk.initialize(2001.0, 2, + {{UnitParams::l2, 1.0}, {UnitParams::efixed, 10.0}}); err_mess = convert_units_check_range(dEk, sample, rezult); TSM_ASSERT(" ERROR:" + err_mess, err_mess.size() == 0); @@ -1034,41 +1201,50 @@ public: 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_THROWS_NOTHING(dEf.toTOF( + x, y, 1.5, 1, {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.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_THROWS_NOTHING(dEf.toTOF( + x, y, 1.5, 2, {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.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), - const std::invalid_argument &) + TS_ASSERT_THROWS( + dEf.toTOF(x, y, 1.5, 0, + {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}}), + const 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_THROWS_NOTHING(dEf.fromTOF( + x, y, 1.5, 1, {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.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_THROWS_NOTHING(dEf.fromTOF( + x, y, 1.5, 2, {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.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), - const std::invalid_argument &) + TS_ASSERT_THROWS( + dEf.fromTOF(x, y, 1.5, 0, + {{UnitParams::l2, 2.5}, {UnitParams::efixed, 4.0}}), + const std::invalid_argument &) } void testDE_fRange() { std::vector<double> sample, rezult; // Direct - dEf.initialize(2001.0, 1.0, 1.5, 1, 10., 0.0); + dEf.initialize(2001.0, 1, + {{UnitParams::l2, 1.0}, {UnitParams::efixed, 10.0}}); std::string err_mess = convert_units_check_range(dEf, sample, rezult, DBL_EPSILON); @@ -1088,7 +1264,8 @@ public: sample[3], rezult[3], 10 * FLT_EPSILON); // Indirect - dEf.initialize(2001.0, 1.0, 1.5, 2, 10., 0.0); + dEf.initialize(2001.0, 2, + {{UnitParams::l2, 1.0}, {UnitParams::efixed, 10.0}}); err_mess = convert_units_check_range(dEf, sample, rezult); TSM_ASSERT(" ERROR:" + err_mess, err_mess.size() == 0); @@ -1129,7 +1306,8 @@ public: void testMomentum_toTOF() { std::vector<double> x(1, 2 * M_PI / 1.5), y(1, 1.5); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(k_i.toTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + TS_ASSERT_THROWS_NOTHING(k_i.toTOF( + x, y, 1.0, 1, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 1.0}})) // TS_ASSERT_DELTA( x[0], 2665.4390, 0.0001 ) // -- wavelength to TOF; TS_ASSERT_DELTA(x[0], 2665.4390, 0.0001) // TS_ASSERT(yy == y) @@ -1138,7 +1316,8 @@ public: void testMomentum_fromTOF() { std::vector<double> x(1, 1000.5), y(1, 1.5); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(k_i.fromTOF(x, y, 1.0, 1.0, 1.0, 1, 1.0, 1.0)) + TS_ASSERT_THROWS_NOTHING(k_i.fromTOF( + x, y, 1.0, 1, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 1.0}})) // TS_ASSERT_DELTA( x[0], -5.0865, 0.0001 ) // wavelength from TOF TS_ASSERT_DELTA(x[0], 2 * M_PI / (-5.0865), 0.0001) // 1.979006 TS_ASSERT(yy == y) @@ -1151,8 +1330,10 @@ public: double input = 1.1; double result = factor * std::pow(input, power); std::vector<double> x(1, input); - k_i.toTOF(x, x, 99.0, 99.0, 99.0, 99, 99.0, 99.0); - energy.fromTOF(x, x, 99.0, 99.0, 99.0, 99, 99.0, 99.0); + k_i.toTOF(x, x, 99.0, 99, + {{UnitParams::l2, 99.0}, {UnitParams::efixed, 99.0}}); + energy.fromTOF(x, x, 99.0, 99, + {{UnitParams::l2, 99.0}, {UnitParams::efixed, 99.0}}); TS_ASSERT_DELTA(x[0], result, 1.0e-10) TS_ASSERT(k_i.quickConversion(energyk, factor, power)) @@ -1160,8 +1341,10 @@ public: TS_ASSERT_EQUALS(result2 / result, Mantid::PhysicalConstants::meVtoWavenumber) std::vector<double> x2(1, input); - k_i.toTOF(x2, x2, 99.0, 99.0, 99.0, 99, 99.0, 99.0); - energyk.fromTOF(x2, x2, 99.0, 99.0, 99.0, 99, 99.0, 99.0); + k_i.toTOF(x2, x2, 99.0, 99, + {{UnitParams::l2, 99.0}, {UnitParams::efixed, 99.0}}); + energyk.fromTOF(x2, x2, 99.0, 99, + {{UnitParams::l2, 99.0}, {UnitParams::efixed, 99.0}}); TS_ASSERT_DELTA(x2[0], result2, 1.0e-10); TS_ASSERT(k_i.quickConversion(lambda, factor, power)); @@ -1173,7 +1356,7 @@ public: } void testK_iRange() { std::vector<double> sample, rezult; - k_i.initialize(1.1, 1.1, 99.0, 0, 99.0, 99); + k_i.initialize(1.1, 0, {{UnitParams::l2, 1.1}}); std::string err_mess = convert_units_check_range(k_i, sample, rezult, DBL_EPSILON); @@ -1193,7 +1376,8 @@ public: } } - k_i.initialize(10000, 11, 99.0, 2, 99.0, 99); + k_i.initialize(10000, 2, + {{UnitParams::l2, 11}, {UnitParams::efixed, 99.0}}); err_mess = convert_units_check_range(k_i, sample, rezult, DBL_EPSILON); TSM_ASSERT(" ERROR:" + err_mess, err_mess.size() == 0); @@ -1212,7 +1396,7 @@ public: } } - k_i.initialize(1, 1.1, 99.0, 1, 99.0, 99); + k_i.initialize(1, 1, {{UnitParams::l2, 1.1}, {UnitParams::efixed, 99.0}}); err_mess = convert_units_check_range(k_i, sample, rezult, DBL_EPSILON); TSM_ASSERT(" ERROR:" + err_mess, err_mess.size() == 0); @@ -1258,30 +1442,36 @@ public: void testSpinEchoLength_toTOF() { std::vector<double> x(1, 4.5), y(1, 1.5); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(delta.toTOF(x, y, 1.0, 1.0, 1.0, 0, 2.0, 1.0)) + TS_ASSERT_THROWS_NOTHING(delta.toTOF( + x, y, 1.0, 0, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 2.0}})) TS_ASSERT_DELTA(x[0], 758.3352, 0.0001) TS_ASSERT(yy == y) - TS_ASSERT_DELTA(delta.convertSingleToTOF(4.5, 1.0, 1.0, 1.0, 0, 2.0, 1.0), - 758.3352, 0.0001); + TS_ASSERT_DELTA( + delta.convertSingleToTOF( + 4.5, 1.0, 0, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 2.0}}), + 758.3352, 0.0001); } void testSpinEchoLength_fromTOF() { std::vector<double> x(1, 1000.5), y(1, 1.5); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(delta.fromTOF(x, y, 1.0, 1.0, 1.0, 0, 2.0, 1.0)) + TS_ASSERT_THROWS_NOTHING(delta.fromTOF( + x, y, 1.0, 0, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 2.0}})) TS_ASSERT_DELTA(x[0], 7.8329, 0.0001) TS_ASSERT(yy == y) TS_ASSERT_DELTA( - delta.convertSingleFromTOF(1000.5, 1.0, 1.0, 1.0, 0, 2.0, 1.0), 7.8329, - 0.0001); + delta.convertSingleFromTOF( + 1000.5, 1.0, 0, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 2.0}}), + 7.8329, 0.0001); } void testSpinEchoLength_invalidfromTOF() { std::vector<double> x(1, 1000.5), y(1, 1.5); // emode must = 0 - TS_ASSERT_THROWS_ANYTHING(delta.fromTOF(x, y, 1.0, 1.0, 1.0, 1, 2.0, 1.0)) + TS_ASSERT_THROWS_ANYTHING(delta.fromTOF( + x, y, 1.0, 1, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 2.0}})) } void testSpinEchoLength_quickConversions() { @@ -1292,7 +1482,8 @@ public: } void testSpinEchoRange() { std::vector<double> sample, rezult; - delta.initialize(10, 1.1, 99.0, 0, 99.0, 99); + delta.initialize(10, 0, + {{UnitParams::l2, 1.1}, {UnitParams::efixed, 99.0}}); std::string err_mess = convert_units_check_range(delta, sample, rezult); TSM_ASSERT(" ERROR:" + err_mess, err_mess.size() == 0); @@ -1336,30 +1527,36 @@ public: void testSpinEchoTime_toTOF() { std::vector<double> x(1, 4.5), y(1, 1.5); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(tau.toTOF(x, y, 1.0, 1.0, 1.0, 0, 2.0, 1.0)) + TS_ASSERT_THROWS_NOTHING(tau.toTOF( + x, y, 1.0, 0, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 2.0}})) TS_ASSERT_DELTA(x[0], 662.4668, 0.0001) TS_ASSERT(yy == y) - TS_ASSERT_DELTA(tau.convertSingleToTOF(4.5, 1.0, 1.0, 1.0, 0, 2.0, 1.0), - 662.4668, 0.0001); + TS_ASSERT_DELTA( + tau.convertSingleToTOF( + 4.5, 1.0, 0, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 2.0}}), + 662.4668, 0.0001); } void testSpinEchoTime_fromTOF() { std::vector<double> x(1, 1000.5), y(1, 1.5); std::vector<double> yy = y; - TS_ASSERT_THROWS_NOTHING(tau.fromTOF(x, y, 1.0, 1.0, 1.0, 0, 2.0, 1.0)) + TS_ASSERT_THROWS_NOTHING(tau.fromTOF( + x, y, 1.0, 0, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 2.0}})) TS_ASSERT_DELTA(x[0], 15.5014, 0.0001) TS_ASSERT(yy == y) TS_ASSERT_DELTA( - tau.convertSingleFromTOF(1000.5, 1.0, 1.0, 1.0, 0, 2.0, 1.0), 15.5014, - 0.0001); + tau.convertSingleFromTOF( + 1000.5, 1.0, 0, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 2.0}}), + 15.5014, 0.0001); } void testSpinEchoTime_invalidfromTOF() { std::vector<double> x(1, 1000.5), y(1, 1.5); // emode must = 0 - TS_ASSERT_THROWS_ANYTHING(tau.fromTOF(x, y, 1.0, 1.0, 1.0, 1, 2.0, 1.0)) + TS_ASSERT_THROWS_ANYTHING(tau.fromTOF( + x, y, 1.0, 1, {{UnitParams::l2, 1.0}, {UnitParams::efixed, 2.0}})) } void testSpinEchoTime_quickConversions() { @@ -1370,7 +1567,7 @@ public: } void testSpinEchoTimeRange() { std::vector<double> sample, rezult; - tau.initialize(100, 11, 1.0, 0, 1.0, 1); + tau.initialize(100, 0, {{UnitParams::l2, 11}}); std::string err_mess = convert_units_check_range(tau, sample, rezult, DBL_EPSILON); diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/UnitsConversionHelper.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/UnitsConversionHelper.h index 9418deb7f6e7829396517b0c8f1737b5cced438d..75aab2e980a6fc2d0e46ea29aa3d660719fd3d3b 100644 --- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/UnitsConversionHelper.h +++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/UnitsConversionHelper.h @@ -48,12 +48,15 @@ class DLLExport UnitsConversionHelper { // these variables needed and used for conversion through TOF int m_Emode; - double m_L1, m_Efix, m_TwoTheta, m_L2; + double m_L1, m_Efix, m_TwoTheta, m_L2, m_DIFA, m_DIFC, m_TZERO; std::vector<double> const *m_pTwoThetas; std::vector<double> const *m_pL2s; // pointer to detector specific input energy (eFixed) defined for indirect // instruments; float *m_pEfixedArray; + std::vector<double> const *m_pDIFAs; + std::vector<double> const *m_pDIFCs; + std::vector<double> const *m_pTZEROs; public: UnitsConversionHelper(); diff --git a/Framework/MDAlgorithms/src/PreprocessDetectorsToMD.cpp b/Framework/MDAlgorithms/src/PreprocessDetectorsToMD.cpp index 34e03a3dd87e53592a2e8e66da29bf20565a7e68..2a8740cd2eb282736130282e8255b4515e20541c 100644 --- a/Framework/MDAlgorithms/src/PreprocessDetectorsToMD.cpp +++ b/Framework/MDAlgorithms/src/PreprocessDetectorsToMD.cpp @@ -161,6 +161,9 @@ PreprocessDetectorsToMD::createTableWorkspace( m_getEFixed = this->getProperty("GetEFixed"); if (m_getEFixed) targWS->addColumn("float", "eFixed"); + targWS->addColumn("double", "DIFA"); + targWS->addColumn("double", "DIFC"); + targWS->addColumn("double", "TZERO"); // will see about that // sin^2(Theta) @@ -220,6 +223,9 @@ void PreprocessDetectorsToMD::processDetectorsPositions( auto &TwoTheta = targWS->getColVector<double>("TwoTheta"); auto &Azimuthal = targWS->getColVector<double>("Azimuthal"); auto &detDir = targWS->getColVector<Kernel::V3D>("DetDirections"); + auto &DIFA = targWS->getColVector<double>("DIFA"); + auto &DIFC = targWS->getColVector<double>("DIFC"); + auto &TZERO = targWS->getColVector<double>("TZERO"); // Efixed; do we need one and does one exist? auto Efi = targWS->getLogs()->getPropertyValueAsType<double>("Ei"); @@ -272,6 +278,13 @@ void PreprocessDetectorsToMD::processDetectorsPositions( TwoTheta[liveDetectorsCount] = polar; Azimuthal[liveDetectorsCount] = azim; + std::vector<int> warningDets; + auto diffConsts = spectrumInfo.diffractometerConstants(i, warningDets); + // map will create an entry with zero value if not present already + DIFA[liveDetectorsCount] = diffConsts[Kernel::UnitParams::difa]; + DIFC[liveDetectorsCount] = diffConsts[Kernel::UnitParams::difc]; + TZERO[liveDetectorsCount] = diffConsts[Kernel::UnitParams::tzero]; + double sPhi = sin(polar); double ez = cos(polar); double ex = sPhi * cos(azim); diff --git a/Framework/MDAlgorithms/src/UnitsConversionHelper.cpp b/Framework/MDAlgorithms/src/UnitsConversionHelper.cpp index a327a4b6223f0108c065695c566aac0b91ec46a6..186b8f5d0c97c7bea95e178e814497b0e8f6bf16 100644 --- a/Framework/MDAlgorithms/src/UnitsConversionHelper.cpp +++ b/Framework/MDAlgorithms/src/UnitsConversionHelper.cpp @@ -10,6 +10,8 @@ #include "MantidKernel/UnitFactory.h" #include <cmath> +using Mantid::Kernel::UnitParams; + namespace Mantid { namespace MDAlgorithms { @@ -265,6 +267,10 @@ void UnitsConversionHelper::initialize( if (m_Emode == static_cast<int>(Kernel::DeltaEMode::Indirect)) m_pEfixedArray = DetWS->getColDataArray<float>("eFixed"); + m_pDIFAs = &(DetWS->getColVector<double>("DIFA")); + m_pDIFCs = &(DetWS->getColVector<double>("DIFC")); + m_pTZEROs = &(DetWS->getColVector<double>("TZERO")); + // set up conversion to working state -- in some tests it can be used straight // from the beginning. m_TwoTheta = (*m_pTwoThetas)[0]; @@ -272,14 +278,29 @@ void UnitsConversionHelper::initialize( double Efix = m_Efix; if (m_pEfixedArray) Efix = static_cast<double>(*(m_pEfixedArray + 0)); - - m_TargetUnit->initialize(m_L1, m_L2, m_TwoTheta, m_Emode, Efix, 0.); + m_DIFA = (*m_pDIFAs)[0]; + m_DIFC = (*m_pDIFCs)[0]; + m_TZERO = (*m_pTZEROs)[0]; + + m_TargetUnit->initialize(m_L1, m_Emode, + {{UnitParams::l2, m_L2}, + {UnitParams::twoTheta, m_TwoTheta}, + {UnitParams::efixed, Efix}, + {UnitParams::difa, m_DIFA}, + {UnitParams::difc, m_DIFC}, + {UnitParams::tzero, m_TZERO}}); if (m_SourceWSUnit) { - m_SourceWSUnit->initialize(m_L1, m_L2, m_TwoTheta, m_Emode, Efix, 0.); + m_SourceWSUnit->initialize(m_L1, m_Emode, + {{UnitParams::l2, m_L2}, + {UnitParams::twoTheta, m_TwoTheta}, + {UnitParams::efixed, Efix}, + {UnitParams::difa, m_DIFA}, + {UnitParams::difc, m_DIFC}, + {UnitParams::tzero, m_TZERO}}); } } -/** Method updates unit conversion given the index of detector parameters in the - * array of detectors */ +/** Method updates unit conversion given the index of detector parameters in + * the array of detectors */ void UnitsConversionHelper::updateConversion(size_t i) { switch (m_UnitCnvrsn) { case (CnvrtToMD::ConvertNo): @@ -287,33 +308,47 @@ void UnitsConversionHelper::updateConversion(size_t i) { case (CnvrtToMD::ConvertFast): return; case (CnvrtToMD::ConvertFromTOF): { - double delta(std::numeric_limits<double>::quiet_NaN()); m_TwoTheta = (*m_pTwoThetas)[i]; m_L2 = (*m_pL2s)[i]; double Efix = m_Efix; if (m_pEfixedArray) Efix = static_cast<double>(*(m_pEfixedArray + i)); - - m_TargetUnit->initialize(m_L1, m_L2, m_TwoTheta, m_Emode, Efix, delta); + m_DIFA = (*m_pDIFAs)[i]; + m_DIFC = (*m_pDIFCs)[i]; + m_TZERO = (*m_pTZEROs)[i]; + + m_TargetUnit->initialize(m_L1, m_Emode, + {{UnitParams::l2, m_L2}, + {UnitParams::twoTheta, m_TwoTheta}, + {UnitParams::efixed, Efix}, + {UnitParams::difa, m_DIFA}, + {UnitParams::difc, m_DIFC}, + {UnitParams::tzero, m_TZERO}}); return; } case (CnvrtToMD::ConvertByTOF): { - double delta(std::numeric_limits<double>::quiet_NaN()); m_TwoTheta = (*m_pTwoThetas)[i]; m_L2 = (*m_pL2s)[i]; double Efix = m_Efix; if (m_pEfixedArray) Efix = static_cast<double>(*(m_pEfixedArray + i)); - - m_TargetUnit->initialize(m_L1, m_L2, m_TwoTheta, m_Emode, Efix, delta); - m_SourceWSUnit->initialize(m_L1, m_L2, m_TwoTheta, m_Emode, Efix, delta); + m_DIFA = (*m_pDIFAs)[i]; + m_DIFC = (*m_pDIFCs)[i]; + m_TZERO = (*m_pTZEROs)[i]; + + Kernel::UnitParametersMap pmap = { + {UnitParams::l2, m_L2}, {UnitParams::twoTheta, m_TwoTheta}, + {UnitParams::efixed, Efix}, {UnitParams::difa, m_DIFA}, + {UnitParams::difc, m_DIFC}, {UnitParams::tzero, m_TZERO}}; + m_TargetUnit->initialize(m_L1, m_Emode, pmap); + m_SourceWSUnit->initialize(m_L1, m_Emode, pmap); return; } default: throw std::runtime_error( "updateConversion: unknown type of conversion requested"); } -} +} // namespace MDAlgorithms /** do actual unit conversion from input to oputput data @param val -- the input value which has to be converted @return the input value converted into the units requested. @@ -350,9 +385,15 @@ UnitsConversionHelper::UnitsConversionHelper( m_Efix = another.m_Efix; m_TwoTheta = another.m_TwoTheta; m_L2 = another.m_L2; + m_DIFA = another.m_DIFA; + m_DIFC = another.m_DIFC; + m_TZERO = another.m_TZERO; m_pTwoThetas = another.m_pTwoThetas; m_pL2s = another.m_pL2s; m_pEfixedArray = another.m_pEfixedArray; + m_pDIFAs = another.m_pDIFAs; + m_pDIFCs = another.m_pDIFCs; + m_pTZEROs = another.m_pTZEROs; if (another.m_SourceWSUnit) m_SourceWSUnit = Kernel::Unit_sptr(another.m_SourceWSUnit->clone()); @@ -363,8 +404,10 @@ UnitsConversionHelper::UnitsConversionHelper( UnitsConversionHelper::UnitsConversionHelper() : m_UnitCnvrsn(CnvrtToMD::ConvertNo), m_Factor(1), m_Power(1), m_Emode(-1), // undefined - m_L1(1), m_Efix(1), m_TwoTheta(0), m_L2(1), m_pTwoThetas(nullptr), - m_pL2s(nullptr), m_pEfixedArray(nullptr) {} + m_L1(1), m_Efix(1), m_TwoTheta(0), m_L2(1), m_DIFA(0.), m_DIFC(0.), + m_TZERO(0.), m_pTwoThetas(nullptr), m_pL2s(nullptr), + m_pEfixedArray(nullptr), m_pDIFAs(nullptr), m_pDIFCs(nullptr), + m_pTZEROs(nullptr) {} } // namespace MDAlgorithms } // namespace Mantid diff --git a/Framework/MDAlgorithms/test/MDTransfModQTest.h b/Framework/MDAlgorithms/test/MDTransfModQTest.h index d03727735866e5ef7dcdece1fd638015d50e3c3c..73128cba17fc04c860aa00e6caa8a2d1c7129365 100644 --- a/Framework/MDAlgorithms/test/MDTransfModQTest.h +++ b/Framework/MDAlgorithms/test/MDTransfModQTest.h @@ -6,6 +6,7 @@ // SPDX - License - Identifier: GPL - 3.0 + #pragma once +#include "MantidAPI/AlgorithmManager.h" #include "MantidGeometry/Instrument/Goniometer.h" #include "MantidKernel/DeltaEMode.h" #include "MantidMDAlgorithms/MDTransfQ3D.h" @@ -179,8 +180,14 @@ public: ModQTransf.initialize(WSDescr), const std::runtime_error &); // let's preprocess detectors positions to go any further - WSDescr.m_PreprDetTable = - WorkspaceCreationHelper::buildPreprocessedDetectorsWorkspace(ws2Dbig); + auto ppDets_alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged( + "PreprocessDetectorsToMD"); + ppDets_alg->initialize(); + ppDets_alg->setChild(true); + ppDets_alg->setProperty("InputWorkspace", ws2Dbig); + ppDets_alg->setProperty("OutputWorkspace", "UnitsConversionHelperTableWs"); + ppDets_alg->execute(); + WSDescr.m_PreprDetTable = ppDets_alg->getProperty("OutputWorkspace"); TSM_ASSERT_THROWS_NOTHING("should initialize properly: ", ModQTransf.initialize(WSDescr)); std::vector<coord_t> coord(4); diff --git a/Framework/MDAlgorithms/test/MDTransfQ3DTest.h b/Framework/MDAlgorithms/test/MDTransfQ3DTest.h index 73349981b759e484ed458f5fffec7dda2ed50a87..f570a2f8d3bdcb1f9bb19554b483fb44063ca17f 100644 --- a/Framework/MDAlgorithms/test/MDTransfQ3DTest.h +++ b/Framework/MDAlgorithms/test/MDTransfQ3DTest.h @@ -6,6 +6,7 @@ // SPDX - License - Identifier: GPL - 3.0 + #pragma once +#include "MantidAPI/AlgorithmManager.h" #include "MantidGeometry/Instrument.h" #include "MantidGeometry/Instrument/Goniometer.h" #include "MantidKernel/DeltaEMode.h" @@ -43,9 +44,14 @@ createTestTransform(const double efixed, const DeltaEMode::Type emode) { wsDescription.setMinMax({-100, -100, -100, -100}, {100, 100, 100, 100}); wsDescription.buildFromMatrixWS(indirectInelasticWS, q3dTransform.transfID(), DeltaEMode::asString(emode), {}); - wsDescription.m_PreprDetTable = - WorkspaceCreationHelper::buildPreprocessedDetectorsWorkspace( - indirectInelasticWS); + auto ppDets_alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged( + "PreprocessDetectorsToMD"); + ppDets_alg->initialize(); + ppDets_alg->setChild(true); + ppDets_alg->setProperty("InputWorkspace", indirectInelasticWS); + ppDets_alg->setProperty("OutputWorkspace", "UnitsConversionHelperTableWs"); + ppDets_alg->execute(); + wsDescription.m_PreprDetTable = ppDets_alg->getProperty("OutputWorkspace"); q3dTransform.initialize(wsDescription); return std::make_tuple(q3dTransform, wsDescription); @@ -147,9 +153,14 @@ public: Q3DTransf.initialize(wsDescription), const std::runtime_error &) // let's preprocess detectors positions to go any further - wsDescription.m_PreprDetTable = - WorkspaceCreationHelper::buildPreprocessedDetectorsWorkspace( - elasticTestWS); + auto ppDets_alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged( + "PreprocessDetectorsToMD"); + ppDets_alg->initialize(); + ppDets_alg->setChild(true); + ppDets_alg->setProperty("InputWorkspace", elasticTestWS); + ppDets_alg->setProperty("OutputWorkspace", "UnitsConversionHelperTableWs"); + ppDets_alg->execute(); + wsDescription.m_PreprDetTable = ppDets_alg->getProperty("OutputWorkspace"); // let's set 2Theta=0 for simplicity and violate const correctness for // testing purposes here auto &TwoTheta = const_cast<std::vector<double> &>( diff --git a/Framework/MDAlgorithms/test/PreprocessDetectorsToMDTest.h b/Framework/MDAlgorithms/test/PreprocessDetectorsToMDTest.h index 8cb1315a6c9faf52c3d16f3df0fd77c204c49cb4..6aec885ed33f05e6f97e995c29ac13302de23cec 100644 --- a/Framework/MDAlgorithms/test/PreprocessDetectorsToMDTest.h +++ b/Framework/MDAlgorithms/test/PreprocessDetectorsToMDTest.h @@ -55,7 +55,7 @@ public: TS_ASSERT(tws); TS_ASSERT_EQUALS(4, tws->rowCount()); - TS_ASSERT_EQUALS(8, tws->columnCount()); + TS_ASSERT_EQUALS(11, tws->columnCount()); } void testPreprocessDetectors() { diff --git a/Framework/MDAlgorithms/test/UnitsConversionHelperTest.h b/Framework/MDAlgorithms/test/UnitsConversionHelperTest.h index ca9f8b0f0889d5f8622ec5989cab3c21683d10a6..ce0d1fd493d4bb7a8e6655b59a845b03a22d288e 100644 --- a/Framework/MDAlgorithms/test/UnitsConversionHelperTest.h +++ b/Framework/MDAlgorithms/test/UnitsConversionHelperTest.h @@ -6,6 +6,7 @@ // SPDX - License - Identifier: GPL - 3.0 + #pragma once +#include "MantidAPI/AlgorithmManager.h" #include "MantidAPI/FrameworkManager.h" #include "MantidAPI/NumericAxis.h" #include "MantidKernel/PhysicalConstants.h" @@ -45,13 +46,19 @@ public: auto pSourceWSUnit = UnitFactory::Instance().create("Wavelength"); auto pWSUnit = UnitFactory::Instance().create("MomentumTransfer"); - double delta; double L1(10), L2(10), TwoTheta(0.1), efix(10); + int emode(0); TS_ASSERT_THROWS_NOTHING( - pWSUnit->initialize(L1, L2, TwoTheta, emode, efix, delta)); + pWSUnit->initialize(L1, emode, + {{UnitParams::l2, L2}, + {UnitParams::twoTheta, TwoTheta}, + {UnitParams::efixed, efix}})); TS_ASSERT_THROWS_NOTHING( - pSourceWSUnit->initialize(L1, L2, TwoTheta, emode, efix, delta)); + pSourceWSUnit->initialize(L1, emode, + {{UnitParams::l2, L2}, + {UnitParams::twoTheta, TwoTheta}, + {UnitParams::efixed, efix}})); double X0(5); double tof(0); @@ -287,6 +294,13 @@ public: ws2D = WorkspaceCreationHelper::createProcessedInelasticWS( L2, polar, azimutal, numBins, -1, 3, 3); - detLoc = WorkspaceCreationHelper::buildPreprocessedDetectorsWorkspace(ws2D); + auto ppDets_alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged( + "PreprocessDetectorsToMD"); + ppDets_alg->initialize(); + ppDets_alg->setChild(true); + ppDets_alg->setProperty("InputWorkspace", ws2D); + ppDets_alg->setProperty("OutputWorkspace", "UnitsConversionHelperTableWs"); + ppDets_alg->execute(); + detLoc = ppDets_alg->getProperty("OutputWorkspace"); } }; \ No newline at end of file diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/Unit.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/Unit.cpp index dd8458c298e0be85627775e99e01fe5f70a95275..9d750c5d1ba844b04f98ea8a73817d807abe671f 100644 --- a/Framework/PythonInterface/mantid/kernel/src/Exports/Unit.cpp +++ b/Framework/PythonInterface/mantid/kernel/src/Exports/Unit.cpp @@ -8,6 +8,7 @@ #include "MantidPythonInterface/core/GetPointer.h" #include <boost/python/class.hpp> +#include <boost/python/enum.hpp> #include <boost/python/register_ptr_to_python.hpp> #include <boost/python/tuple.hpp> @@ -57,6 +58,15 @@ void export_Unit() { register_ptr_to_python<std::shared_ptr<Unit>>(); + enum_<Mantid::Kernel::UnitParams>("UnitParams") + .value("l2", Mantid::Kernel::UnitParams::l2) + .value("twoTheta", Mantid::Kernel::UnitParams::twoTheta) + .value("delta", Mantid::Kernel::UnitParams::delta) + .value("efixed", Mantid::Kernel::UnitParams::efixed) + .value("difa", Mantid::Kernel::UnitParams::difa) + .value("difc", Mantid::Kernel::UnitParams::difc) + .value("tzero", Mantid::Kernel::UnitParams::tzero); + class_<Unit, boost::noncopyable>("Unit", no_init) .def("name", &deprecatedName, arg("self"), "Return the full name of the unit (deprecated, use caption)") diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/UnitConversion.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/UnitConversion.cpp index 7e371ad185ef594a874a0b836d2a9ab74b4b32ab..0579e67257838d2146d691e889f5b66a87292b60 100644 --- a/Framework/PythonInterface/mantid/kernel/src/Exports/UnitConversion.cpp +++ b/Framework/PythonInterface/mantid/kernel/src/Exports/UnitConversion.cpp @@ -6,21 +6,42 @@ // SPDX - License - Identifier: GPL - 3.0 + #include "MantidKernel/UnitConversion.h" #include <boost/python/class.hpp> +#include <boost/python/suite/indexing/map_indexing_suite.hpp> using Mantid::Kernel::DeltaEMode; using Mantid::Kernel::UnitConversion; using namespace boost::python; +double deprecatedSignature(const std::string &src, const std::string &dest, + const double srcValue, const double l1, + const double l2, const double theta, + const DeltaEMode::Type emode, const double efixed) { + PyErr_Warn( + PyExc_DeprecationWarning, + ".run(src, dest, srcValue, l1, l2, theta, emode, efixed) is deprecated. " + "Use .run(src, dest, srcValue, l1, emode, params) instead."); + return UnitConversion::run(src, dest, srcValue, l1, l2, theta, emode, efixed); +} + void export_UnitConversion() { // Function pointer typedef - using StringVersion = double (*)( + using newStringVersion = double (*)( const std::string &, const std::string &, const double, const double, - const double, const double, const DeltaEMode::Type, const double); + const DeltaEMode::Type, const Mantid::Kernel::UnitParametersMap &); + + class_<std::unordered_map<Mantid::Kernel::UnitParams, double>>( + "UnitParametersMap") + .def(map_indexing_suite< + std::unordered_map<Mantid::Kernel::UnitParams, double>>()); class_<UnitConversion, boost::noncopyable>("UnitConversion", no_init) - .def("run", (StringVersion)&UnitConversion::run, + .def("run", &deprecatedSignature, (arg("src"), arg("dest"), arg("srcValue"), arg("l1"), arg("l2"), arg("theta"), arg("emode"), arg("efixed")), + "Performs a unit conversion on a single value (deprecated).") + .def("run", (newStringVersion)&UnitConversion::run, + (arg("src"), arg("dest"), arg("srcValue"), arg("l1"), arg("emode"), + arg("params")), "Performs a unit conversion on a single value.") .staticmethod("run"); } diff --git a/Framework/PythonInterface/test/python/mantid/kernel/UnitConversionTest.py b/Framework/PythonInterface/test/python/mantid/kernel/UnitConversionTest.py index 4b8ebf717e17d93ffc7e8b02b577491f31b43ffe..4bc63af249428b295c8cb756ac8890cdc552728b 100644 --- a/Framework/PythonInterface/test/python/mantid/kernel/UnitConversionTest.py +++ b/Framework/PythonInterface/test/python/mantid/kernel/UnitConversionTest.py @@ -5,7 +5,7 @@ # Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS # SPDX - License - Identifier: GPL - 3.0 + import unittest -from mantid.kernel import UnitConversion, DeltaEModeType +from mantid.kernel import UnitConversion, DeltaEModeType, UnitParams, UnitParametersMap import math @@ -23,5 +23,22 @@ class UnitConversionTest(unittest.TestCase): result = UnitConversion.run(src_unit, dest_unit, src_value, l1, l2, theta, emode, efixed) self.assertAlmostEqual(result, expected, 12) + def test_run_accepts_params_version(self): + src_unit = "Wavelength" + src_value = 1.5 + dest_unit = "Momentum" + + l1 = l2 = theta = efixed = 0.0 + emode = DeltaEModeType.Indirect; + expected = 2.0*math.pi/src_value + params = UnitParametersMap() + params[UnitParams.l2] = l2 + params[UnitParams.twoTheta] = theta + # Haven't got a dictionary to convert automatically into std::unordered_map yet + #params = {UnitParams.l2: l2, UnitParams.twoTheta: theta} + + result = UnitConversion.run(src_unit, dest_unit, src_value, l1, emode, params) + self.assertAlmostEqual(result, expected, 12) + if __name__ == '__main__': unittest.main() diff --git a/Framework/SINQ/src/PoldiPeakSearch.cpp b/Framework/SINQ/src/PoldiPeakSearch.cpp index d16c4966824658d5d522a3c30ba1532708f514af..519ecf47cd43b8494abb53d998b7135cfa192ce3 100644 --- a/Framework/SINQ/src/PoldiPeakSearch.cpp +++ b/Framework/SINQ/src/PoldiPeakSearch.cpp @@ -224,8 +224,8 @@ double PoldiPeakSearch::getTransformedCenter(double value, // Transform value to d-spacing. Unit_sptr dUnit = UnitFactory::Instance().create("dSpacing"); - return UnitConversion::run((*transformUnit), (*dUnit), value, 0, 0, 0, - DeltaEMode::Elastic, 0.0); + return UnitConversion::run((*transformUnit), (*dUnit), value, 0, + DeltaEMode::Elastic); } /** Creates PoldiPeak-objects from peak position iterators diff --git a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp index aa0b53078a1f70fd1ce0d965e8e13da34f320485..e405ff29092fc2735500d396d3fadda110ac448c 100644 --- a/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp +++ b/Framework/TestHelpers/src/WorkspaceCreationHelper.cpp @@ -1356,134 +1356,6 @@ createPeaksWorkspace(const int numPeaks, return peaksWS; } -/** helper method to create preprocessed detector's table workspace */ -std::shared_ptr<DataObjects::TableWorkspace> -createTableWorkspace(const API::MatrixWorkspace_const_sptr &inputWS) { - const size_t nHist = inputWS->getNumberHistograms(); - - // set the target workspace - auto targWS = std::make_shared<TableWorkspace>(nHist); - // detectors positions - targWS->addColumn("V3D", "DetDirections"); - // sample-detector distance; - targWS->addColumn("double", "L2"); - // Diffraction angle - targWS->addColumn("double", "TwoTheta"); - targWS->addColumn("double", "Azimuthal"); - // the detector ID; - targWS->addColumn("int", "DetectorID"); - // stores spectra index which corresponds to a valid detector index; - targWS->addColumn("size_t", "detIDMap"); - // stores detector index which corresponds to the workspace index; - targWS->addColumn("size_t", "spec2detMap"); - - // will see about that - // sin^2(Theta) - // std::vector<double> SinThetaSq; - - //,"If the detectors were actually processed from real instrument or generated - // for some fake one "); - return targWS; -} - -/** method does preliminary calculations of the detectors positions to convert - results into k-dE space ; - and places the results into static cash to be used in subsequent calls to this - algorithm */ -void processDetectorsPositions(const API::MatrixWorkspace_const_sptr &inputWS, - DataObjects::TableWorkspace_sptr &targWS, - double Ei) { - Geometry::Instrument_const_sptr instrument = inputWS->getInstrument(); - // - Geometry::IComponent_const_sptr source = instrument->getSource(); - Geometry::IComponent_const_sptr sample = instrument->getSample(); - if ((!source) || (!sample)) { - - throw Kernel::Exception::InstrumentDefinitionError( - "Instrument not sufficiently defined: failed to get source and/or " - "sample"); - } - - // L1 - try { - double L1 = source->getDistance(*sample); - targWS->logs()->addProperty<double>("L1", L1, true); - } catch (Kernel::Exception::NotFoundError &) { - throw Kernel::Exception::InstrumentDefinitionError( - "Unable to calculate source-sample distance for workspace", - inputWS->getTitle()); - } - // Instrument name - std::string InstrName = instrument->getName(); - targWS->logs()->addProperty<std::string>("InstrumentName", InstrName, true); - targWS->logs()->addProperty<bool>("FakeDetectors", false, true); - // Incident energy for Direct or Analysis energy for indirect instrument; - targWS->logs()->addProperty<double>("Ei", Ei, true); - - // get access to the workspace memory - auto &sp2detMap = targWS->getColVector<size_t>("spec2detMap"); - auto &detId = targWS->getColVector<int32_t>("DetectorID"); - auto &detIDMap = targWS->getColVector<size_t>("detIDMap"); - auto &L2 = targWS->getColVector<double>("L2"); - auto &TwoTheta = targWS->getColVector<double>("TwoTheta"); - auto &Azimuthal = targWS->getColVector<double>("Azimuthal"); - auto &detDir = targWS->getColVector<Kernel::V3D>("DetDirections"); - - //// progress messave appearence - size_t nHist = targWS->rowCount(); - //// Loop over the spectra - uint32_t liveDetectorsCount(0); - const auto &spectrumInfo = inputWS->spectrumInfo(); - for (size_t i = 0; i < nHist; i++) { - sp2detMap[i] = std::numeric_limits<size_t>::quiet_NaN(); - detId[i] = std::numeric_limits<int32_t>::quiet_NaN(); - detIDMap[i] = std::numeric_limits<size_t>::quiet_NaN(); - L2[i] = std::numeric_limits<double>::quiet_NaN(); - TwoTheta[i] = std::numeric_limits<double>::quiet_NaN(); - Azimuthal[i] = std::numeric_limits<double>::quiet_NaN(); - - if (!spectrumInfo.hasDetectors(i) || spectrumInfo.isMonitor(i)) - continue; - - // calculate the requested values; - sp2detMap[i] = liveDetectorsCount; - detId[liveDetectorsCount] = int32_t(spectrumInfo.detector(i).getID()); - detIDMap[liveDetectorsCount] = i; - L2[liveDetectorsCount] = spectrumInfo.l2(i); - - double polar = spectrumInfo.twoTheta(i); - double azim = spectrumInfo.detector(i).getPhi(); - TwoTheta[liveDetectorsCount] = polar; - Azimuthal[liveDetectorsCount] = azim; - - double sPhi = sin(polar); - double ez = cos(polar); - double ex = sPhi * cos(azim); - double ey = sPhi * sin(azim); - - detDir[liveDetectorsCount].setX(ex); - detDir[liveDetectorsCount].setY(ey); - detDir[liveDetectorsCount].setZ(ez); - - // double sinTheta=sin(0.5*polar); - // this->SinThetaSq[liveDetectorsCount] = sinTheta*sinTheta; - - liveDetectorsCount++; - } - targWS->logs()->addProperty<uint32_t>( - "ActualDetectorsNum", liveDetectorsCount, - true); //,"The actual number of detectors receivinv signal"); -} - -std::shared_ptr<Mantid::DataObjects::TableWorkspace> -buildPreprocessedDetectorsWorkspace( - const Mantid::API::MatrixWorkspace_sptr &ws) { - Mantid::DataObjects::TableWorkspace_sptr DetPos = createTableWorkspace(ws); - auto Ei = ws->run().getPropertyValueAsType<double>("Ei"); - processDetectorsPositions(ws, DetPos, Ei); - - return DetPos; -} void create2DAngles(std::vector<double> &L2, std::vector<double> &polar, std::vector<double> &azim, size_t nPolar, size_t nAzim, double polStart, double polEnd, double azimStart, diff --git a/Testing/Data/SystemTest/ISIS_Powder/input/calibration/hrp/16_5/ISIS_Powder-HRPD-VanSplined_66031_hrpd_new_072_01_corr.cal.nxs.md5 b/Testing/Data/SystemTest/ISIS_Powder/input/calibration/hrp/16_5/ISIS_Powder-HRPD-VanSplined_66031_hrpd_new_072_01_corr.cal.nxs.md5 index e932090757cf5c7aed40586b630187f58edc5467..74b69e93ad5924e08c079dd70dd4cf85dcce8abf 100644 --- a/Testing/Data/SystemTest/ISIS_Powder/input/calibration/hrp/16_5/ISIS_Powder-HRPD-VanSplined_66031_hrpd_new_072_01_corr.cal.nxs.md5 +++ b/Testing/Data/SystemTest/ISIS_Powder/input/calibration/hrp/16_5/ISIS_Powder-HRPD-VanSplined_66031_hrpd_new_072_01_corr.cal.nxs.md5 @@ -1 +1 @@ -a2ec43e892f8d2188afb7ab40fa314b0 +608f0a5a0776e7c4318c277306409a75 diff --git a/Testing/SystemTests/tests/framework/EnginXScriptTest.py b/Testing/SystemTests/tests/framework/EnginXScriptTest.py index 21592257bd79535d6fad8f6562d8ae2abd6d5875..73383e66b736596e89e1121b6972dac812c8375d 100644 --- a/Testing/SystemTests/tests/framework/EnginXScriptTest.py +++ b/Testing/SystemTests/tests/framework/EnginXScriptTest.py @@ -10,7 +10,7 @@ import systemtesting import mantid.simpleapi as simple -from mantid import config +from mantid import config, mtd from Engineering.EnginX import main DIRS = config['datasearch.directories'].split(';') @@ -73,19 +73,28 @@ class CreateCalibrationCroppedTest(systemtesting.MantidSystemTest): main(vanadium_run="236516", user="test", focus_run=None, do_cal=True, force_cal=True, directory=cal_directory, crop_type="spectra", crop_on="1-20") + def validateSingleColumn(self, col1, col2, tolerance): + assert len(col1)==len(col2) + for a, b in zip(col1, col2): + den = 0.5 * (abs(a) + abs(b)) + assert (abs(a - b) / den) < tolerance + def validate(self): self.tolerance_is_rel_err = True self.tolerance = 1e-2 # this is neccesary due to appendspectra creating spectrum numbers of 0 self.disableChecking.append('SpectraMap') + # fitted peaks table workspace is v sensitive to changes in input data so just validate X0 col if systemtesting.using_gsl_v1(): - return ("cropped", "engggui_calibration_bank_cropped_gsl1.nxs", - "engg_calibration_banks_parameters", "engggui_calibration_cropped_parameters_gsl1.nxs", + reffile = simple.LoadNexus(Filename="engggui_calibration_bank_cropped_gsl1.nxs") + self.validateSingleColumn(mtd["cropped"].column("X0"),reffile.column("X0"),self.tolerance) + return ("engg_calibration_banks_parameters", "engggui_calibration_cropped_parameters_gsl1.nxs", "Engg difc Zero Peaks Bank cropped", "engggui_difc_zero_peaks_bank_cropped_gsl1.nxs") else: - return ("cropped", "engggui_calibration_bank_cropped.nxs", - "engg_calibration_banks_parameters", "engggui_calibration_bank_cropped_parameters.nxs", + reffile = simple.LoadNexus(Filename="engggui_calibration_bank_cropped.nxs") + self.validateSingleColumn(mtd["cropped"].column("X0"),reffile.column("X0"),self.tolerance) + return ("engg_calibration_banks_parameters", "engggui_calibration_bank_cropped_parameters.nxs", "Engg difc Zero Peaks Bank cropped", "engggui_difc_zero_peaks_bank_cropped.nxs") def cleanup(self): diff --git a/Testing/SystemTests/tests/framework/ISIS_PowderPolarisTest.py b/Testing/SystemTests/tests/framework/ISIS_PowderPolarisTest.py index ef4cf93f5cf5eb4864ffff700166942a409f100d..ab3e737e644161e76c080e5ea59b3e13bdf22a33 100644 --- a/Testing/SystemTests/tests/framework/ISIS_PowderPolarisTest.py +++ b/Testing/SystemTests/tests/framework/ISIS_PowderPolarisTest.py @@ -63,8 +63,8 @@ class CreateVanadiumTest(systemtesting.MantidSystemTest): splined_ws, unsplined_ws = self.calibration_results for ws in splined_ws+unsplined_ws: self.assertEqual(ws.sample().getMaterial().name(), 'V') - return (unsplined_ws.name(), "ISIS_Powder-POLARIS00098533_unsplined.nxs", - splined_ws.name(), "ISIS_Powder-POLARIS00098533_splined.nxs") + return (unsplined_ws.name(), "ISIS_Powder-POLARIS00098532_unsplined.nxs", + splined_ws.name(), "ISIS_Powder-POLARIS00098532_splined.nxs") def cleanup(self): try: @@ -108,7 +108,8 @@ class FocusTest(systemtesting.MantidSystemTest): for ws in self.focus_results: self.assertEqual(ws.sample().getMaterial().name(), 'Si') - self.tolerance = 1e-7 + self.tolerance_is_rel_err = True + self.tolerance = 1e-6 return self.focus_results.name(), "ISIS_Powder-POLARIS98533_FocusSempty.nxs" def cleanup(self): diff --git a/Testing/SystemTests/tests/framework/reference/HRPD66063_focused.nxs.md5 b/Testing/SystemTests/tests/framework/reference/HRPD66063_focused.nxs.md5 index e15d64c7d356898159b330d8f8663cda9f1a4913..cfc032862af689ccf1afa5bee1841445b4c29009 100644 --- a/Testing/SystemTests/tests/framework/reference/HRPD66063_focused.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/HRPD66063_focused.nxs.md5 @@ -1 +1 @@ -8c3a6b213a055248e8a24a7057c095d6 +1be2026d1de55fd2bed0a6f8ddfc4d39 diff --git a/Testing/SystemTests/tests/framework/reference/HRPD66063_focused_with_sac.nxs.md5 b/Testing/SystemTests/tests/framework/reference/HRPD66063_focused_with_sac.nxs.md5 index 7722a1b9661b05fe79506c46e5336a1757b372c2..4c86bda5634b41b8796664a98d26c391e924ba3f 100644 --- a/Testing/SystemTests/tests/framework/reference/HRPD66063_focused_with_sac.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/HRPD66063_focused_with_sac.nxs.md5 @@ -1 +1 @@ -4e22b59dcf154fe612664caad97106a5 +37ca9e41dadb8209c48a94456b293424 diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM83605_FocusSempty.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM83605_FocusSempty.nxs.md5 index 829a5bf235854f5599dbea56c6aace748e8e462b..14147199e4f3b4eac0211ba479716e0c9cc6ca99 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM83605_FocusSempty.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM83605_FocusSempty.nxs.md5 @@ -1 +1 @@ -66daa3c0ca467551327f0fab16603176 +ecea38a404523a3760af402b23ba138d diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM83605_FocusSempty_abscorr.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM83605_FocusSempty_abscorr.nxs.md5 index 46f87415aa779faca870815277b7f888c5c4c979..450cc2132b9b75e641d34f083adba7269c33639e 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM83605_FocusSempty_abscorr.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM83605_FocusSempty_abscorr.nxs.md5 @@ -1 +1 @@ -4449362e48a44a6b9dd022e94bbea290 +3a4603faeb65bdac0c39438df73b6ae1 diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM87618_grouped.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM87618_grouped.nxs.md5 index 99802ed127ec851ff85bead36382901d21b32a79..ae217da0e72640706087aaefe87c89afc64d9729 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM87618_grouped.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM87618_grouped.nxs.md5 @@ -1 +1 @@ -66c9c9248b6aa178ea50be7722aebaca +49479cfe5b2ef222d6fef8e7262b33fe diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM87618_groupedGSAS1.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM87618_groupedGSAS1.nxs.md5 index 88231da7cc10cd6fefd727e7af62ccf34d6eb92a..7db8702743e3420c7f6c5e6413ce35850f9b2e17 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM87618_groupedGSAS1.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-GEM87618_groupedGSAS1.nxs.md5 @@ -1 +1 @@ -8e69351a25f506a59d3de8ca6a68403a +9cf6f0ffda00dfcad3d186590434b7d5 diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098472_splined.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098472_splined.nxs.md5 index 52b72dec866425098afe83ef1cc55dd1358c473b..1c048e99c58ca027af4b79664bf7dd11ae318028 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098472_splined.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098472_splined.nxs.md5 @@ -1 +1 @@ -a828d3c74ab4ce5876aae29e61794f22 +912967bbcca604e98b02540b2d1d069d diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098507_tt70Atten.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098507_tt70Atten.nxs.md5 index 62a7f42f93600ba829c93c99d8dfc8fd584728fc..66f96e555bb1b0f41cde7af01b5435e8c47a19d2 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098507_tt70Atten.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098507_tt70Atten.nxs.md5 @@ -1 +1 @@ -1b79639f158a73a1f1f4d76da14f4ae4 +fdacd843f9fbe1f8309fcc55d75ffa3a diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098507_tt70NoEmptySub.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098507_tt70NoEmptySub.nxs.md5 index ba8e617da7b8af635a8753278a2c1202ebbbd54b..b8dcb8acae0c7a8f5da2a09983a026958d1e10e2 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098507_tt70NoEmptySub.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098507_tt70NoEmptySub.nxs.md5 @@ -1 +1 @@ -205ea520333c267369b8c750b7c8afaf +1d4149c223976a13cc0231315fd8a423 diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098507_tt70_absorb.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098507_tt70_absorb.nxs.md5 index 74e9ea2361d64e5e0e147dd88fe2ab9caecdc2c9..769f6dfcd6d28a2384005e09d8ff209e8d83b57f 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098507_tt70_absorb.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL00098507_tt70_absorb.nxs.md5 @@ -1 +1 @@ -a22807ee5cd6565886832ddba9cb3f16 +7ec38fcc0e659a3941b36a5384a309a3 diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL98494_grouped.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL98494_grouped.nxs.md5 index 85159fd3ae5819d82f207365d911baf49b3d05a1..3a984c302608ecf0f833fde8e41a5e9d5f2338f2 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL98494_grouped.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-PEARL98494_grouped.nxs.md5 @@ -1 +1 @@ -b957a6b0928e12a8c86284ea010df429 \ No newline at end of file +de74dd3f5c3df66740a0f3b5c955b16d diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS00098533_splined.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS00098532_splined.nxs.md5 similarity index 100% rename from Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS00098533_splined.nxs.md5 rename to Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS00098532_splined.nxs.md5 diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS00098533_unsplined.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS00098532_unsplined.nxs.md5 similarity index 100% rename from Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS00098533_unsplined.nxs.md5 rename to Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS00098532_unsplined.nxs.md5 diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS98533_Auto_chopper.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS98533_Auto_chopper.nxs.md5 index 1495b8317052730570e375f0b6d6ddeb088472a7..5b6652bd1903ef3dadbc9d9528670248d2ef4215 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS98533_Auto_chopper.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS98533_Auto_chopper.nxs.md5 @@ -1 +1 @@ -ea4a0c8a223ab9f0fe8d06fc9e1604d3 +d5cd699c2749e999f2273f78c08fff47 diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS98533_FocusSempty.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS98533_FocusSempty.nxs.md5 index 37c1f1bed76e241bbdd40668ee219183b1db59db..5b3ac0c44df6e27058b4b652e46c9d94183fd6d1 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS98533_FocusSempty.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder-POLARIS98533_FocusSempty.nxs.md5 @@ -1 +1 @@ -281e4969b42ff1e891bf3c1377bdc8de +7d22193e2a7634cfe359b95f94e4dab7 diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_all.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_all.nxs.md5 index 2998cab6e1cd122a707ab8ecdec4bea7f4b7509b..3e757cf3177a9c16c97b49bfdd6f76f377d53f72 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_all.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_all.nxs.md5 @@ -1 +1 @@ -92c4276dd271f2ad8d5e7bb37c089b57 +f1a2f87e9dac226355703b9e61cb82f0 diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_groups.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_groups.nxs.md5 index c282ebfdfbd6e0a7ce3977517152be5cd193b447..ca5e1efc08be24576181f263365e80e1ebcffa60 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_groups.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_groups.nxs.md5 @@ -1 +1 @@ -3c19d9a0702c746db0b0ddb6a760abca +80892f681d9cb6f598e50c57294ba44f diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_mods.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_mods.nxs.md5 index 5211bfef5affcff5ddefb92349b73cca0e850a9b..af4d09cc5803b7a8fde265c7df75b7030734b3be 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_mods.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_mods.nxs.md5 @@ -1 +1 @@ -1f5ba298ba0297181053bbae8c470a64 +ad8b3130bc3821f7f678798483a244fd diff --git a/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_trans.nxs.md5 b/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_trans.nxs.md5 index 47f45cfc401751c784aa7a3646308395142d4f23..651fa9fe2309ae53d224de9f70a89aa4ab1e0802 100644 --- a/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_trans.nxs.md5 +++ b/Testing/SystemTests/tests/framework/reference/ISIS_Powder_PRL98472_tt70_trans.nxs.md5 @@ -1 +1 @@ -719362df6faebf097f07fc95ecbaba9c +76defafd738c04e38fa289bff568e294 diff --git a/Testing/SystemTests/tests/framework/reference/PG3_4844_reference.gsa.md5 b/Testing/SystemTests/tests/framework/reference/PG3_4844_reference.gsa.md5 index f5c92d08a9ac9f48fda4dbfbd878c4767fd0207e..98d9db432d9b07e6e21bbc8d664e66a55529d550 100644 --- a/Testing/SystemTests/tests/framework/reference/PG3_4844_reference.gsa.md5 +++ b/Testing/SystemTests/tests/framework/reference/PG3_4844_reference.gsa.md5 @@ -1 +1 @@ -8882c0f4cc428087529940ba49e3bc08 +dbde6312703bb8ab2de56edd29384e18 diff --git a/Testing/SystemTests/tests/framework/reference/PG3_4866_reference.gsa.md5 b/Testing/SystemTests/tests/framework/reference/PG3_4866_reference.gsa.md5 index 1d04c3a13d027d6d1e3040ca106f842398ce08f1..58dbd55244510d434cf0de02d536f91d02099c65 100644 --- a/Testing/SystemTests/tests/framework/reference/PG3_4866_reference.gsa.md5 +++ b/Testing/SystemTests/tests/framework/reference/PG3_4866_reference.gsa.md5 @@ -1 +1 @@ -27a8c7ff7c64574ea6034632f367c991 +b11628262a659bcb05a1368cd3ebe7c6 diff --git a/docs/source/algorithms/ApplyDiffCal-v1.rst b/docs/source/algorithms/ApplyDiffCal-v1.rst new file mode 100644 index 0000000000000000000000000000000000000000..7e58cc152f540daf1f17fa92cdab2c74e2321f74 --- /dev/null +++ b/docs/source/algorithms/ApplyDiffCal-v1.rst @@ -0,0 +1,36 @@ +.. algorithm:: + +.. summary:: + +.. relatedalgorithms:: + +.. properties:: + +Description +----------- + +Loads diffractometer constants (DIFA, DIFC, TZERO) from a calibration data source and +stores them in the instrument parameter map of the `InstrumentWorkspace`. The constants +are used in time of flight diffraction instruments to convert from time of flight to +d spacing and vice versa. + +This algorithm either reads the constants from the +`CalibrationWorkspace`, reads them from `CalibrationFile` using :ref:`LoadDiffCal +<algm-LoadDiffCal>`, or uses :ref:`ConvertDiffCal<algm-ConvertDiffCal>` to generate +them from the `OffsetsWorkspace`. + +This algorithm allows unit conversions between time of flight and d spacing using +calibrated diffractometer constants to be performed using the +:ref:`ConvertUnits <algm-ConvertUnits>` algorithm. :ref:`ConvertUnits <algm-ConvertUnits>` +reads the constants from the instrument parameter map. + +When used together with :ref:`ConvertUnits <algm-ConvertUnits>` this algorithm provides a way of +converting in both directions between time of flight and d spacing and it is an alternative to +using :ref:`AlignDetectors <algm-AlignDetectors>`. + +The values of the diffractometer constants that are stored in the instrument parameter map +can be viewed on the Show Detectors screen of a workspace. + +.. categories:: + +.. sourcelink:: diff --git a/docs/source/algorithms/PreprocessDetectorsToMD-v1.rst b/docs/source/algorithms/PreprocessDetectorsToMD-v1.rst index 7d000a25ae2ea632ba043e2b318db2b5f50fb701..2574019ba9629a08d21614b5f7fd265259b2e30e 100644 --- a/docs/source/algorithms/PreprocessDetectorsToMD-v1.rst +++ b/docs/source/algorithms/PreprocessDetectorsToMD-v1.rst @@ -82,7 +82,7 @@ Usage .. testoutput:: ExPreprocessDetectoresToMD The resulting table has the following columns: - ['DetDirections', 'L2', 'TwoTheta', 'Azimuthal', 'DetectorID', 'detIDMap', 'spec2detMap', 'detMask', 'eFixed'] + ['DetDirections', 'L2', 'TwoTheta', 'Azimuthal', 'DetectorID', 'detIDMap', 'spec2detMap', 'detMask', 'eFixed', 'DIFA', 'DIFC', 'TZERO'] The number of rows in the workspace is : 918 The polar angle for detector N 10 is 0.314159 rad The table workspace logs (properties) are currently not available from python diff --git a/docs/source/concepts/UnitFactory.rst b/docs/source/concepts/UnitFactory.rst index 789f1076b29f75a23109a8b3ec54e879f859ba84..01e75231fe9143d269a1048778b6bb84d27c88c5 100644 --- a/docs/source/concepts/UnitFactory.rst +++ b/docs/source/concepts/UnitFactory.rst @@ -33,7 +33,7 @@ The following units are available in the default Mantid distribution. These unit +-------------------------------------------+---------------------------------+-----------------------------+------------------------------------------------------------------------------------------------------------------+ | Momentum (k) | Momentum | :math:`\mathrm{\AA}^{-1}` | :math:`k = \frac{2 \pi }{\lambda}=\frac{2 \pi \times m_N \times L_{tot}}{h \times \mathrm{tof}}` | +-------------------------------------------+---------------------------------+-----------------------------+------------------------------------------------------------------------------------------------------------------+ -| d-spacing | dSpacing | :math:`\mathrm{\AA}` | :math:`d = \frac{n \, \lambda}{2 \, sin \, \theta}` | +| d-spacing | dSpacing | :math:`\mathrm{\AA}` | :math:`TOF = DIFA \, d^2 + DIFC d + TZERO` (see below) | +-------------------------------------------+---------------------------------+-----------------------------+------------------------------------------------------------------------------------------------------------------+ | Momentum transfer (Q) | MomentumTransfer | :math:`\mathrm{\AA}^{-1}` | :math:`Q = 2 \, k \, sin \, \theta = \frac{4 \pi sin \theta}{\lambda}` | +-------------------------------------------+---------------------------------+-----------------------------+------------------------------------------------------------------------------------------------------------------+ @@ -68,6 +68,15 @@ energy respectively. Units conversion into elastic momentum transfer (MomentumTransfer) will throw in elastic mode (emode=0) on inelastic workspace (when energy transfer is specified along x-axis) +**Note on d-spacing**: The coefficients DIFA, DIFC and TZERO may be obtained +via calibration of a TOF diffraction instrument. In the absence of a calibration, +DIFA=TZERO=0 and the default value of DIFC is: + +:math:`DIFC = 10^{-4} \frac{m_N}{h} (L_1 + L_2) 2 \sin(\theta)` + +where the scaling factor adjusts for the fact that DIFC is required in units +of :math:`\mu s` per :math:`\mathrm{\AA}`. + **d-spacingPerpendicular** is a unit invented in `J. Appl. Cryst. (2015) 48, pp. 1627--1636 <https://doi.org/10.1107/S1600576715016520>`_ for 2D Rietveld refinement of angular and wavelength-dispersive neutron time-of-flight powder diffraction data. Together with the d-Spacing :math:`d`, d-SpacingPerpendicular :math:`d_{\perp}` forms a new orthogonal coordinate system. diff --git a/docs/source/release/v6.1.0/diffraction.rst b/docs/source/release/v6.1.0/diffraction.rst index 03d589f815a6d173d17dea62b7aab6acb6bbbc2f..3d8a6cdd9545ded42227054b8e0461a3893978eb 100644 --- a/docs/source/release/v6.1.0/diffraction.rst +++ b/docs/source/release/v6.1.0/diffraction.rst @@ -49,6 +49,8 @@ Bugfixes - Allow a different number of spectra for absorption correction division of PEARL data. This allows ``create_vanadium`` to work for a non-standard dataset. - Saved filenames for summed empty workspaces now include spline properties to avoid long_mode confusion when focussing. +- The :ref:`ConvertUnits <algm-ConvertUnits>` algorithm has been extended to use a quadratic relationship between d spacing and TOF when doing conversions between these units. The diffractometer constants DIFA, DIFC and TZERO that determine the form of the quadratic can be loaded into a workspace using a new :ref:`ApplyDiffCal <algm-ApplyDiffCal>` algorithm. This functionality was previously only available in :ref:`AlignDetectors <algm-AlignDetectors>` which only performed the conversion in the direction TOF to d spacing. This change will ensure that the conversion of focussed datasets from d spacing back to TOF at the end of the ISIS powder diffraction data reduction is performed correctly. + Engineering Diffraction ----------------------- diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/ImageInfoModelMatrixWS.h b/qt/widgets/common/inc/MantidQtWidgets/Common/ImageInfoModelMatrixWS.h index 48f6955e1c8d0d1632229d6257cc13d200c3aadc..9a1563b0c5227a6c7a5f2a23aafa188f2c1cc195 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/ImageInfoModelMatrixWS.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/ImageInfoModelMatrixWS.h @@ -43,8 +43,6 @@ public: private: void setUnitsInfo(ImageInfoModel::ImageInfo *info, int infoIndex, const size_t wsIndex, const double x) const; - std::tuple<Mantid::Kernel::DeltaEMode::Type, double> - efixedAt(const size_t wsIndex) const; void cacheWorkspaceInfo(); void createItemNames(); diff --git a/qt/widgets/common/src/ImageInfoModelMatrixWS.cpp b/qt/widgets/common/src/ImageInfoModelMatrixWS.cpp index 9a2e687c2f85502777846f81a4db73d98cc41e79..caf5ca327624b6b9b87264d817f7aa641f011823 100644 --- a/qt/widgets/common/src/ImageInfoModelMatrixWS.cpp +++ b/qt/widgets/common/src/ImageInfoModelMatrixWS.cpp @@ -105,10 +105,17 @@ void ImageInfoModelMatrixWS::setUnitsInfo(ImageInfoModel::ImageInfo *info, int infoIndex, const size_t wsIndex, const double x) const { const auto l1 = m_spectrumInfo->l1(); - const auto l2 = m_spectrumInfo->l2(wsIndex); - const auto twoTheta = m_spectrumInfo->twoTheta(wsIndex); - const auto [emode, efixed] = efixedAt(wsIndex); - + auto emode = m_workspace->getEMode(); + UnitParametersMap pmap{}; + m_spectrumInfo->getDetectorValues(Units::Empty(), Units::Empty(), emode, + false, wsIndex, pmap); + double efixed = 0.; + if (pmap.find(UnitParams::efixed) != pmap.end()) { + efixed = pmap[UnitParams::efixed]; + } + // if it's not possible to find an efixed we are forced to treat is as elastic + if (efixed == 0.0) + emode = DeltaEMode::Elastic; double tof(0.0); const auto &unitFactory = UnitFactory::Instance(); const auto tofUnit = unitFactory.create("TOF"); @@ -117,8 +124,7 @@ void ImageInfoModelMatrixWS::setUnitsInfo(ImageInfoModel::ImageInfo *info, tof = x; } else { try { - tof = - m_xunit->convertSingleToTOF(x, l1, l2, twoTheta, emode, efixed, 0.0); + tof = m_xunit->convertSingleToTOF(x, l1, emode, pmap); } catch (std::exception &exc) { // without TOF we can't get to the other units if (g_log.is(Logger::Priority::PRIO_DEBUG)) @@ -133,8 +139,7 @@ void ImageInfoModelMatrixWS::setUnitsInfo(ImageInfoModel::ImageInfo *info, if (!requiresEFixed || efixed > 0.0) { try { // the final parameter is unused and a relic - const auto unitValue = unit->convertSingleFromTOF(tof, l1, l2, twoTheta, - emode, efixed, 0.0); + const auto unitValue = unit->convertSingleFromTOF(tof, l1, emode, pmap); info->setValue(infoIndex, defaultFormat(unitValue)); } catch (std::exception &exc) { if (g_log.is(Logger::Priority::PRIO_DEBUG)) @@ -228,56 +233,5 @@ void ImageInfoModelMatrixWS::createItemNames() { } } -/** - * Return tuple(emode, efixed) for the pixel at the given workspace index - * @param wsIndex Indeox of spectrum to query - */ -std::tuple<Mantid::Kernel::DeltaEMode::Type, double> -ImageInfoModelMatrixWS::efixedAt(const size_t wsIndex) const { - DeltaEMode::Type emode = m_workspace->getEMode(); - double efixed(0.0); - if (m_spectrumInfo->isMonitor(wsIndex)) - return std::make_tuple(emode, efixed); - - if (emode == DeltaEMode::Direct) { - const auto &run = m_workspace->run(); - for (const auto &logName : {"Ei", "EnergyRequested", "EnergyEstimate"}) { - if (run.hasProperty(logName)) { - efixed = run.getPropertyValueAsType<double>(logName); - break; - } - } - } else if (emode == DeltaEMode::Indirect) { - const auto &detector = m_spectrumInfo->detector(wsIndex); - const ParameterMap &pmap = m_workspace->constInstrumentParameters(); - try { - for (const auto ¶mName : {"Efixed", "Efixed-val"}) { - auto parameter = pmap.getRecursive(&detector, paramName); - if (parameter) { - efixed = parameter->value<double>(); - break; - } - // check the instrument as if the detector is a group the above - // recursion doesn't work - parameter = pmap.getRecursive(m_instrument.get(), paramName); - if (parameter) { - efixed = parameter->value<double>(); - break; - } - } - } catch (std::runtime_error &exc) { - g_log.debug() << "Failed to get efixed from spectrum at index " << wsIndex - << ": " << exc.what() << "\n"; - efixed = 0.0; - } - } - - // if it's not possible to find an efixed we are forced to treat is as elastic - if (efixed == 0.0) - emode = DeltaEMode::Elastic; - - return std::make_tuple(emode, efixed); -} - } // namespace MantidWidgets } // namespace MantidQt diff --git a/scripts/Diffraction/isis_powder/abstract_inst.py b/scripts/Diffraction/isis_powder/abstract_inst.py index 62b5a8c40ab1a194af43bce235a5bccadc2471e0..2e402d3142c1bd50f24f71a9afd1a085ef97945b 100644 --- a/scripts/Diffraction/isis_powder/abstract_inst.py +++ b/scripts/Diffraction/isis_powder/abstract_inst.py @@ -7,6 +7,7 @@ import os from isis_powder.routines import calibrate, focus, common, common_enums, common_output from mantid.kernel import config, logger +import mantid.simpleapi as mantid # This class provides common hooks for instruments to override # if they want to define the behaviour of the hook. Otherwise it # returns the object passed in without manipulating it as a default @@ -276,6 +277,11 @@ class AbstractInst(object): """ return None + def apply_calibration_to_focused_data(self, focused_ws): + # convert back to TOF based on engineered detector positions + mantid.ApplyDiffCal(InstrumentWorkspace=focused_ws, + ClearCalibration=True) + # Steps applicable to all instruments @staticmethod diff --git a/scripts/Diffraction/isis_powder/routines/calibrate.py b/scripts/Diffraction/isis_powder/routines/calibrate.py index 5884992041952c994ffb5ca70470a0fb9bad97e7..9e1e42c859c2e57295350da3bd119ca2a5aed2a3 100644 --- a/scripts/Diffraction/isis_powder/routines/calibrate.py +++ b/scripts/Diffraction/isis_powder/routines/calibrate.py @@ -43,21 +43,23 @@ def create_van(instrument, run_details, absorb): # Assume that create_van only uses Vanadium runs mantid.SetSampleMaterial(InputWorkspace=corrected_van_ws, ChemicalFormula='V') - aligned_ws = mantid.AlignDetectors(InputWorkspace=corrected_van_ws, - CalibrationFile=run_details.offset_file_path) + mantid.ApplyDiffCal(InstrumentWorkspace=corrected_van_ws, + CalibrationFile=run_details.offset_file_path) + aligned_ws = mantid.ConvertUnits(InputWorkspace=corrected_van_ws, Target="dSpacing") solid_angle = instrument.get_solid_angle_corrections(run_details.run_number, run_details) if solid_angle: aligned_ws = mantid.Divide(LHSWorkspace=aligned_ws,RHSWorkspace=solid_angle) mantid.DeleteWorkspace(solid_angle) focused_vanadium = mantid.DiffractionFocussing(InputWorkspace=aligned_ws, GroupingFileName=run_details.grouping_file_path) - + # convert back to TOF based on engineered detector positions + mantid.ApplyDiffCal(InstrumentWorkspace=focused_vanadium, + ClearCalibration=True) focused_spectra = common.extract_ws_spectra(focused_vanadium) focused_spectra = instrument._crop_van_to_expected_tof_range(focused_spectra) d_spacing_group, tof_group = instrument._output_focused_ws(processed_spectra=focused_spectra, run_details=run_details) - _create_vanadium_splines(focused_spectra, instrument, run_details) common.keep_single_ws_unit(d_spacing_group=d_spacing_group, tof_group=tof_group, diff --git a/scripts/Diffraction/isis_powder/routines/focus.py b/scripts/Diffraction/isis_powder/routines/focus.py index 51afbfc32585a176f38eaf37bcf735d02f90d7c3..0fb1cc8e2935cc8718acd6de98982ca5d8b0c6ae 100644 --- a/scripts/Diffraction/isis_powder/routines/focus.py +++ b/scripts/Diffraction/isis_powder/routines/focus.py @@ -65,8 +65,9 @@ def _focus_one_ws(input_workspace, run_number, instrument, perform_vanadium_norm Geometry=common.generate_sample_geometry(sample_details), Material=common.generate_sample_material(sample_details)) # Align - aligned_ws = mantid.AlignDetectors(InputWorkspace=input_workspace, - CalibrationFile=run_details.offset_file_path) + mantid.ApplyDiffCal(InstrumentWorkspace=input_workspace, + CalibrationFile=run_details.offset_file_path) + aligned_ws = mantid.ConvertUnits(InputWorkspace=input_workspace, Target="dSpacing") solid_angle = instrument.get_solid_angle_corrections(run_details.vanadium_run_numbers, run_details) if solid_angle: @@ -77,6 +78,8 @@ def _focus_one_ws(input_workspace, run_number, instrument, perform_vanadium_norm focused_ws = mantid.DiffractionFocussing(InputWorkspace=aligned_ws, GroupingFileName=run_details.grouping_file_path) + instrument.apply_calibration_to_focused_data(focused_ws) + calibrated_spectra = _apply_vanadium_corrections(instrument=instrument, input_workspace=focused_ws, perform_vanadium_norm=perform_vanadium_norm,