def __init__(self, nu, dnu, phi, weights=None): """ RMSynth(nu, dnu, phi, weights=None, isl2=False) Initializes the RMSynth class. For an image, this needs only be done once. Each LOS may be inverted individually using the compute_dirty_image method. Inputs: nu- A vector containing frequency(Hz) values. Either way they must be ordered from lowest to highest value. dnu- Width of the frequency channels (in Hz). phi- The requested phi axis. Use numpy.arange to construct. weights-A vector containing weights. Must be the same length as nu. Values should be between 0 and 1. If no weights vector is given, it will be assumed that each value has weight 1. Outputs: None """ # parameters used for gridding self.m = 6 # number of grid cells overwhich the GCF spans self.alpha = 1.5 # oversampling ratio self.dphi = phi[1] - phi[0] self.nphi = len(phi) self.dl2 = 1. / self.nphi / self.dphi / self.alpha self.nl2 = self.alpha * self.nphi stdout.write('RMSynth Initializing... ') stdout.flush() # equal weighting for all frequencies by default. if weights is None: weights = numpy.ones(len(nu)) if len(nu) != len(weights): msg = 'The length of weight and frequency vectors must be equal!' raise IndexError(msg) # for now store the ungridded l2s (for diagnostics) self.l2_nonuni = self.convert_nu_to_l2(nu, dnu) self.weights_nonuni = numpy.flipud(weights) # another gridding parameter, derived from m and alpha self.beta = numpy.pi *\ numpy.sqrt((self.m / self.alpha) ** 2. * (self.alpha - 0.5) ** 2 - 0.8) self.l20 = self.compute_l20() self.l2i = self.l2_nonuni[0] - self.m * self.dl2 * numpy.pi # this axis is actually \lambda^2/\pi self.l2 = numpy.arange(0, self.nl2, 1) * self.dl2 + self.l2i / numpy.pi self.l2_beam = numpy.arange(0, self.nl2 * 2., 1) * self.dl2 / 2. \ + self.l2i / numpy.pi self.phi = -self.dphi * self.nphi * 0.5 \ + numpy.arange(0, self.nphi, 1) * self.dphi self.grid_corr = G.gridnorm(self.phi, self.dl2, self.m, self.beta) self.tndx_phi = int(0.5 * self.nphi * (self.alpha - 1)) [self.rmsf, self.rmsf_phi] = self.compute_rmsf() stdout.write('Complete.\n')
def compute_rmsf(self): """ RMSynth.compute_rmsf() Inverts the given polarization vector to arrive at the dirty dispersion function. Inputs: None Outputs: 1- A map containing the RMSF. A numpy array of complex values. 2- A map containing the RMSF phi axis. """ # RMSF image size must be twice that of the df image for CLEANing phi_center = 0.5 * ((numpy.max(self.phi) + self.dphi) + numpy.min(self.phi)) phi_range = (numpy.max(self.phi) + self.dphi) - numpy.min(self.phi) rmsf_phi = phi_center - phi_range +\ numpy.arange(2 * self.nphi) * self.dphi try: # Convolve weights with the GCF [l2_grid, w_grid] = G.grid_1d(self.weights_nonuni, self.l2_nonuni / numpy.pi, self.dl2 / 2., self.m, self.alpha) # Put the convolved points on a grid weights4rmsf = G.sample_grid(self.l2_beam, l2_grid, w_grid) except TypeError: print type(self.weights) print len(self.weights) print type(self.l2_nonuni) print len(self.l2_nonuni) print self.dphi print self.nphi * 2. raise rmsf = numpy.fft.fftshift(numpy.fft.fft(weights4rmsf)) tndx_phi = int(self. nphi * (self.alpha - 1)) rmsf = rmsf[tndx_phi:tndx_phi + 2 * self.nphi] #for indx in range(2 * self.nphi): #rot = 2. * (self.l20 - self.l2i) * rmsf_phi[indx] ## shift results by the L20 and by the initial l2 value to account ## for the fact that we start at L2!=0 as FFT expects #rmsf[indx] = numpy.complex(math.cos(rot), math.sin(rot)) *\ #rmsf[indx] rot = 2. * (self.l20 - self.l2i) * rmsf_phi # shift results by the L20 and by the initial l2 value to account # for the fact that we start at L2!=0 as FFT expects rmsf *= numpy.exp(complex(0, 1) * rot) gridnorm = G.gridnorm(rmsf_phi, self.dl2 / 2., self.m, self.beta) rmsf = rmsf / gridnorm # The normalization should be as such that the rmsf has a peak # value of 1 self.K = 1. / abs(rmsf[self.nphi]) # normalize the rmsf rmsf = rmsf * self.K # adjust the normalization # because the rmsf has twice as many pixels as the image self.K = 2. * self.K return rmsf, rmsf_phi