Mantid
Loading...
Searching...
No Matches
VMD.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 +
7#include "MantidKernel/VMD.h"
12#include "MantidKernel/V3D.h"
13
14#include <algorithm>
15#include <cmath>
16#include <cstddef>
17#include <iterator>
18#include <sstream>
19#include <stdexcept>
20
21using namespace Mantid::Kernel;
22
23namespace Mantid::Kernel {
26template <typename TYPE> VMDBase<TYPE>::VMDBase() : nd(1) {
27 data = new TYPE[nd];
28 for (size_t d = 0; d < nd; d++)
29 data[d] = TYPE(0.0);
31
34template <typename TYPE> VMDBase<TYPE>::VMDBase(size_t nd) : nd(nd) {
35 if (nd == 0)
36 throw std::invalid_argument("nd must be > 0");
37 data = new TYPE[nd];
38 for (size_t d = 0; d < nd; d++)
39 data[d] = TYPE(0.0);
46template <typename TYPE> VMDBase<TYPE>::VMDBase(double val0, double val1) : nd(2) {
47 data = new TYPE[nd];
48 data[0] = TYPE(val0);
49 data[1] = TYPE(val1);
57template <typename TYPE> VMDBase<TYPE>::VMDBase(double val0, double val1, double val2) : nd(3) {
58 data = new TYPE[nd];
59 data[0] = TYPE(val0);
60 data[1] = TYPE(val1);
61 data[2] = TYPE(val2);
70template <typename TYPE> VMDBase<TYPE>::VMDBase(double val0, double val1, double val2, double val3) : nd(4) {
71 data = new TYPE[nd];
72 data[0] = TYPE(val0);
73 data[1] = TYPE(val1);
74 data[2] = TYPE(val2);
75 data[3] = TYPE(val3);
76}
77
85template <typename TYPE>
86VMDBase<TYPE>::VMDBase(double val0, double val1, double val2, double val3, double val4) : nd(5) {
87 data = new TYPE[nd];
88 data[0] = TYPE(val0);
89 data[1] = TYPE(val1);
90 data[2] = TYPE(val2);
91 data[3] = TYPE(val3);
92 data[4] = TYPE(val4);
93}
94
103template <typename TYPE>
104VMDBase<TYPE>::VMDBase(double val0, double val1, double val2, double val3, double val4, double val5) : nd(6) {
105 data = new TYPE[nd];
106 data[0] = TYPE(val0);
107 data[1] = TYPE(val1);
108 data[2] = TYPE(val2);
109 data[3] = TYPE(val3);
110 data[4] = TYPE(val4);
111 data[5] = TYPE(val5);
112}
113
116template <typename TYPE> VMDBase<TYPE>::VMDBase(const VMDBase &other) : nd(other.nd) {
117 if (nd == 0)
118 throw std::invalid_argument("nd must be > 0");
119 data = new TYPE[nd];
120 for (size_t d = 0; d < nd; d++)
121 data[d] = other.data[d];
122}
123
127template <typename TYPE> VMDBase<TYPE> &VMDBase<TYPE>::operator=(const VMDBase &other) {
128 if ((other.nd) != nd) {
129 nd = other.nd;
130 delete[] data;
131 data = new TYPE[nd];
132 }
133 for (size_t d = 0; d < nd; d++)
134 data[d] = other.data[d];
135 return *this;
136}
137
141template <typename TYPE> VMDBase<TYPE>::VMDBase(VMDBase &&other) noexcept : nd(other.nd), data(other.data) {
142 other.data = nullptr;
143 other.nd = 0;
144}
145
149template <typename TYPE> VMDBase<TYPE> &VMDBase<TYPE>::operator=(VMDBase &&other) noexcept {
150 if (this != &other) {
151 this->nd = other.nd;
152 other.nd = 0;
153 delete[] this->data;
154 this->data = other.data;
155 other.data = nullptr;
156 }
157 return *this;
158}
159
163template <typename TYPE> VMDBase<TYPE>::VMDBase(size_t nd, const double *bareData) : nd(nd) {
164 if (nd == 0)
165 throw std::invalid_argument("nd must be > 0");
166 data = new TYPE[nd];
167 for (size_t d = 0; d < nd; d++)
168 data[d] = TYPE(bareData[d]);
169}
170
174template <typename TYPE> VMDBase<TYPE>::VMDBase(size_t nd, const float *bareData) : nd(nd) {
175 if (nd == 0)
176 throw std::invalid_argument("nd must be > 0");
177 data = new TYPE[nd];
178 for (size_t d = 0; d < nd; d++)
179 data[d] = TYPE(bareData[d]);
180}
181
184template <typename TYPE> VMDBase<TYPE>::VMDBase(const V3D &vector) : nd(3) {
185 data = new TYPE[nd];
186 for (size_t d = 0; d < nd; d++)
187 data[d] = TYPE(vector[d]);
188}
189
192template <typename TYPE> VMDBase<TYPE>::VMDBase(const std::vector<double> &vector) : nd(vector.size()) {
193 if (nd == 0)
194 throw std::invalid_argument("nd must be > 0");
195 data = new TYPE[nd];
196 for (size_t d = 0; d < nd; d++)
197 data[d] = TYPE(vector[d]);
198}
199
202template <typename TYPE> VMDBase<TYPE>::VMDBase(const std::vector<float> &vector) : nd(vector.size()) {
203 if (nd == 0)
204 throw std::invalid_argument("nd must be > 0");
205 data = new TYPE[nd];
206 for (size_t d = 0; d < nd; d++)
207 data[d] = TYPE(vector[d]);
208}
209
213template <typename TYPE> VMDBase<TYPE>::VMDBase(const std::string &str) {
214
216
217 std::vector<TYPE> vals;
218 std::transform(strs.cbegin(), strs.cend(), std::back_inserter(vals), [](const std::string &token) {
219 TYPE v;
220 if (!Strings::convert(token, v))
221 throw std::invalid_argument("VMDBase: Unable to convert the string '" + token + "' to a number.");
222 return v;
223 });
224
225 nd = vals.size();
226 if (nd == 0)
227 throw std::invalid_argument("nd must be > 0");
228 data = new TYPE[nd];
229 std::copy(vals.cbegin(), vals.cend(), data);
230}
231
233template <typename TYPE> VMDBase<TYPE>::~VMDBase() { delete[] data; }
234
236template <typename TYPE> size_t VMDBase<TYPE>::getNumDims() const { return nd; }
237
239template <typename TYPE> size_t VMDBase<TYPE>::size() const { return nd; }
240
242template <typename TYPE> const TYPE &VMDBase<TYPE>::operator[](const size_t index) const { return data[index]; }
243
245template <typename TYPE> TYPE &VMDBase<TYPE>::operator[](const size_t index) { return data[index]; }
246
248template <typename TYPE> const TYPE *VMDBase<TYPE>::getBareArray() const { return data; }
249
254template <typename TYPE> std::string VMDBase<TYPE>::toString(const std::string &separator) const {
255 std::ostringstream mess;
256 for (size_t d = 0; d < nd; d++)
257 mess << (d > 0 ? separator : "") << data[d];
258 return mess.str();
259}
260
265template <typename TYPE> bool VMDBase<TYPE>::operator==(const VMDBase &v) const {
266 if (v.nd != nd)
267 return false;
268 for (size_t d = 0; d < nd; d++)
269 if ((std::fabs(data[d] - v.data[d]) > Tolerance))
270 return false;
271 return true;
272}
273
278template <typename TYPE> bool VMDBase<TYPE>::operator!=(const VMDBase &v) const { return !operator==(v); }
279
282template <typename TYPE> VMDBase<TYPE> VMDBase<TYPE>::operator+(const VMDBase &v) const {
283 VMDBase out(*this);
284 out += v;
285 return out;
286}
287
290template <typename TYPE> VMDBase<TYPE> &VMDBase<TYPE>::operator+=(const VMDBase &v) {
291 if (v.nd != this->nd)
292 throw std::runtime_error("Mismatch in number of dimensions in operation "
293 "between two VMDBase vectors.");
294 for (size_t d = 0; d < nd; d++)
295 data[d] += v.data[d];
296 return *this;
297}
298
302template <typename TYPE> VMDBase<TYPE> VMDBase<TYPE>::operator-(const VMDBase &v) const {
303 VMDBase out(*this);
304 out -= v;
305 return out;
306}
307
310template <typename TYPE> VMDBase<TYPE> &VMDBase<TYPE>::operator-=(const VMDBase &v) {
311 if (v.nd != this->nd)
312 throw std::runtime_error("Mismatch in number of dimensions in operation "
313 "between two VMDBase vectors.");
314 for (size_t d = 0; d < nd; d++)
315 data[d] -= v.data[d];
316 return *this;
317}
318
321template <typename TYPE> VMDBase<TYPE> VMDBase<TYPE>::operator*(const VMDBase &v) const {
322 VMDBase out(*this);
323 out *= v;
324 return out;
325}
326
329template <typename TYPE> VMDBase<TYPE> &VMDBase<TYPE>::operator*=(const VMDBase &v) {
330 if (v.nd != this->nd)
331 throw std::runtime_error("Mismatch in number of dimensions in operation "
332 "between two VMDBase vectors.");
333 for (size_t d = 0; d < nd; d++)
334 data[d] *= v.data[d];
335 return *this;
336}
337
340template <typename TYPE> VMDBase<TYPE> VMDBase<TYPE>::operator/(const VMDBase &v) const {
341 VMDBase out(*this);
342 out /= v;
343 return out;
344}
345
348template <typename TYPE> VMDBase<TYPE> &VMDBase<TYPE>::operator/=(const VMDBase &v) {
349 if (v.nd != this->nd)
350 throw std::runtime_error("Mismatch in number of dimensions in operation "
351 "between two VMDBase vectors.");
352 for (size_t d = 0; d < nd; d++)
353 data[d] /= v.data[d];
354 return *this;
355}
356
359template <typename TYPE> VMDBase<TYPE> VMDBase<TYPE>::operator*(const double scalar) const {
360 VMDBase out(*this);
361 out *= scalar;
362 return out;
363}
364
367template <typename TYPE> VMDBase<TYPE> &VMDBase<TYPE>::operator*=(const double scalar) {
368 for (size_t d = 0; d < nd; d++)
369 data[d] *= TYPE(scalar);
370 return *this;
371}
372
375template <typename TYPE> VMDBase<TYPE> VMDBase<TYPE>::operator/(const double scalar) const {
376 VMDBase out(*this);
377 out /= scalar;
378 return out;
379}
380
383template <typename TYPE> VMDBase<TYPE> &VMDBase<TYPE>::operator/=(const double scalar) {
384 for (size_t d = 0; d < nd; d++)
385 data[d] /= TYPE(scalar);
386 return *this;
387}
388
391template <typename TYPE> TYPE VMDBase<TYPE>::scalar_prod(const VMDBase &v) const {
392 TYPE out = 0;
393 if (v.nd != this->nd)
394 throw std::runtime_error("Mismatch in number of dimensions in operation "
395 "between two VMDBase vectors.");
396 for (size_t d = 0; d < nd; d++)
397 out += (data[d] * v.data[d]);
398 return out;
399}
400
403template <typename TYPE> VMDBase<TYPE> VMDBase<TYPE>::cross_prod(const VMDBase &v) const {
404 if (v.nd != this->nd)
405 throw std::runtime_error("Mismatch in number of dimensions in operation "
406 "between two VMDBase vectors.");
407 if (v.nd != 3)
408 throw std::runtime_error("Cross product of vectors only works in 3 dimensions.");
409 V3D a(data[0], data[1], data[2]);
410 V3D b(v.data[0], v.data[1], v.data[2]);
411 V3D c = a.cross_prod(b);
412 VMDBase out(c);
413 return out;
414}
415
417template <typename TYPE> TYPE VMDBase<TYPE>::length() const { return TYPE(std::sqrt(this->norm2())); }
418
420template <typename TYPE> TYPE VMDBase<TYPE>::norm() const { return this->length(); }
421
423template <typename TYPE> TYPE VMDBase<TYPE>::norm2() const { return this->scalar_prod(*this); }
424
427template <typename TYPE> TYPE VMDBase<TYPE>::normalize() {
428 TYPE length = this->length();
429 for (size_t d = 0; d < nd; d++)
430 data[d] /= length;
431 return length;
432}
433
438template <typename TYPE> TYPE VMDBase<TYPE>::angle(const VMDBase &v) const {
439 return TYPE(acos(this->scalar_prod(v) / (this->norm() * v.norm())));
440}
441
442//-------------------------------------------------------------------------------------------------
449template <typename TYPE>
450std::vector<VMDBase<TYPE>> VMDBase<TYPE>::makeVectorsOrthogonal(std::vector<VMDBase> &vectors) {
451 if (vectors.size() != 2)
452 throw std::runtime_error("VMDBase::makeVectorsOrthogonal(): Need 2 input vectors.");
453 if (vectors[0].getNumDims() != 3 || vectors[1].getNumDims() != 3)
454 throw std::runtime_error("VMDBase::makeVectorsOrthogonal(): Need 3D input vectors.");
455 std::vector<V3D> in, out;
456 for (size_t i = 0; i < vectors.size(); i++)
457 in.emplace_back(vectors[i][0], vectors[i][1], vectors[i][2]);
459 std::vector<VMDBase> retVal;
460 retVal.reserve(out.size());
461 std::copy(std::make_move_iterator(out.begin()), std::make_move_iterator(out.end()), std::back_inserter(retVal));
462 return retVal;
463}
464
465//-------------------------------------------------------------------------------------------------
494template <typename TYPE> VMDBase<TYPE> VMDBase<TYPE>::getNormalVector(const std::vector<VMDBase<TYPE>> &vectors) {
495 if (vectors.empty())
496 throw std::invalid_argument("VMDBase::getNormalVector: Must give at least 1 vector");
497 size_t nd = vectors[0].getNumDims();
498 if (nd < 2)
499 throw std::invalid_argument("VMDBase::getNormalVector: Must have at least 2 dimensions!");
500 if (vectors.size() != nd - 1)
501 throw std::invalid_argument("VMDBase::getNormalVector: Must have as many "
502 "N-1 vectors if there are N dimensions.");
503 for (size_t i = 0; i < vectors.size(); i++)
504 if (vectors[i].getNumDims() != nd)
505 throw std::invalid_argument("VMDBase::getNormalVector: Inconsistent "
506 "number of dimensions in the vectors given!");
507
508 // Start the normal vector
509 VMDBase normal = VMDBase(nd);
510 TYPE sign = +1.0;
511 for (size_t d = 0; d < nd; d++) {
512 // Make the sub-determinant with the columns of every other dimension.
513 Matrix<TYPE> mat(nd - 1, nd - 1);
514 for (size_t row = 0; row < vectors.size(); row++) {
515 VMDBase vec = vectors[row];
516 size_t col = 0;
517 for (size_t i = 0; i < nd; i++) {
518 if (i != d) // Skip the column of this dimension
519 {
520 mat[row][col] = vec[i];
521 col++;
522 }
523 }
524 } // Building the matrix rows
525
526 TYPE det = mat.determinant();
527
528 // The determinant of the sub-matrix = the normal at that dimension
529 normal[d] = sign * det;
530
531 // Sign flips each time
532 sign *= TYPE(-1.0);
533 } // each dimension of the normal vector
534
535 // Unity normal is better.
536 double length = normal.normalize();
537 if (length == 0)
538 throw std::runtime_error("VMDBase::getNormalVector: 0-length normal found. "
539 "Are your vectors collinear?");
540
541 return normal;
542}
543
545template class VMDBase<double>;
546template class VMDBase<float>;
547
554std::ostream &operator<<(std::ostream &os, const VMDBase<double> &v) {
555 os << v.toString();
556 return os;
557}
558
559std::ostream &operator<<(std::ostream &os, const VMDBase<float> &v) {
560 os << v.toString();
561 return os;
562}
563
564} // namespace Mantid::Kernel
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
Numerical Matrix class.
Definition: Matrix.h:42
T determinant() const
Calculate the determinant.
Definition: Matrix.cpp:1048
@ TOK_IGNORE_EMPTY
ignore empty tokens
ConstIterator cend() const
Const iterator referring to the past-the-end element in the container.
ConstIterator cbegin() const
Const iterator referring to first element in the container.
Class for 3D vectors.
Definition: V3D.h:34
static std::vector< V3D > makeVectorsOrthogonal(const std::vector< V3D > &vectors)
Take a list of 2 vectors and makes a 3D orthogonal system out of them The first vector i0 is taken as...
Definition: V3D.cpp:298
constexpr V3D cross_prod(const V3D &v) const noexcept
Cross product (this * argument)
Definition: V3D.h:278
Simple vector class for multiple dimensions (i.e.
Definition: VMD.h:22
VMDBase operator+(const VMDBase &v) const
Add two vectors together.
Definition: VMD.cpp:282
std::string toString(const std::string &separator=" ") const
Return a simple string representation of the vector.
Definition: VMD.cpp:254
static std::vector< VMDBase > makeVectorsOrthogonal(std::vector< VMDBase > &vectors)
Make an orthogonal system with 2 input 3D vectors.
Definition: VMD.cpp:450
VMDBase & operator=(const VMDBase &other)
Assignment operator.
Definition: VMD.cpp:127
TYPE normalize()
Normalize this vector to unity length.
Definition: VMD.cpp:427
const TYPE * getBareArray() const
Definition: VMD.cpp:248
bool operator==(const VMDBase &v) const
Equals operator with tolerance factor.
Definition: VMD.cpp:265
TYPE length() const
Definition: VMD.cpp:417
VMDBase & operator*=(const VMDBase &v)
Inner product of two vectors (element-by-element)
Definition: VMD.cpp:329
VMDBase operator/(const VMDBase &v) const
Inner division of two vectors (element-by-element)
Definition: VMD.cpp:340
TYPE norm2() const
Definition: VMD.cpp:423
TYPE scalar_prod(const VMDBase &v) const
Scalar product of two vectors.
Definition: VMD.cpp:391
VMDBase & operator-=(const VMDBase &v)
Subtract two vectors.
Definition: VMD.cpp:310
size_t nd
Number of dimensions.
Definition: VMD.h:77
~VMDBase()
Destructor.
Definition: VMD.cpp:233
TYPE angle(const VMDBase &v) const
Return the angle between this and another vector.
Definition: VMD.cpp:438
size_t size() const
Definition: VMD.cpp:239
bool operator!=(const VMDBase &v) const
Not-equals operator with tolerance factor.
Definition: VMD.cpp:278
VMDBase()
Default constructor, build with 1 dimension.
Definition: VMD.cpp:26
VMDBase cross_prod(const VMDBase &v) const
Cross product of two vectors.
Definition: VMD.cpp:403
TYPE * data
Data, an array of size nd.
Definition: VMD.h:79
VMDBase operator*(const VMDBase &v) const
Inner product of two vectors (element-by-element)
Definition: VMD.cpp:321
VMDBase & operator/=(const VMDBase &v)
Inner division of two vectors (element-by-element)
Definition: VMD.cpp:348
VMDBase & operator+=(const VMDBase &v)
Add two vectors together.
Definition: VMD.cpp:290
size_t getNumDims() const
Definition: VMD.cpp:236
VMDBase operator-(const VMDBase &v) const
Subtract two vectors.
Definition: VMD.cpp:302
static VMDBase getNormalVector(const std::vector< VMDBase > &vectors)
Given N-1 vectors defining a N-1 dimensional hyperplane in N dimensions, returns a vector that is nor...
Definition: VMD.cpp:494
TYPE norm() const
Definition: VMD.cpp:420
const TYPE & operator[](const size_t index) const
Definition: VMD.cpp:242
MANTID_KERNEL_DLL std::ostream & operator<<(std::ostream &, CPUTimer &)
Convenience function to provide for easier debug printing.
Definition: CPUTimer.cpp:86
MANTID_KERNEL_DLL bool operator==(const Mantid::Kernel::Property &lhs, const Mantid::Kernel::Property &rhs)
Compares this to another property for equality.
Definition: Property.cpp:259
constexpr double Tolerance
Standard tolerance value.
Definition: Tolerance.h:12