@@ -134,6 +134,46 @@ inline int32_t _read_size(struct flac_helper *fh)
134134 return v;
135135}
136136
137+ std::vector<bool > find_time_gaps (const G3VectorTime ×)
138+ {
139+ std::vector<double > dts;
140+ dts.reserve (times.size () - 1 );
141+ for (int i = 1 ; i < times.size (); i++)
142+ dts.push_back (times[i].time - times[i - 1 ].time );
143+
144+ double dt;
145+ {
146+ int mid = dts.size () / 2 ;
147+ std::vector<double > sorted = dts;
148+ std::nth_element (sorted.begin (), sorted.begin () + mid, sorted.end ());
149+ dt = sorted[mid];
150+ }
151+
152+ std::vector<bool > gaps;
153+ gaps.reserve (times.size ());
154+ gaps.push_back (false );
155+
156+ for (int i = 0 ; i < dts.size (); i++) {
157+ int missing = (int )(std::round (dts[i] / dt - 1 ));
158+ for (int j = 0 ; j < missing; j++)
159+ gaps.push_back (true );
160+ gaps.push_back (false );
161+ }
162+
163+ return gaps;
164+ }
165+
166+ template <typename T>
167+ void fill_gaps (struct flac_helper *fh, const std::vector<bool > &gaps)
168+ {
169+ std::vector<T> src ((T*)fh->dest , (T*)fh->dest + fh->count );
170+ T *dest = (T*)fh->dest ;
171+
172+ int sidx = 0 ;
173+ for (int didx = 0 ; didx < gaps.size (); didx++)
174+ dest[didx] = (!gaps[didx] && sidx < fh->count ) ? src[sidx++] : 0.0 ;
175+ }
176+
137177template <class A > void G3SuperTimestream::load (A &ar, unsigned v)
138178{
139179 G3_CHECK_VERSION (v);
@@ -172,7 +212,10 @@ template <class A> void G3SuperTimestream::load(A &ar, unsigned v)
172212 } else
173213 log_fatal (" No support for compression algorithm times_algo=%d" , (int )times_algo);
174214
175- // XXX check times for missing samples
215+ // Create a mask of missing samples
216+ G3Time start = times[0 ];
217+ G3Time stop = times[times.size () - 1 ];
218+ std::vector<bool > time_gaps = find_time_gaps (times);
176219
177220 ar & make_nvp (" names" , names);
178221
@@ -186,37 +229,44 @@ template <class A> void G3SuperTimestream::load(A &ar, unsigned v)
186229 size_t elsize = 0 ;
187230 int ndet = shape[0 ];
188231 int nsamp = shape[1 ];
189- size_t size = ndet * nsamp;
232+ int nsamp_filled = time_gaps.size ();
233+ size_t size = ndet * nsamp_filled;
234+
235+ // Add bad sample mask to map as an extra detector channel at the end
236+ bool found_gaps = (nsamp_filled != nsamp);
237+ if (found_gaps) {
238+ names.push_back (" _nanmask" );
239+ size += nsamp_filled;
240+ }
190241
191242 ar & make_nvp (" data_algo" , data_algo);
192243 char *buf, *cbuf;
193244
194- // XXX handle nans and missing samples
195245 switch (type_num) {
196246 case TYPE_NUM_INT32: {
197247 std::shared_ptr<int32_t []> data (new int32_t [size]);
198- FromBuffer (names, nsamp , data, times[ 0 ], times[nsamp - 1 ] );
248+ FromBuffer (names, nsamp_filled , data, start, stop );
199249 buf = (char *)data.get ();
200250 elsize = sizeof (int32_t );
201251 break ;
202252 }
203253 case TYPE_NUM_FLOAT32: {
204254 std::shared_ptr<float []> data (new float [size]);
205- FromBuffer (names, nsamp , data, times[ 0 ], times[nsamp - 1 ] );
255+ FromBuffer (names, nsamp_filled , data, start, stop );
206256 buf = (char *)data.get ();
207257 elsize = sizeof (int32_t );
208258 break ;
209259 }
210260 case TYPE_NUM_INT64: {
211261 std::shared_ptr<int64_t []> data (new int64_t [size]);
212- FromBuffer (names, nsamp , data, times[ 0 ], times[nsamp - 1 ] );
262+ FromBuffer (names, nsamp_filled , data, start, stop );
213263 buf = (char *)data.get ();
214264 elsize = sizeof (int64_t );
215265 break ;
216266 }
217267 case TYPE_NUM_FLOAT64: {
218268 std::shared_ptr<double []> data (new double [size]);
219- FromBuffer (names, nsamp , data, times[ 0 ], times[nsamp - 1 ] );
269+ FromBuffer (names, nsamp_filled , data, start, stop );
220270 buf = (char *)data.get ();
221271 elsize = sizeof (int64_t );
222272 break ;
@@ -225,39 +275,58 @@ template <class A> void G3SuperTimestream::load(A &ar, unsigned v)
225275 log_fatal (" Invalid type num %d" , (int ) type_num);
226276 }
227277
228- if (data_algo == ALGO_NONE) {
229- ar & make_nvp (" data_raw" , binary_data (buf, nbytes));
230- return ;
278+ // Copy mask data to map
279+ if (found_gaps) {
280+ auto maskts = (*this )[" _nanmask" ];
281+ for (int i=0 ; i<nsamp_filled; i++)
282+ (*maskts)[i] = (double )time_gaps[i];
231283 }
232284
233- int count;
234285 std::vector<int > offsets;
235286 std::vector<double > quanta;
236287
237- // Read the flacblock
238- ar & make_nvp (" quanta" , quanta);
239- ar & make_nvp (" offsets" , offsets);
240- ar & make_nvp (" payload_bytes" , count);
241- cbuf = new char [count];
242- ar & make_nvp (" payload" , binary_data (cbuf, count));
288+ if (data_algo == ALGO_NONE) {
289+ if (!found_gaps) {
290+ ar & make_nvp (" data_raw" , binary_data (buf, nbytes));
291+ return ;
292+ }
293+
294+ for (int i=0 ; i<ndet; i++)
295+ offsets.push_back (elsize * nsamp * i);
296+
297+ cbuf = new char [nbytes];
298+ ar & make_nvp (" data_raw" , binary_data (cbuf, nbytes));
299+ } else {
300+ // Read the flacblock
301+ ar & make_nvp (" quanta" , quanta);
302+ ar & make_nvp (" offsets" , offsets);
303+
304+ int count;
305+ ar & make_nvp (" payload_bytes" , count);
306+ cbuf = new char [count];
307+ ar & make_nvp (" payload" , binary_data (cbuf, count));
308+ }
243309
244310 // Decompress or copy into a buffer.
245311 FLAC__StreamDecoderWriteCallback this_write_callback;
246312 void (*expand_func)(struct flac_helper *, int , char *) = nullptr ;
247313 void (*broadcast_func)(struct flac_helper *, int ) = nullptr ;
314+ void (*gapfill_func)(struct flac_helper *, const std::vector<bool > &) = nullptr ;
248315
249316 switch (type_num) {
250317 case TYPE_NUM_INT32:
251318 case TYPE_NUM_FLOAT32:
252319 this_write_callback = &write_callback_int<int32_t >;
253320 expand_func = expand_branch<int32_t >;
254321 broadcast_func = broadcast_val<int32_t >;
322+ gapfill_func = fill_gaps<int32_t >;
255323 break ;
256324 case TYPE_NUM_INT64:
257325 case TYPE_NUM_FLOAT64:
258326 this_write_callback = &write_callback_int<int64_t >;
259327 expand_func = expand_branch<int64_t >;
260328 broadcast_func = broadcast_val<int64_t >;
329+ gapfill_func = fill_gaps<int64_t >;
261330 break ;
262331 default :
263332 __builtin_unreachable (); // Handled above
@@ -272,7 +341,7 @@ template <class A> void G3SuperTimestream::load(A &ar, unsigned v)
272341
273342#pragma omp for
274343 for (int i=0 ; i<ndet; i++) {
275- char * this_data = buf + elsize * nsamp * i;
344+ char * this_data = buf + elsize * nsamp_filled * i;
276345
277346 // Cue up this detector's data and read the algo code.
278347 helper.src = cbuf + offsets[i];
@@ -312,23 +381,33 @@ template <class A> void G3SuperTimestream::load(A &ar, unsigned v)
312381 }
313382
314383 // Now convert for precision.
315- switch (type_num) {
316- case TYPE_NUM_FLOAT32: {
317- auto src = (int32_t *)this_data;
318- auto dest = (float *)this_data;
319- for (int j=0 ; i<nsamp; i++)
320- dest[j] = (float )src[j] * quanta[i];
321- break ;
384+ if (algo != ALGO_NONE) {
385+ switch (type_num) {
386+ case TYPE_NUM_FLOAT32: {
387+ auto src = (int32_t *)this_data;
388+ auto dest = (float *)this_data;
389+ for (int j=0 ; i<nsamp; i++)
390+ dest[j] = (float )src[j] * quanta[i];
391+ break ;
392+ }
393+ case TYPE_NUM_FLOAT64: {
394+ auto src = (int64_t *)this_data;
395+ auto dest = (double *)this_data;
396+ for (int j=0 ; j<nsamp; j++)
397+ dest[j] = (double )src[j] * quanta[i];
398+ break ;
399+ }
400+ default :
401+ break ;
402+ }
322403 }
323- case TYPE_NUM_FLOAT64: {
324- auto src = (int64_t *)this_data;
325- auto dest = (double *)this_data;
326- for (int j=0 ; j<nsamp; j++)
327- dest[j] = (double )src[j] * quanta[i];
328- break ;
329- }
330- default :
331- break ;
404+
405+ // Fill missing samples with zeros
406+ if (found_gaps) {
407+ helper.dest = this_data;
408+ helper.start = 0 ;
409+ helper.count = nsamp;
410+ gapfill_func (&helper, time_gaps);
332411 }
333412
334413 }
0 commit comments