Mantid
Loading...
Searching...
No Matches
SetGoniometer.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/Run.h"
15
16#include <boost/algorithm/string/classification.hpp>
17#include <boost/algorithm/string/split.hpp>
18
20using namespace Mantid::Geometry;
21
22namespace Mantid::Crystal {
23
24// Register the algorithm into the AlgorithmFactory
25DECLARE_ALGORITHM(SetGoniometer)
26
27using namespace Mantid::Kernel;
28using namespace Mantid::API;
29
31const size_t NUM_AXES = 6;
32
36 declareProperty(std::make_unique<WorkspaceProperty<Workspace>>("Workspace", "", Direction::InOut),
37 "An workspace that will be modified with the new goniometer created.");
38
39 std::vector<std::string> gonOptions{"None, Specify Individually", "Universal"};
40 declareProperty("Goniometers", gonOptions[0], std::make_shared<StringListValidator>(gonOptions),
41 "Set the axes and motor names according to goniometers that "
42 "we define in the code (Universal defined for SNS)");
43
44 std::string axisHelp = ": name, x,y,z, 1/-1 (1 for ccw, -1 for cw rotation). "
45 "A number of degrees can be used instead of name. "
46 "Leave blank for no axis";
47 for (size_t i = 0; i < NUM_AXES; i++) {
48 std::ostringstream propName;
49 propName << "Axis" << i;
50 declareProperty(std::make_unique<PropertyWithValue<std::string>>(propName.str(), "", Direction::Input),
51 propName.str() + axisHelp);
52 }
53 declareProperty("Average", true,
54 "Use the average value of the log, if false a separate "
55 "goniometer will be created for each value in the logs");
56}
57
61 Workspace_sptr ws = getProperty("Workspace");
62 auto ei = std::dynamic_pointer_cast<ExperimentInfo>(ws);
63
64 if (!ei) {
65 // We're dealing with an MD workspace which has multiple experiment infos
66 auto infos = std::dynamic_pointer_cast<MultipleExperimentInfos>(ws);
67 if (!infos) {
68 throw std::invalid_argument("Input workspace does not support Goniometer");
69 }
70 if (infos->getNumExperimentInfo() < 1) {
72 infos->addExperimentInfo(info);
73 }
74 ei = infos->getExperimentInfo(0);
75 }
76
77 std::string gonioDefined = getPropertyValue("Goniometers");
78 // Create the goniometer
79 Goniometer gon;
80
81 if (gonioDefined == "Universal")
83 else
84 for (size_t i = 0; i < NUM_AXES; i++) {
85 std::ostringstream propName;
86 propName << "Axis" << i;
87 std::string axisDesc = getPropertyValue(propName.str());
88
89 if (!axisDesc.empty()) {
90 std::vector<std::string> tokens;
91 boost::split(tokens, axisDesc, boost::algorithm::detail::is_any_ofF<char>(","));
92 if (tokens.size() != 5)
93 throw std::invalid_argument("Wrong number of arguments to parameter " + propName.str() +
94 ". Expected 5 comma-separated arguments.");
95
96 std::string axisName = tokens[0];
97 axisName = Strings::strip(axisName);
98 if (axisName.empty())
99 throw std::invalid_argument("The name must not be empty");
100
101 // If axisName is a number, add a new log value
102 double angle = 0;
103 if (Strings::convert(axisName, angle)) {
104 g_log.information() << "Axis " << i << " - create a new log value GoniometerAxis" << i << "_FixedValue\n";
105 axisName = "GoniometerAxis" + Strings::toString(i) + "_FixedValue";
106 try {
107 Types::Core::DateAndTime now = Types::Core::DateAndTime::getCurrentTime();
108 auto tsp = new Kernel::TimeSeriesProperty<double>(axisName);
109 tsp->addValue(now, angle);
110 tsp->setUnits("degree");
111 if (ei->mutableRun().hasProperty(axisName)) {
112 ei->mutableRun().removeLogData(axisName);
113 }
114 ei->mutableRun().addLogData(tsp);
115 } catch (...) {
116 g_log.error("Could not add axis");
117 }
118 }
119
120 double x = 0, y = 0, z = 0;
121 if (!Strings::convert(tokens[1], x))
122 throw std::invalid_argument("Error converting string '" + tokens[1] + "' to a number.");
123 if (!Strings::convert(tokens[2], y))
124 throw std::invalid_argument("Error converting string '" + tokens[2] + "' to a number.");
125 if (!Strings::convert(tokens[3], z))
126 throw std::invalid_argument("Error converting string '" + tokens[3] + "' to a number.");
127 V3D vec(x, y, z);
128 if (vec.norm() < 1e-4)
129 throw std::invalid_argument("Rotation axis vector should be non-zero!");
130
131 int ccw = 0;
132 Strings::convert(tokens[4], ccw);
133 if (ccw != 1 && ccw != -1)
134 throw std::invalid_argument("The ccw parameter must be 1 (ccw) or -1 "
135 "(cw) but no other value.");
136 // Default to degrees
137 gon.pushAxis(axisName, x, y, z, 0.0, ccw);
138 }
139 }
140
141 if (gon.getNumberAxes() == 0)
142 g_log.warning() << "Empty goniometer created; will always return an "
143 "identity rotation matrix.\n";
144
145 // All went well, copy the goniometer into it. It will throw if the log values
146 // cannot be found
147 try {
148 if (getProperty("Average"))
149 ei->mutableRun().setGoniometer(gon, true);
150 else
151 ei->mutableRun().setGoniometers(gon);
152 } catch (std::runtime_error &) {
153 g_log.error("No log values for goniometers");
154 }
155}
156
157} // namespace Mantid::Crystal
#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
Kernel::Logger & g_log
Definition: Algorithm.h:451
This class is shared by a few Workspace types and holds information related to a particular experimen...
A property class for workspaces.
void init() override
Initialise the properties.
void exec() override
Run the algorithm.
Class to represent a particular goniometer setting, which is described by the rotation matrix.
Definition: Goniometer.h:55
void makeUniversalGoniometer()
Make a default universal goniometer with phi,chi,omega angles according to SNS convention.
Definition: Goniometer.cpp:271
void pushAxis(const std::string &name, double axisx, double axisy, double axisz, double angle=0., int sense=CCW, int angUnit=angDegrees)
Add an additional axis to the goniometer, closer to the sample.
Definition: Goniometer.cpp:133
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
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.
A specialised Property class for holding a series of time-value pairs.
Class for 3D vectors.
Definition: V3D.h:34
double norm() const noexcept
Definition: V3D.h:263
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Definition: Workspace_fwd.h:20
std::shared_ptr< ExperimentInfo > ExperimentInfo_sptr
Shared pointer to ExperimentInfo.
const size_t NUM_AXES
How many axes (max) to define.
MANTID_KERNEL_DLL std::string strip(const std::string &A)
strip pre/post spaces
Definition: Strings.cpp:397
int convert(const std::string &A, T &out)
Convert a string into a number.
Definition: Strings.cpp:665
std::string toString(const T &value)
Convert a number to a string.
Definition: Strings.cpp:703
@ InOut
Both an input & output workspace.
Definition: Property.h:55
@ Input
An input workspace.
Definition: Property.h:53