Mantid
Loading...
Searching...
No Matches
HFIRLoad.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 +
7#include <string>
8
12#include "MantidAPI/Run.h"
18#include "Poco/NumberFormatter.h"
19
21
22// Register the algorithm into the AlgorithmFactory
23DECLARE_ALGORITHM(HFIRLoad)
24
25using namespace Kernel;
26using namespace API;
27using namespace Geometry;
28using namespace DataObjects;
29
31 declareProperty(std::make_unique<API::FileProperty>("Filename", "", API::FileProperty::Load, ".xml"),
32 "The name of the input file to load");
33 declareProperty(std::make_unique<WorkspaceProperty<>>("OutputWorkspace", "", Direction::Output),
34 "Then name of the output workspace");
35 declareProperty("NoBeamCenter", false, "If true, the detector will not be moved according to the beam center");
36 declareProperty("BeamCenterX", EMPTY_DBL(), "Beam position in X pixel coordinates");
37 declareProperty("BeamCenterY", EMPTY_DBL(), "Beam position in Y pixel coordinates");
38 declareProperty("SampleDetectorDistance", EMPTY_DBL(),
39 "Sample to detector distance to use (overrides meta data), in mm");
40 declareProperty("SampleDetectorDistanceOffset", EMPTY_DBL(),
41 "Offset to the sample to detector distance (use only when "
42 "using the distance found in the meta data), in mm."
43 "Not used when SampleDetectorDistance is provided.");
44
45 // Optionally, we can specify the wavelength and wavelength spread and
46 // overwrite
47 // the value in the data file (used when the data file is not populated)
48 auto mustBePositive = std::make_shared<Kernel::BoundedValidator<double>>();
49 mustBePositive->setLower(0.0);
50 declareProperty("Wavelength", EMPTY_DBL(), mustBePositive,
51 "Wavelength value to use when loading the data file (Angstrom).");
52 declareProperty("WavelengthSpread", 0.1, mustBePositive,
53 "Wavelength spread to use when loading the data file (default 0.0)");
54
55 declareProperty("OutputMessage", "", Direction::Output);
56 declareProperty("ReductionProperties", "__sans_reduction_properties", Direction::Input);
57}
58
60void HFIRLoad::moveToBeamCenter(API::MatrixWorkspace_sptr &dataWS, double &center_x, double &center_y) {
61 double default_ctr_x_pix = 0.0;
62 double default_ctr_y_pix = 0.0;
63 double default_ctr_x = 0.0;
64 double default_ctr_y = 0.0;
65 HFIRInstrument::getDefaultBeamCenter(dataWS, default_ctr_x_pix, default_ctr_y_pix);
66 HFIRInstrument::getCoordinateFromPixel(default_ctr_x_pix, default_ctr_y_pix, dataWS, default_ctr_x, default_ctr_y);
67
68 // Check that we have a beam center defined, otherwise set the
69 // default beam center
70 if (isEmpty(center_x) || isEmpty(center_y)) {
71 center_x = default_ctr_x_pix;
72 center_y = default_ctr_y_pix;
73 g_log.information() << "Setting beam center to [" << Poco::NumberFormatter::format(center_x, 1) << ", "
74 << Poco::NumberFormatter::format(center_y, 1) << "]\n";
75 return;
76 }
77
78 double beam_ctr_x = 0.0;
79 double beam_ctr_y = 0.0;
80 HFIRInstrument::getCoordinateFromPixel(center_x, center_y, dataWS, beam_ctr_x, beam_ctr_y);
81
82 auto mvAlg = createChildAlgorithm("MoveInstrumentComponent", 0.5, 0.50);
83 mvAlg->setProperty<MatrixWorkspace_sptr>("Workspace", dataWS);
84 mvAlg->setProperty("ComponentName", "detector1");
85 mvAlg->setProperty("X", default_ctr_x - beam_ctr_x);
86 mvAlg->setProperty("Y", default_ctr_y - beam_ctr_y);
87 mvAlg->setProperty("RelativePosition", true);
88 mvAlg->executeAsChildAlg();
89 g_log.information() << "Moving beam center to " << center_x << " " << center_y << '\n';
90}
91
99 // Reduction property manager
100 const std::string reductionManagerName = getProperty("ReductionProperties");
101 std::shared_ptr<PropertyManager> reductionManager;
102 if (PropertyManagerDataService::Instance().doesExist(reductionManagerName)) {
103 reductionManager = PropertyManagerDataService::Instance().retrieve(reductionManagerName);
104 } else {
105 reductionManager = std::make_shared<PropertyManager>();
106 PropertyManagerDataService::Instance().addOrReplace(reductionManagerName, reductionManager);
107 }
108
109 Progress progress(this, 0.0, 1.0, 5);
110
111 progress.report();
112
113 // If the load algorithm isn't in the reduction properties, add it
114 if (!reductionManager->existsProperty("LoadAlgorithm")) {
115 auto algProp = std::make_unique<AlgorithmProperty>("LoadAlgorithm");
116 algProp->setValue(toString());
117 reductionManager->declareProperty(std::move(algProp));
118 }
119
120 const std::string fileName = getPropertyValue("Filename");
121
122 // Output log
123 std::string output_message;
124 const double wavelength_input = getProperty("Wavelength");
125 const double wavelength_spread_input = getProperty("WavelengthSpread");
126
127 progress.report("LoadSpice2D...");
128
129 auto loadAlg = createChildAlgorithm("LoadSpice2D", 0, 0.2);
130 loadAlg->setProperty("Filename", fileName);
131 loadAlg->setPropertyValue("OutputWorkspace", getPropertyValue("OutputWorkspace"));
132 if (!isEmpty(wavelength_input)) {
133 loadAlg->setProperty("Wavelength", wavelength_input);
134 loadAlg->setProperty("WavelengthSpread", wavelength_spread_input);
135 }
136 try {
137 loadAlg->executeAsChildAlg();
138 } catch (...) {
139 // The only way HFIR SANS can load Nexus files is if it's loading data that
140 // has already
141 // been processed. This will only happen with sensitivity data.
142 // So if we make it here and are still unable to load the file, assume it's
143 // a sensitivity file.
144 // This will cover the special case where the instrument scientist uses a
145 // reduced data set
146 // as a sensitivity data set.
147 g_log.warning() << "Unable to load file as a SPICE file. Trying to load as "
148 "a Nexus file.\n";
149 loadAlg = createChildAlgorithm("Load", 0, 0.2);
150 loadAlg->setProperty("Filename", fileName);
151 loadAlg->executeAsChildAlg();
152 Workspace_sptr dataWS_tmp = loadAlg->getProperty("OutputWorkspace");
153 MatrixWorkspace_sptr dataWS = std::dynamic_pointer_cast<MatrixWorkspace>(dataWS_tmp);
154 dataWS->mutableRun().addProperty("is_sensitivity", 1, "", true);
155 setProperty<MatrixWorkspace_sptr>("OutputWorkspace", dataWS);
156 g_log.notice() << "Successfully loaded " << fileName << " and setting sensitivity flag to True\n";
157 return;
158 }
159 Workspace_sptr dataWS_tmp = loadAlg->getProperty("OutputWorkspace");
160 AnalysisDataService::Instance().addOrReplace(getPropertyValue("OutputWorkspace"), dataWS_tmp);
161 g_log.debug() << "Calling LoadSpice2D Done. OutputWorkspace name = " << dataWS_tmp->getName() << '\n';
162 API::MatrixWorkspace_sptr dataWS = std::dynamic_pointer_cast<MatrixWorkspace>(dataWS_tmp);
163
164 // Get the sample-detector distance
165 // If SampleDetectorDistance is provided, use it!
166 // Otherwise get's "sample-detector-distance" from the data file
167 // And uses SampleDetectorDistanceOffset if given!
168 double sdd = 0.0;
169 const double sample_det_dist = getProperty("SampleDetectorDistance");
170 if (!isEmpty(sample_det_dist)) {
171 g_log.debug() << "Getting the SampleDetectorDistance = " << sample_det_dist
172 << " from the Algorithm input property.\n";
173 sdd = sample_det_dist;
174 } else {
175 const std::string sddName = "total-sample-detector-distance";
176 Mantid::Kernel::Property *prop = dataWS->run().getProperty(sddName);
177 auto *dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double> *>(prop);
178 if (!dp) {
179 throw std::runtime_error("Could not cast (interpret) the property " + sddName +
180 " as a floating point numeric value.");
181 }
182 sdd = *dp;
183
184 // Modify SDD according to offset if given
185 const double sample_det_offset = getProperty("SampleDetectorDistanceOffset");
186 if (!isEmpty(sample_det_offset)) {
187 sdd += sample_det_offset;
188 }
189 }
190 dataWS->mutableRun().addProperty("sample_detector_distance", sdd, "mm", true);
191 g_log.debug() << "FINAL: Using Total Sample Detector Distance = " << sdd << "\n";
192
193 progress.report("MoveInstrumentComponent...");
194
195 // Move the detector to its correct position
196 auto mvAlg = createChildAlgorithm("MoveInstrumentComponent", 0.2, 0.4);
197 mvAlg->setProperty<MatrixWorkspace_sptr>("Workspace", dataWS);
198 mvAlg->setProperty("ComponentName", "detector1");
199 mvAlg->setProperty("Z", sdd / 1000.0);
200 mvAlg->setProperty("RelativePosition", false);
201 mvAlg->executeAsChildAlg();
202 g_log.information() << "Moving detector to " << sdd / 1000.0 << '\n';
203 output_message += " Detector position: " + Poco::NumberFormatter::format(sdd / 1000.0, 3) + " m\n";
204
205 // Compute beam diameter at the detector
206 double src_to_sample = 0.0;
207
208 try {
209 src_to_sample = HFIRInstrument::getSourceToSampleDistance(dataWS);
210 dataWS->mutableRun().addProperty("source-sample-distance", src_to_sample, "mm", true);
211 output_message +=
212 " Computed SSD from number of guides: " + Poco::NumberFormatter::format(src_to_sample / 1000.0, 3) + " \n";
213 } catch (...) {
214 Mantid::Kernel::Property *prop = dataWS->run().getProperty("source-sample-distance");
215 auto *dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double> *>(prop);
216 src_to_sample = *dp;
217 output_message += " Could not compute SSD from number of guides, taking: " +
218 Poco::NumberFormatter::format(src_to_sample / 1000.0, 3) + " \n";
219 }
220
221 const std::string sampleADName = "sample-aperture-diameter";
222 Mantid::Kernel::Property *prop = dataWS->run().getProperty(sampleADName);
223 auto *dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double> *>(prop);
224 if (!dp) {
225 throw std::runtime_error("Could not cast (interpret) the property " + sampleADName +
226 " as a floating point numeric value.");
227 }
228 double sample_apert = *dp;
229
230 const std::string sourceADName = "source-aperture-diameter";
231 prop = dataWS->run().getProperty(sourceADName);
232 dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double> *>(prop);
233 if (!dp) {
234 throw std::runtime_error("Could not cast (interpret) the property " + sourceADName +
235 " as a floating point numeric value.");
236 }
237 double source_apert = *dp;
238
239 const double beam_diameter = sdd / src_to_sample * (source_apert + sample_apert) + sample_apert;
240 dataWS->mutableRun().addProperty("beam-diameter", beam_diameter, "mm", true);
241
242 progress.report("Move to center beam...");
243
244 double center_x = 0;
245 double center_y = 0;
246
247 // Move the beam center to its proper position
248 const bool noBeamCenter = getProperty("NoBeamCenter");
249 if (!noBeamCenter) {
250 center_x = getProperty("BeamCenterX");
251 center_y = getProperty("BeamCenterY");
252 if (isEmpty(center_x) && isEmpty(center_y)) {
253 if (reductionManager->existsProperty("LatestBeamCenterX") &&
254 reductionManager->existsProperty("LatestBeamCenterY")) {
255 center_x = reductionManager->getProperty("LatestBeamCenterX");
256 center_y = reductionManager->getProperty("LatestBeamCenterY");
257 }
258 }
259
260 moveToBeamCenter(dataWS, center_x, center_y);
261
262 progress.report();
263
264 // Add beam center to reduction properties, as the last beam center position
265 // that was used.
266 // This will give us our default position next time.
267 if (!reductionManager->existsProperty("LatestBeamCenterX"))
268 reductionManager->declareProperty(std::make_unique<PropertyWithValue<double>>("LatestBeamCenterX", center_x));
269 else
270 reductionManager->setProperty("LatestBeamCenterX", center_x);
271 if (!reductionManager->existsProperty("LatestBeamCenterY"))
272 reductionManager->declareProperty(std::make_unique<PropertyWithValue<double>>("LatestBeamCenterY", center_y));
273 else
274 reductionManager->setProperty("LatestBeamCenterY", center_y);
275
276 dataWS->mutableRun().addProperty("beam_center_x", center_x, "pixel", true);
277 dataWS->mutableRun().addProperty("beam_center_y", center_y, "pixel", true);
278 output_message += " Beam center: " + Poco::NumberFormatter::format(center_x, 1) + ", " +
279 Poco::NumberFormatter::format(center_y, 1) + "\n";
280 } else {
281 HFIRInstrument::getDefaultBeamCenter(dataWS, center_x, center_y);
282
283 dataWS->mutableRun().addProperty("beam_center_x", center_x, "pixel", true);
284 dataWS->mutableRun().addProperty("beam_center_y", center_y, "pixel", true);
285 output_message += " Default beam center: " + Poco::NumberFormatter::format(center_x, 1) + ", " +
286 Poco::NumberFormatter::format(center_y, 1) + "\n";
287 }
288
289 setProperty<MatrixWorkspace_sptr>("OutputWorkspace", std::dynamic_pointer_cast<MatrixWorkspace>(dataWS));
290 setPropertyValue("OutputMessage", output_message);
291}
292
293} // namespace Mantid::WorkflowAlgorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
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
std::string toString() const override
Serialize an object to a string.
Definition: Algorithm.cpp:905
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
void setPropertyValue(const std::string &name, const std::string &value) override
Set the value of a property by string N.B.
Definition: Algorithm.cpp:1975
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
@ Load
allowed here which will be passed to the algorithm
Definition: FileProperty.h:52
Helper class for reporting progress from algorithms.
Definition: Progress.h:25
A property class for workspaces.
void debug(const std::string &msg)
Logs at debug level.
Definition: Logger.cpp:114
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
The concrete, templated class for properties.
Base class for properties.
Definition: Property.h:94
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
void moveToBeamCenter(API::MatrixWorkspace_sptr &dataWS, double &center_x, double &center_y)
Move the detector according to the beam center.
Definition: HFIRLoad.cpp:60
void exec() override
Execution code.
Definition: HFIRLoad.cpp:98
void init() override
Initialisation code.
Definition: HFIRLoad.cpp:30
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Definition: Workspace_fwd.h:20
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
void getDefaultBeamCenter(const API::MatrixWorkspace_sptr &dataWS, double &pixel_x, double &pixel_y)
double getSourceToSampleDistance(const API::MatrixWorkspace_sptr &dataWS)
void getCoordinateFromPixel(const double &pixel_x, const double &pixel_y, const API::MatrixWorkspace_sptr &dataWS, double &x, double &y)
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