LeanElasticPeak.cpp 13.9 KB
Newer Older
1
2
3
4
5
6
// 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 +
7
#include "MantidDataObjects/LeanElasticPeak.h"
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
#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
34
LeanElasticPeak::LeanElasticPeak()
    : BasePeak(), m_Qsample(V3D(0, 0, 0)), m_wavelength(0.) {}
35

36
37
38
39
40
41
42
43
//----------------------------------------------------------------------------------------------
/** 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).
 */
44
45
LeanElasticPeak::LeanElasticPeak(const Mantid::Kernel::V3D &QSampleFrame)
    : BasePeak() {
46
47
48
  this->setQSampleFrame(QSampleFrame);
}

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

//----------------------------------------------------------------------------------------------
/** 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).
68
 * @param wavelength :: wavelength in Angstroms.
69
 */
70
71
LeanElasticPeak::LeanElasticPeak(const Mantid::Kernel::V3D &QSampleFrame,
                                 double wavelength)
72
    : BasePeak(), m_Qsample(QSampleFrame), m_wavelength(wavelength) {}
73
74
75
76
77
78
79

//----------------------------------------------------------------------------------------------
/** 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
80
 * @param wavelength :: wavelength in Angstroms.
81
 */
82
83
84
LeanElasticPeak::LeanElasticPeak(
    const Mantid::Kernel::V3D &QSampleFrame,
    const Mantid::Kernel::Matrix<double> &goniometer, double wavelength)
85
    : BasePeak(goniometer), m_Qsample(QSampleFrame), m_wavelength(wavelength) {}
86
87
88
89
90

/**
 * @brief Copy constructor
 * @param other : Source
 */
91
LeanElasticPeak::LeanElasticPeak(const LeanElasticPeak &other)
92
93
    : BasePeak(other), m_Qsample(other.m_Qsample),
      m_wavelength(other.m_wavelength) {}
94
95

//----------------------------------------------------------------------------------------------
96
/** Constructor making a LeanElasticPeak from IPeak interface
97
98
99
 *
 * @param ipeak :: const reference to an IPeak object
 */
100
LeanElasticPeak::LeanElasticPeak(const Geometry::IPeak &ipeak)
101
102
103
104
105
106
107
108
109
110
111
    : BasePeak(ipeak), m_Qsample(ipeak.getQSampleFrame()),
      m_wavelength(ipeak.getWavelength()) {}

//----------------------------------------------------------------------------------------------
/** Set the wavelength of the neutron. Assumes elastic scattering.
 *
 * @param wavelength :: wavelength in Angstroms.
 */
void LeanElasticPeak::setWavelength(double wavelength) {
  m_wavelength = wavelength;
}
112
113
114

//----------------------------------------------------------------------------------------------
/** Set the detector ID of the pixel at the centre of the peak and look up and
Whitfield, Ross's avatar
Whitfield, Ross committed
115
116
 * 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.
117
 */
118
void LeanElasticPeak::setDetectorID(int) {
119
  throw Exception::NotImplementedError(
120
121
      "LeanElasticPeak::setDetectorID(): Can't set detectorID on "
      "LeanElasticPeak");
122
123
124
125
}

//----------------------------------------------------------------------------------------------
/** Get the ID of the detector at the center of the peak  */
126
int LeanElasticPeak::getDetectorID() const { return -1; }
127
128
129
130
131
132

//----------------------------------------------------------------------------------------------
/** Set the instrument (and save the source/sample pos).
 * Call setDetectorID AFTER this call.
 *
 */
133
void LeanElasticPeak::setInstrument(const Geometry::Instrument_const_sptr &) {
134
  throw Exception::NotImplementedError(
135
136
      "LeanElasticPeak::setInstrument(): Can't set instrument on "
      "LeanElasticPeak");
137
138
139
140
}

//----------------------------------------------------------------------------------------------
/** Return a shared ptr to the detector at center of peak. */
141
Geometry::IDetector_const_sptr LeanElasticPeak::getDetector() const {
142
  throw Exception::NotImplementedError(
143
      "LeanElasticPeak::getDetector(): Has no detector ID");
144
}
145
146

/** Return a shared ptr to the instrument for this peak. */
147
Geometry::Instrument_const_sptr LeanElasticPeak::getInstrument() const {
148
  throw Exception::NotImplementedError(
149
      "LeanElasticPeak::setInstrument(): Has no instrument");
150
151
}

152
153
154
155
// -------------------------------------------------------------------------------------
/** Return the neutron wavelength (in angstroms) */
double LeanElasticPeak::getWavelength() const { return m_wavelength; }

156
157
158
159
// -------------------------------------------------------------------------------------
/** Calculate the time of flight (in microseconds) of the neutrons for this
 * peak,
 * using the geometry of the detector  */
160
double LeanElasticPeak::getTOF() const {
161
162
  return std::numeric_limits<double>::quiet_NaN();
}
163
164
165

// -------------------------------------------------------------------------------------
/** Calculate the scattering angle of the peak  */
166
double LeanElasticPeak::getScattering() const {
167
  return asin(getWavelength() / (2 * getDSpacing())) * 2;
168
169
170
171
}

// -------------------------------------------------------------------------------------
/** Calculate the azimuthal angle of the peak  */
172
double LeanElasticPeak::getAzimuthal() const {
173
  return std::numeric_limits<double>::quiet_NaN();
174
175
176
177
}

// -------------------------------------------------------------------------------------
/** Calculate the d-spacing of the peak, in 1/Angstroms  */
178
179
180
double LeanElasticPeak::getDSpacing() const {
  return 2 * M_PI / m_Qsample.norm();
}
181
182
183
184
185
186
187

//----------------------------------------------------------------------------------------------
/** 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.
 * */
188
Mantid::Kernel::V3D LeanElasticPeak::getQLabFrame() const {
189
  return getGoniometerMatrix() * m_Qsample;
190
191
192
193
194
}

//----------------------------------------------------------------------------------------------
/** 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. */
195
196
197
Mantid::Kernel::V3D LeanElasticPeak::getQSampleFrame() const {
  return m_Qsample;
}
198
199
200
201
202
203
204
205
206
207
208
209

//----------------------------------------------------------------------------------------------
/** 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.
 */
210
211
void LeanElasticPeak::setQSampleFrame(const Mantid::Kernel::V3D &QSampleFrame,
                                      boost::optional<double>) {
212
  m_Qsample = QSampleFrame;
213
214
215
216
217
218
219
220
221
222
223
224
225
}

//----------------------------------------------------------------------------------------------
/** 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
226
 *        Angstroms).
227
 */
228
229
void LeanElasticPeak::setQLabFrame(const Mantid::Kernel::V3D &qLab,
                                   boost::optional<double>) {
230
  this->setQSampleFrame(getInverseGoniometerMatrix() * qLab);
231
232
}

233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
//----------------------------------------------------------------------------------------------
/** Get the final neutron energy in meV */
double LeanElasticPeak::getFinalEnergy() const {
  // Velocity of the neutron (non-relativistic)
  const double velocity =
      PhysicalConstants::h /
      (m_wavelength * 1e-10 * PhysicalConstants::NeutronMass);
  // Energy in J of the neutron
  const double energy =
      PhysicalConstants::NeutronMass * velocity * velocity / 2.0;
  // Convert to meV
  return energy / PhysicalConstants::meV;
}

/** Get the initial (incident) neutron energy in meV */
double LeanElasticPeak::getInitialEnergy() const { return getFinalEnergy(); }

/** Get the difference between the initial and final neutron energy in meV,
 * elastic so always 0 */
double LeanElasticPeak::getEnergyTransfer() const { return 0.; }

/** Set sample position */
255
256
257
void LeanElasticPeak::setSamplePos(double, double, double) {
  throw Exception::NotImplementedError(
      "LeanElasticPeak has no sample information");
258
259
}

260
/** Set sample position  */
261
262
263
void LeanElasticPeak::setSamplePos(const Mantid::Kernel::V3D &) {
  throw Exception::NotImplementedError(
      "LeanElasticPeak has no sample information");
264
265
}

266
267
268
269
270
271
272
273
274
275
/** Set the final energy */
void LeanElasticPeak::setFinalEnergy(double) {
  throw Exception::NotImplementedError("Use LeanElasticPeak::setWavelength");
}

/** Set the initial energy */
void LeanElasticPeak::setInitialEnergy(double) {
  throw Exception::NotImplementedError("Use LeanElasticPeak::setWavelength");
}

276
277
// -------------------------------------------------------------------------------------
/** Return the detector position vector */
278
279
280
Mantid::Kernel::V3D LeanElasticPeak::getDetPos() const {
  throw Exception::NotImplementedError(
      "LeanElasticPeak has no detector information");
281
}
282
283
284

// -------------------------------------------------------------------------------------
/** Return the sample position vector */
285
286
287
Mantid::Kernel::V3D LeanElasticPeak::getSamplePos() const {
  throw Exception::NotImplementedError(
      "LeanElasticPeak has no sample information");
288
}
289
290
291

// -------------------------------------------------------------------------------------
/** Return the L1 flight path length (source to sample), in meters. */
292
293
294
double LeanElasticPeak::getL1() const {
  throw Exception::NotImplementedError(
      "LeanElasticPeak has no detector information");
295
}
296
297
298

// -------------------------------------------------------------------------------------
/** Return the L2 flight path length (sample to detector), in meters. */
299
300
301
double LeanElasticPeak::getL2() const {
  throw Exception::NotImplementedError(
      "LeanElasticPeak has no detector information");
302
}
303
304
305
306
307
308

/**
 * @brief Assignement operator overload
 * @param other : Other peak object to assign from
 * @return this
 */
309
LeanElasticPeak &LeanElasticPeak::operator=(const LeanElasticPeak &other) {
310
  if (&other != this) {
311
    BasePeak::operator=(other);
Whitfield, Ross's avatar
Whitfield, Ross committed
312
    m_Qsample = other.m_Qsample;
313
    m_wavelength = other.m_wavelength;
314
315
316
317
  }
  return *this;
}

Whitfield, Ross's avatar
Whitfield, Ross committed
318
319
320
321
322
323
324
325
326
/** 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.
 */
327
328
329
bool LeanElasticPeak::findDetector() {
  throw Exception::NotImplementedError(
      "LeanElasticPeak has no detector information");
330
}
Whitfield, Ross's avatar
Whitfield, Ross committed
331
332
333
334
335
336
337
338

/**
 * 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.
 * @return true if the detector ID was found.
 */
339
340
341
bool LeanElasticPeak::findDetector(const InstrumentRayTracer &) {
  throw Exception::NotImplementedError(
      "LeanElasticPeak has no detector information");
Whitfield, Ross's avatar
Whitfield, Ross committed
342
343
}

344
345
346
/**
 Forwarding function. Exposes the detector position directly.
 */
347
348
349
Mantid::Kernel::V3D LeanElasticPeak::getDetectorPositionNoCheck() const {
  throw Exception::NotImplementedError(
      "LeanElasticPeak has no detector information");
350
351
352
353
354
355
}

/**
 Forwarding function. Exposes the detector position directly, but checks that
 the detector is not null before accessing its position. Throws if null.
 */
356
357
358
Mantid::Kernel::V3D LeanElasticPeak::getDetectorPosition() const {
  throw Exception::NotImplementedError(
      "LeanElasticPeak has no detector information");
359
360
}

361
Mantid::Kernel::Logger LeanElasticPeak::g_log("PeakLogger");
362
363
364

} // namespace DataObjects
} // namespace Mantid