Example #1
0
class MultiTransformBlock(Block):
    def __init__(self, irings_, guarantee=True, *args, **kwargs):
        super(MultiTransformBlock, self).__init__(irings_, *args, **kwargs)
        # Note: Must use self.irings rather than irings_ because they may
        #         actually be Block instances.
        self.guarantee = guarantee
        self.orings = [
            self.create_ring(space=iring.space) for iring in self.irings
        ]
        self._seq_count = 0
        self.perf_proclog = ProcLog(self.name + "/perf")
        self.sequence_proclogs = [
            ProcLog(self.name + "/sequence%i" % i)
            for i in range(len(self.irings))
        ]
        self.out_proclog = ProcLog(self.name + "/out")

        rnames = {'nring': len(self.orings)}
        for i, r in enumerate(self.orings):
            rnames['ring%i' % i] = r.name
        self.out_proclog.update(rnames)

    def main(self, orings):
        for iseqs in izip(
                *
            [iring.read(guarantee=self.guarantee) for iring in self.irings]):
            if self.shutdown_event.is_set():
                break
            for i, iseq in enumerate(iseqs):
                self.sequence_proclogs[i].update(iseq.header)
            oheaders = self._on_sequence(iseqs)
            for ohdr in oheaders:
                if 'time_tag' not in ohdr:
                    ohdr['time_tag'] = self._seq_count
            self._seq_count += 1

            igulp_nframes = [
                self.gulp_nframe or iseq.header['gulp_nframe']
                for iseq in iseqs
            ]
            igulp_overlaps = self._define_input_overlap_nframe(iseqs)
            istride_nframes = igulp_nframes[:]
            igulp_nframes = [
                igulp_nframe + nframe_overlap
                for igulp_nframe, nframe_overlap in zip(
                    igulp_nframes, igulp_overlaps)
            ]

            for iseq, igulp_nframe in zip(iseqs, igulp_nframes):
                if self.buffer_factor is None:
                    src_block = iseq.ring.owner
                    if src_block is not None and self.is_fused_with(src_block):
                        buffer_factor = 1
                    else:
                        buffer_factor = None
                else:
                    buffer_factor = self.buffer_factor
                iseq.resize(gulp_nframe=igulp_nframe,
                            buf_nframe=self.buffer_nframe,
                            buffer_factor=buffer_factor)

            # TODO: Ever need to specify starting offset?
            iframe0s = [0 for _ in igulp_nframes]

            force_skip = False

            with ExitStack() as oseq_stack:
                oseqs, ogulp_overlaps = self.begin_sequences(
                    oseq_stack, orings, oheaders, igulp_nframes,
                    istride_nframes)
                if self.shutdown_event.is_set():
                    break
                prev_time = time.time()
                for ispans in izip(*[
                        iseq.read(igulp_nframe, istride_nframe, iframe0)
                        for (iseq, igulp_nframe, istride_nframe, iframe0) in
                        zip(iseqs, igulp_nframes, istride_nframes, iframe0s)
                ]):
                    if self.shutdown_event.is_set():
                        return

                    if any([ispan.nframe_skipped for ispan in ispans]):
                        # There were skipped (overwritten) frames
                        with ExitStack() as ospan_stack:
                            iskip_slices = [
                                slice(iframe0, iframe0 + ispan.nframe_skipped,
                                      istride_nframe)
                                for iframe0, istride_nframe, ispan in zip(
                                    iframe0s, istride_nframes, ispans)
                            ]
                            iskip_nframes = [
                                ispan.nframe_skipped for ispan in ispans
                            ]
                            # ***TODO: Need to loop over multiple ospans here,
                            #            because iskip_nframes can be
                            #            arbitrarily large!
                            ospans = self.reserve_spans(
                                ospan_stack, oseqs, iskip_nframes)
                            ostrides_actual = self._on_skip(
                                iskip_slices, ospans)
                            device.stream_synchronize()
                            self.commit_spans(ospans, ostrides_actual,
                                              ogulp_overlaps)

                    if all([ispan.nframe == 0 for ispan in ispans]):
                        # No data to see here, move right along
                        continue

                    cur_time = time.time()
                    acquire_time = cur_time - prev_time
                    prev_time = cur_time

                    with ExitStack() as ospan_stack:
                        igulp_nframes = [ispan.nframe for ispan in ispans]
                        ospans = self.reserve_spans(ospan_stack, oseqs,
                                                    igulp_nframes)
                        cur_time = time.time()
                        reserve_time = cur_time - prev_time
                        prev_time = cur_time

                        if not force_skip:
                            # *TODO: See if can fuse together multiple on_data calls here before
                            #          calling stream_synchronize().
                            #        Consider passing .data instead of rings here
                            ostrides_actual = self._on_data(ispans, ospans)
                            device.stream_synchronize()

                        any_frames_overwritten = any(
                            [ispan.nframe_overwritten for ispan in ispans])
                        if force_skip or any_frames_overwritten:
                            # Note: To allow interrupted pipelines to catch up,
                            #         we force-skip an additional gulp whenever
                            #         a span is overwritten during on_data.
                            force_skip = any_frames_overwritten
                            iskip_slices = [
                                slice(
                                    ispan.frame_offset, ispan.frame_offset +
                                    ispan.nframe_overwritten, istride_nframe)
                                for ispan, istride_nframe in zip(
                                    ispans, istride_nframes)
                            ]
                            ostrides_actual = self._on_skip(
                                iskip_slices, ospans)
                            device.stream_synchronize()

                        self.commit_spans(ospans, ostrides_actual,
                                          ogulp_overlaps)
                    cur_time = time.time()
                    process_time = cur_time - prev_time
                    prev_time = cur_time
                    self.perf_proclog.update({
                        'acquire_time': acquire_time,
                        'reserve_time': reserve_time,
                        'process_time': process_time
                    })
            # **TODO: This will not be called if an exception is raised
            #           Need to call it from a context manager somehow
            self._on_sequence_end(iseqs)

    def _on_sequence(self, iseqs):
        return self.on_sequence(iseqs)

    def _on_sequence_end(self, iseqs):
        return self.on_sequence_end(iseqs)

    def _on_data(self, ispans, ospans):
        return self.on_data(ispans, ospans)

    def _on_skip(self, islices, ospans):
        return self.on_skip(islices, ospans)

    def _define_input_overlap_nframe(self, iseqs):
        return self.define_input_overlap_nframe(iseqs)

    def define_input_overlap_nframe(self, iseqs):
        """Return no. input frames that should overlap between successive spans
        for each input sequence.
        """
        return [0] * len(self.irings)

    def define_output_nframes(self, input_nframes):
        """Return output nframe for each output, given input_nframes.
        """
        return input_nframes

    def on_sequence(self, iseqs):
        """Return: oheaders (one per output)
        """
        raise NotImplementedError

    def on_sequence_end(self, iseqs):
        """Do any necessary cleanup"""
        pass

    def on_data(self, ispans, ospans):
        """Process data from from ispans to ospans and return the number of
        frames to commit for each output (or None to commit complete spans)."""
        raise NotImplementedError

    def on_skip(self, islices, ospans):
        """Handle skipped frames"""
        raise NotImplementedError
Example #2
0
class Block(BlockScope):
    instance_counts = defaultdict(lambda: 0)

    def __init__(self, irings, name=None, type_=None, **kwargs):
        self.type = type_ or self.__class__.__name__
        self.name = name or '%s_%i' % (self.type,
                                       Block.instance_counts[self.type])
        Block.instance_counts[self.type] += 1
        super(Block, self).__init__(**kwargs)
        self.pipeline = get_default_pipeline()
        self.pipeline.blocks.append(self)

        # Allow Block instances to be passed in place of rings
        irings = [get_ring(iring) for iring in irings]
        self.irings = irings
        valid_inp_spaces = self._define_valid_input_spaces()
        for i, (iring, valid_spaces) in enumerate(zip(irings,
                                                      valid_inp_spaces)):
            if not memory.space_accessible(iring.space, valid_spaces):
                raise ValueError(
                    "Block %s input %i's space must be accessible from one of: %s"
                    % (self.name, i, str(valid_spaces)))
        self.orings = []  # Update this in subclass constructors
        self.shutdown_event = threading.Event()
        self.bind_proclog = ProcLog(self.name + "/bind")
        self.in_proclog = ProcLog(self.name + "/in")

        rnames = {'nring': len(self.irings)}
        for i, r in enumerate(self.irings):
            rnames['ring%i' % i] = r.name
        self.in_proclog.update(rnames)
        self.init_trace = ''.join(traceback.format_stack()[:-1])

    def shutdown(self):
        self.shutdown_event.set()

    def create_ring(self, *args, **kwargs):
        return Ring(*args, owner=self, **kwargs)

    def run(self):
        #affinity.set_openmp_cores(cpus) # TODO
        core = self.core
        if core is not None:
            affinity.set_core(core if isinstance(core, int) else core[0])
        self.bind_proclog.update({'ncore': 1, 'core0': affinity.get_core()})
        if self.gpu is not None:
            device.set_device(self.gpu)
        self.cache_scope_hierarchy()
        with ExitStack() as oring_stack:
            active_orings = self.begin_writing(oring_stack, self.orings)
            try:
                self.main(active_orings)
            except Exception:
                self.pipeline.block_init_queue.put((self, False))
                sys.stderr.write("From block instantiated here:\n")
                sys.stderr.write(self.init_trace)
                raise

    def num_outputs(self):
        # TODO: This is a little hacky
        return len(self.orings)

    def begin_writing(self, exit_stack, orings):
        return [
            exit_stack.enter_context(oring.begin_writing()) for oring in orings
        ]

    def begin_sequences(self, exit_stack, orings, oheaders, igulp_nframes,
                        istride_nframes):
        # Note: The gulp_nframe that is set in the output header does not
        #         include the overlap (i.e., it's based on stride not gulp).
        ostride_nframes = self._define_output_nframes(istride_nframes)
        for ohdr, ostride_nframe in zip(oheaders, ostride_nframes):
            ohdr['gulp_nframe'] = ostride_nframe
        ogulp_nframes = self._define_output_nframes(igulp_nframes)
        # Note: This always specifies buffer_factor=1 on the assumption that
        #         additional buffering is defined by the reader(s) rather
        #         than the writer.
        obuf_nframes = [1 * ogulp_nframe for ogulp_nframe in ogulp_nframes]
        oseqs = [
            exit_stack.enter_context(
                oring.begin_sequence(ohdr, ogulp_nframe, obuf_nframe))
            for (oring, ohdr, ogulp_nframe, obuf_nframe
                 ) in zip(orings, oheaders, ogulp_nframes, obuf_nframes)
        ]

        # Synchronize all blocks here to ensure no sequence race conditions
        self.pipeline.block_init_queue.put((self, True))
        self.pipeline.all_blocks_finished_initializing_event.wait()

        ogulp_overlaps = [
            ogulp_nframe - ostride_nframe for ogulp_nframe, ostride_nframe in
            zip(ogulp_nframes, ostride_nframes)
        ]
        return oseqs, ogulp_overlaps

    def reserve_spans(self, exit_stack, oseqs, igulp_nframes=[]):
        ogulp_nframes = self._define_output_nframes(igulp_nframes)
        return [
            exit_stack.enter_context(oseq.reserve(ogulp_nframe))
            for (oseq, ogulp_nframe) in zip(oseqs, ogulp_nframes)
        ]

    def commit_spans(self, ospans, ostrides_actual, ogulp_overlaps):
        # Allow returning None to indicate complete consumption
        if ostrides_actual is None:
            ostrides = [None] * len(ospans)
        # Note: If ospan.nframe < ogulp_overlap, no frames will be committed
        ostrides = [
            ostride if ostride is not None else max(
                ospan.nframe - ogulp_overlap, 0)
            for (ostride, ospan,
                 ogulp_overlap) in zip(ostrides_actual, ospans, ogulp_overlaps)
        ]
        for ospan, ostride in zip(ospans, ostrides):
            ospan.commit(ostride)

    def _define_output_nframes(self, input_nframes):
        return self.define_output_nframes(input_nframes)

    def define_output_nframes(self, input_nframes):
        """Return output nframe for each output, given input_nframes.
        """
        raise NotImplementedError

    def _define_valid_input_spaces(self):
        return self.define_valid_input_spaces()

    def define_valid_input_spaces(self):
        """Return set of valid spaces (or 'any') for each input"""
        return ['any'] * len(self.irings)
Example #3
0
class SourceBlock(Block):
    def __init__(self, sourcenames, gulp_nframe, space=None, *args, **kwargs):
        super(SourceBlock, self).__init__([],
                                          *args,
                                          gulp_nframe=gulp_nframe,
                                          **kwargs)
        self.sourcenames = sourcenames
        default_space = 'cuda_host' if core.cuda_enabled() else 'system'
        if space is None:
            space = default_space
        self.orings = [self.create_ring(space=space)]
        self._seq_count = 0
        self.perf_proclog = ProcLog(self.name + "/perf")
        self.out_proclog = ProcLog(self.name + "/out")

        rnames = {'nring': len(self.orings)}
        for i, r in enumerate(self.orings):
            rnames['ring%i' % i] = r.name
        self.out_proclog.update(rnames)

    def main(self, orings):
        for sourcename in self.sourcenames:
            if self.shutdown_event.is_set():
                break
            with self.create_reader(sourcename) as ireader:
                oheaders = self.on_sequence(ireader, sourcename)
                for ohdr in oheaders:
                    if 'time_tag' not in ohdr:
                        ohdr['time_tag'] = self._seq_count
                    if 'name' not in ohdr:
                        ohdr['name'] = 'unnamed-sequence-%i' % self._seq_count
                self._seq_count += 1
                with ExitStack() as oseq_stack:
                    oseqs, ogulp_overlaps = self.begin_sequences(
                        oseq_stack,
                        orings,
                        oheaders,
                        igulp_nframes=[],
                        istride_nframes=[])
                    while not self.shutdown_event.is_set():
                        prev_time = time.time()
                        with ExitStack() as ospan_stack:
                            ospans = self.reserve_spans(ospan_stack, oseqs)
                            cur_time = time.time()
                            reserve_time = cur_time - prev_time
                            prev_time = cur_time
                            ostrides_actual = self.on_data(ireader, ospans)
                            device.stream_synchronize()
                            self.commit_spans(ospans, ostrides_actual,
                                              ogulp_overlaps)
                            # TODO: Is this an OK way to detect end-of-data?
                            if any(
                                [ostride == 0 for ostride in ostrides_actual]):
                                break
                        cur_time = time.time()
                        process_time = cur_time - prev_time
                        prev_time = cur_time
                        self.perf_proclog.update({
                            'acquire_time': -1,
                            'reserve_time': reserve_time,
                            'process_time': process_time
                        })

    def define_output_nframes(self, _):
        """Return output nframe for each output, given input_nframes.
        """
        return [self.gulp_nframe] * self.num_outputs()

    def define_valid_input_spaces(self):
        """Return set of valid spaces (or 'any') for each input"""
        return []

    def create_reader(self, sourcename):
        """Return an object to use for reading source data"""
        # TODO: Should return a dummy reader object here?
        raise NotImplementedError

    def on_sequence(self, reader, sourcename):
        """Return header for each output"""
        raise NotImplementedError

    def on_data(self, reader, ospans):
        """Process data from from ispans to ospans and return the number of
        frames to commit for each output."""
        raise NotImplementedError
class StatisticsOp(object):
    def __init__(self, log, id, iring, ntime_gulp=1, guarantee=True, core=None):
        self.log        = log
        self.iring      = iring
        self.ntime_gulp = ntime_gulp
        self.guarantee  = guarantee
        self.core       = core
        
        self.client = Client(id)
        
        self.bind_proclog = ProcLog(type(self).__name__+"/bind")
        self.in_proclog   = ProcLog(type(self).__name__+"/in")
        self.size_proclog = ProcLog(type(self).__name__+"/size")
        self.sequence_proclog = ProcLog(type(self).__name__+"/sequence0")
        self.perf_proclog = ProcLog(type(self).__name__+"/perf")
        
        self.in_proclog.update(  {'nring':1, 'ring0':self.iring.name})
        self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp})
        
    def main(self):
        if self.core is not None:
            cpu_affinity.set_core(self.core)
        self.bind_proclog.update({'ncore': 1, 
                                  'core0': cpu_affinity.get_core(),})
        
        for iseq in self.iring.read(guarantee=self.guarantee):
            ihdr = json.loads(iseq.header.tostring())
            
            self.sequence_proclog.update(ihdr)
            
            self.log.info("Statistics: Start of new sequence: %s", str(ihdr))
            
            # Setup the ring metadata and gulp sizes
            time_tag = ihdr['time_tag']
            navg     = ihdr['navg']
            nbl      = ihdr['nbl']
            nstand   = ihdr['nstand']
            chan0    = ihdr['chan0']
            nchan    = ihdr['nchan']
            chan_bw  = ihdr['bw'] / nchan
            npol     = ihdr['npol']
            
            igulp_size = self.ntime_gulp*nbl*nchan*npol*8        # ci32
            ishape = (self.ntime_gulp,nbl,nchan,npol)
            
            autos = [i*(2*(nstand-1)+1-i)//2 + i for i in range(nstand)]
            data_pols = ['XX', 'YY']
            last_save = 0.0
            
            prev_time = time.time()
            iseq_spans = iseq.read(igulp_size)
            for ispan in iseq_spans:
                if ispan.size < igulp_size:
                    continue # Ignore final gulp
                curr_time = time.time()
                acquire_time = curr_time - prev_time
                prev_time = curr_time
                
                ## Setup and load
                idata = ispan.data_view('ci32').reshape(ishape)
                
                if time.time() - last_save > 60:
                    ## Timestamp
                    tt = LWATime(time_tag, format='timetag')
                    ts = tt.unix
                    
                    ## Pull out the auto-correlations
                    adata = idata.view(numpy.int32)
                    adata = adata.reshape(ishape+(2,))
                    adata = adata[0,autos,:,:,0]
                    adata = adata[:,:,[0,3]]
                    
                    ## Run the statistics over all times/channels
                    ##  * only really works for ntime_gulp=1
                    data_min = numpy.min(adata, axis=1)
                    data_max = numpy.max(adata, axis=1)
                    data_avg = numpy.mean(adata, axis=1)
                    
                    ## Save
                    for data,name in zip((data_min,data_avg,data_max), ('min','avg','max')):
                        value = MultiMonitorPoint([data[:,i].tolist() for i in range(data.shape[1])],
                                                  timestamp=ts, field=data_pols)
                        self.client.write_monitor_point('statistics/%s' % name, value)
                        
                    last_save = time.time()
                    
                time_tag += navg * self.ntime_gulp
                
                curr_time = time.time()
                process_time = curr_time - prev_time
                prev_time = curr_time
                self.perf_proclog.update({'acquire_time': acquire_time, 
                                          'reserve_time': -1, 
                                          'process_time': process_time,})
                
        self.log.info("StatisticsOp - Done")
class WriterOp(object):
    def __init__(self, log, station, iring, ntime_gulp=1, fast=False, guarantee=True, core=None):
        self.log        = log
        self.station    = station
        self.iring      = iring
        self.ntime_gulp = ntime_gulp
        self.fast       = fast
        self.guarantee  = guarantee
        self.core       = core
        
        self.bind_proclog = ProcLog(type(self).__name__+"/bind")
        self.in_proclog   = ProcLog(type(self).__name__+"/in")
        self.size_proclog = ProcLog(type(self).__name__+"/size")
        self.sequence_proclog = ProcLog(type(self).__name__+"/sequence0")
        self.perf_proclog = ProcLog(type(self).__name__+"/perf")
        
        self.in_proclog.update(  {'nring':1, 'ring0':self.iring.name})
        self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp})
        
    def main(self):
        global QUEUE
        
        if self.core is not None:
            cpu_affinity.set_core(self.core)
        self.bind_proclog.update({'ncore': 1, 
                                  'core0': cpu_affinity.get_core(),})
        
        for iseq in self.iring.read(guarantee=self.guarantee):
            ihdr = json.loads(iseq.header.tostring())
            
            self.sequence_proclog.update(ihdr)
            
            self.log.info("Writer: Start of new sequence: %s", str(ihdr))
            
            # Setup the ring metadata and gulp sizes
            time_tag = ihdr['time_tag']
            navg     = ihdr['navg']
            nbl      = ihdr['nbl']
            chan0    = ihdr['chan0']
            nchan    = ihdr['nchan']
            chan_bw  = ihdr['bw'] / nchan
            npol     = ihdr['npol']
            pols     = ['XX','XY','YX','YY']
            
            igulp_size = self.ntime_gulp*nbl*nchan*npol*8        # ci32
            ishape = (self.ntime_gulp,nbl,nchan,npol)
            self.iring.resize(igulp_size, 10*igulp_size*(4 if self.fast else 1))
            
            norm_factor = navg // (2*NCHAN)
            
            first_gulp = True
            was_active = False
            prev_time = time.time()
            iseq_spans = iseq.read(igulp_size)
            for ispan in iseq_spans:
                if ispan.size < igulp_size:
                    continue # Ignore final gulp
                curr_time = time.time()
                acquire_time = curr_time - prev_time
                prev_time = curr_time
                
                ## On our first span, update the pipeline lag for the queue
                ## so that we start recording at the right times
                if first_gulp:
                    QUEUE.update_lag(LWATime(time_tag, format='timetag').datetime)
                    self.log.info("Current pipeline lag is %s", QUEUE.lag)
                    first_gulp = False
                    
                ## Setup and load
                idata = ispan.data_view('ci32').reshape(ishape)
                idata = idata.view(numpy.int32)
                idata = idata.reshape(ishape+(2,))
                idata = idata[...,0] + 1j*idata[...,1]
                idata /= norm_factor
                idata = idata.astype(numpy.complex64)
                
                ## Determine what to do
                if QUEUE.active is not None:
                    ### Recording active - write
                    if not QUEUE.active.is_started:
                        self.log.info("Started operation - %s", QUEUE.active)
                        QUEUE.active.start(self.station, chan0, navg, nchan, chan_bw, npol, pols)
                        was_active = True
                    QUEUE.active.write(time_tag, idata)
                elif was_active:
                    ### Recording just finished
                    #### Clean
                    was_active = False
                    QUEUE.clean()
                    
                    #### Close
                    self.log.info("Ended operation - %s", QUEUE.previous)
                    QUEUE.previous.stop()
                    
                time_tag += navg
                
                curr_time = time.time()
                process_time = curr_time - prev_time
                prev_time = curr_time
                self.perf_proclog.update({'acquire_time': acquire_time, 
                                          'reserve_time': -1, 
                                          'process_time': process_time,})
                
        self.log.info("WriterOp - Done")
class SpectraOp(object):
    def __init__(self, log, id, iring, ntime_gulp=1, guarantee=True, core=-1):
        self.log        = log
        self.iring      = iring
        self.ntime_gulp = ntime_gulp
        self.guarantee  = guarantee
        self.core       = core
        
        self.client = Client(id)
        
        self.bind_proclog = ProcLog(type(self).__name__+"/bind")
        self.in_proclog   = ProcLog(type(self).__name__+"/in")
        self.size_proclog = ProcLog(type(self).__name__+"/size")
        self.sequence_proclog = ProcLog(type(self).__name__+"/sequence0")
        self.perf_proclog = ProcLog(type(self).__name__+"/perf")
        
        self.in_proclog.update({'nring':1, 'ring0':self.iring.name})
        
    def _plot_spectra(self, time_tag, freq, specs):
        # Plotting setup
        nchan = freq.size
        nstand = specs.shape[0]
        try:
            minval = numpy.min(specs[numpy.where(numpy.isfinite(specs))])
            maxval = numpy.max(specs[numpy.where(numpy.isfinite(specs))])
        except ValueError:
            minval = 0.0
            maxval = 1.0
            
        # Image setup
        width = 20
        height = 18
        im = PIL.Image.new('RGB', (width * 65 + 1, height * 65 + 21), '#FFFFFF')
        draw = PIL.ImageDraw.Draw(im)
        font = PIL.ImageFont.load(os.path.join(BASE_PATH, 'fonts', 'helvB10.pil'))
       
        # Axes boxes
        for i in range(width + 1):
            draw.line([i * 65, 0, i * 65, height * 65], fill = '#000000')
        for i in range(height + 1):
            draw.line([(0, i * 65), (im.size[0], i * 65)], fill = '#000000')
            
        # Power as a function of frequency for all antennas
        x = numpy.arange(nchan) * 64 // nchan
        for s in range(nstand):
            if s >= height * width:
                break
            x0, y0 = (s % width) * 65 + 1, (s // width + 1) * 65
            draw.text((x0 + 5, y0 - 60), str(s+1), font=font, fill='#000000')
            
            ## XX
            c = '#1F77B4'
            y = ((54.0 / (maxval - minval)) * (specs[s,:,0] - minval)).clip(0, 54)
            draw.point(list(zip(x0 + x, y0 - y)), fill=c)
            
            ## YY
            c = '#FF7F0E'
            y = ((54.0 / (maxval - minval)) * (specs[s,:,1] - minval)).clip(0, 54)
            draw.point(list(zip(x0 + x, y0 - y)), fill=c)
            
        # Summary
        ySummary = height * 65 + 2
        timeStr = datetime.utcfromtimestamp(time_tag / FS)
        timeStr = timeStr.strftime("%Y/%m/%d %H:%M:%S UTC")
        draw.text((5, ySummary), timeStr, font = font, fill = '#000000')
        rangeStr = 'range shown: %.3f to %.3f dB' % (minval, maxval)
        draw.text((210, ySummary), rangeStr, font = font, fill = '#000000')
        x = im.size[0] + 15
        for label, c in reversed(list(zip(('XX',     'YY'),
                                          ('#1F77B4','#FF7F0E')))):
            x -= draw.textsize(label, font = font)[0] + 20
            draw.text((x, ySummary), label, font = font, fill = c)
            
        return im
        
    def main(self):
        cpu_affinity.set_core(self.core)
        self.bind_proclog.update({'ncore': 1, 
                                  'core0': cpu_affinity.get_core(),})
        
        for iseq in self.iring.read(guarantee=self.guarantee):
            ihdr = json.loads(iseq.header.tostring())
            
            self.sequence_proclog.update(ihdr)
            
            self.log.info("Spectra: Start of new sequence: %s", str(ihdr))
            
            # Setup the ring metadata and gulp sizes
            time_tag = ihdr['time_tag']
            navg     = ihdr['navg']
            nbl      = ihdr['nbl']
            nstand   = ihdr['nstand']
            chan0    = ihdr['chan0']
            nchan    = ihdr['nchan']
            chan_bw  = ihdr['bw'] / nchan
            npol     = ihdr['npol']
            
            igulp_size = self.ntime_gulp*nbl*nchan*npol*8   # ci32
            ishape = (self.ntime_gulp,nbl,nchan,npol)
            
            # Setup the arrays for the frequencies and auto-correlations
            freq = chan0*chan_bw + numpy.arange(nchan)*chan_bw
            autos = [i*(2*(nstand-1)+1-i)//2 + i for i in range(nstand)]
            last_save = 0.0
            
            prev_time = time.time()
            for ispan in iseq.read(igulp_size):
                if ispan.size < igulp_size:
                    continue # Ignore final gulp
                curr_time = time.time()
                acquire_time = curr_time - prev_time
                prev_time = curr_time
                
                ## Setup and load
                idata = ispan.data_view('ci32').reshape(ishape)
                
                if time.time() - last_save > 60:
                    ## Timestamp
                    tt = LWATime(time_tag, format='timetag')
                    ts = tt.unix
                    
                    ## Pull out the auto-correlations
                    adata = idata.view(numpy.int32)
                    adata = adata.reshape(ishape+(2,))
                    adata = adata[0,autos,:,:,0]
                    adata = adata[:,:,[0,3]]
                    
                    ## Plot
                    im = self._plot_spectra(time_tag, freq, 10*numpy.log10(adata))
                    
                    ## Save
                    mp = ImageMonitorPoint.from_image(im)
                    self.client.write_monitor_point('diagnostics/spectra',
                                                    mp, timestamp=ts)
                    
                    last_save = time.time()
                    
                time_tag += navg * self.ntime_gulp
                
                curr_time = time.time()
                process_time = curr_time - prev_time
                prev_time = curr_time
                self.perf_proclog.update({'acquire_time': acquire_time, 
                                          'reserve_time': 0.0, 
                                          'process_time': process_time,})
                
        self.log.info("SpectraOp - Done")
class BaselineOp(object):
    def __init__(self, log, id, station, iring, ntime_gulp=1, guarantee=True, core=-1):
        self.log        = log
        self.station    = station
        self.iring      = iring
        self.ntime_gulp = ntime_gulp
        self.guarantee  = guarantee
        self.core       = core
        
        self.client = Client(id)
        
        self.bind_proclog = ProcLog(type(self).__name__+"/bind")
        self.in_proclog   = ProcLog(type(self).__name__+"/in")
        self.size_proclog = ProcLog(type(self).__name__+"/size")
        self.sequence_proclog = ProcLog(type(self).__name__+"/sequence0")
        self.perf_proclog = ProcLog(type(self).__name__+"/perf")
        
        self.in_proclog.update({'nring':1, 'ring0':self.iring.name})
        
    def _plot_baselines(self, time_tag, freq, dist, baselines, valid):
        # Plotting setup
        nchan = freq.size
        nbl = baselines.shape[0]
        freq = freq[nchan//2]
        baselines = baselines[valid,nchan//2,:]
        baselines = numpy.abs(baselines[:,[0,1,3]])
        minval = numpy.min(baselines)
        maxval = numpy.max(baselines)
        if minval == maxval:
            maxval = minval + 1.0
            
        mindst = 0.0
        maxdst = numpy.max(dist)
        
        # Image setup
        im = PIL.Image.new('RGB', (601, 421), '#FFFFFF')
        draw = PIL.ImageDraw.Draw(im)
        font = PIL.ImageFont.load(os.path.join(BASE_PATH, 'fonts', 'helvB10.pil'))
        
        # Axes boxes
        for i in range(2):
            draw.line([i * 600, 0, i * 600, 400], fill = '#000000')
        for i in range(2):
            draw.line([(0, i * 400), (im.size[0], i * 400)], fill = '#000000')
            
        # Visiblity amplitudes as a function of (u,v) distance
        x0, y0 = 1, 400
        draw.text((x0 + 500, y0 - 395), '%.3f MHz' % (freq/1e6,), font=font, fill='#000000')
        
        ## (u,v) distance
        x = ((599.0 / (maxdst - mindst)) * (dist - mindst)).clip(0, 599)
        
        ## XX
        y = ((399.0 / (maxval - minval)) * (baselines[:,0] - minval)).clip(0, 399)
        draw.point(list(zip(x0 + x, y0 - y)), fill='#1F77B4')
        
        ## YY
        y = ((399.0 / (maxval - minval)) * (baselines[:,2] - minval)).clip(0, 399)
        draw.point(list(zip(x0 + x, y0 - y)), fill='#FF7F0E')
        
        ### XY
        #y = ((399.0 / (maxval - minval)) * (baselines[:,1] - minval)).clip(0, 399)
        #draw.point(list(zip(x0 + x, y0 - y)), fill='#A00000')
        
        # Details and labels
        ySummary = 402
        timeStr = datetime.utcfromtimestamp(time_tag / FS)
        timeStr = timeStr.strftime("%Y/%m/%d %H:%M:%S UTC")
        draw.text((5, ySummary), timeStr, font = font, fill = '#000000')
        rangeStr = 'range shown: %.6f - %.6f' % (minval, maxval)
        draw.text((210, ySummary), rangeStr, font = font, fill = '#000000')
        x = im.size[0] + 15
        #for label, c in reversed(list(zip(('XX','XY','YY'), ('#1F77B4','#A00000','#FF7F0E')))):
        for label, c in reversed(list(zip(('XX','YY'), ('#1F77B4','#FF7F0E')))):
            x -= draw.textsize(label, font = font)[0] + 20
            draw.text((x, ySummary), label, font = font, fill = c)
            
        return im
        
    def main(self):
        cpu_affinity.set_core(self.core)
        self.bind_proclog.update({'ncore': 1, 
                                  'core0': cpu_affinity.get_core(),})
        
        for iseq in self.iring.read(guarantee=self.guarantee):
            ihdr = json.loads(iseq.header.tostring())
            
            self.sequence_proclog.update(ihdr)
            
            self.log.info("Baseline: Start of new sequence: %s", str(ihdr))
            
            # Setup the ring metadata and gulp sizes
            time_tag = ihdr['time_tag']
            navg     = ihdr['navg']
            nbl      = ihdr['nbl']
            nstand   = ihdr['nstand']
            chan0    = ihdr['chan0']
            nchan    = ihdr['nchan']
            chan_bw  = ihdr['bw'] / nchan
            npol     = ihdr['npol']
            
            igulp_size = self.ntime_gulp*nbl*nchan*npol*8
            ishape = (self.ntime_gulp,nbl,nchan,npol)
            self.iring.resize(igulp_size)
            
            # Setup the arrays for the frequencies and baseline lenghts
            freq = chan0*chan_bw + numpy.arange(nchan)*chan_bw
            uvw = get_zenith_uvw(self.station, LWATime(time_tag, format='timetag'))
            uvw[:,2] = 0
            dist = numpy.sqrt((uvw**2).sum(axis=1))
            valid = numpy.where(dist > 0.1)[0]
            last_save = 0.0
            
            prev_time = time.time()
            for ispan in iseq.read(igulp_size):
                if ispan.size < igulp_size:
                    continue # Ignore final gulp
                curr_time = time.time()
                acquire_time = curr_time - prev_time
                prev_time = curr_time
                
                ## Setup and load
                idata = ispan.data_view('ci32').reshape(ishape)
                
                if time.time() - last_save > 60:
                    ## Timestamp
                    tt = LWATime(time_tag, format='timetag')
                    ts = tt.unix
                    
                    ## Plot
                    bdata = idata[0,...]
                    bdata = bdata.view(numpy.int32)
                    bdata = bdata.reshape(ishape+(2,))
                    bdata = bdata[0,:,:,:,0] + 1j*bdata[0,:,:,:,1]
                    bdata = bdata.astype(numpy.complex64)
                    im = self._plot_baselines(time_tag, freq, dist, bdata, valid)
                    
                    ## Save
                    mp = ImageMonitorPoint.from_image(im)
                    self.client.write_monitor_point('diagnostics/baselines',
                                                    mp, timestamp=ts)
                    
                    last_save = time.time()
                    
                time_tag += navg * self.ntime_gulp
                
                curr_time = time.time()
                process_time = curr_time - prev_time
                prev_time = curr_time
                self.perf_proclog.update({'acquire_time': acquire_time, 
                                          'reserve_time': 0.0, 
                                          'process_time': process_time,})
                
        self.log.info("BaselineOp - Done")
Example #8
0
class MultiTransformBlock(Block):
    def __init__(self, irings_, guarantee=True, *args, **kwargs):
        super(MultiTransformBlock, self).__init__(irings_, *args, **kwargs)
        # Note: Must use self.irings rather than irings_ because they may
        #         actually be Block instances.
        self.guarantee = guarantee
        self.orings = [
            self.create_ring(space=iring.space) for iring in self.irings
        ]
        self._seq_count = 0
        self.perf_proclog = ProcLog(self.name + "/perf")
        self.sequence_proclogs = [
            ProcLog(self.name + "/sequence%i" % i)
            for i in xrange(len(self.irings))
        ]

    def main(self, orings):
        for iseqs in izip(
                *
            [iring.read(guarantee=self.guarantee) for iring in self.irings]):
            if self.shutdown_event.is_set():
                break
            for i, iseq in enumerate(iseqs):
                self.sequence_proclogs[i].update(iseq.header)
            oheaders, islices = self._on_sequence(iseqs)
            for ohdr in oheaders:
                if 'time_tag' not in ohdr:
                    ohdr['time_tag'] = self._seq_count
            self._seq_count += 1

            # Allow passing None to mean slice(gulp_nframe)
            if islices is None:
                islices = [None] * len(self.irings)
            default_igulp_nframes = [
                self.gulp_nframe or iseq.header['gulp_nframe']
                for iseq in iseqs
            ]
            islices = [
                islice or slice(igulp_nframe)
                for (islice,
                     igulp_nframe) in zip(islices, default_igulp_nframes)
            ]

            islices = [_span_slice(slice_) for slice_ in islices]
            for iseq, islice in zip(iseqs, islices):
                if self.buffer_factor is None:
                    src_block = iseq.ring.owner
                    if src_block is not None and self.is_fused_with(src_block):
                        buffer_factor = 1
                    else:
                        buffer_factor = None
                else:
                    buffer_factor = self.buffer_factor
                iseq.resize(gulp_nframe=(islice.stop - islice.start),
                            buf_nframe=self.buffer_nframe,
                            buffer_factor=buffer_factor)

            igulp_nframes = [islice.stop - islice.start for islice in islices]

            with ExitStack() as oseq_stack:
                oseqs = self.begin_sequences(oseq_stack, orings, oheaders,
                                             igulp_nframes)
                prev_time = time.time()
                for ispans in izip(*[
                        iseq.read(islice.stop -
                                  islice.start, islice.step, islice.start)
                        for (iseq, islice) in zip(iseqs, islices)
                ]):
                    if self.shutdown_event.is_set():
                        break
                    cur_time = time.time()
                    acquire_time = cur_time - prev_time
                    prev_time = cur_time
                    with ExitStack() as ospan_stack:
                        ospans = self.reserve_spans(ospan_stack, oseqs, ispans)
                        cur_time = time.time()
                        reserve_time = cur_time - prev_time
                        prev_time = cur_time
                        # *TODO: See if can fuse together multiple on_data calls here before
                        #          calling stream_synchronize().
                        #        Consider passing .data instead of rings here
                        ostrides = self._on_data(ispans, ospans)
                        # TODO: // Default to not spinning the CPU: cudaSetDeviceFlags(cudaDeviceScheduleBlockingSync);
                        bf.device.stream_synchronize()
                        # Allow returning None to indicate complete consumption
                        if ostrides is None:
                            ostrides = [ospan.nframe for ospan in ospans]
                        ostrides = [
                            ostride if ostride is not None else ospan.nframe
                            for (ostride, ospan) in zip(ostrides, ospans)
                        ]
                        for ospan, ostride in zip(ospans, ostrides):
                            ospan.commit(ostride)
                    cur_time = time.time()
                    process_time = cur_time - prev_time
                    prev_time = cur_time
                    self.perf_proclog.update({
                        'acquire_time': acquire_time,
                        'reserve_time': reserve_time,
                        'process_time': process_time
                    })
            self._on_sequence_end(iseqs)

    def _on_sequence(self, iseqs):
        return self.on_sequence(iseqs)

    def _on_sequence_end(self, iseqs):
        return self.on_sequence_end(iseqs)

    def _on_data(self, ispans, ospans):
        return self.on_data(ispans, ospans)

    def define_output_nframes(self, input_nframes):
        """Return output nframe for each output, given input_nframes.
		"""
        return input_nframes

    def on_sequence(self, iseqs):
        """Return: oheaders (one per output) and islices (one per input)
		"""
        raise NotImplementedError

    def on_sequence_end(self, iseqs):
        """Do any necessary cleanup"""
        pass

    def on_data(self, ispans, ospans):
        """Process data from from ispans to ospans and return the number of
		frames to commit for each output (or None to commit complete spans)."""
        raise NotImplementedError
class DummyOp(object):
    def __init__(self, log, sock, oring, nbl, ntime_gulp=1,
                 slot_ntime=6, fast=False, shutdown_event=None, core=None):
        self.log     = log
        self.sock    = sock
        self.oring   = oring
        self.nbl     = nbl
        self.ntime_gulp = ntime_gulp
        self.slot_ntime = slot_ntime
        self.fast    = fast
        if shutdown_event is None:
            shutdown_event = threading.Event()
        self.shutdown_event = shutdown_event
        self.core    = core
        
        self.bind_proclog = ProcLog(type(self).__name__+"/bind")
        self.out_proclog  = ProcLog(type(self).__name__+"/out")
        self.size_proclog = ProcLog(type(self).__name__+"/size")
        self.perf_proclog = ProcLog(type(self).__name__+"/perf")
        
        self.out_proclog.update( {'nring':1, 'ring0':self.oring.name})
        self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp})
        
    def shutdown(self):
        self.shutdown_event.set()
          
    def main(self):
        with self.oring.begin_writing() as oring:
            navg  = 2400 if self.fast else 240000
            tint  = navg / CHAN_BW
            tgulp = tint * self.ntime_gulp
            nsrc  = self.nbl
            nbl   = self.nbl
            chan0 = 1234
            nchan = 192 // (4 if self.fast else 1)
            npol  = 4
            
            # Try to load model visibilities
            try:
                vis_base = numpy.load('utils/sky.npy')
            except:
                self.log.warn("Could not load model visibilities from utils/sky.py, using random data")
                vis_base = numpy.zeros((nbl, nchan, npol), dtype=numpy.complex64)
            assert(vis_base.shape[0] >= nbl)
            assert(vis_base.shape[1] >= nchan)
            assert(vis_base.shape[2] == npol)
            
            vis_base = vis_base[:self.nbl,::(4 if self.fast else 1),:]
            vis_base_r = (vis_base.real*1000).astype(numpy.int32)
            vis_base_i = (vis_base.imag*1000).astype(numpy.int32)
            vis_base = numpy.zeros((nbl, nchan, npol, 2), dtype=numpy.int32)
            vis_base[...,0] = vis_base_r
            vis_base[...,1] = vis_base_i
            
            ohdr = {'time_tag': int(int(time.time())*FS),
                    'seq0':     0, 
                    'chan0':    chan0,
                    'cfreq':    chan0*CHAN_BW,
                    'nchan':    nchan,
                    'bw':       nchan*CHAN_BW*(4 if self.fast else 1),
                    'navg':     navg*8192,
                    'nstand':   int(numpy.sqrt(8*nsrc+1)-1)//2,
                    'npol':     npol,
                    'nbl':      nbl,
                    'complex':  True,
                    'nbit':     32}
            ohdr_str = json.dumps(ohdr)
            
            ogulp_size = self.ntime_gulp*nbl*nchan*npol*8      # ci32
            oshape = (self.ntime_gulp,nbl,nchan,npol)
            self.oring.resize(ogulp_size)
            
            prev_time = time.time()
            with oring.begin_sequence(time_tag=ohdr['time_tag'], header=ohdr_str) as oseq:
                while not self.shutdown_event.is_set():
                    with oseq.reserve(ogulp_size) as ospan:
                        curr_time = time.time()
                        reserve_time = curr_time - prev_time
                        prev_time = curr_time
                        
                        odata = ospan.data_view(numpy.int32).reshape(oshape+(2,))
                        temp = vis_base + (1000*0.01*numpy.random.randn(*odata.shape)).astype(numpy.int32)
                        odata[...] = temp
                        
                        curr_time = time.time()
                        while curr_time - prev_time < tgulp:
                            time.sleep(0.01)
                            curr_time = time.time()
                            
                    curr_time = time.time()
                    process_time = curr_time - prev_time
                    prev_time = curr_time
                    self.perf_proclog.update({'acquire_time': -1, 
                                              'reserve_time': reserve_time, 
                                              'process_time': process_time,})
Example #10
0
class WriterOp(object):
    def __init__(self,
                 log,
                 iring,
                 beam=1,
                 ntime_gulp=250,
                 guarantee=True,
                 core=None):
        self.log = log
        self.iring = iring
        self.beam = beam
        self.ntime_gulp = ntime_gulp
        self.guarantee = guarantee
        self.core = core

        self.bind_proclog = ProcLog(type(self).__name__ + "/bind")
        self.in_proclog = ProcLog(type(self).__name__ + "/in")
        self.size_proclog = ProcLog(type(self).__name__ + "/size")
        self.sequence_proclog = ProcLog(type(self).__name__ + "/sequence0")
        self.perf_proclog = ProcLog(type(self).__name__ + "/perf")

        self.in_proclog.update({'nring': 1, 'ring0': self.iring.name})
        self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp})

    def main(self):
        global QUEUE

        if self.core is not None:
            cpu_affinity.set_core(self.core)
        self.bind_proclog.update({
            'ncore': 1,
            'core0': cpu_affinity.get_core(),
        })

        for iseq in self.iring.read(guarantee=self.guarantee):
            ihdr = json.loads(iseq.header.tostring())

            self.sequence_proclog.update(ihdr)

            self.log.info("Writer: Start of new sequence: %s", str(ihdr))

            # Setup the ring metadata and gulp sizes
            time_tag = ihdr['time_tag']
            navg = ihdr['navg']
            nbeam = ihdr['nbeam']
            chan0 = ihdr['chan0']
            nchan = ihdr['nchan']
            chan_bw = ihdr['bw'] / nchan
            npol = ihdr['npol']
            pols = ihdr['pols']
            pols = pols.replace('CR', 'XY_real')
            pols = pols.replace('CI', 'XY_imag')

            igulp_size = self.ntime_gulp * nbeam * nchan * npol * 4  # float32
            ishape = (self.ntime_gulp, nbeam, nchan, npol)
            self.iring.resize(igulp_size, 10 * igulp_size)

            first_gulp = True
            was_active = False
            prev_time = time.time()
            iseq_spans = iseq.read(igulp_size)
            for ispan in iseq_spans:
                if ispan.size < igulp_size:
                    continue  # Ignore final gulp
                curr_time = time.time()
                acquire_time = curr_time - prev_time
                prev_time = curr_time

                ## On our first span, update the pipeline lag for the queue
                ## so that we start recording at the right times
                if first_gulp:
                    QUEUE.update_lag(
                        LWATime(time_tag, format='timetag').datetime)
                    self.log.info("Current pipeline lag is %s", QUEUE.lag)
                    first_gulp = False

                ## Setup and load
                idata = ispan.data_view(numpy.float32).reshape(ishape)

                ## Determine what to do
                if QUEUE.active is not None:
                    ### Recording active - write
                    if not QUEUE.active.is_started:
                        self.log.info("Started operation - %s", QUEUE.active)
                        QUEUE.active.start(self.beam, chan0, navg, nchan,
                                           chan_bw, npol, pols)
                        was_active = True
                    QUEUE.active.write(time_tag, idata)
                elif was_active:
                    ### Recording just finished - clean
                    #### Clean
                    was_active = False
                    QUEUE.clean()

                    #### Close
                    self.log.info("Ended operation - %s", QUEUE.previous)
                    QUEUE.previous.stop()

                time_tag += navg * self.ntime_gulp * (int(FS) // int(CHAN_BW))

                curr_time = time.time()
                process_time = curr_time - prev_time
                prev_time = curr_time
                self.perf_proclog.update({
                    'acquire_time': acquire_time,
                    'reserve_time': -1,
                    'process_time': process_time,
                })

        self.log.info("WriterOp - Done")
Example #11
0
class StatisticsOp(object):
    def __init__(self,
                 log,
                 id,
                 iring,
                 ntime_gulp=250,
                 guarantee=True,
                 core=None):
        self.log = log
        self.iring = iring
        self.ntime_gulp = ntime_gulp
        self.guarantee = guarantee
        self.core = core

        self.client = Client(id)

        self.bind_proclog = ProcLog(type(self).__name__ + "/bind")
        self.in_proclog = ProcLog(type(self).__name__ + "/in")
        self.size_proclog = ProcLog(type(self).__name__ + "/size")
        self.sequence_proclog = ProcLog(type(self).__name__ + "/sequence0")
        self.perf_proclog = ProcLog(type(self).__name__ + "/perf")

        self.in_proclog.update({'nring': 1, 'ring0': self.iring.name})
        self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp})

    def main(self):
        if self.core is not None:
            cpu_affinity.set_core(self.core)
        self.bind_proclog.update({
            'ncore': 1,
            'core0': cpu_affinity.get_core(),
        })

        for iseq in self.iring.read(guarantee=self.guarantee):
            ihdr = json.loads(iseq.header.tostring())

            self.sequence_proclog.update(ihdr)

            self.log.info("Statistics: Start of new sequence: %s", str(ihdr))

            # Setup the ring metadata and gulp sizes
            time_tag = ihdr['time_tag']
            navg = ihdr['navg']
            nbeam = ihdr['nbeam']
            chan0 = ihdr['chan0']
            nchan = ihdr['nchan']
            chan_bw = ihdr['bw'] / nchan
            npol = ihdr['npol']
            pols = ihdr['pols']

            igulp_size = self.ntime_gulp * nbeam * nchan * npol * 4  # float32
            ishape = (self.ntime_gulp, nbeam, nchan, npol)

            data_pols = pols.split(',')
            last_save = 0.0

            prev_time = time.time()
            iseq_spans = iseq.read(igulp_size)
            for ispan in iseq_spans:
                if ispan.size < igulp_size:
                    continue  # Ignore final gulp
                curr_time = time.time()
                acquire_time = curr_time - prev_time
                prev_time = curr_time

                ## Setup and load
                idata = ispan.data_view(numpy.float32).reshape(ishape)
                idata = idata.reshape(-1, npol)

                if time.time() - last_save > 60:
                    ## Timestamp
                    tt = LWATime(time_tag, format='timetag')
                    ts = tt.unix

                    ## Run the statistics over all times/channels
                    ##  * only really works for nbeam=1
                    data_min = numpy.min(idata, axis=0)
                    data_max = numpy.max(idata, axis=0)
                    data_avg = numpy.mean(idata, axis=0)

                    ## Save
                    for data, name in zip((data_min, data_avg, data_max),
                                          ('min', 'avg', 'max')):
                        value = MultiMonitorPoint(data.tolist(),
                                                  timestamp=ts,
                                                  field=data_pols)
                        self.client.write_monitor_point(
                            'statistics/%s' % name, value)

                    last_save = time.time()

                time_tag += navg * self.ntime_gulp * (int(FS) // int(CHAN_BW))

                curr_time = time.time()
                process_time = curr_time - prev_time
                prev_time = curr_time
                self.perf_proclog.update({
                    'acquire_time': acquire_time,
                    'reserve_time': -1,
                    'process_time': process_time,
                })

        self.log.info("StatisticsOp - Done")
Example #12
0
class SpectraOp(object):
    def __init__(self,
                 log,
                 id,
                 iring,
                 ntime_gulp=250,
                 guarantee=True,
                 core=None):
        self.log = log
        self.iring = iring
        self.ntime_gulp = ntime_gulp
        self.guarantee = guarantee
        self.core = core

        self.client = Client(id)

        self.bind_proclog = ProcLog(type(self).__name__ + "/bind")
        self.in_proclog = ProcLog(type(self).__name__ + "/in")
        self.size_proclog = ProcLog(type(self).__name__ + "/size")
        self.sequence_proclog = ProcLog(type(self).__name__ + "/sequence0")
        self.perf_proclog = ProcLog(type(self).__name__ + "/perf")

        self.in_proclog.update({'nring': 1, 'ring0': self.iring.name})
        self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp})

    def main(self):
        if self.core is not None:
            cpu_affinity.set_core(self.core)
        self.bind_proclog.update({
            'ncore': 1,
            'core0': cpu_affinity.get_core(),
        })

        # Setup the figure
        ## Import
        import matplotlib
        matplotlib.use('Agg')
        from matplotlib import pyplot as plt
        from matplotlib.ticker import MultipleLocator

        ## Create
        fig = plt.Figure(figsize=(6, 6))
        ax = fig.gca()

        for iseq in self.iring.read(guarantee=self.guarantee):
            ihdr = json.loads(iseq.header.tostring())

            self.sequence_proclog.update(ihdr)

            self.log.info("Spectra: Start of new sequence: %s", str(ihdr))

            # Setup the ring metadata and gulp sizes
            time_tag = ihdr['time_tag']
            navg = ihdr['navg']
            nbeam = ihdr['nbeam']
            chan0 = ihdr['chan0']
            nchan = ihdr['nchan']
            chan_bw = ihdr['bw'] / nchan
            npol = ihdr['npol']
            pols = ihdr['pols']

            igulp_size = self.ntime_gulp * nbeam * nchan * npol * 4  # float32
            ishape = (self.ntime_gulp, nbeam, nchan, npol)

            nchan_pipeline = nchan // NPIPELINE
            frange = (numpy.arange(nchan) + chan0) * CHAN_BW
            last_save = 0.0

            prev_time = time.time()
            iseq_spans = iseq.read(igulp_size)
            for ispan in iseq_spans:
                if ispan.size < igulp_size:
                    continue  # Ignore final gulp
                curr_time = time.time()
                acquire_time = curr_time - prev_time
                prev_time = curr_time

                ## Setup and load
                idata = ispan.data_view(numpy.float32).reshape(ishape)

                if time.time() - last_save > 60:
                    ## Timestamp
                    tt = LWATime(time_tag, format='timetag')
                    ts = tt.datetime.strftime('%y%m%d %H:%M:%S')

                    ## Average over time
                    sdata = idata.mean(axis=0)

                    ## Create a diagnostic plot after suming the flags across polarization
                    ax.cla()
                    ax.plot(frange / 1e6,
                            numpy.log10(sdata[0, :, 0]) * 10,
                            color='#1F77B4')
                    ax.plot(frange / 1e6,
                            numpy.log10(sdata[0, :, 1]) * 10,
                            color='#FF7F0E')
                    ylim = ax.get_ylim()
                    for b in range(1, NPIPELINE):
                        linestyle = ':'
                        if b % 4 == 0:
                            linestyle = '--'
                        ax.vlines(frange[b * nchan_pipeline] / 1e6,
                                  *ylim,
                                  linestyle=linestyle,
                                  color='black',
                                  alpha=0.2)
                    ax.set_ylim(ylim)
                    ax.set_xlim((frange[0] / 1e6, frange[-1] / 1e6))
                    ax.set_xlabel('Frequency [MHz]')
                    ax.set_ylabel('Power [arb. dB]')
                    ax.xaxis.set_major_locator(MultipleLocator(base=10.0))
                    fig.tight_layout()

                    ## Save
                    tt = LWATime(time_tag, format='timetag')
                    mp = ImageMonitorPoint.from_figure(fig)
                    self.client.write_monitor_point('diagnostics/spectra',
                                                    mp,
                                                    timestamp=tt.unix)

                    last_save = time.time()

                time_tag += navg * self.ntime_gulp * (int(FS) // int(CHAN_BW))

                curr_time = time.time()
                process_time = curr_time - prev_time
                prev_time = curr_time
                self.perf_proclog.update({
                    'acquire_time': acquire_time,
                    'reserve_time': -1,
                    'process_time': process_time,
                })

        self.log.info("SpectraOp - Done")
Example #13
0
class DummyOp(object):
    def __init__(self,
                 log,
                 sock,
                 oring,
                 nserver,
                 beam0=1,
                 ntime_gulp=250,
                 slot_ntime=25000,
                 shutdown_event=None,
                 core=None):
        self.log = log
        self.sock = sock
        self.oring = oring
        self.nserver = nserver
        self.beam0 = beam0
        self.ntime_gulp = ntime_gulp
        self.slot_ntime = slot_ntime
        if shutdown_event is None:
            shutdown_event = threading.Event()
        self.shutdown_event = shutdown_event
        self.core = core

        self.bind_proclog = ProcLog(type(self).__name__ + "/bind")
        self.out_proclog = ProcLog(type(self).__name__ + "/out")
        self.size_proclog = ProcLog(type(self).__name__ + "/size")
        self.perf_proclog = ProcLog(type(self).__name__ + "/perf")

        self.out_proclog.update({'nring': 1, 'ring0': self.oring.name})
        self.size_proclog.update({'nseq_per_gulp': self.ntime_gulp})

    def shutdown(self):
        self.shutdown_event.set()

    def main(self):
        with self.oring.begin_writing() as oring:
            navg = 24
            tint = navg / CHAN_BW
            tgulp = tint * self.ntime_gulp
            nbeam = 1
            chan0 = 1234
            nchan = 16 * 192
            npol = 4

            ohdr = {
                'time_tag': int(int(time.time()) * FS),
                'seq0': 0,
                'chan0': chan0,
                'cfreq0': chan0 * CHAN_BW,
                'bw': nchan * CHAN_BW,
                'navg': navg,
                'nbeam': nbeam,
                'nchan': nchan,
                'npol': npol,
                'pols': 'XX,YY,CR,CI',
                'complex': False,
                'nbit': 32
            }
            ohdr_str = json.dumps(ohdr)

            ogulp_size = self.ntime_gulp * nbeam * nchan * npol * 4  # float32
            oshape = (self.ntime_gulp, nbeam, nchan, npol)
            self.oring.resize(ogulp_size)

            prev_time = time.time()
            with oring.begin_sequence(time_tag=ohdr['time_tag'],
                                      header=ohdr_str) as oseq:
                while not self.shutdown_event.is_set():
                    with oseq.reserve(ogulp_size) as ospan:
                        curr_time = time.time()
                        reserve_time = curr_time - prev_time
                        prev_time = curr_time

                        odata = ospan.data_view(numpy.float32).reshape(oshape)
                        odata[...] = numpy.random.randn(*oshape)

                        curr_time = time.time()
                        while curr_time - prev_time < tgulp:
                            time.sleep(0.01)
                            curr_time = time.time()

                    curr_time = time.time()
                    process_time = curr_time - prev_time
                    prev_time = curr_time
                    self.perf_proclog.update({
                        'acquire_time': -1,
                        'reserve_time': reserve_time,
                        'process_time': process_time,
                    })
Example #14
0
class Block(BlockScope):
    instance_counts = defaultdict(lambda: 0)

    def __init__(self, irings, name=None, type_=None, **kwargs):
        self.type = type_ or self.__class__.__name__
        self.name = name or '%s_%i' % (self.type,
                                       Block.instance_counts[self.type])
        Block.instance_counts[self.type] += 1
        super(Block, self).__init__(**kwargs)
        self.pipeline = get_default_pipeline()
        self.pipeline.blocks.append(self)

        # Allow Block instances to be passed in place of rings
        irings = [get_ring(iring) for iring in irings]
        self.irings = irings
        valid_inp_spaces = self._define_valid_input_spaces()
        for i, (iring, valid_spaces) in enumerate(zip(irings,
                                                      valid_inp_spaces)):
            if not bf.memory.space_accessible(iring.space, valid_spaces):
                raise ValueError(
                    "Block %s input %i's space must be accessible from one of: %s"
                    % (self.name, i, str(valid_spaces)))
        self.orings = []  # Update this in subclass constructors
        self.shutdown_event = threading.Event()
        self.bind_proclog = ProcLog(self.name + "/bind")
        self.in_proclog = ProcLog(self.name + "/in")

        rnames = {'nring': len(self.irings)}
        for i, r in enumerate(self.irings):
            rnames['ring%i' % i] = r.name
        self.in_proclog.update(rnames)

    def shutdown(self):
        self.shutdown_event.set()

    def create_ring(self, *args, **kwargs):
        return Ring(*args, owner=self, **kwargs)

    def run(self):
        #bf.affinity.set_openmp_cores(cpus) # TODO
        core = self.core
        if core is not None:
            bf.affinity.set_core(core if isinstance(core, int) else core[0])
        self.bind_proclog.update({'ncore': 1, 'core0': bf.affinity.get_core()})
        if self.gpu is not None:
            bf.device.set_device(self.gpu)
        self.cache_scope_hierarchy()
        with ExitStack() as oring_stack:
            active_orings = self.begin_writing(oring_stack, self.orings)
            self.main(active_orings)

    def num_outputs(self):
        # TODO: This is a little hacky
        return len(self.orings)

    def begin_writing(self, exit_stack, orings):
        return [
            exit_stack.enter_context(oring.begin_writing()) for oring in orings
        ]

    def begin_sequences(self, exit_stack, orings, oheaders, igulp_nframes):
        ogulp_nframes = self._define_output_nframes(igulp_nframes)
        for ohdr, ogulp_nframe in zip(oheaders, ogulp_nframes):
            ohdr['gulp_nframe'] = ogulp_nframe
        # Note: This always specifies buffer_factor=1 on the assumption that
        #         additional buffering is defined by the reader(s) rather
        #         than the writer.
        obuf_nframes = [1 * ogulp_nframe for ogulp_nframe in ogulp_nframes]
        return [
            exit_stack.enter_context(oring.begin_sequence(ohdr, obuf_nframe))
            for (oring, ohdr,
                 obuf_nframe) in zip(orings, oheaders, obuf_nframes)
        ]

    def reserve_spans(self, exit_stack, oseqs, ispans):
        igulp_nframes = [span.nframe for span in ispans]
        ogulp_nframes = self._define_output_nframes(igulp_nframes)
        return [
            exit_stack.enter_context(oseq.reserve(ogulp_nframe))
            for (oseq, ogulp_nframe) in zip(oseqs, ogulp_nframes)
        ]

    def _define_output_nframes(self, input_nframes):
        return self.define_output_nframes(input_nframes)

    def define_output_nframes(self, input_nframes):
        """Return output nframe for each output, given input_nframes.
		"""
        raise NotImplementedError

    def _define_valid_input_spaces(self):
        return self.define_valid_input_spaces()

    def define_valid_input_spaces(self):
        """Return set of valid spaces (or 'any') for each input"""
        return ['any'] * len(self.irings)