PeakTest.h 21.1 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
// SPDX - License - Identifier: GPL - 3.0 +
7
8
9
#ifndef MANTID_DATAOBJECTS_PEAKTEST_H_
#define MANTID_DATAOBJECTS_PEAKTEST_H_

LamarMoore's avatar
LamarMoore committed
10
11
#include "MantidGeometry/Instrument/ReferenceFrame.h"
#include "MantidKernel/PhysicalConstants.h"
12
#include "MantidKernel/System.h"
LamarMoore's avatar
LamarMoore committed
13
#include "MantidKernel/Timer.h"
14
#include "MantidKernel/Unit.h"
LamarMoore's avatar
LamarMoore committed
15
#include "MantidKernel/UnitFactory.h"
16
#include "MantidKernel/V3D.h"
17
#include "MantidKernel/make_unique.h"
LamarMoore's avatar
LamarMoore committed
18
19
#include "MockObjects.h"
#include <cxxtest/TestSuite.h>
20
#include <gmock/gmock.h>
21
22

#include "MantidDataObjects/Peak.h"
23
#include "MantidTestHelpers/ComponentCreationHelper.h"
24
25

using namespace Mantid::DataObjects;
26
27
using namespace Mantid::Geometry;
using namespace Mantid::Kernel;
28

Hahn, Steven's avatar
Hahn, Steven committed
29
30
31
32
33
34
35
36
37
namespace boost {
template <class CharType, class CharTrait>
std::basic_ostream<CharType, CharTrait> &
operator<<(std::basic_ostream<CharType, CharTrait> &out,
           optional<double> const &maybe) {
  if (maybe)
    out << maybe;
  return out;
}
LamarMoore's avatar
LamarMoore committed
38
} // namespace boost
Hahn, Steven's avatar
Hahn, Steven committed
39

40
class PeakTest : public CxxTest::TestSuite {
41
private:
42
43
44
  /// Common instrument
  Instrument_sptr inst;
  Instrument_sptr m_minimalInstrument;
45

46
public:
47
48
  // This pair of boilerplate methods prevent the suite being created statically
  // This means the constructor isn't called when running other tests
49
  static PeakTest *createSuite() { return new PeakTest(); }
50
51
52
  static void destroySuite(PeakTest *suite) { delete suite; }

  // Constructor
53
54
  PeakTest()
      : inst(ComponentCreationHelper::createTestInstrumentRectangular(5, 100)) {
55

56
57
  }

58
  void test_constructor() {
59
60
61
62
63
64
    // detector IDs start at 10000
    Peak p(inst, 10000, 2.0);
    TS_ASSERT_DELTA(p.getH(), 0.0, 1e-5)
    TS_ASSERT_DELTA(p.getK(), 0.0, 1e-5)
    TS_ASSERT_DELTA(p.getL(), 0.0, 1e-5)
    TS_ASSERT_EQUALS(p.getDetectorID(), 10000)
65
66
    TS_ASSERT_EQUALS(p.getDetector()->getID(), 10000)
    TS_ASSERT_EQUALS(p.getInstrument(), inst)
67
    check_Contributing_Detectors(p, std::vector<int>(1, 10000));
68
69
  }

70
  void test_constructorHKL() {
71
    // detector IDs start at 10000
72
    Peak p(inst, 10000, 2.0, V3D(1, 2, 3));
73
74
75
76
77
78
    TS_ASSERT_DELTA(p.getH(), 1.0, 1e-5)
    TS_ASSERT_DELTA(p.getK(), 2.0, 1e-5)
    TS_ASSERT_DELTA(p.getL(), 3.0, 1e-5)
    TS_ASSERT_EQUALS(p.getDetectorID(), 10000)
    TS_ASSERT_EQUALS(p.getDetector()->getID(), 10000)
    TS_ASSERT_EQUALS(p.getInstrument(), inst)
79
    check_Contributing_Detectors(p, std::vector<int>(1, 10000));
80
81
  }

82
83
84
85
86
87
88
89
90
  void test_constructorHKLGon() {
    Matrix<double> mats(3, 3), mat(3, 3);
    for (int x = 0; x < 3; x++)
      for (int y = 0; y < 3; y++)
        mats[x][y] = 1.0 * x + 1.0 * y;
    mat[0][0] = 1.0;
    mat[1][2] = 1.0;
    mat[2][1] = 1.0;

91
    // detector IDs start at 10000
92
93
94
    TS_ASSERT_THROWS_ANYTHING(Peak ps(inst, 10000, 2.0, V3D(1, 2, 3), mats);)
    TS_ASSERT_THROWS_NOTHING(Peak p(inst, 10000, 2.0, V3D(1, 2, 3), mat);)
    Peak p(inst, 10000, 2.0, V3D(1, 2, 3), mat);
95
96
97
98
99
100
    TS_ASSERT_DELTA(p.getH(), 1.0, 1e-5)
    TS_ASSERT_DELTA(p.getK(), 2.0, 1e-5)
    TS_ASSERT_DELTA(p.getL(), 3.0, 1e-5)
    TS_ASSERT_EQUALS(p.getDetectorID(), 10000)
    TS_ASSERT_EQUALS(p.getDetector()->getID(), 10000)
    TS_ASSERT_EQUALS(p.getInstrument(), inst)
101
    TS_ASSERT_EQUALS(p.getGoniometerMatrix(), mat);
102
    check_Contributing_Detectors(p, std::vector<int>(1, 10000));
103
104
  }

105
  void test_ConstructorFromIPeakInterface() {
106
    Peak p(inst, 10102, 2.0);
107
    p.setHKL(1, 2, 3);
108
109
110
    p.setRunNumber(1234);
    p.addContributingDetID(10103);

111
    const Mantid::Geometry::IPeak &ipeak = p;
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
    Peak p2(ipeak);
    TS_ASSERT_EQUALS(p.getRow(), p2.getRow());
    TS_ASSERT_EQUALS(p.getCol(), p2.getCol());
    TS_ASSERT_EQUALS(p.getH(), p2.getH());
    TS_ASSERT_EQUALS(p.getK(), p2.getK());
    TS_ASSERT_EQUALS(p.getL(), p2.getL());
    TS_ASSERT_EQUALS(p.getGoniometerMatrix(), p2.getGoniometerMatrix());
    TS_ASSERT_EQUALS(p.getRunNumber(), p2.getRunNumber());
    TS_ASSERT_EQUALS(p.getDetector(), p2.getDetector())
    TS_ASSERT_EQUALS(p.getInstrument(), p2.getInstrument())
    auto expectedIDs = std::vector<int>(2, 10102);
    expectedIDs[1] = 10103;
    check_Contributing_Detectors(p2, expectedIDs);
  }

127
  void test_copyConstructor() {
128
    Peak p(inst, 10102, 2.0);
129
    p.setHKL(1, 2, 3);
130
131
132
133
134
135
136
137
138
139
    p.setRunNumber(1234);
    // Default (not-explicit) copy constructor
    Peak p2(p);
    TS_ASSERT_EQUALS(p.getRow(), p2.getRow());
    TS_ASSERT_EQUALS(p.getCol(), p2.getCol());
    TS_ASSERT_EQUALS(p.getH(), p2.getH());
    TS_ASSERT_EQUALS(p.getK(), p2.getK());
    TS_ASSERT_EQUALS(p.getL(), p2.getL());
    TS_ASSERT_EQUALS(p.getGoniometerMatrix(), p2.getGoniometerMatrix());
    TS_ASSERT_EQUALS(p.getRunNumber(), p2.getRunNumber());
140
141
    TS_ASSERT_EQUALS(p.getDetector(), p2.getDetector());
    TS_ASSERT_EQUALS(p.getInstrument(), p2.getInstrument());
142
143
    TS_ASSERT_EQUALS(p.getPeakShape().shapeName(),
                     p2.getPeakShape().shapeName());
144
    check_Contributing_Detectors(p2, std::vector<int>(1, 10102));
145
146
  }

147
  void test_getValueByColName() {
148
    Peak p(inst, 10102, 2.0);
149
    p.setHKL(1, 2, 3);
150
151
152
153
154
155
156
157
    p.setRunNumber(1234);
    TS_ASSERT_EQUALS(p.getValueByColName("Row"), p.getRow());
    TS_ASSERT_EQUALS(p.getValueByColName("Col"), p.getCol());
    TS_ASSERT_EQUALS(p.getValueByColName("H"), p.getH());
    TS_ASSERT_EQUALS(p.getValueByColName("K"), p.getK());
    TS_ASSERT_EQUALS(p.getValueByColName("L"), p.getL());
    TS_ASSERT_EQUALS(p.getValueByColName("RunNumber"), p.getRunNumber());
    TS_ASSERT_EQUALS(p.getValueByColName("DetId"), p.getDetectorID())
158
    TS_ASSERT_THROWS_ANYTHING(p.getValueByColName("bankname"));
159
160
  }

161
  /** Set the wavelength and see the other "versions" of it get calculated. */
162
163
  void test_wavelength_conversion() {
    // 1 angstroms wavelength, and at the opposite corner of the detector
164
165
    Peak p(inst, 19999, 1.0);
    // Energy in meV
166
167
    TS_ASSERT_DELTA(p.getInitialEnergy(), 81.805, 1e-3) // Conversion table at :
    // www.ncnr.nist.gov/instruments/dcs/dcs_usersguide/Conversion_Factors.pdf
168
    TS_ASSERT_DELTA(p.getFinalEnergy(), p.getInitialEnergy(), 1e-5)
169
170
171
    V3D dp = p.getDetPos();
    double tt = dp.angle(V3D(0, 0, 1));
    double d = 0.5 / sin(0.5 * tt); // d=lambda/2/sin(theta)=4.5469
172
    TS_ASSERT_DELTA(p.getDSpacing(), d, 1e-3);
173
174
175
176
    TS_ASSERT_DELTA(p.getTOF(), 3823, 1);

    // Back-converting to wavelength should give you the same.
    TS_ASSERT_DELTA(p.getWavelength(), 1.00, 1e-2);
177
178
  }

179
  void test_badDetectorID_throws() {
180
    Peak p(inst, 10000, 2.0);
181
    TS_ASSERT_THROWS_ANYTHING(p.setDetectorID(7));
182
  }
183

184
185
  void
  test_setDetector_Adds_ID_To_Contributing_List_And_Does_Not_Remove_Old_From_Contrib_List() {
186
187
188
189
    int expectedIDs[2] = {10000, 10001};
    Peak peak(inst, expectedIDs[0], 2.0);
    peak.setDetectorID(expectedIDs[1]);

190
191
    check_Contributing_Detectors(
        peak, std::vector<int>(expectedIDs, expectedIDs + 2));
192
193
  }

194
  void test_runNumber() {
195
196
    Peak p(inst, 10000, 2.0);
    p.setRunNumber(12345);
197
    TS_ASSERT_EQUALS(p.getRunNumber(), 12345);
198
199
  }

200
  void test_GoniometerMatrix() {
201
    Peak p(inst, 10000, 2.0);
202
203
204
205
206
207
208
209
210
211
212
213
214
    Matrix<double> mats(3, 3), mat(3, 3);
    for (int x = 0; x < 3; x++)
      for (int y = 0; y < 3; y++)
        mats[x][y] = 1.0 * x + 1.0 * y;
    TS_ASSERT_THROWS_ANYTHING(p.setGoniometerMatrix(mats)); // matrix is
                                                            // singular
    TS_ASSERT_EQUALS(p.getGoniometerMatrix(), mats);
    mat[0][0] = 1.0;
    mat[1][2] = 1.0;
    mat[2][1] = 1.0;
    TS_ASSERT_THROWS_NOTHING(
        p.setGoniometerMatrix(mat)); // matrix is not singular
    TS_ASSERT_EQUALS(p.getGoniometerMatrix(), mat);
215
    // Matrix must be 3x3
216
217
    Matrix<double> mat2(4, 3);
    TS_ASSERT_THROWS_ANYTHING(p.setGoniometerMatrix(mat2));
218
219
  }

220
  void test_HKL() {
221
222
    Peak p(inst, 10000, 2.0);
    p.setHKL(1.0, 2.0, 3.0);
223
224
225
    TS_ASSERT_EQUALS(p.getH(), 1.0);
    TS_ASSERT_EQUALS(p.getK(), 2.0);
    TS_ASSERT_EQUALS(p.getL(), 3.0);
226
227
228
    p.setH(5);
    p.setK(6);
    p.setL(7);
229
230
231
    TS_ASSERT_EQUALS(p.getH(), 5.0);
    TS_ASSERT_EQUALS(p.getK(), 6.0);
    TS_ASSERT_EQUALS(p.getL(), 7.0);
232
    p.setHKL(V3D(1.0, 2.0, 3.0));
233
234
235
236
    TS_ASSERT_EQUALS(p.getH(), 1.0);
    TS_ASSERT_EQUALS(p.getK(), 2.0);
    TS_ASSERT_EQUALS(p.getL(), 3.0);
    TS_ASSERT_EQUALS(p.getHKL(), V3D(1.0, 2.0, 3.0));
237
238
  }

239
  void test_getBank_and_row() {
240
241
242
243
    Peak p(inst, 10000, 2.0);
    TS_ASSERT_EQUALS(p.getBankName(), "bank1")
    TS_ASSERT_EQUALS(p.getRow(), 0)
    TS_ASSERT_EQUALS(p.getCol(), 0)
244
245
246
247
248
249
    p.setDetectorID(10050);
    TS_ASSERT_EQUALS(p.getRow(), 50)
    TS_ASSERT_EQUALS(p.getCol(), 0)
    p.setDetectorID(10100);
    TS_ASSERT_EQUALS(p.getRow(), 0)
    TS_ASSERT_EQUALS(p.getCol(), 1)
250
251
  }

252
  void test_getQSampleFrame() {
253
    // Peak 3 is phi,chi,omega of 90,0,0; giving this matrix:
254
    Matrix<double> r2(3, 3, false);
255
256
257
258
259
260
261
262
263
264
265
    r2[0][2] = 1;
    r2[1][1] = 1;
    r2[2][0] = -1;

    Peak p(inst, 10000, 2.0);
    p.setGoniometerMatrix(r2);

    // Q in the lab frame
    V3D qLab = p.getQLabFrame();
    // q in the sample frame.
    V3D qSample = p.getQSampleFrame();
266
267
    // If we re-rotate q in the sample frame by the gonio matrix, we should get
    // q in the lab frame
268
269
270
271
272
273
    V3D qSampleRotated = r2 * qSample;

    // Did the peak properly invert the rotation matrix?
    TS_ASSERT_EQUALS(qLab, qSampleRotated);
  }

Samuel Jackson's avatar
Samuel Jackson committed
274
  void test_getQLabFrame() {
275
276
277
278
279
280
281
282
283
    Instrument_sptr inst =
        ComponentCreationHelper::createTestInstrumentRectangular2(1, 10);
    Peak p(inst, 0, 1.5);
    p.setQLabFrame(V3D(1, 1, 1));
    auto q = p.getQLabFrame();
    // should be the same
    TS_ASSERT_DELTA(q[0], 1, 1e-5);
    TS_ASSERT_DELTA(q[1], 1, 1e-5);
    TS_ASSERT_DELTA(q[2], 1, 1e-5);
Samuel Jackson's avatar
Samuel Jackson committed
284
285
  }

286
287
  //------------------------------------------------------------------------------------
  /** Can't have Q = 0,0,0 or 0 in the Z direction when creating */
288
  void test_setQLabFrame_ThrowsIfQIsNull() {
289
    Peak p1(inst, 10000, 2.0);
290
    const boost::optional<double> distance = 1.0;
291
292
    TS_ASSERT_THROWS_ANYTHING(Peak p2(inst, V3D(0, 0, 0), distance));
    TS_ASSERT_THROWS_ANYTHING(Peak p2(inst, V3D(1, 2, 0), distance));
293
294
295
  }

  /** Compare two peaks, but not the detector IDs etc. */
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  void comparePeaks(Peak &p1, Peak &p2) {
    // TODO. Peak should implement bool operator==(const Peak&) and that should
    // be tested, rather than having external functionality here.
    TS_ASSERT_EQUALS(p1.getQLabFrame(), p2.getQLabFrame());
    TS_ASSERT_EQUALS(p1.getQSampleFrame(), p2.getQSampleFrame());
    TS_ASSERT_EQUALS(p1.getDetPos(), p2.getDetPos());
    TS_ASSERT_EQUALS(p1.getHKL(), p2.getHKL());
    TS_ASSERT_DELTA(p1.getWavelength(), p2.getWavelength(), 1e-5);
    TS_ASSERT_DELTA(p1.getL1(), p2.getL1(), 1e-5);
    TS_ASSERT_DELTA(p1.getL2(), p2.getL2(), 1e-5);
    TS_ASSERT_DELTA(p1.getTOF(), p2.getTOF(), 1e-5);
    TS_ASSERT_DELTA(p1.getInitialEnergy(), p2.getInitialEnergy(), 1e-5);
    TS_ASSERT_DELTA(p1.getFinalEnergy(), p2.getFinalEnergy(), 1e-5);
    TS_ASSERT(p1.getGoniometerMatrix().equals(p2.getGoniometerMatrix(), 1e-5));
310
311
312
  }

  /** Create peaks using Q in the lab frame */
313
  void test_setQLabFrame() {
314
315
316
317
318
    Peak p1(inst, 19999, 2.0);
    V3D Qlab1 = p1.getQLabFrame();
    V3D detPos1 = p1.getDetPos();

    // Construct using just Q
319
    Peak p2(inst, Qlab1, boost::optional<double>(detPos1.norm()));
320
    comparePeaks(p1, p2);
321
322
323
324
    TS_ASSERT_EQUALS(p2.getBankName(), "None");
    TS_ASSERT_EQUALS(p2.getRow(), -1);
    TS_ASSERT_EQUALS(p2.getCol(), -1);
    TS_ASSERT_EQUALS(p2.getDetectorID(), -1);
325
326
  }

327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
  void test_setQLabFrame2() {
    // Create fictional instrument
    const V3D source(0, 0, 0);
    const V3D sample(15, 0, 0);
    const V3D detectorPos(20, 5, 0);
    const V3D beam1 = sample - source;
    const V3D beam2 = detectorPos - sample;
    auto minimalInstrument = ComponentCreationHelper::createMinimalInstrument(
        source, sample, detectorPos);

    // Derive distances and angles
    const double l1 = beam1.norm();
    const double l2 = beam2.norm();
    const V3D qLabDir = (beam1 / l1) - (beam2 / l2);

    const double microSecsInSec = 1e6;

    // Derive QLab for diffraction
    const double wavenumber_in_angstrom_times_tof_in_microsec =
        (Mantid::PhysicalConstants::NeutronMass * (l1 + l2) * 1e-10 *
         microSecsInSec) /
        Mantid::PhysicalConstants::h_bar;

    V3D qLab = qLabDir * wavenumber_in_angstrom_times_tof_in_microsec;

    Peak peak; // Everything will be default
    peak.setInstrument(
        minimalInstrument); // Can't do anything without the instrument
    peak.setQLabFrame(qLab);
    auto detector = peak.getDetector();

    TSM_ASSERT("No detector", detector);
    TS_ASSERT_EQUALS(1, detector->getID());
    TS_ASSERT_EQUALS(detectorPos, detector->getPos());
361
362
  }

363
  /** Create peaks using Q in sample frame + a goniometer rotation matrix*/
364
  void test_setQSampleFrame() {
365
    // A goniometer rotation matrix
366
    Matrix<double> r2(3, 3, false);
367
368
369
370
    r2[0][2] = 1;
    r2[1][1] = 1;
    r2[2][0] = -1;

371
    Peak p1(inst, 19999, 2.0, V3D(1, 2, 3), r2);
372
373
374
375
376
    V3D q = p1.getQSampleFrame();
    V3D detPos1 = p1.getDetPos();

    // Construct using Q + rotation matrix
    Peak p2(inst, q, r2, detPos1.norm());
377
    p2.setHKL(V3D(1, 2, 3)); // Make sure HKL matches too.
378
    comparePeaks(p1, p2);
379
380
381
382
    TS_ASSERT_EQUALS(p2.getBankName(), "None");
    TS_ASSERT_EQUALS(p2.getRow(), -1);
    TS_ASSERT_EQUALS(p2.getCol(), -1);
    TS_ASSERT_EQUALS(p2.getDetectorID(), -1);
383
384
  }

385
386
  void test_setQSampleFrameVirtualDetectorWithQLab() {
    constexpr auto radius = 10.;
387
388
389
390
    auto sphereInst =
        ComponentCreationHelper::createTestInstrumentRectangular(5, 100);
    auto extendedSpaceObj =
        ComponentCreationHelper::createSphere(10., V3D(0, 0, 0));
391
    auto extendedSpace = Mantid::Kernel::make_unique<ObjComponent>(
392
        "extended-detector-space", extendedSpaceObj, sphereInst.get());
393
    extendedSpace->setPos(V3D(0.0, 0.0, 0.0));
394
    sphereInst->add(extendedSpace.release());
395
396
397
398
    const auto refFrame = sphereInst->getReferenceFrame();
    const auto refBeamDir = refFrame->vecPointingAlongBeam();

    // test with & without extended detector space
399
    // extended space is a sphere, so all points should fall radius*detector
400
    // direction away from the detector direction with extended space
401
    auto testQ = [&](const V3D &q) {
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
      // Compute expected direction
      const auto qBeam = q.scalar_prod(refBeamDir);
      const double norm_q = q.norm();
      const double one_over_wl = (norm_q * norm_q) / (2.0 * qBeam);

      V3D detectorDir = q * -1.0;
      detectorDir[refFrame->pointingAlongBeam()] = one_over_wl - qBeam;
      detectorDir.normalize();

      // test without extended detector space
      // should be a unit vector in the direction of the virtual detector
      // position
      Peak peak1(inst, q);

      // skip tests for which Q actually does intersect with a valid detector
      if (peak1.getDetectorID() > 0) {
        return;
      }

      TS_ASSERT_EQUALS(peak1.getDetectorID(), -1)
      TS_ASSERT_EQUALS(peak1.getDetPos(), detectorDir)

      // test with extended detector space
      // should be the full vector to the virtual detector position
      Peak peak2(sphereInst, q);
      TS_ASSERT_EQUALS(peak2.getDetectorID(), -1)
      TS_ASSERT_EQUALS(peak2.getDetPos(), detectorDir * radius)
429
430
431
432
433
434
435
436
437
438
    };

    // Make hemisphere of q vectors to test
    std::vector<double> xDirections(20);
    std::vector<double> yDirections(20);
    std::vector<double> zDirections(10);

    // create x values of the range -1 to 1
    int index = 0;
    double startValue = -1;
439
440
441
    std::generate(
        xDirections.begin(), xDirections.end(),
        [&index, &startValue]() { return startValue + index++ * 0.1; });
442
443
444
445
446

    // create z values of the range 0.1 to 1
    // ignore negative z values as these are not physical!
    index = 0;
    startValue = 0.1;
447
448
449
    std::generate(
        zDirections.begin(), zDirections.end(),
        [&index, &startValue]() { return startValue + index++ * 0.1; });
450
451
452

    yDirections = xDirections;

453
454
455
456
    for (auto &x : xDirections) {
      for (auto &y : yDirections) {
        for (auto &z : zDirections) {
          testQ(V3D(x, y, z));
457
        }
458
      }
459
460
461
462
    }
  }

  void test_setQSampleFrameVirtualDetectorWithScatteringAngle() {
463
464
465
466
    auto sphereInst =
        ComponentCreationHelper::createTestInstrumentRectangular(5, 100);
    auto extendedSpaceObj =
        ComponentCreationHelper::createSphere(10., V3D(0, 0, 0));
467
    auto extendedSpace = Mantid::Kernel::make_unique<ObjComponent>(
468
        "extended-detector-space", extendedSpaceObj, sphereInst.get());
469
    extendedSpace->setPos(V3D(0.0, 0.0, 0.0));
470
    sphereInst->add(extendedSpace.release());
471
472

    // test with & without extended detector space
473
    // extended space is a sphere, so all points should fall radius*detector
474
    // direction away from the detector direction with extended space
Hahn, Steven's avatar
Hahn, Steven committed
475
    auto testTheta = [this, &sphereInst](const double theta) {
Hahn, Steven's avatar
Hahn, Steven committed
476
      constexpr auto radius = 10.;
477
478
479
480
481
482
483
484
485
486
487
488
489
      const auto expectedDir = V3D(sin(theta), 0., cos(theta));

      // test without extended detector space
      // should be {sin(theta), 0, cos(theta)}
      Peak p1(this->inst, theta, 2.0);
      V3D detPos1 = p1.getDetPos();
      TS_ASSERT_EQUALS(detPos1, expectedDir);

      // test with extended detector space
      // should be radius*{sin(theta), 0, cos(theta)}
      Peak p2(sphereInst, theta, 2.0);
      V3D detPos2 = p2.getDetPos();
      TS_ASSERT_EQUALS(detPos2, expectedDir * radius);
490
491
492
493
494
    };

    // generate & test a range of angles from 0 - 360
    int index = 0;
    std::vector<double> angles(8);
495
    std::generate(angles.begin(), angles.end(), [&index, &angles]() {
496
497
      return static_cast<double>(index++) * M_PI /
             static_cast<double>(angles.size());
498
    });
499
500
501
502

    std::for_each(angles.begin(), angles.end(), testTheta);
  }

503
504
  /** Create peaks using Q in the lab frame,
   * then find the corresponding detector ID */
505
  void test_findDetector() {
506
507
508
509
510
    Peak p1(inst, 19999, 2.0);
    V3D Qlab1 = p1.getQLabFrame();
    V3D detPos1 = p1.getDetPos();

    // Construct using just Q
511
    Peak p2(inst, Qlab1, boost::optional<double>(detPos1.norm()));
512
    TS_ASSERT(p2.findDetector());
513
    comparePeaks(p1, p2);
514
515
516
517
    TS_ASSERT_EQUALS(p2.getBankName(), "bank1");
    TS_ASSERT_EQUALS(p2.getRow(), 99);
    TS_ASSERT_EQUALS(p2.getCol(), 99);
    TS_ASSERT_EQUALS(p2.getDetectorID(), 19999);
518
519
  }

520
  void test_getDetectorPosition() {
521
522
523
524
525
    const int detectorId = 19999;
    const double wavelength = 2;
    Peak p(inst, detectorId, wavelength);

    V3D a = p.getDetectorPosition();
Owen Arnold's avatar
Owen Arnold committed
526
    V3D b = p.getDetectorPositionNoCheck();
527
528
529
530

    TSM_ASSERT_EQUALS("Results should be the same", a, b);
  }

531
  void test_getDetectorPositionThrows() {
532
533
534
    const int detectorId = 19999;
    const double wavelength = 2;
    Peak p(inst, detectorId, wavelength);
535
536
537
538
539
540
541
    TSM_ASSERT_THROWS_NOTHING("Nothing wrong here, detector is valid",
                              p.getDetectorPosition());
    p.setQLabFrame(
        V3D(1, 1, 1),
        1.0); // This sets the detector pointer to null and detector id to -1;
    TSM_ASSERT_THROWS("Detector is not valid", p.getDetectorPosition(),
                      Mantid::Kernel::Exception::NullPointerException &);
542
543
  }

544
545
546
547
  void test_get_peak_shape_default() {
    Peak peak;
    const PeakShape &integratedShape = peak.getPeakShape();
    TS_ASSERT_EQUALS("none", integratedShape.shapeName());
548
549
  }

550
551
  void test_set_peak_shape() {
    using namespace testing;
552

553
    Peak peak;
554

555
556
557
    MockPeakShape *replacementShape = new MockPeakShape;
    EXPECT_CALL(*replacementShape, shapeName()).Times(1);
    peak.setPeakShape(replacementShape);
558

559
560
    const PeakShape &currentShape = peak.getPeakShape();
    currentShape.shapeName();
561

562
    TS_ASSERT(Mock::VerifyAndClearExpectations(replacementShape));
563
564
  }

Samuel Jackson's avatar
Samuel Jackson committed
565
566
567
  void test_get_intensity_over_sigma() {
    const int detectorId = 19999;
    const double wavelength = 2;
568
569
    const double intensity{100};
    const double sigma{10};
Samuel Jackson's avatar
Samuel Jackson committed
570
571
572
573
574
    Peak p(inst, detectorId, wavelength);

    p.setIntensity(intensity);
    p.setSigmaIntensity(sigma);

575
    TS_ASSERT_EQUALS(p.getIntensityOverSigma(), intensity / sigma);
Samuel Jackson's avatar
Samuel Jackson committed
576
577
578
579
580
  }

  void test_get_intensity_over_sigma_empty_sigma() {
    const int detectorId = 19999;
    const double wavelength = 2;
581
    const double intensity{10};
582
    const double sigma{0};
Samuel Jackson's avatar
Samuel Jackson committed
583
584
585
586
587
    Peak p(inst, detectorId, wavelength);

    p.setIntensity(intensity);
    p.setSigmaIntensity(sigma);

588
589
    const double expectedResult{0.0};
    const double tolerance{1e-10};
590
    TS_ASSERT_DELTA(p.getIntensityOverSigma(), expectedResult, tolerance);
Samuel Jackson's avatar
Samuel Jackson committed
591
592
593
594
595
596
597
598
599
600
601
602
  }

  void test_get_energy() {
    const int detectorId = 19999;
    const double wavelength = 2;
    const double initialEnergy{100};
    const double finalEnergy{110};
    Peak p(inst, detectorId, wavelength);

    p.setInitialEnergy(initialEnergy);
    p.setFinalEnergy(finalEnergy);

Samuel Jackson's avatar
Samuel Jackson committed
603
    TS_ASSERT_EQUALS(p.getEnergyTransfer(), initialEnergy - finalEnergy);
Samuel Jackson's avatar
Samuel Jackson committed
604
605
  }

606
private:
607
608
  void check_Contributing_Detectors(const Peak &peak,
                                    const std::vector<int> &expected) {
609
    auto peakIDs = peak.getContributingDetIDs();
610
    for (int id : expected) {
611
612
613
      TSM_ASSERT_EQUALS("Expected " + boost::lexical_cast<std::string>(id) +
                            " in contribution list",
                        1, peakIDs.count(id))
614
615
    }
  }
616
617
618
};

#endif /* MANTID_DATAOBJECTS_PEAKTEST_H_ */