PeakTest.h 14.8 KB
Newer Older
1
2
3
4
#ifndef MANTID_DATAOBJECTS_PEAKTEST_H_
#define MANTID_DATAOBJECTS_PEAKTEST_H_

#include <cxxtest/TestSuite.h>
5
#include "MockObjects.h"
6
7
#include "MantidKernel/Timer.h"
#include "MantidKernel/System.h"
8
9
10
11
12
#include "MantidKernel/UnitFactory.h"
#include "MantidKernel/Unit.h"
#include "MantidKernel/V3D.h"
#include "MantidKernel/PhysicalConstants.h"
#include "MantidGeometry/Instrument/ReferenceFrame.h"
13
#include <gmock/gmock.h>
14
15

#include "MantidDataObjects/Peak.h"
16
#include "MantidTestHelpers/ComponentCreationHelper.h"
17
18

using namespace Mantid::DataObjects;
19
20
using namespace Mantid::Geometry;
using namespace Mantid::Kernel;
21

22
class PeakTest : public CxxTest::TestSuite {
23
private:
24
25
26
  /// Common instrument
  Instrument_sptr inst;
  Instrument_sptr m_minimalInstrument;
27

28
public:
29
30
  // This pair of boilerplate methods prevent the suite being created statically
  // This means the constructor isn't called when running other tests
31
  static PeakTest *createSuite() { return new PeakTest(); }
32
33
34
  static void destroySuite(PeakTest *suite) { delete suite; }

  // Constructor
35
36
  PeakTest()
      : inst(ComponentCreationHelper::createTestInstrumentRectangular(5, 100)) {
37

38
39
  }

40
  void test_constructor() {
41
42
43
44
45
46
    // 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)
47
48
    TS_ASSERT_EQUALS(p.getDetector()->getID(), 10000)
    TS_ASSERT_EQUALS(p.getInstrument(), inst)
49
    check_Contributing_Detectors(p, std::vector<int>(1, 10000));
50
51
  }

52
  void test_constructorHKL() {
53
    // detector IDs start at 10000
54
    Peak p(inst, 10000, 2.0, V3D(1, 2, 3));
55
56
57
58
59
60
    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)
61
    check_Contributing_Detectors(p, std::vector<int>(1, 10000));
62
63
  }

64
65
66
67
68
69
70
71
72
  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;

73
    // detector IDs start at 10000
74
75
76
    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);
77
78
79
80
81
82
    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)
83
    TS_ASSERT_EQUALS(p.getGoniometerMatrix(), mat);
84
    check_Contributing_Detectors(p, std::vector<int>(1, 10000));
85
86
  }

87
  void test_ConstructorFromIPeakInterface() {
88
    Peak p(inst, 10102, 2.0);
89
    p.setHKL(1, 2, 3);
90
91
92
    p.setRunNumber(1234);
    p.addContributingDetID(10103);

93
    const Mantid::Geometry::IPeak &ipeak = p;
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
    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);
  }

109
  void test_copyConstructor() {
110
    Peak p(inst, 10102, 2.0);
111
    p.setHKL(1, 2, 3);
112
113
114
115
116
117
118
119
120
121
    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());
122
123
    TS_ASSERT_EQUALS(p.getDetector(), p2.getDetector());
    TS_ASSERT_EQUALS(p.getInstrument(), p2.getInstrument());
124
125
    TS_ASSERT_EQUALS(p.getPeakShape().shapeName(),
                     p2.getPeakShape().shapeName());
126
    check_Contributing_Detectors(p2, std::vector<int>(1, 10102));
127
128
  }

129
  void test_getValueByColName() {
130
    Peak p(inst, 10102, 2.0);
131
    p.setHKL(1, 2, 3);
132
133
134
135
136
137
138
139
    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())
140
    TS_ASSERT_THROWS_ANYTHING(p.getValueByColName("bankname"));
141
142
  }

143
  /** Set the wavelength and see the other "versions" of it get calculated. */
144
145
  void test_wavelength_conversion() {
    // 1 angstroms wavelength, and at the opposite corner of the detector
146
147
    Peak p(inst, 19999, 1.0);
    // Energy in meV
148
149
    TS_ASSERT_DELTA(p.getInitialEnergy(), 81.805, 1e-3) // Conversion table at :
    // www.ncnr.nist.gov/instruments/dcs/dcs_usersguide/Conversion_Factors.pdf
150
    TS_ASSERT_DELTA(p.getFinalEnergy(), p.getInitialEnergy(), 1e-5)
151
152
153
    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
154
    TS_ASSERT_DELTA(p.getDSpacing(), d, 1e-3);
155
156
157
158
    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);
159
160
  }

161
  void test_badDetectorID_throws() {
162
    Peak p(inst, 10000, 2.0);
163
    TS_ASSERT_THROWS_ANYTHING(p.setDetectorID(7));
164
  }
165

166
167
  void
  test_setDetector_Adds_ID_To_Contributing_List_And_Does_Not_Remove_Old_From_Contrib_List() {
168
169
170
171
    int expectedIDs[2] = {10000, 10001};
    Peak peak(inst, expectedIDs[0], 2.0);
    peak.setDetectorID(expectedIDs[1]);

172
173
    check_Contributing_Detectors(
        peak, std::vector<int>(expectedIDs, expectedIDs + 2));
174
175
  }

176
  void test_runNumber() {
177
178
    Peak p(inst, 10000, 2.0);
    p.setRunNumber(12345);
179
    TS_ASSERT_EQUALS(p.getRunNumber(), 12345);
180
181
  }

182
  void test_GoniometerMatrix() {
183
    Peak p(inst, 10000, 2.0);
184
185
186
187
188
189
190
191
192
193
194
195
196
    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);
197
    // Matrix must be 3x3
198
199
    Matrix<double> mat2(4, 3);
    TS_ASSERT_THROWS_ANYTHING(p.setGoniometerMatrix(mat2));
200
201
  }

202
  void test_HKL() {
203
204
    Peak p(inst, 10000, 2.0);
    p.setHKL(1.0, 2.0, 3.0);
205
206
207
    TS_ASSERT_EQUALS(p.getH(), 1.0);
    TS_ASSERT_EQUALS(p.getK(), 2.0);
    TS_ASSERT_EQUALS(p.getL(), 3.0);
208
209
210
    p.setH(5);
    p.setK(6);
    p.setL(7);
211
212
213
    TS_ASSERT_EQUALS(p.getH(), 5.0);
    TS_ASSERT_EQUALS(p.getK(), 6.0);
    TS_ASSERT_EQUALS(p.getL(), 7.0);
214
    p.setHKL(V3D(1.0, 2.0, 3.0));
215
216
217
218
    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));
219
220
  }

221
  void test_getBank_and_row() {
222
223
224
225
    Peak p(inst, 10000, 2.0);
    TS_ASSERT_EQUALS(p.getBankName(), "bank1")
    TS_ASSERT_EQUALS(p.getRow(), 0)
    TS_ASSERT_EQUALS(p.getCol(), 0)
226
227
228
229
230
231
    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)
232
233
  }

234
  void test_getQSampleFrame() {
235
    // Peak 3 is phi,chi,omega of 90,0,0; giving this matrix:
236
    Matrix<double> r2(3, 3, false);
237
238
239
240
241
242
243
244
245
246
247
    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();
248
249
    // If we re-rotate q in the sample frame by the gonio matrix, we should get
    // q in the lab frame
250
251
252
253
254
255
    V3D qSampleRotated = r2 * qSample;

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

256
257
  //------------------------------------------------------------------------------------
  /** Can't have Q = 0,0,0 or 0 in the Z direction when creating */
258
  void test_setQLabFrame_ThrowsIfQIsNull() {
259
    Peak p1(inst, 10000, 2.0);
260
    const boost::optional<double> distance = 1.0;
261
262
    TS_ASSERT_THROWS_ANYTHING(Peak p2(inst, V3D(0, 0, 0), distance));
    TS_ASSERT_THROWS_ANYTHING(Peak p2(inst, V3D(1, 2, 0), distance));
263
264
265
  }

  /** Compare two peaks, but not the detector IDs etc. */
266
267
268
269
270
271
272
273
274
275
276
277
278
279
  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));
280
281
282
  }

  /** Create peaks using Q in the lab frame */
283
  void test_setQLabFrame() {
284
285
286
287
288
    Peak p1(inst, 19999, 2.0);
    V3D Qlab1 = p1.getQLabFrame();
    V3D detPos1 = p1.getDetPos();

    // Construct using just Q
289
    Peak p2(inst, Qlab1, boost::optional<double>(detPos1.norm()));
290
    comparePeaks(p1, p2);
291
292
293
294
    TS_ASSERT_EQUALS(p2.getBankName(), "None");
    TS_ASSERT_EQUALS(p2.getRow(), -1);
    TS_ASSERT_EQUALS(p2.getCol(), -1);
    TS_ASSERT_EQUALS(p2.getDetectorID(), -1);
295
296
  }

297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  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());
331
332
  }

333
  /** Create peaks using Q in sample frame + a goniometer rotation matrix*/
334
  void test_setQSampleFrame() {
335
    // A goniometer rotation matrix
336
    Matrix<double> r2(3, 3, false);
337
338
339
340
    r2[0][2] = 1;
    r2[1][1] = 1;
    r2[2][0] = -1;

341
    Peak p1(inst, 19999, 2.0, V3D(1, 2, 3), r2);
342
343
344
345
346
    V3D q = p1.getQSampleFrame();
    V3D detPos1 = p1.getDetPos();

    // Construct using Q + rotation matrix
    Peak p2(inst, q, r2, detPos1.norm());
347
    p2.setHKL(V3D(1, 2, 3)); // Make sure HKL matches too.
348
    comparePeaks(p1, p2);
349
350
351
352
    TS_ASSERT_EQUALS(p2.getBankName(), "None");
    TS_ASSERT_EQUALS(p2.getRow(), -1);
    TS_ASSERT_EQUALS(p2.getCol(), -1);
    TS_ASSERT_EQUALS(p2.getDetectorID(), -1);
353
354
  }

355
356
  /** Create peaks using Q in the lab frame,
   * then find the corresponding detector ID */
357
  void test_findDetector() {
358
359
360
361
362
    Peak p1(inst, 19999, 2.0);
    V3D Qlab1 = p1.getQLabFrame();
    V3D detPos1 = p1.getDetPos();

    // Construct using just Q
363
    Peak p2(inst, Qlab1, boost::optional<double>(detPos1.norm()));
364
    TS_ASSERT(p2.findDetector());
365
    comparePeaks(p1, p2);
366
367
368
369
    TS_ASSERT_EQUALS(p2.getBankName(), "bank1");
    TS_ASSERT_EQUALS(p2.getRow(), 99);
    TS_ASSERT_EQUALS(p2.getCol(), 99);
    TS_ASSERT_EQUALS(p2.getDetectorID(), 19999);
370
371
  }

372
  void test_getDetectorPosition() {
373
374
375
376
377
    const int detectorId = 19999;
    const double wavelength = 2;
    Peak p(inst, detectorId, wavelength);

    V3D a = p.getDetectorPosition();
Owen Arnold's avatar
Owen Arnold committed
378
    V3D b = p.getDetectorPositionNoCheck();
379
380
381
382

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

383
  void test_getDetectorPositionThrows() {
384
385
386
    const int detectorId = 19999;
    const double wavelength = 2;
    Peak p(inst, detectorId, wavelength);
387
388
389
390
391
392
393
    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 &);
394
395
  }

396
397
398
399
  void test_get_peak_shape_default() {
    Peak peak;
    const PeakShape &integratedShape = peak.getPeakShape();
    TS_ASSERT_EQUALS("none", integratedShape.shapeName());
400
401
  }

402
403
  void test_set_peak_shape() {
    using namespace testing;
404

405
    Peak peak;
406

407
408
409
    MockPeakShape *replacementShape = new MockPeakShape;
    EXPECT_CALL(*replacementShape, shapeName()).Times(1);
    peak.setPeakShape(replacementShape);
410

411
412
    const PeakShape &currentShape = peak.getPeakShape();
    currentShape.shapeName();
413

414
    TS_ASSERT(Mock::VerifyAndClearExpectations(replacementShape));
415
416
  }

417
private:
418
419
  void check_Contributing_Detectors(const Peak &peak,
                                    const std::vector<int> &expected) {
420
    auto peakIDs = peak.getContributingDetIDs();
421
    for (auto it = expected.begin(); it != expected.end(); ++it) {
422
      const int id = *it;
423
424
425
      TSM_ASSERT_EQUALS("Expected " + boost::lexical_cast<std::string>(id) +
                            " in contribution list",
                        1, peakIDs.count(id))
426
427
    }
  }
428
429
430
};

#endif /* MANTID_DATAOBJECTS_PEAKTEST_H_ */