PeakTest.h 15 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

Hahn, Steven's avatar
Hahn, Steven committed
22
23
24
25
26
27
28
29
30
31
32
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;
}
}

33
class PeakTest : public CxxTest::TestSuite {
34
private:
35
36
37
  /// Common instrument
  Instrument_sptr inst;
  Instrument_sptr m_minimalInstrument;
38

39
public:
40
41
  // This pair of boilerplate methods prevent the suite being created statically
  // This means the constructor isn't called when running other tests
42
  static PeakTest *createSuite() { return new PeakTest(); }
43
44
45
  static void destroySuite(PeakTest *suite) { delete suite; }

  // Constructor
46
47
  PeakTest()
      : inst(ComponentCreationHelper::createTestInstrumentRectangular(5, 100)) {
48

49
50
  }

51
  void test_constructor() {
52
53
54
55
56
57
    // 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)
58
59
    TS_ASSERT_EQUALS(p.getDetector()->getID(), 10000)
    TS_ASSERT_EQUALS(p.getInstrument(), inst)
60
    check_Contributing_Detectors(p, std::vector<int>(1, 10000));
61
62
  }

63
  void test_constructorHKL() {
64
    // detector IDs start at 10000
65
    Peak p(inst, 10000, 2.0, V3D(1, 2, 3));
66
67
68
69
70
71
    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)
72
    check_Contributing_Detectors(p, std::vector<int>(1, 10000));
73
74
  }

75
76
77
78
79
80
81
82
83
  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;

84
    // detector IDs start at 10000
85
86
87
    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);
88
89
90
91
92
93
    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)
94
    TS_ASSERT_EQUALS(p.getGoniometerMatrix(), mat);
95
    check_Contributing_Detectors(p, std::vector<int>(1, 10000));
96
97
  }

98
  void test_ConstructorFromIPeakInterface() {
99
    Peak p(inst, 10102, 2.0);
100
    p.setHKL(1, 2, 3);
101
102
103
    p.setRunNumber(1234);
    p.addContributingDetID(10103);

104
    const Mantid::Geometry::IPeak &ipeak = p;
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
    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);
  }

120
  void test_copyConstructor() {
121
    Peak p(inst, 10102, 2.0);
122
    p.setHKL(1, 2, 3);
123
124
125
126
127
128
129
130
131
132
    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());
133
134
    TS_ASSERT_EQUALS(p.getDetector(), p2.getDetector());
    TS_ASSERT_EQUALS(p.getInstrument(), p2.getInstrument());
135
136
    TS_ASSERT_EQUALS(p.getPeakShape().shapeName(),
                     p2.getPeakShape().shapeName());
137
    check_Contributing_Detectors(p2, std::vector<int>(1, 10102));
138
139
  }

140
  void test_getValueByColName() {
141
    Peak p(inst, 10102, 2.0);
142
    p.setHKL(1, 2, 3);
143
144
145
146
147
148
149
150
    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())
151
    TS_ASSERT_THROWS_ANYTHING(p.getValueByColName("bankname"));
152
153
  }

154
  /** Set the wavelength and see the other "versions" of it get calculated. */
155
156
  void test_wavelength_conversion() {
    // 1 angstroms wavelength, and at the opposite corner of the detector
157
158
    Peak p(inst, 19999, 1.0);
    // Energy in meV
159
160
    TS_ASSERT_DELTA(p.getInitialEnergy(), 81.805, 1e-3) // Conversion table at :
    // www.ncnr.nist.gov/instruments/dcs/dcs_usersguide/Conversion_Factors.pdf
161
    TS_ASSERT_DELTA(p.getFinalEnergy(), p.getInitialEnergy(), 1e-5)
162
163
164
    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
165
    TS_ASSERT_DELTA(p.getDSpacing(), d, 1e-3);
166
167
168
169
    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);
170
171
  }

172
  void test_badDetectorID_throws() {
173
    Peak p(inst, 10000, 2.0);
174
    TS_ASSERT_THROWS_ANYTHING(p.setDetectorID(7));
175
  }
176

177
178
  void
  test_setDetector_Adds_ID_To_Contributing_List_And_Does_Not_Remove_Old_From_Contrib_List() {
179
180
181
182
    int expectedIDs[2] = {10000, 10001};
    Peak peak(inst, expectedIDs[0], 2.0);
    peak.setDetectorID(expectedIDs[1]);

183
184
    check_Contributing_Detectors(
        peak, std::vector<int>(expectedIDs, expectedIDs + 2));
185
186
  }

187
  void test_runNumber() {
188
189
    Peak p(inst, 10000, 2.0);
    p.setRunNumber(12345);
190
    TS_ASSERT_EQUALS(p.getRunNumber(), 12345);
191
192
  }

193
  void test_GoniometerMatrix() {
194
    Peak p(inst, 10000, 2.0);
195
196
197
198
199
200
201
202
203
204
205
206
207
    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);
208
    // Matrix must be 3x3
209
210
    Matrix<double> mat2(4, 3);
    TS_ASSERT_THROWS_ANYTHING(p.setGoniometerMatrix(mat2));
211
212
  }

213
  void test_HKL() {
214
215
    Peak p(inst, 10000, 2.0);
    p.setHKL(1.0, 2.0, 3.0);
216
217
218
    TS_ASSERT_EQUALS(p.getH(), 1.0);
    TS_ASSERT_EQUALS(p.getK(), 2.0);
    TS_ASSERT_EQUALS(p.getL(), 3.0);
219
220
221
    p.setH(5);
    p.setK(6);
    p.setL(7);
222
223
224
    TS_ASSERT_EQUALS(p.getH(), 5.0);
    TS_ASSERT_EQUALS(p.getK(), 6.0);
    TS_ASSERT_EQUALS(p.getL(), 7.0);
225
    p.setHKL(V3D(1.0, 2.0, 3.0));
226
227
228
229
    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));
230
231
  }

232
  void test_getBank_and_row() {
233
234
235
236
    Peak p(inst, 10000, 2.0);
    TS_ASSERT_EQUALS(p.getBankName(), "bank1")
    TS_ASSERT_EQUALS(p.getRow(), 0)
    TS_ASSERT_EQUALS(p.getCol(), 0)
237
238
239
240
241
242
    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)
243
244
  }

245
  void test_getQSampleFrame() {
246
    // Peak 3 is phi,chi,omega of 90,0,0; giving this matrix:
247
    Matrix<double> r2(3, 3, false);
248
249
250
251
252
253
254
255
256
257
258
    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();
259
260
    // If we re-rotate q in the sample frame by the gonio matrix, we should get
    // q in the lab frame
261
262
263
264
265
266
    V3D qSampleRotated = r2 * qSample;

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

267
268
  //------------------------------------------------------------------------------------
  /** Can't have Q = 0,0,0 or 0 in the Z direction when creating */
269
  void test_setQLabFrame_ThrowsIfQIsNull() {
270
    Peak p1(inst, 10000, 2.0);
271
    const boost::optional<double> distance = 1.0;
272
273
    TS_ASSERT_THROWS_ANYTHING(Peak p2(inst, V3D(0, 0, 0), distance));
    TS_ASSERT_THROWS_ANYTHING(Peak p2(inst, V3D(1, 2, 0), distance));
274
275
276
  }

  /** Compare two peaks, but not the detector IDs etc. */
277
278
279
280
281
282
283
284
285
286
287
288
289
290
  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));
291
292
293
  }

  /** Create peaks using Q in the lab frame */
294
  void test_setQLabFrame() {
295
296
297
298
299
    Peak p1(inst, 19999, 2.0);
    V3D Qlab1 = p1.getQLabFrame();
    V3D detPos1 = p1.getDetPos();

    // Construct using just Q
300
    Peak p2(inst, Qlab1, boost::optional<double>(detPos1.norm()));
301
    comparePeaks(p1, p2);
302
303
304
305
    TS_ASSERT_EQUALS(p2.getBankName(), "None");
    TS_ASSERT_EQUALS(p2.getRow(), -1);
    TS_ASSERT_EQUALS(p2.getCol(), -1);
    TS_ASSERT_EQUALS(p2.getDetectorID(), -1);
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
331
332
333
334
335
336
337
338
339
340
341
  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());
342
343
  }

344
  /** Create peaks using Q in sample frame + a goniometer rotation matrix*/
345
  void test_setQSampleFrame() {
346
    // A goniometer rotation matrix
347
    Matrix<double> r2(3, 3, false);
348
349
350
351
    r2[0][2] = 1;
    r2[1][1] = 1;
    r2[2][0] = -1;

352
    Peak p1(inst, 19999, 2.0, V3D(1, 2, 3), r2);
353
354
355
356
357
    V3D q = p1.getQSampleFrame();
    V3D detPos1 = p1.getDetPos();

    // Construct using Q + rotation matrix
    Peak p2(inst, q, r2, detPos1.norm());
358
    p2.setHKL(V3D(1, 2, 3)); // Make sure HKL matches too.
359
    comparePeaks(p1, p2);
360
361
362
363
    TS_ASSERT_EQUALS(p2.getBankName(), "None");
    TS_ASSERT_EQUALS(p2.getRow(), -1);
    TS_ASSERT_EQUALS(p2.getCol(), -1);
    TS_ASSERT_EQUALS(p2.getDetectorID(), -1);
364
365
  }

366
367
  /** Create peaks using Q in the lab frame,
   * then find the corresponding detector ID */
368
  void test_findDetector() {
369
370
371
372
373
    Peak p1(inst, 19999, 2.0);
    V3D Qlab1 = p1.getQLabFrame();
    V3D detPos1 = p1.getDetPos();

    // Construct using just Q
374
    Peak p2(inst, Qlab1, boost::optional<double>(detPos1.norm()));
375
    TS_ASSERT(p2.findDetector());
376
    comparePeaks(p1, p2);
377
378
379
380
    TS_ASSERT_EQUALS(p2.getBankName(), "bank1");
    TS_ASSERT_EQUALS(p2.getRow(), 99);
    TS_ASSERT_EQUALS(p2.getCol(), 99);
    TS_ASSERT_EQUALS(p2.getDetectorID(), 19999);
381
382
  }

383
  void test_getDetectorPosition() {
384
385
386
387
388
    const int detectorId = 19999;
    const double wavelength = 2;
    Peak p(inst, detectorId, wavelength);

    V3D a = p.getDetectorPosition();
Owen Arnold's avatar
Owen Arnold committed
389
    V3D b = p.getDetectorPositionNoCheck();
390
391
392
393

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

394
  void test_getDetectorPositionThrows() {
395
396
397
    const int detectorId = 19999;
    const double wavelength = 2;
    Peak p(inst, detectorId, wavelength);
398
399
400
401
402
403
404
    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 &);
405
406
  }

407
408
409
410
  void test_get_peak_shape_default() {
    Peak peak;
    const PeakShape &integratedShape = peak.getPeakShape();
    TS_ASSERT_EQUALS("none", integratedShape.shapeName());
411
412
  }

413
414
  void test_set_peak_shape() {
    using namespace testing;
415

416
    Peak peak;
417

418
419
420
    MockPeakShape *replacementShape = new MockPeakShape;
    EXPECT_CALL(*replacementShape, shapeName()).Times(1);
    peak.setPeakShape(replacementShape);
421

422
423
    const PeakShape &currentShape = peak.getPeakShape();
    currentShape.shapeName();
424

425
    TS_ASSERT(Mock::VerifyAndClearExpectations(replacementShape));
426
427
  }

428
private:
429
430
  void check_Contributing_Detectors(const Peak &peak,
                                    const std::vector<int> &expected) {
431
    auto peakIDs = peak.getContributingDetIDs();
432
    for (auto it = expected.begin(); it != expected.end(); ++it) {
433
      const int id = *it;
434
435
436
      TSM_ASSERT_EQUALS("Expected " + boost::lexical_cast<std::string>(id) +
                            " in contribution list",
                        1, peakIDs.count(id))
437
438
    }
  }
439
440
441
};

#endif /* MANTID_DATAOBJECTS_PEAKTEST_H_ */