GatedSpectrometerTest.cu 22 KB
Newer Older
Tobias Winchen's avatar
Tobias Winchen committed
1
#include "psrdada_cpp/effelsberg/edd/DadaBufferLayout.hpp"
2
3
#include "psrdada_cpp/effelsberg/edd/GatedSpectrometer.cuh"

Tobias Winchen's avatar
Tobias Winchen committed
4
#include "psrdada_cpp/dada_db.hpp"
5
6
7
8
9
10
11
#include "psrdada_cpp/dada_null_sink.hpp"
#include "psrdada_cpp/multilog.hpp"
#include "gtest/gtest.h"

#include "thrust/device_vector.h"
#include "thrust/extrema.h"

Tobias Winchen's avatar
Tobias Winchen committed
12
TEST(GatedSpectrometer, BitManipulationMacros) {
13
  for (int i = 0; i < 64; i++) {
14
    uint64_t v = 0;
15
16
17
18
19
20
21
22
23
24
25
    SET_BIT(v, i);

    for (int j = 0; j < 64; j++) {
      if (j == i)
        EXPECT_EQ(TEST_BIT(v, j), 1);
      else
        EXPECT_EQ(TEST_BIT(v, j), 0);
    }
  }
}

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81

TEST(GatedSpectrometer, stokes_IQUV)
{
    float I,Q,U,V;
    // No field
    psrdada_cpp::effelsberg::edd::stokes_IQUV((float2){0.0f,0.0f}, (float2){0.0f,0.0f}, I, Q, U, V);
    EXPECT_FLOAT_EQ(I, 0);
    EXPECT_FLOAT_EQ(Q, 0);
    EXPECT_FLOAT_EQ(U, 0);
    EXPECT_FLOAT_EQ(V, 0);

    // For p1 = Ex, p2 = Ey
    // horizontal polarized
    psrdada_cpp::effelsberg::edd::stokes_IQUV((float2){1.0f,0.0f}, (float2){0.0f,0.0f}, I, Q, U, V);
    EXPECT_FLOAT_EQ(I, 1);
    EXPECT_FLOAT_EQ(Q, 1);
    EXPECT_FLOAT_EQ(U, 0);
    EXPECT_FLOAT_EQ(V, 0);

    // vertical polarized
    psrdada_cpp::effelsberg::edd::stokes_IQUV((float2){0.0f,0.0f}, (float2){1.0f,0.0f}, I, Q, U, V);
    EXPECT_FLOAT_EQ(I, 1);
    EXPECT_FLOAT_EQ(Q, -1);
    EXPECT_FLOAT_EQ(U, 0);
    EXPECT_FLOAT_EQ(V, 0);

    //linear +45 deg.
    psrdada_cpp::effelsberg::edd::stokes_IQUV((float2){1.0f/std::sqrt(2),0.0f}, (float2){1.0f/std::sqrt(2),0.0f}, I, Q, U, V);
    EXPECT_FLOAT_EQ(I, 1);
    EXPECT_FLOAT_EQ(Q, 0);
    EXPECT_FLOAT_EQ(U, 1);
    EXPECT_FLOAT_EQ(V, 0);

    //linear -45 deg.
    psrdada_cpp::effelsberg::edd::stokes_IQUV((float2){-1.0f/std::sqrt(2),0.0f}, (float2){1.0f/std::sqrt(2),0.0f}, I, Q, U, V);
    EXPECT_FLOAT_EQ(I, 1);
    EXPECT_FLOAT_EQ(Q, 0);
    EXPECT_FLOAT_EQ(U, -1);
    EXPECT_FLOAT_EQ(V, 0);

    //left circular
    psrdada_cpp::effelsberg::edd::stokes_IQUV((float2){.0f,1.0f/std::sqrt(2)}, (float2){1.0f/std::sqrt(2),.0f}, I, Q, U, V);
    EXPECT_FLOAT_EQ(I, 1);
    EXPECT_FLOAT_EQ(Q, 0);
    EXPECT_FLOAT_EQ(U, 0);
    EXPECT_FLOAT_EQ(V, -1);

    // right circular
    psrdada_cpp::effelsberg::edd::stokes_IQUV((float2){.0f,-1.0f/std::sqrt(2)}, (float2){1.0f/std::sqrt(2),.0f}, I, Q, U, V);
    EXPECT_FLOAT_EQ(I, 1);
    EXPECT_FLOAT_EQ(Q, 0);
    EXPECT_FLOAT_EQ(U, 0);
    EXPECT_FLOAT_EQ(V, 1);
}


Tobias Winchen's avatar
Tobias Winchen committed
82

Tobias Winchen's avatar
Tobias Winchen committed
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
void testStokesAccumulateParam(size_t nchans, size_t naccumulate){
    // Test the stokes accumulate kernel for different channel / accumualte
    // numbers

    CUDA_ERROR_CHECK(cudaDeviceSynchronize());

    thrust::device_vector<float2> P0(nchans * naccumulate);
    thrust::device_vector<float2> P1(nchans * naccumulate);
    thrust::fill(P0.begin(), P0.end(), (float2){0, 0});
    thrust::fill(P1.begin(), P1.end(), (float2){0, 0});
    thrust::device_vector<float> I(nchans);
    thrust::device_vector<float> Q(nchans);
    thrust::device_vector<float> U(nchans);
    thrust::device_vector<float> V(nchans);
    thrust::fill(I.begin(), I.end(), 0);
    thrust::fill(Q.begin(), Q.end(), 0);
    thrust::fill(U.begin(), U.end(), 0);
    thrust::fill(V.begin(), V.end(), 0);

    // This channel should be left circular polarized
    size_t idx0 = 23;
104
    for (size_t k = 0; k< naccumulate; k++)
Tobias Winchen's avatar
Tobias Winchen committed
105
106
107
108
109
    {
        size_t idx = idx0 + k * nchans;
        P0[idx] = (float2){0.0f, 1.0f/std::sqrt(2)};
        P1[idx] = (float2){1.0f/std::sqrt(2),0.0f};
    }
Tobias Winchen's avatar
Tobias Winchen committed
110

Tobias Winchen's avatar
Tobias Winchen committed
111
112
113
114
115
116
117
118
119
120
121
122
123
    psrdada_cpp::effelsberg::edd::stokes_accumulate<<<1024, 1024>>>(
          thrust::raw_pointer_cast(P0.data()),
          thrust::raw_pointer_cast(P1.data()),
          thrust::raw_pointer_cast(I.data()),
          thrust::raw_pointer_cast(Q.data()),
          thrust::raw_pointer_cast(U.data()),
          thrust::raw_pointer_cast(V.data()),
          nchans,
          naccumulate
            );

    CUDA_ERROR_CHECK(cudaDeviceSynchronize());
    thrust::pair<thrust::device_vector<float>::iterator, thrust::device_vector<float>::iterator> minmax;
Tobias Winchen's avatar
Tobias Winchen committed
124

Tobias Winchen's avatar
Tobias Winchen committed
125
126
127
128
129
130
131
132
133
134
135
    minmax = thrust::minmax_element(I.begin(), I.end());
    EXPECT_FLOAT_EQ(*minmax.first, 0);
    EXPECT_FLOAT_EQ(*minmax.second, naccumulate);

    minmax = thrust::minmax_element(Q.begin(), Q.end());
    EXPECT_FLOAT_EQ(*minmax.first, 0);
    EXPECT_FLOAT_EQ(*minmax.second, 0);

    minmax = thrust::minmax_element(U.begin(), U.end());
    EXPECT_FLOAT_EQ(*minmax.first, 0);
    EXPECT_FLOAT_EQ(*minmax.second, 0);
136

Tobias Winchen's avatar
Tobias Winchen committed
137
138
139
140
    minmax = thrust::minmax_element(V.begin(), V.end());
    EXPECT_FLOAT_EQ(*minmax.first, -1. * naccumulate);
    EXPECT_FLOAT_EQ(*minmax.second, 0);
};
Tobias Winchen's avatar
Tobias Winchen committed
141

Tobias Winchen's avatar
Tobias Winchen committed
142
143
144
145
146
147
148

TEST(GatedSpectrometer, stokes_accumulate)
{
    testStokesAccumulateParam(8 * 1024 * 1024 + 1, 5);
    testStokesAccumulateParam(8 * 1024 * 1024 + 1, 32);
    testStokesAccumulateParam(1024 + 1, 5);
    testStokesAccumulateParam(1024 + 1, 64);
149
    testStokesAccumulateParam(1024, 65536);
150
151
}

152

153

Tobias Winchen's avatar
Tobias Winchen committed
154

155
156
TEST(GatedSpectrometer, GatingKernel)
{
157
158
  const size_t blockSize = 1024;
  const size_t nBlocks = 16 * 1024;
159
160
161

  thrust::device_vector<float> G0(blockSize * nBlocks);
  thrust::device_vector<float> G1(blockSize * nBlocks);
162
  thrust::device_vector<uint64_t> _sideChannelData(nBlocks);
163
164
165
166
  thrust::device_vector<psrdada_cpp::effelsberg::edd::uint64_cu> _nG0(nBlocks);
  thrust::device_vector<psrdada_cpp::effelsberg::edd::uint64_cu> _nG1(nBlocks);
  thrust::device_vector<float> baseLineG0(1);
  thrust::device_vector<float> baseLineG1(1);
167

168
169
  thrust::device_vector<float> baseLineG0_update(1);
  thrust::device_vector<float> baseLineG1_update(1);
170
171
172
173
174
175
  thrust::fill(G0.begin(), G0.end(), 42);
  thrust::fill(G1.begin(), G1.end(), 23);
  thrust::fill(_sideChannelData.begin(), _sideChannelData.end(), 0);

  // everything to G0
  {
176
177
    thrust::fill(_nG0.begin(), _nG0.end(), 0);
    thrust::fill(_nG1.begin(), _nG1.end(), 0);
178
179
180
181
182
    baseLineG0[0] = -3;
    baseLineG1[0] = -4;
    baseLineG0_update[0] = 0;
    baseLineG1_update[0] = 0;

183
184
    const uint64_t *sideCD =
        (uint64_t *)(thrust::raw_pointer_cast(_sideChannelData.data()));
185
    psrdada_cpp::effelsberg::edd::gating<<<1024 , 1024>>>(
186
187
          thrust::raw_pointer_cast(G0.data()),
          thrust::raw_pointer_cast(G1.data()), sideCD,
188
          G0.size(), blockSize, 0, 1,
189
190
191
          0,
          thrust::raw_pointer_cast(baseLineG0.data()),
          thrust::raw_pointer_cast(baseLineG1.data()),
192
193
          thrust::raw_pointer_cast(baseLineG0_update.data()),
          thrust::raw_pointer_cast(baseLineG1_update.data()),
194
195
196
          thrust::raw_pointer_cast(_nG0.data()),
          thrust::raw_pointer_cast(_nG1.data())
          );
197

198
199
200
201
202
203
    thrust::pair<thrust::device_vector<float>::iterator, thrust::device_vector<float>::iterator> minmax;
    minmax = thrust::minmax_element(G0.begin(), G0.end());
    EXPECT_EQ(*minmax.first, 42);
    EXPECT_EQ(*minmax.second, 42);

    minmax = thrust::minmax_element(G1.begin(), G1.end());
204
205
    EXPECT_EQ(*minmax.first, -4.);
    EXPECT_EQ(*minmax.second, -4.);
206
207

    EXPECT_EQ(_nG0[0], G0.size());
208
    EXPECT_EQ(_nG1[0], 0u);
209

210
211
    EXPECT_FLOAT_EQ(42.f, baseLineG0_update[0] / (_nG0[0] + 1E-121));
    EXPECT_FLOAT_EQ(0.f, baseLineG1_update[0] / (_nG1[0] + 1E-121));
212
213
  }

Tobias Winchen's avatar
Tobias Winchen committed
214
  // everything to G1 // with baseline -5
215
  {
216
217
    thrust::fill(_nG0.begin(), _nG0.end(), 0);
    thrust::fill(_nG1.begin(), _nG1.end(), 0);
218
219
220
221
222
    baseLineG0[0] = 5.;
    baseLineG1[0] = -2;
    baseLineG0_update[0] = 0;
    baseLineG1_update[0] = 0;

223
    thrust::fill(_sideChannelData.begin(), _sideChannelData.end(), 1L);
224
225
    const uint64_t *sideCD =
        (uint64_t *)(thrust::raw_pointer_cast(_sideChannelData.data()));
226
227
228
    psrdada_cpp::effelsberg::edd::gating<<<1024, 1024>>>(
          thrust::raw_pointer_cast(G0.data()),
          thrust::raw_pointer_cast(G1.data()), sideCD,
229
          G0.size(), blockSize, 0, 1,
230
231
232
          0,
          thrust::raw_pointer_cast(baseLineG0.data()),
          thrust::raw_pointer_cast(baseLineG1.data()),
233
234
          thrust::raw_pointer_cast(baseLineG0_update.data()),
          thrust::raw_pointer_cast(baseLineG1_update.data()),
235
236
237
          thrust::raw_pointer_cast(_nG0.data()),
          thrust::raw_pointer_cast(_nG1.data())
          );
238
239
    thrust::pair<thrust::device_vector<float>::iterator, thrust::device_vector<float>::iterator> minmax;
    minmax = thrust::minmax_element(G0.begin(), G0.end());
240
241
    EXPECT_EQ(*minmax.first, 5.);
    EXPECT_EQ(*minmax.second, 5.);
242
243
244
245

    minmax = thrust::minmax_element(G1.begin(), G1.end());
    EXPECT_EQ(*minmax.first, 42);
    EXPECT_EQ(*minmax.second, 42);
246

247
248
    EXPECT_EQ(_nG0[0], 0u);
    EXPECT_EQ(_nG1[0], G1.size());
249
250
251

    EXPECT_FLOAT_EQ(0.f, baseLineG0_update[0] / (_nG0[0] + 1E-121));
    EXPECT_FLOAT_EQ(42.f, baseLineG1_update[0] / (_nG1[0] + 1E-121));
252
253
254
  }
}

Tobias Winchen's avatar
Tobias Winchen committed
255
256
257
258
259
260
261
262
263
264
TEST(GatedSpectrometer, array_sum) {

  const size_t NBLOCKS = 16 * 32;
  const size_t NTHREADS = 1024;

  size_t inputLength = 1 << 22 + 1 ;
  size_t dataLength = inputLength;
  ////zero pad input array
  //if (inputLength % (2 * NTHREADS) != 0)
  //  dataLength = (inputLength / (2 * NTHREADS) + 1) * 2 * NTHREADS;
Tobias Winchen's avatar
Tobias Winchen committed
265
  thrust::device_vector<float> data(dataLength);
Tobias Winchen's avatar
Tobias Winchen committed
266
267
268
269
270
271
272
273
274
275
276
  thrust::fill(data.begin(), data.begin() + inputLength, 1);
  //thrust::fill(data.begin() + inputLength, data.end(), 0);
  thrust::device_vector<float> blr(NTHREADS * 2);

  thrust::fill(blr.begin(), blr.end(), 0);

  psrdada_cpp::effelsberg::edd::array_sum<<<NBLOCKS, NTHREADS, NTHREADS* sizeof(float)>>>(thrust::raw_pointer_cast(data.data()), data.size(), thrust::raw_pointer_cast(blr.data()));
  psrdada_cpp::effelsberg::edd::array_sum<<<1, NTHREADS, NTHREADS* sizeof(float)>>>(thrust::raw_pointer_cast(blr.data()), blr.size(), thrust::raw_pointer_cast(blr.data()));

  EXPECT_EQ(size_t(blr[0]), inputLength);
}
Tobias Winchen's avatar
Tobias Winchen committed
277
278


279
class GatedTestSinkSinglePol{
Tobias Winchen's avatar
Tobias Winchen committed
280
281
282
283
284
285
    private:
        size_t fft_length;
        size_t call_count;
        size_t nHeaps;
        size_t naccumulate;
    public:
286
        GatedTestSinkSinglePol(size_t fft_length, size_t nHeaps, size_t naccumulate): fft_length(fft_length), nHeaps(nHeaps), naccumulate(naccumulate), call_count(0) {};
Tobias Winchen's avatar
Tobias Winchen committed
287
288
289
290
291
    // Test the correctness of output of the processing test
        void init(psrdada_cpp::RawBytes&){
        };
        bool operator()(psrdada_cpp::RawBytes& buf)
        {
292
            const size_t number_of_sc_items = 2;
Tobias Winchen's avatar
Tobias Winchen committed
293
294
295
296
297
298
299
            const size_t nchans = fft_length / 2 + 1;
            EXPECT_EQ(buf.used_bytes(), (32 / 8 * nchans + number_of_sc_items* 64 / 8) * 2);

            float *G0 = reinterpret_cast<float*>(buf.ptr());
            float *G1 = reinterpret_cast<float*>(buf.ptr() + nchans * 32 /8);

            // Expected half number of samples per gate
300
            uint64_t *S = reinterpret_cast<uint64_t*>(buf.ptr() + 2 *nchans * 32 /8);
Tobias Winchen's avatar
Tobias Winchen committed
301
            EXPECT_EQ(S[0], nHeaps * 4096 / 2);
302
            EXPECT_EQ(S[2], nHeaps * 4096 / 2);
Tobias Winchen's avatar
Tobias Winchen committed
303

304
            // Correct number of overflowed samples
305
306
            EXPECT_EQ(S[1], 27uL);
            EXPECT_EQ(S[3], 23uL);  // First heap has 23 and bit set, thus G1
Tobias Winchen's avatar
Tobias Winchen committed
307
308
309
310
311
312
313

            call_count ++;
            return false;
        };

};

314
TEST(GatedSpectrometer, processingSinglePol)
Tobias Winchen's avatar
Tobias Winchen committed
315
316
317
318
319
320
321
322
323
324
325
326
327
328
{
    const size_t nbits = 8;
    const size_t nHeaps = 1024;
    const size_t fft_length = 1024 * 64;
    const size_t naccumulate = 4096 * nHeaps / fft_length;

    const size_t heapSize = 4096 * nbits / 8;
    const size_t inputBufferSize = nHeaps * (heapSize + 64 / 8);

    psrdada_cpp::DadaDB idbuffer(5, inputBufferSize, 1, 4096);
    idbuffer.create();

    psrdada_cpp::effelsberg::edd::DadaBufferLayout bufferLayout(idbuffer.key(), heapSize, 1);

329
    GatedTestSinkSinglePol sink(fft_length, nHeaps, naccumulate);
Tobias Winchen's avatar
Tobias Winchen committed
330
    psrdada_cpp::effelsberg::edd::GatedSpectrometer<
331
        GatedTestSinkSinglePol,
Tobias Winchen's avatar
Tobias Winchen committed
332
333
334
335
336
337
338
339
340
341
342
343
344
        psrdada_cpp::effelsberg::edd::SinglePolarizationInput,
        psrdada_cpp::effelsberg::edd::GatedPowerSpectrumOutput>
            spectrometer(bufferLayout,
                    0, 0,
                    fft_length,
                    naccumulate, nbits,
                    sink);

    char  *raw_buffer = new char[inputBufferSize];

    psrdada_cpp::RawBytes buff(raw_buffer, inputBufferSize, inputBufferSize);
    EXPECT_NO_THROW(spectrometer.init(buff));

345
346
    //// fill sci data
    uint64_t* sc_items = reinterpret_cast<uint64_t*>(raw_buffer + nHeaps * 4096);
347
    for (size_t i = 0; i < nHeaps; i+=2)
Tobias Winchen's avatar
Tobias Winchen committed
348
    {
349
350
351
        sc_items[i] = 0;
        sc_items[i+1] = 0;
        SET_BIT(sc_items[i], 0);
Tobias Winchen's avatar
Tobias Winchen committed
352
    }
353
354
    sc_items[0] |= (23UL) << 32;
    sc_items[1] |= (27UL) << 32;
Tobias Winchen's avatar
Tobias Winchen committed
355

356
    for (int i = 0; i < 12; i++)
Tobias Winchen's avatar
Tobias Winchen committed
357
    {
358
        EXPECT_NO_THROW(spectrometer(buff));
Tobias Winchen's avatar
Tobias Winchen committed
359
    }
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384

    delete [] raw_buffer;
}


class GatedTestSinkFullStokes{
    private:
        size_t fft_length;
        size_t call_count;
        size_t nHeaps;
        size_t naccumulate;
    public:
        GatedTestSinkFullStokes(size_t fft_length, size_t nHeaps, size_t naccumulate): fft_length(fft_length), nHeaps(nHeaps), naccumulate(naccumulate), call_count(0) {};
    // Test the correctness of output of the processing test
        void init(psrdada_cpp::RawBytes&){
        };
        bool operator()(psrdada_cpp::RawBytes& buf)
        {
            const size_t number_of_sc_items = 2;
            const size_t nchans = fft_length / 2 + 1;
            EXPECT_EQ(buf.used_bytes(), (32 / 8 * nchans + number_of_sc_items* 64 / 8) * 2 * 4); // 4 Spectra (IQUV), 2 Gates

            // Expected half number of samples per gate
            for(int i =0; i <4; i++)
            {
Tobias Winchen's avatar
Tobias Winchen committed
385
386
387
                uint64_t *S = reinterpret_cast<uint64_t*>(buf.ptr() + 8 *nchans * 32 /8 + i * 4 *sizeof(size_t));
                EXPECT_EQ(S[0], nHeaps * 4096) << "G0, S" << i; // expect samples from two polarizations
                EXPECT_EQ(S[2], nHeaps * 4096) << "G1, S" << i;
388
389

                // Correct number of overflowed samples
390
391
                EXPECT_EQ(S[1], uint64_t(27 + 7)) << "G0, S" << i;;
                EXPECT_EQ(S[3], uint64_t(23 + 3)) << "G1, S" << i;;  // First heap has 23+3 and bit set, thus G1
392
393
394
395
396
397
398
399
400
401
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
429
430
431
432
433
            }

            call_count ++;
            return false;
        };

};




TEST(GatedSpectrometer, processingFullStokes)
{
    const size_t nbits = 8;
    const size_t nHeaps = 1024;
    const size_t fft_length = 1024 * 64;
    const size_t naccumulate = 4096 * nHeaps / fft_length;

    const size_t heapSize = 4096 * nbits / 8;
    const size_t inputBufferSize = 2 * nHeaps * (heapSize + 64 / 8) ;

    psrdada_cpp::DadaDB idbuffer(5, inputBufferSize, 1, 4096);
    idbuffer.create();

    psrdada_cpp::effelsberg::edd::DadaBufferLayout bufferLayout(idbuffer.key(), heapSize, 1);

    GatedTestSinkFullStokes sink(fft_length, nHeaps, naccumulate);
    psrdada_cpp::effelsberg::edd::GatedSpectrometer<
        GatedTestSinkFullStokes,
        psrdada_cpp::effelsberg::edd::DualPolarizationInput,
        psrdada_cpp::effelsberg::edd::GatedFullStokesOutput>
            spectrometer(bufferLayout,
                    0, 0,
                    fft_length,
                    naccumulate, nbits,
                    sink);

    char  *raw_buffer = new char[inputBufferSize];

    psrdada_cpp::RawBytes buff(raw_buffer, inputBufferSize, inputBufferSize);
    EXPECT_NO_THROW(spectrometer.init(buff));

Tobias Winchen's avatar
Tobias Winchen committed
434
    //// fill sci data
435
    uint64_t* sc_items = reinterpret_cast<uint64_t*>(raw_buffer + 2*nHeaps * 4096);
436
    for (size_t i = 0; i < 2 * nHeaps; i+=4)
Tobias Winchen's avatar
Tobias Winchen committed
437
    {
Tobias Winchen's avatar
Tobias Winchen committed
438
439
440
441
        sc_items[i] = 0uL;
        sc_items[i+1] = 0uL;
        sc_items[i+2] = 0uL;
        sc_items[i+3] = 0uL;
Tobias Winchen's avatar
Tobias Winchen committed
442
        SET_BIT(sc_items[i], 0);
443
        SET_BIT(sc_items[i + 1], 0);
Tobias Winchen's avatar
Tobias Winchen committed
444
    }
445
446
    sc_items[0] |= (23UL) << 32;
    sc_items[1] |= (3UL) << 32;
Tobias Winchen's avatar
Tobias Winchen committed
447

448
449
    sc_items[2] |= (27UL) << 32;
    sc_items[3] |= (7UL) << 32;
Tobias Winchen's avatar
Tobias Winchen committed
450
451


452
    for (int i = 0; i < 12; i++)
Tobias Winchen's avatar
Tobias Winchen committed
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
    {
        EXPECT_NO_THROW(spectrometer(buff));
    }

    delete [] raw_buffer;
}









Tobias Winchen's avatar
Tobias Winchen committed
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
struct gated_params
{
    std::size_t fft_length;
    std::size_t naccumulate;
    std::size_t nbits;
    std::size_t nHeaps;
    std::string msg;
};


class ExecutionTests: public testing::TestWithParam<gated_params> {
// Test that the spectrometers execute without error in certain parameter
// settings

};


TEST_P(ExecutionTests, SinglePolOutput)
{
    gated_params params = GetParam();

    const size_t heapSize = 4096 * params.nbits / 8;
    const size_t inputBufferSize = params.nHeaps * (heapSize + 64 / 8);

    psrdada_cpp::DadaDB buffer(5, inputBufferSize, 1, 4096);
    buffer.create();

    psrdada_cpp::effelsberg::edd::DadaBufferLayout bufferLayout(buffer.key(), heapSize, 1);
496
497
    // Test buffer consistency with input parameters
    EXPECT_EQ(bufferLayout.getNHeaps(), params.nHeaps);
Tobias Winchen's avatar
Tobias Winchen committed
498

Tobias Winchen's avatar
Tobias Winchen committed
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
    struct output_pointer
    {
        float* spectrum;
        size_t* nbitsset;
        size_t* nsaturated;
        output_pointer(psrdada_cpp::RawBytes& block, size_t _nchans, size_t ND, size_t offset)
        {
            size_t specsize = _nchans * sizeof(float);
            size_t memoffset = 2 * offset * (specsize + 2 * sizeof(size_t));

            spectrum = (float*)static_cast<void *>(block.ptr() + ND * specsize + memoffset);
            nbitsset = (size_t*)static_cast<void *>(block.ptr() + memoffset + 2 * specsize + ND * 2 * sizeof(size_t));
            nsaturated =(size_t*)static_cast<void *>(block.ptr() + memoffset + 2 * specsize + ND * 2 * sizeof(size_t) + sizeof(size_t));
        }
    };

    class TestSink
    {
        size_t _counter;
        size_t _nchans;
    public:
        TestSink(size_t nchans) : _nchans(nchans), _counter(0){};
        ~TestSink(){};
        void init(psrdada_cpp::RawBytes&){};
        bool operator()(psrdada_cpp::RawBytes& block){
            _counter++;
            output_pointer ND0(block, _nchans, 0, 0);
            output_pointer ND1(block, _nchans, 1, 0);

            if (_counter == 1)
            { // First sepctrum all zeros in ND on and ND off
                for (size_t i=1; i < _nchans; i++)
                {
                    EXPECT_NEAR(ND0.spectrum[i], 0, 1E-10) <<  ", i = " << i;
                    EXPECT_NEAR(ND1.spectrum[i], 0, 1E-10) <<  ", i = " << i;
                }
            }
            else if (_counter == 2)
            { // Second spectrum all data in ND1 (and flat)

                for (size_t i=1; i < _nchans; i++)
                {
                    EXPECT_GT(ND0.spectrum[i], 1) << i;
                    EXPECT_NEAR(ND0.spectrum[i], ND0.spectrum[_nchans / 2], 1E-1) << ", i = " << i;
                    EXPECT_NEAR(ND1.spectrum[i], 0, 1E-10) << i;
                }
            }
            else if (_counter == 3)
            { // Third spectrum all zeros in ND0
                for (size_t i=1; i < _nchans; i++)
                {
                    EXPECT_NEAR(ND0.spectrum[i], 0, 1E-10) << i;
                    EXPECT_GT(ND1.spectrum[i], 1) << i;
                    EXPECT_NEAR(ND1.spectrum[i], ND1.spectrum[_nchans / 2], 1E-1) <<  ", i = " << i;
                }

            }

            return false;
        };
    };
    TestSink sink(params.fft_length / 2 + 1);

Tobias Winchen's avatar
Tobias Winchen committed
562
563

    psrdada_cpp::effelsberg::edd::GatedSpectrometer<
Tobias Winchen's avatar
Tobias Winchen committed
564
        TestSink,
Tobias Winchen's avatar
Tobias Winchen committed
565
566
567
568
569
570
571
572
573
574
        psrdada_cpp::effelsberg::edd::SinglePolarizationInput,
        psrdada_cpp::effelsberg::edd::GatedPowerSpectrumOutput>
            spectrometer(bufferLayout,
                    0, 0,
                     params.fft_length,
                    params.naccumulate, params.nbits,
                    sink);

    char  *raw_buffer = new char[inputBufferSize];

Tobias Winchen's avatar
Tobias Winchen committed
575
    psrdada_cpp::RawBytes buff(raw_buffer, inputBufferSize, inputBufferSize);
Tobias Winchen's avatar
Tobias Winchen committed
576
    EXPECT_NO_THROW(spectrometer.init(buff)) << params.msg;
Tobias Winchen's avatar
Tobias Winchen committed
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
    // 1 Block, all zeros
    memset(raw_buffer, 0, inputBufferSize);
    EXPECT_NO_THROW(spectrometer(buff)) << params.msg;

    // 2 Block, set value
    raw_buffer[122] =  int8_t(13);
    EXPECT_NO_THROW(spectrometer(buff)) << params.msg;

    // 3 Block, set value and SCI
    raw_buffer[122] =  int8_t(13);
    uint64_t* sc_items = reinterpret_cast<uint64_t*>(raw_buffer + params.nHeaps * heapSize);
    for (int i = 0; i < params.nHeaps; i++)
        SET_BIT(sc_items[i], 0);
    EXPECT_NO_THROW(spectrometer(buff)) << params.msg;

    // Additional three executions to get blocks out
    EXPECT_NO_THROW(spectrometer(buff)) << params.msg;
    EXPECT_NO_THROW(spectrometer(buff)) << params.msg;
    EXPECT_NO_THROW(spectrometer(buff)) << params.msg;
Tobias Winchen's avatar
Tobias Winchen committed
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611

    delete [] raw_buffer;
}


TEST_P(ExecutionTests, FullStokesOutput)
{
    gated_params params = GetParam();

    const size_t heapSize = 4096 * params.nbits / 8;
    const size_t inputBufferSize = params.nHeaps * (heapSize + 64 / 8);

    psrdada_cpp::DadaDB buffer(5, inputBufferSize, 1, 4096);
    buffer.create();

    psrdada_cpp::effelsberg::edd::DadaBufferLayout bufferLayout(buffer.key(), heapSize, 1);
612
613
    // Test buffer consistency with input parameters
    EXPECT_EQ(bufferLayout.getNHeaps(), params.nHeaps);
Tobias Winchen's avatar
Tobias Winchen committed
614
615
616
617
618
619
620
621
622
623
624
625
626
627

    psrdada_cpp::NullSink sink;

    psrdada_cpp::effelsberg::edd::GatedSpectrometer<
        psrdada_cpp::NullSink,
        psrdada_cpp::effelsberg::edd::DualPolarizationInput,
        psrdada_cpp::effelsberg::edd::GatedFullStokesOutput>
            spectrometer(bufferLayout,
                    0, 0,
                     params.fft_length,
                    params.naccumulate, params.nbits,
                    sink);

    char  *raw_buffer = new char[inputBufferSize];
628
    memset(raw_buffer, 0, inputBufferSize);
Tobias Winchen's avatar
Tobias Winchen committed
629

Tobias Winchen's avatar
Tobias Winchen committed
630
    psrdada_cpp::RawBytes buff(raw_buffer, inputBufferSize, inputBufferSize);
Tobias Winchen's avatar
Tobias Winchen committed
631
632
633
634
635
636
637
638
639
640
641
642
643
644

    EXPECT_NO_THROW(spectrometer.init(buff)) << params.msg;
    for (int i = 0; i < 5; i++)
    {
        EXPECT_NO_THROW(spectrometer(buff)) << params.msg;
    }

    delete [] raw_buffer;
}


INSTANTIATE_TEST_CASE_P (GatedSpectrometer,
        ExecutionTests,
        testing::Values(
645
646
647
648
649
650
651
652
653

          // fft_length; naccumulate; nbits; nHeaps; msg;
          gated_params({2*1024, 2,  8, 1024, "1k Channel:  8 Bit"}),
          gated_params({2*1024, 2, 10, 1024, "1k Channel: 10 Bit"}),
          gated_params({2*1024, 2, 12, 1024, "1k Channel: 12 Bit"}),
          gated_params({2*1024 * 1024, 2,  8, 8*1024, "1M Channel, buffer 8x larger than spectrum; 8 bit"}),
          gated_params({2*1024 * 1024, 2, 10, 8*1024, "1M Channel, buffer 8x larger than spectrum; 10-bit"}),
          gated_params({2*1024 * 1024, 2, 12, 8*1024, "1M Channel, buffer 8x larger than spectrum; 12-bit"}),
          gated_params({2*1024 * 1024, 2048, 8, 1024, "1M Channel, integration larger than buffer"}),
Tobias Winchen's avatar
Tobias Winchen committed
654
655
656
          gated_params({2*1024, 4096, 8, 1024, "1k Channel, integration larger than buffer"})
            )
        );
Tobias Winchen's avatar
Tobias Winchen committed
657
658
659
660