Source code for pyoof.telgeometry.telgeometry

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Author: Tomas Cassanelli
import numpy as np
from astropy import units as apu
from ..math_functions import line_equation

__all__ = ['opd_effelsberg', 'opd_manual', 'block_manual', 'block_effelsberg']


[docs]def opd_effelsberg(x, y, d_z): """ Optical path difference (OPD) function, :math:`\\delta(x,y;d_z)`. Given by the geometry of the telescope and radial offset parameter, :math:`d_z`. This function is specific for the Effelsberg telescope. Parameters ---------- x : `~astropy.units.quantity.Quantity` Grid value for the :math:`x` variable in length units. y : `~astropy.units.quantity.Quantity` Grid value for the :math:`y` variable in length units. d_z : `~astropy.units.quantity.Quantity` Radial offset, :math:`d_z`, added to the sub-reflector in meters. This characteristic measurement adds the classical interference pattern to the beam maps, normalized squared (field) radiation pattern, which is an out-of-focus property. It is usually of the order of centimeters. Returns ------- opd : `~astropy.units.quantity.Quantity` Optical path difference function, :math:`\\delta(x,y;d_z)`. Notes ----- For a Gregorian configuration, and with the dish diameter of Effelsberg, the OPD function becomes, .. math:: \\delta(x,;d_z) = d_z\\left( \\frac{1-a^2}{1+a^2} + \\frac{1-b^2}{1+b^2} \\right), .. math:: a = \\frac{\\sqrt{x^2+y^2}}{2F_\\mathrm{p}}, \\qquad b = \\frac{\\sqrt{x^2+y^2}}{2F_\\mathrm{eff}}, where :math:`F_\\mathrm{p}=30` m corresponds to the parabola focal length and :math:`F_\\mathrm{eff}=387.4` m, the effective or total focal length. """ # Cassegrain/Gregorian (at focus) telescope Fp = 30 * apu.m # Focus primary reflector m F = 387.39435 * apu.m # Total focus Gregorian telescope m r = np.sqrt(x ** 2 + y ** 2) # polar coordinates radius a = r / (2 * Fp) b = r / (2 * F) opd = d_z * ((1 - a ** 2) / (1 + a ** 2) + (1 - b ** 2) / (1 + b ** 2)) return opd
[docs]def opd_manual(Fp, F): """ Optical path difference (OPD) function, :math:`\\delta(x, yd_z)`. Given by geometry of the telescope and defocus parameter, :math:`d_z`. For Cassegrain/Gregorian geometries. Primary and total (or effective) foci are required, :math:`F_\\mathrm{p}` and :math:`F_\\mathrm{eff}`, respectively. Parameters ---------- Fp : `~astropy.units.quantity.Quantity` Focus primary reflector, :math:`F_\\mathrm{p}`, in length units. F : `~astropy.units.quantity.Quantity` Effective or total focus for the telescope mirror configuration, :math:`F_\\mathrm{eff}`, in length units. Returns ------- opd_func : `function` It returns the function ``opd_func(x, y, d_z)``, which depends only on the grid and radial offset values, similar to `~pyoof.telgeometry.opd_effelsberg`. """ def opd_func(x, y, d_z): # Cassegrain/Gregorian (at focus) telescope r = np.sqrt(x ** 2 + y ** 2) # radial polar coordinate a = r / (2 * Fp) b = r / (2 * F) opd = d_z * ( (1 - a ** 2) / (1 + a ** 2) + (1 - b ** 2) / (1 + b ** 2) ) return opd return opd_func
[docs]def block_effelsberg(alpha=20 * apu.deg): """ Truncation in the aperture (amplitude) distribution, :math:`B(x, y)`, given by the telescope's structure; i.e. support legs, sub-reflector and shade effect as seen from the secondary focus of the Effelsberg telescope. Parameters ---------- x : `~astropy.units.quantity.Quantity` Grid value for the :math:`x` variable in length units. y : `~astropy.units.quantity.Quantity` Grid value for the :math:`y` variable in length units. alpha : `~astropy.units.quantity.Quantity` Inclination of the shade effect done by the support legs on the aperture plane, a larger angle will have a broader shade. It is measured in angle units. Returns ------- block_func : `function` Aperture (amplitude) distribution truncation, :math:`B(x, y)`. Values that are zero correspond to blocked values. """ # Default Effelsberg geometry pr = 50 * apu.m # Primary reflector radius sr = 3.25 * apu.m # Sub-reflector radius L = 20 * apu.m # Length support structure (from the edge of the sr) a = 1 * apu.m # Half-width support structure def block_func(x, y): block = np.zeros(x.shape) # or y.shape same block[(x ** 2 + y ** 2 < pr ** 2) & (x ** 2 + y ** 2 > sr ** 2)] = 1 block[(-(sr + L) < x) & (x < (sr + L)) & (-a < y) & (y < a)] = 0 block[(-(sr + L) < y) & (y < (sr + L)) & (-a < x) & (x < a)] = 0 # block[(x ** 2 + y ** 2 < sr ** 2)] = 0.8 csc2 = np.sin(alpha) ** (-2) # squared cosecant # base of the triangle d = (-a + np.sqrt(a ** 2 - (a ** 2 - pr ** 2) * csc2)) / csc2 # points for the triangle coordinates A = sr + L B = a C = d / np.tan(alpha) D = a + d y1 = line_equation((A, B), (C, D), x) y2 = line_equation((A, -B), (C, -D), x) x3 = line_equation((-A, B), (-C, D), y) x4 = line_equation((-A, -B), (-C, -D), y) y5 = line_equation((-A, -B), (-C, -D), x) y6 = line_equation((-A, B), (-C, D), x) x7 = line_equation((A, -B), (C, -D), y) x8 = line_equation((A, B), (C, D), y) def circ(s): return np.sqrt(np.abs(pr ** 2 - s ** 2)) block[(A < x) & (C > x) & (y1 > y) & (y2 < y)] = 0 block[(pr > x) & (C < x) & (circ(x) > y) & (-circ(x) < y)] = 0 block[(-A > y) & (-C < y) & (x4 < x) & (x3 > x)] = 0 block[(-pr < y) & (-C > y) & (circ(y) > x) & (-circ(y) < x)] = 0 block[(-A > x) & (-C < x) & (y5 < y) & (y6 > y)] = 0 block[(-pr < x) & (-C > x) & (circ(x) > y) & (-circ(x) < y)] = 0 block[(A < y) & (C > y) & (x7 < x) & (x8 > x)] = 0 block[(pr > y) & (C < y) & (circ(x) > y) & (-circ(x) < y)] = 0 return block return block_func
[docs]def block_manual(pr, sr, a, L): """ Truncation for the aperture (amplitude) distribution, :math:`B(x, y)`, manual set up for the primary radius (**pr**), sub-reflector radius (**sr**), half-width of a support leg (**a**) and length of the support leg (**L**) measured from the edge of the sub-reflector radius. It has been considered 4 support legs. To exclude **sr**, **a** or **L** set them to zero. Parameters ---------- pr : `astropy.units.quantity.Quantity` Primary reflector radius in length units. sr : `float` Sub-reflector radius in length units. a : `float` Half-width of a support leg in length units. L : `float` Length of a support leg, measured from the edge of the sub-reflector towards its end, in length units. Returns ------- block_func : `function` It returns the function ``block_func(x, y)``, which depends only on the grid values, similar to `~pyoof.telgeometry.block_effelsberg`. """ def block_func(x, y): block = np.zeros(x.shape) # or y.shape same block[(x ** 2 + y ** 2 < pr ** 2) & (x ** 2 + y ** 2 > sr ** 2)] = 1 block[(-(sr + L) < x) & (x < (sr + L)) & (-a < y) & (y < a)] = 0 block[(-(sr + L) < y) & (y < (sr + L)) & (-a < x) & (x < a)] = 0 return block return block_func