{ "cells": [ { "cell_type": "markdown", "id": "intro", "metadata": {}, "source": [ "# NEID L2: querying and inspecting RV products\n", "\n", "This is the most common NEID workflow: search the **Level-2** holdings over a\n", "date range, keep just the columns you care about, and look at what comes back.\n", "By the end you will have an {term}`astropy Table` of radial velocities ready to\n", "plot or fit.\n", "\n", "```{note}\n", "This notebook runs against the live NEID server. The published version here\n", "uses synthetic data so it builds without an archive account — the numbers shown\n", "are illustrative, not real observations.\n", "```\n", "\n", "## What is NEID L2?\n", "\n", "{term}`NEID` is a high-precision {term}`radial velocity (RV)` spectrograph. Its\n", "archive offers files at several {term}`data level`s — a ladder of how far the\n", "data has been processed:\n", "\n", "- {term}`L0` — raw detector frames, straight off the CCD.\n", "- {term}`L1` — calibrated 1D {term}`extracted spectrum` (flux vs. wavelength).\n", "- {term}`L2` — RV-ready products: the {term}`CCF (cross-correlation function)`\n", " and the radial velocity derived from it.\n", "\n", "Most science users want **L2**, because that is where the radial velocities\n", "live. The pipeline measures each RV by cross-correlating the star's spectrum\n", "against a template of known stellar lines and finding the Doppler shift of the\n", "result; you never compute any of that yourself. For the full story see\n", "{doc}`../concepts/data-levels` and {doc}`../concepts/radial-velocities`." ] }, { "cell_type": "code", "execution_count": null, "id": "setup", "metadata": { "tags": [ "remove-cell" ] }, "outputs": [], "source": [ "import os\n", "\n", "from astropy.table import Table\n", "\n", "OFFLINE = bool(os.getenv(\"NEXSCI_RV_OFFLINE_FIXTURES\"))\n", "\n", "if OFFLINE:\n", " from unittest.mock import patch\n", "\n", " from astropy.coordinates import SkyCoord\n", "\n", " _fake = Table(\n", " {\n", " \"l2filename\": [\n", " \"neid20241101_0001.fits\",\n", " \"neid20241101_0002.fits\",\n", " \"neid20241102_0001.fits\",\n", " ],\n", " \"obsdate\": [\"2024-11-01T03:12:00\", \"2024-11-01T03:25:00\", \"2024-11-02T03:18:00\"],\n", " \"object\": [\"HD 189733\", \"HD 189733\", \"HD 189733\"],\n", " \"exptime\": [300.0, 300.0, 300.0],\n", " \"ccfrvmod\": [-2.276, -2.279, -2.281],\n", " }\n", " )\n", " _patcher = patch(\"nexsci_rv.tap.TapClient.query\", return_value=_fake)\n", " _patcher.start()\n", " # Stub Simbad/NED name resolution so query_criteria(object=...) works offline.\n", " _fake_coord = SkyCoord(\"20h00m43.7s\", \"+22d42m39s\")\n", " _resolver_patcher = patch(\"nexsci_rv.base.SkyCoord.from_name\", return_value=_fake_coord)\n", " _resolver_patcher.start()\n", " print(\"Offline mode: queries return synthetic data.\")" ] }, { "cell_type": "markdown", "id": "build-client-md", "metadata": {}, "source": [ "## Build the archive client\n", "\n", "`NEIDArchive()` with no arguments points at the IPAC production server. Public\n", "L2 data is queryable without `login()`.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "build-client", "metadata": {}, "outputs": [], "source": [ "from nexsci_rv import NEIDArchive\n", "\n", "neid = NEIDArchive()\n", "neid" ] }, { "cell_type": "markdown", "id": "query-date-md", "metadata": {}, "source": [ "## Query by date range\n", "\n", "All query methods return an `astropy.table.Table`. Use `columns=` to keep only\n", "what you need; the package validates column names against the table's static\n", "schema before any HTTP request.\n" ] }, { "cell_type": "code", "execution_count": null, "id": "query-date", "metadata": {}, "outputs": [], "source": [ "tbl = neid.query_datetime(\n", " \"l2\",\n", " (\"2024-11-01\", \"2024-11-06\"),\n", " columns=[\"l2filename\", \"obsdate\", \"object\", \"exptime\", \"ccfrvmod\"],\n", " maxrec=20,\n", ")\n", "tbl" ] }, { "cell_type": "markdown", "id": "e34eb613", "metadata": {}, "source": [ "Each row is one observation. The columns we asked for:\n", "\n", "- `l2filename` — the name of the L2 {term}`FITS` file; you need it (with\n", " `l2filepath`) to {term}`download` the data later.\n", "- {term}`obsdate` — the observation time stamp;\n", " this is the column {term}`query_datetime` filters on.\n", "- {term}`object` — the free-text target name the observer typed in.\n", "- {term}`exptime` — exposure time in seconds.\n", "- {term}`ccfrvmod` — **the answer**: the radial velocity in m/s, the number you\n", " would phase-fold and fit for a planet (its error bar is {term}`ccfnoise`).\n", "\n", "For the full column tour see {doc}`../concepts/results-columns`; `describe_table`\n", "(below) lists every column the table offers." ] }, { "cell_type": "markdown", "id": "2c80699a", "metadata": {}, "source": [ "```{tip}\n", "We searched by **date range** here because a time window is the safest first\n", "query — it always works. When you know a star by name, RA/Dec, a catalog ID, a\n", "program, or a PI instead, there is a dedicated `query_*` method for each. See\n", "{doc}`../concepts/choosing-a-query` for picking the right one.\n", "\n", "`maxrec` caps how many rows the server returns (here, 20). Keep it small while\n", "you are still working out a query, then raise it once the results look right.\n", "```\n", "\n", "Most NEID data is public and needs no login. Reaching data still inside its\n", "{term}`proprietary period` requires `neid.login()` with IPAC NEID credentials —\n", "see {doc}`../concepts/downloading-and-proprietary`." ] }, { "cell_type": "markdown", "id": "criteria-md", "metadata": {}, "source": [ "## Multi-criterion query in one round-trip\n", "\n", "`query_criteria` composes constraints into a single ADQL query — one HTTP\n", "request even with several filters." ] }, { "cell_type": "code", "execution_count": null, "id": "criteria", "metadata": {}, "outputs": [], "source": [ "from astropy import units as u\n", "\n", "tbl2 = neid.query_criteria(\n", " {\n", " \"data_level\": \"l2\",\n", " \"datetime\": (\"2024-11-01\", \"2024-11-06\"),\n", " \"object\": \"HD 189733\",\n", " \"object_radius\": 30 * u.arcsec,\n", " },\n", " columns=[\"l2filename\", \"obsdate\", \"object\", \"ccfrvmod\"],\n", " maxrec=20,\n", ")\n", "tbl2" ] }, { "cell_type": "markdown", "id": "schema-md", "metadata": {}, "source": [ "## Inspecting the schema\n", "\n", "`describe_table` returns the server-side `TAP_SCHEMA` metadata for a given\n", "table — useful for finding columns that aren't in the package's static map." ] }, { "cell_type": "code", "execution_count": null, "id": "schema", "metadata": {}, "outputs": [], "source": [ "if not OFFLINE:\n", " schema = neid.describe_table(\"neidl2\")\n", " schema[:10]\n", "else:\n", " print(\"(skipped in offline mode)\")" ] }, { "cell_type": "markdown", "id": "next-steps", "metadata": {}, "source": [ "## What next\n", "\n", "You now have a table of NEID radial velocities. From here:\n", "\n", "- {doc}`02_expres_solar` — the same query pattern applied to the EXPRES solar\n", " RV time series.\n", "- {doc}`03_download_and_plot` — turn a result table into FITS files on disk and\n", " open a spectrum.\n", "- {doc}`../quickstart` — every query pattern at a glance." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.12" } }, "nbformat": 4, "nbformat_minor": 5 }