Mantid
Loading...
Searching...
No Matches
CorrectKiKf.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 +
8#include "MantidAPI/Run.h"
18
19namespace Mantid::Algorithms {
20
21// Register with the algorithm factory
22DECLARE_ALGORITHM(CorrectKiKf)
23
24using namespace Kernel;
25using namespace API;
26using namespace DataObjects;
27using namespace Geometry;
28using std::size_t;
29
32 auto wsValidator = std::make_shared<WorkspaceUnitValidator>("DeltaE");
33
34 this->declareProperty(
35 std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>("InputWorkspace", "", Direction::Input, wsValidator),
36 "Name of the input workspace");
37 this->declareProperty(
38 std::make_unique<WorkspaceProperty<API::MatrixWorkspace>>("OutputWorkspace", "", Direction::Output),
39 "Name of the output workspace, can be the same as the input");
40
41 std::vector<std::string> propOptions{"Direct", "Indirect"};
42 this->declareProperty("EMode", "Direct", std::make_shared<StringListValidator>(propOptions),
43 "The energy mode (default: Direct)");
44 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
45 mustBePositive->setLower(0.0);
46 this->declareProperty("EFixed", EMPTY_DBL(), mustBePositive,
47 "Value of fixed energy in meV : EI (EMode=Direct) or "
48 "EF (EMode=Indirect) .");
49}
50
52 // Get the workspaces
53 MatrixWorkspace_const_sptr inputWS = this->getProperty("InputWorkspace");
54 MatrixWorkspace_sptr outputWS = this->getProperty("OutputWorkspace");
55
56 // Check if it is an event workspace
57 EventWorkspace_const_sptr eventW = std::dynamic_pointer_cast<const EventWorkspace>(inputWS);
58 if (eventW != nullptr) {
59 this->execEvent();
60 return;
61 }
62
63 // If input and output workspaces are not the same, create a new workspace for
64 // the output using the clone method to account for different workspace types
65 if (outputWS != inputWS) {
66 outputWS = inputWS->clone();
67 }
68
69 const size_t size = inputWS->blocksize();
70 // Calculate the number of spectra in this workspace
71 const auto numberOfSpectra = static_cast<int>(inputWS->size() / size);
72 API::Progress prog(this, 0.0, 1.0, numberOfSpectra);
73 bool negativeEnergyWarning = false;
74
75 const std::string emodeStr = getProperty("EMode");
76 double efixedProp = getProperty("EFixed");
77
78 if (efixedProp == EMPTY_DBL()) {
79 if (emodeStr == "Direct") {
80 // Check if it has been store on the run object for this workspace
81 if (inputWS->run().hasProperty("Ei")) {
82 efixedProp = inputWS->run().getPropertyValueAsType<double>("Ei");
83 g_log.debug() << "Using stored Ei value " << efixedProp << "\n";
84 } else {
85 throw std::invalid_argument("No Ei value has been set or stored within the run information.");
86 }
87 } else {
88 // If not specified, will try to get Ef from the parameter file for
89 // indirect geometry,
90 // but it will be done for each spectrum separately, in case of different
91 // analyzer crystals
92 }
93 }
94
95 // Get the parameter map
96 const auto &componentInfo = outputWS->componentInfo();
97 const auto &spectrumInfo = inputWS->spectrumInfo();
98
99 PARALLEL_FOR_IF(Kernel::threadSafe(*inputWS, *outputWS))
100 for (int64_t i = 0; i < int64_t(numberOfSpectra); ++i) {
102 double Efi = 0;
103 // Now get the detector object for this histogram to check if monitor
104 // or to get Ef for indirect geometry
105 if (emodeStr == "Indirect") {
106 if (efixedProp != EMPTY_DBL())
107 Efi = efixedProp;
108 // If a DetectorGroup is present should provide a value as a property
109 // instead
110 else if (spectrumInfo.hasUniqueDetector(i)) {
111 getEfixedFromParameterMap(Efi, i, spectrumInfo, componentInfo);
112 } else {
113 g_log.information() << "Workspace Index " << i << ": cannot find detector"
114 << "\n";
115 }
116 }
117
118 auto &yOut = outputWS->mutableY(i);
119 auto &eOut = outputWS->mutableE(i);
120 const auto &xIn = inputWS->points(i);
121 auto &yIn = inputWS->y(i);
122 auto &eIn = inputWS->e(i);
123 // Copy the energy transfer axis
124 outputWS->setSharedX(i, inputWS->sharedX(i));
125 for (unsigned int j = 0; j < size; ++j) {
126 const double deltaE = xIn[j];
127 double Ei = 0.;
128 double Ef = 0.;
129 double kioverkf = 1.;
130 if (emodeStr == "Direct") // Ei=Efixed
131 {
132 Ei = efixedProp;
133 Ef = Ei - deltaE;
134 } else // Ef=Efixed
135 {
136 Ef = Efi;
137 Ei = Efi + deltaE;
138 }
139 // if Ei or Ef is negative, it should be a warning
140 // however, if the intensity is 0 (histogram goes to energy transfer
141 // higher than Ei) it is still ok, so no warning.
142 if ((Ei <= 0) || (Ef <= 0)) {
143 kioverkf = 0.;
144 if (yIn[j] != 0)
145 negativeEnergyWarning = true;
146 } else
147 kioverkf = std::sqrt(Ei / Ef);
148
149 yOut[j] = yIn[j] * kioverkf;
150 eOut[j] = eIn[j] * kioverkf;
151 }
152 prog.report();
154 } // end for i
156
157 if (negativeEnergyWarning)
158 g_log.information() << "Ef <= 0 or Ei <= 0 in at least one spectrum!!!!\n";
159 if ((negativeEnergyWarning) && (efixedProp == EMPTY_DBL()))
160 g_log.information() << "Try to set fixed energy\n";
161 this->setProperty("OutputWorkspace", outputWS);
162}
163
170 g_log.information("Processing event workspace");
171
172 const MatrixWorkspace_const_sptr matrixInputWS = getProperty("InputWorkspace");
173 auto inputWS = std::dynamic_pointer_cast<const EventWorkspace>(matrixInputWS);
174
175 // generate the output workspace pointer
176 API::MatrixWorkspace_sptr matrixOutputWS = getProperty("OutputWorkspace");
177 if (matrixOutputWS != matrixInputWS) {
178 matrixOutputWS = matrixInputWS->clone();
179 setProperty("OutputWorkspace", matrixOutputWS);
180 }
181 auto outputWS = std::dynamic_pointer_cast<EventWorkspace>(matrixOutputWS);
182
183 const std::string emodeStr = getProperty("EMode");
184 double efixedProp = getProperty("EFixed"), efixed;
185
186 if (efixedProp == EMPTY_DBL()) {
187 if (emodeStr == "Direct") {
188 // Check if it has been store on the run object for this workspace
189 if (inputWS->run().hasProperty("Ei")) {
190 efixedProp = inputWS->run().getPropertyValueAsType<double>("Ei");
191 g_log.debug() << "Using stored Ei value " << efixedProp << "\n";
192 } else {
193 throw std::invalid_argument("No Ei value has been set or stored within the run information.");
194 }
195 } else {
196 // If not specified, will try to get Ef from the parameter file for
197 // indirect geometry,
198 // but it will be done for each spectrum separately, in case of different
199 // analyzer crystals
200 }
201 }
202
203 // Get the parameter map
204 const auto &componentInfo = outputWS->componentInfo();
205
206 auto numHistograms = static_cast<int64_t>(inputWS->getNumberHistograms());
207 const auto &spectrumInfo = inputWS->spectrumInfo();
208 API::Progress prog = API::Progress(this, 0.0, 1.0, numHistograms);
210 for (int64_t i = 0; i < numHistograms; ++i) {
212 // Now get the detector object for this histogram to check if monitor
213 // or to get Ef for indirect geometry
214 if (emodeStr == "Indirect") {
215 double Efi = 0;
216 if (efixedProp != EMPTY_DBL()) {
217 Efi = efixedProp;
218 // If a DetectorGroup is present should provide a value as a property
219 // instead
220 } else if (spectrumInfo.hasUniqueDetector(i)) {
221 getEfixedFromParameterMap(Efi, i, spectrumInfo, componentInfo);
222 } else {
223 g_log.information() << "Workspace Index " << i << ": cannot find detector"
224 << "\n";
225 }
226 efixed = Efi;
227 } else
228 efixed = efixedProp;
229
230 // Do the correction
231 auto &evlist = outputWS->getSpectrum(i);
232 switch (evlist.getEventType()) {
233 case TOF:
234 // Switch to weights if needed.
235 evlist.switchTo(WEIGHTED);
236 /* no break */
237 // Fall through
238
239 case WEIGHTED:
240 correctKiKfEventHelper(evlist.getWeightedEvents(), efixed, emodeStr);
241 break;
242
243 case WEIGHTED_NOTIME:
244 correctKiKfEventHelper(evlist.getWeightedEventsNoTime(), efixed, emodeStr);
245 break;
246 }
247
248 prog.report();
250 }
252
253 outputWS->clearMRU();
254 if (inputWS->getNumberEvents() != outputWS->getNumberEvents()) {
255 g_log.information() << "Ef <= 0 or Ei <= 0 for " << inputWS->getNumberEvents() - outputWS->getNumberEvents()
256 << " events, out of " << inputWS->getNumberEvents() << '\n';
257 if (efixedProp == EMPTY_DBL())
258 g_log.information() << "Try to set fixed energy\n";
259 }
260}
261
262template <class T>
263void CorrectKiKf::correctKiKfEventHelper(std::vector<T> &wevector, double efixed, const std::string &emodeStr) {
264 double Ei, Ef;
265 float kioverkf;
266 typename std::vector<T>::iterator it;
267 for (it = wevector.begin(); it < wevector.end();) {
268 if (emodeStr == "Direct") // Ei=Efixed
269 {
270 Ei = efixed;
271 Ef = Ei - it->tof();
272 } else // Ef=Efixed
273 {
274 Ef = efixed;
275 Ei = Ef + it->tof();
276 }
277 // if Ei or Ef is negative, delete the event
278 if ((Ei <= 0) || (Ef <= 0)) {
279 it = wevector.erase(it);
280 } else {
281 kioverkf = static_cast<float>(std::sqrt(Ei / Ef));
282 it->m_weight *= kioverkf;
283 it->m_errorSquared *= kioverkf * kioverkf;
284 ++it;
285 }
286 }
287}
288
289void CorrectKiKf::getEfixedFromParameterMap(double &Efi, int64_t i, const SpectrumInfo &spectrumInfo,
290 const ComponentInfo &componentInfo) {
291 Efi = 0;
292
293 // A spectrum of several detectors has no parameters of its own
294 if (spectrumInfo.isMonitor(i) || !spectrumInfo.hasUniqueDetector(i))
295 return;
296
297 const auto eFixed = componentInfo.getNumberParameter(spectrumInfo.spectrumDefinition(i)[0].first, "Efixed");
298 if (!eFixed.empty()) {
299 Efi = eFixed.front();
300 g_log.debug() << "Spectrum index: " << i << " EFixed: " << Efi << "\n";
301 }
302}
303
304} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:547
#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.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Kernel::Logger & g_log
Definition Algorithm.h:426
Helper class for reporting progress from algorithms.
Definition Progress.h:25
API::SpectrumInfo is an intermediate step towards a SpectrumInfo that is part of Instrument-2....
bool isMonitor(const size_t index) const
Returns true if the detector(s) associated with the spectrum are monitors.
bool hasUniqueDetector(const size_t index) const
Returns true if the spectrum is associated with exactly one detector.
const SpectrumDefinition & spectrumDefinition(const size_t index) const
Returns a const reference to the SpectrumDefinition of the spectrum.
A property class for workspaces.
void getEfixedFromParameterMap(double &Efi, int64_t i, const Mantid::API::SpectrumInfo &spectrumInfo, const Mantid::Geometry::ComponentInfo &componentInfo)
void execEvent()
Execute CorrectKiKf for event workspaces.
void exec() override
Virtual method - must be overridden by concrete algorithm.
void correctKiKfEventHelper(std::vector< T > &wevector, double efixed, const std::string &emodeStr)
Execute CorrectKiKf for event lists.
void init() override
Initialisation method.
ComponentInfo : Provides a component centric view on to the instrument.
std::vector< double > getNumberParameter(const size_t componentIndex, const std::string &name, bool recursive=true) const
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.
Definition Logger.cpp:145
void information(const std::string &msg)
Logs at information level.
Definition Logger.cpp:136
void report()
Increments the loop counter by 1, then sends the progress notification on behalf of its algorithm.
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< const EventWorkspace > EventWorkspace_const_sptr
shared pointer to a const Workspace2D
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.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
@ Input
An input workspace.
Definition Property.h:54
@ Output
An output workspace.
Definition Property.h:55