Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 16 additions & 1 deletion episodes/02-coords.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ perpendicular to the direction of the stream (the y-axis in Figure 1).
These are called the $\phi_1$ and $\phi_2$ coordinates, respectively.

```python
from gala.coordinates import GD1Koposov10
from gd1 import GD1Koposov10

gd1_frame = GD1Koposov10()
gd1_frame
Expand All @@ -405,6 +405,21 @@ gd1_frame
<GD1Koposov10 Frame>
```

::::::::::::::::::::::::::::::::::::::::: callout

## GD1Koposov10 import

The `GD1Koposov10` reference frame is part of the `gala` package. For convience we provide
the stand alone file as part of the `student_download` zip file you downloaded. If your notebook
is not in your `student_download` directory, you will need to add the following before the import
statement
```python
import sys
sys.path.append(<path to student_download>)
```
Where `<path to student_download>` is the path to your `student_download` directory ending with `student_download`.
::::::::::::::::::::::::::::::::::::::::::::::::::

We can use it to find the coordinates of Betelgeuse in the GD-1 frame,
like this:

Expand Down
13 changes: 9 additions & 4 deletions episodes/03-transform.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,21 @@ Whether you are working from a new notebook or coming back from a checkpoint,
reloading the data will save you from having to run the query again.

If you are starting this episode here or starting this episode in a new notebook,
you will need to run the following lines of code.
you will need to run the following lines of code. The last two lines of the import
statements assume your notebook is being run in the `student_download` directory.
If you are running it from a different directory you will need to add the path using
`sys.path.append(<path to student download>)` where `<path to student_download>` is
the path to your `student_download` directory ending with `student_download`.

This imports previously imported functions:

```python
import astropy.units as u
from astropy.coordinates import SkyCoord
from gala.coordinates import GD1Koposov10
from astropy.table import Table

from episode_functions import *
from gd1 import GD1Koposov10
```

The following code loads in the data (instructions for downloading data can be
Expand Down Expand Up @@ -430,10 +434,11 @@ That might seem like a strange thing to do, but here is the motivation:
With this preparation, we can use `reflex_correct` from Gala
([documentation
here](https://gala-astro.readthedocs.io/en/latest/api/gala.coordinates.reflex_correct.html))
to correct for the motion of the solar system.
to correct for the motion of the solar system which we have included as a stand alone file
in the `student_download`.

```python
from gala.coordinates import reflex_correct
from reflex import reflex_correct

skycoord_gd1 = reflex_correct(transformed)
```
Expand Down
9 changes: 8 additions & 1 deletion episodes/05-select.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,12 @@ Whether you are working from a new notebook or coming back from a checkpoint,
reloading the data will save you from having to run the query again.

If you are starting this episode here or starting this episode in a new notebook,
you will need to run the following lines of code.
you will need to run the following lines of code. The last two lines of the import
statements assume your notebook is being run in the `student_download` directory.
If you are running it from a different directory you will need to add the path using
`sys.path.append(<path to student download>)` where `<path to student_download>` is
the path to your `student_download` directory ending with `student_download`.


This imports previously imported functions:

Expand All @@ -77,6 +82,8 @@ import matplotlib.pyplot as plt
import pandas as pd

from episode_functions import *
from gd1 import GD1Koposov10
from reflex import reflex_correct
```

The following code loads in the data (instructions for downloading data can be
Expand Down
3 changes: 2 additions & 1 deletion student_download/episode_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

import astropy.units as u
from astropy.coordinates import SkyCoord
from gala.coordinates import GD1Koposov10, reflex_correct
from gd1 import GD1Koposov10
from reflex import reflex_correct

##########################
# Episode 2
Expand Down
96 changes: 96 additions & 0 deletions student_download/gd1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""Astropy coordinate class for the GD-1 coordinate system"""

import astropy.coordinates as coord
import astropy.units as u
import numpy as np
from astropy.coordinates import frame_transform_graph

__all__ = ["GD1Koposov10"]


class GD1Koposov10(coord.BaseCoordinateFrame):
"""
A Heliocentric spherical coordinate system defined by the orbit of the GD1 stream,
as described in Koposov et al. 2010 (see: `<http://arxiv.org/abs/0907.1085>`_).

For more information about this class, see the Astropy documentation on coordinate
frames in :mod:`~astropy.coordinates`.

Parameters
----------
representation : :class:`~astropy.coordinates.BaseRepresentation` or None
A representation object or None to have no data (or use the other keywords)
phi1 : angle_like, optional, must be keyword
The longitude-like angle corresponding to GD-1's orbit.
phi2 : angle_like, optional, must be keyword
The latitude-like angle corresponding to GD-1's orbit.
distance : :class:`~astropy.units.Quantity`, optional, must be keyword
The Distance for this object along the line-of-sight.
pm_phi1_cosphi2 : :class:`~astropy.units.Quantity`, optional, must be keyword
The proper motion in the longitude-like direction corresponding to
the GD-1 stream's orbit.
pm_phi2 : :class:`~astropy.units.Quantity`, optional, must be keyword
The proper motion in the latitude-like direction perpendicular to the
GD-1 stream's orbit.
radial_velocity : :class:`~astropy.units.Quantity`, optional, must be keyword
The radial velocity for this object along the line-of-sight.

"""

default_representation = coord.SphericalRepresentation
default_differential = coord.SphericalCosLatDifferential

frame_specific_representation_info = {
coord.SphericalRepresentation: [
coord.RepresentationMapping("lon", "phi1"),
coord.RepresentationMapping("lat", "phi2"),
coord.RepresentationMapping("distance", "distance"),
],
}

_default_wrap_angle = 180 * u.deg

def __init__(self, *args, **kwargs):
wrap = kwargs.pop("wrap_longitude", True)
super().__init__(*args, **kwargs)
if wrap and isinstance(
self._data,
coord.UnitSphericalRepresentation | coord.SphericalRepresentation,
):
self._data.lon.wrap_angle = self._default_wrap_angle

# TODO: remove this. This is a hack required as of astropy v3.1 in order
# to have the longitude components wrap at the desired angle
def represent_as(self, base, s="base", in_frame_units=False):
r = super().represent_as(base, s=s, in_frame_units=in_frame_units)
if hasattr(r, "lon"):
r.lon.wrap_angle = self._default_wrap_angle
return r

represent_as.__doc__ = coord.BaseCoordinateFrame.represent_as.__doc__


# Rotation matrix as defined in the Appendix of Koposov et al. (2010)
R = np.array(
[
[-0.4776303088, -0.1738432154, 0.8611897727],
[0.510844589, -0.8524449229, 0.111245042],
[0.7147776536, 0.4930681392, 0.4959603976],
]
)


@frame_transform_graph.transform(coord.StaticMatrixTransform, coord.ICRS, GD1Koposov10)
def icrs_to_gd1():
"""
Compute the transformation from ICRS spherical to heliocentric GD-1 coordinates.
"""
return R


@frame_transform_graph.transform(coord.StaticMatrixTransform, GD1Koposov10, coord.ICRS)
def gd1_to_icrs():
"""
Compute the transformation from heliocentric GD-1 coordinates to ICRS spherical.
"""
return icrs_to_gd1().T
43 changes: 43 additions & 0 deletions student_download/reflex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import astropy.coordinates as coord

__all__ = ["reflex_correct"]


def reflex_correct(coords, galactocentric_frame=None):
"""Correct the input Astropy coordinate object for solar reflex motion.

The input coordinate instance must have distance and radial velocity information.
So, if the radial velocity is not known, fill the radial velocity values with zeros
to reflex-correct the proper motions.

Parameters
----------
coords : `~astropy.coordinates.SkyCoord`
The Astropy coordinate object with position and velocity information.
galactocentric_frame : `~astropy.coordinates.Galactocentric` (optional)
To change properties of the Galactocentric frame, like the height of the
sun above the midplane, or the velocity of the sun in a Galactocentric
intertial frame, set arguments of the
`~astropy.coordinates.Galactocentric` object and pass in to this
function with your coordinates.

Returns
-------
coords : `~astropy.coordinates.SkyCoord`
The coordinates in the same frame as input, but with solar motion
removed.

"""
c = coord.SkyCoord(coords)

# If not specified, use the Astropy default Galactocentric frame
if galactocentric_frame is None:
galactocentric_frame = coord.Galactocentric()

v_sun = galactocentric_frame.galcen_v_sun

observed = c.transform_to(galactocentric_frame)
rep = observed.cartesian.without_differentials()
rep = rep.with_differentials(observed.cartesian.differentials["s"] + v_sun)
fr = galactocentric_frame.realize_frame(rep).transform_to(c.frame)
return coord.SkyCoord(fr)
28 changes: 6 additions & 22 deletions student_download/test_setup.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -195,31 +195,15 @@
"metadata": {},
"outputs": [],
"source": [
"import gala.coordinates as gc"
"from gd1 import GD1Koposov10\n",
"from reflex import reflex_correct"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Created TAP+ (v20200428.1) - Connection:\n",
"\tHost: gea.esac.esa.int\n",
"\tUse HTTPS: True\n",
"\tPort: 443\n",
"\tSSL Port: 443\n",
"Created TAP+ (v20200428.1) - Connection:\n",
"\tHost: gea.esac.esa.int\n",
"\tUse HTTPS: True\n",
"\tPort: 443\n",
"\tSSL Port: 443\n"
]
}
],
"outputs": [],
"source": [
"# Note: running this import statement opens a connection\n",
"# to a Gaia server, so it will fail if you are not connected\n",
Expand Down Expand Up @@ -258,9 +242,9 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python (AstronomicalData)",
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "astronomicaldata"
"name": "python3"
},
"language_info": {
"codemirror_mode": {
Expand All @@ -272,7 +256,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
"version": "3.9.17"
}
},
"nbformat": 4,
Expand Down