LeanPeak.cpp 12.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
//   NScD Oak Ridge National Laboratory, European Spallation Source,
//   Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
// SPDX - License - Identifier: GPL - 3.0 +
#include "MantidDataObjects/LeanPeak.h"
#include "MantidDataObjects/NoShape.h"
#include "MantidGeometry/Instrument/RectangularDetector.h"
#include "MantidGeometry/Instrument/ReferenceFrame.h"
#include "MantidGeometry/Objects/InstrumentRayTracer.h"
#include "MantidGeometry/Surfaces/LineIntersectVisit.h"
#include "MantidKernel/ConfigService.h"
#include "MantidKernel/Exception.h"
#include "MantidKernel/Strings.h"

#include "boost/make_shared.hpp"

#include <algorithm>
#include <cctype>
#include <string>
#include <utility>

using namespace Mantid;
using namespace Mantid::Kernel;
using namespace Mantid::Geometry;

namespace Mantid {
namespace DataObjects {

//----------------------------------------------------------------------------------------------
/** Default constructor */
33
LeanPeak::LeanPeak() : BasePeak(), m_Qsample(V3D(0, 0, 0)) {}
34

35
36
37
38
39
40
41
42
//----------------------------------------------------------------------------------------------
/** Constructor that uses the Q position of the peak (in the sample frame)
 * and a goniometer rotation matrix.
 * No detector ID is set.
 *
 * @param QSampleFrame :: Q of the center of the peak, in reciprocal space, in
 *the sample frame (goniometer rotation accounted for).
 */
43
LeanPeak::LeanPeak(const Mantid::Kernel::V3D &QSampleFrame) : BasePeak() {
44
45
46
  this->setQSampleFrame(QSampleFrame);
}

47
48
49
50
//----------------------------------------------------------------------------------------------
/** Constructor that uses the Q position of the peak (in the lab frame).
 * No detector ID is set.
 *
51
 * @param QSampleFrame :: Q of the center of the peak, in reciprocal space
52
 * @param goniometer :: a 3x3 rotation matrix
53
 */
54
LeanPeak::LeanPeak(const Mantid::Kernel::V3D &QSampleFrame,
55
                   const Mantid::Kernel::Matrix<double> &goniometer)
56
    : BasePeak(goniometer) {
57
  this->setQSampleFrame(QSampleFrame);
58
59
60
61
62
63
64
65
66
}

//----------------------------------------------------------------------------------------------
/** Constructor that uses the Q position of the peak (in the sample frame)
 * and a goniometer rotation matrix.
 * No detector ID is set.
 *
 * @param QSampleFrame :: Q of the center of the peak, in reciprocal space, in
 *the sample frame (goniometer rotation accounted for).
67
 * @param wavelength :: wavelength in Angstroms.
68
 */
69
LeanPeak::LeanPeak(const Mantid::Kernel::V3D &QSampleFrame, double wavelength)
70
    : BasePeak() {
71
  this->setQSampleFrame(QSampleFrame);
72
73
74
75
76
77
78
79
80
  this->setWavelength(wavelength);
}

//----------------------------------------------------------------------------------------------
/** Constructor that uses the Q position of the peak (in the lab frame).
 * No detector ID is set.
 *
 * @param QSampleFrame :: Q of the center of the peak, in reciprocal space
 * @param goniometer :: a 3x3 rotation matrix
81
 * @param wavelength :: wavelength in Angstroms.
82
83
84
85
 */
LeanPeak::LeanPeak(const Mantid::Kernel::V3D &QSampleFrame,
                   const Mantid::Kernel::Matrix<double> &goniometer,
                   double wavelength)
86
    : BasePeak(goniometer) {
87
88
  this->setQSampleFrame(QSampleFrame);
  this->setWavelength(wavelength);
89
90
91
92
93
94
95
}

/**
 * @brief Copy constructor
 * @param other : Source
 */
LeanPeak::LeanPeak(const LeanPeak &other)
96
    : BasePeak(other), m_Qsample(other.m_Qsample) {}
97
98
99
100
101
102
103

//----------------------------------------------------------------------------------------------
/** Constructor making a LeanPeak from IPeak interface
 *
 * @param ipeak :: const reference to an IPeak object
 */
LeanPeak::LeanPeak(const Geometry::IPeak &ipeak)
104
    : BasePeak(ipeak), m_Qsample(ipeak.getQSampleFrame()) {}
105
106
107
108
109
110
111
112
113

//----------------------------------------------------------------------------------------------
/** Set the detector ID of the pixel at the centre of the peak and look up and
 * cache
 *  values related to it. It also adds it to the list of contributing detectors
 * for this peak but
 *  does NOT remove the old centre.
 * @param id :: ID of detector at the centre of the peak.
 */
114
void LeanPeak::setDetectorID([[maybe_unused]] int id) {
115
116
  throw std::runtime_error(
      "LeanPeak::setDetectorID(): Can't set detectorID on LeanPeak");
117
118
119
120
}

//----------------------------------------------------------------------------------------------
/** Get the ID of the detector at the center of the peak  */
121
int LeanPeak::getDetectorID() const { return -1; }
122
123
124
125
126
127
128

//----------------------------------------------------------------------------------------------
/** Set the instrument (and save the source/sample pos).
 * Call setDetectorID AFTER this call.
 *
 * @param inst :: Instrument sptr to use
 */
129
130
void LeanPeak::setInstrument([
    [maybe_unused]] const Geometry::Instrument_const_sptr &inst) {
131
132
  throw std::runtime_error(
      "LeanPeak::setInstrument(): Can't set instrument on LeanPeak");
133
134
135
136
}

//----------------------------------------------------------------------------------------------
/** Return a shared ptr to the detector at center of peak. */
137
138
139
Geometry::IDetector_const_sptr LeanPeak::getDetector() const {
  throw std::runtime_error("LeanPeak::getDetector(): Has no detector ID");
}
140
141
142

/** Return a shared ptr to the instrument for this peak. */
Geometry::Instrument_const_sptr LeanPeak::getInstrument() const {
143
  throw std::runtime_error("LeanPeak::setInstrument(): Has no instrument");
144
145
146
147
148
149
}

// -------------------------------------------------------------------------------------
/** Calculate the time of flight (in microseconds) of the neutrons for this
 * peak,
 * using the geometry of the detector  */
150
151
152
double LeanPeak::getTOF() const {
  return std::numeric_limits<double>::quiet_NaN();
}
153
154
155
156

// -------------------------------------------------------------------------------------
/** Calculate the scattering angle of the peak  */
double LeanPeak::getScattering() const {
157
  return asin(getWavelength() / (2 * getDSpacing())) * 2;
158
159
160
161
162
}

// -------------------------------------------------------------------------------------
/** Calculate the azimuthal angle of the peak  */
double LeanPeak::getAzimuthal() const {
163
  return std::numeric_limits<double>::quiet_NaN();
164
165
166
167
}

// -------------------------------------------------------------------------------------
/** Calculate the d-spacing of the peak, in 1/Angstroms  */
168
double LeanPeak::getDSpacing() const { return 2 * M_PI / m_Qsample.norm(); }
169
170
171
172
173
174
175
176

//----------------------------------------------------------------------------------------------
/** Return the Q change (of the lattice, k_i - k_f) for this peak.
 * The Q is in the Lab frame: the goniometer rotation was NOT taken out.
 *
 * Note: There is a 2*pi factor used, so |Q| = 2*pi/wavelength.
 * */
Mantid::Kernel::V3D LeanPeak::getQLabFrame() const {
177
  return getGoniometerMatrix() * m_Qsample;
178
179
180
181
182
}

//----------------------------------------------------------------------------------------------
/** Return the Q change (of the lattice, k_i - k_f) for this peak.
 * The Q is in the Sample frame: the goniometer rotation WAS taken out. */
183
Mantid::Kernel::V3D LeanPeak::getQSampleFrame() const { return m_Qsample; }
184
185
186
187
188
189
190
191
192
193
194

//----------------------------------------------------------------------------------------------
/** Set the peak using the peak's position in reciprocal space, in the sample
 *frame.
 * The GoniometerMatrix will be used to find the Q in the lab frame, so it
 *should
 * be set beforehand.
 *
 * @param QSampleFrame :: Q of the center of the peak, in reciprocal space
 *        This is in inelastic convention: momentum transfer of the LATTICE!
 *        Also, q does NOT have a 2pi factor = it is equal to 1/wavelength.
195
 * @param detectorDistance :: unused
196
 */
197
198
199
200
void LeanPeak::setQSampleFrame(
    const Mantid::Kernel::V3D &QSampleFrame,
    [[maybe_unused]] boost::optional<double> detectorDistance) {
  m_Qsample = QSampleFrame;
201
202
203
204
205
206
207
208
209
210
211
212
213
}

//----------------------------------------------------------------------------------------------
/** Set the peak using the peak's position in reciprocal space, in the lab
 *frame.
 * The detector position will be determined.
 * DetectorID, row and column will be set to -1 since they are not (necessarily)
 *found.
 * You can call findDetector to look for the detector ID
 *
 * @param qLab :: Q of the center of the peak, in reciprocal space.
 *        This is in inelastic convention: momentum transfer of the LATTICE!
 *        Also, q does have a 2pi factor = it is equal to 2pi/wavelength (in
214
 *        Angstroms).
215
 * @param detectorDistance :: distance between the sample and the detector. If
216
217
218
 *        this is provided. Then we do not ray trace to find the intersecing
 *detector.
 * @param detectorDistance :: unused
219
 */
220
221
222
void LeanPeak::setQLabFrame(
    const Mantid::Kernel::V3D &qLab,
    [[maybe_unused]] boost::optional<double> detectorDistance) {
223
  this->setQSampleFrame(getInverseGoniometerMatrix() * qLab);
224
225
226
227
228
229
}

/** Set sample position
 *
 * @ doubles x,y,z-> samplePos(x), samplePos(y), samplePos(z)
 */
230
231
232
233
void LeanPeak::setSamplePos([[maybe_unused]] double samX,
                            [[maybe_unused]] double samY,
                            [[maybe_unused]] double samZ) {
  throw std::runtime_error("not implemented");
234
235
236
237
238
239
}

/** Set sample position
 *
 * @param XYZ :: vector x,y,z-> samplePos(x), samplePos(y), samplePos(z)
 */
240
241
void LeanPeak::setSamplePos([[maybe_unused]] const Mantid::Kernel::V3D &XYZ) {
  throw std::runtime_error("not implemented");
242
243
244
245
}

// -------------------------------------------------------------------------------------
/** Return the detector position vector */
246
247
248
Mantid::Kernel::V3D LeanPeak::getDetPos() const {
  throw std::runtime_error("not implemented");
}
249
250
251

// -------------------------------------------------------------------------------------
/** Return the sample position vector */
252
253
254
Mantid::Kernel::V3D LeanPeak::getSamplePos() const {
  throw std::runtime_error("not implemented");
}
255
256
257

// -------------------------------------------------------------------------------------
/** Return the L1 flight path length (source to sample), in meters. */
258
259
260
double LeanPeak::getL1() const {
  return std::numeric_limits<double>::quiet_NaN();
}
261
262
263

// -------------------------------------------------------------------------------------
/** Return the L2 flight path length (sample to detector), in meters. */
264
265
266
double LeanPeak::getL2() const {
  return std::numeric_limits<double>::quiet_NaN();
}
267
268
269
270
271
272
273
274

/**
 * @brief Assignement operator overload
 * @param other : Other peak object to assign from
 * @return this
 */
LeanPeak &LeanPeak::operator=(const LeanPeak &other) {
  if (&other != this) {
275
    BasePeak::operator=(other);
Whitfield, Ross's avatar
Whitfield, Ross committed
276
    m_Qsample = other.m_Qsample;
277
278
279
280
  }
  return *this;
}

Whitfield, Ross's avatar
Whitfield, Ross committed
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
/** After creating a peak using the Q in the lab frame,
 * the detPos is set to the direction of the detector (but the detector is
 *unknown)
 *
 * Using the instrument set in the peak, perform ray tracing
 * to find the exact detector.
 *
 * @return true if the detector ID was found.
 */
bool LeanPeak::findDetector() { throw std::runtime_error("not implemented"); }

/**
 * Performs the same algorithm as findDetector() but uses a pre-existing
 * InstrumentRayTracer object to be able to take adavtange of its caches.
 * This method should be preferred if findDetector is to be called many times
 * over the same instrument.
 * @param tracer A reference to an existing InstrumentRayTracer object.
 * @return true if the detector ID was found.
 */
bool LeanPeak::findDetector([
    [maybe_unused]] const InstrumentRayTracer &tracer) {
  throw std::runtime_error("not implemented");
}

305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
/**
 Forwarding function. Exposes the detector position directly.
 */
Mantid::Kernel::V3D LeanPeak::getDetectorPositionNoCheck() const {
  return getDetector()->getPos();
}

/**
 Forwarding function. Exposes the detector position directly, but checks that
 the detector is not null before accessing its position. Throws if null.
 */
Mantid::Kernel::V3D LeanPeak::getDetectorPosition() const {
  auto det = getDetector();
  if (det == nullptr) {
    throw Mantid::Kernel::Exception::NullPointerException("LeanPeak",
                                                          "Detector");
  }
  return getDetector()->getPos();
}

Mantid::Kernel::Logger LeanPeak::g_log("PeakLogger");

} // namespace DataObjects
} // namespace Mantid