12#include <boost/algorithm/string.hpp>
32 file->makeGroup(
group,
"NXmotor",
true);
33 file->writeData(
"name",
name);
34 file->writeData(
"angle",
angle);
35 file->openData(
"angle");
37 file->putAttr(
"unit", unit);
38 std::string sen = (
sense ==
CW) ?
"CW" :
"CCW";
39 file->putAttr(
"sense", sen);
46 file->openGroup(
group,
"NXmotor");
47 file->readData(
"name",
name);
48 file->readData(
"angle",
angle);
49 file->openData(
"angle");
51 file->getAttr(
"sense", s);
53 file->getAttr(
"unit", s);
71 throw std::invalid_argument(
"rot has not been evaluated to be a valid rotation matrix");
79 : m_R(other.m_R), m_motors(other.m_motors), m_initFromR(other.m_initFromR) {}
93 : m_R(std::move(other.m_R)), m_motors(std::move(other.m_motors)), m_initFromR(other.m_initFromR) {}
98 m_R = std::move(other.m_R);
99 m_motors = std::move(other.m_motors);
100 m_initFromR = other.m_initFromR;
113 m_R = std::move(rot);
130 return std::string(
"Goniometer was initialized from a rotation matrix. No "
131 "information about axis is available.\n");
133 std::stringstream info;
134 std::vector<GoniometerAxis>::iterator it;
137 info <<
"No axis is found\n";
139 info <<
"Name \t Direction \t Sense \t Angle \n";
140 std::string strCW(
"CW"), strCCW(
"CCW");
142 std::string sense = ((*it).sense ==
CCW) ? strCCW : strCW;
143 double angle = ((*it).angleunit ==
angDegrees) ? ((*it).angle) : ((*it).angle *
rad2deg);
144 info << (*it).name <<
"\t" << (*it).rotationaxis <<
"\t" << sense <<
"\t" << angle <<
'\n';
163 throw std::runtime_error(
"Initialized from a rotation matrix, so no axes can be pushed.");
165 if (!std::isfinite(axisx) || !std::isfinite(axisy) || !std::isfinite(axisz) || !std::isfinite(angle)) {
166 g_log.
warning() <<
"NaN encountered while trying to push axis to "
167 "goniometer, Operation aborted"
168 <<
"\naxis name" <<
name <<
"\naxisx" << axisx <<
"\naxisy" << axisx <<
"\naxisz" << axisz
169 <<
"\nangle" << angle;
174 std::find_if(
m_motors.cbegin(),
m_motors.cend(), [&
name](
const auto &axis) { return axis.name == name; });
176 throw std::invalid_argument(
"Motor name already defined");
189 bool changed =
false;
190 std::vector<GoniometerAxis>::iterator it;
192 if (
name == it->name) {
198 throw std::invalid_argument(
"Motor name " +
name +
" not found");
209 throw std::out_of_range(
"Goniometer::setRotationAngle(): axis number specified is too large.");
227 if (Kernel::ConfigService::Instance().getString(
"Q.convention") ==
"Crystallography")
233 Q = starting_goniometer * Q;
235 double wv = 2.0 * M_PI / wavelength;
236 double norm_q2 = Q.norm2();
237 double theta = acos(1 - norm_q2 / (2 * wv * wv));
238 double phi = asin(-Q[1] / (wv * sin(theta)));
239 V3D Q_lab(-wv * sin(theta) * cos(phi), -wv * sin(theta) * sin(phi), wv * (1 - cos(theta)));
245 starting_goniometer.
Invert();
246 Q_lab = starting_goniometer * Q_lab;
253 std::vector<double> B{Q_lab[0], Q_lab[2]};
254 std::vector<double>
X = A * B;
255 double rot = atan2(
X[1],
X[0]);
258 goniometer[0][0] = cos(rot);
259 goniometer[0][2] = sin(rot);
260 goniometer[2][0] = -sin(rot);
261 goniometer[2][2] = cos(rot);
263 starting_goniometer.
Invert();
264 setR(starting_goniometer * goniometer);
266 setR(goniometer * starting_goniometer);
281 std::find_if(
m_motors.cbegin(),
m_motors.cend(), [&axisname](
const auto &axis) { return axis.name == axisname; });
285 throw std::invalid_argument(
"Motor name " + axisname +
" not found");
319 g_log.
warning() <<
"Goniometerdoes not have 3 axes. Cannot determine "
324 std::string convention;
325 for (
const auto &motor :
m_motors) {
326 switch (std::abs(motor.rotationaxis.masterDir())) {
337 g_log.
warning() <<
"Goniometer has an axis with a non-standard "
348 g_log.
information() <<
"Goniometer was initialized from a rotation matrix. No "
349 <<
"recalculation from motors will be done.\n";
353 std::vector<GoniometerAxis>::iterator it;
354 std::vector<double> elements;
355 Quat QGlobal, QCurrent;
358 double ang = (*it).angle * (*it).sense;
361 QCurrent =
Quat(ang, (*it).rotationaxis);
374 file->makeGroup(
group,
"NXpositioner",
true);
375 file->putAttr(
"version", 1);
378 file->writeData(
"num_axes",
int(
m_motors.size()));
379 for (
size_t i = 0; i <
m_motors.size(); i++)
383 std::vector<double> matrixData = rMatrix.
getVector();
384 file->writeData(
"rotation_matrix", matrixData);
394 file->openGroup(
group,
"NXpositioner");
396 file->readData(
"num_axes", num_axes);
400 if (file->hasData(
"rotation_matrix") && (num_axes < 1)) {
401 std::vector<double> matrixData;
402 file->readData(
"rotation_matrix", matrixData);
404 setR(std::move(rotMat));
407 for (
int i = 0; i < num_axes; i++) {
double value
The value of the point.
Class to represent a particular goniometer setting, which is described by the rotation matrix.
Goniometer()
Default constructor The rotation matrix is initialized to identity.
void setRotationAngle(const std::string &name, double value)
Set rotation angle for an axis using motor name.
size_t getNumberAxes() const
std::vector< double > getEulerAngles(const std::string &convention="YZX")
Return Euler angles acording to a convention.
void recalculateR()
Private function to recalculate R when setRotationAngle is called.
void makeUniversalGoniometer()
Make a default universal goniometer with phi,chi,omega angles according to SNS convention.
bool operator!=(const Goniometer &other) const
bool isDefined() const
the method reports if the goniometer was defined with some parameters
bool operator==(const Goniometer &other) const
void saveNexus(Nexus::File *file, const std::string &group) const
Save the object to an open NeXus file.
std::string getConventionFromMotorAxes() const
return the goniometer convention used determine from the motor axes
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.
void setR(Kernel::DblMatrix rot)
Set the new rotation matrix.
bool m_initFromR
Flag to specify if the goniometer is initialized from a rotation matrix.
std::vector< GoniometerAxis > m_motors
Motors vector contains GoniometerAxis objects, the last one is the closest to the sample.
const Kernel::DblMatrix & getR() const
Return global rotation matrix.
void loadNexus(Nexus::File *file, const std::string &group)
Load the object from an open NeXus file.
Kernel::DblMatrix m_R
Global rotation matrix of the goniometer.
std::string axesInfo()
Return information about axes.
Goniometer & operator=(const Goniometer &other)
Copy assigment constructor.
void calcFromQSampleAndWavelength(const Mantid::Kernel::V3D &Q, double wavelength, bool flip_x=false, bool inner=false)
Calculate goniometer for rotation around y-asix for constant wavelength from Q Sample.
const GoniometerAxis & getAxis(size_t axisnumber) const
Get GoniometerAxis obfject using motor number.
The Logger class is in charge of the publishing messages from the framework through various channels.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
T Invert()
LU inversion routine.
bool isRotation() const
Check if a matrix represents a proper rotation @ return :: true/false.
std::vector< T > getVector() const
std::vector< double > getEulerAngles(const std::string &convention) const
Calculate the Euler angles that are equivalent to this Quaternion.
std::vector< double > getRotation(bool check_normalisation=false, bool throw_on_errors=false) const
returns the rotation matrix defined by this quaternion as an 9-point
void loadNexus(Nexus::File *file, const std::string &name)
Load the object from an open NeXus file.
void saveNexus(Nexus::File *file, const std::string &name) const
Save the object to an open NeXus file.
constexpr double rad2deg
Radians to degrees conversion factor.
Mantid::Kernel::Logger g_log("Goniometer")
std::string toString(const T &value)
Convert a number to a string.
Mantid::Kernel::Matrix< double > DblMatrix
Counter clockwise rotation.
void loadNexus(Nexus::File *file, const std::string &group)
double angle
GoniometerAxis direction.
int angleunit
Rotation sense (1 for CCW, -1 for CW)
Kernel::V3D rotationaxis
GoniometerAxis name.
void saveNexus(Nexus::File *file, const std::string &group) const