18#include "MantidHistogramData/Histogram.h"
19#include "MantidHistogramData/HistogramBuilder.h"
26#include "MantidTypes/SpectrumDefinition.h"
35using namespace Kernel;
37using namespace Geometry;
38using namespace DataObjects;
39using namespace HistogramData;
43 auto wsVal = std::make_shared<CompositeValidator>();
47 "The name of the input workspace.");
49 "The name to use for the output workspace.");
50 std::vector<std::string> targetOptions{
51 "Theta",
"SignedTheta",
"InPlaneTwoTheta",
"SignedInPlaneTwoTheta",
"ElasticQ",
52 "ElasticQSquared",
"theta",
"signed_theta",
"ElasticDSpacing"};
53 declareProperty(
"Target",
"", std::make_shared<StringListValidator>(targetOptions),
54 "The unit to which spectrum axis is converted to - \"theta\" (for the "
55 "angle in degrees), Q or Q^2, where elastic Q is evaluated at EFixed. "
56 "InPlaneTwoTheta and SignedInPlaneTwoTheta are the angle when each point "
57 "is projected on the horizontal plane."
58 "Note that 'theta' and 'signed_theta' are there for compatibility "
59 "purposes; they are the same as 'Theta' and 'SignedTheta' respectively");
60 std::vector<std::string> eModeOptions;
61 eModeOptions.emplace_back(
"Direct");
62 eModeOptions.emplace_back(
"Indirect");
63 declareProperty(
"EMode",
"Direct", std::make_shared<StringListValidator>(eModeOptions),
64 "Some unit conversions require this value to be set "
65 "(\"Direct\" or \"Indirect\")");
66 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
67 mustBePositive->setLower(0.0);
69 "Value of fixed energy in meV : EI (EMode=Direct) or EF "
73 "Whether or not to sort the resulting"
81 const size_t nHist = inputWS->getNumberHistograms();
84 const std::string unitTarget =
getProperty(
"Target");
88 size_t nProgress = nHist;
99 if (unitTarget ==
"theta" || unitTarget ==
"Theta" || unitTarget ==
"signed_theta" || unitTarget ==
"SignedTheta" ||
100 unitTarget ==
"InPlaneTwoTheta" || unitTarget ==
"SignedInPlaneTwoTheta") {
102 }
else if (unitTarget ==
"ElasticQ" || unitTarget ==
"ElasticQSquared" || unitTarget ==
"ElasticDSpacing") {
119 enum thetaTypes { theta, signedTheta, inPlaneTheta, signedInPlaneTheta };
120 thetaTypes thetaType = theta;
121 if (targetUnit ==
"signed_theta" || targetUnit ==
"SignedTheta") {
122 thetaType = signedTheta;
123 }
else if (targetUnit ==
"theta" || targetUnit ==
"Theta") {
125 }
else if (targetUnit ==
"InPlaneTwoTheta") {
126 thetaType = inPlaneTheta;
127 }
else if (targetUnit ==
"SignedInPlaneTwoTheta") {
128 thetaType = signedInPlaneTheta;
130 bool warningGiven =
false;
132 const auto &spectrumInfo = inputWS->spectrumInfo();
133 for (
size_t i = 0; i < spectrumInfo.size(); ++i) {
134 if (!spectrumInfo.hasDetectors(i)) {
136 g_log.
warning(
"The instrument definition is incomplete - spectra "
137 "dropped from output");
141 if (!spectrumInfo.isMonitor(i)) {
152 case signedInPlaneTheta:
160 progress.report(
"Converting to theta...");
172 const auto spectrumInfo = inputWS->spectrumInfo();
173 const auto refFrame = inputWS->getInstrument()->getReferenceFrame();
174 const V3D position = spectrumInfo.position(
index) - spectrumInfo.samplePosition();
177 std::atan2(std::abs(
position[refFrame->pointingHorizontal()]),
position[refFrame->pointingAlongBeam()]);
189 const auto spectrumInfo = inputWS->spectrumInfo();
190 const auto refFrame = inputWS->getInstrument()->getReferenceFrame();
192 const auto samplePos = spectrumInfo.samplePosition();
193 const auto beamLine = samplePos - spectrumInfo.sourcePosition();
195 if (beamLine.nullVector()) {
199 const V3D sampleDetVec = spectrumInfo.position(
index) - samplePos;
201 return std::atan2(sampleDetVec[refFrame->pointingHorizontal()], sampleDetVec[refFrame->pointingAlongBeam()]);
214 if (emodeStr ==
"Direct")
216 else if (emodeStr ==
"Indirect")
219 const auto &spectrumInfo = inputWS->spectrumInfo();
220 const auto &detectorInfo = inputWS->detectorInfo();
221 const size_t nHist = spectrumInfo.size();
222 for (
size_t i = 0; i < nHist; i++) {
223 double theta(0.0),
efixed(0.0);
224 if (!spectrumInfo.isMonitor(i)) {
225 theta = 0.5 * spectrumInfo.twoTheta(i);
234 const auto detectorIndex = spectrumInfo.spectrumDefinition(i)[0].first;
245 if (targetUnit ==
"ElasticQ") {
247 }
else if (targetUnit ==
"ElasticQSquared") {
249 double elasticQSquaredInAngstroms = elasticQInAngstroms * elasticQInAngstroms;
252 }
else if (targetUnit ==
"ElasticDSpacing") {
253 double elasticDSpacing = 2 * M_PI / elasticQInAngstroms;
257 progress.report(
"Converting to " + targetUnit);
272 std::unique_ptr<NumericAxis> newAxis =
nullptr;
276 const Histogram hist = eventWS ? Histogram(inputWS->binEdges(0)) : inputWS->histogram(0);
277 outputWorkspace = create<MatrixWorkspace>(*inputWS,
m_indexMap.size(), hist);
278 std::vector<double> axis;
281 [](
const auto &it) { return it.first; });
283 newAxis = std::make_unique<NumericAxis>(std::move(axis));
286 outputWorkspace = inputWS->clone();
287 newAxis = std::make_unique<NumericAxis>(
m_axis);
291 if (targetUnit ==
"theta" || targetUnit ==
"Theta" || targetUnit ==
"signed_theta" || targetUnit ==
"SignedTheta" ||
292 targetUnit ==
"InPlaneTwoTheta" || targetUnit ==
"SignedInPlaneTwoTheta") {
293 newAxis->unit() = std::make_shared<Units::Degrees>();
294 }
else if (targetUnit ==
"ElasticQ") {
296 }
else if (targetUnit ==
"ElasticQSquared") {
298 }
else if (targetUnit ==
"ElasticDSpacing") {
301 outputWorkspace->replaceAxis(1, std::move(newAxis));
304 size_t currentIndex = 0;
305 std::multimap<double, size_t>::const_iterator it;
308 outputWorkspace->getSpectrum(currentIndex).copyDataFrom(inputWS->getSpectrum(it->second));
310 outputWorkspace->getSpectrum(currentIndex).copyInfoFrom(inputWS->getSpectrum(it->second));
316 return outputWorkspace;
326 g_log.
debug() <<
"Detector: " << detectorID <<
" Efixed: " <<
efixed <<
"\n";
332 throw std::invalid_argument(
"Could not retrieve Efixed from the "
333 "workspace. Please provide a value.");
335 }
else if (emode == 2) {
341 if (!efixedVec.empty()) {
343 g_log.
debug() <<
"Detector: " << detectorID <<
" EFixed: " <<
efixed <<
"\n";
345 g_log.
warning() <<
"Efixed could not be found for detector " << detectorID <<
", please provide a value\n";
346 throw std::invalid_argument(
"Could not retrieve Efixed from the "
347 "detector. Please provide a value.");
#define DECLARE_ALGORITHM(classname)
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
const Run & run() const
Run details object access.
A validator which checks that a workspace has a valid instrument.
bool hasProperty(const std::string &name) const
Does the property exist on the object.
double getLogAsSingleValue(const std::string &name, Kernel::Math::StatisticType statistic=Kernel::Math::Mean) const
Base MatrixWorkspace Abstract Class.
Helper class for reporting progress from algorithms.
A validator which checks whether the input workspace has the Spectra number in the axis.
A property class for workspaces.
std::vector< double > m_axis
Vector of axis in case ordering is not asked.
double getEfixed(const size_t detectorIndex, const Mantid::Geometry::DetectorInfo &detectorInfo, const API::MatrixWorkspace &inputWS, const int emode) const
Getting Efixed.
bool m_toOrder
Flag whether ordering is needed.
double signedInPlaneTwoTheta(const size_t index, const API::MatrixWorkspace_sptr &inputWS) const
Compute signed in plane two theta.
void createElasticQMap(API::Progress &progress, const std::string &targetUnit, API::MatrixWorkspace_sptr &inputWS)
Converting to Q and QSquared.
double inPlaneTwoTheta(const size_t index, const API::MatrixWorkspace_sptr &inputWS) const
Compute inPlaneTwoTheta.
void emplaceIndexMap(double value, size_t wsIndex)
Emplaces to value and the index pair into the map.
API::MatrixWorkspace_sptr createOutputWorkspace(API::Progress &progress, const std::string &targetUnit, API::MatrixWorkspace_sptr &inputWS)
Creates an output workspace.
std::multimap< double, size_t > m_indexMap
Map to which the conversion to the unit is stored.
void createThetaMap(API::Progress &progress, const std::string &targetUnit, API::MatrixWorkspace_sptr &inputWS)
Converting to theta.
void init() override
Initialisation code.
void exec() override
Execution code.
Geometry::DetectorInfo is an intermediate step towards a DetectorInfo that is part of Instrument-2....
const std::vector< detid_t > & detectorIDs() const
Returns a sorted vector of all detector IDs.
const Geometry::IDetector & detector(const size_t index) const
Return a const reference to the detector with given index.
virtual std::vector< double > getNumberParameter(const std::string &pname, bool recursive=true) const =0
Get a parameter defined as a double.
Exception for errors associated with the instrument definition.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void debug(const std::string &msg)
Logs at debug level.
void warning(const std::string &msg)
Logs at warning level.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
static double convertToElasticQ(const double theta, const double efixed)
Convert to ElasticQ from Energy.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
constexpr double rad2deg
Radians to degrees conversion factor.
int32_t detid_t
Typedef for a detector ID.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
std::string to_string(const wide_integer< Bits, Signed > &n)
@ Input
An input workspace.
@ Output
An output workspace.