18#include "MantidHistogramData/Histogram.h"
31using namespace Kernel;
33using namespace DataObjects;
34using namespace HistogramData;
38 auto wsValidator = std::make_shared<CompositeValidator>();
42 "Name of the input workspace");
44 "Name of the output workspace, can be the same as the input");
48 declareProperty(
"Target",
"", std::make_shared<StringListValidator>(UnitFactory::Instance().getConvertibleUnits()),
49 "The name of the units to convert to (must be one of those "
52 std::vector<std::string> propOptions{
"Elastic",
"Direct",
"Indirect"};
53 declareProperty(
"EMode",
"Elastic", std::make_shared<StringListValidator>(propOptions),
54 "The energy mode (default: elastic)");
55 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
56 mustBePositive->setLower(0.0);
58 "Value of fixed energy in meV : EI (EMode='Direct') or EF "
59 "(EMode='Indirect') . Must be\n"
60 "set if the target unit requires it (e.g. DeltaE)");
63 "If true (default is false), rebins after conversion to "
64 "ensure that all spectra in the output workspace\n"
65 "have identical bin boundaries. This option is not "
67 "http://docs.mantidproject.org/algorithms/ConvertUnits).");
70 "When checked, if the Input Workspace contains Points\n"
71 "the algorithm ConvertToHistogram will be run to convert\n"
72 "the Points to Bins. The Output Workspace will contains Bins.");
88 const bool acceptPointData =
getProperty(
"ConvertFromPointData");
89 bool workspaceWasConverted =
false;
99 if (outputWSName == inputWSName) {
102 <<
"), so just pointing the output workspace property to the input workspace.\n";
103 setProperty(
"OutputWorkspace", std::const_pointer_cast<MatrixWorkspace>(inputWS));
108 duplicate->initialize();
109 duplicate->setProperty(
"InputWorkspace", inputWS);
110 duplicate->execute();
112 auto outputWs = std::dynamic_pointer_cast<MatrixWorkspace>(temp);
121 if (!inputWS->isHistogramData()) {
122 if (acceptPointData) {
123 workspaceWasConverted =
true;
124 g_log.
information(
"ConvertFromPointData is checked. Running ConvertToHistogram\n");
128 convToHist->setProperty(
"InputWorkspace", inputWS);
129 convToHist->execute();
131 correctWS = std::dynamic_pointer_cast<MatrixWorkspace>(temp);
133 if (!correctWS->isHistogramData()) {
134 throw std::runtime_error(
"Failed to convert workspace from Points to Bins");
137 throw std::runtime_error(
"Workspace contains points, you can either run ConvertToHistogram on it, or set "
138 "ConvertFromPointData to enabled");
147 if (workspaceWasConverted) {
148 g_log.
information(
"ConvertUnits is completed. Running ConvertToPointData.\n");
150 convtoPoints->setProperty(
"InputWorkspace", outputWS);
151 convtoPoints->execute();
153 outputWS = std::dynamic_pointer_cast<MatrixWorkspace>(temp);
155 if (outputWS->isHistogramData()) {
156 throw std::runtime_error(
"Failed to convert workspace from Bins to Points");
175 if (inputWS->x(0).size() < 2) {
176 std::stringstream msg;
177 msg <<
"Input workspace has invalid X axis binning parameters. Should have at least 2 values. Found "
178 << inputWS->x(0).size() <<
".";
179 throw std::runtime_error(msg.str());
181 if (inputWS->x(0).front() > inputWS->x(0).back() ||
183 throw std::runtime_error(
"Input workspace has invalid X axis binning "
184 "parameters. X values should be increasing.");
188 double factor, power;
198 if (!outputWS->x(0).empty() &&
199 (outputWS->x(0).front() > outputWS->x(0).back() ||
213 if (doAlignBins && !outputWS->isCommonBins())
230 m_distribution = inputWS->isDistribution() && !inputWS->YUnit().empty();
232 m_inputEvents = (std::dynamic_pointer_cast<const EventWorkspace>(inputWS) !=
nullptr);
236 m_outputUnit = UnitFactory::Instance().create(targetUnit);
248 if (outputWS != inputWS) {
249 outputWS = inputWS->clone();
259 const auto &
X = outputWS->x(i);
260 auto &
Y = outputWS->mutableY(i);
261 auto &E = outputWS->mutableE(i);
262 for (
size_t j = 0; j <
Y.size(); ++j) {
263 const double width = std::abs(
X[j + 1] -
X[j]);
286 const bool overwrite(
true);
287 outputWS->mutableRun().addProperty(
"deltaE-mode",
getPropertyValue(
"EMode"), overwrite);
298 const double &power) {
304 const bool commonBoundaries = inputWS->isCommonBins();
305 if (commonBoundaries) {
307 std::transform(outputWS->mutableX(0).cbegin(), outputWS->mutableX(0).cend(), outputWS->mutableX(0).begin(),
308 [&](
const auto &
x) { return factor * std::pow(x, power); });
310 auto xVals = outputWS->sharedX(0);
313 for (int64_t j = 1; j < numberOfSpectra_i; ++j) {
315 outputWS->setX(j, xVals);
331 for (int64_t k = 0; k < numberOfSpectra_i; ++k) {
333 if (!commonBoundaries) {
334 std::transform(outputWS->mutableX(k).cbegin(), outputWS->mutableX(k).cend(), outputWS->mutableX(k).begin(),
335 [&](
const auto &
x) { return factor * std::pow(x, power); });
339 eventWS->getSpectrum(k).convertUnitsQuickly(factor, power);
360 using namespace Geometry;
367 const auto &spectrumInfo = inputWS->spectrumInfo();
368 double l1 = spectrumInfo.l1();
369 g_log.
debug() <<
"Source-sample distance: " << l1 <<
'\n';
371 int failedDetectorCount = 0;
381 std::vector<double> emptyVec;
385 efixedProp = inputWS->getEFixedGivenEMode(
nullptr, emode);
386 }
catch (std::runtime_error &) {
390 std::vector<std::string> parameters = inputWS->getInstrument()->getStringParameter(
"show-signed-theta");
391 bool signedTheta = (!parameters.empty()) && find(parameters.begin(), parameters.end(),
"Always") != parameters.end();
393 auto checkFromUnit = std::unique_ptr<Unit>(fromUnit->clone());
394 auto checkOutputUnit = std::unique_ptr<Unit>(outputUnit->clone());
397 const double checkdelta = 0.0;
400 upmap[UnitParams::efixed] = efixedProp;
402 size_t checkIndex = 0;
403 spectrumInfo.getDetectorValues(*fromUnit, *outputUnit, emode, signedTheta, checkIndex, upmap);
405 auto checkXValues = inputWS->readX(checkIndex);
408 checkFromUnit->toTOF(checkXValues, emptyVec, l1, emode, upmap);
410 checkOutputUnit->fromTOF(checkXValues, emptyVec, l1, emode, upmap);
411 }
catch (std::runtime_error &) {
419 auto &outSpectrumInfo = outputWS->mutableSpectrumInfo();
422 for (int64_t i = 0; i < numberOfSpectra_i; ++i) {
424 double efixed = efixedProp;
428 const double delta = 0.0;
430 auto localFromUnit = std::unique_ptr<Unit>(fromUnit->clone());
431 auto localOutputUnit = std::unique_ptr<Unit>(outputUnit->clone());
438 outSpectrumInfo.getDetectorValues(*fromUnit, *outputUnit, emode, signedTheta, i,
pmap);
440 localFromUnit->toTOF(outputWS->dataX(i), emptyVec, l1, emode,
pmap);
442 localOutputUnit->fromTOF(outputWS->dataX(i), emptyVec, l1, emode,
pmap);
446 eventWS->getSpectrum(i).convertUnitsViaTof(localFromUnit.get(), localOutputUnit.get());
448 }
catch (std::runtime_error &) {
451 failedDetectorCount++;
456 outputWS->getSpectrum(i).clearData();
457 if (outSpectrumInfo.hasDetectors(i))
458 outSpectrumInfo.setMasked(i,
true);
466 if (failedDetectorCount != 0) {
467 g_log.
warning() <<
"Unable to calculate sample-detector distance for " << failedDetectorCount
468 <<
" spectra. Masking spectrum.\n";
477 API::Run &run = outputWS->mutableRun();
495 childAlg->executeAsChildAlg();
496 return childAlg->getProperty(
"OutputWorkspace");
502 const auto &spectrumInfo =
workspace->spectrumInfo();
504 double XMin = DBL_MAX, XMax = DBL_MIN;
505 const size_t numSpec =
workspace->getNumberHistograms();
506 for (
size_t i = 0; i < numSpec; ++i) {
507 if (spectrumInfo.hasDetectors(i) && !spectrumInfo.isMasked(i)) {
509 double xfront = XData.front();
510 double xback = XData.back();
511 if (std::isfinite(xfront) && std::isfinite(xback)) {
519 const double step = (XMax - XMin) /
static_cast<double>(
workspace->blocksize());
521 return {XMin, step, XMax};
529 auto isInputEvents =
static_cast<bool>(eventWS);
530 size_t numberOfSpectra = WS->getNumberHistograms();
531 if (WS->isCommonBins() && !isInputEvents) {
532 auto reverseX = make_cow<HistogramData::HistogramX>(WS->x(0).crbegin(), WS->x(0).crend());
533 for (
size_t j = 0; j < numberOfSpectra; ++j) {
534 WS->setSharedX(j, reverseX);
535 std::reverse(WS->dataY(j).begin(), WS->dataY(j).end());
536 std::reverse(WS->dataE(j).begin(), WS->dataE(j).end());
542 auto numberOfSpectra_i =
static_cast<int>(numberOfSpectra);
544 for (
int j = 0; j < numberOfSpectra_i; ++j) {
547 eventWS->getSpectrum(j).reverse();
549 std::reverse(WS->mutableX(j).begin(), WS->mutableX(j).end());
550 std::reverse(WS->mutableY(j).begin(), WS->mutableY(j).end());
551 std::reverse(WS->mutableE(j).begin(), WS->mutableE(j).end());
578 const auto &spectrumInfo =
workspace->spectrumInfo();
579 const size_t numSpec =
workspace->getNumberHistograms();
581 if (emode ==
"Direct") {
588 for (; i < numSpec; ++i) {
589 if (spectrumInfo.hasDetectors(i) && !spectrumInfo.isMonitor(i))
594 auto start = std::lower_bound(X0.cbegin(), X0.cend(), -1.0e-10 * DBL_MAX);
595 if (start == X0.end()) {
596 const std::string e(
"Check the input EFixed: the one given leads to all "
597 "bins being in the physically inaccessible region.");
599 throw std::invalid_argument(e);
601 MantidVec::difference_type bins = X0.cend() - start;
602 MantidVec::difference_type first = start - X0.cbegin();
604 result = create<MatrixWorkspace>(*
workspace, BinEdges(bins));
606 for (
size_t wsIndex = 0; wsIndex < numSpec; ++wsIndex) {
610 result->mutableX(wsIndex).assign(
X.begin() + first,
X.end());
611 result->mutableY(wsIndex).assign(
Y.begin() + first,
Y.end());
612 result->mutableE(wsIndex).assign(E.begin() + first, E.end());
614 }
else if (emode ==
"Indirect") {
621 std::vector<MantidVec::difference_type> lastBins(numSpec);
623 for (
size_t i = 0; i < numSpec; ++i) {
625 auto end = std::lower_bound(
X.cbegin(),
X.cend(), 1.0e-10 * DBL_MAX);
626 MantidVec::difference_type bins = end -
X.cbegin();
629 maxBins =
static_cast<int>(bins);
634 result = create<MatrixWorkspace>(*
workspace, numSpec, BinEdges(maxBins));
636 for (int64_t j = 0; j < int64_t(numSpec); ++j) {
638 auto k = lastBins[j];
640 auto &
X = result->mutableX(j);
641 std::copy(edges.cbegin(), edges.cbegin() + k,
X.begin());
645 std::iota(
X.begin() + k,
X.end(),
workspace->x(j)[k] + 1);
648 std::copy(
workspace->y(j).cbegin(),
workspace->y(j).cbegin() + (k - 1), result->mutableY(j).begin());
649 std::copy(
workspace->e(j).cbegin(),
workspace->e(j).cbegin() + (k - 1), result->mutableE(j).begin());
661 const size_t outSize = outputWS->getNumberBins(i);
662 for (
size_t j = 0; j < outSize; ++j) {
663 const double width = std::abs(outputWS->x(i)[j + 1] - outputWS->x(i)[j]);
664 outputWS->mutableY(i)[j] = outputWS->y(i)[j] / width;
665 outputWS->mutableE(i)[j] = outputWS->e(i)[j] / width;
#define DECLARE_ALGORITHM(classname)
IPeaksWorkspace_sptr workspace
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PARALLEL_FOR_IF(condition)
Empty definitions - to enable set your complier to enable openMP.
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
virtual std::shared_ptr< Algorithm > createChildAlgorithm(const std::string &name, const double startProgress=-1., const double endProgress=-1., const bool enableLogging=true, const int &version=-1)
Create a Child Algorithm.
void interruption_point()
This is called during long-running operations, and check if the algorithm has requested that it be ca...
void addProperty(Kernel::Property *prop, bool overwrite=false)
Add data to the object in the form of a property.
Helper class for reporting progress from algorithms.
This class stores information regarding an experimental run as a series of log entries.
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
void reverse(const API::MatrixWorkspace_sptr &WS)
Reverses the workspace if X values are in descending order.
API::MatrixWorkspace_sptr convertQuickly(const API::MatrixWorkspace_const_sptr &inputWS, const double &factor, const double &power)
Convert the workspace units according to a simple output = a * (input^b) relationship.
virtual API::MatrixWorkspace_sptr convertViaTOF(Kernel::Unit_const_sptr fromUnit, API::MatrixWorkspace_const_sptr inputWS)
Convert the workspace units using TOF as an intermediate step in the conversion.
const std::vector< double > calculateRebinParams(const API::MatrixWorkspace_const_sptr &workspace) const
The Rebin parameters should cover the full range of the converted unit, with the same number of bins.
virtual void storeEModeOnWorkspace(API::MatrixWorkspace_sptr outputWS)
Stores the emode in the provided workspace.
Kernel::Unit_const_sptr m_inputUnit
The unit of the input workspace.
void putBackBinWidth(const API::MatrixWorkspace_sptr &outputWS)
Divide by the bin width if workspace is a distribution.
API::MatrixWorkspace_sptr alignBins(const API::MatrixWorkspace_sptr &workspace)
Calls Rebin as a Child Algorithm to align the bins.
API::MatrixWorkspace_sptr executeUnitConversion(const API::MatrixWorkspace_sptr &inputWS)
Executes the main part of the algorithm that handles the conversion of the units.
void init() override
Initialisation method.
void setupMemberVariables(const API::MatrixWorkspace_const_sptr &inputWS)
Initialise the member variables.
API::MatrixWorkspace_sptr removeUnphysicalBins(const API::MatrixWorkspace_const_sptr &workspace)
For conversions to energy transfer, removes bins corresponding to inaccessible values.
bool m_inputEvents
to histogram workspaces.
Kernel::Unit_sptr m_outputUnit
The unit we're going to.
bool m_distribution
Whether input is a distribution.
void exec() override
Executes the algorithm.
std::size_t m_numberOfSpectra
The number of spectra in the input workspace.
API::MatrixWorkspace_sptr setupOutputWorkspace(const API::MatrixWorkspace_const_sptr &inputWS)
Create an output workspace of the appropriate (histogram or event) type and copy over the data.
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 error(const std::string &msg)
Logs at error level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
std::shared_ptr< const MatrixWorkspace > MatrixWorkspace_const_sptr
shared pointer to the matrix workspace base class (const version)
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
std::unordered_map< UnitParams, double > UnitParametersMap
std::shared_ptr< const Unit > Unit_const_sptr
Shared pointer to the Unit base class (const version)
std::enable_if< std::is_pointer< Arg >::value, bool >::type threadSafe(Arg workspace)
Thread-safety check Checks the workspace to ensure it is suitable for multithreaded access.
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Generate a tableworkspace to store the calibration results.
static Type fromString(const std::string &modeStr)
Returns the emode from the given string.
Type
Define the available energy transfer modes It is important to assign enums proper numbers,...
@ Input
An input workspace.
@ Output
An output workspace.