Mantid
Loading...
Searching...
No Matches
ApplyTransmissionCorrection.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
17
18namespace Mantid::Algorithms {
19
20// Register the algorithm into the AlgorithmFactory
21DECLARE_ALGORITHM(ApplyTransmissionCorrection)
22
23using namespace Kernel;
24using namespace API;
25using namespace Geometry;
26using namespace HistogramData;
27using namespace DataObjects;
28
29namespace {
30namespace PropertyNames {
31const std::string INPUT_WKSP("InputWorkspace");
32const std::string OUTPUT_WKSP("OutputWorkspace");
33const std::string TRANSMISSION_WKSP("TransmissionWorkspace");
34const std::string TRANSMISSION_VALUE("TransmissionValue");
35const std::string TRANSMISSION_ERROR("TransmissionError");
36} // namespace PropertyNames
37} // namespace
38
40 declareProperty(std::make_unique<WorkspaceProperty<>>(PropertyNames::INPUT_WKSP, "", Direction::Input),
41 "Workspace to apply the transmission correction to");
42 declareProperty(std::make_unique<WorkspaceProperty<>>(PropertyNames::TRANSMISSION_WKSP, "", Direction::Input,
44 "Workspace containing the transmission values [optional]");
45 declareProperty(std::make_unique<WorkspaceProperty<>>(PropertyNames::OUTPUT_WKSP, "", Direction::Output),
46 "Workspace to store the corrected data in");
47
48 // Alternatively, the user can specify a transmission that will ba applied to
49 // all wavelength bins
50 declareProperty(PropertyNames::TRANSMISSION_VALUE, EMPTY_DBL(),
51 "Transmission value to apply to all wavelengths. If specified, "
52 "TransmissionWorkspace will not be used.");
53 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
54 mustBePositive->setLower(0.0);
55 declareProperty(PropertyNames::TRANSMISSION_ERROR, 0.0, mustBePositive,
56 "The error on the transmission value (default 0.0)");
57
58 declareProperty("ThetaDependent", true, "If true, a theta-dependent transmission correction will be applied.");
59}
60
61std::map<std::string, std::string> ApplyTransmissionCorrection::validateInputs() {
62 std::map<std::string, std::string> result;
63
64 // needed to find out what mode we are working in
65 const double trans_value = getProperty(PropertyNames::TRANSMISSION_VALUE);
66 if (isEmpty(trans_value)) { // require a transmission workspace
67 MatrixWorkspace_const_sptr transWS = getProperty(PropertyNames::TRANSMISSION_WKSP);
68 if (!transWS) {
69 const std::string msg("Must specify \"TransmissionValue\" or \"TransmissionWorkspace\"");
70 result[PropertyNames::TRANSMISSION_VALUE] = msg;
71 result[PropertyNames::TRANSMISSION_WKSP] = msg;
72 } else {
73 MatrixWorkspace_const_sptr inputWS = getProperty(PropertyNames::INPUT_WKSP);
74 if ((transWS->getNumberHistograms() > 1) && (transWS->getNumberHistograms() != inputWS->getNumberHistograms())) {
75 const std::string msg("Input and transmission workspaces have "
76 "incompatible number of spectra");
77 result[PropertyNames::INPUT_WKSP] = msg;
78 result[PropertyNames::TRANSMISSION_WKSP] = msg;
79 } else if (transWS->y(0).size() != inputWS->y(0).size()) {
80 const std::string msg("Input and transmission workspaces have a "
81 "different number of wavelength bins");
82 result[PropertyNames::INPUT_WKSP] = msg;
83 result[PropertyNames::TRANSMISSION_WKSP] = msg;
84 }
85 }
86 }
87
88 return result;
89}
90
92 const bool thetaDependent = getProperty("ThetaDependent");
93 const double trans_value = getProperty(PropertyNames::TRANSMISSION_VALUE);
94 const double trans_error = getProperty(PropertyNames::TRANSMISSION_ERROR);
95 MatrixWorkspace_const_sptr transWS = getProperty(PropertyNames::TRANSMISSION_WKSP);
96
97 // Check whether we only need to divided the workspace by the transmission.
98 // theta-dependence modifies the input transmission information
99 if (thetaDependent) {
100 MatrixWorkspace_sptr inputWS = getProperty(PropertyNames::INPUT_WKSP);
101
102 // initial values of tranmission come from the value
103 HistogramY TrIn(inputWS->y(0).size(), trans_value);
104 HistogramE ETrIn(inputWS->y(0).size(), trans_error);
105
106 if (isEmpty(trans_value)) {
107 // override the values specified above
108 TrIn = transWS->y(0);
109 ETrIn = transWS->e(0);
110 }
111
112 const auto numHists = static_cast<int>(inputWS->getNumberHistograms());
113 Progress progress(this, 0.0, 1.0, numHists);
114
115 // Create a Workspace2D to hold the correction (applied through
116 // multiplication)
117 MatrixWorkspace_sptr corrWS = create<HistoWorkspace>(*inputWS);
118
119 const auto &spectrumInfo = inputWS->spectrumInfo();
120
121 // Loop through the spectra and apply correction
122 PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *corrWS))
123 for (int i = 0; i < numHists; i++) {
125
126 if (!spectrumInfo.hasDetectors(i)) {
127 g_log.warning() << "Workspace index " << i << " has no detector assigned to it - discarding'\n";
128 continue;
129 }
130
131 // Copy over the X data
132 corrWS->setSharedX(i, inputWS->sharedX(i));
133
134 // Skip if we have a monitor or if the detector is masked.
135 if (spectrumInfo.isMonitor(i) || spectrumInfo.isMasked(i))
136 continue;
137
138 // Compute theta-dependent transmission term for each wavelength bin
139 auto &correctionY = corrWS->mutableY(i);
140 auto &correctionE = corrWS->mutableE(i);
141
142 const double exp_term = 0.5 / cos(spectrumInfo.twoTheta(i)) + 0.5;
143 for (int j = 0; j < static_cast<int>(inputWS->y(0).size()); j++) {
144 correctionY[j] = pow(TrIn[j], -1. * exp_term); // 1 / TrIn^exp_term
145 correctionE[j] = std::fabs(ETrIn[j] * exp_term / pow(TrIn[j], exp_term + 1.0));
146 }
147
148 progress.report("Calculating transmission correction");
150 }
152
153 // apply the correction
154 MatrixWorkspace_sptr outputWS = inputWS * corrWS;
155 ;
156 setProperty(PropertyNames::OUTPUT_WKSP, outputWS);
157 } else { // !thetaDependent case - divide does the actual work
158 // this case divide and set output workspace
159 auto divideAlg = createChildAlgorithm("Divide", 0.0, 1.0);
160 divideAlg->setProperty("LHSWorkspace", getPropertyValue(PropertyNames::INPUT_WKSP));
161 if (transWS) { // use the supplied transmission workspace
162 divideAlg->setProperty("RHSWorkspace", getPropertyValue(PropertyNames::TRANSMISSION_WKSP));
163 } else {
164 // set the RHS to be a single value workspace with the requested
165 // uncertainty
166 auto createSingleAlg = createChildAlgorithm("CreateSingleValuedWorkspace");
167 createSingleAlg->setProperty("DataValue", trans_value);
168 createSingleAlg->setProperty("ErrorValue", trans_error);
169 createSingleAlg->executeAsChildAlg();
170 MatrixWorkspace_sptr singleWS = createSingleAlg->getProperty("OutputWorkspace");
171
172 divideAlg->setProperty("RHSWorkspace", singleWS);
173 }
174 divideAlg->setProperty("OutputWorkspace", getPropertyValue(PropertyNames::OUTPUT_WKSP));
175 divideAlg->executeAsChildAlg();
176
177 // call divide and set output workspace
178 MatrixWorkspace_sptr outputWS = divideAlg->getProperty("OutputWorkspace");
179 setProperty(PropertyNames::OUTPUT_WKSP, outputWS);
180 }
181}
182
183} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
#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...
Definition: MultiThreaded.h:94
#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.
Definition: Algorithm.cpp:1913
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
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.
Definition: Algorithm.cpp:842
Kernel::Logger & g_log
Definition: Algorithm.h:451
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A property class for workspaces.
std::map< std::string, std::string > validateInputs() override
Cross check inputs.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
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::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.
Definition: MultiThreaded.h:22
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54