Source code for momxml.backend

from lofarobsxml.observationspecificationbase import ObservationSpecificationBase
from lofarobsxml.utilities import lower_case, AutoReprBaseClass, indent

r'''
This module contains the helper classes that contain the miriad
different setting of the correlator. The main class here is
BackendProcessing, which contains pointers to the other classes:
TiedArrayBeams and Stokes, when needed.
'''


[docs]class TiedArrayBeams(AutoReprBaseClass): r''' Description of Tied Array Beam (TAB) settings. **Parameters** flyseye : bool If True, store data streams from each station individually. beams_ra_dec_rad : None or list of pairs of float The RA, Dec in rad of the phase centres of the TABs in J2000 coordinates. nr_tab_rings : int Alternatively, one can specify with how many rings one wants to tile the beam. tab_ring_size : float Distance between TAB rings in RADIANS. beam_offsets : None Previously, the offsets with repsoect to the phase center. Option is invalid as of 2014-06-14, LOFAR 2.4. Use beams_ra_dec_rad instead. **Examples** >>> tab = TiedArrayBeams() >>> tab TiedArrayBeams(beams_ra_dec_rad = None, flyseye = False, nr_tab_rings = 0, tab_ring_size = 0) >>> print(tab.xml()) <BLANKLINE> <tiedArrayBeams> <flyseye>false</flyseye> <nrTabRings>0</nrTabRings> <tabRingSize>0.000000</tabRingSize> <tiedArrayBeamList/> </tiedArrayBeams> >>> tab_fe = TiedArrayBeams(flyseye = True, ... beam_offsets = [(0.0, 0.0), (0.1, -0.05)]) Traceback (most recent call last): ... ValueError: Relative beam_offsets not supported as of LOFAR 2.4 (2014-06-30) use beams_ra_dec_rad instead Whoops.... that was the old way of specifying. Let's try again now. >>> tab_fe = TiedArrayBeams(flyseye = True, ... beams_ra_dec_rad = [(3.1, +0.5), ... (3.2, +0.54)]) >>> tab_fe TiedArrayBeams(beams_ra_dec_rad = [(3.1, 0.5), (3.2, 0.54)], flyseye = True, nr_tab_rings = 0, tab_ring_size = 0) >>> print(tab_fe.xml()) <BLANKLINE> <tiedArrayBeams> <flyseye>true</flyseye> <nrTabRings>0</nrTabRings> <tabRingSize>0.000000</tabRingSize> <tiedArrayBeamList> <tiedArrayBeam><coherent>true</coherent><angle1>3.100000</angle1><angle2>0.500000</angle2></tiedArrayBeam> <tiedArrayBeam><coherent>true</coherent><angle1>3.200000</angle1><angle2>0.540000</angle2></tiedArrayBeam> </tiedArrayBeamList> </tiedArrayBeams> ''' def __init__(self, flyseye = False, beam_offsets = None, beams_ra_dec_rad = None, nr_tab_rings = 0, tab_ring_size = 0): self.flyseye = flyseye if beam_offsets is not None: raise ValueError( 'Relative beam_offsets not supported as of LOFAR 2.4 (2014-06-30) use beams_ra_dec_rad instead') self.beams_ra_dec_rad = beams_ra_dec_rad self.nr_tab_rings = nr_tab_rings self.tab_ring_size = tab_ring_size def xml(self, project_name = None): output = (''' <tiedArrayBeams> <flyseye>%s</flyseye> <nrTabRings>%d</nrTabRings> <tabRingSize>%f</tabRingSize>''' % (lower_case(self.flyseye), self.nr_tab_rings, self.tab_ring_size)) if self.beams_ra_dec_rad and len(self.beams_ra_dec_rad) > 0: output += (''' <tiedArrayBeamList> %s </tiedArrayBeamList>''' % '\n '.join( ['<tiedArrayBeam><coherent>true</coherent><angle1>%f</angle1><angle2>%f</angle2></tiedArrayBeam>' % (angle_1, angle_2) for angle_1, angle_2 in self.beams_ra_dec_rad])) else: output += ''' <tiedArrayBeamList/>''' return output+'\n</tiedArrayBeams>'
[docs]class Stokes(AutoReprBaseClass): r''' Describes averaging and storage parameters for beam formed observations. This class is not derived from ObservationSpecificationBase because it is really only a helper to BackendProcessing. Use instances of this class as parameters to BackendProcessing for ``coherent_stokes_data`` and ``incoherent_stokes_data``. **Parameters** mode : string Either 'coherent' or 'incoherent'. subbands_per_file : int Number of sub bands per output file / storage machine. Use 512 for low data rates, but decrease as necessary to keep the data rate per file (locus node / storage machine) below about 300 MB / s. number_collapsed_channels : None or int The number of output channels. If this is smaller than the number of channels for the correlator, the output channels will be averaged. None implies no averaging. stokes_downsampling_steps : int Number of time samples to average before writing to disk. Default is 1 (no averaging). polarizations : string Either 'I', 'IQUV', or 'XXYY'. **Examples** >>> stk = Stokes(mode = 'coherent', polarizations = 'IQUV', ... stokes_downsampling_steps = 64) >>> stk Stokes(mode = 'coherent', number_collapsed_channels = None, polarizations = 'IQUV', stokes_downsampling_steps = 64, subbands_per_file = 512) >>> print(stk.xml()) Traceback (most recent call last): ... ValueError: Stokes.xml(): number_collapsed_channels is not set. >>> stk = Stokes(mode = 'coherent', polarizations = 'IQUV', ... stokes_downsampling_steps = 64, ... number_collapsed_channels = 16) >>> stk Stokes(mode = 'coherent', number_collapsed_channels = 16, polarizations = 'IQUV', stokes_downsampling_steps = 64, subbands_per_file = 512) >>> print(stk.xml()) <subbandsPerFileCS>512</subbandsPerFileCS> <numberCollapsedChannelsCS>16</numberCollapsedChannelsCS> <stokesDownsamplingStepsCS>64</stokesDownsamplingStepsCS> <whichCS>IQUV</whichCS> ''' def __init__(self, mode, subbands_per_file = 512, number_collapsed_channels = None, stokes_downsampling_steps = 1, polarizations = 'I'): self.mode = mode self.subbands_per_file = subbands_per_file self.number_collapsed_channels = number_collapsed_channels self.stokes_downsampling_steps = stokes_downsampling_steps self.polarizations = polarizations self.validate()
[docs] def validate(self): r''' Raises a ValueError for every problem found in the settings. ''' valid_modes = ['coherent', 'incoherent'] valid_polarizations = ['I', 'IQUV', 'XXYY'] if self.mode not in valid_modes: raise ValueError('mode(%r) not one of %r.' % (self.mode, valid_modes)) if self.polarizations not in valid_polarizations: raise ValueError('polarizations(%r) not one of %r.' % (self.polarizations, valid_polarizations)) if type(self.subbands_per_file) != int: raise ValueError('subbands_per_file(%r) must be an integer.' % self.subbands_per_file) if self.subbands_per_file <= 0 or self.subbands_per_file > 1024: raise ValueError('subbands_per_file(%r) not in <0, 1024]' % self.subbands_per_file) if type(self.stokes_downsampling_steps) != int: raise ValueError('stokes_downsampling_steps(%r) must be an integer.' % self.stokes_downsampling_steps) if self.stokes_downsampling_steps <= 0: raise ValueError('stokes_downsampling_steps(%r) must be > 0.' % self.stokes_downsampling_steps)
[docs] def stokes_suffix(self): r''' return CS or IS, depending on whether these are coherent or incoherent stokes settings. coherent stokes settings also need tied array beams / fly's eye stuff specified. ''' return self.mode[0].upper()+'S'
[docs] def xml(self, project_name = None): r''' Produce the xml for the coherent stokes or incoherent stokes settings of the backend. ''' if self.number_collapsed_channels is None: raise ValueError('Stokes.xml(): number_collapsed_channels is not set.') return ('''<subbandsPerFile%(suffix)s>%(subbands_per_file)d</subbandsPerFile%(suffix)s> <numberCollapsedChannels%(suffix)s>%(number_collapsed_channels)d</numberCollapsedChannels%(suffix)s> <stokesDownsamplingSteps%(suffix)s>%(stokes_downsampling_steps)d</stokesDownsamplingSteps%(suffix)s> <which%(suffix)s>%(polarizations)s</which%(suffix)s>''' % {'suffix' : self.stokes_suffix(), 'subbands_per_file' : self.subbands_per_file, 'number_collapsed_channels': self.number_collapsed_channels, 'stokes_downsampling_steps': self.stokes_downsampling_steps, 'polarizations' : self.polarizations})
[docs]class BackendProcessing(AutoReprBaseClass): r''' BackendProcessing contains all the settings for the correlator and beamformer hardware. **Parameters** channels_per_subband : int Number of channels per sub band. Default is 64. integration_time_seconds : number Integration time for correlator observations. Typically 1 or 2 seconds, but anything from 0.2 to 99 seconds should be possible. correlated_data : bool True if cross-correlation visibilities should be produced. filtered_data : bool No idea what this means. Default is False. beamformed_data : bool True if beamformed data is to be produced, such as complex voltage, coherent stokes, or incoherent stokes data. If True and coherent_stokes_data is set to Stokes('coherent', polarizations='XXYY', number_collapsed_channels=1, stokes_downsampling_steps=1), complex voltages are produced. coherent_stokes_data : None or Stokes instance Coherent stokes settings. incoherent_stokes_data : None or Stokes instance Incoherent stokes settings. stokes_integrate_channels : bool Apply frequency averaging. Default False. coherent_dedispersed_channels : bool Apply coherent dedispersion? Default False. tied_array_beams : None or TiedArrayBeams instance Tied array beam settings. bypass_pff : bool If True, skip the correlator's / beamformer's polyphase filter entirely. Useful for high time resolution beamformed data. Default: False. enable_superterp: bool If True, also beamform the superterp stations and treat them as a separate large station. default_template: string Default observation template to use. Possible values are: 'BeamObservation' (default), 'BeamObservationNoStationControl', and 'BeamObservationNoPlots'. **Examples** >>> bp = BackendProcessing() >>> bp BackendProcessing(beamformed_data = False, bypass_pff = False, channels_per_subband = 64, coherent_dedispersed_channels = False, coherent_stokes_data = None, correlated_data = True, default_template = 'BeamObservation', enable_superterp = False, filtered_data = False, incoherent_stokes_data = None, integration_time_seconds = 2, stokes_integrate_channels = False, tied_array_beams = TiedArrayBeams(beams_ra_dec_rad = None, flyseye = False, nr_tab_rings = 0, tab_ring_size = 0)) >>> print(bp.xml()) <correlatedData>true</correlatedData> <filteredData>false</filteredData> <beamformedData>false</beamformedData> <coherentStokesData>false</coherentStokesData> <incoherentStokesData>false</incoherentStokesData> <integrationInterval>2</integrationInterval> <channelsPerSubband>64</channelsPerSubband> <pencilBeams> <flyseye>false</flyseye> <pencilBeamList/> </pencilBeams> <tiedArrayBeams> <flyseye>false</flyseye> <nrTabRings>0</nrTabRings> <tabRingSize>0.000000</tabRingSize> <tiedArrayBeamList/> </tiedArrayBeams> <stokes> <integrateChannels>false</integrateChannels> </stokes> <bypassPff>false</bypassPff> <enableSuperterp>false</enableSuperterp> <BLANKLINE> Here is a Fly's eye example: >>> channels_per_subband = 16 >>> coherent_stokes_data = Stokes('coherent', ... stokes_downsampling_steps = 128) >>> tied_array_beams = TiedArrayBeams(flyseye = True, ... beams_ra_dec_rad = None) >>> bp_fe = BackendProcessing( ... correlated_data = False, ... channels_per_subband = channels_per_subband, ... coherent_stokes_data = coherent_stokes_data, ... tied_array_beams = tied_array_beams) >>> bp_fe BackendProcessing(beamformed_data = False, bypass_pff = False, channels_per_subband = 16, coherent_dedispersed_channels = False, coherent_stokes_data = Stokes(mode = 'coherent', number_collapsed_channels = 16, polarizations = 'I', stokes_downsampling_steps = 128, subbands_per_file = 512), correlated_data = False, default_template = 'BeamObservation', enable_superterp = False, filtered_data = False, incoherent_stokes_data = None, integration_time_seconds = 2, stokes_integrate_channels = False, tied_array_beams = TiedArrayBeams(beams_ra_dec_rad = None, flyseye = True, nr_tab_rings = 0, tab_ring_size = 0)) >>> print(bp_fe.xml()) <correlatedData>false</correlatedData> <filteredData>false</filteredData> <beamformedData>false</beamformedData> <coherentStokesData>true</coherentStokesData> <incoherentStokesData>false</incoherentStokesData> <channelsPerSubband>16</channelsPerSubband> <pencilBeams> <flyseye>true</flyseye> <pencilBeamList/> </pencilBeams> <tiedArrayBeams> <flyseye>true</flyseye> <nrTabRings>0</nrTabRings> <tabRingSize>0.000000</tabRingSize> <tiedArrayBeamList/> </tiedArrayBeams> <stokes> <integrateChannels>false</integrateChannels> <subbandsPerFileCS>512</subbandsPerFileCS> <numberCollapsedChannelsCS>16</numberCollapsedChannelsCS> <stokesDownsamplingStepsCS>128</stokesDownsamplingStepsCS> <whichCS>I</whichCS> </stokes> <bypassPff>false</bypassPff> <enableSuperterp>false</enableSuperterp> <BLANKLINE> And here for coherent stokes beam forming: >>> tied_array_beams = TiedArrayBeams(flyseye = False, ... beams_ra_dec_rad = None) >>> bp_cs = BackendProcessing( ... correlated_data = False, ... channels_per_subband = channels_per_subband, ... coherent_stokes_data = coherent_stokes_data, ... tied_array_beams = tied_array_beams) >>> bp_cs BackendProcessing(beamformed_data = False, bypass_pff = False, channels_per_subband = 16, coherent_dedispersed_channels = False, coherent_stokes_data = Stokes(mode = 'coherent', number_collapsed_channels = 16, polarizations = 'I', stokes_downsampling_steps = 128, subbands_per_file = 512), correlated_data = False, default_template = 'BeamObservation', enable_superterp = False, filtered_data = False, incoherent_stokes_data = None, integration_time_seconds = 2, stokes_integrate_channels = False, tied_array_beams = TiedArrayBeams(beams_ra_dec_rad = None, flyseye = False, nr_tab_rings = 0, tab_ring_size = 0)) >>> print(bp_cs.xml()) <correlatedData>false</correlatedData> <filteredData>false</filteredData> <beamformedData>false</beamformedData> <coherentStokesData>true</coherentStokesData> <incoherentStokesData>false</incoherentStokesData> <channelsPerSubband>16</channelsPerSubband> <pencilBeams> <flyseye>false</flyseye> <pencilBeamList/> </pencilBeams> <tiedArrayBeams> <flyseye>false</flyseye> <nrTabRings>0</nrTabRings> <tabRingSize>0.000000</tabRingSize> <tiedArrayBeamList/> </tiedArrayBeams> <stokes> <integrateChannels>false</integrateChannels> <subbandsPerFileCS>512</subbandsPerFileCS> <numberCollapsedChannelsCS>16</numberCollapsedChannelsCS> <stokesDownsamplingStepsCS>128</stokesDownsamplingStepsCS> <whichCS>I</whichCS> </stokes> <bypassPff>false</bypassPff> <enableSuperterp>false</enableSuperterp> <BLANKLINE> ''' def __init__(self, channels_per_subband = 64, integration_time_seconds = 2, correlated_data = True, filtered_data = False, beamformed_data = False, coherent_stokes_data = None, incoherent_stokes_data = None, stokes_integrate_channels = False, coherent_dedispersed_channels = False, tied_array_beams = None, bypass_pff = False, enable_superterp = False, default_template = 'BeamObservation' ): self.channels_per_subband = channels_per_subband self.integration_time_seconds = integration_time_seconds self.correlated_data = correlated_data self.filtered_data = filtered_data self.beamformed_data = beamformed_data self.coherent_stokes_data = coherent_stokes_data # If number_collapsed_channels is not set, default to # correlator settings. if self.coherent_stokes_data: if self.coherent_stokes_data.number_collapsed_channels is None: self.coherent_stokes_data.number_collapsed_channels = \ self.channels_per_subband self.tied_array_beams = tied_array_beams if self.tied_array_beams is None: self.tied_array_beams = TiedArrayBeams() self.incoherent_stokes_data = incoherent_stokes_data if self.incoherent_stokes_data: if self.incoherent_stokes_data.number_collapsed_channels is None: self.incoherent_stokes_data.number_collapsed_channels = \ self.channels_per_subband self.stokes_integrate_channels = stokes_integrate_channels self.coherent_dedispersed_channels = coherent_dedispersed_channels self.bypass_pff = bypass_pff self.enable_superterp = enable_superterp valid_default_templates = ['BeamObservation', 'BeamObservationNoPlots', 'BeamObservationNoStationControl'] if default_template not in valid_default_templates: raise ValueError('%s is not a valid default template, choose one of %r' % (default_template, valid_default_templates)) self.default_template = default_template
[docs] def need_beam_observation(self): r''' ''' return (self.coherent_stokes_data or self.incoherent_stokes_data or self.filtered_data or self.beamformed_data)
[docs] def instrument_name(self): r''' These names are actually very important to MoM. They specify which default observation screen is displayed. Valid values are 'Beam Observation', 'Interferometer', and 'TBB (standalone)' ''' if self.need_beam_observation(): return 'Beam Observation' else: return 'Beam Observation' # 'Interferometer'
def measurement_type(self): if self.need_beam_observation(): return 'lofar:BFMeasurementType' else: return 'lofar:UVMeasurementType' def measurement_attributes(self): if self.need_beam_observation(): return 'bfMeasurementAttributes' else: return 'uvMeasurementAttributes'
[docs] def xml(self, project_name=None, child_id=None, parent_label=None): r''' ''' def lower_case(bool): return repr(bool).lower() incoherent_stokes = self.incoherent_stokes_data is not None coherent_stokes = self.coherent_stokes_data is not None flyseye = False if coherent_stokes: flyseye = self.tied_array_beams.flyseye output = '''<correlatedData>'''+lower_case(self.correlated_data)+'''</correlatedData> <filteredData>'''+lower_case(self.filtered_data)+'''</filteredData> <beamformedData>'''+lower_case(self.beamformed_data)+'''</beamformedData> <coherentStokesData>'''+lower_case(coherent_stokes)+'''</coherentStokesData> <incoherentStokesData>'''+lower_case(incoherent_stokes)+'''</incoherentStokesData>''' if self.correlated_data: output += ''' <integrationInterval>'''+str(self.integration_time_seconds)+'''</integrationInterval>''' output += ''' <channelsPerSubband>'''+str(self.channels_per_subband)+'''</channelsPerSubband> <pencilBeams> <flyseye>'''+lower_case(flyseye)+'''</flyseye> <pencilBeamList/> </pencilBeams>''' + self.tied_array_beams.xml()+''' <stokes> <integrateChannels>'''+lower_case(self.stokes_integrate_channels)+'''</integrateChannels>''' # If number_collapsed_channels is not set, default to # correlator settings. if self.incoherent_stokes_data: if self.incoherent_stokes_data.number_collapsed_channels is None: self.incoherent_stokes_data.number_collapsed_channels = self.channels_per_subband output += '\n'+indent(self.incoherent_stokes_data.xml(), 2) if self.coherent_stokes_data: if self.coherent_stokes_data.number_collapsed_channels is None: self.coherent_stokes_data.number_collapsed_channels = self.channels_per_subband output += '\n'+indent(self.coherent_stokes_data.xml(), 2) output += ''' </stokes> <bypassPff>'''+lower_case(self.bypass_pff)+'''</bypassPff> <enableSuperterp>'''+lower_case(self.enable_superterp)+'''</enableSuperterp> ''' return output