Cheetah - SKA - PSS - Prototype Time Domain Search Pipeline
SpsTester.cpp
1 /*
2  * The MIT License (MIT)
3  *
4  * Copyright (c) 2016 The SKA organisation
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 #include "cheetah/sps/test_utils/SpsTester.h"
25 #include "cheetah/sps/Sps.h"
26 #include "cheetah/data/RfimFlaggedData.h"
27 #include "cheetah/data/TimeFrequency.h"
28 #include "cheetah/generators/GaussianNoiseConfig.h"
29 #include "cheetah/generators/GaussianNoise.h"
30 #include "cheetah/generators/DispersedPulse.h"
31 #include "cheetah/generators/RfiScenario.h"
32 //#include "pss/astrotypes/sigproc/SigProc.h"
33 
34 namespace ska {
35 namespace cheetah {
36 namespace sps {
37 namespace test {
38 
39 
40 template<int ScenarioNum, typename TimeFrequencyType>
41 class TestRfiData: public data::RfimFlaggedData<TimeFrequencyType>
42 {
43  private:
45 
46  public:
47  TestRfiData(TimeFrequencyType& data);
48  ~TestRfiData();
49 
50  private:
52 
53 };
54 
55 template<int ScenarioNum, typename TimeFrequencyType>
57  : BaseT(data)
58 {
59  _generator.next(*this);
60 }
61 
62 template<int ScenarioNum, typename TimeFrequencyType>
64 {
65 }
66 
67 template<typename RfiDataType, typename TraitsType, typename PoolType>
68 void test_single_pulse_with_noise(TraitsType& traits, PoolType& pool)
69 {
70  auto& api = traits.api(pool);
71  auto& sps_config = traits.config();
72  ddtr::DedispersionConfig dedispersion_config;
73  typedef typename ddtr::DedispersionConfig::Dm Dm;
74  dedispersion_config.dm_start(Dm(0 * pss::astrotypes::units::parsecs_per_cube_cm));
75  dedispersion_config.dm_end(Dm(800 * pss::astrotypes::units::parsecs_per_cube_cm));
76  dedispersion_config.dm_step(Dm(100 * pss::astrotypes::units::parsecs_per_cube_cm));
77  sps_config.dedispersion_config(dedispersion_config);
78 
79  typedef sps::Sps<sps::Config, uint8_t> SpsType;
80  typedef typename SpsType::TimeFrequencyType DataType;
81  pss::astrotypes::DimensionSize<pss::astrotypes::units::Time> chunk_samples(10000);
82  pss::astrotypes::DimensionSize<pss::astrotypes::units::Frequency> number_of_channels(64);
83  std::shared_ptr<DataType> data = DataType::make_shared(chunk_samples, number_of_channels);
84  // generate random noise data and pass to Sps
85  // until we get a callback
87  typedef sps::Sps<sps::Config, uint8_t> SpsType;
88  typedef typename SpsType::TimeFrequencyType DataType;
89 
90  // keep sending data until we get a callback
91  //std::ofstream ofile("single_pulse.fil", std::ofstream::binary);
92  //pss::astrotypes::sigproc::Header sigproc_header;
93  //sigproc_header.number_of_channels(number_of_channels);
94  //sigproc_header.number_of_bits(8);
95  //sigproc_header.fch1(data::FrequencyType(1000.0 * boost::units::si::mega * data::hz));
96  //sigproc_header.foff(data::FrequencyType(-1.0 * boost::units::si::mega * data::hz));
97  //sigproc_header.sample_interval(boost::units::quantity<pss::astrotypes::units::Seconds, double>(0.5 * boost::units::si::milli * boost::units::si::seconds));
98  //ofile << sigproc_header;
99  //pss::astrotypes::sigproc::SigProcFormat<pss::astrotypes::units::Time, pss::astrotypes::units::Frequency> sigproc_formatter;
100  std::size_t count=0;
101  while(!traits.dm_handler_called())
102  {
103  auto data = DataType::make_shared(chunk_samples, number_of_channels);
104  data->sample_interval(boost::units::quantity<pss::astrotypes::units::Seconds, double>(0.5 * boost::units::si::milli * boost::units::si::seconds));
105  data->set_channel_frequencies_const_width(data::FrequencyType(1000.0 * boost::units::si::mega * data::hz), data::FrequencyType(-1.0 * boost::units::si::mega * data::hz));
106  std::fill(data->begin(), data->end(), 0);
107 
108  generator.next(*data);
109  RfiDataType Rfidata(*data);
110  api(*data);
111  //ofile << sigproc_formatter << *data;
112  ++count;
113  }
114  //ofile.close();
115  ASSERT_TRUE(traits.wait_sp_handler_called());
116  auto sp_data_ptr = traits.sp_data();
117  auto const& sp_data = *sp_data_ptr;
118 
119  ASSERT_GE(sp_data.size(), 1U);
120 }
121 
122 
123 template <typename TestTraits>
126 {
127 }
128 
129 template <typename TestTraits>
131 {
132 }
133 
134 template<typename TestTraits>
136 {
137 }
138 
139 template<typename TestTraits>
141 {
142 }
143 
144 
145 template<typename ArchitectureTag, typename ArchitectureCapability>
147  : _dm_called(false)
148  , _sp_called(false)
149  , _sp_call_count(0u)
150 {
151 }
152 
153 template<typename ArchitectureTag, typename ArchitectureCapability>
155 {
156  if(!_api) {
157  configure(_config); // call configuration method
158  _config.set_pool(pool);
159  _config.set_dedispersion_samples(1<<16);
160  _api.reset(new Api(_config,
161  [this](std::shared_ptr<DmType> data)
162  {
163  _dm_called = true;
164  _dm_data = data;
165  },
166  [this](std::shared_ptr<SpType> data)
167  {
168  try {
169  std::lock_guard<std::mutex> lock(_sp_data_mutex);
170  {
171  _sp_called = true;
172  ++_sp_call_count;
173  _sp_data.push_back(data);
174  }
175  } catch(...) {}
176  _sp_wait.notify_all();
177  }));
178  }
179  return *_api;
180 }
181 
182 template<typename ArchitectureTag, typename ArchitectureCapability>
184 {
185  return _config;
186 }
187 
188 template<typename ArchitectureTag, typename ArchitectureCapability>
190 {
191  return _dm_called;
192 }
193 
194 template<typename ArchitectureTag, typename ArchitectureCapability>
196 {
197  return _sp_called;
198 }
199 
200 template<typename ArchitectureTag, typename ArchitectureCapability>
202 {
203  std::unique_lock<std::mutex> lock(_sp_data_mutex);
204  _sp_wait.wait_for(lock, std::chrono::seconds(5), [this] { return _sp_called; });
205  return _sp_called;
206 }
207 
208 template<typename ArchitectureTag, typename ArchitectureCapability>
209 std::shared_ptr<typename SpsTesterTraits<ArchitectureTag, ArchitectureCapability>::SpType> SpsTesterTraits<ArchitectureTag, ArchitectureCapability>::sp_data() const
210 {
211  std::lock_guard<std::mutex> lock(_sp_data_mutex);
212  auto data_ptr = _sp_data.front();
213  _sp_data.pop_front();
214  return data_ptr;
215 }
216 
217 template<typename ArchitectureTag, typename ArchitectureCapability>
219 {
220  return _sp_call_count;
221 }
222 
223 POOL_ALGORITHM_TYPED_TEST_P(SpsTester, test_handlers)
224 {
225  TypeParam traits;
226  auto& api = traits.api(pool);
227 
228  // generate random noise data and pass to Sps
229  // until we get a callback
230  generators::GaussianNoiseConfig generator_config;
231  generators::GaussianNoise<uint8_t> generator(generator_config);
232  typedef sps::Sps<sps::Config, uint8_t> SpsType;
233  typedef typename SpsType::TimeFrequencyType DataType;
234 
235  // keep sending data until we get a callback
236  std::size_t count=0;
237  std::size_t chunk_samples=10000;
238  while(!traits.sp_handler_called())
239  {
240  auto data = DataType::make_shared(data::DimensionSize<data::Time>(chunk_samples), data::DimensionSize<data::Frequency>(64));
241  data->sample_interval(DataType::TimeType(15.0 * boost::units::si::milli * boost::units::si::seconds));
242  data->set_channel_frequencies_const_width(data::FrequencyType(1000.0 * boost::units::si::mega * data::hz), data::FrequencyType(-1.0 * boost::units::si::mega * data::hz));
243  generator.next(*data);
244  api(*data);
245  ++count;
246  }
247  ASSERT_TRUE(traits.dm_handler_called());
248 
249  // now we expec the buffer to flush data as it is destroyed. so the pool has to stay alive whilst this happns
250 }
251 
252 /*
253 POOL_ALGORITHM_TYPED_TEST_P(SpsTester, single_pulse_without_noise)
254 {
255  TypeParam traits;
256  test_single_pulse_with_noise<TestRfiData<0, data::TimeFrequency<Cpu, uint8_t>>>(traits, pool);
257 }
258 */
259 
260 POOL_ALGORITHM_TYPED_TEST_P(SpsTester, single_pulse_with_noise_1)
261 {
262  TypeParam traits;
263  test_single_pulse_with_noise<TestRfiData<1, data::TimeFrequency<Cpu, uint8_t>>>(traits, pool);
264 }
265 
266 POOL_ALGORITHM_TYPED_TEST_P(SpsTester, single_pulse_with_noise_2)
267 {
268  TypeParam traits;
269  test_single_pulse_with_noise<TestRfiData<2, data::TimeFrequency<Cpu, uint8_t>>>(traits, pool);
270 }
271 
272 POOL_ALGORITHM_TYPED_TEST_P(SpsTester, single_pulse_with_noise_3)
273 {
274  TypeParam traits;
275  test_single_pulse_with_noise<TestRfiData<3, data::TimeFrequency<Cpu, uint8_t>>>(traits, pool);
276 }
277 
278 POOL_ALGORITHM_TYPED_TEST_P(SpsTester, single_pulse_with_noise_4)
279 {
280  TypeParam traits;
281  test_single_pulse_with_noise<TestRfiData<4, data::TimeFrequency<Cpu, uint8_t>>>(traits, pool);
282 }
283 
284 POOL_ALGORITHM_TYPED_TEST_P(SpsTester, single_pulse_with_noise_5)
285 {
286  TypeParam traits;
287  test_single_pulse_with_noise<TestRfiData<5, data::TimeFrequency<Cpu, uint8_t>>>(traits, pool);
288 }
289 
290 /*
291 POOL_ALGORITHM_TYPED_TEST_P(SpsTester, test_single_pulse_without_noise)
292 {
293  TypeParam traits;
294  auto& api = traits.api(pool);
295  auto& sps_config = traits.config();
296 
297  ddtr::DedispersionConfig dedispersion_config;
298  typedef typename ddtr::DedispersionConfig::Dm Dm;
299  dedispersion_config.dm_start(Dm(0 * pss::astrotypes::units::parsecs_per_cube_cm));
300  dedispersion_config.dm_end(Dm(800 * pss::astrotypes::units::parsecs_per_cube_cm));
301  dedispersion_config.dm_step(Dm(100 * pss::astrotypes::units::parsecs_per_cube_cm));
302  sps_config.dedispersion_config(dedispersion_config);
303 
304  typedef sps::Sps<sps::Config, uint8_t> SpsType;
305  typedef typename SpsType::TimeFrequencyType DataType;
306  pss::astrotypes::DimensionSize<pss::astrotypes::units::Time> chunk_samples(10000);
307  pss::astrotypes::DimensionSize<pss::astrotypes::units::Frequency> number_of_channels(64);
308  std::shared_ptr<DataType> data = DataType::make_shared(chunk_samples, number_of_channels);
309  // generate random noise data and pass to Sps
310  // until we get a callback
311  generators::DispersedPulse<typename DataType::DataType> generator;
312  typedef sps::Sps<sps::Config, uint8_t> SpsType;
313  typedef typename SpsType::TimeFrequencyType DataType;
314 
315  // keep sending data until we get a callback
316  //std::ofstream ofile("single_pulse.fil", std::ofstream::binary);
317  pss::astrotypes::sigproc::Header sigproc_header;
318  sigproc_header.number_of_channels(number_of_channels);
319  sigproc_header.number_of_bits(8);
320  sigproc_header.fch1(data::FrequencyType(1000.0 * boost::units::si::mega * data::hz));
321  sigproc_header.foff(data::FrequencyType(-1.0 * boost::units::si::mega * data::hz));
322  sigproc_header.sample_interval(boost::units::quantity<pss::astrotypes::units::Seconds, double>(0.5 * boost::units::si::milli * boost::units::si::seconds));
323  //ofile << sigproc_header;
324  //pss::astrotypes::sigproc::SigProcFormat<pss::astrotypes::units::Time, pss::astrotypes::units::Frequency> sigproc_formatter;
325  std::size_t count=0;
326  while(!traits.dm_handler_called())
327  {
328  auto data = DataType::make_shared(chunk_samples, number_of_channels);
329  data->sample_interval(sigproc_header.sample_interval());
330  data->set_channel_frequencies_const_width(*sigproc_header.fch1(), *sigproc_header.foff());
331  std::fill(data->begin(), data->end(), 0);
332 
333  generator.next(*data);
334  api(*data);
335  //ofile << sigproc_formatter << *data;
336  ++count;
337  }
338  //ofile.close();
339  ASSERT_TRUE(traits.sp_handler_called());
340  auto const& sp_data = *traits.sp_data();
341 
342  ASSERT_GE(sp_data.size(), 1U); // there is only one candidate but we should expect many more potentials
343 }
344 // each test defined by ALGORITHM_TYPED_TEST_P must be added to the
345 // test register (each one as an element of the comma seperated list)
346 */
347 REGISTER_TYPED_TEST_CASE_P(SpsTester, test_handlers, single_pulse_with_noise_1, single_pulse_with_noise_2, single_pulse_with_noise_3, single_pulse_with_noise_4, single_pulse_with_noise_5);
348 
349 } // namespace test
350 } // namespace sps
351 } // namespace cheetah
352 } // namespace ska
bool sp_handler_called() const
return true if the sp_handler has been called
Definition: SpsTester.cpp:195
all non-templated options for the sps module
Definition: Config.h:52
Dm dm_start() const
the first dm condidate to try
bool wait_sp_handler_called() const
return true if the sp_handler has been called
Definition: SpsTester.cpp:201
std::size_t sp_handler_call_count() const
return true if the sp_handler has been called
Definition: SpsTester.cpp:218
Single Pulse Search top level interface.
Definition: Sps.h:61
bool dm_handler_called() const
return true if the dm_handler has been called
Definition: SpsTester.cpp:189
describes dedispersion configuration
TimeFrequency data with flags representing rfim detection.
Some limits and constants for FLDO.
Definition: Brdz.h:35
Dm dm_end() const
the last dm condidate to try
A class to compute timefrequency stats (mean and variance.
Dm dm_step() const
the step size to take in generating dm trials between start and end
Inject a single pulse at a specified dispersion measure.