Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding new Telescope attributes for feeds and mounts #1521

Open
wants to merge 29 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
15c4113
Adding new Telescope attributes for feeds and mounts, folding into MI…
kartographer Jan 24, 2025
46a627c
Modifying handling of feed angle in UVFITS
kartographer Jan 25, 2025
8e506c3
Fixing some compatibility bugs w/ older versions of astropy and casacore
kartographer Jan 25, 2025
3f6475a
Adding test coverage
kartographer Jan 28, 2025
12dde57
First round of fixes based on external testing, adding time interval …
kartographer Jan 29, 2025
ac094c8
More updates based on testing
kartographer Jan 29, 2025
17e4143
Plugging in default values for poltype in write_ms_feed (rather than …
kartographer Feb 4, 2025
5cbc050
Removing and deprecating x-orientation attribute in Telescope
kartographer Feb 7, 2025
0b708d3
Updating test coverage, adding test file for xorient keyword in MIRIAD
kartographer Feb 13, 2025
4c7b503
Fixing tutorials
kartographer Feb 14, 2025
927a1d2
Fixing minor spelling error
kartographer Feb 14, 2025
8d0c5bd
Adding conventions page
kartographer Feb 15, 2025
784839d
Fixing up doc strings
kartographer Feb 15, 2025
76fa186
Fixing bug in convert_to_slices discoverd in external testing
kartographer Feb 15, 2025
f89734d
More _convert_to_slices clean-up and testing
kartographer Feb 15, 2025
b3936f9
First pass at CHANGELOG
kartographer Feb 15, 2025
635f5f9
fix Sphinx errors bad formatting
bhazelton Feb 17, 2025
0ccffc9
Adding polcal test file for MSCal
kartographer Feb 17, 2025
58223da
Adding MS tcal file (T Jones) for testing
kartographer Feb 17, 2025
fea9f25
Adding support for cross-jones terms in MSCal
kartographer Feb 17, 2025
4640910
Small fixes to address failing tests
kartographer Feb 17, 2025
a104d4d
Making updates to docs in response to reviewer comments
kartographer Feb 17, 2025
6dfde4b
One more attempted fix to failing tests...
kartographer Feb 17, 2025
1ff22fd
Putting in small check for UVData feed info setting in uvcalibrate
kartographer Feb 17, 2025
04fe14f
Adding pol_convention to conventions doc
kartographer Feb 18, 2025
3639ad2
Fix sphinx formatting
bhazelton Feb 18, 2025
bf1d1af
Updating beams with feed_array (and x_orientation deprecation)
kartographer Mar 2, 2025
2604328
Fixing failure in min_versions tests
kartographer Mar 2, 2025
0167b0f
Updating tutorial for UVBeam
kartographer Mar 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file.
## [Unreleased]

### Added
- Handling for MeasurementSet calibration subtypes "T Jones" (non-pol-specific antenna
gains) and "D Jones" (polarization leakages) has been added to `MSCal`.
- A new page to the docs labeled "Conventions" has been added.
- The `Telescope.x_orientation` parameter has been deprecated, superseded by two new
parameters: `Telescope.feed_array` and `Telescope.feed_angle`, which describe the
polarization and orientation of the detectors for a given antenna.
- The `Telescope.mount_type` parameter has been added, which describes the mount and
optics of a given antenna (e.g., HERA/MWA are "fixed", VLA/ALMA are "alt-az").
- The `Telescope.get_x_orientation_from_feeds` method has been added, which returns
a string (either "east" or "north") based on values present in `Telescope.feed_array`
and `Telescope.feed_angle` (mimicking the behavior of getting the now-defunct
`Telescope.x_orientation` parameter).
- The `Telescope.set_feeds_from_x_orientation` method has been added, which sets
values in `Telescope.feed_array` and `Telescope.feed_angle` based on a string describing
the x-orientation (mimicking the behavior of setting the now-defunct
`Telescope.x_orientation` parameter).
- New `strict` keyword added to `UVData.select`, `UVBeam.select`, `UVFlag.select`, and
`UVFlag.select`, which allows the user to specify whether to warn or error when
supplied criteria only partially match (default being to warn).
Expand All @@ -21,6 +37,7 @@ default is `True`), such that most warnings about frequency/polarization/time sp
will not normally be raised.

### Changed
- Flex-jones `UVCal` objects now recorded to MeasurementSet format as "T Jones" subtype.
- `UVData.select`, `UVBeam.select`, `UVFlag.select`, `UVFlag.select` have been
significantly refactored and made to behave more uniformly.
- Allowing `UVParameter.__eq__` to use `UVParameter.compare_value` if the item being
Expand All @@ -29,6 +46,8 @@ compared and `UVParameter.value` share the same class.
and `UVBeam.check`.

### Fixed
- Bug in `utils.tools._convert_to_slices` where reverse-ordered slices (i.e., where
the step was negative) where not correctly handled.
- Bug in `UVBeam.select` where `polarization_array` could be incorrectly ordered after
selection (if input to `polarizations` keyword was unordered).

Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
("MWA FITS", "params_style"),
("MIR", "params_style"),
("CalH5", "params_style"),
("MSCal", "params_style"),
]

# Add any paths that contain templates here, relative to this directory.
Expand Down
167 changes: 167 additions & 0 deletions docs/conventions.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
Conventions
==============
Documentation for various conventions that are used or otherwise assumed within
pyuvdata objects and methods.


Baseline conjugation and *uvw*-direction
----------------------------------------
Because of the Hermitian nature of the *uv*-plane (arising from the fact that images of
the sky should contain no imaginary components), a single visibility at a given
(*u*, *v*, *w*) coordinate is simply the complex conjugate of the visibility at
(-*u*, -*v*, -*w*). Because the two values are highly redundant, most file formats and
software packages expect that only one of these values to be recorded, saving a factor
of two in memory usage and disk space in the processes. But which member of the pair
is stored depends on the file-format and/or software package.

There are two two standard conventions for this. The first is *ant2-ant1*, where a
given visibility :math:`\mathcal{V}` is calculated by taking the complex conjugate of
the data from the first antenna multiplied against the data from the second (i.e.,
:math:`\mathcal{V}_{12}=\langle V^{*}_1 V_{2} \rangle`), in which case the
*uvw*-coordinate is calculated by taking the position of the second antenna minus
the position of the first (after which various rotations are applied). The second is
*ant1-ant2*, where :math:`\mathcal{V}_{12}=\langle V_{1} V_{2}^{*} \rangle`, and the
*uvw*-coordinate is calculated by taking the position of the first antenna minus
the second. The pyuvdata software package uses the *ant2-ant1* convention (as does
MIRIAD; with UVFITS, MeasurementSet, FHD, and Mir formats use the opposite convention).

Phase Center Types
------------------
Several different pyuvdata classes have support for (and in the case of ``UVData``,
in fact require) handling information about the "phase center" of the telescope, which
records the position in the sky for which geometric delays of the interferometer have
been compensated for (and, if imaging, where the center of the field-of-view will
appear). There is support for four different "phase types", each of one which is
discussed further below:

- ``"sidereal"``: A sidereal phase center is one whose position remains (relatively)
static in a celestial frame, such as ICRS or FK5/J2000. Sidereal sources are
permitted to have both proper motion and parallax (the former of which is
calculated relative to the epoch date provided for the phase center), but otherwise
is assumed that it can be described by a single coordinate pair.
- ``"ephem"``: An ephem phase center is one whose position varies with time within
a celestial frame, and whose exact position requires an ephemeris (which can be
interpolated to provide exact position information for phasing).
- ``"driftscan"``: A driftscan phase center is similar to a sidereal one, except that
the phase center is assumed to be static within the observer frame, and therefore
desribed by a single pair of horizontal coordinates (i..e, azimuth and elevation).
- ``"unprojected"``: An unprojected phase center is a bit of an oxymoron, in that it
denotes when no phasing has been applied (and therefore no phase center exists). In
this context, geometric delays are *not* compensated for, but *uvw*-coordinates
are calculated with respect to zenith for a given telescope.

Polarization Normalization
--------------------------
For an unpolarized source, a single-polarization receiver will typically detect half of
the Stokes I emission (e.g., an "xx"-polarization feed will physically detect 0.5 Jy of
a 1 Jy unpolarized point source). However, several software packages (including CASA and
MIRIAD) normalize to account for thus and double this quantity, such that a
single-polarization baseline is expressed as a Stokes I equivalent (e.g., an "xx"
baseline will show 1 Jy of flux for a 1 Jy unpolarized point source).

As mixing the two conventions can result in data having a factor of two error in
amplitude, both ``UVCal`` and ``UVData`` objects have the parameter ``pol_convention``,
which denotes the normalization behavior. The two supported options are ``"sum"``, where
Stokes I is the sum of fluxes measured on the XX and YY baselines for a linear
polarization system (i.e., I = XX + YY), or RR and LL baselines for a circular system;
and ``"mean"``, where Stokes I is the mean of the XX/YY or RR/LL baselines
(i.e, I = (XX + YY) / 2).

Feed angles and x-orientation
-----------------------------
As part of the ``Telescope`` object, one can specify ``Telescope.feed_type`` to specify
the handedness that a single-polarization receiver/input sees, which includes options
for both linear polarization receivers (``"x"`` and ``"y"``) and circular polarization
receivers (``"l"`` and ``"r"``). However, how individual feeds are oriented can impact
which polarization of light they see. A case in point: "x" and "y" polarizations through
a simple 90-degree rotation of the detector can either see vertically or horizontally
polarized light from the perspective of the observer. While this ambiguity is apparent
with linear feeds, it impacts measurements from circular feeds as well -- what is
ascribed to Stokes parameters Q and U (and correspondingly, the polarization angle
of a given source) can be modulated based on the orientation of the feeds.

To account for this potential ambiguity, there also exists a ``Telescope.feed_angle``
parameter, which is recorded in units of radians and preserves the orientation
information of the feeds. How this maps to polarization on sky depends on a few
different parameters (see the discussion about ``Telescope.mount_type`` below), but
to provide a few examples:

- For a Cassegrain antenna on an Alt-Az mount (like VLA), a 0 degree feed angle is in
the direction of zenith.

- For a "fixed" antenna that points at zenith (like HERA), a 0 degree feed angle points
in the direction of north.

In the absence of any information about the antenna mount, within pyuvdata a 0 degree
feed angle is one where the polarization response is aligned with the direction of
zenith for steerable antennas, otherwise toward north for stationary antennas. This is
equivalent to setting the now-defunct parameter ``Telescope.x_orientation`` to
``"north"`` when handling the x-polarization or ``"east"`` when handling the
y-polarization.

Feed angles are provided on a per-polarization basis, even if a given feed may be
dual-polarization. Nominally, feed angles for linearly polarized feeds should be
separated by 90 degrees (i.e., if ``Telescope.feed_array`` is ``[["x", "y"]]``, then
one might expect ``Telescope.feed_angle`` to be ``[[np.pi / 2, 0]]`` where the
"x-orientation" is pointing toward the east).

Telescope Mount Types
---------------------
As part of the ``Telescope`` object, one can specify ``Telescope.mount_type``, which
records information about the optics of the antenna. The telescope optics can impact
data in multiple ways, though we focus our discussion here on its impact for polarimetric
measurements, since a "static" single-polarization receiver can be sensitive to
differing polarizations of light (depending on the optics type and where the source is
in the sky from the persepctive of the observer).


One good reference that covers several of the mount types listed below is
`Dodson and Rioja (2022) <https://arxiv.org/abs/2210.13381>`_, as well as the
`Wikipedia page on telescope mounts <https://en.wikipedia.org/wiki/Telescope_mount>`_
(as well as the page on `Nasmyth telescopes <https://en.wikipedia.org/wiki/Nasmyth_telescope>`_).
We limit our focus here to those mount types presently supported in pyuvdata, which
include:

- ``"alt-az"``: Arguably the most common form of antenna mount, where the two axes of
rotation rotate in azimuth and elevation (i.e., "altitude"), and "up" from the
perspective of the receiver points toward zenith. For a mount of this type, a feed
angle of 0 degrees is aligned with the parallactic angle at the given position of
the sky.
- ``"equatorial"``: Similar to "alt-az", but where one axis of rotation is aligned
to the celestial equatorial plane (i.e., where the declination is zero), such that
the two axes of rotation are aligned to the right ascension/hour angle and
declination axes. For a mount of this type, a feed angle of 0 degrees is aligned
with north on the (apparent) celestial sphere.
- ``"orbiting"``: Denotes that the antenna is in orbit, such that the orientation of
the antenna changes with time. This mode appears to have been added to UVFITS to
support the `VLBI Space Observatory Programme <https://en.wikipedia.org/wiki/HALCA>`_.
pyuvdata does not currently support additional orbital parameters.
- ``"x-y"``: A mount type that is somewhat prevalent for tracking of LEO and MEO
satellites due to its ability to `track more easily through zenith than "alt-az"
mounts <https://ntrs.nasa.gov/api/citations/19650021134/downloads/19650021134.pdf>`_,
this has one rotation axis aligned to local north-south, and the other lies in the
plane of the great circle connecting local east-west through zenith. For this mount
type, a feed angle of 0 degrees varies with sky position, aligned to
:math:`\arctan(\cos(\textrm{HA}) / (\sin(\textrm{HA}) * \sin(\delta)))`,
where :math:`\delta` is the declination of the source and HA the hour angle.
- ``"alt-az+nasmyth-r"``: Similar to "alt-az", with the addition of a flat tertiary
mirror that allows the detector to sit at a fixed elevation while the antenna primary
moves up and down in elevation. For this "right-handed" Nasmyth variant, a feed angle
of 0 degrees will be aligned to sum of the parallactic and elevation angles.
- ``"alt-az+nasmyth-l"``: The "left-handed" variant of the Nasmyth mount, where a
feed angle of 0 degrees is aigned to the **difference** of the parallactic and
elevation angles.
- ``"phased"``: Denotes an instrument where the an individual antenna input is
a phased array of detectors that are "beamformed" into a single voltage stream
(otherwise sometimes referred to as "electronically steered"). For this mount, a
0-degree feed angle is aligned/parallel to the direction of local north. Note
while supported in UVFITS, it is a later addition to the format, and may be grouped
into "other" in some software packages.
- ``"fixed"``: Similar to "phased", expect where there is neither mechanical or
electical steering of the antenna, and thus the beam remains fixed in the
azimuth-elevation frame. In this frame, a feed angle of 0 degrees is aligned/
parallel to the direction of local north. Note that this is a pyuvdata-defined mount
type, and does not necessarily have a corresponding entry in, for example, UVFITS.
- ``"other"`` While nominally a pyuvdata-defined mount type, UVFITS and CASA both
allow for the designation of "bizarre" mount-types, which for all intents and purposes
denotes the same lack of knowledge of underlying optics behavior.
1 change: 1 addition & 0 deletions docs/make_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ def write_index_rst(readme_file=None, write_file=None):
".. toctree::\n"
" :maxdepth: 1\n\n"
" tutorial\n"
" conventions\n"
" uvdata\n"
" uvcal\n"
" uvbeam\n"
Expand Down
26 changes: 17 additions & 9 deletions docs/uvbeam_tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ of creating a consistent object from a minimal set of inputs
... data_normalization="physical",
... freq_array=np.linspace(100e6, 200e6, 10),
... x_orientation = "east",
... feed_array = ["e", "n"],
... feed_array = ["x", "y"],
... axis1_array=np.deg2rad(np.linspace(-180, 179, 360)),
... axis2_array=np.deg2rad(np.linspace(0, 90, 181)),
... )
Expand Down Expand Up @@ -301,15 +301,15 @@ a) Selecting a range of Zenith Angles

a) Selecting Feeds or Polarizations
***********************************
Selecting feeds on E-field beams can be done using the feed name (e.g. "x" or "y"). If
``x_orientation`` is set on the object, strings represting the physical orientation of
the feed can also be used (e.g. "n" or "e).
Selecting feeds on E-field beams can be done using the feed name (e.g. "x" or "y").
Strings representing the physical orientation of the feed (e.g. "n" or "e) can also
be used if the feeds are oriented toward 0 or 90 degrees (as denoted by ``feed_angle``).

Selecting polarizations on power beams can be done either using the polarization
numbers or the polarization strings (e.g. "xx" or "yy" for linear polarizations or
"rr" or "ll" for circular polarizations). If ``x_orientation`` is set on the object,
strings represting the physical orientation of the dipole can also be used (e.g. "nn"
or "ee).
"rr" or "ll" for circular polarizations). Strings representing the physical orientation
of the feed (e.g. "nn" or "ee") can also be used if the feeds are oriented toward 0 or
90 degrees (as denoted by ``feed_angle``).

.. code-block:: python

Expand All @@ -331,8 +331,12 @@ or "ee).
>>> print(uvb2.feed_array)
['y']

>>> # check the feed_angle
>>> print(uvb2.feed_angle)
[0.]

>>> # check the x_orientation
>>> print(uvb.x_orientation)
>>> print(uvb.get_x_orientation_from_feeds())
east

>>> # make a copy and select a feed by phyiscal orientation
Expand Down Expand Up @@ -375,8 +379,12 @@ or "ee).
>>> print(utils.polnum2str(uvb.polarization_array))
['xx', 'yy']

>>> # print feed_angle
>>> print(uvb.feed_angle)
[1.57079633 0. ]

>>> # print x_orientation
>>> print(uvb.x_orientation)
>>> print(uvb.get_x_orientation_from_feeds())
east

>>> # select polarizations using the physical orientation strings
Expand Down
9 changes: 6 additions & 3 deletions docs/uvcal_tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -493,8 +493,11 @@ d) Select Jones components
**************************
Selecting on Jones component can be done either using the component numbers or
the component strings (e.g. "Jxx" or "Jyy" for linear polarizations or "Jrr" or
"Jll" for circular polarizations). If ``telescope.x_orientation`` is set, strings
represting the physical orientation of the dipole can also be used (e.g. "Jnn" or "ee).
"Jll" for circular polarizations). Under special circumstances, where x-polarization
feeds (as recorded in ``telescope.feed_array``) are aligned to 0 or 90 degrees relative
to a line perpendicular to the horizon (as record in ``telescope.feed_angle``) and/or
y-polarization are aligned to -90 or 0 degrees, strings representing the cardinal
orientation of the dipole can also be used (e.g. "Jnn" or "ee").

.. code-block:: python

Expand Down Expand Up @@ -535,7 +538,7 @@ represting the physical orientation of the dipole can also be used (e.g. "Jnn" o
['Jxx']

>>> # print x_orientation
>>> print(cal.telescope.x_orientation)
>>> print(cal.telescope.get_x_orientation_from_feeds())
east

>>> # make a copy of the object and select Jones components using the physical orientation strings
Expand Down
11 changes: 7 additions & 4 deletions docs/uvdata_tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1089,8 +1089,11 @@ e) Select polarizations
***********************
Selecting on polarizations can be done either using the polarization numbers or the
polarization strings (e.g. "xx" or "yy" for linear polarizations or "rr" or "ll" for
circular polarizations). If ``telescope.x_orientation`` is set, strings representing
the physical orientation of the dipole can also be used (e.g. "nn" or "ee).
circular polarizations). Under special circumstances, where x-polarization feeds
(as recorded in ``telescope.feed_array``) are aligned to 0 or 90 degrees relative to a
line perpendicular to the horizon (as record in ``telescope.feed_angle``) and/or
y-polarization are aligned to -90 or 0 degrees, strings representing the cardinal
orientation of the dipole can also be used (e.g. "nn" or "ee").

.. code-block:: python

Expand Down Expand Up @@ -1149,8 +1152,8 @@ the physical orientation of the dipole can also be used (e.g. "nn" or "ee).
['xx', 'yy']

>>> # print x_orientation
>>> print(uvd.telescope.x_orientation)
NORTH
>>> print(uvd.telescope.get_x_orientation_from_feeds())
north

>>> # select polarizations using the physical orientation strings
>>> uvd.select(polarizations=["ee"])
Expand Down
Loading
Loading