Mantid
Loading...
Searching...
No Matches
ApplyDetailedBalanceMD.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 +
10// #include "MantidAPI/IMDEventWorkspace.h"
14#include "MantidAPI/Run.h"
23#include <cmath>
24
25using namespace Mantid::Kernel;
26using namespace Mantid::API;
27using namespace Mantid::Geometry;
28using namespace Mantid::DataObjects;
29
30namespace Mantid::MDAlgorithms {
31
32// Register the algorithm into the AlgorithmFactory
33DECLARE_ALGORITHM(ApplyDetailedBalanceMD)
34
35
36const std::string ApplyDetailedBalanceMD::name() const { return "ApplyDetailedBalanceMD"; }
37
39int ApplyDetailedBalanceMD::version() const { return 1; }
40
42const std::string ApplyDetailedBalanceMD::summary() const { return "Apply detailed balance to MDEventWorkspace"; }
43
45const std::string ApplyDetailedBalanceMD::category() const { return "MDAlgorithms"; }
46
47//---------------------------------------------------------------------------------------------------------
52
54 std::make_unique<WorkspaceProperty<API::IMDEventWorkspace>>("InputWorkspace", "", Kernel::Direction::Input),
55 "An input MDEventWorkspace. Must be in Q_sample/Q_lab frame. Must have an axis as DeltaE");
56
57 declareProperty(std::make_unique<PropertyWithValue<std::string>>("Temperature", "", Direction::Input),
58 "SampleLog variable name that contains the temperature or a number");
59
60 auto mustBePositive = std::make_shared<BoundedValidator<double>>();
61 mustBePositive->setLower(0.0);
62 mustBePositive->setLowerExclusive(true);
63 declareProperty(std::make_unique<PropertyWithValue<double>>("RescaleToTemperature", EMPTY_DBL(), mustBePositive,
65 "The temperature to which to rescale the intensity");
66
68 std::make_unique<WorkspaceProperty<API::IMDEventWorkspace>>("OutputWorkspace", "", Kernel::Direction::Output),
69 "The output MDEventWorkspace with detailed balance applied");
70}
71
72//---------------------------------------------------------------------------------------------------------
77 // Get input workspace
78 API::IMDEventWorkspace_sptr input_ws = getProperty("InputWorkspace");
79
80 // Get temperature to convert to
81 mFinalTemperature = getProperty("RescaleToTemperature");
82 if (mFinalTemperature > EMPTY_DBL() / 2) {
83 mFinalTemperature = -10.; // set to an unphysical value
84 }
85
86 // Process input workspace and create output workspace
87 std::string output_ws_name = getPropertyValue("OutputWorkspace");
88
89 API::IMDEventWorkspace_sptr output_ws(0);
90 if (input_ws->getName() == output_ws_name) {
91 // Calcualte in-place
92 output_ws = input_ws;
93 } else {
94 // Clone input workace to output workspace
95 output_ws = input_ws->clone();
96 }
97
98 // Apply detailed balance to MDEvents
100
101 // refresh cache for MDBoxes: set correct Box signal
102 output_ws->refreshCache();
103
104 // Clear masking (box flags) from the output workspace
105 output_ws->clearMDMasking();
106
107 // Set output
108 setProperty("OutputWorkspace", output_ws);
109}
110
111//---------------------------------------------------------------------------------------------------------
122std::map<std::string, std::string> ApplyDetailedBalanceMD::validateInputs() {
123 std::map<std::string, std::string> output;
124
125 // Get input workspace
126 API::IMDEventWorkspace_sptr input_ws = getProperty("InputWorkspace");
127
128 // check input dimension
129 std::string dim_error = checkInputMDDimension();
130 if (dim_error != "") {
131 output["InputWorkspace"] = dim_error;
132 }
133
134 std::string kerror = getTemperature(input_ws);
135 if (kerror != "")
136 output["Temperature"] = kerror;
137
138 return output;
139}
140
141//---------------------------------------------------------------------------------------------------------
149 std::string errormsg("");
150
151 API::IMDEventWorkspace_sptr inputws = getProperty("InputWorkspace");
152 size_t numdims = inputws->getNumDims();
153
154 // Get and check the dimensions: Q3D or Q1D
155 const Mantid::Kernel::SpecialCoordinateSystem coordsys = inputws->getSpecialCoordinateSystem();
156 size_t qdim(0);
157 std::string qdimstr("Not Q3D or |Q|");
160 // q3d
161 qdim = 3;
162 qdimstr = "Q3D";
163 } else {
164 // search Q1D: at any place
165 for (size_t i = 0; i < numdims; ++i) {
166 if (inputws->getDimension(i)->getName() == "|Q|") {
167 qdim = 1;
168 qdimstr = "|Q|";
169 break;
170 }
171 }
172 }
173
174 // Check DeltaE
175 if (qdim == 1 && inputws->getDimension(1)->getName() == "DeltaE") {
176 // 2nd dimension is DeltaE
177 mDeltaEIndex = 1;
178 } else if (qdim == 3 && inputws->getDimension(3)->getName() == "DeltaE") {
179 // 4th dimension is DeltaE
180 mDeltaEIndex = 3;
181 } else {
182 // Error
183 g_log.error() << "Coordiate system = " << coordsys << " does not meet requirement: \n";
184 for (size_t i = 0; i < numdims; ++i) {
185 g_log.error() << i << "-th dim: " << inputws->getDimension(i)->getName() << "\n";
186 }
187 errormsg += "Q Dimension (" + qdimstr +
188 ") is neither Q3D nor |Q|. Or DeltaE is found in proper place (2nd or 4th dimension).";
189 }
190
191 return errormsg;
192}
193
194//---------------------------------------------------------------------------------------------
198template <typename MDE, size_t nd>
200 // Get Box from MDEventWorkspace
201 MDBoxBase<MDE, nd> *box1 = ws->getBox();
202 std::vector<API::IMDNode *> boxes;
203 box1->getBoxes(boxes, 1000, true);
204 auto numBoxes = int(boxes.size());
205
206 // Add the boxes in parallel. They should be spread out enough on each
207 // core to avoid stepping on each other.
208
209 PRAGMA_OMP( parallel for if (!ws->isFileBacked()))
210 for (int i = 0; i < numBoxes; ++i) {
212 auto *box = dynamic_cast<MDBox<MDE, nd> *>(boxes[i]);
213 if (box && !box->getIsMasked()) {
214 // get the MEEvents from box
215 std::vector<MDE> &events = box->getEvents();
216 // Add events, with bounds checking
217 for (auto it = events.begin(); it != events.end(); ++it) {
218 // Create the event
219 // do calculattion
220 float temperature(static_cast<float>(mExpinfoTemperatureMean[it->getExpInfoIndex()]));
221 float factor;
222
223 // delta_e = it->getCenter(mDeltaEIndex);
224 // factor = pi * (1 - exp(-deltaE/(kb*T)))
225 // using expm1=e^x-1 function
226 if (mFinalTemperature < 0) { // convert to chi''
227 factor =
228 -static_cast<float>(M_PI) * std::expm1f(-static_cast<float>(it->getCenter(mDeltaEIndex)) *
229 static_cast<float>(PhysicalConstants::meVtoKelvin / temperature));
230 } else {
231 float de = static_cast<float>(it->getCenter(mDeltaEIndex));
232 if (std::fabs(de) < 1e-10) {
233 factor = static_cast<float>(mFinalTemperature) / temperature;
234 } else {
235 factor = std::expm1f(-de * static_cast<float>(PhysicalConstants::meVtoKelvin / temperature)) /
236 std::expm1f(-de * static_cast<float>(PhysicalConstants::meVtoKelvin / mFinalTemperature));
237 }
238 }
239
240 // calcalate and set intesity
241 auto intensity = it->getSignal() * factor;
242 it->setSignal(intensity);
243
244 // calculate and set error
245 auto error2 = it->getErrorSquared() * factor * factor;
246 // error2 *= factor * factor;
247 it->setErrorSquared(error2);
248 }
249 }
250 if (box) {
251 box->releaseEvents();
252 }
254 }
256
257 return;
258}
259
260//---------------------------------------------------------------------------------------------------------
267 // Get temperture sample log name
268 std::string Tstring = getProperty("Temperature");
269 std::string temperature_error("");
270
271 // Try to convert Tstring to a float
272 float temperature;
273 try {
274 temperature = boost::lexical_cast<float>(Tstring);
275 } catch (...) {
276 // set to a unphysical value
277 temperature = -10;
278 }
279
280 // the input property could be a valid float; if not must search the experiment info
282 uint16_t numexpinfo = mdws->getNumExperimentInfo();
283
284 for (uint16_t i = 0; i < numexpinfo; ++i) {
285 if (temperature < 0) {
286 // if user specified is not a valid float
287 ExperimentInfo_const_sptr expinfo = mdws->getExperimentInfo(i);
288 if (expinfo->run().hasProperty(Tstring)) {
289 auto log = dynamic_cast<Kernel::TimeSeriesProperty<double> *>(expinfo->run().getProperty(Tstring));
290 if (!log) {
291 // wrong type of sample log: must be TimeSeriesProperty<double>
292 std::stringstream errss;
293 errss << "ExperimentInfo" << i << " has " << Tstring << ", which is not a valid double-valuesd log";
294 temperature_error += errss.str() + "\n";
295 } else {
297 }
298 } else {
299 // specified sample log does not exist
300 std::stringstream errss;
301 errss << "ExperimentInfo " << i << " does not have tempertaure log " << Tstring;
302 temperature_error += errss.str() + "\n";
303 }
304 } else {
305 // set user specified temperature to map
306 mExpinfoTemperatureMean[i] = temperature;
307 }
308 }
309
310 return temperature_error;
311}
312
313} // namespace Mantid::MDAlgorithms
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:538
#define CALL_MDEVENT_FUNCTION(funcname, workspace)
Macro that makes it possible to call a templated method for a MDEventWorkspace using a IMDEventWorksp...
#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 PRAGMA_OMP(expression)
#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.
Kernel::Logger & g_log
Definition Algorithm.h:422
virtual void getBoxes(std::vector< IMDNode * > &boxes, size_t maxDepth, bool leafOnly)=0
Fill a vector with all the boxes who are the childred of this one up to a certain depth.
A property class for workspaces.
Templated super-class of a multi-dimensional event "box".
Definition MDBoxBase.h:50
Templated class for a multi-dimensional event "box".
Definition MDBox.h:45
std::vector< MDE > & getEvents()
Get vector of events to change.
Definition MDBox.hxx:243
std::shared_ptr< MDEventWorkspace< MDE, nd > > sptr
Typedef for a shared pointer of this kind of event workspace.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
The concrete, templated class for properties.
A specialised Property class for holding a series of time-value pairs.
TimeSeriesPropertyStatistics getStatistics(const Kernel::TimeROI *roi=nullptr) const override
Return a TimeSeriesPropertyStatistics object.
ApplyDetailedBalance : Convert to chi'' of an MDEvent workspace.
std::string checkInputMDDimension()
Check input workspace dimension.
std::string getTemperature(const API::IMDEventWorkspace_sptr &mdws)
Get temperature.
const std::string summary() const override
Summary.
void applyDetailedBalance(typename Mantid::DataObjects::MDEventWorkspace< MDE, nd >::sptr ws)
Apply detailed balance to each MDEvent.
double mFinalTemperature
temperature to convert to
void init() override
Initialize the proeprties.
std::map< uint16_t, double > mExpinfoTemperatureMean
map of temperature retrieved from sample logs
size_t mDeltaEIndex
index of the MD dimension index for DeltaE
const std::string category() const override
category
int version() const override
Algorithm's version for identification.
std::map< std::string, std::string > validateInputs() override
Validate inputs.
std::shared_ptr< IMDEventWorkspace > IMDEventWorkspace_sptr
Shared pointer to Mantid::API::IMDEventWorkspace.
std::shared_ptr< const ExperimentInfo > ExperimentInfo_const_sptr
Shared pointer to const ExperimentInfo.
SpecialCoordinateSystem
Special coordinate systems for Q3D.
static constexpr double meVtoKelvin
1 meV in Kelvin.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition EmptyValues.h:42
STL namespace.
@ Input
An input workspace.
Definition Property.h:53
@ Output
An output workspace.
Definition Property.h:54