class GradientCylinder(cylinder.UnpolarisedCylinderTelescope): min_spacing = config.Property(proptype=float, default=-1.0) max_spacing = config.Property(proptype=float, default=20.0) def feed_positions_cylinder(self, cylinder_index): if cylinder_index >= self.num_cylinders or cylinder_index < 0: raise Exception("Cylinder index is invalid.") nf = self.num_feeds # Parameters for gradient feedspacing a = self.wavelengths[ -1] / 2.0 if self.min_spacing < 0.0 else self.min_spacing # b = 2 * (sp - a) / nf b = 2.0 * (self.max_spacing - a * (nf - 1)) / (nf - 1)**2.0 pos = np.empty([nf, 2], dtype=np.float64) i = np.arange(nf) pos[:, 0] = cylinder_index * self.cylinder_spacing pos[:, 1] = a * i + 0.5 * b * i**2 return pos
class RestrictedBeam(cylinder.CylinderTelescope): beam_height = config.Property(proptype=typeutil.nonnegative_float, default=30.0) beam_type = config.Property(proptype=str, default='box') def bmask_gaussian(self, feed, freq): pointing = self.zenith bdist = (self._angpos - pointing[np.newaxis, :]) bdist = np.abs(np.where((bdist[:, 1] < np.pi)[:, np.newaxis], bdist, bdist - np.array([0, 2*np.pi])[np.newaxis, :])) bmask = gaussian_fwhm(bdist[:, 0], np.radians(self.beam_height)) return bmask def bmask_box(self, feed, freq): pointing = self.zenith bdist = (self._angpos - pointing[np.newaxis, :]) bdist = np.abs(np.where((bdist[:, 1] < np.pi)[:, np.newaxis], bdist, bdist - np.array([0, 2*np.pi])[np.newaxis, :])) bmask = (np.abs(bdist[:, 0] / np.radians(self.beam_height)) < 0.5) return bmask
class UnequalFeedsCylinder(cylinder.PolarisedCylinderTelescope): """A polarized unequal number of feeds cylinder array. A class for multiple side by side placed cylinders, each may have different number of equal spacing feeds. """ num_cylinders = config.Property(proptype=typeutil.positive_int, default=3) num_feeds = config.Property( proptype=typeutil.positive_int_or_non_empty_list, default=[31, 32, 33]) feed_spacing = config.Property( proptype=typeutil.positive_float_or_non_empty_list, default=[15.5 / 30, 0.5, 15.5 / 32]) cylinder_width = config.Property(proptype=typeutil.positive_float, default=15.0) def feed_positions_cylinder(self, cylinder_index): """Get the feed positions on the specified cylinder. Parameters ---------- cylinder_index : integer The cylinder index, an integer from 0 to self.num_cylinders. Returns ------- feed_positions : np.ndarray The positions in the telescope plane of the receivers. Packed as [[u1, v1], [u2, v2], ...]. """ if cylinder_index >= self.num_cylinders or cylinder_index < 0: raise Exception("Cylinder index is invalid.") ncyl = self.num_cylinders if len(self.num_feeds) == 1: self.num_feeds *= ncyl if len(self.num_feeds) != ncyl: raise Exception('Invalid num_feeds.') if len(self.feed_spacing) == 1: self.feed_spacing *= ncyl if len(self.feed_spacing) != ncyl: raise Exception('Invalid feed_spacings.') nf = self.num_feeds[cylinder_index] sp = self.feed_spacing[cylinder_index] if self.non_commensurate: nf = nf - cylinder_index sp = sp / (nf - 1.0) * nf pos = np.empty([nf, 2], dtype=np.float64) pos[:, 0] = cylinder_index * self.cylinder_spacing pos[:, 1] = np.arange(nf) * sp return pos
class CylinderExtra(cylinder.UnpolarisedCylinderTelescope): extra_feeds = config.Property(proptype=np.array, default=[]) def feed_positions_cylinder(self, cylinder_index): pos = super(CylinderExtra, self).feed_positions_cylinder(cylinder_index) nextra = self.extra_feeds.shape[0] pos2 = np.zeros((pos.shape[0] + nextra, 2), dtype=np.float64) pos2[nextra:] = pos pos2[:nextra, 0] = cylinder_index * self.cylinder_spacing pos2[:nextra, 1] = self.extra_feeds return pos2
class PolarisedCylinderShift(cylinder.PolarisedCylinderTelescope): shift = config.Property(proptype=typeutil.float_or_non_empty_list, default=0.0) def feed_positions_cylinder(self, cylinder_index): if cylinder_index >= self.num_cylinders or cylinder_index < 0: raise Exception("Cylinder index is invalid.") ncyl = self.num_cylinders if len(self.shift) == 1: self.shift *= ncyl if len(self.shift) != ncyl: raise Exception('Invalid shifts.') pos = super(PolarisedCylinderShift, self).feed_positions_cylinder(cylinder_index) v_shift = np.ones_like(pos) v_shift[:, 0] = 0.0 # u-direction doesn't change pos += self.shift[cylinder_index] * v_shift return pos
class GmrtArray(telescope.TransitTelescope): """A Telescope describing an interferometric array of dishes. Attributes ---------- gridu, gridv : integer Number of dishes in u and v directions. dish_width : scalar Width of the dish in metres. """ fwhm = 3.1 # degrees freq_lower = 139.33 freq_upper = 156.00 num_freq = 64 _pos_file = os.path.dirname(__file__) + '/gmrtpositions.dat' _compact = True _bc_freq = None _bc_nside = None _positions = None pointing = config.Property(proptype=float, default=0.0) dish_width = 45.0 tsys_flat = 582.0 minlength = 0.0 maxlength = 600.0 def __init__(self, pointing=0.0): super(GmrtArray, self).__init__(latitude=19.09, longitude=74.05) self._positions = np.loadtxt(self._pos_file) #self._positions = self._positions[np.where((self._positions**2).sum(axis=1)**0.5 < 1000)] self.pointing = pointing @property def u_width(self): return self.dish_width @property def v_width(self): return self.dish_width def beam(self, feed, freq): """Beam for a particular feed. Parameters ---------- feed : integer Index for the feed. freq : integer Index for the frequency. Returns ------- beam : np.ndarray A Healpix map (of size self._nside) of the beam. Potentially complex. """ if self._bc_freq != freq or self._bc_nside != self._nside: sigma = np.radians(self.fwhm) / (8.0 * np.log(2.0))**0.5 / ( self.frequencies[freq] / 150.0) pointing = np.array( [np.pi / 2.0 - np.radians(self.pointing), self.zenith[1]]) x2 = (1.0 - coord.sph_dot(self._angpos, pointing)**2) / (4 * sigma**2) self._bc_map = np.exp(-x2) self._bc_freq = freq self._bc_nside = self._nside return self._bc_map beamx = beam beamy = beam @property def _single_feedpositions(self): """The set of feed positions in the CMU telescope. Returns ------- feedpositions : np.ndarray The positions in the telescope plane of the receivers. Packed as [[u1, v1], [u2, v2], ...]. """ if self._positions is None: self._positions = np.loadtxt(self._pos_file) return self._positions
class FocalPlaneArray(telescope.UnpolarisedTelescope): beam_num_u = config.Property(proptype=typeutil.positive_int, default=10) beam_num_v = config.Property(proptype=typeutil.positive_int, default=10) beam_spacing_u = config.Property(proptype=typeutil.positive_float, default=0.1) beam_spacing_v = config.Property(proptype=typeutil.positive_float, default=0.1) beam_size = config.Property(proptype=typeutil.positive_float, default=0.1) beam_pivot = config.Property(proptype=typeutil.positive_float, default=400.0) beam_freq_scale = config.Property(proptype=bool, default=True) square_beam = config.Property(proptype=bool, default=False) @property def beam_pointings(self): pnt_u = self.beam_spacing_u * (np.arange(self.beam_num_u) - (self.beam_num_u - 1) / 2.0) pnt_v = self.beam_spacing_v * (np.arange(self.beam_num_v) - (self.beam_num_v - 1) / 2.0) pnt_u = np.radians(pnt_u) + self.zenith[1] pnt_v = np.radians(pnt_v) + self.zenith[0] pnt = np.zeros((self.beam_num_u, self.beam_num_v, 2)) pnt[:, :, 1] = pnt_u[:, np.newaxis] pnt[:, :, 0] = pnt_v[np.newaxis, :] return pnt.reshape(-1, 2) #== Methods for calculating the unique baselines === @util.cache_last def beam_gaussian(self, feed, freq): pointing = self.beam_pointings[feed] if self.beam_freq_scale: fwhm = self.beam_size * self.frequencies[freq] / self.beam_pivot else: fwhm = self.beam_size return gaussian_beam(self._angpos, pointing, fwhm) @util.cache_last def beam_square(self, feed, freq): pointing = self.beam_pointings[feed] bdist = (self._angpos - pointing[np.newaxis, :]) bdist = np.abs(np.where((bdist[:, 1] < np.pi)[:, np.newaxis], bdist, bdist - np.array([0, 2*np.pi])[np.newaxis, :])) / np.radians(self.beam_size) #bdist = np.abs(np.where((bdist[:, 1] < np.pi)[:, np.newaxis], bdist, bdist - np.array([0, 2*np.pi])[np.newaxis, :])) / np.radians(self.beam_size) beam = np.logical_and(bdist[:, 0] < 0.5, bdist[:, 1] < 0.5).astype(np.float64) return beam def beam(self, feed, freq): if self.square_beam: return self.beam_square(feed, freq) else: return self.beam_gaussian(feed, freq) @property def dish_width(self): lpivot = (units.c / self.beam_pivot * 1e-6) return (lpivot / np.radians(self.beam_size)) @property def u_width(self): return self.dish_width @property def v_width(self): return self.dish_width @property def nfeed(self): return self.beam_num_u * self.beam_num_v @property def feedpositions(self): """Feed positions (all zero in FPA). """ return np.zeros([self.nfeed, 2]) def _unique_beams(self): beam_mask = np.identity(self.nfeed, dtype=np.bool) beam_map = telescope._remap_keyarray(np.diag(np.arange(self.nfeed)), mask=beam_mask) return beam_map, beam_mask
class PersonWithPet(Person): petname = config.Property(default='Molly', proptype=str) petage = 36
class Person(config.Reader): name = config.Property(default='Bill', proptype=str) age = config.Property(default=26, proptype=float, key='ageinyears')