def run(self):
        print 'Calculating synthesis dirty beam and clean beam...'

        # gather configuration
        uvmapgen = self.previous_results['uvmapgenerator']
        cubeparams = self.previous_results['cubeparameters']
        self.result['wn'] = wn = cubeparams['wn']
        self.result['pixsize [rad]'] = pixsize = cubeparams['pixsize [rad]']
        self.result['npix'] = npix = cubeparams['npix']

        # spatial axes same for all wavelengths
        self.result['spatial axis [arcsec]'] = axis = \
          cubeparams['spatial axis [arcsec]']
        axis1 = co.Axis(data=-axis, title='RA offset', units='arcsec')
        axis2 = co.Axis(data=axis, title='Dec offset', units='arcsec')
        axis3 = co.Axis(data=wn, title='Frequency', units='cm-1')

        # calculate beam for each wavenumber in 'wn'
        rpix = npix / 2

        mx, my = np.meshgrid(np.arange(-rpix, rpix), np.arange(-rpix, rpix))
        self.result['dirty beam'] = collections.OrderedDict()
        self.result['clean beam'] = collections.OrderedDict()

        # calculate synthesis beams using pp
        jobs = {}
        wnmax = np.max(wn)
        for wavenum in wn:
            #
            # Submit pp calls to calculate_synthesis_beams to calculate
            # the results.
            indata = (
                npix,
                pixsize,
                wavenum,
                uvmapgen['bxby'],
            )
            jobs[wavenum] = self.job_server.submit(calculate_synthesis_beams,
                                                   indata, (), (
                                                       'numpy',
                                                       'fitgaussian',
                                                   ))

        for wavenum in wn:
            if jobs[wavenum]() is None:
                raise Exception, 'calculate_synthesis_beams has failed'

            dirty_beam, clean_beam = jobs[wavenum]()
            image = co.Image(data=dirty_beam,
                             axes=[axis1, axis2],
                             title='Dirty Beam %06.4g cm-1' % wavenum)
            self.result['dirty beam'][wavenum] = image
            image = co.Image(data=clean_beam,
                             axes=[axis1, axis2],
                             title='Clean Beam %06.4g cm-1' % wavenum)
            self.result['clean beam'][wavenum] = image

        return self.result
Beispiel #2
0
    def _create_point_source(self, xpos, ypos, skymodel, spatial_axis,
                             frequency_axis, spectrum_function):
        """Create a point source.
        """

        # calculate xpos, ypos in units of pixel - numpy arrays [row,col]
        nx = len(spatial_axis)
        colpos = float(nx - 1) * float(xpos - spatial_axis[0]) / (
            spatial_axis[-1] - spatial_axis[0])
        rowpos = float(nx - 1) * float(ypos - spatial_axis[0]) / (
            spatial_axis[-1] - spatial_axis[0])

        if colpos < 0 or colpos > (nx - 1) or rowpos < 0 or rowpos > (nx - 1):
            # point source is outside modelled area
            return

        # calculate fourier phase shift to move point at [0,0] to
        # [rowpos, colpos]
        shiftx = np.zeros([nx], np.complex)
        shiftx[:nx / 2] = np.arange(nx / 2, dtype=np.complex)
        shiftx[nx / 2:] = np.arange(-nx / 2, 0, dtype=np.complex)
        shiftx = np.exp((-2.0j * np.pi * colpos * shiftx) / float(nx))

        shifty = np.zeros([nx], np.complex)
        shifty[:nx / 2] = np.arange(nx / 2, dtype=np.complex)
        shifty[nx / 2:] = np.arange(-nx / 2, 0, dtype=np.complex)
        shifty = np.exp((-2.0j * np.pi * rowpos * shifty) / float(nx))

        shift = np.ones([nx, nx], np.complex)
        for j in range(nx):
            shift[j, :] *= shiftx
        for i in range(nx):
            shift[:, i] *= shifty

        # calculate spectrum
        spectrum = spectrum_function.calculate()

        # go through freq planes and add point source to each
        for iwn, wn in enumerate(frequency_axis):
            # create point in frequency space
            temp = np.zeros([nx, nx])
            temp[0, 0] = spectrum[iwn]
            # 2d fft
            temp = np.fft.fft2(temp)
            # apply phase shift to move point to required offset
            temp *= shift
            # transform back
            temp = np.fft.ifft2(temp)

            # add to sky model
            skymodel[:, :, iwn] += temp

        # return spectrum
        axis = co.Axis(data=frequency_axis, title='wavenumber', units='cm-1')
        spectrum = co.Spectrum(data=spectrum,
                               axis=axis,
                               title='Source spectrum',
                               units='W sr-1 m-2 Hz-1')

        return spectrum
Beispiel #3
0
    def _create_gaussian_source(self, xpos, ypos, xwidth, ywidth, skymodel,
                                spatial_axis, frequency_axis,
                                spectrum_function):
        """Create a point source.
        """
        # calculate spectrum
        spectrum = spectrum_function.calculate()

        # calculate Gaussian profile - a cunning use of array slicing found
        # on the web
        x = spatial_axis
        y = x[:, np.newaxis]
        profile = np.exp(-4 * np.log(2) * ((x - xpos)**2 / xwidth**2 +
                                           (y - ypos)**2 / ywidth**2))

        # apodise
        profile[((x - xpos)**2 + (y - ypos)**2) > 16] = 0.0

        # go through freq planes and add source to each
        for iwn, wn in enumerate(frequency_axis):
            # add to sky model
            skymodel[:, :, iwn] += profile * spectrum[iwn]

        # return spectrum
        axis = co.Axis(data=frequency_axis, title='wavenumber', units='cm-1')
        spectrum = co.Spectrum(data=spectrum,
                               axis=axis,
                               title='Source spectrum',
                               units='W sr-1 m-2 Hz-1')

        return spectrum
Beispiel #4
0
    def run(self):
        #        print 'ReduceInterferogram.run'

        # namedtuple to hold UVspectrum result
        UVspectrum = collections.namedtuple('uvspectrum', [
            'scan_number', 'baseline_x', 'baseline_y', 'baseline_z',
            'interferogram', 'opd', 'spectrum', 'wavenumber'
        ],
                                            verbose=False)

        # get observation list
        observe = self.previous_results['observe']
        obs_timeline = observe['observed_timeline']

        # Construct a dict holding lists of configurations for each
        # baseline observed
        baseline_configs = collections.defaultdict(list)
        observed_times = obs_timeline.keys()
        observed_times.sort()

        for t in observed_times:
            config = obs_timeline[t]
            b = (config.baseline_x, config.baseline_y, config.baseline_z)
            baseline_configs[b].append(config)

        baselines = baseline_configs.keys()
        baselines.sort()

        # for each baseline assemble config data into arrays
        baseline_scans = {}
        baseline_mean = {}
        baseline_uvspectrum = {}

        for b in baselines:
            data = []
            smec_position = []
            flag = []

            for config in baseline_configs[b]:
                data.append(config.data)
                smec_position.append(config.smec_position)
                flag.append(config.flag)

            data = np.array(data)
            smec_position = np.array(smec_position)
            flag = np.array(flag)

            # identify scans within the data flow
            flag_sections = find_flagged_sections(flag)

            # extract scans from the data stream
            scans = []
            mark = 0
            for flag_section in flag_sections:
                interferogram = data[mark:flag_section[0]]
                opd = 100.0 * smec_position[mark:flag_section[0]] / \
                  self.smec_opd_to_mpd

                if len(interferogram):
                    axis = co.Axis(data=opd, title='OPD', units='cm')
                    scan = co.Spectrum(data=interferogram,
                                       flag=np.zeros(np.shape(interferogram),
                                                     np.bool),
                                       axis=axis,
                                       title='scan interferogram',
                                       units='')
                    scans.append(scan)

                mark = flag_section[1] + 1

            # deal with last scan
            interferogram = data[mark:]
            opd = 100.0 * smec_position[mark:] / self.smec_opd_to_mpd

            if len(interferogram):
                axis = co.Axis(data=opd, title='OPD', units='cm')
                scan = co.Spectrum(data=interferogram,
                                   flag=np.zeros(np.shape(interferogram),
                                                 np.bool),
                                   axis=axis,
                                   title='scan interferogram',
                                   units='')
                scans.append(scan)

            baseline_scans[b] = scans

            # now obtain mean of scans for each baseline

            interferogram_sum = np.zeros(np.shape(scans[0].data))
            interferogram_n = np.zeros(np.shape(scans[0].data))

            for scan in scans:
                # assume opd ranges are the same but sort them into
                # ascending order
                opd = scan.axis.data
                opd_sort = np.argsort(opd)
                interferogram_sum += scan.data[opd_sort]
                interferogram_n += 1.0

            interferogram_mean = interferogram_sum / interferogram_n

            axis = co.Axis(data=opd[opd_sort], title='OPD', units='cm')
            scan_mean = co.Spectrum(data=interferogram_mean,
                                    flag=np.zeros(np.shape(interferogram_mean),
                                                  np.bool),
                                    axis=axis,
                                    title='mean interferogram',
                                    units='')

            baseline_mean[b] = scan_mean

            # now convert interferogram to spectrum at this u-v position
            # first, shift interferogram so that 0 opd is at index 0
            # must ask David N how to do this properly
            postzero = []
            prezero = []
            postzero_opd = []
            prezero_opd = []
            zero_opd_found = False

            for i, opd in enumerate(scan_mean.axis.data):
                if abs(opd) < 1e-10:
                    zero_opd_found = True
                if not zero_opd_found:
                    prezero.append(scan_mean.data[i])
                    prezero_opd.append(scan_mean.axis.data[i])
                else:
                    postzero.append(scan_mean.data[i])
                    postzero_opd.append(scan_mean.axis.data[i])

            shifted = postzero + prezero
            shifted_opd = postzero_opd + prezero_opd

            shifted = np.array(shifted)
            shifted_opd = np.array(shifted_opd)

            # spectrum is complex
            spectrum = np.fft.fft(shifted)
            wavenumber = np.fft.fftfreq(n=spectrum.size,
                                        d=abs(shifted_opd[1] - shifted_opd[0]))

            # save it
            uvspectrum = UVspectrum(None, b[0], b[1], 0.0, shifted,
                                    shifted_opd, spectrum, wavenumber)

            baseline_uvspectrum[b] = uvspectrum

        self.result['baseline_scans'] = baseline_scans
        self.result['baseline_mean'] = baseline_mean
        self.result['baseline_uvspectrum'] = baseline_uvspectrum

        return self.result
Beispiel #5
0
    def run(self):
        print 'DoubleFourier.run'

        # convert lengths to m. Wavenumbers leave as cm-1.
        fts = self.previous_results['fts']
        fts_wn = fts['fts_wn']
        fts_wn_truncated = fts['fts_wn_truncated']
        opd_max = fts['opd_max'] / 100.0
        fts_nsample = fts['ftsnsample']
        vdrive = fts['vdrive'] / 100.0
        delta_opd = fts['delta_opd']
        delta_time = delta_opd / vdrive

        times = np.arange(int(fts_nsample), dtype=np.float)
        times *= delta_time
        opd_start = -((fts_nsample + 1) / 2) * delta_opd

        beamsgenerator = self.previous_results['beamsgenerator']

        uvmapgenerator = self.previous_results['uvmapgenerator']
        bxby = uvmapgenerator['bxby']

        skygenerator = self.previous_results['skygenerator']
        skymodel = skygenerator['sky model']
        spatial_axis = self.result['spatial axis'] = skygenerator[
            'spatial axis']
        self.result['frequency axis'] = fts_wn_truncated

        # assuming nx is even then transform has 0 freq at origin and [nx/2] is
        # Nyquist frequency. Nyq freq = 0.5 * Nyquist sampling freq.
        # Assume further that the fft is shifted so that 0 freq is at nx/2
        nx = len(spatial_axis)
        spatial_freq_axis = np.arange(-nx / 2, nx / 2, dtype=np.float)
        sample_freq = (180.0 * 3600.0 / np.pi) / (spatial_axis[1] -
                                                  spatial_axis[0])
        spatial_freq_axis *= (sample_freq / nx)
        self.result['spatial frequency axis'] = spatial_freq_axis

        self.result['baseline interferograms'] = collections.OrderedDict()
        #        for baseline in bxby:
        for baseline in bxby[:1]:
            print 'baseline', baseline
            measurement = np.zeros(np.shape(times))
            opd = np.zeros(np.shape(times))

            # FTS path diff and possibly baseline itself vary with time
            for tindex, t in enumerate(times):

                # calculate the sky that the system is observing at this
                # moment, incorporating various errors in turn. Be explicit
                # about the copy otherwise a reference is made instead.
                sky_now = skymodel.copy()

                # 1. baseline should be perp to centre of field.
                #    If baseline is tilted then origin of sky map shifts.
                #    (I think effect could be corrected by changing
                #    FTS sample position to compensate.?)
                # for now assume 0 error but do full calculation for timing
                # purposes

                # perfect baseline is perpendicular to direction to 'centre'
                # on sky. Add errors in x,y,z - z towards sky 'centre'
                bz = 0.0
                # convert bz to angular error
                blength = math.sqrt(baseline[0] * baseline[0] +
                                    baseline[1] * baseline[1])
                bangle = (180.0 * 3600.0 / math.pi) * bz / blength
                bx_error = bangle * baseline[0] / blength
                by_error = bangle * baseline[1] / blength

                # calculate xpos, ypos in units of pixel - numpy arrays
                # [row,col]
                nx = len(spatial_axis)
                colpos = float(nx-1) * bx_error / \
                  (spatial_axis[-1] - spatial_axis[0])
                rowpos = float(nx-1) * by_error / \
                  (spatial_axis[-1] - spatial_axis[0])

                # calculate fourier phase shift to move point at [0,0] to
                # [rowpos, colpos]
                shiftx = np.zeros([nx], np.complex)
                shiftx[:nx / 2] = np.arange(nx / 2, dtype=np.complex)
                shiftx[nx / 2:] = np.arange(-nx / 2, 0, dtype=np.complex)
                shiftx = np.exp((-2.0j * np.pi * colpos * shiftx) / float(nx))

                shifty = np.zeros([nx], np.complex)
                shifty[:nx / 2] = np.arange(nx / 2, dtype=np.complex)
                shifty[nx / 2:] = np.arange(-nx / 2, 0, dtype=np.complex)
                shifty = np.exp((-2.0j * np.pi * rowpos * shifty) / float(nx))

                shift = np.ones([nx, nx], np.complex)
                for j in range(nx):
                    shift[j, :] *= shiftx
                for i in range(nx):
                    shift[:, i] *= shifty

                jobs = {}
                # go through freq planes and shift them
                for iwn, wn in enumerate(fts_wn_truncated):
                    # submit jobs
                    indata = (
                        sky_now[:, :, iwn],
                        shift,
                    )
                    jobs[wn] = self.job_server.submit(fftshift, indata, (),
                                                      ('numpy', ))

                for iwn, wn in enumerate(fts_wn_truncated):
                    # collect and store results
                    temp = jobs[wn]()
                    sky_now[:, :, iwn] = temp

                if t == times[0]:
                    # take copy of array to fix a snapshot of it now
                    self.result['sky at time 0'] = sky_now.copy()

                # 2. telescopes should be centred on centre of field
                #    Telescopes collect flux from the 'sky' and pass
                #    it to the FTS beam combiner. In doing this each
                #    telescope multiplies the sky emission by its
                #    amplitude beam response - always real but with
                #    negative areas. Is this correct? Gives right
                #    answer for 'no error' case.

                # multiply sky by amplitude beam 1 * amplitude beam 2
                amp_beam_1 = beamsgenerator['primary amplitude beam'].data
                amp_beam_2 = beamsgenerator['primary amplitude beam'].data

                for iwn, wn in enumerate(fts_wn):
                    # calculate shifted beams here
                    # for now assume no errors and just use beam
                    # calculated earlier
                    pass

                # multiply sky by amplitude beams of 2 antennas
                sky_now *= amp_beam_1 * amp_beam_2

                if t == times[0]:
                    # take copy of array to fix a snapshot of it now
                    self.result['sky*beams at time 0'] = sky_now.copy()

                # 3. baseline error revisited
                # derive baseline at this time
                #
                # Perhaps baseline should be a continuous function in
                # time, which would allow baselines that intentionally
                # smoothly vary (as in rotating tethered assembly)
                # and errors to be handled by one description.
                #
                # what follows assumes zero error

                baseline_error = 0.0
                baseline_now = baseline + baseline_error

                fft_now = np.zeros(np.shape(sky_now), np.complex)
                spectrum = np.zeros(np.shape(fts_wn), np.complex)
                for iwn, wn in enumerate(fts_wn_truncated):

                    # derive shift needed to place baseline at one of FFT coords
                    # this depends on physical baseline and frequency
                    baseline_now_lambdas = baseline_now * wn * 100.0

                    # calculate baseline position in units of pixels of FFTed
                    # sky - numpy arrays [row,col]
                    colpos = float(nx-1) * \
                      float(baseline_now_lambdas[0] - spatial_freq_axis[0]) / \
                      (spatial_freq_axis[-1] - spatial_freq_axis[0])
                    rowpos = float(nx-1) * \
                      float(baseline_now_lambdas[1] - spatial_freq_axis[0]) / \
                      (spatial_freq_axis[-1] - spatial_freq_axis[0])
                    colpos = 0.0
                    rowpos = 0.0

                    # calculate fourier phase shift to move point at [rowpos,colpos] to
                    # [0,0]
                    shiftx = np.zeros([nx], np.complex)
                    shiftx[:nx / 2] = np.arange(nx / 2, dtype=np.complex)
                    shiftx[nx / 2:] = np.arange(-nx / 2, 0, dtype=np.complex)
                    shiftx = np.exp((-2.0j * np.pi * colpos * shiftx) / \
                      float(nx))

                    shifty = np.zeros([nx], np.complex)
                    shifty[:nx / 2] = np.arange(nx / 2, dtype=np.complex)
                    shifty[nx / 2:] = np.arange(-nx / 2, 0, dtype=np.complex)
                    shifty = np.exp(
                        (-2.0j * np.pi * rowpos * shifty) / float(nx))

                    shift = np.ones([nx, nx], np.complex)
                    for j in range(nx):
                        shift[j, :] *= shiftx
                    for i in range(nx):
                        shift[:, i] *= shifty

                    # move centre of sky image to origin
                    temp = np.fft.fftshift(sky_now[:, :, iwn])
                    # apply phase shift
                    temp *= shift
                    # 2d fft
                    temp = np.fft.fft2(temp)
                    fft_now[:, :, iwn] = temp

                    # set amp/phase at this frequency
                    spectrum[wn == fts_wn] = temp[0, 0]

                if t == times[0]:
                    self.result['skyfft at time 0'] = fft_now.copy()

                    axis = co.Axis(data=fts_wn,
                                   title='wavenumber',
                                   units='cm-1')
                    temp = co.Spectrum(data=spectrum,
                                       axis=axis,
                                       title='Detected spectrum',
                                       units='W sr-1 m-2 Hz-1')
                    self.result['skyfft spectrum at time 0'] = temp

                # 3. FTS sampling should be accurate
                #    derive lag due to FTS path difference
                #    0 error for now

                if t == times[0]:
                    # test interferogram
                    # inverse fft of emission spectrum at this point
                    reflected_spectrum = np.zeros([2 * (len(spectrum) - 1)],
                                                  np.complex)
                    reflected_spectrum[:len(spectrum)].real = spectrum
                    reflected_spectrum[len(spectrum):].real = spectrum[-2:0:-1]

                    temp = np.fft.ifft(reflected_spectrum)
                    pos = np.fft.fftfreq(len(reflected_spectrum),
                                         d=fts_wn[1] - fts_wn[0])

                    # move 0 frequency to centre of array
                    temp = np.fft.fftshift(temp)
                    pos = np.fft.fftshift(pos)

                    axis = co.Axis(data=pos,
                                   title='path difference',
                                   units='cm')
                    temp = co.Spectrum(data=temp,
                                       axis=axis,
                                       title='Detected interferogram',
                                       units='')

                    self.result['test FTS at time 0'] = temp

                mirror_error = 0.0
                opd[tindex] = opd_start + (vdrive * t + mirror_error)
                opd_ipos = opd[tindex] / delta_opd

                # calculate shift needed to move point at opd to 0
                nfreq = len(fts_wn)
                ndoublefreq = 2 * (nfreq - 1)
                shift = np.zeros([ndoublefreq], dtype=np.complex)
                shift[:nfreq] = np.arange(nfreq, dtype=np.complex)
                shift[nfreq:] = np.arange(nfreq, dtype=np.complex)[-2:0:-1]
                shift = np.exp((-2.0j * np.pi * opd_ipos * shift) / \
                  float(ndoublefreq))

                # reflect spectrum about 0 to give unaliased version
                reflected_spectrum = np.zeros([2 * (len(spectrum) - 1)],
                                              np.complex)
                reflected_spectrum[:len(spectrum)].real = spectrum
                reflected_spectrum[len(spectrum):].real = spectrum[-2:0:-1]

                # apply phase shift and fft
                reflected_spectrum *= shift
                spectrum_fft = np.fft.ifft(reflected_spectrum)
                measurement[tindex] = spectrum_fft[0]

#                if np.array_equal(baseline, bxby[0]):
#                    if 'skyfft check' not in self.result.keys():
#                        self.result['skyfft check'] = {}
#                    temp = co.Spectrum(data=spectrum_fft,
#                      title='Test interferogram', units='')
#                    self.result['skyfft check'][t] = temp

            axis = co.Axis(data=np.array(opd),
                           title='path difference',
                           units='cm')
            temp = co.Spectrum(data=measurement,
                               axis=axis,
                               title='Detected interferogram',
                               units='')
            self.result['baseline interferograms'][tuple(baseline)] = \
              temp

        return self.result
Beispiel #6
0
    def run(self):
        print 'Calculating beams'

        # gather configuration 
        uvmapgen = self.previous_results['uvmapgenerator']
        fts = self.previous_results['fts']
        telescope = self.previous_results['loadparameters']['substages']\
          ['Telescope']

        # number of mirror positions sampled by FTS
        nsample = fts['ftsnsample']
        fts_wn = fts['fts_wn']
        fts_wn_truncated = fts['fts_wn_truncated']
      
        # max pixel size (radians) that will fully sample the image.
        # Sampling freq is 2 * Nyquist freq.
        # So sampling freq = 2 * b_max / lambda_min.
        bmax = uvmapgen['bmax']
        self.result['max baseline [m]'] = bmax

        lambda_min = 1.0 / (np.max(fts_wn) * 100.0)
        max_pixsize = lambda_min / (2.0 * bmax)
        self.result['max pixsize [rad]'] = max_pixsize

        # Number of pixels per beam
        # radius of first null of Airy disk is theta=1.22lambda/d. Number of
        # pixels is beam diameter/max_pixsize. Calculate this for the 
        # longest wavelength that has flux (at wnmin), largest beam
        
        max_beam_radius = 1.22 * (1.0 / (np.min(fts_wn_truncated) * 100.0)) /\
          telescope['Primary mirror diameter']
        self.result['beam diam [rad]'] = 2.0 * max_beam_radius
         
        # go out to radius of first null
        rpix = int(max_beam_radius / max_pixsize)
        npix = 2 * rpix
        self.result['npix'] = npix

        # spatial axes same for all wavelengths
        axis = np.arange(-rpix, rpix, dtype=np.float)
        axis *= max_pixsize
        axis *= 206264.806247
        self.result['spatial axis [arcsec]'] = axis
        axis1 = co.Axis(data=-axis, title='RA offset', units='arcsec') 
        axis2 = co.Axis(data=axis, title='Dec offset', units='arcsec') 
        axis3 = co.Axis(data=fts_wn_truncated, title='Frequency', units='cm-1')

        # calculate beams for each point on fts_wn_truncated
        # oversample uv grid by mult to minimise aliasing
        mult = 5
        mx,my = np.meshgrid(np.arange(-mult*rpix, mult*rpix),
          np.arange(-mult*rpix, mult*rpix))
        self.result['primary beam'] = collections.OrderedDict()
        self.result['primary amplitude beam'] = collections.OrderedDict()
        self.result['dirty beam'] = collections.OrderedDict()
        self.result['clean beam'] = collections.OrderedDict()

        wnmax = np.max(fts_wn_truncated)
        m1_diameter = telescope['Primary mirror diameter']

        # first calculate primary beam for each wn
        jobs = {}
        for wn in fts_wn_truncated:
            # submit jobs
            indata = (npix, rpix, mult, mx, my, bmax, m1_diameter, wnmax,
              wn,)
            jobs[wn] = self.job_server.submit(calculate_primary_beam,
              indata, (), ('numpy',))

        primary_amplitude_beam = np.zeros([npix,npix,len(fts_wn_truncated)],
          np.complex)
        for iwn,wn in enumerate(fts_wn_truncated):
            # collect and store results
            primary_intensity_beam, primary_amplitude_beam[:,:,iwn] = jobs[wn]()
            image = co.Image(data=primary_intensity_beam, axes=[axis1, axis2],
              title='Primary Beam %06.4g cm-1' % wn)
            self.result['primary beam'][wn] = image

        cube = co.Cube(data=primary_amplitude_beam, axes=[axis1, axis2, axis3],
          title='Amplitude Primary Beam %06.4g cm-1' % wn)
        self.result['primary amplitude beam'] = cube

        # second calculate dirty beam, same use of pp
        for wn in fts_wn_truncated:
            #
            # 1. uv plane covered by discrete points so should use a
            # slow dft rather than fft, which requires evenly spaced
            # samples. Perhaps a bit slow though as calcs done in Python
            # layer.
            # 2. Could use shift theorem to give even-spaced equivalent
            # of each discrete point, then use ffts. Equivalent to 1
            # in speed.
            # 3. Oversample uv plane and accept small error in point
            # positions. Fastest but adequate?

            indata = (npix, rpix, mult, bmax, uvmapgen['bxby'], wnmax, wn,)
            jobs[wn] = self.job_server.submit(calculate_dirty_beam,
              indata, (), ('numpy','fitgaussian',))


        # axes for dirty beam
        axis = np.arange(-rpix, rpix, dtype=np.float)
        axis *= (lambda_min / bmax)
        axis *= 206264.806247
        axis1 = co.Axis(data=-axis, title='RA offset', units='arcsec') 
        axis2 = co.Axis(data=axis, title='Dec offset', units='arcsec') 

        for wn in fts_wn_truncated:
            dirty_beam,clean_beam = jobs[wn]()
            image = co.Image(data=dirty_beam, axes=[axis1, axis2],
              title='Dirty Beam %06.4g cm-1' % wn)
            self.result['dirty beam'][wn] = image
            image = co.Image(data=clean_beam, axes=[axis1, axis2],
              title='Clean Beam %06.4g cm-1' % wn)
            self.result['clean beam'][wn] = image

        return self.result
Beispiel #7
0
    def run(self):
        print 'Calculating primary beams...'

        # gather configuration
        cubeparams = self.previous_results['cubeparameters']
        self.result['wn'] = wn = cubeparams['wn']
        self.result['pixsize [rad]'] = pixsize = cubeparams['pixsize [rad]']
        self.result['npix'] = npix = cubeparams['npix']

        telescope = self.previous_results['loadparameters']['substages']\
          ['Telescope']
        m1_diameter = telescope['Primary mirror diameter']

        rpix = npix / 2
        # spatial axes same for all wavelengths
        axis = np.arange(-rpix, rpix, dtype=np.float)
        axis *= pixsize
        axis = np.rad2deg(axis) * 3600.0
        axis1 = co.Axis(data=-axis, title='RA offset', units='arcsec')
        axis2 = co.Axis(data=axis, title='Dec offset', units='arcsec')
        axis3 = co.Axis(data=wn, title='Frequency', units='cm-1')

        # calculate beams for each point on 'wn'
        jobs = {}

        for wavenum in wn:
            # submit jobs
            indata = (
                npix,
                pixsize,
                m1_diameter,
                wavenum,
                self.nuv,
            )
            jobs[wavenum] = self.job_server.submit(calculate_primary_beam,
                                                   indata, (), (
                                                       'numpy',
                                                       'math',
                                                       'zernike',
                                                   ))

        # collect results
        self.result['primary beam'] = collections.OrderedDict()
        self.result['primary amplitude beam'] = collections.OrderedDict()

        primary_amplitude_beam = np.zeros([npix, npix, len(wn)], np.complex)
        for iwn, wavenum in enumerate(wn):
            if jobs[wavenum]() is None:
                raise Exception, 'calculate_primary_beams has failed'

            primary_amplitude_beam[:, :, iwn] = temp = jobs[wavenum]()
            primary_intensity_beam = (temp * np.conjugate(temp)).real
            image = co.Image(data=primary_intensity_beam,
                             axes=[axis1, axis2],
                             title='Primary Beam %06.4g cm-1' % wavenum)
            self.result['primary beam'][wavenum] = image

        cube = co.Cube(data=primary_amplitude_beam,
                       axes=[axis1, axis2, axis3],
                       title='Amplitude Primary Beam')
        self.result['primary amplitude beam'] = cube

        return self.result