18#include "MantidHistogramData/Histogram.h"
23#include "MantidParallel/Communicator.h"
32using namespace Kernel;
34using namespace DataObjects;
35using namespace HistogramData;
39 auto wsValidator = std::make_shared<CompositeValidator>();
43 "Name of the input workspace");
45 "Name of the output workspace, can be the same as the input");
50 "The name of the units to convert to (must be one of those "
53 std::vector<std::string> propOptions{
"Elastic",
"Direct",
"Indirect"};
54 declareProperty(
"EMode",
"Elastic", std::make_shared<StringListValidator>(propOptions),
55 "The energy mode (default: elastic)");
56 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
57 mustBePositive->setLower(0.0);
59 "Value of fixed energy in meV : EI (EMode='Direct') or EF "
60 "(EMode='Indirect') . Must be\n"
61 "set if the target unit requires it (e.g. DeltaE)");
64 "If true (default is false), rebins after conversion to "
65 "ensure that all spectra in the output workspace\n"
66 "have identical bin boundaries. This option is not "
68 "http://www.mantidproject.org/ConvertUnits).");
71 "When checked, if the Input Workspace contains Points\n"
72 "the algorithm ConvertToHistogram will be run to convert\n"
73 "the Points to Bins. The Output Workspace will contains Bins.");
89 const bool acceptPointData =
getProperty(
"ConvertFromPointData");
90 bool workspaceWasConverted =
false;
100 if (outputWSName == inputWSName) {
104 <<
"), so just pointing the output workspace "
105 "property to the input workspace.\n";
106 setProperty(
"OutputWorkspace", std::const_pointer_cast<MatrixWorkspace>(inputWS));
111 duplicate->initialize();
112 duplicate->setProperty(
"InputWorkspace", inputWS);
113 duplicate->execute();
115 auto outputWs = std::dynamic_pointer_cast<MatrixWorkspace>(temp);
124 if (!inputWS->isHistogramData()) {
125 if (acceptPointData) {
126 workspaceWasConverted =
true;
127 g_log.
information(
"ConvertFromPointData is checked. Running ConvertToHistogram\n");
131 convToHist->setProperty(
"InputWorkspace", inputWS);
132 convToHist->execute();
134 correctWS = std::dynamic_pointer_cast<MatrixWorkspace>(temp);
136 if (!correctWS->isHistogramData()) {
137 throw std::runtime_error(
"Failed to convert workspace from Points to Bins");
140 throw std::runtime_error(
"Workspace contains points, you can either run "
141 "ConvertToHistogram on it, or set "
142 "ConvertFromPointData to enabled");
151 if (workspaceWasConverted) {
152 g_log.
information(
"ConvertUnits is completed. Running ConvertToPointData.\n");
154 convtoPoints->setProperty(
"InputWorkspace", outputWS);
155 convtoPoints->execute();
157 outputWS = std::dynamic_pointer_cast<MatrixWorkspace>(temp);
159 if (outputWS->isHistogramData()) {
160 throw std::runtime_error(
"Failed to convert workspace from Bins to Points");
180 if (inputWS->x(0).size() < 2) {
181 std::stringstream msg;
182 msg <<
"Input workspace has invalid X axis binning parameters. Should "
184 "at least 2 values. Found "
185 << inputWS->x(0).size() <<
".";
186 throw std::runtime_error(msg.str());
188 if (inputWS->x(0).front() > inputWS->x(0).back() ||
190 throw std::runtime_error(
"Input workspace has invalid X axis binning "
191 "parameters. X values should be increasing.");
195 double factor, power;
208 if (!outputWS->x(0).empty() &&
209 (outputWS->x(0).front() > outputWS->x(0).back() ||
224 if (
alignBins && !outputWS->isCommonBins())
242 m_distribution = inputWS->isDistribution() && !inputWS->YUnit().empty();
244 m_inputEvents = (std::dynamic_pointer_cast<const EventWorkspace>(inputWS) !=
nullptr);
262 if (outputWS != inputWS) {
263 outputWS = inputWS->clone();
273 const auto &
X = outputWS->x(i);
274 auto &
Y = outputWS->mutableY(i);
275 auto &E = outputWS->mutableE(i);
276 for (
size_t j = 0; j <
Y.size(); ++j) {
277 const double width = std::abs(
X[j + 1] -
X[j]);
300 const bool overwrite(
true);
301 outputWS->mutableRun().addProperty(
"deltaE-mode",
getPropertyValue(
"EMode"), overwrite);
312 const double &power) {
318 const bool commonBoundaries = inputWS->isCommonBins();
319 if (commonBoundaries) {
321 for (
auto &
x : outputWS->mutableX(0)) {
322 x = factor * std::pow(
x, power);
325 auto xVals = outputWS->sharedX(0);
328 for (int64_t j = 1; j < numberOfSpectra_i; ++j) {
330 outputWS->setX(j, xVals);
346 for (int64_t k = 0; k < numberOfSpectra_i; ++k) {
348 if (!commonBoundaries) {
349 for (
auto &
x : outputWS->mutableX(k)) {
350 x = factor * std::pow(
x, power);
355 eventWS->getSpectrum(k).convertUnitsQuickly(factor, power);
376 using namespace Geometry;
383 const auto &spectrumInfo = inputWS->spectrumInfo();
384 double l1 = spectrumInfo.l1();
385 g_log.
debug() <<
"Source-sample distance: " << l1 <<
'\n';
387 int failedDetectorCount = 0;
397 std::vector<double> emptyVec;
401 efixedProp = inputWS->getEFixedGivenEMode(
nullptr, emode);
402 }
catch (std::runtime_error &) {
406 std::vector<std::string> parameters = inputWS->getInstrument()->getStringParameter(
"show-signed-theta");
407 bool signedTheta = (!parameters.empty()) && find(parameters.begin(), parameters.end(),
"Always") != parameters.end();
409 auto checkFromUnit = std::unique_ptr<Unit>(fromUnit->clone());
410 auto checkOutputUnit = std::unique_ptr<Unit>(outputUnit->clone());
413 const double checkdelta = 0.0;
416 upmap[UnitParams::efixed] = efixedProp;
418 size_t checkIndex = 0;
419 spectrumInfo.getDetectorValues(*fromUnit, *outputUnit, emode, signedTheta, checkIndex, upmap);
421 auto checkXValues = inputWS->readX(checkIndex);
424 checkFromUnit->toTOF(checkXValues, emptyVec, l1, emode, upmap);
426 checkOutputUnit->fromTOF(checkXValues, emptyVec, l1, emode, upmap);
427 }
catch (std::runtime_error &) {
435 auto &outSpectrumInfo = outputWS->mutableSpectrumInfo();
438 for (int64_t i = 0; i < numberOfSpectra_i; ++i) {
440 double efixed = efixedProp;
444 const double delta = 0.0;
446 auto localFromUnit = std::unique_ptr<Unit>(fromUnit->clone());
447 auto localOutputUnit = std::unique_ptr<Unit>(outputUnit->clone());
454 outSpectrumInfo.getDetectorValues(*fromUnit, *outputUnit, emode, signedTheta, i,
pmap);
456 localFromUnit->toTOF(outputWS->dataX(i), emptyVec, l1, emode,
pmap);
458 localOutputUnit->fromTOF(outputWS->dataX(i), emptyVec, l1, emode,
pmap);
462 eventWS->getSpectrum(i).convertUnitsViaTof(localFromUnit.get(), localOutputUnit.get());
464 }
catch (std::runtime_error &) {
467 failedDetectorCount++;
472 outputWS->getSpectrum(i).clearData();
473 if (outSpectrumInfo.hasDetectors(i))
474 outSpectrumInfo.setMasked(i,
true);
482 if (failedDetectorCount != 0) {
483 g_log.
information() <<
"Unable to calculate sample-detector distance for " << failedDetectorCount
484 <<
" spectra. Masking spectrum.\n";
493 API::Run &run = outputWS->mutableRun();
504 throw std::runtime_error(
"ConvertUnits: Parallel support for aligning bins not implemented.");
513 childAlg->executeAsChildAlg();
514 return childAlg->getProperty(
"OutputWorkspace");
520 const auto &spectrumInfo =
workspace->spectrumInfo();
522 double XMin = DBL_MAX, XMax = DBL_MIN;
523 const size_t numSpec =
workspace->getNumberHistograms();
524 for (
size_t i = 0; i < numSpec; ++i) {
525 if (spectrumInfo.hasDetectors(i) && !spectrumInfo.isMasked(i)) {
527 double xfront = XData.front();
528 double xback = XData.back();
529 if (std::isfinite(xfront) && std::isfinite(xback)) {
537 const double step = (XMax - XMin) /
static_cast<double>(
workspace->blocksize());
539 return {XMin, step, XMax};
547 auto isInputEvents =
static_cast<bool>(eventWS);
548 size_t numberOfSpectra = WS->getNumberHistograms();
549 if (WS->isCommonBins() && !isInputEvents) {
550 auto reverseX = make_cow<HistogramData::HistogramX>(WS->x(0).crbegin(), WS->x(0).crend());
551 for (
size_t j = 0; j < numberOfSpectra; ++j) {
552 WS->setSharedX(j, reverseX);
553 std::reverse(WS->dataY(j).begin(), WS->dataY(j).end());
554 std::reverse(WS->dataE(j).begin(), WS->dataE(j).end());
560 auto numberOfSpectra_i =
static_cast<int>(numberOfSpectra);
562 for (
int j = 0; j < numberOfSpectra_i; ++j) {
565 eventWS->getSpectrum(j).reverse();
567 std::reverse(WS->mutableX(j).begin(), WS->mutableX(j).end());
568 std::reverse(WS->mutableY(j).begin(), WS->mutableY(j).end());
569 std::reverse(WS->mutableE(j).begin(), WS->mutableE(j).end());
596 const auto &spectrumInfo =
workspace->spectrumInfo();
597 const size_t numSpec =
workspace->getNumberHistograms();
599 if (emode ==
"Direct") {
606 for (; i < numSpec; ++i) {
607 if (spectrumInfo.hasDetectors(i) && !spectrumInfo.isMonitor(i))
612 auto start = std::lower_bound(X0.cbegin(), X0.cend(), -1.0e-10 * DBL_MAX);
613 if (start == X0.end()) {
614 const std::string e(
"Check the input EFixed: the one given leads to all "
615 "bins being in the physically inaccessible region.");
617 throw std::invalid_argument(e);
619 MantidVec::difference_type bins = X0.cend() - start;
620 MantidVec::difference_type first = start - X0.cbegin();
622 result = create<MatrixWorkspace>(*
workspace, BinEdges(bins));
624 for (
size_t wsIndex = 0; wsIndex < numSpec; ++wsIndex) {
628 result->mutableX(wsIndex).assign(
X.begin() + first,
X.end());
629 result->mutableY(wsIndex).assign(
Y.begin() + first,
Y.end());
630 result->mutableE(wsIndex).assign(E.begin() + first, E.end());
632 }
else if (emode ==
"Indirect") {
639 std::vector<MantidVec::difference_type> lastBins(numSpec);
641 for (
size_t i = 0; i < numSpec; ++i) {
643 auto end = std::lower_bound(
X.cbegin(),
X.cend(), 1.0e-10 * DBL_MAX);
644 MantidVec::difference_type bins = end -
X.cbegin();
647 maxBins =
static_cast<int>(bins);
652 result = create<MatrixWorkspace>(*
workspace, numSpec, BinEdges(maxBins));
654 for (int64_t j = 0; j < int64_t(numSpec); ++j) {
656 auto k = lastBins[j];
658 auto &
X = result->mutableX(j);
659 std::copy(edges.cbegin(), edges.cbegin() + k,
X.begin());
663 std::iota(
X.begin() + k,
X.end(),
workspace->x(j)[k] + 1);
666 std::copy(
workspace->y(j).cbegin(),
workspace->y(j).cbegin() + (k - 1), result->mutableY(j).begin());
667 std::copy(
workspace->e(j).cbegin(),
workspace->e(j).cbegin() + (k - 1), result->mutableE(j).begin());
678 const size_t outSize = outputWS->blocksize();
681 for (
size_t j = 0; j < outSize; ++j) {
682 const double width = std::abs(outputWS->x(i)[j + 1] - outputWS->x(i)[j]);
683 outputWS->mutableY(i)[j] = outputWS->y(i)[j] / width;
684 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...
const Parallel::Communicator & communicator() const
Returns a const reference to the (MPI) communicator of the algorithm.
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 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.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
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.