In this section we will review some of the concepts seen in the introduction, such as units, coordinate systems, etc. and work some tutorials in Python
This is not intended to be a complete course on programing in python .The idea is mor to put python in the context of astro-article physics, and address some of the questions seen in the following tutorials.
Working with units
In this first case or tutorial we are going to show a n example of how to work with units using the module units that exist for example in astropy
import astropy.units as ufrom astropy import constants as constM_Earth =5.97E24* u.kgM_Sun =1.99E30* u.kgM_MW=1E12* M_Sun#By adding the quantity u.kg you can print directly the mass in Kgprint ("Mass Earth is: %s"%M_Earth)
Mass Earth is: 5.97e+24 kg
There are many other modules in python that have the units utility
Note that the variables defined above already have their units attached to them, so when you make a print statement it will provide as well the units as a string. That's the reason of the %s format. More examples:
With the radius we can calculate the mean density of Earth and the Sun. We will show that units are preserved along calculations:
from numpy import pivol_sphere =lambdar:4*pi/3*r**3rho_Sun = M_Sun /vol_sphere(R_Sun)rho_Earth = M_Earth /vol_sphere(R_Earth)#A unit can be changed calling the .to(u.unit) methodprint ("Density of Earth: %s"%(rho_Earth.to(u.g/u.cm**3)))print ("Density of Sun: %s"%rho_Sun)
Density of Earth: 5.51141236929 g / cm3 Density of Sun: 1412.12474755 kg / m3
We can use this module to make different transformations of units, for example from light years to meters:
Assuming that the Galaxy is roughly a disk 50 kpc in diameter and 500 pc thick we can now calculate its density:
Exercise: How long does the light travel from the Sun to the Earth in minutes? How long does the light travel from the Galactic center (assume a distance of 8 kpc) in years?
Coordinates
The coordinates package of astropy provides classes for representing a variety of celestial/spatial coordinates and their velocity components, as well as tools for converting between common coordinate systems in a uniform way. The simplest way to use coordinates is to use the SkyCoord class. SkyCoord objects are instantiated by passing in positions (and optional velocities) with specified units and a coordinate frame.
With SkyCoord you can handle more than one set of coordinates:
You can use from_name method of SkyCoord to retrieve the coordinates of known sources. It uses Sesame (http://cds.u-strasbg.fr/cgi-bin/Sesame) to retrieve coordinates for a particular named object:
Exercise: Define the sky coordinate for your favorite object and find the distance to the crab nebula and Galactic center.
Let's create a simple table with three columns of data named a, b, and c. These columns have integer, float, and string values respectively:
To check which columns are available you can use Table.colnames:
And access individual columns just by their name:
And also a subset of columns:
Rows can be accessed using numpy indexing:
Or by using a boolean numpy array for indexing:
Astropy tables can be serialized into many formats. Some examples below:
To sort the table by column 'a':
🖋️Exercise: The (Lon, Lat) positions of Crab, Sagittarius A* and Cassiopeia A in the Galactic Coordinate system are:
(184.55754381,-5.78427369) Crab
(359.94422947,-0.04615714) Sag A*
(111.74169477,-2.13544151) Cas A
Put in a Table the positions (with the first two columns for Lon, Lat) of the three objects (rows), and add two columns with the RA and DEC coordinates of the objects
The Astroquery package
Another package that allows one to retrieve information from astronomy databases for further processing is astroquery. It can query in different databases (SIMBAD , SDSS). You can import this package to explore the SDSS database by inserting the following line at the top of your script:
🖋️Exercise: Using the astroquery.sdss imported above, call the function query_region to get the following output [’ra’, ’dec’, ’u’, ’g’, ’r’, ’i’, ’z’, ’type’] in 1 arc minutes around ’pos’. Call this output ’xid’. Hint: To specify the output, use the option photoobj_fields If you check the type of this output, you see that it is of type Table.
Select only sources that are identified as galaxies and put them in a table called ’galaxy_table’
Select stars and put them in ’a table called ’stars_table’
Now let's do a little tutorial. We are going to work. Let's do some "representation" of the galactic plane. We generate some random points using numpy following a 2-dimensional gaussian in the ℓ: −π,+π and b:−π/2,+π/2 space. Now we are going to use matplotlib to make plots. If you are using jupyter notebook, don't forget to use the magic command %matplotlib inline if you want to make the plots appear inline inside the notebook:
Toy representation of the galactic plane in galactic coordinates
Now let's plot it in equatorial coordinates (right ascension, declination). Because matplotlib needs the coordinates in radians and between −π and π, not between 0 and 2π, we have to convert them.
Toy representation of the galactic plane in galactic coordinates
Usually right ascension is plotted from right (0°) to left (360°), but it can also be expressed in hours (1 hr = 15°).
Calculating the Age of the Universe
We are going to use python to numerically solve the look-back time for any given set of cosmological parameters. For that we are going to rewrite the loopback formula in terms of the scale factor $a$ since we have the redshift scale relation:
(1+z)=a1
we can prove thatL
1+zdz=−ada
dt=H(a)ada
with
H2(a)=H02[ΩM0a−3+Ωr0a−4+Ωk0a−2+ΩΛ0]
First we are going to use the astropy.cosmology module to retrieve the values of the cosmological constants using Planck data from 2013.
ly = 1 * u.lyr
print ("Number of seconds for light to travel from Sun to Earth:", 1./const.c.to(u.AU/u.s))
print ("Meters in a light year: %s", ly.to(u.m))
Number of seconds for light to travel from Sun to Earth: 499.004783836 s / AU
Meters in a light year: 9.46073047258e+15 m
V_Gal = pi * (25000*u.pc)**2 * 500*u.pc
print "Volume of the Milky Way is approximately: %s " % V_Gal.to(u.m**3)
M_Gal = 1E12 * M_Sun
rho_Gal = M_Gal / V_Gal
print "Average density of Milky Way is %s" % rho_Gal.to(u.g/u.cm**3)
Volume of the Milky Way is approximately: 2.88437372034e+61 m3
Average density of Milky Way is 6.89924466433e-23 g / cm3
from astropy import units as u
from astropy.coordinates import SkyCoord
c = SkyCoord(ra=10.625*u.degree, dec=41.2*u.degree, frame='icrs')
print(c)
print("ra = {:.2f}, {:.2f} rad".format(c.ra,c.ra.radian))
print("dec = {:.2f}, {:.2f} rad".format(c.dec,c.dec.radian))
from astroquery.sdss import SDSS
from astroquery.simbad import Simbad
%matplotlib inline
#We call random.multivariate_normal
#to generate randon normal points at 0
import numpy as np
#import matplotlib for plots
import matplotlib.pylab as plt
#Lets use the inline figure format as svg
%config InlineBackend.figure_format = 'svg'
plt.style.use("seaborn-poster")
disk = np.random.multivariate_normal(mean=[0,0],
cov=np.diag([1,0.001]), size=5000)
#disk is a list of pairs [l, b] in radians
f = plt.figure(figsize=(9,7))
ax = plt.subplot(111, projection='aitoff')
#There are several projections: Aitoff, Hammer, Lambert,
#MollWeide
ax.set_title("Galactic\n Coordinates")
ax.grid(True)
ll = disk[:,0]
bb = disk[:,1]
ax.plot(ll, bb, 'o', markersize=2, alpha=0.3)
plt.show()
from astropy import units as u
from astropy.coordinates import SkyCoord
c_gal = SkyCoord(l=ll*u.radian, b=bb*u.radian, frame='galactic')
c_gal_icrs = c_gal.icrs
ra_rad = c_gal_icrs.ra.wrap_at(180 * u.deg).radian
dec_rad = c_gal_icrs.dec.radian
plt.figure(figsize=(9,7))
ax = plt.subplot(111, projection="mollweide")
ax.set_title("Equatorial coordinates")
plt.grid(True)
ax.plot(ra_rad, dec_rad, 'o', markersize=2, alpha=0.3)
plt.show()
import scipy.integrate as integrate
def calculate_times(omega_m, omega_lambda):
#Lets check if there is a maximal, ie, if H^2(a) = 0
astep = 0.001
scales = np.arange(0.1, 3, astep)
amax = 1e9
for a in scales:
if( friedman(a, omega_M, omega_lambda) < 0):
amax = a
scales = np.arange(0.1, 2*amax, 0.01) #we go from a = 0 to a= 2*amax
print ("Found a-max in %.2f" %amax)
break
#time at a = a_max
tmax = integrate.quad(lambda x: 1/x * 1/np.sqrt(friedman(x,omega_m, omega_lambda)), 0, amax - astep)[0]
#time today a = 1
t0 = integrate.quad(lambda x: 1/x * 1/np.sqrt(friedman(x,omega_m, omega_lambda)), 0, 1)[0]
#Empty x,y for the plots
times = []
scale = []
for a in scales:
if a < amax: #If a < amax we do the typical integral 0 -> a
time = integrate.quad(lambda x: 1/x * 1/np.sqrt(friedman(x,omega_m, omega_lambda)), 0, a)[0]
times.append(H0*(time - t0)) #We calibrate at -t0 to place all curves together
scfrom IPython.core.display import HTML
if a >= amax: #If a > amax we are out the domain we integrate backwards
time = 2*tmax - integrate.quad(lambda x: 1/x * 1/np.sqrt(friedman(x,omega_m, omega_lambda)), 0, 2*amax -a)[0]
times.append(H0*(time - t0))
scale.append(2*amax - a)
return np.array(times), np.array(scale)