Mantid
Loading...
Searching...
No Matches
ConvertHFIRSCDtoMDE.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 +
11#include "MantidAPI/Run.h"
23
24#include "Eigen/Dense"
25#include "boost/math/constants/constants.hpp"
26
27namespace Mantid::MDAlgorithms {
28
31using namespace Mantid::Geometry;
32using namespace Mantid::Kernel;
33using namespace Mantid::MDAlgorithms;
34using namespace Mantid::API;
35using namespace Mantid::DataObjects;
36
37// Register the algorithm into the AlgorithmFactory
39
40//----------------------------------------------------------------------------------------------
41
42
43const std::string ConvertHFIRSCDtoMDE::name() const { return "ConvertHFIRSCDtoMDE"; }
44
46int ConvertHFIRSCDtoMDE::version() const { return 1; }
47
49const std::string ConvertHFIRSCDtoMDE::category() const { return "MDAlgorithms\\Creation"; }
50
52const std::string ConvertHFIRSCDtoMDE::summary() const {
53 return "Convert from the detector vs scan index MDHistoWorkspace into a "
54 "MDEventWorkspace with units in Q_sample.";
55}
56
57std::map<std::string, std::string> ConvertHFIRSCDtoMDE::validateInputs() {
58 std::map<std::string, std::string> result;
59
60 API::IMDHistoWorkspace_sptr inputWS = this->getProperty("InputWorkspace");
61 std::stringstream inputWSmsg;
62 if (inputWS->getNumDims() != 3) {
63 inputWSmsg << "Incorrect number of dimensions";
64 } else if (inputWS->getDimension(0)->getName() != "y" || inputWS->getDimension(1)->getName() != "x" ||
65 inputWS->getDimension(2)->getName() != "scanIndex") {
66 inputWSmsg << "Wrong dimensions";
67 } else if (inputWS->getNumExperimentInfo() == 0) {
68 inputWSmsg << "Missing experiment info";
69 } else if (inputWS->getExperimentInfo(0)->getInstrument()->getName() != "HB3A" &&
70 inputWS->getExperimentInfo(0)->getInstrument()->getName() != "WAND") {
71 inputWSmsg << "This only works for DEMAND (HB3A) or WAND (HB2C)";
72 } else if (inputWS->getDimension(2)->getNBins() != inputWS->getExperimentInfo(0)->run().getNumGoniometers()) {
73 inputWSmsg << "goniometers not set correctly, did you run SetGoniometer "
74 "with Average=False";
75 } else {
76 std::string instrument = inputWS->getExperimentInfo(0)->getInstrument()->getName();
77 const auto run = inputWS->getExperimentInfo(0)->run();
78 size_t number_of_runs = inputWS->getDimension(2)->getNBins();
79 std::vector<std::string> logs;
80 if (instrument == "HB3A")
81 logs = {"monitor", "time"};
82 else
83 logs = {"duration", "monitor_count"};
84 for (auto log : logs) {
85 if (run.hasProperty(log)) {
86 if (static_cast<size_t>(run.getLogData(log)->size()) != number_of_runs)
87 inputWSmsg << "Log " << log << " has incorrect length, ";
88 } else {
89 inputWSmsg << "Missing required log " << log << ", ";
90 }
91 }
92 }
93 if (!inputWSmsg.str().empty())
94 result["InputWorkspace"] = inputWSmsg.str();
95
96 std::vector<double> minVals = this->getProperty("MinValues");
97 std::vector<double> maxVals = this->getProperty("MaxValues");
98
99 if (minVals.size() != 3 || maxVals.size() != 3) {
100 std::stringstream msg;
101 msg << "Must provide 3 values, 1 for every dimension";
102 result["MinValues"] = msg.str();
103 result["MaxValues"] = msg.str();
104 } else {
105 std::stringstream msg;
106
107 size_t rank = minVals.size();
108 for (size_t i = 0; i < rank; ++i) {
109 if (minVals[i] >= maxVals[i]) {
110 if (msg.str().empty())
111 msg << "max not bigger than min ";
112 else
113 msg << ", ";
114 msg << "at index=" << (i + 1) << " (" << minVals[i] << ">=" << maxVals[i] << ")";
115 }
116 }
117
118 if (!msg.str().empty()) {
119 result["MinValues"] = msg.str();
120 result["MaxValues"] = msg.str();
121 }
122 }
123
124 return result;
125}
126
127//----------------------------------------------------------------------------------------------
131
132 declareProperty(std::make_unique<WorkspaceProperty<API::IMDHistoWorkspace>>("InputWorkspace", "", Direction::Input),
133 "An input workspace.");
135 std::make_unique<PropertyWithValue<double>>(
136 "Wavelength", DBL_MAX, std::make_shared<BoundedValidator<double>>(0.0, 100.0, true), Direction::Input),
137 "Wavelength");
138 declareProperty(std::make_unique<PropertyWithValue<bool>>("LorentzCorrection", false, Direction::Input),
139 "Correct the weights of events or signals and errors transformed into "
140 "reciprocal space by multiplying them "
141 "by the Lorentz multiplier:\n :math:`sin(2\\theta)cos(\\phi)/\\lambda^3`");
142 declareProperty(std::make_unique<ArrayProperty<double>>("MinValues", "-10,-10,-10"),
143 "It has to be 3 comma separated values, one for each dimension in "
144 "q_sample."
145 "Values smaller then specified here will not be added to "
146 "workspace.");
147 declareProperty(std::make_unique<ArrayProperty<double>>("MaxValues", "10,10,10"),
148 "A list of the same size and the same units as MinValues "
149 "list. Values higher or equal to the specified by "
150 "this list will be ignored");
151 // Box controller properties. These are the defaults
152 this->initBoxControllerProps("5" /*SplitInto*/, 1000 /*SplitThreshold*/, 20 /*MaxRecursionDepth*/);
153 declareProperty(std::make_unique<PropertyWithValue<double>>("ObliquityParallaxCoefficient", 1.0, Direction::Input),
154 "Geometrical correction for shift in vertical beam position due to wide beam.");
155 declareProperty(std::make_unique<WorkspaceProperty<API::IMDEventWorkspace>>("OutputWorkspace", "", Direction::Output),
156 "An output workspace.");
157}
158
159//----------------------------------------------------------------------------------------------
163 double wavelength = this->getProperty("Wavelength");
164 bool lorentz = getProperty("LorentzCorrection");
165
166 API::IMDHistoWorkspace_sptr inputWS = this->getProperty("InputWorkspace");
167 auto &expInfo = *(inputWS->getExperimentInfo(static_cast<uint16_t>(0)));
168 std::string instrument = expInfo.getInstrument()->getName();
169
170 std::vector<double> twotheta, azimuthal;
171 std::vector<int> detectorID; // detector ID for each (twotheta, azimuthal), most useful when detector grouping done
172 if (instrument == "HB3A" && !expInfo.run().hasProperty("azimuthal")) { // HB3A Load MD
173 const auto &di = expInfo.detectorInfo();
174 for (size_t x = 0; x < 512; x++) {
175 for (size_t y = 0; y < 512 * 3; y++) {
176 size_t n = x + y * 512;
177 if (!di.isMonitor(n)) {
178 twotheta.push_back(di.twoTheta(n));
179 azimuthal.push_back(di.azimuthal(n));
180 detectorID.push_back(static_cast<int>(1 + n)); // detector ID's start at 1 in HB3A
181 }
182 }
183 }
184 } else { // HB2C LoadWAND or HB3A HB3AAdjustSampleNorm
185 azimuthal = (*(dynamic_cast<Kernel::PropertyWithValue<std::vector<double>> *>(expInfo.getLog("azimuthal"))))();
186 twotheta = (*(dynamic_cast<Kernel::PropertyWithValue<std::vector<double>> *>(expInfo.getLog("twotheta"))))();
187 if (expInfo.run().hasProperty("detectorID")) {
188 detectorID = (*(dynamic_cast<Kernel::PropertyWithValue<std::vector<int>> *>(expInfo.getLog("detectorID"))))();
189 } else {
190 // backwards compatibility if sample-log is not present
191 detectorID.assign(azimuthal.size(), 0);
192 }
193 }
194
195 auto outputWS = DataObjects::MDEventFactory::CreateMDWorkspace(3, "MDEvent");
197 std::vector<double> minVals = this->getProperty("MinValues");
198 std::vector<double> maxVals = this->getProperty("MaxValues");
199 outputWS->addDimension(std::make_shared<Geometry::MDHistoDimension>(
200 "Q_sample_x", "Q_sample_x", frame, static_cast<coord_t>(minVals[0]), static_cast<coord_t>(maxVals[0]), 1));
201
202 outputWS->addDimension(std::make_shared<Geometry::MDHistoDimension>(
203 "Q_sample_y", "Q_sample_y", frame, static_cast<coord_t>(minVals[1]), static_cast<coord_t>(maxVals[1]), 1));
204
205 outputWS->addDimension(std::make_shared<Geometry::MDHistoDimension>(
206 "Q_sample_z", "Q_sample_z", frame, static_cast<coord_t>(minVals[2]), static_cast<coord_t>(maxVals[2]), 1));
207 outputWS->setCoordinateSystem(Mantid::Kernel::QSample);
208 outputWS->initialize();
209
210 BoxController_sptr bc = outputWS->getBoxController();
211 this->setBoxController(bc);
212 outputWS->splitBox();
213
214 auto mdws_mdevt_3 = std::dynamic_pointer_cast<MDEventWorkspace<MDEvent<3>, 3>>(outputWS);
215 MDEventInserter<MDEventWorkspace<MDEvent<3>, 3>::sptr> inserter(mdws_mdevt_3);
216
217 double cop = this->getProperty("ObliquityParallaxCoefficient");
218 float coeff = static_cast<float>(cop);
219
220 float k = boost::math::float_constants::two_pi / static_cast<float>(wavelength);
221 float inv_wl_cube = static_cast<float>(1 / (wavelength * wavelength * wavelength));
222 // check convention to determine the sign of k
223 std::string convention = Kernel::ConfigService::Instance().getString("Q.convention");
224 if (convention == "Crystallography") {
225 k *= -1.f;
226 }
227 std::vector<Eigen::Vector3f> q_lab_pre;
228 std::vector<float> lorentz_pre;
229 q_lab_pre.reserve(azimuthal.size());
230 lorentz_pre.reserve(azimuthal.size());
231 for (size_t m = 0; m < azimuthal.size(); ++m) {
232 auto twotheta_f = static_cast<float>(twotheta[m]);
233 auto azimuthal_f = static_cast<float>(azimuthal[m]);
234 q_lab_pre.push_back({-std::sin(twotheta_f) * std::cos(azimuthal_f) * k,
235 -std::sin(twotheta_f) * std::sin(azimuthal_f) * k * coeff, (1.f - std::cos(twotheta_f)) * k});
236 lorentz_pre.push_back(std::abs(std::sin(twotheta_f) * std::cos(azimuthal_f)) * inv_wl_cube);
237 }
238 float factor = 1;
239 const auto run = inputWS->getExperimentInfo(0)->run();
240 for (size_t n = 0; n < inputWS->getDimension(2)->getNBins(); n++) {
241 auto gon = run.getGoniometerMatrix(n);
242 Eigen::Matrix3f goniometer;
243 for (int i = 0; i < 3; i++)
244 for (int j = 0; j < 3; j++)
245 goniometer(i, j) = static_cast<float>(gon[i][j]);
246 goniometer = goniometer.inverse().eval();
247 auto goniometerIndex = static_cast<uint16_t>(n);
248 for (size_t m = 0; m < azimuthal.size(); m++) {
249 size_t idx = n * azimuthal.size() + m;
250 coord_t signal = static_cast<coord_t>(inputWS->getSignalAt(idx));
251 if (signal > 0.f && std::isfinite(signal)) {
252 Eigen::Vector3f q_sample = goniometer * q_lab_pre[m];
253 if (lorentz) {
254 factor = lorentz_pre[m];
255 }
256 inserter.insertMDEvent(signal * factor, signal * factor * factor, 0, goniometerIndex, detectorID[m],
257 q_sample.data());
258 }
259 }
260 }
261
262 auto *ts = new ThreadSchedulerFIFO();
263 ThreadPool tp(ts);
264 outputWS->splitAllIfNeeded(ts);
265 tp.joinAll();
266
267 outputWS->refreshCache();
268 outputWS->copyExperimentInfos(*inputWS);
269 auto &outRun = outputWS->getExperimentInfo(0)->mutableRun();
270 if (outRun.hasProperty("wavelength")) {
271 outRun.removeLogData("wavelength");
272 }
273 outRun.addLogData(new PropertyWithValue<double>("wavelength", wavelength));
274 outRun.getProperty("wavelength")->setUnits("Angstrom");
275
276 auto user_convention = Kernel::ConfigService::Instance().getString("Q.convention");
277 auto ws_convention = outputWS->getConvention();
278 if (user_convention != ws_convention) {
279 auto convention_alg = createChildAlgorithm("ChangeQConvention");
280 convention_alg->setProperty("InputWorkspace", outputWS);
281 convention_alg->executeAsChildAlg();
282 }
283 setProperty("OutputWorkspace", outputWS);
284}
285
286} // namespace Mantid::MDAlgorithms
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:542
static std::unique_ptr< QThreadPool > tp
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.
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 setBoxController(const Mantid::API::BoxController_sptr &bc, const Mantid::Geometry::Instrument_const_sptr &instrument)
Set the settings in the given box controller.
void initBoxControllerProps(const std::string &SplitInto="5", int SplitThreshold=1000, int MaxRecursionDepth=5)
Initialise the properties.
A property class for workspaces.
static API::IMDEventWorkspace_sptr CreateMDWorkspace(size_t nd, const std::string &eventType="MDLeanEvent", const Mantid::API::MDNormalization &preferredNormalization=Mantid::API::MDNormalization::VolumeNormalization, const Mantid::API::MDNormalization &preferredNormalizationHisto=Mantid::API::MDNormalization::VolumeNormalization)
Create a MDEventWorkspace of the given type.
MDEventInserter : Helper class that provides a generic interface for adding events to an MDWorkspace ...
QSample : Q in the sample frame.
Definition QSample.h:20
Support for a property that holds an array of values.
BoundedValidator is a validator that requires the values to be between upper or lower bounds,...
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
The concrete, templated class for properties.
A Thread Pool implementation that keeps a certain number of threads running (normally,...
Definition ThreadPool.h:36
A First-In-First-Out Thread Scheduler.
ConvertHFIRSCDtoMDE : TODO: DESCRIPTION.
int version() const override
Algorithm's version for identification.
const std::string summary() const override
Algorithm's summary for use in the GUI and help.
void exec() override
Execute the algorithm.
const std::string category() const override
Algorithm's category for identification.
void init() override
Initialize the algorithm's properties.
std::map< std::string, std::string > validateInputs() override
Perform validation of ALL the input properties of the algorithm.
std::shared_ptr< IMDHistoWorkspace > IMDHistoWorkspace_sptr
shared pointer to Mantid::API::IMDHistoWorkspace
std::shared_ptr< BoxController > BoxController_sptr
Shared ptr to BoxController.
float coord_t
Typedef for the data type to use for coordinate axes in MD objects such as MDBox, MDEventWorkspace,...
Definition MDTypes.h:27
STL namespace.
Describes the direction (within an algorithm) of a Property.
Definition Property.h:50
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54