RebinTest.h 34.9 KB
Newer Older
1
2
3
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4
5
//   NScD Oak Ridge National Laboratory, European Spallation Source,
//   Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6
// SPDX - License - Identifier: GPL - 3.0 +
7
#pragma once
8

Dickon Champion's avatar
re #93    
Dickon Champion committed
9
#include <cxxtest/TestSuite.h>
10
11

#include "MantidAPI/AnalysisDataService.h"
12
#include "MantidAPI/RefAxis.h"
13
#include "MantidAPI/ScopedWorkspace.h"
14
15
#include "MantidAPI/SpectraAxis.h"
#include "MantidAPI/WorkspaceProperty.h"
16
#include "MantidAlgorithms/CreateWorkspace.h"
17
18
19
20
21
#include "MantidAlgorithms/MaskBins.h"
#include "MantidAlgorithms/Rebin.h"
#include "MantidDataObjects/EventWorkspace.h"
#include "MantidDataObjects/Workspace2D.h"
#include "MantidHistogramData/LinearGenerator.h"
22
23
#include "MantidTestHelpers/ParallelAlgorithmCreation.h"
#include "MantidTestHelpers/ParallelRunner.h"
24
#include "MantidTestHelpers/WorkspaceCreationHelper.h"
25

26
27
#include <numeric>

Nick Draper's avatar
re #100    
Nick Draper committed
28
using namespace Mantid;
29
30
31
32
using namespace Mantid::Kernel;
using namespace Mantid::DataObjects;
using namespace Mantid::API;
using namespace Mantid::Algorithms;
33
using Mantid::HistogramData::BinEdges;
LamarMoore's avatar
LamarMoore committed
34
using Mantid::HistogramData::Counts;
35
using Mantid::HistogramData::CountStandardDeviations;
36

37
38
namespace {

Samuel Jones's avatar
Samuel Jones committed
39
std::unique_ptr<Rebin> prepare_rebin(const Parallel::Communicator &comm, const std::string &storageMode) {
40
41
42
  auto create = ParallelTestHelpers::create<Algorithms::CreateWorkspace>(comm);
  std::vector<double> dataEYX(2000);
  for (size_t i = 0; i < dataEYX.size(); ++i)
43
    dataEYX[i] = static_cast<double>(i % 2);
44
45
46
47
48
49
50
51
52
53
54
55
56
  int nspec = 1000;
  create->setProperty<int>("NSpec", nspec);
  create->setProperty<std::vector<double>>("DataX", dataEYX);
  create->setProperty<std::vector<double>>("DataY", dataEYX);
  create->setProperty<std::vector<double>>("DataE", dataEYX);
  create->setProperty("ParallelStorageMode", storageMode);
  create->execute();
  MatrixWorkspace_sptr ws = create->getProperty("OutputWorkspace");
  auto rebin = ParallelTestHelpers::create<Algorithms::Rebin>(comm);
  rebin->setProperty("InputWorkspace", ws);
  return rebin;
}

Samuel Jones's avatar
Samuel Jones committed
57
void run_rebin(const Parallel::Communicator &comm, const std::string &storageMode) {
58
  using namespace Parallel;
59
60
61
62
  auto rebin = prepare_rebin(comm, storageMode);
  rebin->setProperty("Params", "1,1,3");
  TS_ASSERT_THROWS_NOTHING(rebin->execute());
  MatrixWorkspace_const_sptr ws = rebin->getProperty("OutputWorkspace");
63
64
65
66
67
  if (comm.rank() == 0 || fromString(storageMode) != StorageMode::MasterOnly) {
    TS_ASSERT_EQUALS(ws->storageMode(), fromString(storageMode));
  } else {
    TS_ASSERT_EQUALS(ws, nullptr);
  }
68
69
}

Samuel Jones's avatar
Samuel Jones committed
70
void run_rebin_params_only_bin_width(const Parallel::Communicator &comm, const std::string &storageMode) {
71
  using namespace Parallel;
72
73
  auto rebin = prepare_rebin(comm, storageMode);
  rebin->setProperty("Params", "0.5");
74
75
76
77
  TS_ASSERT_THROWS_NOTHING(rebin->execute());
  MatrixWorkspace_const_sptr ws = rebin->getProperty("OutputWorkspace");
  if (comm.rank() == 0 || fromString(storageMode) != StorageMode::MasterOnly) {
    TS_ASSERT_EQUALS(ws->storageMode(), fromString(storageMode));
78
  } else {
79
    TS_ASSERT_EQUALS(ws, nullptr);
80
81
  }
}
LamarMoore's avatar
LamarMoore committed
82
} // namespace
83

84
class RebinTest : public CxxTest::TestSuite {
85
public:
Nick Draper's avatar
re #100    
Nick Draper committed
86
87
88
  double BIN_DELTA;
  int NUMPIXELS, NUMBINS;

89
90
91
  // This pair of boilerplate methods prevent the suite being created statically
  // This means the constructor isn't called when running other tests
  static RebinTest *createSuite() { return new RebinTest(); }
92
  static void destroySuite(RebinTest *suite) { delete suite; }
93

94
  RebinTest() {
Nick Draper's avatar
re #100    
Nick Draper committed
95
96
97
98
99
    BIN_DELTA = 2.0;
    NUMPIXELS = 20;
    NUMBINS = 50;
  }

100
  void testworkspace1D_dist() {
101
    Workspace2D_sptr test_in1D = Create1DWorkspace(50);
102
    test_in1D->setDistribution(true);
103
104
    AnalysisDataService::Instance().add("test_in1D", test_in1D);

105
    Rebin rebin;
106
    rebin.initialize();
107
108
    rebin.setPropertyValue("InputWorkspace", "test_in1D");
    rebin.setPropertyValue("OutputWorkspace", "test_out");
109
    // Check it fails if "Params" property not set
110
    TS_ASSERT_THROWS(rebin.execute(), const std::runtime_error &);
111
    TS_ASSERT(!rebin.isExecuted());
112
    // Now set the property
113
    rebin.setPropertyValue("Params", "1.5,2.0,20,-0.1,30,1.0,35");
Nick Draper's avatar
re #100    
Nick Draper committed
114
115
    TS_ASSERT(rebin.execute());
    TS_ASSERT(rebin.isExecuted());
Samuel Jones's avatar
Samuel Jones committed
116
    MatrixWorkspace_sptr rebindata = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_out");
117
118
119
    auto &outX = rebindata->x(0);
    auto &outY = rebindata->y(0);
    auto &outE = rebindata->e(0);
120
121
122
123
124
125
126
127
128
129
130
131
132

    TS_ASSERT_DELTA(outX[7], 15.5, 0.000001);
    TS_ASSERT_DELTA(outY[7], 3.0, 0.000001);
    TS_ASSERT_DELTA(outE[7], sqrt(4.5) / 2.0, 0.000001);

    TS_ASSERT_DELTA(outX[12], 24.2, 0.000001);
    TS_ASSERT_DELTA(outY[12], 3.0, 0.000001);
    TS_ASSERT_DELTA(outE[12], sqrt(5.445) / 2.42, 0.000001);

    TS_ASSERT_DELTA(outX[17], 32.0, 0.000001);
    TS_ASSERT_DELTA(outY[17], 3.0, 0.000001);
    TS_ASSERT_DELTA(outE[17], sqrt(2.25), 0.000001);
    bool dist = rebindata->isDistribution();
133
134
135
136
137
    TS_ASSERT(dist);
    AnalysisDataService::Instance().remove("test_in1D");
    AnalysisDataService::Instance().remove("test_out");
  }

138
  void testworkspace1D_nondist() {
139
    Workspace2D_sptr test_in1D = Create1DWorkspace(50);
140
141
    AnalysisDataService::Instance().add("test_in1D", test_in1D);

142
    Rebin rebin;
143
    rebin.initialize();
144
145
    rebin.setPropertyValue("InputWorkspace", "test_in1D");
    rebin.setPropertyValue("OutputWorkspace", "test_out");
146
    rebin.setPropertyValue("Params", "1.5,2.0,20,-0.1,30,1.0,35");
Nick Draper's avatar
re #100    
Nick Draper committed
147
148
    TS_ASSERT(rebin.execute());
    TS_ASSERT(rebin.isExecuted());
Samuel Jones's avatar
Samuel Jones committed
149
    MatrixWorkspace_sptr rebindata = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_out");
150

151
152
153
    auto &outX = rebindata->x(0);
    auto &outY = rebindata->y(0);
    auto &outE = rebindata->e(0);
154
155
156
157
158
159
160
161
162
163
164

    TS_ASSERT_DELTA(outX[7], 15.5, 0.000001);
    TS_ASSERT_DELTA(outY[7], 8.0, 0.000001);
    TS_ASSERT_DELTA(outE[7], sqrt(8.0), 0.000001);
    TS_ASSERT_DELTA(outX[12], 24.2, 0.000001);
    TS_ASSERT_DELTA(outY[12], 9.68, 0.000001);
    TS_ASSERT_DELTA(outE[12], sqrt(9.68), 0.000001);
    TS_ASSERT_DELTA(outX[17], 32, 0.000001);
    TS_ASSERT_DELTA(outY[17], 4.0, 0.000001);
    TS_ASSERT_DELTA(outE[17], sqrt(4.0), 0.000001);
    bool dist = rebindata->isDistribution();
165
166
167
168
169
    TS_ASSERT(!dist);
    AnalysisDataService::Instance().remove("test_in1D");
    AnalysisDataService::Instance().remove("test_out");
  }

170
  void testworkspace1D_logarithmic_binning() {
171
    Workspace2D_sptr test_in1D = Create1DWorkspace(50);
172
    test_in1D->setDistribution(true);
173
174
    AnalysisDataService::Instance().add("test_in1D", test_in1D);

175
    Rebin rebin;
176
    rebin.initialize();
177
178
    rebin.setPropertyValue("InputWorkspace", "test_in1D");
    rebin.setPropertyValue("OutputWorkspace", "test_out");
179
    // Check it fails if "Params" property not set
180
    TS_ASSERT_THROWS(rebin.execute(), const std::runtime_error &);
181
    TS_ASSERT(!rebin.isExecuted());
182
183
184
185
    // Now set the property
    rebin.setPropertyValue("Params", "1.0,-1.0,1000.0");
    TS_ASSERT(rebin.execute());
    TS_ASSERT(rebin.isExecuted());
Samuel Jones's avatar
Samuel Jones committed
186
    MatrixWorkspace_sptr rebindata = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_out");
187
    auto &outX = rebindata->x(0);
188
189

    TS_ASSERT_EQUALS(outX.size(), 11);
190
191
192
193
    TS_ASSERT_DELTA(outX[0], 1.0, 1e-5);
    TS_ASSERT_DELTA(outX[1], 2.0, 1e-5);
    TS_ASSERT_DELTA(outX[2], 4.0, 1e-5); // and so on...
    TS_ASSERT_DELTA(outX[10], 1000.0, 1e-5);
194

195
    bool dist = rebindata->isDistribution();
196
    TS_ASSERT(dist);
Mathieu Tillet's avatar
Mathieu Tillet committed
197
198
199

    TS_ASSERT(checkBinWidthMonotonic(rebindata, false));

200
201
202
203
    AnalysisDataService::Instance().remove("test_in1D");
    AnalysisDataService::Instance().remove("test_out");
  }

204
205
  void testworkspace2D_dist() {
    Workspace2D_sptr test_in2D = Create2DWorkspace(50, 20);
206
    test_in2D->setDistribution(true);
207
208
    AnalysisDataService::Instance().add("test_in2D", test_in2D);

209
    Rebin rebin;
210
    rebin.initialize();
211
212
    rebin.setPropertyValue("InputWorkspace", "test_in2D");
    rebin.setPropertyValue("OutputWorkspace", "test_out");
213
    rebin.setPropertyValue("Params", "1.5,2.0,20,-0.1,30,1.0,35");
Nick Draper's avatar
re #100    
Nick Draper committed
214
215
    TS_ASSERT(rebin.execute());
    TS_ASSERT(rebin.isExecuted());
Samuel Jones's avatar
Samuel Jones committed
216
    MatrixWorkspace_sptr rebindata = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_out");
217

Moore's avatar
Moore committed
218
219
220
    auto &outX = rebindata->x(5);
    auto &outY = rebindata->y(5);
    auto &outE = rebindata->e(5);
221
222
223
224
225
226
227
228
229
230
231
232
    TS_ASSERT_DELTA(outX[7], 15.5, 0.000001);
    TS_ASSERT_DELTA(outY[7], 3.0, 0.000001);
    TS_ASSERT_DELTA(outE[7], sqrt(4.5) / 2.0, 0.000001);

    TS_ASSERT_DELTA(outX[12], 24.2, 0.000001);
    TS_ASSERT_DELTA(outY[12], 3.0, 0.000001);
    TS_ASSERT_DELTA(outE[12], sqrt(5.445) / 2.42, 0.000001);

    TS_ASSERT_DELTA(outX[17], 32.0, 0.000001);
    TS_ASSERT_DELTA(outY[17], 3.0, 0.000001);
    TS_ASSERT_DELTA(outE[17], sqrt(2.25), 0.000001);
    bool dist = rebindata->isDistribution();
233
234
    TS_ASSERT(dist);

235
    // Test the axes are of the correct type
236
237
238
    TS_ASSERT_EQUALS(rebindata->axes(), 2);
    TS_ASSERT(dynamic_cast<RefAxis *>(rebindata->getAxis(0)));
    TS_ASSERT(dynamic_cast<SpectraAxis *>(rebindata->getAxis(1)));
239

240
241
242
243
    AnalysisDataService::Instance().remove("test_in2D");
    AnalysisDataService::Instance().remove("test_out");
  }

Samuel Jones's avatar
Samuel Jones committed
244
  void do_test_EventWorkspace(EventType eventType, bool inPlace, bool PreserveEvents, bool expectOutputEvent) {
245
    // Two events per bin
Samuel Jones's avatar
Samuel Jones committed
246
    EventWorkspace_sptr test_in = WorkspaceCreationHelper::createEventWorkspace2(50, 100);
247
    test_in->switchEventType(eventType);
248

249
250
    std::string inName("test_inEvent");
    std::string outName("test_inEvent_output");
251
252
    if (inPlace)
      outName = inName;
Nick Draper's avatar
re #100    
Nick Draper committed
253

254
    AnalysisDataService::Instance().addOrReplace(inName, test_in);
255
    Rebin rebin;
256
    rebin.initialize();
257
258
    rebin.setPropertyValue("InputWorkspace", inName);
    rebin.setPropertyValue("OutputWorkspace", outName);
259
    rebin.setPropertyValue("Params", "0.0,4.0,100");
260
    rebin.setProperty("PreserveEvents", PreserveEvents);
Nick Draper's avatar
re #100    
Nick Draper committed
261
262
    TS_ASSERT(rebin.execute());
    TS_ASSERT(rebin.isExecuted());
263

264
265
    MatrixWorkspace_sptr outWS;
    EventWorkspace_sptr eventOutWS;
266
    TS_ASSERT_THROWS_NOTHING(
Samuel Jones's avatar
Samuel Jones committed
267
        outWS = std::dynamic_pointer_cast<MatrixWorkspace>(AnalysisDataService::Instance().retrieve(outName)));
268
269
270
    TS_ASSERT(outWS);
    if (!outWS)
      return;
271

272
    // Is the output gonna be events?
273
    if (expectOutputEvent) {
274
      eventOutWS = std::dynamic_pointer_cast<EventWorkspace>(outWS);
275
      TS_ASSERT(eventOutWS);
276
277
278
      if (!eventOutWS)
        return;
      TS_ASSERT_EQUALS(eventOutWS->getNumberEvents(), 50 * 100 * 2);
279
280
      // Check that it is the same workspace
      if (inPlace)
281
        TS_ASSERT(eventOutWS == test_in);
282
283
    }

284
285
286
    auto &X = outWS->x(0);
    auto &Y = outWS->y(0);
    auto &E = outWS->e(0);
287

288
289
290
291
    TS_ASSERT_EQUALS(X.size(), 26);
    TS_ASSERT_DELTA(X[0], 0.0, 1e-5);
    TS_ASSERT_DELTA(X[1], 4.0, 1e-5);
    TS_ASSERT_DELTA(X[2], 8.0, 1e-5);
292

293
294
295
296
    TS_ASSERT_EQUALS(Y.size(), 25);
    TS_ASSERT_DELTA(Y[0], 8.0, 1e-5);
    TS_ASSERT_DELTA(Y[1], 8.0, 1e-5);
    TS_ASSERT_DELTA(Y[2], 8.0, 1e-5);
297

298
299
300
    TS_ASSERT_EQUALS(E.size(), 25);
    TS_ASSERT_DELTA(E[0], sqrt(8.0), 1e-5);
    TS_ASSERT_DELTA(E[1], sqrt(8.0), 1e-5);
301

302
    // Test the axes are of the correct type
303
304
305
    TS_ASSERT_EQUALS(outWS->axes(), 2);
    TS_ASSERT(dynamic_cast<RefAxis *>(outWS->getAxis(0)));
    TS_ASSERT(dynamic_cast<SpectraAxis *>(outWS->getAxis(1)));
306

307
308
309
    AnalysisDataService::Instance().remove(inName);
    AnalysisDataService::Instance().remove(outName);
  }
310

Samuel Jones's avatar
Samuel Jones committed
311
  void testEventWorkspace_InPlace_PreserveEvents() { do_test_EventWorkspace(TOF, true, true, true); }
312

Samuel Jones's avatar
Samuel Jones committed
313
  void testEventWorkspace_InPlace_PreserveEvents_weighted() { do_test_EventWorkspace(WEIGHTED, true, true, true); }
314

315
  void testEventWorkspace_InPlace_PreserveEvents_weightedNoTime() {
316
317
    do_test_EventWorkspace(WEIGHTED_NOTIME, true, true, true);
  }
318

Samuel Jones's avatar
Samuel Jones committed
319
  void testEventWorkspace_InPlace_NoPreserveEvents() { do_test_EventWorkspace(TOF, true, false, false); }
320

Samuel Jones's avatar
Samuel Jones committed
321
  void testEventWorkspace_InPlace_NoPreserveEvents_weighted() { do_test_EventWorkspace(WEIGHTED, true, false, false); }
322

323
  void testEventWorkspace_InPlace_NoPreserveEvents_weightedNoTime() {
324
    do_test_EventWorkspace(WEIGHTED_NOTIME, true, false, false);
325
326
  }

Samuel Jones's avatar
Samuel Jones committed
327
  void testEventWorkspace_NotInPlace_NoPreserveEvents() { do_test_EventWorkspace(TOF, false, false, false); }
328

329
  void testEventWorkspace_NotInPlace_NoPreserveEvents_weighted() {
330
    do_test_EventWorkspace(WEIGHTED, false, false, false);
331
332
  }

333
  void testEventWorkspace_NotInPlace_NoPreserveEvents_weightedNoTime() {
334
    do_test_EventWorkspace(WEIGHTED_NOTIME, false, false, false);
335
336
  }

Samuel Jones's avatar
Samuel Jones committed
337
  void testEventWorkspace_NotInPlace_PreserveEvents() { do_test_EventWorkspace(TOF, false, true, true); }
Nick Draper's avatar
re #100    
Nick Draper committed
338

Samuel Jones's avatar
Samuel Jones committed
339
  void testEventWorkspace_NotInPlace_PreserveEvents_weighted() { do_test_EventWorkspace(WEIGHTED, false, true, true); }
340

341
  void testEventWorkspace_NotInPlace_PreserveEvents_weightedNoTime() {
342
343
    do_test_EventWorkspace(WEIGHTED_NOTIME, false, true, true);
  }
344

345
  void testRebinPointData() {
346
    Workspace2D_sptr input = Create1DWorkspace(51);
Michael Whitty's avatar
Michael Whitty committed
347
348
    AnalysisDataService::Instance().add("test_RebinPointDataInput", input);

Samuel Jones's avatar
Samuel Jones committed
349
    Mantid::API::Algorithm_sptr ctpd = Mantid::API::AlgorithmFactory::Instance().create("ConvertToPointData", 1);
Michael Whitty's avatar
Michael Whitty committed
350
351
352
353
354
    ctpd->initialize();
    ctpd->setPropertyValue("InputWorkspace", "test_RebinPointDataInput");
    ctpd->setPropertyValue("OutputWorkspace", "test_RebinPointDataInput");
    ctpd->execute();

Samuel Jones's avatar
Samuel Jones committed
355
    Mantid::API::Algorithm_sptr reb = Mantid::API::AlgorithmFactory::Instance().create("Rebin", 1);
Michael Whitty's avatar
Michael Whitty committed
356
    reb->initialize();
Samuel Jones's avatar
Samuel Jones committed
357
    TS_ASSERT_THROWS_NOTHING(reb->setPropertyValue("InputWorkspace", "test_RebinPointDataInput"));
Michael Whitty's avatar
Michael Whitty committed
358
359
    reb->setPropertyValue("OutputWorkspace", "test_RebinPointDataOutput");
    reb->setPropertyValue("Params", "7,0.75,23");
360
    TS_ASSERT_THROWS_NOTHING(reb->execute());
Michael Whitty's avatar
Michael Whitty committed
361

362
    TS_ASSERT(reb->isExecuted());
363

364
    MatrixWorkspace_sptr outWS = std::dynamic_pointer_cast<MatrixWorkspace>(
365
        AnalysisDataService::Instance().retrieve("test_RebinPointDataOutput"));
Michael Whitty's avatar
Michael Whitty committed
366

367
368
    TS_ASSERT(!outWS->isHistogramData());
    TS_ASSERT_EQUALS(outWS->getNumberHistograms(), 1);
Michael Whitty's avatar
Michael Whitty committed
369

370
371
372
    TS_ASSERT_EQUALS(outWS->x(0)[0], 7.3750);
    TS_ASSERT_EQUALS(outWS->x(0)[10], 14.8750);
    TS_ASSERT_EQUALS(outWS->x(0)[20], 22.3750);
Michael Whitty's avatar
Michael Whitty committed
373
374
375
376

    AnalysisDataService::Instance().remove("test_RebinPointDataInput");
    AnalysisDataService::Instance().remove("test_RebinPointDataOutput");
  }
Nick Draper's avatar
re #100    
Nick Draper committed
377

378
  void testMaskedBinsDist() {
379
380
    Workspace2D_sptr test_in1D = Create1DWorkspace(50);
    AnalysisDataService::Instance().add("test_Rebin_mask_dist", test_in1D);
381
    test_in1D->setDistribution(true);
382
383
384
385
386
    maskFirstBins("test_Rebin_mask_dist", "test_Rebin_masked_ws", 10.0);

    Rebin rebin;
    rebin.initialize();
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_masked_ws");
387
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_masked_ws");
388
389
390
    rebin.setPropertyValue("Params", "1.5,3.0,12,-0.1,30");
    TS_ASSERT(rebin.execute());
    TS_ASSERT(rebin.isExecuted());
391
    MatrixWorkspace_sptr rebindata =
Samuel Jones's avatar
Samuel Jones committed
392
        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_masked_ws");
393
394
    auto &outX = rebindata->x(0);
    auto &outY = rebindata->y(0);
395

Samuel Jones's avatar
Samuel Jones committed
396
    MatrixWorkspace_sptr input = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_mask_dist");
397
398
    auto &inX = input->x(0);
    auto &inY = input->y(0);
399

400
    const MatrixWorkspace::MaskList &mask = rebindata->maskedBins(0);
401

402
    // turn the mask list into an array like the Y values
403
    MantidVec weights(outY.size(), 0);
404
405
    for (auto it : mask) {
      weights[it.first] = it.second;
406
407
    }

408
409
410
    // the degree of masking must be the same as the reduction in the y-value,
    // for distributions, this is the easy case
    for (size_t i = 0; i < outY.size(); ++i) {
Samuel Jones's avatar
Samuel Jones committed
411
      size_t inBin = std::lower_bound(inX.begin(), inX.end(), outX[i]) - inX.begin();
412
413
      if (inBin < inX.size() - 2) {
        TS_ASSERT_DELTA(outY[i] / inY[inBin], 1 - weights[i], 0.000001);
414
415
      }
    }
416
417
    // the above formula tests the criterian that must be true for masking,
    // however we need some more specific tests incase outY.empty() or something
418
419
420
    TS_ASSERT_DELTA(outY[1], 0.0, 0.000001)
    TS_ASSERT_DELTA(outY[2], 0.25, 0.000001)
    TS_ASSERT_DELTA(outY[3], 3.0, 0.000001)
421
    TS_ASSERT_DELTA(weights[2], 1 - (0.25 / 3.0), 0.000001)
422
423
424
425
426

    TS_ASSERT(rebindata->isDistribution());
    AnalysisDataService::Instance().remove("test_Rebin_mask_dist");
    AnalysisDataService::Instance().remove("test_Rebin_masked_ws");
  }
427
428

  void testMaskedBinsIntegratedCounts() {
429
    Workspace2D_sptr test_in1D = Create1DWorkspace(51);
430
    test_in1D->setDistribution(false);
431
432
433
434
    AnalysisDataService::Instance().add("test_Rebin_mask_raw", test_in1D);

    Rebin rebin;
    rebin.initialize();
435
436
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_mask_raw");
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_unmasked");
437
438
439
    rebin.setPropertyValue("Params", "1.5,3.0,12,-0.1,30");
    rebin.execute();

Samuel Jones's avatar
Samuel Jones committed
440
    MatrixWorkspace_sptr input = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_unmasked");
441
442
    auto &inX = input->x(0);
    auto &inY = input->y(0);
443
444
445

    maskFirstBins("test_Rebin_mask_raw", "test_Rebin_masked_ws", 10.0);

446
447
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_masked_ws");
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_masked_ws");
448
449
    rebin.setPropertyValue("Params", "1.5,3.0,12,-0.1,30");
    rebin.execute();
Samuel Jones's avatar
Samuel Jones committed
450
    MatrixWorkspace_sptr masked = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_masked_ws");
451
452
    auto &outX = masked->x(0);
    auto &outY = masked->y(0);
453

454
    const MatrixWorkspace::MaskList &mask = masked->maskedBins(0);
455

456
    // turn the mask list into an array like the Y values
457
    MantidVec weights(outY.size(), 0);
458
459
    for (auto it : mask) {
      weights[it.first] = it.second;
460
461
    }

462
463
464
    // the degree of masking must be the same as the reduction in the y-value,
    // for distributions, this is the easy case
    for (size_t i = 0; i < outY.size(); ++i) {
Samuel Jones's avatar
Samuel Jones committed
465
      size_t inBin = std::lower_bound(inX.begin(), inX.end(), outX[i]) - inX.begin();
466
467
      if (inBin < inX.size() - 2) {
        TS_ASSERT_DELTA(outY[i] / inY[inBin], 1 - weights[i], 0.000001);
468
469
      }
    }
470
471
    // the above formula tests the criterian that must be true for masking,
    // however we need some more specific tests incase outY.empty() or something
472
473
474
    TS_ASSERT_DELTA(outY[1], 0.0, 0.000001)
    TS_ASSERT_DELTA(outY[2], 1.0, 0.000001)
    TS_ASSERT_DELTA(outY[3], 6.0, 0.000001)
475
    TS_ASSERT_DELTA(weights[2], 1 - (0.25 / 3.0), 0.000001)
476
477
478
479
480
481

    AnalysisDataService::Instance().remove("test_Rebin_masked_ws");
    AnalysisDataService::Instance().remove("test_Rebin_unmasked");
    AnalysisDataService::Instance().remove("test_Rebin_mask_raw");
  }

482
  void test_FullBinsOnly_Fixed() {
483
    std::vector<double> xExpected = {0.5, 2.5, 4.5, 6.5};
484
    std::vector<double> yExpected(3, 8.0);
485
486
487
488
    std::string params = "2.0";
    do_test_FullBinsOnly(params, yExpected, xExpected);
  }

489
  void test_FullBinsOnly_Variable() {
490
491
    std::vector<double> xExpected = {0.5, 1.5, 2.5, 3.2, 3.9, 4.6, 6.6};
    std::vector<double> yExpected = {4.0, 4.0, 2.8, 2.8, 2.8, 8.0};
492
493
    std::string params = "0.5, 1.0, 3.1, 0.7, 5.0, 2.0, 7.25";
    do_test_FullBinsOnly(params, yExpected, xExpected);
494
495
  }

Mathieu Tillet's avatar
Mathieu Tillet committed
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
  void test_reverseLogSimple() {
    // Test UseReverseLogarithmic alone
    Workspace2D_sptr test_1D = Create1DWorkspace(51);
    test_1D->setDistribution(false);
    AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);

    Rebin rebin;
    rebin.initialize();
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("Params", "1, -1, 37");
    rebin.setProperty("UseReverseLogarithmic", true);
    TS_ASSERT_THROWS_NOTHING(rebin.execute());

    MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
    auto &outX = out->x(0);

513
514
515
516
517
518
519
    TS_ASSERT_EQUALS(outX.size(), 6);
    TS_ASSERT_DELTA(outX[0], 1, 1e-5);
    TS_ASSERT_DELTA(outX[1], 22, 1e-5);
    TS_ASSERT_DELTA(outX[2], 30, 1e-5);
    TS_ASSERT_DELTA(outX[3], 34, 1e-5);
    TS_ASSERT_DELTA(outX[4], 36, 1e-5);
    TS_ASSERT_DELTA(outX[5], 37, 1e-5);
Mathieu Tillet's avatar
Mathieu Tillet committed
520
521
522

    TS_ASSERT(checkBinWidthMonotonic(out, true));

Mathieu Tillet's avatar
Mathieu Tillet committed
523
524
525
526
527
528
529
530
531
532
533
534
535
    AnalysisDataService::Instance().remove("test_Rebin_revLog");
  }

  void test_reverseLogDiffStep() {
    // Test UseReverseLog with a different step than the usual -1
    Workspace2D_sptr test_1D = Create1DWorkspace(51);
    test_1D->setDistribution(false);
    AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);

    Rebin rebin;
    rebin.initialize();
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
536
    rebin.setPropertyValue("Params", "1, -2, 42");
Mathieu Tillet's avatar
Mathieu Tillet committed
537
538
539
540
541
542
    rebin.setProperty("UseReverseLogarithmic", true);
    TS_ASSERT_THROWS_NOTHING(rebin.execute());

    MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
    auto &outX = out->x(0);

543
544
545
546
547
    TS_ASSERT_EQUALS(outX.size(), 4);
    TS_ASSERT_DELTA(outX[0], 1, 1e-5);
    TS_ASSERT_DELTA(outX[1], 34, 1e-5);
    TS_ASSERT_DELTA(outX[2], 40, 1e-5);
    TS_ASSERT_DELTA(outX[3], 42, 1e-5);
Mathieu Tillet's avatar
Mathieu Tillet committed
548
549
550

    TS_ASSERT(checkBinWidthMonotonic(out, true));

Mathieu Tillet's avatar
Mathieu Tillet committed
551
552
553
554
    AnalysisDataService::Instance().remove("test_Rebin_revLog");
  }

  void test_reverseLogEdgeCase() {
555
556
    // Check the case where the parameters given are so that the edges of the bins fall perfectly, and so no padding is
    // needed
Mathieu Tillet's avatar
Mathieu Tillet committed
557
558
559
560
561
562
563
564
    Workspace2D_sptr test_1D = Create1DWorkspace(51);
    test_1D->setDistribution(false);
    AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);

    Rebin rebin;
    rebin.initialize();
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
565
    rebin.setPropertyValue("Params", "1, -1, 16");
Mathieu Tillet's avatar
Mathieu Tillet committed
566
567
568
569
570
571
    rebin.setProperty("UseReverseLogarithmic", true);
    TS_ASSERT_THROWS_NOTHING(rebin.execute());

    MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
    auto &outX = out->x(0);

572
573
574
575
576
577
    TS_ASSERT_EQUALS(outX.size(), 5);
    TS_ASSERT_DELTA(outX[0], 1, 1e-5)
    TS_ASSERT_DELTA(outX[1], 9, 1e-5);
    TS_ASSERT_DELTA(outX[2], 13, 1e-5);
    TS_ASSERT_DELTA(outX[3], 15, 1e-5);
    TS_ASSERT_DELTA(outX[4], 16, 1e-5);
Mathieu Tillet's avatar
Mathieu Tillet committed
578
579
580

    TS_ASSERT(checkBinWidthMonotonic(out, true));

Mathieu Tillet's avatar
Mathieu Tillet committed
581
582
583
584
585
586
587
588
589
590
591
592
593
    AnalysisDataService::Instance().remove("test_Rebin_revLog");
  }

  void test_reverseLogAgainst() {
    // Test UseReverseLogarithmic with a linear spacing before it
    Workspace2D_sptr test_1D = Create1DWorkspace(51);
    test_1D->setDistribution(false);
    AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);

    Rebin rebin;
    rebin.initialize();
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
594
    rebin.setPropertyValue("Params", "1, 2, 5, -1, 100");
Mathieu Tillet's avatar
Mathieu Tillet committed
595
596
597
598
599
600
    rebin.setProperty("UseReverseLogarithmic", true);
    TS_ASSERT_THROWS_NOTHING(rebin.execute());

    MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
    auto &outX = out->x(0);

601
602
603
604
605
606
607
608
    TS_ASSERT_EQUALS(outX.size(), 7); // 2 lin + 4 log
    TS_ASSERT_DELTA(outX[0], 1, 1e-5);
    TS_ASSERT_DELTA(outX[1], 3, 1e-5);
    TS_ASSERT_DELTA(outX[2], 5, 1e-5);
    TS_ASSERT_DELTA(outX[3], 65, 1e-5);
    TS_ASSERT_DELTA(outX[4], 85, 1e-5);
    TS_ASSERT_DELTA(outX[5], 95, 1e-5);
    TS_ASSERT_DELTA(outX[6], 100, 1e-5);
Mathieu Tillet's avatar
Mathieu Tillet committed
609

Mathieu Tillet's avatar
Mathieu Tillet committed
610
611
612
613
614
615
616
617
618
619
620
621
622
623
    AnalysisDataService::Instance().remove("test_Rebin_revLog");
  }

  void test_reverseLogBetween() {
    // Test UseReverseLogarithmic between 2 linear binnings

    Workspace2D_sptr test_1D = Create1DWorkspace(51);
    test_1D->setDistribution(false);
    AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);

    Rebin rebin;
    rebin.initialize();
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
624
    rebin.setPropertyValue("Params", "1, 2, 5, -1, 100, 2, 110");
Mathieu Tillet's avatar
Mathieu Tillet committed
625
626
627
628
629
630
    rebin.setProperty("UseReverseLogarithmic", true);
    TS_ASSERT_THROWS_NOTHING(rebin.execute());

    MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
    auto &outX = out->x(0);

631
632
633
634
635
636
637
638
639
640
641
    TS_ASSERT_EQUALS(outX.size(), 12);
    TS_ASSERT_DELTA(outX[0], 1, 1e-5);
    TS_ASSERT_DELTA(outX[1], 3, 1e-5);
    TS_ASSERT_DELTA(outX[2], 5, 1e-5);
    TS_ASSERT_DELTA(outX[3], 65, 1e-5);
    TS_ASSERT_DELTA(outX[4], 85, 1e-5);
    TS_ASSERT_DELTA(outX[5], 95, 1e-5);
    TS_ASSERT_DELTA(outX[6], 100, 1e-5);
    TS_ASSERT_DELTA(outX[7], 102, 1e-5);
    TS_ASSERT_DELTA(outX[11], 110, 1e-5);

Mathieu Tillet's avatar
Mathieu Tillet committed
642
643
644
645
    AnalysisDataService::Instance().remove("test_Rebin_revLog");
  }

  void test_reverseLogFullBinsOnly() {
646
647
    // Test UseReverseLogarithmic with the FullBinsOnly option checked. It should not change anything from the non
    // checked version.
Mathieu Tillet's avatar
Mathieu Tillet committed
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
    Workspace2D_sptr test_1D = Create1DWorkspace(51);
    test_1D->setDistribution(false);
    AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);

    Rebin rebin;
    rebin.initialize();
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("Params", "1, -1, 37");
    rebin.setProperty("UseReverseLogarithmic", true);
    rebin.setProperty("FullBinsOnly", true);
    TS_ASSERT_THROWS_NOTHING(rebin.execute());

    MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
    auto &outX = out->x(0);

664
665
666
667
668
669
670
671
    TS_ASSERT_EQUALS(outX.size(), 6);
    TS_ASSERT_DELTA(outX[0], 1, 1e-5);
    TS_ASSERT_DELTA(outX[1], 22, 1e-5);
    TS_ASSERT_DELTA(outX[2], 30, 1e-5);
    TS_ASSERT_DELTA(outX[3], 34, 1e-5);
    TS_ASSERT_DELTA(outX[4], 36, 1e-5);
    TS_ASSERT_DELTA(outX[5], 37, 1e-5);

Mathieu Tillet's avatar
Mathieu Tillet committed
672
673
    TS_ASSERT(checkBinWidthMonotonic(out, true));

674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
    AnalysisDataService::Instance().remove("test_Rebin_revLog");
  }

  void test_reverseLogIncompleteFirstBin() {
    // Test UseReverseLogarithmic with a first bin that is incomplete, but still bigger than the next one so not merged.
    Workspace2D_sptr test_1D = Create1DWorkspace(51);
    test_1D->setDistribution(false);
    AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);

    Rebin rebin;
    rebin.initialize();
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("Params", "1, -1, 60");
    rebin.setProperty("UseReverseLogarithmic", true);
    rebin.setProperty("FullBinsOnly", true);
    TS_ASSERT_THROWS_NOTHING(rebin.execute());

    MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
    auto &outX = out->x(0);

Mathieu Tillet's avatar
Mathieu Tillet committed
695
    TS_ASSERT_EQUALS(outX.size(), 7);
696
697
698
699
700
701
702
703
    TS_ASSERT_DELTA(outX[0], 1, 1e-5);
    TS_ASSERT_DELTA(outX[1], 29, 1e-5);
    TS_ASSERT_DELTA(outX[2], 45, 1e-5);
    TS_ASSERT_DELTA(outX[3], 53, 1e-5);
    TS_ASSERT_DELTA(outX[4], 57, 1e-5);
    TS_ASSERT_DELTA(outX[5], 59, 1e-5);
    TS_ASSERT_DELTA(outX[6], 60, 1e-5);

Mathieu Tillet's avatar
Mathieu Tillet committed
704
705
    TS_ASSERT(checkBinWidthMonotonic(out, true));

Mathieu Tillet's avatar
Mathieu Tillet committed
706
707
708
    AnalysisDataService::Instance().remove("test_Rebin_revLog");
  }

709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
  void test_inversePowerSquareRoot() {
    // Test InversePower in a simple case of square root sum
    Workspace2D_sptr test_1D = Create1DWorkspace(51);
    test_1D->setDistribution(false);
    AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);

    Rebin rebin;
    rebin.initialize();
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("Params", "1, 1, 10");
    rebin.setPropertyValue("Power", "0.5");
    TS_ASSERT_THROWS_NOTHING(rebin.execute());

    MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
    auto &outX = out->x(0);

    TS_ASSERT_EQUALS(outX.size(), 28);
    TS_ASSERT_DELTA(outX[0], 1, 1e-5);
    TS_ASSERT_DELTA(outX[1], 2, 1e-5);
    TS_ASSERT_DELTA(outX[2], 2.707106781, 1e-5);
    TS_ASSERT_DELTA(outX[3], 3.28445705, 1e-5);
    TS_ASSERT_DELTA(outX[27], 10, 1e-5);

Mathieu Tillet's avatar
Mathieu Tillet committed
733
734
    TS_ASSERT(checkBinWidthMonotonic(out, true));

735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
    AnalysisDataService::Instance().remove("test_Rebin_revLog");
  }

  void test_inversePowerHarmonic() {
    // Test InversePower in a simple case of harmonic serie
    Workspace2D_sptr test_1D = Create1DWorkspace(51);
    test_1D->setDistribution(false);
    AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);

    Rebin rebin;
    rebin.initialize();
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("Params", "1, 1, 5");
    rebin.setPropertyValue("Power", "1");
    TS_ASSERT_THROWS_NOTHING(rebin.execute());

    MatrixWorkspace_sptr out = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>("test_Rebin_revLog");
    auto &outX = out->x(0);

    TS_ASSERT_EQUALS(outX.size(), 31);
    TS_ASSERT_DELTA(outX[0], 1, 1e-5);
    TS_ASSERT_DELTA(outX[1], 2, 1e-5);
    TS_ASSERT_DELTA(outX[2], 2.5, 1e-5);
    TS_ASSERT_DELTA(outX[3], 2.8333333, 1e-5);
    TS_ASSERT_DELTA(outX[30], 5, 1e-5);

Mathieu Tillet's avatar
Mathieu Tillet committed
762
763
    TS_ASSERT(checkBinWidthMonotonic(out, true, true));

764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
    AnalysisDataService::Instance().remove("test_Rebin_revLog");
  }

  void test_inversePowerValidateHarmonic() {
    // Test that the validator which forbid breating more than 10000 bins works in a harmonic series case
    Workspace2D_sptr test_1D = Create1DWorkspace(51);
    test_1D->setDistribution(false);
    AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);

    Rebin rebin;
    rebin.initialize();
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("Params", "1, 1, 100");
    rebin.setPropertyValue("Power", "1");
    TS_ASSERT_THROWS(rebin.execute(), const std::runtime_error &);
    AnalysisDataService::Instance().remove("test_Rebin_revLog");
  }

  void test_inversePowerValidateInverseSquareRoot() {
    // Test that the validator which forbid breating more than 10000 bins works in an inverse square root case
    // We test both because they rely on different formula to compute the expected number of bins.
    Workspace2D_sptr test_1D = Create1DWorkspace(51);
    test_1D->setDistribution(false);
    AnalysisDataService::Instance().add("test_Rebin_revLog", test_1D);

    Rebin rebin;
    rebin.initialize();
    rebin.setPropertyValue("InputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("OutputWorkspace", "test_Rebin_revLog");
    rebin.setPropertyValue("Params", "1, 1, 1000");
    rebin.setPropertyValue("Power", "0.5");
    TS_ASSERT_THROWS(rebin.execute(), const std::runtime_error &);
    AnalysisDataService::Instance().remove("test_Rebin_revLog");
  }

Samuel Jones's avatar
Samuel Jones committed
800
  void test_parallel_cloned() { ParallelTestHelpers::runParallel(run_rebin, "Parallel::StorageMode::Cloned"); }
801
802

  void test_parallel_distributed() {
Samuel Jones's avatar
Samuel Jones committed
803
    ParallelTestHelpers::runParallel(run_rebin, "Parallel::StorageMode::Distributed");
804
805
  }

Samuel Jones's avatar
Samuel Jones committed
806
  void test_parallel_master_only() { ParallelTestHelpers::runParallel(run_rebin, "Parallel::StorageMode::MasterOnly"); }
807
808

  void test_parallel_only_bin_width() {
Samuel Jones's avatar
Samuel Jones committed
809
810
811
    ParallelTestHelpers::runParallel(run_rebin_params_only_bin_width, "Parallel::StorageMode::Cloned");
    ParallelTestHelpers::runParallel(run_rebin_params_only_bin_width, "Parallel::StorageMode::Distributed");
    ParallelTestHelpers::runParallel(run_rebin_params_only_bin_width, "Parallel::StorageMode::MasterOnly");
812
813
  }

814
private:
815
  Workspace2D_sptr Create1DWorkspace(int size) {
816
    auto retVal = createWorkspace<Workspace2D>(1, size, size - 1);
Mathieu Tillet's avatar
Mathieu Tillet committed
817
    double j = 0.5;
818
    for (int i = 0; i < size; i++) {
Mathieu Tillet's avatar
Mathieu Tillet committed
819
820
      retVal->dataX(0)[i] = j;
      j += 0.75;
821
    }
822
823
    retVal->setCounts(0, size - 1, 3.0);
    retVal->setCountVariances(0, size - 1, 3.0);
824
825
    return retVal;
  }
826
827

  Workspace2D_sptr Create2DWorkspace(int xlen, int ylen) {
828
    BinEdges x1(xlen, HistogramData::LinearGenerator(0.5, 0.75));
829
830
    Counts y1(xlen - 1, 3.0);
    CountStandardDeviations e1(xlen - 1, sqrt(3.0));
831

832
    auto retVal = createWorkspace<Workspace2D>(ylen, xlen, xlen - 1);
833

834
    for (int i = 0; i < ylen; i++) {
835
      retVal->setBinEdges(i, x1);
836
837
      retVal->setCounts(i, y1);
      retVal->setCountStandardDeviations(i, e1);
838
839
840
841
842
    }

    return retVal;
  }

Samuel Jones's avatar
Samuel Jones committed
843
  void maskFirstBins(const std::string &in, const std::string &out, double maskBinsTo) {
844
845
846
847
848
849
850
851
    MaskBins mask;
    mask.initialize();
    mask.setPropertyValue("InputWorkspace", in);
    mask.setPropertyValue("OutputWorkspace", out);
    mask.setProperty("XMin", 0.0);
    mask.setProperty("XMax", maskBinsTo);
    mask.execute();
  }
Nick Draper's avatar
re #100    
Nick Draper committed
852

Samuel Jones's avatar
Samuel Jones committed
853
  void do_test_FullBinsOnly(const std::string &params, const std::vector<double> &yExpected,
854
855
                            const std::vector<double> &xExpected) {
    ScopedWorkspace inWsEntry(Create1DWorkspace(10));
856
857
    ScopedWorkspace outWsEntry;

858
    try {
859
860
861
862
863
864
865
      Rebin rebin;
      rebin.initialize();
      rebin.setPropertyValue("InputWorkspace", inWsEntry.name());
      rebin.setPropertyValue("OutputWorkspace", outWsEntry.name());
      rebin.setPropertyValue("Params", params);
      rebin.setProperty("FullBinsOnly", true);
      rebin.execute();
866
    } catch (std::runtime_error &e) {
867
868
869
870
      TS_FAIL(e.what());
      return;
    }

871
    auto ws = std::dynamic_pointer_cast<MatrixWorkspace>(outWsEntry.retrieve());
872

873
    if (!ws) {
874
875
876
877
      TS_FAIL("Unable to retrieve result workspace");
      return; // Nothing else to check
    }

878
879
    auto &xValues = ws->x(0);
    TS_ASSERT_DELTA(xValues.rawData(), xExpected, 0.001);
880

881
882
    auto &yValues = ws->y(0);
    TS_ASSERT_DELTA(yValues.rawData(), yExpected, 0.001);
883
  }
Mathieu Tillet's avatar
Mathieu Tillet committed
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901

  bool checkBinWidthMonotonic(MatrixWorkspace_sptr ws, bool reverse = false, bool ignoreLastBin = false) {
    size_t binEdgesTotal = ws->blocksize();
    if (ignoreLastBin)
      binEdgesTotal--;
    auto binEdges = ws->binEdges(0);
    double lastBinSize = binEdges[1] - binEdges[0];
    for (size_t i = 1; i < binEdgesTotal; ++i) {
      double currentBinSize = binEdges[i + 1] - binEdges[i];

      if (((lastBinSize < currentBinSize) && reverse) || ((lastBinSize > currentBinSize) && !reverse)) {
        return false;
      }

      lastBinSize = currentBinSize;
    }
    return true;
  }
902
903
};

904
class RebinTestPerformance : public CxxTest::TestSuite {
905
906
907
public:
  // This pair of boilerplate methods prevent the suite being created statically
  // This means the constructor isn't called when running other tests
Samuel Jones's avatar
Samuel Jones committed
908
  static RebinTestPerformance *createSuite() { return new RebinTestPerformance(); }
909
  static void destroySuite(RebinTestPerformance *suite) { delete suite; }
910

Samuel Jones's avatar
Samuel Jones committed
911
  RebinTestPerformance() { ws = WorkspaceCreationHelper::create2DWorkspaceBinned(5000, 20000); }
912

913
  void test_rebin() {
914
915
    Rebin rebin;
    rebin.initialize();
916
917
918
919
    rebin.setProperty("InputWorkspace", ws);
    rebin.setPropertyValue("OutputWorkspace", "out");
    rebin.setPropertyValue("Params", "50,1.77,18801");
    TS_ASSERT(rebin.execute());
920
921
922
923
  }

private:
  MatrixWorkspace_sptr ws;
924
};