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);
75 throw std::invalid_argument(
"rot is not a rotation matrix");
103 return std::string(
"Goniometer was initialized from a rotation matrix. No "
104 "information about axis is available.\n");
106 std::stringstream info;
107 std::vector<GoniometerAxis>::iterator it;
108 std::string strCW(
"CW"), strCCW(
"CCW"), sense;
111 info <<
"No axis is found\n";
113 info <<
"Name \t Direction \t Sense \t Angle \n";
115 sense = ((*it).sense ==
CCW) ? strCCW : strCW;
116 double angle = ((*it).angleunit ==
angDegrees) ? ((*it).angle) : ((*it).angle *
rad2deg);
117 info << (*it).name <<
"\t" << (*it).rotationaxis <<
"\t" << sense <<
"\t" << angle <<
'\n';
133void Goniometer::pushAxis(
const std::string &name,
double axisx,
double axisy,
double axisz,
double angle,
int sense,
136 throw std::runtime_error(
"Initialized from a rotation matrix, so no axes can be pushed.");
138 if (!std::isfinite(axisx) || !std::isfinite(axisy) || !std::isfinite(axisz) || !std::isfinite(angle)) {
139 g_log.
warning() <<
"NaN encountered while trying to push axis to "
140 "goniometer, Operation aborted"
141 <<
"\naxis name" << name <<
"\naxisx" << axisx <<
"\naxisy" << axisx <<
"\naxisz" << axisz
142 <<
"\nangle" << angle;
145 std::vector<GoniometerAxis>::iterator it;
148 if (name == it->name)
149 throw std::invalid_argument(
"Motor name already defined");
162 bool changed =
false;
163 std::vector<GoniometerAxis>::iterator it;
165 if (name == it->name) {
171 throw std::invalid_argument(
"Motor name " + name +
" not found");
181 if (axisnumber >=
motors.size())
182 throw std::out_of_range(
"Goniometer::setRotationAngle(): axis number specified is too large.");
206 Q = starting_goniometer * Q;
208 double wv = 2.0 * M_PI / wavelength;
209 double norm_q2 = Q.
norm2();
210 double theta = acos(1 - norm_q2 / (2 * wv * wv));
211 double phi = asin(-Q[1] / (wv * sin(theta)));
212 V3D Q_lab(-wv * sin(theta) * cos(phi), -wv * sin(theta) * sin(phi), wv * (1 - cos(theta)));
218 starting_goniometer.
Invert();
219 Q_lab = starting_goniometer * Q_lab;
226 std::vector<double> B{Q_lab[0], Q_lab[2]};
227 std::vector<double>
X = A * B;
228 double rot = atan2(
X[1],
X[0]);
231 goniometer[0][0] = cos(rot);
232 goniometer[0][2] = sin(rot);
233 goniometer[2][0] = -sin(rot);
234 goniometer[2][2] = cos(rot);
236 starting_goniometer.
Invert();
237 setR(starting_goniometer * goniometer);
239 setR(goniometer * starting_goniometer);
246 return motors.at(axisnumber);
253 for (
auto it =
motors.begin(); it <
motors.end(); ++it) {
254 if (axisname == it->name) {
258 throw std::invalid_argument(
"Motor name " + axisname +
" not found");
289 g_log.
warning() <<
"Goniometer was initialized from a rotation matrix. No "
290 <<
"recalculation from motors will be done.\n";
293 std::vector<GoniometerAxis>::iterator it;
294 std::vector<double> elements;
295 Quat QGlobal, QCurrent;
298 double ang = (*it).angle * (*it).sense;
301 QCurrent =
Quat(ang, (*it).rotationaxis);
314 file->makeGroup(group,
"NXpositioner",
true);
315 file->putAttr(
"version", 1);
318 file->writeData(
"num_axes",
int(
motors.size()));
319 for (
size_t i = 0; i <
motors.size(); i++)
330 file->openGroup(group,
"NXpositioner");
332 file->readData(
"num_axes", num_axes);
335 for (
int i = 0; i < num_axes; i++) {
338 motors.emplace_back(newAxis);
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.
bool initFromR
Flag to specify if the goniometer is initialized from a rotation matrix.
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
std::vector< GoniometerAxis > motors
Motors vector contains GoniometerAxis objects, the last one is the closest to the sample.
bool isDefined() const
the method reports if the goniometer was defined with some parameters
bool operator==(const Goniometer &other) const
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 loadNexus(::NeXus::File *file, const std::string &group)
Load the object from an open NeXus file.
void setR(Kernel::DblMatrix rot)
Set the new rotation matrix.
Kernel::DblMatrix R
Global rotation matrix of the goniometer.
void saveNexus(::NeXus::File *file, const std::string &group) const
Save the object to an open NeXus file.
const Kernel::DblMatrix & getR() const
Return global rotation matrix.
std::string axesInfo()
Return information about axes.
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.
T Invert()
LU inversion routine.
void identityMatrix()
Makes the matrix an idenity matrix.
Matrix< T > Tprime() const
Transpose the matrix.
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
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
void loadNexus(::NeXus::File *file, const std::string &name)
Load the object from an open NeXus file.
constexpr double norm2() const noexcept
Vector length squared.
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.
double angle
GoniometerAxis direction.
void loadNexus(::NeXus::File *file, const std::string &group)
int angleunit
Rotation sense (1 for CCW, -1 for CW)
void saveNexus(::NeXus::File *file, const std::string &group) const
Kernel::V3D rotationaxis
GoniometerAxis name.