5. Querying from the Catalog#

If WCS(World Coordinate System: converts image XY pixel to, e.g., RA/DEC. See slides 4-7 of this, for example) is properly implemented, we should be able to find stars in the image automatically.

astroquery is an astropy-affiliated python package for such query.

Here I will demonstrate how to query Pan-STARRS DR2 and Gaia catalog, which are two of the widely used catalogs as of 2023.

And in the later part, I will show how to use JPL HORIZONS, that is used for querying the ephemerides (positional information of celestial objects) of solar system objects.

%load_ext version_information
import time
now = time.strftime("%Y-%m-%d %H:%M:%S (%Z = GMT%z)")
print(f"This notebook was generated at {now} ")

vv = %version_information astropy, numpy, scipy, matplotlib, astroquery, photutils, version_information
for i, pkg in enumerate(vv.packages):
    print(f"{i} {pkg[0]:10s} {pkg[1]:s}")
This notebook was generated at 2023-05-09 15:36:36 (KST = GMT+0900) 
0 Python     3.10.10 64bit [Clang 14.0.6 ]
1 IPython    8.13.2
2 OS         macOS 13.1 arm64 arm 64bit
3 astropy    5.2.2
4 numpy      1.24.3
5 scipy      1.10.1
6 matplotlib 3.7.1
7 astroquery 0.4.7.dev8597
8 photutils  1.6.0
9 version_information 1.0.4
# %matplotlib notebook
from IPython.core.interactiveshell import InteractiveShell
from IPython import get_ipython
%config InlineBackend.figure_format = 'retina'
InteractiveShell.ast_node_interactivity = 'last_expr'
ipython = get_ipython()

from pathlib import Path

import numpy as np

from astropy import units as u
from astropy.nddata import CCDData
from astropy.coordinates import SkyCoord
from astropy.time import Time

from astroquery.gaia import Gaia
from astroquery.mast import Catalogs
from astroquery.jplhorizons import Horizons
Gaia.ROW_LIMIT = -1  # no limit

from matplotlib import pyplot as plt
from matplotlib import rcParams
plt.style.use('default')
rcParams.update({'font.size':12})

from photutils.aperture import (CircularAperture, CircularAnnulus, 
                                aperture_photometry, ApertureStats)
from photutils.detection import DAOStarFinder

import warnings
warnings.filterwarnings('ignore', category=UserWarning, append=True)

import _tool_visualization as vis

DATAPATH = Path('../../Tutorial_Data')
TMPDIR = Path('tmp')
TMPDIR.mkdir(exist_ok=True)

allfits = list(DATAPATH.glob("*p4179*.fits"))
allfits.sort()

ccd = CCDData.read(allfits[0])
WARNING: FITSFixedWarning: RADECSYS= 'ICRS ' / Telescope Coordinate System 
the RADECSYS keyword is deprecated, use RADESYSa. [astropy.wcs.wcs]

5.1. The Catalogs#

Gaia (Wikipedia) is the ESA space mission that is planned to work from 2013-2025. Its main goal is to perform precise astrometry of 1 billion objects. Since it has two passbands, colorimetry has also been performed.

As of 2023, Data Realease 3 (DR3) is the most recent available data set for Gaia.

Pan-STARRS1 (also called PS1; Wikipedia) is a ground-based 1.8 m Ritchey-Chredien telescope facility at Hawaii.

As of 2023, Data Realease 2 (DR2) is the most recent available data set for PS1.

5.2. Archives#

There are multiple archive services for large-scale astronomical datasets:

VizieR (Wikipedia)

A catalog service run by Université de Strasbourg/CNRS. I feel many people archive their observational results (e.g., galaxy redshift catalog, asteroid polarimetric observation results, etc) to VizieR. Sometimes, for some reasons I cannot understand, large-catalog data are not accessible from VizieR for very long time. Also, the column names in VizieR is always very different from other catalog services. You can go to here and search for gaia or ps1 for instance.

MAST (kulski Archive for Space Telescopes; Wikipedia)

A catalog survice run by STScI. I feel MAST mainly goes with space telescope data (HST, JWST, Gaia, TESS, …). Two main ground-based mission data are available, namely Pan-STARRS and VLA-FIRST.

It seems like the most official way to access Gaia is through astroquery.Gaia using TAP+ (see official website’s “PYTHON ACCESS”). Indeed, Gaia DR3 is available only from here, not from MAST.

Important

Before proceed, please read and follow the tutorials of astroquery/gaia. (only 1.1. Query object and 1.2. Cone search are enough, i.e., .query_object_async and .cone_search_async)

Also, please skim through astropy/wcs. You don’t have to know the details, but you have to know the basic usages, e.g., the basic usage shown in astropy/wcs/wcsapi.

5.3. Query Stars in the FoV#

Now check if our FITS file (CCDData) has WCS information. Since in our observation, the pixel scale is roughly 0.39 arcsec per pixel. Thus, let’s query the stars within

  • a circular region (so-called the cone) centered at the center of our FoV, radius of fov_radius = 0.4*diagonal_length/2. ← This is because MAST only supports cone search.

  • a rectangular region centered at the center of our FoV, width and height of 0.4*width and 0.4*height, respectively. ← This is because Gaia.query_object_async supports rectangular query.

print(ccd.wcs)

pix_scale = 0.4*u.arcsec

center_xy = np.array(ccd.shape)/2
center_radec = ccd.wcs.wcs_pix2world(*center_xy, 0)
center_coo = SkyCoord(*center_radec, unit='deg')

width, height = np.array(ccd.shape)*pix_scale

print("\nCoordinate of the center of the image:\n", center_coo)

fov_radius = np.sqrt((np.array(ccd.shape)**2).sum())/2 * pix_scale
WCS Keywords

Number of WCS axes: 2
CTYPE : 'RA---TAN'  'DEC--TAN'  
CRVAL : 204.8640878996  -8.991494826739  
CRPIX : -4068.090526349  5085.76507007  
PC1_1 PC1_2  : -0.0001096993846665  -1.593373136163e-06  
PC2_1 PC2_2  : -2.91576786403e-07  0.0001095957848141  
CDELT : 1.0  1.0  
NAXIS : 999  999

Coordinate of the center of the image:
 <SkyCoord (ICRS): (ra, dec) in deg
    (204.36178211, -9.49675272)>
/Users/ysbach/mambaforge/envs/snuao/lib/python3.10/site-packages/astropy/wcs/wcs.py:3064: RuntimeWarning: cdelt will be ignored since cd is present
  description.append(s.format(*self.wcs.cdelt))

The meaning of CRVAL, CRVAL, CRPIX, and PC (you can just assume CD is identical to PC) matrices:

# =====
# If you want to use MAST, only DR2 is available as of 2023-04-26. 
# You can uncomment q_gaia line.
# Gaia DR2 needs `version=2`
# q_gaia = Catalogs.query_region(center_coo, radius=fov_radius, catalog="Gaia", version=2) 
# =====

# Set default table as DR3 and GAIA_SOURCE.
Gaia.MAIN_GAIA_TABLE = "gaiadr3.gaia_source"
q_gaia = Gaia.query_object_async(coordinate=center_coo, width=width, height=height)

# PS1 DR2 needs `data_release="dr2"`.
q_ps = Catalogs.query_region(center_coo, radius=fov_radius, catalog="Panstarrs", 
                             data_release="dr2", table="mean")
# Change some column names for convenience.
q_ps["raMean"].name = "ra"
q_ps["decMean"].name = "dec"
q_ps["gMeanPSFMag"].name = "g"
q_ps["rMeanPSFMag"].name = "r"

print("Number of results:",len(q_gaia))
print("Number of results:",len(q_ps))
INFO: Query finished. [astroquery.utils.tap.core]
Number of results: 75
Number of results: 5907
print("Number of columns in Gaia, PS1:", len(q_gaia.colnames), len(q_ps.colnames))
Number of columns in Gaia, PS1: 153 125

5.3.1. Gaia DR3#

Note that Gaia DR3 GAIA_SOURCES has 153 columns! The detailed explanation of this table (GAIA_SOURCE table) in DR3 is available here. What we need are only RA, DEC, and magnitude information. For the magnitudes, the magnitude conversion methods for DR3 are given here:

\[ G - V = -0.02704 + 0.01424C - 0.2156 C^2 + 0.01426 C^3 \]

using 96413 sources (\(\sigma = 0.03017\)) and \(C := G_\mathrm{BP} - G_\mathrm{RP}\) color. The equation above is applicable to \(-0.5 < C < 5.0\).

Warning

When you load FITS by CCDData.read, the WCS related information in the header will be deleted. Hence, you must use ccd.wcs to access the WCS information. In other words, WCS(ccd.header) will give empty WCS. This is a bit confusing, since you had to use WCS(hdu.header) in case of HDU object, as you practiced. When saving the CCDData back, WCS-related headers will be re-added.

For error analysis, note that, from Pogson’s formula:

\[ C = G_\mathrm{BP} - G_\mathrm{RP} = -2.5 \lg \frac{I_\mathrm{BP}}{I_\mathrm{RP}} \]

(I is flux). Thus, ignoring any covariance, a simple error propagation gives

\[ \Delta C \approx \frac{2.5}{\ln 10} \sqrt{ \left( \frac{dI_\mathrm{BP}}{I_\mathrm{BP}} \right)^2 + \left( \frac{dI_\mathrm{RP}}{I_\mathrm{RP}} \right)^2 } \]

and

\[ \Delta V = \sqrt{ (\Delta G)^2 + (0.01424 - 2 \times 0.2156 C + 3 \times 0.01426 C^2)^2 (\Delta C)^2 } \]

And you may also include the RMS error \(\sigma = 0.03017\) with that.

coef = np.array([-0.02704, 0.1425, -0.2156, 0.01426])
rmse = 0.03017
color = q_gaia["bp_rp"]

# Add useful columns
q_gaia["bp_snr"] = 1/q_gaia["phot_bp_mean_flux_over_error"]
q_gaia["rp_snr"] = 1/q_gaia["phot_rp_mean_flux_over_error"]
q_gaia["g_snr"] = 1/q_gaia["phot_g_mean_flux_over_error"]

# Calculate color error
q_gaia["dC"] = 2.5/np.log(10)*np.sqrt((q_gaia["rp_snr"])**2 + (q_gaia["bp_snr"])**2)

# Calculate V-mag and error
q_gaia["V"] = (
    q_gaia["phot_g_mean_mag"]
    + coef[0] + coef[1]*color + coef[2]*color**2 + coef[3]*color**3
)
q_gaia["dV"] = np.sqrt(
    2.5/np.log(10)*q_gaia["g_snr"]**2
    + (coef[1] + 2*coef[2]*color + 3*coef[3]*color**2)**2*q_gaia["dC"]**2
    + rmse**2
)

# Only select stars with good color
mask = (-0.5 < color) & (color < 5)
q1 = q_gaia["ra", "dec", "bp_rp", "g_snr", "bp_snr", "rp_snr", "dC", "V", "dV"][mask]

# Calculate x, y position
coo = SkyCoord(q1["ra"], q1["dec"], unit='deg')
q1["x"], q1["y"] = ccd.wcs.wcs_world2pix(coo.ra, coo.dec, 0)

# Remove stars outside the image
q1 = q1[(q1["x"] > 10) & (q1["x"] < ccd.shape[1]-10) 
        & (q1["y"] > 10) & (q1["y"] < ccd.shape[0]-10)]

# print
print(f"Total {len(q1)} stars")
q1.round(3)
q1
Total 65 stars
Table length=65
radecbp_rpg_snrbp_snrrp_snrdCVdVxy
degdegmag
float64float64float32float32float32float32float32float32float32float64float64
204.352-9.5040.7320.0160.1390.1880.25420.8590.051586.313435.758
204.373-9.5052.8550.0020.0330.0040.03616.6810.041399.077428.649
204.373-9.5052.8710.0060.0160.010.0216.7810.034399.015427.491
204.373-9.5052.7480.0050.2450.0870.28219.1310.205403.101420.853
204.35-9.5081.9560.0040.130.0510.15219.7120.087607.765395.122
204.378-9.5020.280.0030.0350.0580.07319.4320.03355.88450.611
204.34-9.4862.010.0030.0920.0320.10619.1250.066692.754596.982
204.343-9.5142.1160.0050.1160.0370.13219.6650.082669.384345.025
204.341-9.5131.080.00.0020.0020.00315.470.03684.598352.004
204.345-9.5181.8010.0060.1350.0610.16120.1720.085650.856304.49
204.334-9.5020.7320.0050.0850.0770.12520.3130.036752.049455.31
204.377-9.5231.1740.0020.0130.0090.01717.8660.031367.571259.337
204.35-9.4690.7250.0030.040.0390.06119.5680.032599.882755.681
204.379-9.4711.1730.0120.2060.1380.26920.7410.088338.946728.53
204.375-9.4692.530.0020.0590.010.06518.2770.054379.274753.508
204.352-9.4671.9240.0010.0190.0080.02317.4260.032582.302772.492
204.376-9.4681.0260.0070.1120.1320.18820.4950.057366.729759.281
204.387-9.5170.6380.00.0030.0030.00415.9860.03273.809314.073
204.33-9.5132.2940.0050.1350.0470.15519.7020.101783.429350.589
.................................
204.384-9.5421.7660.0150.1660.0510.18820.2130.098306.3190.397
204.354-9.4472.0590.0010.040.0120.04517.9440.039562.63949.677
204.354-9.5470.9410.0010.0110.0080.01517.6910.03573.42644.983
204.313-9.5171.1270.0050.1030.0660.13320.1530.049938.2315.155
204.335-9.4511.0160.0010.010.010.01517.6180.03730.181914.864
204.375-9.4451.640.0010.0330.0060.03617.5610.034374.606964.896
204.308-9.5060.9960.00.0010.0010.00214.8910.03980.531417.518
204.31-9.4790.7830.0010.0050.0060.00816.6310.03959.438663.959
204.399-9.5360.4660.0140.1810.1990.29220.8730.036167.756139.08
204.31-9.4760.9660.0020.0440.0290.05719.0630.033962.303689.623
204.392-9.451.7060.0030.0760.0390.09319.2680.053226.356925.276
204.386-9.4460.3170.0120.1020.1560.20220.8580.033280.684962.428
204.402-9.4530.8580.0050.1430.0780.17620.260.046139.056892.001
204.33-9.5471.3860.0020.0080.0040.00916.9150.03789.27146.365
204.326-9.4490.9590.0010.0040.0040.00616.4880.03814.182930.355
204.391-9.5492.6860.0020.0980.0140.10718.1530.082243.06527.85
204.401-9.5450.7450.0010.0170.0120.02317.6420.03150.90561.991
204.398-9.550.9470.0020.0450.0380.06419.2080.034176.52515.585
204.321-9.5490.6640.0040.0640.0680.10220.0120.033873.15120.835
204.41-9.5431.5360.0020.040.0190.04818.8440.03668.81776.787

5.3.2. Pan-STARRS1 DR2#

It seems like there are three tables available from PS1 web query API (e.g., this notebook): “mean”, “stack”, and “detection”. All the metadata can be found based on the url (see ps1metadata function), e.g., this link for the metadata of mean table.

According to Tonry+12,

\[\begin{split} V - r = 0.006 + 0.474(g-r) \quad\rightarrow\quad V = 0.006 + 0.474g + 0.526r \quad (\pm 0.012) \\ R - r = -0.138 - 0.131(g-r) \quad\rightarrow\quad R = -0.138 -0.131g + 1.131 r \quad (\pm 0.015) \end{split}\]

where g, r are the g- and r-band magnitudes in PS1 filter system, respectively. Thus,

\[\begin{split} \Delta V = \sqrt{ (0.474 \Delta g)^2 + (0.526 \Delta r)^2 } \\ \Delta R = \sqrt{ (0.131 \Delta g)^2 + (1.131 \Delta r)^2 } \end{split}\]

And you may also include the RMS error \(\sigma = 0.012\) or \(0.015\) with that.

In real science case, you must remove galaxies for differential photometry (maybe discussed later). Here, we will ignore it.

# drop stars with unknown magnitudes
q_ps = q_ps.to_pandas().dropna(subset=["g", "r"])

# Calculate V and R
q_ps["V"] = 0.006 + 0.474*q_ps["g"] + 0.526*q_ps["r"]
q_ps["R"] = -0.138 - 0.131*q_ps["g"] + 1.131*q_ps["r"]
q_ps["dV"] = np.sqrt(
    0.474**2*q_ps["gMeanPSFMagErr"]**2 
    + 0.526**2*q_ps["rMeanPSFMagErr"]**2 + 0.012**2
)
q_ps["dR"] = np.sqrt(
    0.131**2*q_ps["gMeanPSFMagErr"]**2
    + 1.131**2*q_ps["rMeanPSFMagErr"]**2 + 0.015**2
)

# Select only important columns
q2 = q_ps[["ra", "dec", "g", "r", "V", "R", "dV", "dR"]].copy().reset_index(drop=True)

# Select only brighter than 22 mag
q2 = q2[(q2["V"] < 22) & (q2["R"] < 22)].copy().reset_index(drop=True)

# Calculate x, y position
coo = SkyCoord(q2["ra"], q2["dec"], unit='deg')
q2["x"], q2["y"] = ccd.wcs.wcs_world2pix(coo.ra, coo.dec, 0)

# Remove stars outside the image
q2 = q2[(q2["x"] > 10) & (q2["x"] < ccd.shape[1]-10) 
        & (q2["y"] > 10) & (q2["y"] < ccd.shape[0]-10)]

# print
print(f"Total {len(q2)} stars")
q2.round(3)
q2
Total 126 stars
ra dec g r V R dV dR x y
3 204.398498 -9.549908 19.685900 19.234800 19.454621 19.037706 0.013322 0.017627 176.493198 15.583189
4 204.401293 -9.544794 17.974100 17.651400 17.810360 17.471126 0.012964 0.017497 150.902974 62.031846
5 204.402051 -9.542688 21.183201 21.687500 21.454462 21.615563 0.165217 0.265355 143.877901 81.172085
6 204.404399 -9.545665 21.825600 21.294300 21.552136 21.086700 0.078924 0.103779 123.186834 54.046154
7 204.410444 -9.543147 19.949100 19.042500 19.478228 18.785735 0.021401 0.031288 68.791659 76.814691
... ... ... ... ... ... ... ... ... ... ...
187 204.324440 -9.513110 19.802000 19.544500 19.672555 19.372768 0.028427 0.025100 836.145051 351.508219
193 204.398435 -9.494967 21.852900 21.455200 21.649710 21.265102 0.094912 0.174163 171.053749 514.877474
194 204.399843 -9.495393 21.027300 20.572201 20.793918 20.374583 0.026426 0.036101 158.496791 510.969308
195 204.410279 -9.496189 22.013399 20.967699 21.469361 20.692712 0.053874 0.058962 65.182124 503.478261
196 204.412028 -9.498573 22.103300 21.557199 21.822051 21.347660 0.036635 0.020576 49.785889 481.781735

126 rows × 10 columns

Note that q2 is in pandas.DataFrame and q1 is astropy.Table.

5.3.3. Comparing two catalogs#

aps1 = CircularAperture(np.array([q1["x"], q1["y"]]).T, r=12)
aps2 = CircularAperture(np.array([q2["x"], q2["y"]]).T, r=15)

fig, axs = plt.subplots(1, 1, figsize=(8, 5), sharex=False, sharey=False, gridspec_kw=None)

vis.norm_imshow(axs, ccd, zscale=True)
aps1.plot(color='r', lw=1, alpha=0.5, ax=axs)
aps2.plot(color='k', lw=1, alpha=0.5, ax=axs)

for c, l in zip("rk", ["Gaia", "PS1"]):
    axs.plot(np.nan, np.nan, f"{c}", label=l)
axs.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)

plt.tight_layout()
plt.show();
../_images/854a6424911561cb337b9ac7f68a6e1a355540ef0548a79f48ea24de105fc2be.png

5.3.4. A Short Discussion#

Note that there are more objects in PS1 than Gaia. Since Gaia’s main purpose is astrometry, it is not surprising that PS1 is sensing more celestial objects. Also, PS1 has the filter system that is closer to the classical filter systems (it uses grizy). Thus, for ground-based differential photometry, PS1 catalog will be more useful.

5.4. JPL HORIZONS (Solar System)#

JPL HORIZONS is a ephemeris (plural ephemerides) service operated by NASA JPL. The main purpose of this tool is to perform precise N-body simulation, including the modern computational algorithms, and provide the results to the users. There are many cases you may need it, but the main purpose is to obtain the positional information of the solar system objects or satellite or spacecrafts at certain epoch(s).

Practice

For example, let’s query the information of our target in the CCD image that we are using. We took the image of asteroid (4179) Toutatis on UT 2018-04-13T21:30 (see ccd.header["DATE-OBS"]).

Set the table as below:

  1. Ephemeris Type: "Observer Table"

  2. Target Body: Click edit and search for 4179.

  3. Observer Location: Search for SAAO and select Korea Microlensing Telescope Network-SAAO (code: L32)

  4. Time Specification: Insert start/stop times as 2018-04-13 and 2018-04-14. Type Step size of 10 and "minutes".

  5. Table Settings: Click edit and select "Default" button.

    • “Additional Table Settings”: Elevation cutoff: 10, check the box of “Skip daylight

Then hit the “Generate Ephemeris” button. You will see a long output, but what’s important is just the lines near the observation time (UT 2018-04-13T21:30):

Date__(UT)__HR:MN     R.A._____(ICRF)_____DEC    APmag   S-brt             delta      deldot     S-O-T /r     S-T-O  Sky_motion  Sky_mot_PA  RelVel-ANG  Lun_Sky_Brt  sky_SNR
2018-Apr-13 22:30     13 37 24.57 -09 29 35.4   20.609   7.453  2.82285755430415   2.9894066  177.5789 /L    0.6391   0.5987445   290.83331   8.3188634         n.a.     n.a.

The explanation for each column is given at the bottom of the website. Important ones are the time (Date__(UT)__HR:MN), RA/DEC (R.A._____(ICRF)_____DEC), and the expected V-band magnitude (APmag). Sometimes you may need the heliocentric and geocentric distances (go to the Table Settings and check number 19 & 20).

After generating the ephemerides, you can see the detailed explanations of each column at the bottom part of the result page. https://astroquery.readthedocs.io/en/latest/jplhorizons/jplhorizons.html

From python, you can access HORIZONS using astroquery’s JPLHorizons module, thanks to M. Mommert:

objname = "4179"
observat = "L32"
t_obs = Time(ccd.header["DATE-OBS"]) + ccd.header["EXPTIME"] * u.s / 2
obj = Horizons(id=objname, location=observat, epochs=t_obs.jd)
obj_q = obj.ephemerides()
obj_q.pprint(max_width=100)
       targetname             datetime_str          datetime_jd    ... alpha_true  PABLon  PABLat
          ---                     ---                    d         ...    deg       deg     deg  
----------------------- ------------------------ ----------------- ... ---------- -------- ------
4179 Toutatis (1989 AC) 2018-Apr-13 21:30:56.000 2458222.396481481 ...     0.6463 205.7217 0.5207

The resulting obj_q contains many columns and they have slightly different names than that of HORIZONS you saw above. They are summarized in the official documentation. Few important columns are

  • RA and DEC: The RA/DEC in degrees.

  • lighttime: asteroid-observer distance / c = time delay. The true time of light when it departed the object is, thus, observed time - lighttime.

  • alpha: The phase angle in degrees (alpha differ from alpha_true by only less than around 1 arcmin, so astronomers just use alpha, not alpha_true).

Note

In real work, you don’t want to query this for every image (as it takes a lot of time). Better way is to obtain the t_obs for all the images and pass that as Horizons(..., epochs=t_obs_list) as python list object. See the official documentation for the usage, if necessary.

Once we know the RA/DEC, we can convert those to the image XY coordinate by using the WCS information in the header, as we did for stars:

pos_sky = SkyCoord(obj_q["RA"][0], obj_q["DEC"][0], unit='deg')
pos_pix = pos_sky.to_pixel(wcs=ccd.wcs)
print(pos_sky)
print(pos_pix)

ap0 = CircularAperture(np.array([pos_pix[0], pos_pix[1]]).T, r=20)

fig, axs = plt.subplots(1, 1, figsize=(8, 5), sharex=False, sharey=False, gridspec_kw=None)

vis.norm_imshow(axs, ccd, zscale=True)
aps2.plot(color='k', lw=1, alpha=0.5, ax=axs)
ap0.plot(color='r', lw=1, alpha=1, ax=axs)

plt.tight_layout()
plt.show();
<SkyCoord (ICRS): (ra, dec) in deg
    (204.36166, -9.49665)>
(array(500.58291238), array(500.43561473))
../_images/821e0fea80a1aac6d15a2d7c2e4423e5cdda6d6c692fbd33fadff8d46010b80a.png

The red circle is the location of our asteoid, (4179) Toutatis.