Mantid
Loading...
Searching...
No Matches
ConvertToMDMinMaxGlobal.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
11#include "MantidAPI/Run.h"
12#include "MantidAPI/Sample.h"
24
25#include <tuple>
26
27using namespace Mantid;
28using namespace Mantid::Kernel;
29using namespace Mantid::API;
30using namespace Mantid::DataObjects;
31
32namespace Mantid::MDAlgorithms {
33
34// Register the algorithm into the AlgorithmFactory
35DECLARE_ALGORITHM(ConvertToMDMinMaxGlobal)
36
37
38const std::string ConvertToMDMinMaxGlobal::name() const { return "ConvertToMDMinMaxGlobal"; }
39
41int ConvertToMDMinMaxGlobal::version() const { return 1; }
42
44const std::string ConvertToMDMinMaxGlobal::category() const { return "MDAlgorithms\\Creation"; }
45
49 auto ws_valid = std::make_shared<CompositeValidator>();
50 ws_valid->add<InstrumentValidator>();
51 // the validator which checks if the workspace has axis and any units
52 ws_valid->add<WorkspaceUnitValidator>("");
53 // histogram needed by ConvertUnits
54 ws_valid->add<HistogramValidator>();
56 std::make_unique<WorkspaceProperty<MatrixWorkspace>>("InputWorkspace", "", Direction::Input, ws_valid),
57 "An input Matrix Workspace (Workspace2D or Event workspace) ");
58
59 std::vector<std::string> Q_modes = MDAlgorithms::MDTransfFactory::Instance().getKeys();
60 // something to do with different moments of time when algorithm or test loads
61 // library. To avoid empty factory always do this.
62 if (Q_modes.empty())
63 Q_modes.assign(1, "ERROR IN LOADING Q-converters");
64
66 declareProperty("QDimensions", Q_modes[0], std::make_shared<StringListValidator>(Q_modes),
67 "String, describing MD-analysis modes, this algorithm can process. "
68 "There are 3 modes currently available and described in details on"
69 "*MD Transformation factory* page. "
70 "The modes names are **CopyToMD**, **|Q|** and **Q3D**",
73 std::vector<std::string> dE_modes = Kernel::DeltaEMode::availableTypes();
74 declareProperty("dEAnalysisMode", dE_modes[Kernel::DeltaEMode::Direct],
75 std::make_shared<StringListValidator>(dE_modes),
76 "You can analyze neutron energy transfer in **Direct**, "
77 "**Indirect** or **Elastic** mode. "
78 "The analysis mode has to correspond to experimental set up. "
79 "Selecting inelastic mode increases "
80 "the number of the target workspace dimensions by one. See "
81 "*MD Transformation factory* for further details.",
83
84 setPropertySettings("dEAnalysisMode",
85 std::make_unique<VisibleWhenProperty>("QDimensions", IS_NOT_EQUAL_TO, "CopyToMD"));
86
87 std::vector<std::string> TargFrames{"AutoSelect", "Q", "HKL"};
88 declareProperty("Q3DFrames", "AutoSelect", std::make_shared<StringListValidator>(TargFrames),
89 "What will be the Q-dimensions of the output workspace in **Q3D** case?"
90 " **AutoSelect**: **Q** by default, **HKL** if sample has a UB matrix."
91 " **Q** - momentum in inverse angstroms. Can be used for both "
92 "laboratory or sample frame."
93 " **HKL** - reciprocal lattice units");
94
95 setPropertySettings("Q3DFrames", std::make_unique<VisibleWhenProperty>("QDimensions", IS_EQUAL_TO, "Q3D"));
96
97 declareProperty(std::make_unique<ArrayProperty<std::string>>("OtherDimensions", Direction::Input),
98 "List(comma separated) of additional to **Q** and **DeltaE** variables "
99 "which form additional "
100 "(orthogonal) to **Q** dimensions in the target workspace (e.g. "
101 "Temperature or Magnetic field). "
102 "These variables had to be logged during experiment and the names of "
103 "these variables have to coincide "
104 "with the log names for the records of these variables in the source "
105 "workspace.");
106
107 declareProperty(std::make_unique<ArrayProperty<double>>("MinValues", Direction::Output));
108 declareProperty(std::make_unique<ArrayProperty<double>>("MaxValues", Direction::Output));
109}
110
111//----------------------------------------------------------------------------------------------
115 std::vector<double> MinValues, MaxValues;
116 std::string QDimension = getPropertyValue("QDimensions");
117 std::string GeometryMode = getPropertyValue("dEAnalysisMode");
118 std::string Q3DFrames = getPropertyValue("Q3DFrames");
119 std::vector<std::string> OtherDimensions = getProperty("OtherDimensions");
120
121 MatrixWorkspace_sptr ws = getProperty("InputWorkspace"), wstemp;
123
124 if (QDimension == "CopyToMD") {
125 const auto [xmin, xmax] = ws->getXMinMax();
126 MinValues.emplace_back(xmin);
127 MaxValues.emplace_back(xmax);
128 } else // need to calculate the appropriate q values
129 {
130 double qmax, deltaEmax, deltaEmin;
131 auto conv = createChildAlgorithm("ConvertUnits", 0.0, 0.9);
132 conv->setProperty<MatrixWorkspace_sptr>("InputWorkspace", ws);
133 conv->setProperty<MatrixWorkspace_sptr>("OutputWorkspace", wstemp);
134 // Calculate maxumum momentum transfer Q
135 if (GeometryMode == "Elastic") {
136 conv->setProperty("Target", "Momentum");
137 conv->setProperty("Emode", "Elastic");
138 conv->executeAsChildAlg();
139
140 wstemp = conv->getProperty("OutputWorkspace");
141 evWS = std::dynamic_pointer_cast<Mantid::DataObjects::EventWorkspace>(wstemp);
142 if (evWS)
143 qmax = evWS->getTofMax() * 2; // assumes maximum scattering angle 180 degrees
144 else
145 qmax = wstemp->getXMax() * 2.; // assumes maximum scattering angle 180 degrees
146 } else // inelastic
147 {
148 conv->setProperty("Target", "DeltaE");
149 conv->setProperty("Emode", GeometryMode);
150 conv->executeAsChildAlg();
151 wstemp = conv->getProperty("OutputWorkspace");
152 evWS = std::dynamic_pointer_cast<Mantid::DataObjects::EventWorkspace>(wstemp);
153 if (evWS) {
154 deltaEmin = evWS->getTofMin();
155 deltaEmax = evWS->getTofMax();
156 } else {
157 std::tie(deltaEmin, deltaEmax) = wstemp->getXMinMax();
158 }
159
160 // Deal with nonphysical energies - conversion to DeltaE yields +-DBL_MAX
161 if (deltaEmin < -DBL_MAX / 2)
162 deltaEmin = -deltaEmax;
163 if (deltaEmax > DBL_MAX / 2)
164 deltaEmax = -deltaEmin;
165
166 // Conversion constant for E->k. k(A^-1) = sqrt(energyToK*E(meV))
167 const double energyToK = 8.0 * M_PI * M_PI * PhysicalConstants::NeutronMass * PhysicalConstants::meV * 1e-20 /
169 if (GeometryMode == "Direct") {
170 const auto Ei = ws->run().getPropertyValueAsType<double>("Ei");
171 qmax = std::sqrt(energyToK * Ei) + std::sqrt(energyToK * (Ei - deltaEmin));
172 } else // indirect
173 {
174 double Ef = -DBL_MAX, Eftemp = Ef;
175 const auto &pmap = ws->constInstrumentParameters();
176 const auto &specInfo = ws->spectrumInfo();
177 for (size_t i = 0; i < ws->getNumberHistograms(); i++) {
178 if (!specInfo.hasDetectors(i))
179 continue;
180 const auto &det = specInfo.detector(i);
181 const auto &par = pmap.getRecursive(det.getComponentID(), "eFixed");
182 Eftemp = (par) ? par->value<double>() : Eftemp;
183 Ef = (Eftemp > Ef) ? Eftemp : Ef;
184 if (Ef <= 0)
185 throw std::runtime_error("Could not find a fixed final energy for "
186 "indirect geometry instrument.");
187 }
188 qmax = std::sqrt(energyToK * Ef) + std::sqrt(energyToK * (Ef + deltaEmax));
189 }
190 }
191 // Calculate limits from qmax
192 if (QDimension == "|Q|") {
193 MinValues.emplace_back(0.);
194 MaxValues.emplace_back(qmax);
195 } else // Q3D
196 {
197 // Q in angstroms
198 if ((Q3DFrames == "Q") || ((Q3DFrames == "AutoSelect") && (!ws->sample().hasOrientedLattice()))) {
199 MinValues.emplace_back(-qmax);
200 MinValues.emplace_back(-qmax);
201 MinValues.emplace_back(-qmax);
202 MaxValues.emplace_back(qmax);
203 MaxValues.emplace_back(qmax);
204 MaxValues.emplace_back(qmax);
205 } else // HKL
206 {
207 if (!ws->sample().hasOrientedLattice()) {
208 g_log.error() << "Sample has no oriented lattice\n";
209 throw std::invalid_argument("No UB set");
210 }
211 Mantid::Geometry::OrientedLattice ol = ws->sample().getOrientedLattice();
212 qmax /= (2. * M_PI);
213 MinValues.emplace_back(-qmax * ol.a());
214 MinValues.emplace_back(-qmax * ol.b());
215 MinValues.emplace_back(-qmax * ol.c());
216 MaxValues.emplace_back(qmax * ol.a());
217 MaxValues.emplace_back(qmax * ol.b());
218 MaxValues.emplace_back(qmax * ol.c());
219 }
220 }
221
222 // Push deltaE if necessary
223 if (GeometryMode != "Elastic") {
224 MinValues.emplace_back(deltaEmin);
225 MaxValues.emplace_back(deltaEmax);
226 }
227 }
228
229 for (auto &OtherDimension : OtherDimensions) {
230 if (!ws->run().hasProperty(OtherDimension)) {
231 g_log.error() << "The workspace does not have a property " << OtherDimension << '\n';
232 throw std::invalid_argument("Property not found. Please see error log.");
233 }
234 Kernel::Property *pProperty = (ws->run().getProperty(OtherDimension));
235 auto *p = dynamic_cast<TimeSeriesProperty<double> *>(pProperty);
236 if (p) {
237 MinValues.emplace_back(p->getStatistics().minimum);
238 MaxValues.emplace_back(p->getStatistics().maximum);
239 } else // it may be not a time series property but just number property
240 {
241 auto *property = dynamic_cast<Kernel::PropertyWithValue<double> *>(pProperty);
242 if (!property) {
243 std::string ERR = " Can not interpret property, used as dimension.\n Property: " + OtherDimension +
244 " is neither a time series (run) property nor "
245 "a property with value<double>";
246 throw(std::invalid_argument(ERR));
247 }
248 double val = *property;
249 MinValues.emplace_back(val);
250 MaxValues.emplace_back(val);
251 }
252 }
253
254 setProperty("MinValues", MinValues);
255 setProperty("MaxValues", MaxValues);
256}
257
258} // namespace Mantid::MDAlgorithms
std::string name
Definition Run.cpp:60
#define DECLARE_ALGORITHM(classname)
Definition Algorithm.h:547
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.
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.
Kernel::Logger & g_log
Definition Algorithm.h:426
A validator which checks that a workspace contains histogram data (the default) or point data as requ...
A validator which checks that a workspace has a valid instrument.
A property class for workspaces.
A validator which checks that the unit of the workspace referred to by a WorkspaceProperty is the exp...
Class to implement UB matrix.
double a(int nd) const
Get lattice parameter a1-a3 as function of index (0-2)
Definition UnitCell.cpp:94
double c() const
Get lattice parameter.
Definition UnitCell.cpp:128
double b() const
Get lattice parameter.
Definition UnitCell.cpp:123
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings const > settings)
Add a PropertySettings instance to the chain of settings for a given property.
void error(const std::string &msg)
Logs at error level.
Definition Logger.cpp:108
The concrete, templated class for properties.
Base class for properties.
Definition Property.h:95
A specialised Property class for holding a series of time-value pairs.
ConvertToMDMinMaxGlobal : Algorithm to calculate limits for ConvertToMD transformation which can be o...
void init() override
Initialize the algorithm's properties.
const std::string category() const override
Algorithm's category for identification.
int version() const override
Algorithm's version for identification.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< EventWorkspace > EventWorkspace_sptr
shared pointer to the EventWorkspace class
static constexpr double NeutronMass
Mass of the neutron in kg.
static constexpr double h
Planck constant in J*s.
static constexpr double meV
1 meV in Joules.
Helper class which provides the Collimation Length for SANS instruments.
Generate a tableworkspace to store the calibration results.
STL namespace.
static const std::vector< std::string > availableTypes()
Returns the string list of available modes.
@ InOut
Both an input & output workspace.
Definition Property.h:56
@ Input
An input workspace.
Definition Property.h:54
@ Output
An output workspace.
Definition Property.h:55