Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PSRDADA block updates #194

Merged
merged 12 commits into from
Dec 9, 2024
13 changes: 13 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ jobs:
run: |
sudo apt-get update && \
sudo apt-get install -y \
autoconf \
automake \
build-essential \
ca-certificates \
curl \
Expand All @@ -41,6 +43,7 @@ jobs:
git \
libhwloc-dev \
libopenblas-dev \
libtool \
pkg-config \
software-properties-common
- name: "Software Install - MacOS"
Expand Down Expand Up @@ -84,6 +87,16 @@ jobs:
jupyter_client \
nbformat \
nbconvert
- name: "Software Install - PSRDADA"
if: ${{ matrix.os == 'ubuntu-20.04' || matrix.os == 'self-hosted' }}
run: |
git clone git://git.code.sf.net/p/psrdada/code psrdada
cd psrdada
./bootstrap
./configure
make -j all
sudo make install
cd ..
- uses: actions/checkout@v3
- name: "Build and Install"
run: |
Expand Down
207 changes: 207 additions & 0 deletions python/bifrost/blocks/dada_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
# Copyright (c) 2016-2023, The Bifrost Authors. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of The Bifrost Authors nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


"""
# binary_file_io.py

Basic file I/O blocks for reading and writing data.
"""
import numpy as np
import time
import bifrost as bf
import bifrost.pipeline as bfp
from bifrost.dtype import string2numpy
from astropy.time import Time
import glob
import os

Check warning on line 40 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L33-L40

Added lines #L33 - L40 were not covered by tests
jaycedowell marked this conversation as resolved.
Show resolved Hide resolved

from bifrost import telemetry
telemetry.track_module()

Check warning on line 43 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L42-L43

Added lines #L42 - L43 were not covered by tests

def _angle_str_to_sigproc(ang):
aparts = ang.split(':')
if len(aparts) == 2:
sp_ang = int(aparts[0])*10000 + int(aparts[1])*100 + 0.0
elif len(aparts) == 3:
sp_ang = int(aparts[0])*10000 + int(aparts[1])*100 + float(aparts[2])

Check warning on line 50 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L45-L50

Added lines #L45 - L50 were not covered by tests
else:
raise RuntimeError("Cannot parse: {ang} does not match XX:YY:ZZ.zz".format(ang=ang))

Check warning on line 52 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L52

Added line #L52 was not covered by tests

class DadaFileRead(object):

Check warning on line 54 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L54

Added line #L54 was not covered by tests
""" Simple file-like reading object for pipeline testing

Args:
filename (str): Name of file to open
dtype (np.dtype or str): datatype of data, e.g. float32. This should be a *numpy* dtype,
not a bifrost.ndarray dtype (eg. float32, not f32)
gulp_size (int): How much data to read per gulp, (i.e. sub-array size)
"""
def __init__(self, filename, header_callback):
super(DadaFileRead, self).__init__()
if isinstance(filename, str):
self.file_obj = open(filename, 'rb')
self.nfiles = 1

Check warning on line 67 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L63-L67

Added lines #L63 - L67 were not covered by tests
else:
self.file_obj = open(filename[0], 'rb')
self.nfiles = len(filename)

Check warning on line 70 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L69-L70

Added lines #L69 - L70 were not covered by tests

self.filenames = filename
self.fcount = 0

Check warning on line 73 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L72-L73

Added lines #L72 - L73 were not covered by tests

print("%i/%i: opening %s" % (self.fcount+1, self.nfiles, self.file_obj.name))
self._header_callback = header_callback
self.header = self._read_header(header_callback)
itensor = self.header['_tensor']
self.dtype = np.dtype(string2numpy(itensor['dtype']))
self.block_shape = np.copy(itensor['shape'])
self.block_shape[0] = 1
self.block_size = np.prod(self.block_shape)
self.gulp_size = self.block_size * self.dtype.itemsize

Check warning on line 83 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L75-L83

Added lines #L75 - L83 were not covered by tests

def _read_header(self, header_callback):

Check warning on line 85 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L85

Added line #L85 was not covered by tests
""" Read DADA header, and apply header_callback

Applies header_callback to convert DADA header to bifrost header. Specifically,
need to generate the '_tensor' from the DADA keywords which have no formal spec.
"""
hdr_buf = self.file_obj.read(4096).decode('ascii')
hdr = {}
for line in hdr_buf.split('\n'):
try:
key, val = line.split()
hdr[key] = val
except ValueError:
pass
hdr = header_callback(hdr)
return hdr

Check warning on line 100 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L91-L100

Added lines #L91 - L100 were not covered by tests

def _open_next_file(self):
self.file_obj.close()
self.fcount += 1
print("%i/%i: opening %s" % (self.fcount+1, self.nfiles, self.filenames[self.fcount]))
self.file_obj = open(self.filenames[self.fcount], 'rb')
_hdr = self._read_header(self._header_callback)

Check warning on line 107 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L102-L107

Added lines #L102 - L107 were not covered by tests

def _read_data(self):
d = np.fromfile(self.file_obj, dtype=self.dtype, count=self.block_size)
return d

Check warning on line 111 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L109-L111

Added lines #L109 - L111 were not covered by tests

def read_block(self):

Check warning on line 113 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L113

Added line #L113 was not covered by tests
#print("Reading...")
d = self._read_data()
if d.size == 0 and self.fcount < self.nfiles - 1:
self._open_next_file()
d = self._read_data()
d = d.reshape(self.block_shape)
return d
elif d.size == 0 and self.fcount == self.nfiles - 1:

Check warning on line 121 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L115-L121

Added lines #L115 - L121 were not covered by tests
#print("EOF")
return np.array([0]) # EOF
elif self.block_size != np.prod(d.shape):
print(self.block_size, np.prod(d.shape), d.shape, d.size)
print("Warning: File truncated or gulp size does not divide n_blocks")
try:
bs_truncated = list(self.block_shape)
bs_truncated[0] = -1 # Attempt to load truncated data anyway
d = d.reshape(bs_truncated)
return d
except ValueError:
return np.array([0]) # EOF

Check warning on line 133 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L123-L133

Added lines #L123 - L133 were not covered by tests
else:
d = d.reshape(self.block_shape)
return d

Check warning on line 136 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L135-L136

Added lines #L135 - L136 were not covered by tests

def read(self):
gulp_break = False
d = self.read_block()
return d

Check warning on line 141 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L138-L141

Added lines #L138 - L141 were not covered by tests


def __enter__(self):
return self

Check warning on line 145 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L144-L145

Added lines #L144 - L145 were not covered by tests

def close(self):
pass

Check warning on line 148 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L147-L148

Added lines #L147 - L148 were not covered by tests

def __exit__(self, type, value, tb):
self.close()

Check warning on line 151 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L150-L151

Added lines #L150 - L151 were not covered by tests


def generate_dada_filelist(filename):

Check warning on line 154 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L154

Added line #L154 was not covered by tests
""" Generate a list of DADA files from start filename

Args:
filename (str): Path to file. e.g.
/data/dprice/2020-07-23-02:33:07.587_0000000000000000.000000.dada

Returns:
flist (list): A list of all associated files
"""
bn = os.path.basename(filename)
dn = os.path.dirname(filename)
bn_root = '_'.join(bn.split('_')[:-1]) # Strips off _000.000.dada bit
flist = sorted(glob.glob(os.path.join(dn, bn_root + '_*.dada')))
return flist

Check warning on line 168 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L164-L168

Added lines #L164 - L168 were not covered by tests


class DadaFileReadBlock(bfp.SourceBlock):
def __init__(self, filename, header_callback, gulp_nframe, *args, **kwargs):
super(DadaFileReadBlock, self).__init__(filename, gulp_nframe, *args, **kwargs)
self.header_callback = header_callback

Check warning on line 174 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L171-L174

Added lines #L171 - L174 were not covered by tests

def create_reader(self, filename):
flist = generate_dada_filelist(filename)
return DadaFileRead(flist, self.header_callback)

Check warning on line 178 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L176-L178

Added lines #L176 - L178 were not covered by tests

def on_sequence(self, ireader, filename):
ohdr = ireader.header
return [ohdr]

Check warning on line 182 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L180-L182

Added lines #L180 - L182 were not covered by tests

def on_data(self, reader, ospans):
indata = reader.read()
odata = ospans[0].data

Check warning on line 186 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L184-L186

Added lines #L184 - L186 were not covered by tests
#print indata.shape, odata.shape
if np.prod(indata.shape) == np.prod(odata.shape[1:]):
ospans[0].data[0] = indata
return [1]

Check warning on line 190 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L188-L190

Added lines #L188 - L190 were not covered by tests
else:
# EOF or truncated block
return [0]

Check warning on line 193 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L193

Added line #L193 was not covered by tests


def read_dada_file(filename, header_callback, gulp_nframe, *args, **kwargs):

Check warning on line 196 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L196

Added line #L196 was not covered by tests
""" Block for reading binary data from file and streaming it into a bifrost pipeline

Args:
filenames (list): A list of filenames to open
header_callback (method): A function that converts from PSRDADA header into a
bifrost header.
gulp_size (int): Number of elements in a gulp (i.e. sub-array size)
gulp_nframe (int): Number of frames in a gulp. (Ask Ben / Miles for good explanation)
dtype (bifrost dtype string): dtype, e.g. f32, cf32
"""
return DadaFileReadBlock(filename, header_callback, gulp_nframe, *args, **kwargs)

Check warning on line 207 in python/bifrost/blocks/dada_file.py

View check run for this annotation

Codecov / codecov/patch

python/bifrost/blocks/dada_file.py#L207

Added line #L207 was not covered by tests
Loading
Loading