|
| 1 | +from __future__ import annotations |
| 2 | + |
| 3 | +import pathlib |
| 4 | +import pickle |
| 5 | + |
| 6 | +import numpy as np |
| 7 | + |
| 8 | +from blimpy import Waterfall |
| 9 | +from blimpy.io import sigproc |
| 10 | + |
| 11 | + |
| 12 | +def _create_synthetic_waterfall(frame, *, max_load=1): |
| 13 | + path = pathlib.Path(__file__).resolve().parents[1] / "assets" / "sample.fil" |
| 14 | + waterfall = Waterfall(str(path), max_load=max_load) |
| 15 | + waterfall.header["source_name"] = frame.source_name |
| 16 | + waterfall.header["rawdatafile"] = "Synthetic" |
| 17 | + |
| 18 | + container_attr = { |
| 19 | + "t_begin": 0, |
| 20 | + "t_end": frame.tchans, |
| 21 | + "file_size_bytes": frame.tchans * frame.fchans * waterfall.header["nbits"] / 8, |
| 22 | + "n_channels_in_file": frame.fchans, |
| 23 | + "n_ints_in_file": frame.tchans, |
| 24 | + "file_shape": (frame.tchans, 1, frame.fchans), |
| 25 | + "f_end": frame.fmax * 1e-6, |
| 26 | + "f_begin": frame.fmin * 1e-6, |
| 27 | + "f_stop": frame.fmax * 1e-6, |
| 28 | + "f_start": frame.fmin * 1e-6, |
| 29 | + "t_start": 0, |
| 30 | + "t_stop": frame.tchans, |
| 31 | + "selection_shape": (frame.tchans, 1, frame.fchans), |
| 32 | + "chan_start_idx": 0, |
| 33 | + "chan_stop_idx": frame.fchans, |
| 34 | + } |
| 35 | + for key, value in container_attr.items(): |
| 36 | + setattr(waterfall.container, key, value) |
| 37 | + |
| 38 | + wat_attr = { |
| 39 | + "n_channels_in_file": frame.fchans, |
| 40 | + "n_ints_in_file": frame.tchans, |
| 41 | + "file_shape": (frame.tchans, 1, frame.fchans), |
| 42 | + "file_size_bytes": frame.tchans * frame.fchans * waterfall.header["nbits"] / 8, |
| 43 | + "selection_shape": (frame.tchans, 1, frame.fchans), |
| 44 | + } |
| 45 | + for key, value in wat_attr.items(): |
| 46 | + setattr(waterfall, key, value) |
| 47 | + |
| 48 | + return waterfall |
| 49 | + |
| 50 | + |
| 51 | +def _update_waterfall(frame, *, filename=None, max_load=1): |
| 52 | + if frame.waterfall is None: |
| 53 | + frame.waterfall = _create_synthetic_waterfall(frame, max_load=max_load) |
| 54 | + |
| 55 | + frame.waterfall.data = frame.data[:, np.newaxis, :] |
| 56 | + if not frame.ascending: |
| 57 | + frame.waterfall.data = frame.waterfall.data[:, :, ::-1] |
| 58 | + |
| 59 | + header_attr = { |
| 60 | + "tsamp": frame.dt, |
| 61 | + "tstart": frame.mjd, |
| 62 | + "nchans": frame.fchans, |
| 63 | + "fch1": frame.fch1 * 1e-6, |
| 64 | + } |
| 65 | + if frame.ascending: |
| 66 | + header_attr["foff"] = frame.df * 1e-6 |
| 67 | + else: |
| 68 | + header_attr["foff"] = frame.df * -1e-6 |
| 69 | + frame.waterfall.header.update(header_attr) |
| 70 | + frame.waterfall.file_header.update(header_attr) |
| 71 | + |
| 72 | + if filename is not None: |
| 73 | + frame.waterfall.container.filename = str(pathlib.Path(filename).resolve()) |
| 74 | + frame.waterfall.container.idx_data = len(sigproc.generate_sigproc_header(frame.waterfall)) |
| 75 | + |
| 76 | + |
| 77 | +def _encode_bytestrings(frame): |
| 78 | + for key in ["source_name", "rawdatafile"]: |
| 79 | + if key in frame.waterfall.header and not isinstance(frame.waterfall.header[key], bytes): |
| 80 | + frame.waterfall.header[key] = frame.waterfall.header[key].encode() |
| 81 | + |
| 82 | + |
| 83 | +def _decode_bytestrings(frame): |
| 84 | + for key in ["source_name", "rawdatafile"]: |
| 85 | + if key in frame.waterfall.header and isinstance(frame.waterfall.header[key], bytes): |
| 86 | + frame.waterfall.header[key] = frame.waterfall.header[key].decode() |
| 87 | + |
| 88 | + |
| 89 | +def _get_waterfall(frame): |
| 90 | + _update_waterfall(frame) |
| 91 | + return frame.waterfall |
| 92 | + |
| 93 | + |
| 94 | +def _check_waterfall(frame): |
| 95 | + if frame.waterfall is None: |
| 96 | + return None |
| 97 | + return _get_waterfall(frame) |
| 98 | + |
| 99 | + |
| 100 | +def _save_fil(frame, filename, *, max_load=1): |
| 101 | + _update_waterfall(frame, filename=filename, max_load=max_load) |
| 102 | + _encode_bytestrings(frame) |
| 103 | + frame.waterfall.write_to_fil(filename) |
| 104 | + _decode_bytestrings(frame) |
| 105 | + |
| 106 | + |
| 107 | +def _save_hdf5(frame, filename, *, max_load=1): |
| 108 | + _update_waterfall(frame, filename=filename, max_load=max_load) |
| 109 | + _encode_bytestrings(frame) |
| 110 | + frame.waterfall.write_to_hdf5(filename) |
| 111 | + _decode_bytestrings(frame) |
| 112 | + |
| 113 | + |
| 114 | +def _save_npy(frame, filename): |
| 115 | + np.save(filename, frame.data) |
| 116 | + |
| 117 | + |
| 118 | +def _load_npy(frame, filename): |
| 119 | + frame.data = np.load(filename) |
| 120 | + |
| 121 | + |
| 122 | +def _save_pickle(frame, filename): |
| 123 | + with open(filename, "wb") as f: |
| 124 | + pickle.dump(frame, f) |
| 125 | + |
| 126 | + |
| 127 | +def _load_pickle(filename): |
| 128 | + with open(filename, "rb") as f: |
| 129 | + return pickle.load(f) |
0 commit comments