diff --git a/notebooks/1_too_models.ipynb b/notebooks/1_too_models.ipynb
deleted file mode 100644
index 8096ce2..0000000
--- a/notebooks/1_too_models.ipynb
+++ /dev/null
@@ -1,663 +0,0 @@
-{
- "cells": [
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "d331f783",
- "metadata": {},
- "outputs": [],
- "source": [
- "import logging\n",
- "from winterapi import WinterAPI\n",
- "from wintertoo.models import SummerFieldToO, SummerRaDecToO, WinterFieldToO, WinterRaDecToO"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "68657fec",
- "metadata": {},
- "outputs": [],
- "source": [
- "logging.getLogger(\"winterapi\").setLevel(\"DEBUG\")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "75c8a14e",
- "metadata": {},
- "outputs": [],
- "source": [
- "winter = WinterAPI()"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "bd4d474c",
- "metadata": {},
- "source": [
- "Our credentials from the previous notebook will still be active!"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "eb5f0374",
- "metadata": {},
- "source": [
- "# Setting up a ToO"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "e6a15b09",
- "metadata": {},
- "source": [
- "Now we are going to set up a ToO. There are two ways to trigger a ToO:\n",
- "* Using a ra/dec value\n",
- "* Using a field value\n",
- "\n",
- "There are also two types of instruments to trigger: WINTER or SUMMER. \n",
- "\n",
- "That makes **4 different ToO objects to choose from*.\n",
- "\n",
- "Let's go through the procedure for a Summer ToO using a field."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "504be7f4",
- "metadata": {},
- "source": [
- "## Step 1: What can go into a ToO request?"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "3a212a51",
- "metadata": {},
- "source": [
- "For `winterapi`, we handle data using `pydantic`. We specify what types of data can be provided, what the conditions are, and what the default values are.\n",
- "\n",
- "You can see all options in a human-readable way by converting the data model to a json schema:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "15e67d82",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "{\n",
- " \"title\": \"SummerFieldToO\",\n",
- " \"description\": \"Summer ToO Request with field\",\n",
- " \"type\": \"object\",\n",
- " \"properties\": {\n",
- " \"field_id\": {\n",
- " \"title\": \"Field ID\",\n",
- " \"minimum\": 1,\n",
- " \"type\": \"integer\"\n",
- " },\n",
- " \"filters\": {\n",
- " \"title\": \"Filters\",\n",
- " \"default\": [\n",
- " \"u\",\n",
- " \"g\",\n",
- " \"r\",\n",
- " \"i\"\n",
- " ],\n",
- " \"type\": \"array\",\n",
- " \"items\": {\n",
- " \"enum\": [\n",
- " \"u\",\n",
- " \"g\",\n",
- " \"r\",\n",
- " \"i\"\n",
- " ],\n",
- " \"type\": \"string\"\n",
- " }\n",
- " },\n",
- " \"target_priority\": {\n",
- " \"title\": \"Priority for target\",\n",
- " \"default\": 50.0,\n",
- " \"minimum\": 0.0,\n",
- " \"type\": \"number\"\n",
- " },\n",
- " \"t_exp\": {\n",
- " \"title\": \"Individual exposure time (s)\",\n",
- " \"default\": 30.0,\n",
- " \"minimum\": 1.0,\n",
- " \"maximum\": 300,\n",
- " \"type\": \"number\"\n",
- " },\n",
- " \"n_exp\": {\n",
- " \"title\": \"Number of dither sets\",\n",
- " \"default\": 1,\n",
- " \"minimum\": 1,\n",
- " \"type\": \"integer\"\n",
- " },\n",
- " \"n_dither\": {\n",
- " \"title\": \"Number of dithers\",\n",
- " \"default\": 1,\n",
- " \"minimum\": 1,\n",
- " \"type\": \"integer\"\n",
- " },\n",
- " \"dither_distance\": {\n",
- " \"title\": \"dither distance (arcsec)\",\n",
- " \"default\": 15.0,\n",
- " \"minimum\": 0.0,\n",
- " \"type\": \"number\"\n",
- " },\n",
- " \"start_time_mjd\": {\n",
- " \"title\": \"ToO validity start (MJD)\",\n",
- " \"default\": 60103.72062578728,\n",
- " \"type\": \"number\"\n",
- " },\n",
- " \"end_time_mjd\": {\n",
- " \"title\": \"ToO validity end (MJD)\",\n",
- " \"default\": 60104.71062579434,\n",
- " \"minimum\": 60103.71062579612,\n",
- " \"type\": \"number\"\n",
- " },\n",
- " \"max_airmass\": {\n",
- " \"title\": \"Allowed airmass range\",\n",
- " \"default\": 2.0,\n",
- " \"minimum\": 1,\n",
- " \"maximum\": 5,\n",
- " \"type\": \"number\"\n",
- " }\n",
- " },\n",
- " \"required\": [\n",
- " \"field_id\"\n",
- " ],\n",
- " \"additionalProperties\": false\n",
- "}\n"
- ]
- }
- ],
- "source": [
- "print(SummerFieldToO.schema_json(indent=1))"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "56fceaf1",
- "metadata": {},
- "source": [
- "There is a lot of information, but the most important line is right at the bottom. The only thing that is required is `field_id`. Everything else is optional.\n",
- "\n",
- "We can initialise the ToO using a random field number:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "3dcfcdae",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "SummerFieldToO(field_id=55, filters=['u', 'g', 'r', 'i'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=15.0, start_time_mjd=60103.72062578728, end_time_mjd=60104.71062579434, max_airmass=2.0)"
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "too = SummerFieldToO(field_id=55)\n",
- "too"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "43a49362",
- "metadata": {},
- "source": [
- "As you can see, we got a full ToO request with sensible defaults. If we only wanted one filter rather than 4, we could specify this:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "id": "6605d149",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "SummerFieldToO(field_id=55, filters=['u'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=15.0, start_time_mjd=60103.72062578728, end_time_mjd=60104.71062579434, max_airmass=2.0)"
- ]
- },
- "execution_count": 6,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "too = SummerFieldToO(field_id=55, filters=[\"u\"])\n",
- "too"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "54ef13e4",
- "metadata": {},
- "source": [
- "Pydantic also validates the data we enter, to make sure things are sensible. Here are some examples of things you can't do:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "id": "217812b9",
- "metadata": {},
- "outputs": [
- {
- "ename": "ValidationError",
- "evalue": "1 validation error for SummerFieldToO\nfilters -> 0\n unexpected value; permitted: 'u', 'g', 'r', 'i' (type=value_error.const; given=V; permitted=('u', 'g', 'r', 'i'))",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)",
- "Cell \u001b[0;32mIn[7], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Names a filter that isn't avbailable\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m too \u001b[38;5;241m=\u001b[39m \u001b[43mSummerFieldToO\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfield_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m55\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfilters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mV\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3\u001b[0m too\n",
- "File \u001b[0;32m~/anaconda3/envs/winterapi/lib/python3.11/site-packages/pydantic/main.py:341\u001b[0m, in \u001b[0;36mpydantic.main.BaseModel.__init__\u001b[0;34m()\u001b[0m\n",
- "\u001b[0;31mValidationError\u001b[0m: 1 validation error for SummerFieldToO\nfilters -> 0\n unexpected value; permitted: 'u', 'g', 'r', 'i' (type=value_error.const; given=V; permitted=('u', 'g', 'r', 'i'))"
- ]
- }
- ],
- "source": [
- "# Names a filter that isn't avbailable\n",
- "too = SummerFieldToO(field_id=55, filters=[\"V\"])\n",
- "too"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "id": "00b582dd",
- "metadata": {},
- "outputs": [
- {
- "ename": "ValidationError",
- "evalue": "1 validation error for SummerFieldToO\nend_time_mjd\n ensure this value is greater than or equal to 60103.71062579612 (type=value_error.number.not_ge; limit_value=60103.71062579612)",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)",
- "Cell \u001b[0;32mIn[8], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# end time in the past\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m too \u001b[38;5;241m=\u001b[39m \u001b[43mSummerFieldToO\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfield_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m55\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mend_time_mjd\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m58000.\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3\u001b[0m too\n",
- "File \u001b[0;32m~/anaconda3/envs/winterapi/lib/python3.11/site-packages/pydantic/main.py:341\u001b[0m, in \u001b[0;36mpydantic.main.BaseModel.__init__\u001b[0;34m()\u001b[0m\n",
- "\u001b[0;31mValidationError\u001b[0m: 1 validation error for SummerFieldToO\nend_time_mjd\n ensure this value is greater than or equal to 60103.71062579612 (type=value_error.number.not_ge; limit_value=60103.71062579612)"
- ]
- }
- ],
- "source": [
- "# end time in the past\n",
- "too = SummerFieldToO(field_id=55, end_time_mjd=58000.)\n",
- "too"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "id": "7133e738",
- "metadata": {},
- "outputs": [
- {
- "ename": "ValidationError",
- "evalue": "1 validation error for SummerFieldToO\nn_dither\n ensure this value is greater than or equal to 1 (type=value_error.number.not_ge; limit_value=1)",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)",
- "Cell \u001b[0;32mIn[9], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Chooses a nonsensical n_dither number\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m too \u001b[38;5;241m=\u001b[39m \u001b[43mSummerFieldToO\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfield_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m55\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mn_dither\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3\u001b[0m too\n",
- "File \u001b[0;32m~/anaconda3/envs/winterapi/lib/python3.11/site-packages/pydantic/main.py:341\u001b[0m, in \u001b[0;36mpydantic.main.BaseModel.__init__\u001b[0;34m()\u001b[0m\n",
- "\u001b[0;31mValidationError\u001b[0m: 1 validation error for SummerFieldToO\nn_dither\n ensure this value is greater than or equal to 1 (type=value_error.number.not_ge; limit_value=1)"
- ]
- }
- ],
- "source": [
- "# Chooses a nonsensical n_dither number\n",
- "too = SummerFieldToO(field_id=55, n_dither=0)\n",
- "too"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "1371556c",
- "metadata": {},
- "source": [
- "## Step 2 Choosing a ToO using ra/dec"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "7614d0d0",
- "metadata": {},
- "source": [
- "If you know the field to observe, then you have all the information you need, because each grid has a unique ra/dec value for that field.\n",
- "The API will look that value up, so you do not need to worry about it.\n",
- "\n",
- "However, more often, if you are performing a ToO, it's because you know the ra/dec of a specific object.\n",
- "\n",
- "In that case, we can use a Ra/Dec model. Here's one with Summer:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "id": "8f56c276",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "{\n",
- " \"title\": \"SummerRaDecToO\",\n",
- " \"description\": \"Summer ToO Request with Ra/Dec\",\n",
- " \"type\": \"object\",\n",
- " \"properties\": {\n",
- " \"ra_deg\": {\n",
- " \"title\": \"Right ascension in decimal degrees\",\n",
- " \"minimum\": 0.0,\n",
- " \"maximum\": 360.0,\n",
- " \"example\": 180.0,\n",
- " \"type\": \"number\"\n",
- " },\n",
- " \"dec_deg\": {\n",
- " \"title\": \"Declination in decimal degrees\",\n",
- " \"minimum\": -90.0,\n",
- " \"maximum\": 90.0,\n",
- " \"example\": 0.0,\n",
- " \"type\": \"number\"\n",
- " },\n",
- " \"use_field_grid\": {\n",
- " \"title\": \"boolean whether to select nearest field in grid for central ra/dec\",\n",
- " \"default\": true,\n",
- " \"type\": \"boolean\"\n",
- " },\n",
- " \"filters\": {\n",
- " \"title\": \"Filters\",\n",
- " \"default\": [\n",
- " \"u\",\n",
- " \"g\",\n",
- " \"r\",\n",
- " \"i\"\n",
- " ],\n",
- " \"type\": \"array\",\n",
- " \"items\": {\n",
- " \"enum\": [\n",
- " \"u\",\n",
- " \"g\",\n",
- " \"r\",\n",
- " \"i\"\n",
- " ],\n",
- " \"type\": \"string\"\n",
- " }\n",
- " },\n",
- " \"target_priority\": {\n",
- " \"title\": \"Priority for target\",\n",
- " \"default\": 50.0,\n",
- " \"minimum\": 0.0,\n",
- " \"type\": \"number\"\n",
- " },\n",
- " \"t_exp\": {\n",
- " \"title\": \"Individual exposure time (s)\",\n",
- " \"default\": 30.0,\n",
- " \"minimum\": 1.0,\n",
- " \"maximum\": 300,\n",
- " \"type\": \"number\"\n",
- " },\n",
- " \"n_exp\": {\n",
- " \"title\": \"Number of dither sets\",\n",
- " \"default\": 1,\n",
- " \"minimum\": 1,\n",
- " \"type\": \"integer\"\n",
- " },\n",
- " \"n_dither\": {\n",
- " \"title\": \"Number of dithers\",\n",
- " \"default\": 1,\n",
- " \"minimum\": 1,\n",
- " \"type\": \"integer\"\n",
- " },\n",
- " \"dither_distance\": {\n",
- " \"title\": \"dither distance (arcsec)\",\n",
- " \"default\": 15.0,\n",
- " \"minimum\": 0.0,\n",
- " \"type\": \"number\"\n",
- " },\n",
- " \"start_time_mjd\": {\n",
- " \"title\": \"ToO validity start (MJD)\",\n",
- " \"default\": 60103.72062578728,\n",
- " \"type\": \"number\"\n",
- " },\n",
- " \"end_time_mjd\": {\n",
- " \"title\": \"ToO validity end (MJD)\",\n",
- " \"default\": 60104.71062579434,\n",
- " \"minimum\": 60103.71062579612,\n",
- " \"type\": \"number\"\n",
- " },\n",
- " \"max_airmass\": {\n",
- " \"title\": \"Allowed airmass range\",\n",
- " \"default\": 2.0,\n",
- " \"minimum\": 1,\n",
- " \"maximum\": 5,\n",
- " \"type\": \"number\"\n",
- " }\n",
- " },\n",
- " \"required\": [\n",
- " \"ra_deg\",\n",
- " \"dec_deg\"\n",
- " ],\n",
- " \"additionalProperties\": false\n",
- "}\n"
- ]
- }
- ],
- "source": [
- "print(SummerRaDecToO.schema_json(indent=1))"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "cc4aba3a",
- "metadata": {},
- "source": [
- "In this case, we only need to provide the ra and dec:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "id": "266c0940",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "SummerRaDecToO(ra_deg=300.0, dec_deg=51.0, use_field_grid=True, filters=['u', 'g', 'r', 'i'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=15.0, start_time_mjd=60103.72062578728, end_time_mjd=60104.71062579434, max_airmass=2.0)"
- ]
- },
- "execution_count": 11,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "too = SummerRaDecToO(ra_deg=300., dec_deg=51.)\n",
- "too"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "5bdf48c2",
- "metadata": {},
- "source": [
- "**One important note: by default, a schedule with an ra/dec will be matched to the nearest field, and the exposure will be centered on that field RA/dec**\n",
- " \n",
- "You can disable this behaviour by setting `use_field_grid` to false! "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "id": "42a4c48c",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "SummerRaDecToO(ra_deg=300.0, dec_deg=51.0, use_field_grid=False, filters=['u', 'g', 'r', 'i'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=15.0, start_time_mjd=60103.72062578728, end_time_mjd=60104.71062579434, max_airmass=2.0)"
- ]
- },
- "execution_count": 12,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "too = SummerRaDecToO(ra_deg=300., dec_deg=51., use_field_grid=False)\n",
- "too"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "13798041",
- "metadata": {},
- "source": [
- "# Step 3: Choosing Summer or Winter"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "5e192a5b",
- "metadata": {},
- "source": [
- "Creating a Winter ToO is exactly the same as the examples above, though the validation rules are different because the telescopes are different:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 13,
- "id": "1a28ca82",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "WinterFieldToO(field_id=55, filters=['Y', 'J', 'Hs'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=15.0, start_time_mjd=60103.72062578728, end_time_mjd=60104.71062579434, max_airmass=2.0)"
- ]
- },
- "execution_count": 13,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# A field ToO\n",
- "too = WinterFieldToO(field_id=55)\n",
- "too"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 14,
- "id": "337d7cec",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "WinterRaDecToO(ra_deg=300.0, dec_deg=51.0, use_field_grid=True, filters=['Y', 'J', 'Hs'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=15.0, start_time_mjd=60103.72062578728, end_time_mjd=60104.71062579434, max_airmass=2.0)"
- ]
- },
- "execution_count": 14,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "# A ra/dec ToO\n",
- "too = WinterRaDecToO(ra_deg=300., dec_deg=51.)\n",
- "too"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "386d383e",
- "metadata": {},
- "source": [
- "**Remember, WINTER has different filters!**"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 15,
- "id": "6c2e061d",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "field_id=55 filters=['u'] target_priority=50.0 t_exp=30.0 n_exp=1 n_dither=1 dither_distance=15.0 start_time_mjd=60103.72062578728 end_time_mjd=60104.71062579434 max_airmass=2.0\n"
- ]
- },
- {
- "ename": "ValidationError",
- "evalue": "1 validation error for WinterFieldToO\nfilters -> 0\n unexpected value; permitted: 'Y', 'J', 'Hs' (type=value_error.const; given=u; permitted=('Y', 'J', 'Hs'))",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)",
- "Cell \u001b[0;32mIn[15], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m too \u001b[38;5;241m=\u001b[39m SummerFieldToO(field_id\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m55\u001b[39m, filters\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mu\u001b[39m\u001b[38;5;124m\"\u001b[39m])\n\u001b[1;32m 2\u001b[0m \u001b[38;5;28mprint\u001b[39m(too)\n\u001b[0;32m----> 3\u001b[0m too \u001b[38;5;241m=\u001b[39m \u001b[43mWinterFieldToO\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfield_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m55\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfilters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mu\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28mprint\u001b[39m(too)\n",
- "File \u001b[0;32m~/anaconda3/envs/winterapi/lib/python3.11/site-packages/pydantic/main.py:341\u001b[0m, in \u001b[0;36mpydantic.main.BaseModel.__init__\u001b[0;34m()\u001b[0m\n",
- "\u001b[0;31mValidationError\u001b[0m: 1 validation error for WinterFieldToO\nfilters -> 0\n unexpected value; permitted: 'Y', 'J', 'Hs' (type=value_error.const; given=u; permitted=('Y', 'J', 'Hs'))"
- ]
- }
- ],
- "source": [
- "too = SummerFieldToO(field_id=55, filters=[\"u\"])\n",
- "print(too)\n",
- "too = WinterFieldToO(field_id=55, filters=[\"u\"])\n",
- "print(too)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "c7fec6d4",
- "metadata": {},
- "outputs": [],
- "source": []
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "winterapi",
- "language": "python",
- "name": "winterapi"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.11.3"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/notebooks/Example_1_Setting_Up_Credentials.ipynb b/notebooks/Example_1_Setting_Up_Credentials.ipynb
new file mode 100644
index 0000000..1c9b031
--- /dev/null
+++ b/notebooks/Example_1_Setting_Up_Credentials.ipynb
@@ -0,0 +1,165 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "3fb54b95",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [],
+ "source": [
+ "import logging\n",
+ "from winterapi import WinterAPI\n",
+ "from winterapi.endpoints import BASE_URL"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "84869822",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "logging.getLogger(\"winterapi\").setLevel(\"DEBUG\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "b7024bc4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "winter = WinterAPI()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "25197a54",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Using server http://winter.caltech.edu:82\n",
+ "Pinging server: True\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(f\"Using server {BASE_URL}\") # Should show the URL of the API\n",
+ "print(f\"Pinging server: {winter.ping()}\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "88d1d907",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "User is rdstein@caltech.edu\n"
+ ]
+ }
+ ],
+ "source": [
+ "try:\n",
+ " print(f\"User is {winter.get_user()}\")\n",
+ "except KeyError:\n",
+ " print(\"No user credentials found. Please add these first!\")\n",
+ " winter.add_user_details(overwrite=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "f0dc0b3f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Uncomment to add new credentials\n",
+ "# winter.add_user_details(user=x, password=y, overwrite=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "64797375",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Found the following saved programs: ['2024A001']\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(f\"Found the following saved programs: {winter.get_programs()}\")\n",
+ "if len(winter.get_programs()) == 0:\n",
+ " print(\"No programs found. Add one to get started:\")\n",
+ " winter.add_program(overwrite=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "42f4d81b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Uncomment to add additional programs\n",
+ "winter.add_program(overwrite=True)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b16a0900",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# A fake local program I have created\n",
+ "winter.get_program_details(\"202XA000\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1023561f",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "winterapi",
+ "language": "python",
+ "name": "winterapi"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/notebooks/Example_2_Submitting_a_ToO.ipynb b/notebooks/Example_2_Submitting_a_ToO.ipynb
new file mode 100644
index 0000000..0ce1144
--- /dev/null
+++ b/notebooks/Example_2_Submitting_a_ToO.ipynb
@@ -0,0 +1,514 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "f91a536f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import logging\n",
+ "from winterapi import WinterAPI\n",
+ "from wintertoo.models import WinterRaDecToO"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "5e92d4e2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "logging.getLogger(\"winterapi\").setLevel(\"DEBUG\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "ba9823d9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "winter = WinterAPI()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "c68cfda7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Program details\n",
+ "program = \"2024A001\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "513407c4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Target details\n",
+ "ra_deg = 249.1311789\n",
+ "dec_deg = 47.858962\n",
+ "# Target name is a useful field for querying data, so put something useful!\n",
+ "# If you use Skyportal, we strongly advise you to use that name\n",
+ "target_name = \"ZTF23aaxeacr\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "031d4780",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "WinterRaDecToO(ra_deg=249.1311789, dec_deg=47.858962, use_field_grid=False, filters=['Y', 'J'], target_priority=50.0, target_name='ZTF23aaxeacr', t_exp=960.0, n_exp=1, n_dither=8, dither_distance=30.0, start_time_mjd=60346.16884958786, end_time_mjd=60347.15884959191, max_airmass=2.0)"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# A ToO with the same dither combo for Y/J\n",
+ "too_1 = WinterRaDecToO(ra_deg=ra_deg, dec_deg=dec_deg, n_dither=8, t_exp=960., filters=['Y', 'J'], target_name=target_name)\n",
+ "too_1"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "7c3daafe",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "WinterRaDecToO(ra_deg=249.1311789, dec_deg=47.858962, use_field_grid=False, filters=['Hs'], target_priority=50.0, target_name='ZTF23aaxeacr', t_exp=960.0, n_exp=1, n_dither=15, dither_distance=30.0, start_time_mjd=60346.16884958786, end_time_mjd=60347.15884959191, max_airmass=2.0)"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# A second ToO, with a different dither number for Hs\n",
+ "too_2 = WinterRaDecToO(ra_deg=ra_deg, dec_deg=dec_deg, n_dither=15, t_exp=960., filters=[\"Hs\"], target_name=target_name)\n",
+ "too_2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "b7be6f9f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "too_list = [too_1, too_2]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "555800e8",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Available programs: ['2024A001', '2023A000', '2023A001', '2023A002']\n"
+ ]
+ }
+ ],
+ "source": [
+ "program_list = winter.get_programs()\n",
+ "print(f\"Available programs: {program_list}\")\n",
+ "assert program in program_list, f\"program {program} not found! Add this program first.\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "ec20aa42",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " targName | \n",
+ " raDeg | \n",
+ " decDeg | \n",
+ " fieldID | \n",
+ " filter | \n",
+ " visitExpTime | \n",
+ " priority | \n",
+ " progPI | \n",
+ " progName | \n",
+ " progID | \n",
+ " validStart | \n",
+ " validStop | \n",
+ " observed | \n",
+ " maxAirmass | \n",
+ " ditherNumber | \n",
+ " ditherStepSize | \n",
+ " obsHistID | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " ZTF23aaxeacr | \n",
+ " 249.131179 | \n",
+ " 47.858962 | \n",
+ " 999999999 | \n",
+ " Y | \n",
+ " 960.0 | \n",
+ " 50.0 | \n",
+ " RStein | \n",
+ " 2024A001 | \n",
+ " 3 | \n",
+ " 60346.16885 | \n",
+ " 60347.15885 | \n",
+ " False | \n",
+ " 2.0 | \n",
+ " 8 | \n",
+ " 30.0 | \n",
+ " 0 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " ZTF23aaxeacr | \n",
+ " 249.131179 | \n",
+ " 47.858962 | \n",
+ " 999999999 | \n",
+ " J | \n",
+ " 960.0 | \n",
+ " 50.0 | \n",
+ " RStein | \n",
+ " 2024A001 | \n",
+ " 3 | \n",
+ " 60346.16885 | \n",
+ " 60347.15885 | \n",
+ " False | \n",
+ " 2.0 | \n",
+ " 8 | \n",
+ " 30.0 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " ZTF23aaxeacr | \n",
+ " 249.131179 | \n",
+ " 47.858962 | \n",
+ " 999999999 | \n",
+ " Hs | \n",
+ " 960.0 | \n",
+ " 50.0 | \n",
+ " RStein | \n",
+ " 2024A001 | \n",
+ " 3 | \n",
+ " 60346.16885 | \n",
+ " 60347.15885 | \n",
+ " False | \n",
+ " 2.0 | \n",
+ " 15 | \n",
+ " 30.0 | \n",
+ " 2 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " targName raDeg decDeg fieldID filter visitExpTime \\\n",
+ "0 ZTF23aaxeacr 249.131179 47.858962 999999999 Y 960.0 \n",
+ "1 ZTF23aaxeacr 249.131179 47.858962 999999999 J 960.0 \n",
+ "2 ZTF23aaxeacr 249.131179 47.858962 999999999 Hs 960.0 \n",
+ "\n",
+ " priority progPI progName progID validStart validStop observed \\\n",
+ "0 50.0 RStein 2024A001 3 60346.16885 60347.15885 False \n",
+ "1 50.0 RStein 2024A001 3 60346.16885 60347.15885 False \n",
+ "2 50.0 RStein 2024A001 3 60346.16885 60347.15885 False \n",
+ "\n",
+ " maxAirmass ditherNumber ditherStepSize obsHistID \n",
+ "0 2.0 8 30.0 0 \n",
+ "1 2.0 8 30.0 1 \n",
+ "2 2.0 15 30.0 2 "
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Schedule has three observations in total\n",
+ "local_schedule = winter.build_schedule_locally(\n",
+ " program_name=program,\n",
+ " data=too_list\n",
+ ")\n",
+ "local_schedule"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "2a6462c6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# If submit_trigger is False, the API will just check the schedule but not put in a ToO\n",
+ "# Set this to True to actually trigger!\n",
+ "api_res, api_schedule = winter.submit_too(\n",
+ " program_name=program,\n",
+ " data=too_list,\n",
+ " submit_trigger=False\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "edc16188",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Request passed validation! Triggering was set to False. Schedule was not saved to disk and has no assigned name.'"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Let's see what message the API sent back\n",
+ "api_res.json()[\"msg\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "1758d4f7",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "\"Request passed validation! Triggering was set to True. Schedule name is 'request_2024A001_2024_02_05_19_49_26' .\""
+ ]
+ },
+ "execution_count": 13,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Uncomment to trigger for real\n",
+ "api_res, api_schedule = winter.submit_too(\n",
+ " program_name=program,\n",
+ " data=too_list,\n",
+ " submit_trigger=True\n",
+ ")\n",
+ "api_res.json()[\"msg\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "id": "dfebd472",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " targName | \n",
+ " raDeg | \n",
+ " decDeg | \n",
+ " fieldID | \n",
+ " filter | \n",
+ " visitExpTime | \n",
+ " priority | \n",
+ " progPI | \n",
+ " progName | \n",
+ " progID | \n",
+ " validStart | \n",
+ " validStop | \n",
+ " observed | \n",
+ " maxAirmass | \n",
+ " ditherNumber | \n",
+ " ditherStepSize | \n",
+ " obsHistID | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " ZTF23aaxeacr | \n",
+ " 249.131179 | \n",
+ " 47.858962 | \n",
+ " 999999999 | \n",
+ " Y | \n",
+ " 960.0 | \n",
+ " 50.0 | \n",
+ " RStein | \n",
+ " 2024A001 | \n",
+ " 3 | \n",
+ " 60346.16885 | \n",
+ " 60347.15885 | \n",
+ " False | \n",
+ " 2.0 | \n",
+ " 8 | \n",
+ " 30.0 | \n",
+ " 0 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " ZTF23aaxeacr | \n",
+ " 249.131179 | \n",
+ " 47.858962 | \n",
+ " 999999999 | \n",
+ " J | \n",
+ " 960.0 | \n",
+ " 50.0 | \n",
+ " RStein | \n",
+ " 2024A001 | \n",
+ " 3 | \n",
+ " 60346.16885 | \n",
+ " 60347.15885 | \n",
+ " False | \n",
+ " 2.0 | \n",
+ " 8 | \n",
+ " 30.0 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " ZTF23aaxeacr | \n",
+ " 249.131179 | \n",
+ " 47.858962 | \n",
+ " 999999999 | \n",
+ " Hs | \n",
+ " 960.0 | \n",
+ " 50.0 | \n",
+ " RStein | \n",
+ " 2024A001 | \n",
+ " 3 | \n",
+ " 60346.16885 | \n",
+ " 60347.15885 | \n",
+ " False | \n",
+ " 2.0 | \n",
+ " 15 | \n",
+ " 30.0 | \n",
+ " 2 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " targName raDeg decDeg fieldID filter visitExpTime \\\n",
+ "0 ZTF23aaxeacr 249.131179 47.858962 999999999 Y 960.0 \n",
+ "1 ZTF23aaxeacr 249.131179 47.858962 999999999 J 960.0 \n",
+ "2 ZTF23aaxeacr 249.131179 47.858962 999999999 Hs 960.0 \n",
+ "\n",
+ " priority progPI progName progID validStart validStop observed \\\n",
+ "0 50.0 RStein 2024A001 3 60346.16885 60347.15885 False \n",
+ "1 50.0 RStein 2024A001 3 60346.16885 60347.15885 False \n",
+ "2 50.0 RStein 2024A001 3 60346.16885 60347.15885 False \n",
+ "\n",
+ " maxAirmass ditherNumber ditherStepSize obsHistID \n",
+ "0 2.0 8 30.0 0 \n",
+ "1 2.0 8 30.0 1 \n",
+ "2 2.0 15 30.0 2 "
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# This is the schedule sent back by the API. Reassuringly, it matches the local one\n",
+ "api_schedule"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "ba9f510f",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "winterapi",
+ "language": "python",
+ "name": "winterapi"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/notebooks/Example_3_Interacting_with_Observatory_Queue.ipynb b/notebooks/Example_3_Interacting_with_Observatory_Queue.ipynb
new file mode 100644
index 0000000..f164336
--- /dev/null
+++ b/notebooks/Example_3_Interacting_with_Observatory_Queue.ipynb
@@ -0,0 +1,505 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "f91a536f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import logging\n",
+ "from winterapi import WinterAPI\n",
+ "from wintertoo.models import WinterRaDecToO"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "5e92d4e2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "logging.getLogger(\"winterapi\").setLevel(\"DEBUG\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "ba9823d9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "winter = WinterAPI()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3370c4d8",
+ "metadata": {},
+ "source": [
+ "# Getting a summary of your queued ToOs"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "db3b7f84",
+ "metadata": {},
+ "source": [
+ "After you've submitted your ToOs, you might wonder how they are doing in the queue. You can find this out using the API."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "202aa614",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "program_name = \"2024A001\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "03095da8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "res, queue = winter.get_observatory_queue(program_name=program_name)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "38524494",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Returning schedule summary for 2024A001'"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res.json()[\"msg\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "1621a452",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " prog_name | \n",
+ " observed_frac | \n",
+ " too_schedule_name | \n",
+ " target_names | \n",
+ " n_entries | \n",
+ " total_time_hours | \n",
+ " window_start | \n",
+ " window_end | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 2024A001 | \n",
+ " 0.0 | \n",
+ " request_2024A001_2024_02_05_19_49_26 | \n",
+ " [ZTF23aaxeacr] | \n",
+ " 3 | \n",
+ " 0.8 | \n",
+ " 2024-02-06 04:03:08.604 | \n",
+ " 2024-02-07 03:48:44.605 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " prog_name observed_frac too_schedule_name \\\n",
+ "0 2024A001 0.0 request_2024A001_2024_02_05_19_49_26 \n",
+ "\n",
+ " target_names n_entries total_time_hours window_start \\\n",
+ "0 [ZTF23aaxeacr] 3 0.8 2024-02-06 04:03:08.604 \n",
+ "\n",
+ " window_end \n",
+ "0 2024-02-07 03:48:44.605 "
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "queue"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e6e88fea",
+ "metadata": {},
+ "source": [
+ "# Checking an individual ToO"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b48e76c5",
+ "metadata": {},
+ "source": [
+ "You can see when you submitted a ToO request, since the date is in the `too_schedule_name` name. Nonethless, let's imagine you have forgotten what request you submitted, and want to see what is in that schedule. We can use the schedule_details function to ask the API for this."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "877ed48e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "schedule_name = \"request_2024A001_2024_02_05_19_49_26\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "463289d3",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Returning details of schedule request_2024A001_2024_02_05_19_49_26'"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res, too_request = winter.get_too_details(\n",
+ " too_schedule_name=schedule_name,\n",
+ " program_name=program_name\n",
+ ")\n",
+ "res.json()[\"msg\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "48b9dd11",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " targName | \n",
+ " raDeg | \n",
+ " decDeg | \n",
+ " fieldID | \n",
+ " filter | \n",
+ " visitExpTime | \n",
+ " priority | \n",
+ " progPI | \n",
+ " progName | \n",
+ " progID | \n",
+ " validStart | \n",
+ " validStop | \n",
+ " observed | \n",
+ " maxAirmass | \n",
+ " ditherNumber | \n",
+ " ditherStepSize | \n",
+ " obsHistID | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " ZTF23aaxeacr | \n",
+ " 249.131179 | \n",
+ " 47.858962 | \n",
+ " 999999999 | \n",
+ " Y | \n",
+ " 960.0 | \n",
+ " 50.0 | \n",
+ " RStein | \n",
+ " 2024A001 | \n",
+ " 3 | \n",
+ " 60346.16885 | \n",
+ " 60347.15885 | \n",
+ " 0 | \n",
+ " 2.0 | \n",
+ " 8 | \n",
+ " 30.0 | \n",
+ " 0 | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " ZTF23aaxeacr | \n",
+ " 249.131179 | \n",
+ " 47.858962 | \n",
+ " 999999999 | \n",
+ " J | \n",
+ " 960.0 | \n",
+ " 50.0 | \n",
+ " RStein | \n",
+ " 2024A001 | \n",
+ " 3 | \n",
+ " 60346.16885 | \n",
+ " 60347.15885 | \n",
+ " 0 | \n",
+ " 2.0 | \n",
+ " 8 | \n",
+ " 30.0 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " ZTF23aaxeacr | \n",
+ " 249.131179 | \n",
+ " 47.858962 | \n",
+ " 999999999 | \n",
+ " Hs | \n",
+ " 960.0 | \n",
+ " 50.0 | \n",
+ " RStein | \n",
+ " 2024A001 | \n",
+ " 3 | \n",
+ " 60346.16885 | \n",
+ " 60347.15885 | \n",
+ " 0 | \n",
+ " 2.0 | \n",
+ " 15 | \n",
+ " 30.0 | \n",
+ " 2 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " targName raDeg decDeg fieldID filter visitExpTime \\\n",
+ "0 ZTF23aaxeacr 249.131179 47.858962 999999999 Y 960.0 \n",
+ "1 ZTF23aaxeacr 249.131179 47.858962 999999999 J 960.0 \n",
+ "2 ZTF23aaxeacr 249.131179 47.858962 999999999 Hs 960.0 \n",
+ "\n",
+ " priority progPI progName progID validStart validStop observed \\\n",
+ "0 50.0 RStein 2024A001 3 60346.16885 60347.15885 0 \n",
+ "1 50.0 RStein 2024A001 3 60346.16885 60347.15885 0 \n",
+ "2 50.0 RStein 2024A001 3 60346.16885 60347.15885 0 \n",
+ "\n",
+ " maxAirmass ditherNumber ditherStepSize obsHistID \n",
+ "0 2.0 8 30.0 0 \n",
+ "1 2.0 8 30.0 1 \n",
+ "2 2.0 15 30.0 2 "
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Here we see that it's the request we submitted earlier!\n",
+ "too_request"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "15cf523b",
+ "metadata": {},
+ "source": [
+ "# Deleting Requests"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "43b972b0",
+ "metadata": {},
+ "source": [
+ "Now let's imagine that you have made a horrible mistake! The dec of your target is actually 28 degrees, not 48.\n",
+ "\n",
+ "You need to urgently need to delete this request! Fornuately, there is a function for this too."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "14666fd9",
+ "metadata": {
+ "scrolled": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Deleted request_2024A001_2024_02_05_19_49_26'"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res = winter.delete_too_request(\n",
+ " too_schedule_name=schedule_name,\n",
+ " program_name=program_name\n",
+ ")\n",
+ "res.json()[\"msg\"]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "72477640",
+ "metadata": {},
+ "source": [
+ "Let's just double check to make see there is no request left. **You may need to wait up to 1 minute before changes take appear.**"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "id": "525f3d16",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "No active schedules found for 2024A001\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ "Empty DataFrame\n",
+ "Columns: []\n",
+ "Index: []"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res, queue = winter.get_observatory_queue(program_name=program_name)\n",
+ "print(res.json()[\"msg\"])\n",
+ "queue"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "15c58dd6",
+ "metadata": {},
+ "source": [
+ "Fortunately the request has been removed, and the queue is empty!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "13e087c7",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "winterapi",
+ "language": "python",
+ "name": "winterapi"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/notebooks/Example_4_Finding_Observatory_Data.ipynb b/notebooks/Example_4_Finding_Observatory_Data.ipynb
new file mode 100644
index 0000000..e9f05eb
--- /dev/null
+++ b/notebooks/Example_4_Finding_Observatory_Data.ipynb
@@ -0,0 +1,1935 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "f91a536f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import logging\n",
+ "from winterapi import WinterAPI\n",
+ "from wintertoo.models import ProgramImageQuery"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "5e92d4e2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "logging.getLogger(\"winterapi\").setLevel(\"DEBUG\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "ba9823d9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "winter = WinterAPI()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "13e087c7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "program_name = \"2023A002\"\n",
+ "start_date = \"20230721\"\n",
+ "end_date = \"20230730\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "179e69d0",
+ "metadata": {},
+ "source": [
+ "# Query by program"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "b8c16182",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Querying images for 2023A002 between 20230721 and 20230730 of type 'exposure'\n",
+ "program_name='2023A002' start_date=20230721 end_date=20230730 kind='exposure'\n"
+ ]
+ }
+ ],
+ "source": [
+ "res, images = winter.query_images_by_program(program_name, image_type=\"exposure\", start_date=start_date, end_date=end_date)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "0af1415d",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Request passed validation! Found 67 images.'"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res.json()[\"msg\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "68525bf4",
+ "metadata": {
+ "scrolled": false
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " progname | \n",
+ " nightdate | \n",
+ " targname | \n",
+ " ra | \n",
+ " dec | \n",
+ " fid | \n",
+ " utctime | \n",
+ " fieldid | \n",
+ " image_type | \n",
+ " savepath | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.674838 | \n",
+ " 54.023881 | \n",
+ " 2 | \n",
+ " 2023-07-29T11:14:15.923000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.703027 | \n",
+ " 53.973475 | \n",
+ " 3 | \n",
+ " 2023-07-29T11:32:21.242000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.641702 | \n",
+ " 54.035399 | \n",
+ " 3 | \n",
+ " 2023-07-29T11:34:28.476000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.602247 | \n",
+ " 54.049005 | \n",
+ " 1 | \n",
+ " 2023-07-29T10:58:33.601000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 2023A002 | \n",
+ " 2023-07-28 | \n",
+ " None | \n",
+ " 211.551919 | \n",
+ " 54.057056 | \n",
+ " 3 | \n",
+ " 2023-07-28T12:18:36.003000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ " ... | \n",
+ "
\n",
+ " \n",
+ " 62 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.564014 | \n",
+ " 54.000018 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:53:57.778000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 63 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.603932 | \n",
+ " 53.980763 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:56:04.654000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 64 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.600961 | \n",
+ " 53.953119 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:58:11.748000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 65 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.484563 | \n",
+ " 53.959085 | \n",
+ " 2 | \n",
+ " 2023-07-27T11:00:18.851000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 66 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.463750 | \n",
+ " 53.989283 | \n",
+ " 2 | \n",
+ " 2023-07-27T11:02:25.732000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
67 rows × 10 columns
\n",
+ "
"
+ ],
+ "text/plain": [
+ " progname nightdate targname ra dec fid \\\n",
+ "0 2023A002 2023-07-29 None 211.674838 54.023881 2 \n",
+ "1 2023A002 2023-07-29 None 211.703027 53.973475 3 \n",
+ "2 2023A002 2023-07-29 None 211.641702 54.035399 3 \n",
+ "3 2023A002 2023-07-29 None 211.602247 54.049005 1 \n",
+ "4 2023A002 2023-07-28 None 211.551919 54.057056 3 \n",
+ ".. ... ... ... ... ... ... \n",
+ "62 2023A002 2023-07-27 SN2023ixf 211.564014 54.000018 2 \n",
+ "63 2023A002 2023-07-27 SN2023ixf 211.603932 53.980763 2 \n",
+ "64 2023A002 2023-07-27 SN2023ixf 211.600961 53.953119 2 \n",
+ "65 2023A002 2023-07-27 SN2023ixf 211.484563 53.959085 2 \n",
+ "66 2023A002 2023-07-27 SN2023ixf 211.463750 53.989283 2 \n",
+ "\n",
+ " utctime fieldid image_type \\\n",
+ "0 2023-07-29T11:14:15.923000+00:00 3944 exposure \n",
+ "1 2023-07-29T11:32:21.242000+00:00 3944 exposure \n",
+ "2 2023-07-29T11:34:28.476000+00:00 3944 exposure \n",
+ "3 2023-07-29T10:58:33.601000+00:00 3944 exposure \n",
+ "4 2023-07-28T12:18:36.003000+00:00 3944 exposure \n",
+ ".. ... ... ... \n",
+ "62 2023-07-27T10:53:57.778000+00:00 3944 exposure \n",
+ "63 2023-07-27T10:56:04.654000+00:00 3944 exposure \n",
+ "64 2023-07-27T10:58:11.748000+00:00 3944 exposure \n",
+ "65 2023-07-27T11:00:18.851000+00:00 3944 exposure \n",
+ "66 2023-07-27T11:02:25.732000+00:00 3944 exposure \n",
+ "\n",
+ " savepath \n",
+ "0 None \n",
+ "1 None \n",
+ "2 None \n",
+ "3 None \n",
+ "4 None \n",
+ ".. ... \n",
+ "62 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "63 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "64 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "65 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "66 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "\n",
+ "[67 rows x 10 columns]"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "images"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2cddf5b7",
+ "metadata": {},
+ "source": [
+ "# Query by program and target name"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "653daae7",
+ "metadata": {},
+ "source": [
+ "If you are triggering lots of requests, you might want to restrict yourself to a specific target name.\n",
+ "**This will only work if you specified a target name in the ToO request though**. \n",
+ "So it's a good idea to do that!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "72816e21",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "target_name = \"SN2023ixf\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "bb347283",
+ "metadata": {
+ "scrolled": true
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Querying images for 2023A002 between 20230721 and 20230730 of type 'exposure', with name SN2023ixf\n",
+ "program_name='2023A002' start_date=20230721 end_date=20230730 kind='exposure' target_name='SN2023ixf'\n"
+ ]
+ }
+ ],
+ "source": [
+ "res, images = winter.query_images_by_target_name(program_name, image_type=\"exposure\", target_name=target_name, start_date=start_date, end_date=end_date)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "8d323f95",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Request passed validation! Found 5 images.'"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res.json()[\"msg\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "a54e729c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " progname | \n",
+ " nightdate | \n",
+ " targname | \n",
+ " ra | \n",
+ " dec | \n",
+ " fid | \n",
+ " utctime | \n",
+ " fieldid | \n",
+ " image_type | \n",
+ " savepath | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.564014 | \n",
+ " 54.000018 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:53:57.778000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.603932 | \n",
+ " 53.980763 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:56:04.654000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.600961 | \n",
+ " 53.953119 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:58:11.748000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.484563 | \n",
+ " 53.959085 | \n",
+ " 2 | \n",
+ " 2023-07-27T11:00:18.851000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.463750 | \n",
+ " 53.989283 | \n",
+ " 2 | \n",
+ " 2023-07-27T11:02:25.732000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " progname nightdate targname ra dec fid \\\n",
+ "0 2023A002 2023-07-27 SN2023ixf 211.564014 54.000018 2 \n",
+ "1 2023A002 2023-07-27 SN2023ixf 211.603932 53.980763 2 \n",
+ "2 2023A002 2023-07-27 SN2023ixf 211.600961 53.953119 2 \n",
+ "3 2023A002 2023-07-27 SN2023ixf 211.484563 53.959085 2 \n",
+ "4 2023A002 2023-07-27 SN2023ixf 211.463750 53.989283 2 \n",
+ "\n",
+ " utctime fieldid image_type \\\n",
+ "0 2023-07-27T10:53:57.778000+00:00 3944 exposure \n",
+ "1 2023-07-27T10:56:04.654000+00:00 3944 exposure \n",
+ "2 2023-07-27T10:58:11.748000+00:00 3944 exposure \n",
+ "3 2023-07-27T11:00:18.851000+00:00 3944 exposure \n",
+ "4 2023-07-27T11:02:25.732000+00:00 3944 exposure \n",
+ "\n",
+ " savepath \n",
+ "0 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "1 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "2 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "3 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "4 /Users/robertstein/Data/winter/20230726/raw/WI... "
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "images"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a2c19cd",
+ "metadata": {},
+ "source": [
+ "# Query by program and position (cone)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2bc01c56",
+ "metadata": {},
+ "source": [
+ "In this case, I suspect there are more images. Maybe I forgot to tag all ToO requests with the appropriate name.\n",
+ "\n",
+ "You can instead search in a cone around a known position, which may pick up dome extra images."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "6a832f90",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Querying images for 2023A002 between 20230721 and 20230730 of type 'exposure', with a radius of 1.0 degrees around 211.564014, 53.953119\n",
+ "program_name='2023A002' start_date=20230721 end_date=20230730 kind='exposure' ra=211.564014 dec=53.953119 radius_deg=1.0\n"
+ ]
+ }
+ ],
+ "source": [
+ "res, images = winter.query_images_by_cone(program_name, image_type=\"exposure\", ra_deg=211.564014, dec_deg=53.953119, start_date=start_date, end_date=end_date)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "id": "f3b1a443",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Request passed validation! Found 26 images.'"
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res.json()[\"msg\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "id": "1e96a188",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " progname | \n",
+ " nightdate | \n",
+ " targname | \n",
+ " ra | \n",
+ " dec | \n",
+ " fid | \n",
+ " utctime | \n",
+ " fieldid | \n",
+ " image_type | \n",
+ " savepath | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.674838 | \n",
+ " 54.023881 | \n",
+ " 2 | \n",
+ " 2023-07-29T11:14:15.923000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.703027 | \n",
+ " 53.973475 | \n",
+ " 3 | \n",
+ " 2023-07-29T11:32:21.242000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.641702 | \n",
+ " 54.035399 | \n",
+ " 3 | \n",
+ " 2023-07-29T11:34:28.476000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.602247 | \n",
+ " 54.049005 | \n",
+ " 1 | \n",
+ " 2023-07-29T10:58:33.601000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 2023A002 | \n",
+ " 2023-07-28 | \n",
+ " None | \n",
+ " 211.551919 | \n",
+ " 54.057056 | \n",
+ " 3 | \n",
+ " 2023-07-28T12:18:36.003000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 5 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.579693 | \n",
+ " 54.007654 | \n",
+ " 2 | \n",
+ " 2023-07-29T11:12:08.915000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 6 | \n",
+ " 2023A002 | \n",
+ " 2023-07-28 | \n",
+ " None | \n",
+ " 211.579817 | \n",
+ " 54.011482 | \n",
+ " 3 | \n",
+ " 2023-07-28T12:20:44.046000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 7 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.563987 | \n",
+ " 54.000012 | \n",
+ " 1 | \n",
+ " 2023-07-29T10:54:19.249000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 8 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.563971 | \n",
+ " 54.000022 | \n",
+ " 3 | \n",
+ " 2023-07-29T11:30:13.813000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 9 | \n",
+ " 2023A002 | \n",
+ " 2023-07-28 | \n",
+ " None | \n",
+ " 211.563963 | \n",
+ " 54.000016 | \n",
+ " 1 | \n",
+ " 2023-07-28T10:54:32.773000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 10 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.563968 | \n",
+ " 54.000003 | \n",
+ " 2 | \n",
+ " 2023-07-29T11:05:46.324000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 11 | \n",
+ " 2023A002 | \n",
+ " 2023-07-28 | \n",
+ " None | \n",
+ " 211.563935 | \n",
+ " 53.999989 | \n",
+ " 3 | \n",
+ " 2023-07-28T12:16:28.921000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 12 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.682929 | \n",
+ " 53.952960 | \n",
+ " 1 | \n",
+ " 2023-07-29T11:02:47.879000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 13 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.619561 | \n",
+ " 53.976947 | \n",
+ " 3 | \n",
+ " 2023-07-29T11:38:43.505000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 14 | \n",
+ " 2023A002 | \n",
+ " 2023-07-28 | \n",
+ " None | \n",
+ " 211.592616 | \n",
+ " 53.986777 | \n",
+ " 3 | \n",
+ " 2023-07-28T12:24:58.300000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 15 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.525396 | \n",
+ " 53.986620 | \n",
+ " 1 | \n",
+ " 2023-07-29T11:00:41.100000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 16 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.513125 | \n",
+ " 53.982132 | \n",
+ " 1 | \n",
+ " 2023-07-29T10:56:26.509000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 17 | \n",
+ " 2023A002 | \n",
+ " 2023-07-28 | \n",
+ " None | \n",
+ " 211.508044 | \n",
+ " 53.975719 | \n",
+ " 3 | \n",
+ " 2023-07-28T12:22:51.710000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 18 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.469302 | \n",
+ " 54.007045 | \n",
+ " 2 | \n",
+ " 2023-07-29T11:10:02.560000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 19 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.485915 | \n",
+ " 53.988701 | \n",
+ " 3 | \n",
+ " 2023-07-29T11:36:35.974000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 20 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 211.502436 | \n",
+ " 53.916982 | \n",
+ " 2 | \n",
+ " 2023-07-29T11:07:54.564000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " None | \n",
+ "
\n",
+ " \n",
+ " 21 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.564014 | \n",
+ " 54.000018 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:53:57.778000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 22 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.603932 | \n",
+ " 53.980763 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:56:04.654000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 23 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.600961 | \n",
+ " 53.953119 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:58:11.748000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 24 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.484563 | \n",
+ " 53.959085 | \n",
+ " 2 | \n",
+ " 2023-07-27T11:00:18.851000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 25 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.463750 | \n",
+ " 53.989283 | \n",
+ " 2 | \n",
+ " 2023-07-27T11:02:25.732000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " progname nightdate targname ra dec fid \\\n",
+ "0 2023A002 2023-07-29 None 211.674838 54.023881 2 \n",
+ "1 2023A002 2023-07-29 None 211.703027 53.973475 3 \n",
+ "2 2023A002 2023-07-29 None 211.641702 54.035399 3 \n",
+ "3 2023A002 2023-07-29 None 211.602247 54.049005 1 \n",
+ "4 2023A002 2023-07-28 None 211.551919 54.057056 3 \n",
+ "5 2023A002 2023-07-29 None 211.579693 54.007654 2 \n",
+ "6 2023A002 2023-07-28 None 211.579817 54.011482 3 \n",
+ "7 2023A002 2023-07-29 None 211.563987 54.000012 1 \n",
+ "8 2023A002 2023-07-29 None 211.563971 54.000022 3 \n",
+ "9 2023A002 2023-07-28 None 211.563963 54.000016 1 \n",
+ "10 2023A002 2023-07-29 None 211.563968 54.000003 2 \n",
+ "11 2023A002 2023-07-28 None 211.563935 53.999989 3 \n",
+ "12 2023A002 2023-07-29 None 211.682929 53.952960 1 \n",
+ "13 2023A002 2023-07-29 None 211.619561 53.976947 3 \n",
+ "14 2023A002 2023-07-28 None 211.592616 53.986777 3 \n",
+ "15 2023A002 2023-07-29 None 211.525396 53.986620 1 \n",
+ "16 2023A002 2023-07-29 None 211.513125 53.982132 1 \n",
+ "17 2023A002 2023-07-28 None 211.508044 53.975719 3 \n",
+ "18 2023A002 2023-07-29 None 211.469302 54.007045 2 \n",
+ "19 2023A002 2023-07-29 None 211.485915 53.988701 3 \n",
+ "20 2023A002 2023-07-29 None 211.502436 53.916982 2 \n",
+ "21 2023A002 2023-07-27 SN2023ixf 211.564014 54.000018 2 \n",
+ "22 2023A002 2023-07-27 SN2023ixf 211.603932 53.980763 2 \n",
+ "23 2023A002 2023-07-27 SN2023ixf 211.600961 53.953119 2 \n",
+ "24 2023A002 2023-07-27 SN2023ixf 211.484563 53.959085 2 \n",
+ "25 2023A002 2023-07-27 SN2023ixf 211.463750 53.989283 2 \n",
+ "\n",
+ " utctime fieldid image_type \\\n",
+ "0 2023-07-29T11:14:15.923000+00:00 3944 exposure \n",
+ "1 2023-07-29T11:32:21.242000+00:00 3944 exposure \n",
+ "2 2023-07-29T11:34:28.476000+00:00 3944 exposure \n",
+ "3 2023-07-29T10:58:33.601000+00:00 3944 exposure \n",
+ "4 2023-07-28T12:18:36.003000+00:00 3944 exposure \n",
+ "5 2023-07-29T11:12:08.915000+00:00 3944 exposure \n",
+ "6 2023-07-28T12:20:44.046000+00:00 3944 exposure \n",
+ "7 2023-07-29T10:54:19.249000+00:00 3944 exposure \n",
+ "8 2023-07-29T11:30:13.813000+00:00 3944 exposure \n",
+ "9 2023-07-28T10:54:32.773000+00:00 3944 exposure \n",
+ "10 2023-07-29T11:05:46.324000+00:00 3944 exposure \n",
+ "11 2023-07-28T12:16:28.921000+00:00 3944 exposure \n",
+ "12 2023-07-29T11:02:47.879000+00:00 3944 exposure \n",
+ "13 2023-07-29T11:38:43.505000+00:00 3944 exposure \n",
+ "14 2023-07-28T12:24:58.300000+00:00 3944 exposure \n",
+ "15 2023-07-29T11:00:41.100000+00:00 3944 exposure \n",
+ "16 2023-07-29T10:56:26.509000+00:00 3944 exposure \n",
+ "17 2023-07-28T12:22:51.710000+00:00 3944 exposure \n",
+ "18 2023-07-29T11:10:02.560000+00:00 3944 exposure \n",
+ "19 2023-07-29T11:36:35.974000+00:00 3944 exposure \n",
+ "20 2023-07-29T11:07:54.564000+00:00 3944 exposure \n",
+ "21 2023-07-27T10:53:57.778000+00:00 3944 exposure \n",
+ "22 2023-07-27T10:56:04.654000+00:00 3944 exposure \n",
+ "23 2023-07-27T10:58:11.748000+00:00 3944 exposure \n",
+ "24 2023-07-27T11:00:18.851000+00:00 3944 exposure \n",
+ "25 2023-07-27T11:02:25.732000+00:00 3944 exposure \n",
+ "\n",
+ " savepath \n",
+ "0 None \n",
+ "1 None \n",
+ "2 None \n",
+ "3 None \n",
+ "4 None \n",
+ "5 None \n",
+ "6 None \n",
+ "7 None \n",
+ "8 None \n",
+ "9 None \n",
+ "10 None \n",
+ "11 None \n",
+ "12 None \n",
+ "13 None \n",
+ "14 None \n",
+ "15 None \n",
+ "16 None \n",
+ "17 None \n",
+ "18 None \n",
+ "19 None \n",
+ "20 None \n",
+ "21 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "22 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "23 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "24 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "25 /Users/robertstein/Data/winter/20230726/raw/WI... "
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "images"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f5e13dd1",
+ "metadata": {},
+ "source": [
+ "We see that we obtain a subset of the images in our program query, but more than before! Specifically those centered at our chosen position, with a default search radius of 1 deg."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1cc70aa8",
+ "metadata": {},
+ "source": [
+ "# Query by program and position (rectangle)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "11ae3977",
+ "metadata": {},
+ "source": [
+ "You can also query with a rectangle"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "id": "882eb586",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Querying images for 2023A002 between 20230701 and 20240206 of type 'stack', with RA between 32.0 and 33.0 and Dec between -3.0 and -2.0\n",
+ "program_name='2023A002' start_date=20230701 end_date=20240206 kind='stack' ra_min=32.0 ra_max=33.0 dec_min=-3.0 dec_max=-2.0\n"
+ ]
+ }
+ ],
+ "source": [
+ "res, images = winter.query_images_by_rectangle(\n",
+ " program_name, start_date=\"20230701\",\n",
+ " ra_min_deg = 32., ra_max_deg=33., \n",
+ " dec_min_deg = -3., dec_max_deg = -2.,\n",
+ " image_type=\"stack\"\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "id": "f0a2561b",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Request passed validation! Found 2 images.'"
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res.json()[\"msg\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "id": "a634f907",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " progname | \n",
+ " nightdate | \n",
+ " targname | \n",
+ " ra | \n",
+ " dec | \n",
+ " fid | \n",
+ " utctime | \n",
+ " fieldid | \n",
+ " image_type | \n",
+ " savepath | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 32.402744 | \n",
+ " -2.038495 | \n",
+ " 1 | \n",
+ " 2023-07-29T17:26:45.891000+00:00 | \n",
+ " 21155 | \n",
+ " stack | \n",
+ " /data/loki/data/winter/20230728/final/WINTERca... | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 2023A002 | \n",
+ " 2023-07-29 | \n",
+ " None | \n",
+ " 32.414180 | \n",
+ " -2.374698 | \n",
+ " 1 | \n",
+ " 2023-07-29T17:24:38.502000+00:00 | \n",
+ " 21155 | \n",
+ " stack | \n",
+ " /data/loki/data/winter/20230728/final/WINTERca... | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " progname nightdate targname ra dec fid \\\n",
+ "0 2023A002 2023-07-29 None 32.402744 -2.038495 1 \n",
+ "1 2023A002 2023-07-29 None 32.414180 -2.374698 1 \n",
+ "\n",
+ " utctime fieldid image_type \\\n",
+ "0 2023-07-29T17:26:45.891000+00:00 21155 stack \n",
+ "1 2023-07-29T17:24:38.502000+00:00 21155 stack \n",
+ "\n",
+ " savepath \n",
+ "0 /data/loki/data/winter/20230728/final/WINTERca... \n",
+ "1 /data/loki/data/winter/20230728/final/WINTERca... "
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "images"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d7198881",
+ "metadata": {},
+ "source": [
+ "# Query different image types"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7dca7581",
+ "metadata": {},
+ "source": [
+ "There are multiple types of image that can be queried by the API:"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0159143f",
+ "metadata": {},
+ "source": [
+ "## Exposure"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "id": "738dc40b",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Querying images for 2023A002 between 20230721 and 20230730 of type 'exposure', with name SN2023ixf\n",
+ "program_name='2023A002' start_date=20230721 end_date=20230730 kind='exposure' target_name='SN2023ixf'\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " progname | \n",
+ " nightdate | \n",
+ " targname | \n",
+ " ra | \n",
+ " dec | \n",
+ " fid | \n",
+ " utctime | \n",
+ " fieldid | \n",
+ " image_type | \n",
+ " savepath | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.564014 | \n",
+ " 54.000018 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:53:57.778000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.603932 | \n",
+ " 53.980763 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:56:04.654000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.600961 | \n",
+ " 53.953119 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:58:11.748000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.484563 | \n",
+ " 53.959085 | \n",
+ " 2 | \n",
+ " 2023-07-27T11:00:18.851000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.463750 | \n",
+ " 53.989283 | \n",
+ " 2 | \n",
+ " 2023-07-27T11:02:25.732000+00:00 | \n",
+ " 3944 | \n",
+ " exposure | \n",
+ " /Users/robertstein/Data/winter/20230726/raw/WI... | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " progname nightdate targname ra dec fid \\\n",
+ "0 2023A002 2023-07-27 SN2023ixf 211.564014 54.000018 2 \n",
+ "1 2023A002 2023-07-27 SN2023ixf 211.603932 53.980763 2 \n",
+ "2 2023A002 2023-07-27 SN2023ixf 211.600961 53.953119 2 \n",
+ "3 2023A002 2023-07-27 SN2023ixf 211.484563 53.959085 2 \n",
+ "4 2023A002 2023-07-27 SN2023ixf 211.463750 53.989283 2 \n",
+ "\n",
+ " utctime fieldid image_type \\\n",
+ "0 2023-07-27T10:53:57.778000+00:00 3944 exposure \n",
+ "1 2023-07-27T10:56:04.654000+00:00 3944 exposure \n",
+ "2 2023-07-27T10:58:11.748000+00:00 3944 exposure \n",
+ "3 2023-07-27T11:00:18.851000+00:00 3944 exposure \n",
+ "4 2023-07-27T11:02:25.732000+00:00 3944 exposure \n",
+ "\n",
+ " savepath \n",
+ "0 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "1 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "2 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "3 /Users/robertstein/Data/winter/20230726/raw/WI... \n",
+ "4 /Users/robertstein/Data/winter/20230726/raw/WI... "
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res, images = winter.query_images_by_target_name(program_name, image_type=\"exposure\", target_name=target_name, start_date=start_date, end_date=end_date)\n",
+ "images"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9384408c",
+ "metadata": {},
+ "source": [
+ "## Raw"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "id": "c73fa604",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Querying images for 2023A002 between 20230721 and 20230730 of type 'raw', with name SN2023ixf\n",
+ "program_name='2023A002' start_date=20230721 end_date=20230730 kind='raw' target_name='SN2023ixf'\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " progname | \n",
+ " nightdate | \n",
+ " targname | \n",
+ " ra | \n",
+ " dec | \n",
+ " fid | \n",
+ " utctime | \n",
+ " fieldid | \n",
+ " image_type | \n",
+ " savepath | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.564014 | \n",
+ " 54.000018 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:53:57.778000+00:00 | \n",
+ " 3944 | \n",
+ " raw | \n",
+ " /data/loki/data/winter/20230726/raw_unpacked/W... | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.603932 | \n",
+ " 53.980763 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:56:04.654000+00:00 | \n",
+ " 3944 | \n",
+ " raw | \n",
+ " /data/loki/data/winter/20230726/raw_unpacked/W... | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.600961 | \n",
+ " 53.953119 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:58:11.748000+00:00 | \n",
+ " 3944 | \n",
+ " raw | \n",
+ " /data/loki/data/winter/20230726/raw_unpacked/W... | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.463750 | \n",
+ " 53.989283 | \n",
+ " 2 | \n",
+ " 2023-07-27T11:02:25.732000+00:00 | \n",
+ " 3944 | \n",
+ " raw | \n",
+ " /data/loki/data/winter/20230726/raw_unpacked/W... | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.484563 | \n",
+ " 53.959085 | \n",
+ " 2 | \n",
+ " 2023-07-27T11:00:18.851000+00:00 | \n",
+ " 3944 | \n",
+ " raw | \n",
+ " /data/loki/data/winter/20230726/raw_unpacked/W... | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " progname nightdate targname ra dec fid \\\n",
+ "0 2023A002 2023-07-27 SN2023ixf 211.564014 54.000018 2 \n",
+ "1 2023A002 2023-07-27 SN2023ixf 211.603932 53.980763 2 \n",
+ "2 2023A002 2023-07-27 SN2023ixf 211.600961 53.953119 2 \n",
+ "3 2023A002 2023-07-27 SN2023ixf 211.463750 53.989283 2 \n",
+ "4 2023A002 2023-07-27 SN2023ixf 211.484563 53.959085 2 \n",
+ "\n",
+ " utctime fieldid image_type \\\n",
+ "0 2023-07-27T10:53:57.778000+00:00 3944 raw \n",
+ "1 2023-07-27T10:56:04.654000+00:00 3944 raw \n",
+ "2 2023-07-27T10:58:11.748000+00:00 3944 raw \n",
+ "3 2023-07-27T11:02:25.732000+00:00 3944 raw \n",
+ "4 2023-07-27T11:00:18.851000+00:00 3944 raw \n",
+ "\n",
+ " savepath \n",
+ "0 /data/loki/data/winter/20230726/raw_unpacked/W... \n",
+ "1 /data/loki/data/winter/20230726/raw_unpacked/W... \n",
+ "2 /data/loki/data/winter/20230726/raw_unpacked/W... \n",
+ "3 /data/loki/data/winter/20230726/raw_unpacked/W... \n",
+ "4 /data/loki/data/winter/20230726/raw_unpacked/W... "
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res, images = winter.query_images_by_target_name(program_name, image_type=\"raw\", target_name=target_name, start_date=start_date, end_date=end_date)\n",
+ "images"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1665b1b4",
+ "metadata": {},
+ "source": [
+ "## Science"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "id": "a6c2499a",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Querying images for 2023A002 between 20230721 and 20230730 of type 'science', with name SN2023ixf\n",
+ "program_name='2023A002' start_date=20230721 end_date=20230730 kind='science' target_name='SN2023ixf'\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " progname | \n",
+ " nightdate | \n",
+ " targname | \n",
+ " ra | \n",
+ " dec | \n",
+ " fid | \n",
+ " utctime | \n",
+ " fieldid | \n",
+ " image_type | \n",
+ " savepath | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.603932 | \n",
+ " 53.980763 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:56:04.654000+00:00 | \n",
+ " 3944 | \n",
+ " science | \n",
+ " /data/loki/data/winter/20230726/post_scamp/WIN... | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.600961 | \n",
+ " 53.953119 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:58:11.748000+00:00 | \n",
+ " 3944 | \n",
+ " science | \n",
+ " /data/loki/data/winter/20230726/post_scamp/WIN... | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.564014 | \n",
+ " 54.000018 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:53:57.778000+00:00 | \n",
+ " 3944 | \n",
+ " science | \n",
+ " /data/loki/data/winter/20230726/post_scamp/WIN... | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.484563 | \n",
+ " 53.959085 | \n",
+ " 2 | \n",
+ " 2023-07-27T11:00:18.851000+00:00 | \n",
+ " 3944 | \n",
+ " science | \n",
+ " /data/loki/data/winter/20230726/post_scamp/WIN... | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 211.463750 | \n",
+ " 53.989283 | \n",
+ " 2 | \n",
+ " 2023-07-27T11:02:25.732000+00:00 | \n",
+ " 3944 | \n",
+ " science | \n",
+ " /data/loki/data/winter/20230726/post_scamp/WIN... | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " progname nightdate targname ra dec fid \\\n",
+ "0 2023A002 2023-07-27 SN2023ixf 211.603932 53.980763 2 \n",
+ "1 2023A002 2023-07-27 SN2023ixf 211.600961 53.953119 2 \n",
+ "2 2023A002 2023-07-27 SN2023ixf 211.564014 54.000018 2 \n",
+ "3 2023A002 2023-07-27 SN2023ixf 211.484563 53.959085 2 \n",
+ "4 2023A002 2023-07-27 SN2023ixf 211.463750 53.989283 2 \n",
+ "\n",
+ " utctime fieldid image_type \\\n",
+ "0 2023-07-27T10:56:04.654000+00:00 3944 science \n",
+ "1 2023-07-27T10:58:11.748000+00:00 3944 science \n",
+ "2 2023-07-27T10:53:57.778000+00:00 3944 science \n",
+ "3 2023-07-27T11:00:18.851000+00:00 3944 science \n",
+ "4 2023-07-27T11:02:25.732000+00:00 3944 science \n",
+ "\n",
+ " savepath \n",
+ "0 /data/loki/data/winter/20230726/post_scamp/WIN... \n",
+ "1 /data/loki/data/winter/20230726/post_scamp/WIN... \n",
+ "2 /data/loki/data/winter/20230726/post_scamp/WIN... \n",
+ "3 /data/loki/data/winter/20230726/post_scamp/WIN... \n",
+ "4 /data/loki/data/winter/20230726/post_scamp/WIN... "
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res, images = winter.query_images_by_target_name(program_name, image_type=\"science\", target_name=target_name, start_date=start_date, end_date=end_date)\n",
+ "images"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d646c777",
+ "metadata": {},
+ "source": [
+ "## Stack"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "id": "c512205e",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Querying images for 2023A002 between 20230721 and 20230730 of type 'stack', with name SN2023ixf\n",
+ "program_name='2023A002' start_date=20230721 end_date=20230730 kind='stack' target_name='SN2023ixf'\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " progname | \n",
+ " nightdate | \n",
+ " targname | \n",
+ " ra | \n",
+ " dec | \n",
+ " fid | \n",
+ " utctime | \n",
+ " fieldid | \n",
+ " image_type | \n",
+ " savepath | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 2023A002 | \n",
+ " 2023-07-27 | \n",
+ " SN2023ixf | \n",
+ " 210.9419 | \n",
+ " 54.262352 | \n",
+ " 2 | \n",
+ " 2023-07-27T10:53:57.778000+00:00 | \n",
+ " 3944 | \n",
+ " stack | \n",
+ " /data/loki/data/winter/20230726/final/WINTERca... | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " progname nightdate targname ra dec fid \\\n",
+ "0 2023A002 2023-07-27 SN2023ixf 210.9419 54.262352 2 \n",
+ "\n",
+ " utctime fieldid image_type \\\n",
+ "0 2023-07-27T10:53:57.778000+00:00 3944 stack \n",
+ "\n",
+ " savepath \n",
+ "0 /data/loki/data/winter/20230726/final/WINTERca... "
+ ]
+ },
+ "execution_count": 23,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res, images = winter.query_images_by_target_name(program_name, image_type=\"stack\", target_name=target_name, start_date=start_date, end_date=end_date)\n",
+ "images"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8e484c3a",
+ "metadata": {},
+ "source": [
+ "## Diff"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "id": "29c53ab5",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Querying images for 2023A002 between 20230721 and 20230730 of type 'diff', with name SN2023ixf\n",
+ "program_name='2023A002' start_date=20230721 end_date=20230730 kind='diff' target_name='SN2023ixf'\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " progname | \n",
+ " nightdate | \n",
+ " targname | \n",
+ " ra | \n",
+ " dec | \n",
+ " fid | \n",
+ " utctime | \n",
+ " fieldid | \n",
+ " image_type | \n",
+ " savepath | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ "Empty DataFrame\n",
+ "Columns: [progname, nightdate, targname, ra, dec, fid, utctime, fieldid, image_type, savepath]\n",
+ "Index: []"
+ ]
+ },
+ "execution_count": 24,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "res, images = winter.query_images_by_target_name(program_name, image_type=\"diff\", target_name=target_name, start_date=start_date, end_date=end_date)\n",
+ "images"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "88983a1c",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "winterapi",
+ "language": "python",
+ "name": "winterapi"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/notebooks/Example_5_Downloading_Observatory_Data.ipynb b/notebooks/Example_5_Downloading_Observatory_Data.ipynb
new file mode 100644
index 0000000..c451b95
--- /dev/null
+++ b/notebooks/Example_5_Downloading_Observatory_Data.ipynb
@@ -0,0 +1,325 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "f91a536f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import logging\n",
+ "from winterapi import WinterAPI\n",
+ "from wintertoo.models import ProgramImageQuery"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "5e92d4e2",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "logging.getLogger(\"winterapi\").setLevel(\"DEBUG\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "ba9823d9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "winter = WinterAPI()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "13e087c7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "program_name = \"2023A002\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "179e69d0",
+ "metadata": {},
+ "source": [
+ "# Query by program and target"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "65f70acd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "image_type = \"stack\""
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "b8c16182",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Querying images for 2023A002 between 20240129 and 20240206 of type 'stack'\n",
+ "program_name='2023A002' start_date=20240129 end_date=20240206 kind='stack'\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " progname | \n",
+ " nightdate | \n",
+ " targname | \n",
+ " ra | \n",
+ " dec | \n",
+ " fid | \n",
+ " utctime | \n",
+ " fieldid | \n",
+ " image_type | \n",
+ " savepath | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " 0 | \n",
+ " 2023A002 | \n",
+ " 2024-01-30 | \n",
+ " None | \n",
+ " 184.72127 | \n",
+ " 49.994120 | \n",
+ " 2 | \n",
+ " 2024-01-30T14:14:25.616000+00:00 | \n",
+ " 999999999 | \n",
+ " stack | \n",
+ " /data/loki/data/winter/20240129/final/WINTERca... | \n",
+ "
\n",
+ " \n",
+ " 1 | \n",
+ " 2023A002 | \n",
+ " 2024-01-30 | \n",
+ " None | \n",
+ " 184.79090 | \n",
+ " 49.371407 | \n",
+ " 2 | \n",
+ " 2024-01-30T14:14:25.616000+00:00 | \n",
+ " 999999999 | \n",
+ " stack | \n",
+ " /data/loki/data/winter/20240129/final/WINTERca... | \n",
+ "
\n",
+ " \n",
+ " 2 | \n",
+ " 2023A002 | \n",
+ " 2024-01-30 | \n",
+ " None | \n",
+ " 185.22182 | \n",
+ " 49.978348 | \n",
+ " 2 | \n",
+ " 2024-01-30T14:14:25.616000+00:00 | \n",
+ " 999999999 | \n",
+ " stack | \n",
+ " /data/loki/data/winter/20240129/final/WINTERca... | \n",
+ "
\n",
+ " \n",
+ " 3 | \n",
+ " 2023A002 | \n",
+ " 2024-01-30 | \n",
+ " None | \n",
+ " 185.78201 | \n",
+ " 49.376770 | \n",
+ " 2 | \n",
+ " 2024-01-30T14:14:25.616000+00:00 | \n",
+ " 999999999 | \n",
+ " stack | \n",
+ " /data/loki/data/winter/20240129/final/WINTERca... | \n",
+ "
\n",
+ " \n",
+ " 4 | \n",
+ " 2023A002 | \n",
+ " 2024-01-30 | \n",
+ " None | \n",
+ " 185.82114 | \n",
+ " 49.970936 | \n",
+ " 2 | \n",
+ " 2024-01-30T14:14:25.616000+00:00 | \n",
+ " 999999999 | \n",
+ " stack | \n",
+ " /data/loki/data/winter/20240129/final/WINTERca... | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " progname nightdate targname ra dec fid \\\n",
+ "0 2023A002 2024-01-30 None 184.72127 49.994120 2 \n",
+ "1 2023A002 2024-01-30 None 184.79090 49.371407 2 \n",
+ "2 2023A002 2024-01-30 None 185.22182 49.978348 2 \n",
+ "3 2023A002 2024-01-30 None 185.78201 49.376770 2 \n",
+ "4 2023A002 2024-01-30 None 185.82114 49.970936 2 \n",
+ "\n",
+ " utctime fieldid image_type \\\n",
+ "0 2024-01-30T14:14:25.616000+00:00 999999999 stack \n",
+ "1 2024-01-30T14:14:25.616000+00:00 999999999 stack \n",
+ "2 2024-01-30T14:14:25.616000+00:00 999999999 stack \n",
+ "3 2024-01-30T14:14:25.616000+00:00 999999999 stack \n",
+ "4 2024-01-30T14:14:25.616000+00:00 999999999 stack \n",
+ "\n",
+ " savepath \n",
+ "0 /data/loki/data/winter/20240129/final/WINTERca... \n",
+ "1 /data/loki/data/winter/20240129/final/WINTERca... \n",
+ "2 /data/loki/data/winter/20240129/final/WINTERca... \n",
+ "3 /data/loki/data/winter/20240129/final/WINTERca... \n",
+ "4 /data/loki/data/winter/20240129/final/WINTERca... "
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Let's start by doing an image query\n",
+ "res, images = winter.query_images_by_program(program_name, image_type=image_type, start_date=\"20240129\")\n",
+ "images"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b9642e4f",
+ "metadata": {},
+ "source": [
+ "# Downloading a list of images"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "88983a1c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "['/data/loki/data/winter/20240129/final/WINTERcamera_20240130-061425-616_mef_1_0_0_stack.fits',\n",
+ " '/data/loki/data/winter/20240129/final/WINTERcamera_20240130-061425-616_mef_5_0_0_stack.fits',\n",
+ " '/data/loki/data/winter/20240129/final/WINTERcamera_20240130-061425-616_mef_3_0_0_stack.fits',\n",
+ " '/data/loki/data/winter/20240129/final/WINTERcamera_20240130-061425-616_mef_2_0_0_stack.fits',\n",
+ " '/data/loki/data/winter/20240129/final/WINTERcamera_20240130-061425-616_mef_4_0_0_stack.fits']"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# Let's say we want to download an image. What's the savepath?\n",
+ "savepaths = images[\"savepath\"].tolist()\n",
+ "savepaths"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ca13baee",
+ "metadata": {},
+ "source": [
+ "We can use the API to download this file, or files, as a compressed zip. \n",
+ "You must specify the type of image!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "96ec4b1f",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "No output directory specified, using /Users/robertstein\n"
+ ]
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Saved images to /Users/robertstein/WINTER_images_stack_2024_02_05_22_58_41.zip\n",
+ "{'Server': 'nginx/1.14.1', 'Date': 'Tue, 06 Feb 2024 06:58:45 GMT', 'Content-Type': 'application/x-zip-compressed', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'content-disposition': 'attachment; filename=WINTER_images_stack_2024_02_05_22_58_41.zip', 'missing-images': '0', 'total-images': '5', 'image-type': 'stack'}\n"
+ ]
+ }
+ ],
+ "source": [
+ "res, output_path = winter.download_image_list(program_name, image_type=image_type, paths=savepaths)\n",
+ "print(f\"Saved images to {output_path}\")\n",
+ "print(res.headers)\n",
+ "res.raise_for_status()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f741610d",
+ "metadata": {},
+ "source": [
+ "Success! We downloaded a zip file with all our images."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "2390cfd3",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "winterapi",
+ "language": "python",
+ "name": "winterapi"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/notebooks/0_intro_accounts.ipynb b/notebooks/Info_1_Introduction_To_Credentials.ipynb
similarity index 59%
rename from notebooks/0_intro_accounts.ipynb
rename to notebooks/Info_1_Introduction_To_Credentials.ipynb
index 8cd9f9a..2028bb5 100644
--- a/notebooks/0_intro_accounts.ipynb
+++ b/notebooks/Info_1_Introduction_To_Credentials.ipynb
@@ -23,17 +23,18 @@
},
{
"cell_type": "code",
- "execution_count": null,
+ "execution_count": 3,
"id": "84ae8151",
"metadata": {},
"outputs": [],
"source": [
- "WinterAPI.clear_cache()"
+ "# Uncomment to clear cache\n",
+ "# WinterAPI.clear_cache()"
]
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 4,
"id": "3fbd0cbf",
"metadata": {},
"outputs": [],
@@ -51,7 +52,7 @@
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 5,
"id": "90ac54c2",
"metadata": {
"scrolled": false
@@ -87,7 +88,7 @@
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 6,
"id": "5739be95",
"metadata": {},
"outputs": [],
@@ -107,7 +108,7 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 7,
"id": "e4dc8ccb",
"metadata": {},
"outputs": [
@@ -125,7 +126,7 @@
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
- "Cell \u001b[0;32mIn[6], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mwinter\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_user_details\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mrdstein@caltech.edu\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43man-incorrect-password\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moverwrite\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m)\u001b[49m\n",
+ "Cell \u001b[0;32mIn[7], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mwinter\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_user_details\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mrdstein@caltech.edu\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43man-incorrect-password\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moverwrite\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m~/Code/winterapi/winterapi/messenger.py:160\u001b[0m, in \u001b[0;36mWinterAPI.add_user_details\u001b[0;34m(self, user, password, overwrite)\u001b[0m\n\u001b[1;32m 157\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m password \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 158\u001b[0m password \u001b[38;5;241m=\u001b[39m getpass\u001b[38;5;241m.\u001b[39mgetpass(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mEnter password for user \u001b[39m\u001b[38;5;132;01m{\u001b[39;00muser\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m: \u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m--> 160\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcheck_user_details\u001b[49m\u001b[43m(\u001b[49m\u001b[43muser\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43muser\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpassword\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mpassword\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 162\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfidelius\u001b[38;5;241m.\u001b[39mset_user(user\u001b[38;5;241m=\u001b[39muser, password\u001b[38;5;241m=\u001b[39mpassword, overwrite\u001b[38;5;241m=\u001b[39moverwrite)\n",
"File \u001b[0;32m~/Code/winterapi/winterapi/messenger.py:172\u001b[0m, in \u001b[0;36mWinterAPI.check_user_details\u001b[0;34m(self, user, password)\u001b[0m\n\u001b[1;32m 164\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcheck_user_details\u001b[39m(\u001b[38;5;28mself\u001b[39m, user: \u001b[38;5;28mstr\u001b[39m, password: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m requests\u001b[38;5;241m.\u001b[39mResponse:\n\u001b[1;32m 165\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 166\u001b[0m \u001b[38;5;124;03m Check the user details are correct.\u001b[39;00m\n\u001b[1;32m 167\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 170\u001b[0m \u001b[38;5;124;03m :return: API response\u001b[39;00m\n\u001b[1;32m 171\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 172\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[43murl\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mUSER_URL\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mauth\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43muser\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpassword\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m~/anaconda3/envs/winterapi/lib/python3.11/site-packages/backoff/_sync.py:105\u001b[0m, in \u001b[0;36mretry_exception..retry\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 96\u001b[0m details \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 97\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtarget\u001b[39m\u001b[38;5;124m\"\u001b[39m: target,\n\u001b[1;32m 98\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124margs\u001b[39m\u001b[38;5;124m\"\u001b[39m: args,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 101\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124melapsed\u001b[39m\u001b[38;5;124m\"\u001b[39m: elapsed,\n\u001b[1;32m 102\u001b[0m }\n\u001b[1;32m 104\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 105\u001b[0m ret \u001b[38;5;241m=\u001b[39m \u001b[43mtarget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 106\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m exception \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 107\u001b[0m max_tries_exceeded \u001b[38;5;241m=\u001b[39m (tries \u001b[38;5;241m==\u001b[39m max_tries_value)\n",
@@ -181,46 +182,23 @@
},
{
"cell_type": "code",
- "execution_count": 7,
+ "execution_count": null,
"id": "b5d1e0d3",
"metadata": {},
"outputs": [],
"source": [
- "winter.add_program(\"2020A000\", \"a-secure-api-key\")\n",
- "winter.add_program(\"2020B000\", \"other-secure-api-key\")"
+ "winter.add_program(\"202XA000\", \"an-api-key\")\n",
+ "# winter.add_program(\"2020B000\", \"other-secure-api-key\")"
]
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": null,
"id": "a12a83db",
"metadata": {
"scrolled": true
},
- "outputs": [
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "API call failed with ': {\"success\":false,\"msg\":\"Failed to validate credentials provided.\"}'\n"
- ]
- },
- {
- "ename": "ValueError",
- "evalue": "API call failed with ': {\"success\":false,\"msg\":\"Failed to validate credentials provided.\"}'",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
- "Cell \u001b[0;32mIn[8], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mwinter\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_program\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m2022A000\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43ma-fake-api-key\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n",
- "File \u001b[0;32m~/Code/winterapi/winterapi/messenger.py:203\u001b[0m, in \u001b[0;36mWinterAPI.add_program\u001b[0;34m(self, program_name, program_api_key, overwrite)\u001b[0m\n\u001b[1;32m 198\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m program_api_key \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 199\u001b[0m program_api_key \u001b[38;5;241m=\u001b[39m getpass\u001b[38;5;241m.\u001b[39mgetpass(\n\u001b[1;32m 200\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mEnter password for user \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mprogram_name\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m: \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 201\u001b[0m )\n\u001b[0;32m--> 203\u001b[0m res \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcheck_program_details\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 204\u001b[0m \u001b[43m \u001b[49m\u001b[43mprogram_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mprogram_name\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 205\u001b[0m \u001b[43m \u001b[49m\u001b[43mprogram_api_key\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mprogram_api_key\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 206\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 208\u001b[0m program_dict \u001b[38;5;241m=\u001b[39m res\u001b[38;5;241m.\u001b[39mjson()[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mbody\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n\u001b[1;32m 209\u001b[0m program_dict[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mprog_key\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m program_api_key\n",
- "File \u001b[0;32m~/Code/winterapi/winterapi/messenger.py:223\u001b[0m, in \u001b[0;36mWinterAPI.check_program_details\u001b[0;34m(self, program_name, program_api_key)\u001b[0m\n\u001b[1;32m 213\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcheck_program_details\u001b[39m(\n\u001b[1;32m 214\u001b[0m \u001b[38;5;28mself\u001b[39m, program_name: \u001b[38;5;28mstr\u001b[39m, program_api_key: \u001b[38;5;28mstr\u001b[39m\n\u001b[1;32m 215\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m requests\u001b[38;5;241m.\u001b[39mResponse:\n\u001b[1;32m 216\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 217\u001b[0m \u001b[38;5;124;03m Check program details are correct.\u001b[39;00m\n\u001b[1;32m 218\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 221\u001b[0m \u001b[38;5;124;03m :return: API response\u001b[39;00m\n\u001b[1;32m 222\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 223\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 224\u001b[0m \u001b[43m \u001b[49m\u001b[43mPROGRAM_URL\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprogram_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mprogram_name\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mprogram_api_key\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mprogram_api_key\u001b[49m\n\u001b[1;32m 225\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n",
- "File \u001b[0;32m~/anaconda3/envs/winterapi/lib/python3.11/site-packages/backoff/_sync.py:105\u001b[0m, in \u001b[0;36mretry_exception..retry\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 96\u001b[0m details \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 97\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtarget\u001b[39m\u001b[38;5;124m\"\u001b[39m: target,\n\u001b[1;32m 98\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124margs\u001b[39m\u001b[38;5;124m\"\u001b[39m: args,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 101\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124melapsed\u001b[39m\u001b[38;5;124m\"\u001b[39m: elapsed,\n\u001b[1;32m 102\u001b[0m }\n\u001b[1;32m 104\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 105\u001b[0m ret \u001b[38;5;241m=\u001b[39m \u001b[43mtarget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 106\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m exception \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 107\u001b[0m max_tries_exceeded \u001b[38;5;241m=\u001b[39m (tries \u001b[38;5;241m==\u001b[39m max_tries_value)\n",
- "File \u001b[0;32m~/Code/winterapi/winterapi/messenger.py:87\u001b[0m, in \u001b[0;36mWinterAPI.get\u001b[0;34m(self, url, auth, **kwargs)\u001b[0m\n\u001b[1;32m 85\u001b[0m err \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAPI call failed with \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mres\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mres\u001b[38;5;241m.\u001b[39mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 86\u001b[0m logger\u001b[38;5;241m.\u001b[39merror(err)\n\u001b[0;32m---> 87\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(err)\n\u001b[1;32m 88\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m res\n",
- "\u001b[0;31mValueError\u001b[0m: API call failed with ': {\"success\":false,\"msg\":\"Failed to validate credentials provided.\"}'"
- ]
- }
- ],
+ "outputs": [],
"source": [
"winter.add_program(\"2022A000\", \"a-fake-api-key\")"
]
diff --git a/notebooks/Info_2a_ToO_Parameters.ipynb b/notebooks/Info_2a_ToO_Parameters.ipynb
new file mode 100644
index 0000000..106571f
--- /dev/null
+++ b/notebooks/Info_2a_ToO_Parameters.ipynb
@@ -0,0 +1,600 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "d331f783",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import logging\n",
+ "from IPython.display import JSON\n",
+ "import json\n",
+ "from winterapi import WinterAPI\n",
+ "from wintertoo.models import SummerFieldToO, SummerRaDecToO, WinterFieldToO, WinterRaDecToO"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "68657fec",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "logging.getLogger(\"winterapi\").setLevel(\"DEBUG\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "75c8a14e",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "winter = WinterAPI()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bd4d474c",
+ "metadata": {},
+ "source": [
+ "Our credentials from the previous notebook will still be active!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "eb5f0374",
+ "metadata": {},
+ "source": [
+ "# Setting up a ToO"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e6a15b09",
+ "metadata": {},
+ "source": [
+ "Now we are going to set up a ToO. There are two ways to trigger a ToO:\n",
+ "* Using a ra/dec value\n",
+ "* Using a field value\n",
+ "\n",
+ "There are also two types of instruments to trigger: WINTER or SUMMER. \n",
+ "\n",
+ "That makes **4 different ToO objects to choose from*.\n",
+ "\n",
+ "Let's go through the procedure for a Summer ToO using a field."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "504be7f4",
+ "metadata": {},
+ "source": [
+ "## Step 1: What can go into a ToO request?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3a212a51",
+ "metadata": {},
+ "source": [
+ "For `winterapi`, we handle data using `pydantic`. We specify what types of data can be provided, what the conditions are, and what the default values are.\n",
+ "\n",
+ "You can see all options in a human-readable way by converting the data model to a json schema:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "15e67d82",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{\n",
+ " \"additionalProperties\": false,\n",
+ " \"description\": \"Winter ToO Request with field\",\n",
+ " \"properties\": {\n",
+ " \"field_id\": {\n",
+ " \"minimum\": 1,\n",
+ " \"title\": \"Field ID\",\n",
+ " \"type\": \"integer\"\n",
+ " },\n",
+ " \"filters\": {\n",
+ " \"default\": [\n",
+ " \"Y\",\n",
+ " \"J\",\n",
+ " \"Hs\"\n",
+ " ],\n",
+ " \"items\": {\n",
+ " \"enum\": [\n",
+ " \"dark\",\n",
+ " \"Y\",\n",
+ " \"J\",\n",
+ " \"Hs\"\n",
+ " ],\n",
+ " \"type\": \"string\"\n",
+ " },\n",
+ " \"title\": \"Filters\",\n",
+ " \"type\": \"array\"\n",
+ " },\n",
+ " \"target_priority\": {\n",
+ " \"default\": 50.0,\n",
+ " \"minimum\": 0.0,\n",
+ " \"title\": \"Priority for target\",\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " \"t_exp\": {\n",
+ " \"default\": 30.0,\n",
+ " \"minimum\": 1.0,\n",
+ " \"title\": \"Combined Exposure Time across dithers (s)\",\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " \"n_exp\": {\n",
+ " \"default\": 1,\n",
+ " \"minimum\": 1,\n",
+ " \"title\": \"Number of dither sets\",\n",
+ " \"type\": \"integer\"\n",
+ " },\n",
+ " \"n_dither\": {\n",
+ " \"default\": 1,\n",
+ " \"minimum\": 1,\n",
+ " \"title\": \"Number of dithers\",\n",
+ " \"type\": \"integer\"\n",
+ " },\n",
+ " \"dither_distance\": {\n",
+ " \"default\": 30.0,\n",
+ " \"minimum\": 0.0,\n",
+ " \"title\": \"dither distance (arcsec)\",\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " \"start_time_mjd\": {\n",
+ " \"anyOf\": [\n",
+ " {\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " {\n",
+ " \"type\": \"null\"\n",
+ " }\n",
+ " ],\n",
+ " \"default\": 60341.0835267944,\n",
+ " \"title\": \"ToO validity start (MJD)\"\n",
+ " },\n",
+ " \"end_time_mjd\": {\n",
+ " \"anyOf\": [\n",
+ " {\n",
+ " \"minimum\": 60341.07352680047,\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " {\n",
+ " \"type\": \"null\"\n",
+ " }\n",
+ " ],\n",
+ " \"default\": 60342.07352679921,\n",
+ " \"title\": \"ToO validity end (MJD)\"\n",
+ " },\n",
+ " \"max_airmass\": {\n",
+ " \"anyOf\": [\n",
+ " {\n",
+ " \"maximum\": 5,\n",
+ " \"minimum\": 1,\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " {\n",
+ " \"type\": \"null\"\n",
+ " }\n",
+ " ],\n",
+ " \"default\": 2.0,\n",
+ " \"title\": \"Allowed airmass range\"\n",
+ " }\n",
+ " },\n",
+ " \"required\": [\n",
+ " \"field_id\"\n",
+ " ],\n",
+ " \"title\": \"WinterFieldToO\",\n",
+ " \"type\": \"object\"\n",
+ "}\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(json.dumps(WinterFieldToO.model_json_schema(), indent=2))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "56fceaf1",
+ "metadata": {},
+ "source": [
+ "There is a lot of information, but the most important line is right at the bottom. The only thing that is required is `field_id`. Everything else is optional.\n",
+ "\n",
+ "We can initialise the ToO using a random field number:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "3dcfcdae",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "WinterFieldToO(field_id=55, filters=['Y', 'J', 'Hs'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=30.0, start_time_mjd=60341.0835267944, end_time_mjd=60342.07352679921, max_airmass=2.0)"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "too = WinterFieldToO(field_id=55)\n",
+ "too"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "43a49362",
+ "metadata": {},
+ "source": [
+ "As you can see, we got a full ToO request with sensible defaults. If we only wanted one filter rather than 3, we could specify this:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "6605d149",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "WinterFieldToO(field_id=55, filters=['J'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=30.0, start_time_mjd=60341.0835267944, end_time_mjd=60342.07352679921, max_airmass=2.0)"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "too = WinterFieldToO(field_id=55, filters=[\"J\"])\n",
+ "too"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "54ef13e4",
+ "metadata": {},
+ "source": [
+ "Pydantic also validates the data we enter, to make sure things are sensible. Here are some examples of things you can't do:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "217812b9",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ValidationError",
+ "evalue": "1 validation error for WinterFieldToO\nfilters.0\n Input should be 'dark', 'Y', 'J' or 'Hs' [type=literal_error, input_value='V', input_type=str]\n For further information visit https://errors.pydantic.dev/2.3/v/literal_error",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[7], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Names a filter that isn't available\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m too \u001b[38;5;241m=\u001b[39m \u001b[43mWinterFieldToO\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfield_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m55\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mfilters\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mV\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3\u001b[0m too\n",
+ "File \u001b[0;32m~/anaconda3/envs/winterapi/lib/python3.11/site-packages/pydantic/main.py:165\u001b[0m, in \u001b[0;36mBaseModel.__init__\u001b[0;34m(__pydantic_self__, **data)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[38;5;66;03m# `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks\u001b[39;00m\n\u001b[1;32m 164\u001b[0m __tracebackhide__ \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[0;32m--> 165\u001b[0m \u001b[43m__pydantic_self__\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__pydantic_validator__\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mvalidate_python\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mself_instance\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m__pydantic_self__\u001b[49m\u001b[43m)\u001b[49m\n",
+ "\u001b[0;31mValidationError\u001b[0m: 1 validation error for WinterFieldToO\nfilters.0\n Input should be 'dark', 'Y', 'J' or 'Hs' [type=literal_error, input_value='V', input_type=str]\n For further information visit https://errors.pydantic.dev/2.3/v/literal_error"
+ ]
+ }
+ ],
+ "source": [
+ "# Names a filter that isn't available\n",
+ "too = WinterFieldToO(field_id=55, filters=[\"V\"])\n",
+ "too"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "00b582dd",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ValidationError",
+ "evalue": "1 validation error for WinterFieldToO\nend_time_mjd\n Input should be greater than or equal to 60341.07352680047 [type=greater_than_equal, input_value=58000.0, input_type=float]\n For further information visit https://errors.pydantic.dev/2.3/v/greater_than_equal",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[8], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# end time in the past\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m too \u001b[38;5;241m=\u001b[39m \u001b[43mWinterFieldToO\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfield_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m55\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mend_time_mjd\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m58000.\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3\u001b[0m too\n",
+ "File \u001b[0;32m~/anaconda3/envs/winterapi/lib/python3.11/site-packages/pydantic/main.py:165\u001b[0m, in \u001b[0;36mBaseModel.__init__\u001b[0;34m(__pydantic_self__, **data)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[38;5;66;03m# `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks\u001b[39;00m\n\u001b[1;32m 164\u001b[0m __tracebackhide__ \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[0;32m--> 165\u001b[0m \u001b[43m__pydantic_self__\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__pydantic_validator__\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mvalidate_python\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mself_instance\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m__pydantic_self__\u001b[49m\u001b[43m)\u001b[49m\n",
+ "\u001b[0;31mValidationError\u001b[0m: 1 validation error for WinterFieldToO\nend_time_mjd\n Input should be greater than or equal to 60341.07352680047 [type=greater_than_equal, input_value=58000.0, input_type=float]\n For further information visit https://errors.pydantic.dev/2.3/v/greater_than_equal"
+ ]
+ }
+ ],
+ "source": [
+ "# end time in the past\n",
+ "too = WinterFieldToO(field_id=55, end_time_mjd=58000.)\n",
+ "too"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "7133e738",
+ "metadata": {},
+ "outputs": [
+ {
+ "ename": "ValidationError",
+ "evalue": "1 validation error for WinterFieldToO\nn_dither\n Input should be greater than or equal to 1 [type=greater_than_equal, input_value=0, input_type=int]\n For further information visit https://errors.pydantic.dev/2.3/v/greater_than_equal",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)",
+ "Cell \u001b[0;32mIn[9], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Chooses a nonsensical n_dither number\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m too \u001b[38;5;241m=\u001b[39m \u001b[43mWinterFieldToO\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfield_id\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m55\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mn_dither\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3\u001b[0m too\n",
+ "File \u001b[0;32m~/anaconda3/envs/winterapi/lib/python3.11/site-packages/pydantic/main.py:165\u001b[0m, in \u001b[0;36mBaseModel.__init__\u001b[0;34m(__pydantic_self__, **data)\u001b[0m\n\u001b[1;32m 163\u001b[0m \u001b[38;5;66;03m# `__tracebackhide__` tells pytest and some other tools to omit this function from tracebacks\u001b[39;00m\n\u001b[1;32m 164\u001b[0m __tracebackhide__ \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[0;32m--> 165\u001b[0m \u001b[43m__pydantic_self__\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__pydantic_validator__\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mvalidate_python\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdata\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mself_instance\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m__pydantic_self__\u001b[49m\u001b[43m)\u001b[49m\n",
+ "\u001b[0;31mValidationError\u001b[0m: 1 validation error for WinterFieldToO\nn_dither\n Input should be greater than or equal to 1 [type=greater_than_equal, input_value=0, input_type=int]\n For further information visit https://errors.pydantic.dev/2.3/v/greater_than_equal"
+ ]
+ }
+ ],
+ "source": [
+ "# Chooses a nonsensical n_dither number\n",
+ "too = WinterFieldToO(field_id=55, n_dither=0)\n",
+ "too"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1371556c",
+ "metadata": {},
+ "source": [
+ "## Step 2 Choosing a ToO using ra/dec"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7614d0d0",
+ "metadata": {},
+ "source": [
+ "If you know the field to observe, then you have all the information you need, because each grid has a unique ra/dec value for that field.\n",
+ "The API will look that value up, so you do not need to worry about it.\n",
+ "\n",
+ "However, more often, if you are performing a ToO, it's because you know the ra/dec of a specific object.\n",
+ "\n",
+ "In that case, we can use a Ra/Dec model. Here's one with Winter:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "8f56c276",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{\n",
+ " \"additionalProperties\": false,\n",
+ " \"description\": \"Winter ToO Request with Ra/Dec\",\n",
+ " \"properties\": {\n",
+ " \"ra_deg\": {\n",
+ " \"example\": 180.0,\n",
+ " \"maximum\": 360.0,\n",
+ " \"minimum\": 0.0,\n",
+ " \"title\": \"Right ascension in decimal degrees\",\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " \"dec_deg\": {\n",
+ " \"example\": 0.0,\n",
+ " \"maximum\": 90.0,\n",
+ " \"minimum\": -90.0,\n",
+ " \"title\": \"Declination in decimal degrees\",\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " \"use_field_grid\": {\n",
+ " \"default\": true,\n",
+ " \"title\": \"boolean whether to select nearest field in grid for central ra/dec\",\n",
+ " \"type\": \"boolean\"\n",
+ " },\n",
+ " \"filters\": {\n",
+ " \"default\": [\n",
+ " \"Y\",\n",
+ " \"J\",\n",
+ " \"Hs\"\n",
+ " ],\n",
+ " \"items\": {\n",
+ " \"enum\": [\n",
+ " \"dark\",\n",
+ " \"Y\",\n",
+ " \"J\",\n",
+ " \"Hs\"\n",
+ " ],\n",
+ " \"type\": \"string\"\n",
+ " },\n",
+ " \"title\": \"Filters\",\n",
+ " \"type\": \"array\"\n",
+ " },\n",
+ " \"target_priority\": {\n",
+ " \"default\": 50.0,\n",
+ " \"minimum\": 0.0,\n",
+ " \"title\": \"Priority for target\",\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " \"t_exp\": {\n",
+ " \"default\": 30.0,\n",
+ " \"minimum\": 1.0,\n",
+ " \"title\": \"Combined Exposure Time across dithers (s)\",\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " \"n_exp\": {\n",
+ " \"default\": 1,\n",
+ " \"minimum\": 1,\n",
+ " \"title\": \"Number of dither sets\",\n",
+ " \"type\": \"integer\"\n",
+ " },\n",
+ " \"n_dither\": {\n",
+ " \"default\": 1,\n",
+ " \"minimum\": 1,\n",
+ " \"title\": \"Number of dithers\",\n",
+ " \"type\": \"integer\"\n",
+ " },\n",
+ " \"dither_distance\": {\n",
+ " \"default\": 30.0,\n",
+ " \"minimum\": 0.0,\n",
+ " \"title\": \"dither distance (arcsec)\",\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " \"start_time_mjd\": {\n",
+ " \"anyOf\": [\n",
+ " {\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " {\n",
+ " \"type\": \"null\"\n",
+ " }\n",
+ " ],\n",
+ " \"default\": 60341.0835267944,\n",
+ " \"title\": \"ToO validity start (MJD)\"\n",
+ " },\n",
+ " \"end_time_mjd\": {\n",
+ " \"anyOf\": [\n",
+ " {\n",
+ " \"minimum\": 60341.07352680047,\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " {\n",
+ " \"type\": \"null\"\n",
+ " }\n",
+ " ],\n",
+ " \"default\": 60342.07352679921,\n",
+ " \"title\": \"ToO validity end (MJD)\"\n",
+ " },\n",
+ " \"max_airmass\": {\n",
+ " \"anyOf\": [\n",
+ " {\n",
+ " \"maximum\": 5,\n",
+ " \"minimum\": 1,\n",
+ " \"type\": \"number\"\n",
+ " },\n",
+ " {\n",
+ " \"type\": \"null\"\n",
+ " }\n",
+ " ],\n",
+ " \"default\": 2.0,\n",
+ " \"title\": \"Allowed airmass range\"\n",
+ " }\n",
+ " },\n",
+ " \"required\": [\n",
+ " \"ra_deg\",\n",
+ " \"dec_deg\"\n",
+ " ],\n",
+ " \"title\": \"WinterRaDecToO\",\n",
+ " \"type\": \"object\"\n",
+ "}\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(json.dumps(WinterRaDecToO.model_json_schema(), indent=2))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cc4aba3a",
+ "metadata": {},
+ "source": [
+ "In this case, we only need to provide the ra and dec:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "266c0940",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "WinterRaDecToO(ra_deg=300.0, dec_deg=51.0, use_field_grid=True, filters=['Y', 'J', 'Hs'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=30.0, start_time_mjd=60341.0835267944, end_time_mjd=60342.07352679921, max_airmass=2.0)"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "too = WinterRaDecToO(ra_deg=300., dec_deg=51.)\n",
+ "too"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5bdf48c2",
+ "metadata": {},
+ "source": [
+ "**One important note: by default, a schedule with an ra/dec will be matched to the nearest field, and the exposure will be centered on that field RA/dec**\n",
+ " \n",
+ "You can disable this behaviour by setting `use_field_grid` to false! "
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "42a4c48c",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "WinterRaDecToO(ra_deg=300.0, dec_deg=51.0, use_field_grid=False, filters=['Y', 'J', 'Hs'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=30.0, start_time_mjd=60341.0835267944, end_time_mjd=60342.07352679921, max_airmass=2.0)"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "too = WinterRaDecToO(ra_deg=300., dec_deg=51., use_field_grid=False)\n",
+ "too"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4c0bada9",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "winterapi",
+ "language": "python",
+ "name": "winterapi"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.3"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/notebooks/2_submitting_toos.ipynb b/notebooks/Info_2b_Submitting_ToOs.ipynb
similarity index 57%
rename from notebooks/2_submitting_toos.ipynb
rename to notebooks/Info_2b_Submitting_ToOs.ipynb
index 59b2bc9..4bccffd 100644
--- a/notebooks/2_submitting_toos.ipynb
+++ b/notebooks/Info_2b_Submitting_ToOs.ipynb
@@ -10,7 +10,7 @@
"import logging\n",
"import pandas as pd\n",
"from winterapi import WinterAPI\n",
- "from wintertoo.models import SummerFieldToO, SummerRaDecToO, WinterFieldToO, WinterRaDecToO"
+ "from wintertoo.models import WinterFieldToO, WinterRaDecToO"
]
},
{
@@ -58,8 +58,8 @@
{
"data": {
"text/plain": [
- "[SummerFieldToO(field_id=55, filters=['u', 'g', 'r', 'i'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=15.0, start_time_mjd=60103.72832172684, end_time_mjd=60104.71832173089, max_airmass=2.0),\n",
- " SummerFieldToO(field_id=56, filters=['u', 'g', 'r', 'i'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=15.0, start_time_mjd=60103.72832172684, end_time_mjd=60104.71832173089, max_airmass=2.0)]"
+ "[WinterFieldToO(field_id=55, filters=['Y', 'J', 'Hs'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=30.0, start_time_mjd=60341.08759327358, end_time_mjd=60342.077593278416, max_airmass=2.0),\n",
+ " WinterFieldToO(field_id=56, filters=['Y', 'J', 'Hs'], target_priority=50.0, t_exp=30.0, n_exp=1, n_dither=1, dither_distance=30.0, start_time_mjd=60341.08759327358, end_time_mjd=60342.077593278416, max_airmass=2.0)]"
]
},
"execution_count": 4,
@@ -68,8 +68,8 @@
}
],
"source": [
- "too_1 = SummerFieldToO(field_id=55)\n",
- "too_2 = SummerFieldToO(field_id=56)\n",
+ "too_1 = WinterFieldToO(field_id=55)\n",
+ "too_2 = WinterFieldToO(field_id=56)\n",
"\n",
"too_list = [too_1, too_2]\n",
"too_list"
@@ -103,7 +103,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
- "Available programs: ['2020A000', '2020B000']\n"
+ "Available programs: ['202XA000']\n"
]
}
],
@@ -121,23 +121,12 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": null,
"id": "f534541c",
"metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "Program(progname='2020A000', prog_key='a-secure-api-key', puid=None, progid=1, pi_name='Stein', pi_email='rdstein@caltech.edu', startdate=datetime.date(2023, 5, 1), enddate=datetime.date(2024, 12, 31), hours_allocated=10.0, hours_remaining=10.0, maxpriority=150.0, progtitle='\"Dummy program 1\"')"
- ]
- },
- "execution_count": 6,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
+ "outputs": [],
"source": [
- "winter.get_program_details(\"2020A000\")"
+ "winter.get_program_details(\"202XA000\")"
]
},
{
@@ -197,189 +186,145 @@
" \n",
" 0 | \n",
" 259.2 | \n",
- " 88.9593 | \n",
+ " 86.0 | \n",
" 55 | \n",
- " u | \n",
+ " Y | \n",
" 30.0 | \n",
" 50.0 | \n",
" Stein | \n",
- " 2020A000 | \n",
+ " 202XA000 | \n",
" 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
+ " 60341.087593 | \n",
+ " 60342.077593 | \n",
" False | \n",
" 2.0 | \n",
" 1 | \n",
- " 15.0 | \n",
+ " 30.0 | \n",
" 0 | \n",
"
\n",
" \n",
" 1 | \n",
" 259.2 | \n",
- " 88.9593 | \n",
+ " 86.0 | \n",
" 55 | \n",
- " g | \n",
+ " J | \n",
" 30.0 | \n",
" 50.0 | \n",
" Stein | \n",
- " 2020A000 | \n",
+ " 202XA000 | \n",
" 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
+ " 60341.087593 | \n",
+ " 60342.077593 | \n",
" False | \n",
" 2.0 | \n",
" 1 | \n",
- " 15.0 | \n",
+ " 30.0 | \n",
" 1 | \n",
"
\n",
" \n",
" 2 | \n",
" 259.2 | \n",
- " 88.9593 | \n",
+ " 86.0 | \n",
" 55 | \n",
- " r | \n",
+ " Hs | \n",
" 30.0 | \n",
" 50.0 | \n",
" Stein | \n",
- " 2020A000 | \n",
+ " 202XA000 | \n",
" 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
+ " 60341.087593 | \n",
+ " 60342.077593 | \n",
" False | \n",
" 2.0 | \n",
" 1 | \n",
- " 15.0 | \n",
+ " 30.0 | \n",
" 2 | \n",
"
\n",
" \n",
" 3 | \n",
- " 259.2 | \n",
- " 88.9593 | \n",
- " 55 | \n",
- " i | \n",
+ " 273.6 | \n",
+ " 86.0 | \n",
+ " 56 | \n",
+ " Y | \n",
" 30.0 | \n",
" 50.0 | \n",
" Stein | \n",
- " 2020A000 | \n",
+ " 202XA000 | \n",
" 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
+ " 60341.087593 | \n",
+ " 60342.077593 | \n",
" False | \n",
" 2.0 | \n",
" 1 | \n",
- " 15.0 | \n",
+ " 30.0 | \n",
" 3 | \n",
"
\n",
" \n",
" 4 | \n",
" 273.6 | \n",
- " 88.9593 | \n",
+ " 86.0 | \n",
" 56 | \n",
- " u | \n",
+ " J | \n",
" 30.0 | \n",
" 50.0 | \n",
" Stein | \n",
- " 2020A000 | \n",
+ " 202XA000 | \n",
" 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
+ " 60341.087593 | \n",
+ " 60342.077593 | \n",
" False | \n",
" 2.0 | \n",
" 1 | \n",
- " 15.0 | \n",
+ " 30.0 | \n",
" 4 | \n",
"
\n",
" \n",
" 5 | \n",
" 273.6 | \n",
- " 88.9593 | \n",
+ " 86.0 | \n",
" 56 | \n",
- " g | \n",
+ " Hs | \n",
" 30.0 | \n",
" 50.0 | \n",
" Stein | \n",
- " 2020A000 | \n",
+ " 202XA000 | \n",
" 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
+ " 60341.087593 | \n",
+ " 60342.077593 | \n",
" False | \n",
" 2.0 | \n",
" 1 | \n",
- " 15.0 | \n",
- " 5 | \n",
- "
\n",
- " \n",
- " 6 | \n",
- " 273.6 | \n",
- " 88.9593 | \n",
- " 56 | \n",
- " r | \n",
" 30.0 | \n",
- " 50.0 | \n",
- " Stein | \n",
- " 2020A000 | \n",
- " 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
- " False | \n",
- " 2.0 | \n",
- " 1 | \n",
- " 15.0 | \n",
- " 6 | \n",
- "
\n",
- " \n",
- " 7 | \n",
- " 273.6 | \n",
- " 88.9593 | \n",
- " 56 | \n",
- " i | \n",
- " 30.0 | \n",
- " 50.0 | \n",
- " Stein | \n",
- " 2020A000 | \n",
- " 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
- " False | \n",
- " 2.0 | \n",
- " 1 | \n",
- " 15.0 | \n",
- " 7 | \n",
+ " 5 | \n",
"
\n",
" \n",
"\n",
""
],
"text/plain": [
- " raDeg decDeg fieldID filter visitExpTime priority progPI progName \\\n",
- "0 259.2 88.9593 55 u 30.0 50.0 Stein 2020A000 \n",
- "1 259.2 88.9593 55 g 30.0 50.0 Stein 2020A000 \n",
- "2 259.2 88.9593 55 r 30.0 50.0 Stein 2020A000 \n",
- "3 259.2 88.9593 55 i 30.0 50.0 Stein 2020A000 \n",
- "4 273.6 88.9593 56 u 30.0 50.0 Stein 2020A000 \n",
- "5 273.6 88.9593 56 g 30.0 50.0 Stein 2020A000 \n",
- "6 273.6 88.9593 56 r 30.0 50.0 Stein 2020A000 \n",
- "7 273.6 88.9593 56 i 30.0 50.0 Stein 2020A000 \n",
+ " raDeg decDeg fieldID filter visitExpTime priority progPI progName \\\n",
+ "0 259.2 86.0 55 Y 30.0 50.0 Stein 202XA000 \n",
+ "1 259.2 86.0 55 J 30.0 50.0 Stein 202XA000 \n",
+ "2 259.2 86.0 55 Hs 30.0 50.0 Stein 202XA000 \n",
+ "3 273.6 86.0 56 Y 30.0 50.0 Stein 202XA000 \n",
+ "4 273.6 86.0 56 J 30.0 50.0 Stein 202XA000 \n",
+ "5 273.6 86.0 56 Hs 30.0 50.0 Stein 202XA000 \n",
"\n",
" progID validStart validStop observed maxAirmass ditherNumber \\\n",
- "0 1 60103.728322 60104.718322 False 2.0 1 \n",
- "1 1 60103.728322 60104.718322 False 2.0 1 \n",
- "2 1 60103.728322 60104.718322 False 2.0 1 \n",
- "3 1 60103.728322 60104.718322 False 2.0 1 \n",
- "4 1 60103.728322 60104.718322 False 2.0 1 \n",
- "5 1 60103.728322 60104.718322 False 2.0 1 \n",
- "6 1 60103.728322 60104.718322 False 2.0 1 \n",
- "7 1 60103.728322 60104.718322 False 2.0 1 \n",
+ "0 1 60341.087593 60342.077593 False 2.0 1 \n",
+ "1 1 60341.087593 60342.077593 False 2.0 1 \n",
+ "2 1 60341.087593 60342.077593 False 2.0 1 \n",
+ "3 1 60341.087593 60342.077593 False 2.0 1 \n",
+ "4 1 60341.087593 60342.077593 False 2.0 1 \n",
+ "5 1 60341.087593 60342.077593 False 2.0 1 \n",
"\n",
" ditherStepSize obsHistID \n",
- "0 15.0 0 \n",
- "1 15.0 1 \n",
- "2 15.0 2 \n",
- "3 15.0 3 \n",
- "4 15.0 4 \n",
- "5 15.0 5 \n",
- "6 15.0 6 \n",
- "7 15.0 7 "
+ "0 30.0 0 \n",
+ "1 30.0 1 \n",
+ "2 30.0 2 \n",
+ "3 30.0 3 \n",
+ "4 30.0 4 \n",
+ "5 30.0 5 "
]
},
"execution_count": 7,
@@ -389,7 +334,7 @@
],
"source": [
"local_schedule = winter.build_schedule_locally(\n",
- " program_name=\"2020A000\",\n",
+ " program_name=\"202XA000\",\n",
" data=too_list\n",
")\n",
"local_schedule"
@@ -416,8 +361,8 @@
"metadata": {},
"outputs": [],
"source": [
- "api_res, api_schedule = winter.submit_too_summer(\n",
- " program_name=\"2020A000\",\n",
+ "api_res, api_schedule = winter.submit_too(\n",
+ " program_name=\"202XA000\",\n",
" data=too_list,\n",
" submit_trigger=False\n",
")"
@@ -480,189 +425,145 @@
" \n",
" 0 | \n",
" 259.2 | \n",
- " 88.9593 | \n",
+ " 86.0 | \n",
" 55 | \n",
- " u | \n",
+ " Y | \n",
" 30.0 | \n",
" 50.0 | \n",
" Stein | \n",
- " 2020A000 | \n",
+ " 202XA000 | \n",
" 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
+ " 60341.087593 | \n",
+ " 60342.077593 | \n",
" False | \n",
" 2.0 | \n",
" 1 | \n",
- " 15.0 | \n",
+ " 30.0 | \n",
" 0 | \n",
"
\n",
" \n",
" 1 | \n",
" 259.2 | \n",
- " 88.9593 | \n",
+ " 86.0 | \n",
" 55 | \n",
- " g | \n",
+ " J | \n",
" 30.0 | \n",
" 50.0 | \n",
" Stein | \n",
- " 2020A000 | \n",
+ " 202XA000 | \n",
" 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
+ " 60341.087593 | \n",
+ " 60342.077593 | \n",
" False | \n",
" 2.0 | \n",
" 1 | \n",
- " 15.0 | \n",
+ " 30.0 | \n",
" 1 | \n",
"
\n",
" \n",
" 2 | \n",
" 259.2 | \n",
- " 88.9593 | \n",
+ " 86.0 | \n",
" 55 | \n",
- " r | \n",
+ " Hs | \n",
" 30.0 | \n",
" 50.0 | \n",
" Stein | \n",
- " 2020A000 | \n",
+ " 202XA000 | \n",
" 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
+ " 60341.087593 | \n",
+ " 60342.077593 | \n",
" False | \n",
" 2.0 | \n",
" 1 | \n",
- " 15.0 | \n",
+ " 30.0 | \n",
" 2 | \n",
"
\n",
" \n",
" 3 | \n",
- " 259.2 | \n",
- " 88.9593 | \n",
- " 55 | \n",
- " i | \n",
+ " 273.6 | \n",
+ " 86.0 | \n",
+ " 56 | \n",
+ " Y | \n",
" 30.0 | \n",
" 50.0 | \n",
" Stein | \n",
- " 2020A000 | \n",
+ " 202XA000 | \n",
" 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
+ " 60341.087593 | \n",
+ " 60342.077593 | \n",
" False | \n",
" 2.0 | \n",
" 1 | \n",
- " 15.0 | \n",
+ " 30.0 | \n",
" 3 | \n",
"
\n",
" \n",
" 4 | \n",
" 273.6 | \n",
- " 88.9593 | \n",
+ " 86.0 | \n",
" 56 | \n",
- " u | \n",
+ " J | \n",
" 30.0 | \n",
" 50.0 | \n",
" Stein | \n",
- " 2020A000 | \n",
+ " 202XA000 | \n",
" 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
+ " 60341.087593 | \n",
+ " 60342.077593 | \n",
" False | \n",
" 2.0 | \n",
" 1 | \n",
- " 15.0 | \n",
+ " 30.0 | \n",
" 4 | \n",
"
\n",
" \n",
" 5 | \n",
" 273.6 | \n",
- " 88.9593 | \n",
+ " 86.0 | \n",
" 56 | \n",
- " g | \n",
+ " Hs | \n",
" 30.0 | \n",
" 50.0 | \n",
" Stein | \n",
- " 2020A000 | \n",
+ " 202XA000 | \n",
" 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
+ " 60341.087593 | \n",
+ " 60342.077593 | \n",
" False | \n",
" 2.0 | \n",
" 1 | \n",
- " 15.0 | \n",
- " 5 | \n",
- "
\n",
- " \n",
- " 6 | \n",
- " 273.6 | \n",
- " 88.9593 | \n",
- " 56 | \n",
- " r | \n",
" 30.0 | \n",
- " 50.0 | \n",
- " Stein | \n",
- " 2020A000 | \n",
- " 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
- " False | \n",
- " 2.0 | \n",
- " 1 | \n",
- " 15.0 | \n",
- " 6 | \n",
- "
\n",
- " \n",
- " 7 | \n",
- " 273.6 | \n",
- " 88.9593 | \n",
- " 56 | \n",
- " i | \n",
- " 30.0 | \n",
- " 50.0 | \n",
- " Stein | \n",
- " 2020A000 | \n",
- " 1 | \n",
- " 60103.728322 | \n",
- " 60104.718322 | \n",
- " False | \n",
- " 2.0 | \n",
- " 1 | \n",
- " 15.0 | \n",
- " 7 | \n",
+ " 5 | \n",
"
\n",
" \n",
"\n",
""
],
"text/plain": [
- " raDeg decDeg fieldID filter visitExpTime priority progPI progName \\\n",
- "0 259.2 88.9593 55 u 30.0 50.0 Stein 2020A000 \n",
- "1 259.2 88.9593 55 g 30.0 50.0 Stein 2020A000 \n",
- "2 259.2 88.9593 55 r 30.0 50.0 Stein 2020A000 \n",
- "3 259.2 88.9593 55 i 30.0 50.0 Stein 2020A000 \n",
- "4 273.6 88.9593 56 u 30.0 50.0 Stein 2020A000 \n",
- "5 273.6 88.9593 56 g 30.0 50.0 Stein 2020A000 \n",
- "6 273.6 88.9593 56 r 30.0 50.0 Stein 2020A000 \n",
- "7 273.6 88.9593 56 i 30.0 50.0 Stein 2020A000 \n",
+ " raDeg decDeg fieldID filter visitExpTime priority progPI progName \\\n",
+ "0 259.2 86.0 55 Y 30.0 50.0 Stein 202XA000 \n",
+ "1 259.2 86.0 55 J 30.0 50.0 Stein 202XA000 \n",
+ "2 259.2 86.0 55 Hs 30.0 50.0 Stein 202XA000 \n",
+ "3 273.6 86.0 56 Y 30.0 50.0 Stein 202XA000 \n",
+ "4 273.6 86.0 56 J 30.0 50.0 Stein 202XA000 \n",
+ "5 273.6 86.0 56 Hs 30.0 50.0 Stein 202XA000 \n",
"\n",
" progID validStart validStop observed maxAirmass ditherNumber \\\n",
- "0 1 60103.728322 60104.718322 False 2.0 1 \n",
- "1 1 60103.728322 60104.718322 False 2.0 1 \n",
- "2 1 60103.728322 60104.718322 False 2.0 1 \n",
- "3 1 60103.728322 60104.718322 False 2.0 1 \n",
- "4 1 60103.728322 60104.718322 False 2.0 1 \n",
- "5 1 60103.728322 60104.718322 False 2.0 1 \n",
- "6 1 60103.728322 60104.718322 False 2.0 1 \n",
- "7 1 60103.728322 60104.718322 False 2.0 1 \n",
+ "0 1 60341.087593 60342.077593 False 2.0 1 \n",
+ "1 1 60341.087593 60342.077593 False 2.0 1 \n",
+ "2 1 60341.087593 60342.077593 False 2.0 1 \n",
+ "3 1 60341.087593 60342.077593 False 2.0 1 \n",
+ "4 1 60341.087593 60342.077593 False 2.0 1 \n",
+ "5 1 60341.087593 60342.077593 False 2.0 1 \n",
"\n",
" ditherStepSize obsHistID \n",
- "0 15.0 0 \n",
- "1 15.0 1 \n",
- "2 15.0 2 \n",
- "3 15.0 3 \n",
- "4 15.0 4 \n",
- "5 15.0 5 \n",
- "6 15.0 6 \n",
- "7 15.0 7 "
+ "0 30.0 0 \n",
+ "1 30.0 1 \n",
+ "2 30.0 2 \n",
+ "3 30.0 3 \n",
+ "4 30.0 4 \n",
+ "5 30.0 5 "
]
},
"execution_count": 9,
@@ -697,8 +598,8 @@
"source": [
"# An example ToO that would submit for real!\n",
"#\n",
- "# api_res, api_schedule = winter.submit_too_summer(\n",
- "# program_name=\"2020A000\",\n",
+ "# api_res, api_schedule = winter.submit_too(\n",
+ "# program_name=\"202XA000\",\n",
"# data=too_list,\n",
"# submit_trigger=True\n",
"# )\n",
diff --git a/pyproject.toml b/pyproject.toml
index ff1496a..240caa6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "winterapi"
-version = "0.3.0"
+version = "1.0.0"
description = ""
authors = [
{name = "Robert Stein", email = "rdstein@caltech.edu"}
@@ -29,17 +29,18 @@ classifiers = [
]
dependencies = [
"pandas",
+ "packaging",
"keyring",
"cryptography",
"pre-commit",
"jupyter",
"backoff",
"pydantic",
- "wintertoo>=0.4.2"
+ "wintertoo>=1.2.0"
]
[project.optional-dependencies]
dev = [
- "black == 23.11.0",
+ "black == 24.1.1",
"isort == 5.13.0",
"pylint == 3.0.2",
"coveralls",
diff --git a/tests/test_login.py b/tests/test_login.py
index 502632b..fd40c4d 100644
--- a/tests/test_login.py
+++ b/tests/test_login.py
@@ -1,6 +1,7 @@
"""
Module for testing the API
"""
+
import logging
import time
import unittest
diff --git a/tests/test_schedule.py b/tests/test_schedule.py
index 6a70493..80115c6 100644
--- a/tests/test_schedule.py
+++ b/tests/test_schedule.py
@@ -1,6 +1,7 @@
"""
Test for schedule
"""
+
import logging
import os
import unittest
@@ -42,6 +43,7 @@ def test_ra_dec(self):
n_dither=9,
start_time_mjd=62721.1894969287,
end_time_mjd=62722.1894969452,
+ target_name="test_field",
)
too_radec = WinterRaDecToO(
@@ -50,6 +52,7 @@ def test_ra_dec(self):
start_time_mjd=62721.1894969287,
end_time_mjd=62722.1894969452,
use_field_grid=False,
+ target_name="test_radec",
)
too_list = [too_field, too_radec]
diff --git a/tests/testdata/test_schedule.csv b/tests/testdata/test_schedule.csv
index efedbdd..428fef9 100644
--- a/tests/testdata/test_schedule.csv
+++ b/tests/testdata/test_schedule.csv
@@ -1,7 +1,7 @@
-raDeg,decDeg,fieldID,filter,visitExpTime,priority,progPI,progName,progID,validStart,validStop,observed,maxAirmass,ditherNumber,ditherStepSize,obsHistID
-211.56398,54.0,3944,Y,30.0,50.0,Stein,2023A999,0,62721.1894969287,62722.1894969452,False,2.0,9,600.0,0
-211.56398,54.0,3944,J,30.0,50.0,Stein,2023A999,0,62721.1894969287,62722.1894969452,False,2.0,9,600.0,1
-211.56398,54.0,3944,Hs,30.0,50.0,Stein,2023A999,0,62721.1894969287,62722.1894969452,False,2.0,9,600.0,2
-210.910674637,54.3116510708,999999999,Y,30.0,50.0,Stein,2023A999,0,62721.1894969287,62722.1894969452,False,2.0,1,600.0,3
-210.910674637,54.3116510708,999999999,J,30.0,50.0,Stein,2023A999,0,62721.1894969287,62722.1894969452,False,2.0,1,600.0,4
-210.910674637,54.3116510708,999999999,Hs,30.0,50.0,Stein,2023A999,0,62721.1894969287,62722.1894969452,False,2.0,1,600.0,5
+targName,raDeg,decDeg,fieldID,filter,visitExpTime,priority,progPI,progName,progID,validStart,validStop,observed,maxAirmass,ditherNumber,ditherStepSize,obsHistID
+test_field,211.56398,54.0,3944,Y,30.0,50.0,Stein,2023A999,0,62721.1894969287,62722.1894969452,False,2.0,9,30.0,0
+test_field,211.56398,54.0,3944,J,30.0,50.0,Stein,2023A999,0,62721.1894969287,62722.1894969452,False,2.0,9,30.0,1
+test_field,211.56398,54.0,3944,Hs,30.0,50.0,Stein,2023A999,0,62721.1894969287,62722.1894969452,False,2.0,9,30.0,2
+test_radec,210.910674637,54.3116510708,999999999,Y,30.0,50.0,Stein,2023A999,0,62721.1894969287,62722.1894969452,False,2.0,1,30.0,3
+test_radec,210.910674637,54.3116510708,999999999,J,30.0,50.0,Stein,2023A999,0,62721.1894969287,62722.1894969452,False,2.0,1,30.0,4
+test_radec,210.910674637,54.3116510708,999999999,Hs,30.0,50.0,Stein,2023A999,0,62721.1894969287,62722.1894969452,False,2.0,1,30.0,5
diff --git a/winterapi/__init__.py b/winterapi/__init__.py
index 13a099e..3529da5 100644
--- a/winterapi/__init__.py
+++ b/winterapi/__init__.py
@@ -1,4 +1,5 @@
"""
WinterAPI is a Python toolkit for interacting with the Winter API.
"""
+
from winterapi.messenger import WinterAPI
diff --git a/winterapi/base_api.py b/winterapi/base_api.py
new file mode 100644
index 0000000..4d8437b
--- /dev/null
+++ b/winterapi/base_api.py
@@ -0,0 +1,192 @@
+"""
+Module with the base class for generic API interactions
+"""
+
+import json
+import logging
+import re
+from pathlib import Path
+
+import backoff
+import requests
+from pydantic import BaseModel
+
+logger = logging.getLogger(__name__)
+
+MAX_TIMEOUT = 30.0
+
+
+class BaseAPI:
+ """
+ Base class for interacting with the API
+ """
+
+ def get_auth(self):
+ """
+ Get the authentication details.
+
+ :return: Authentication details.
+ """
+ raise NotImplementedError
+
+ @staticmethod
+ def clean_data(data):
+ """
+ Clean the data for the API.
+
+ :param data: Data to clean.
+ :return: Cleaned data.
+ """
+
+ if isinstance(data, list):
+ convert = json.dumps([x.model_dump() for x in data])
+ elif isinstance(data, BaseModel):
+ convert = json.dumps([data.model_dump()])
+ else:
+ err = f"Unrecognised data type {type(data)}"
+ logger.error(err)
+ raise TypeError(err)
+
+ return convert
+
+ @backoff.on_exception(
+ backoff.expo, requests.exceptions.RequestException, max_time=MAX_TIMEOUT
+ )
+ def get(self, url, auth=None, data=None, **kwargs) -> requests.Response:
+ """
+ Run a get request.
+
+ :param url: URL to get.
+ :param auth: Authentication details.
+ :param data: Data to get.
+ :param kwargs: additional arguments for API.
+ :return: API response.
+ """
+ if auth is None:
+ auth = self.get_auth()
+
+ if data is not None:
+ data = self.clean_data(data)
+
+ res = requests.get(
+ url, data=data, auth=auth, params=kwargs, timeout=MAX_TIMEOUT
+ )
+
+ if res.status_code != 200:
+ err = f"API call failed with '{res}: {res.text}'"
+ logger.error(err)
+ raise ValueError(err)
+ return res
+
+ @backoff.on_exception(
+ backoff.expo, requests.exceptions.RequestException, max_time=MAX_TIMEOUT
+ )
+ def post(
+ self, url, data: BaseModel | list[BaseModel], auth=None, **kwargs
+ ) -> requests.Response:
+ """
+ Run a post request.
+
+ :param url: URL to post to.
+ :param data: Data to post.
+ :param auth: Authentication details.
+ :param kwargs: additional arguments for API.
+ :return: Response.
+ """
+ if auth is None:
+ auth = self.get_auth()
+
+ convert = self.clean_data(data)
+
+ res = requests.post(
+ url, data=convert, auth=auth, params=kwargs, timeout=MAX_TIMEOUT
+ )
+
+ if res.status_code != 200:
+ err = f"API call failed with '{res}: {res.text}'"
+ logger.error(err)
+ raise ValueError(err)
+ return res
+
+ @backoff.on_exception(
+ backoff.expo, requests.exceptions.RequestException, max_time=MAX_TIMEOUT
+ )
+ def delete(self, url, auth=None, **kwargs) -> requests.Response:
+ """
+ Run a delete request.
+
+ :param url: URL to post to.
+ :param auth: Authentication details.
+ :param kwargs: additional arguments for API.
+ :return: Response.
+ """
+ if auth is None:
+ auth = self.get_auth()
+
+ res = requests.delete(url, auth=auth, params=kwargs, timeout=MAX_TIMEOUT)
+
+ if res.status_code != 200:
+ err = f"API call failed with '{res}: {res.text}'"
+ logger.error(err)
+ raise ValueError(err)
+ return res
+
+ @backoff.on_exception(
+ backoff.expo, requests.exceptions.RequestException, max_time=MAX_TIMEOUT
+ )
+ def get_stream(
+ self, url, output_dir: str | Path | None = None, auth=None, data=None, **kwargs
+ ) -> tuple[requests.Response, Path]:
+ """
+ Run a get request.
+
+ :param url: URL to get.
+ :param output_dir: Directory to save the output.
+ :param auth: Authentication details.
+ :param kwargs: additional arguments for API.
+ :return: API response.
+ """
+ if auth is None:
+ auth = self.get_auth()
+
+ if data is not None:
+ data = self.clean_data(data)
+
+ if output_dir is None:
+ output_dir = Path.home()
+ logger.warning(f"No output directory specified, using {output_dir}")
+
+ if not isinstance(output_dir, Path):
+ output_dir = Path(output_dir)
+
+ if not output_dir.parent.exists():
+ output_dir.parent.mkdir(parents=True)
+
+ fname = "winterapi_output.zip"
+
+ with requests.Session() as session:
+
+ with session.get(
+ url,
+ data=data,
+ auth=auth,
+ params=kwargs,
+ timeout=MAX_TIMEOUT,
+ stream=True,
+ ) as resp:
+ header = resp.headers
+
+ if "Content-Disposition" in header.keys():
+ fname = re.findall("filename=(.+)", header["Content-Disposition"])[
+ 0
+ ]
+
+ output_path = output_dir.joinpath(fname)
+
+ with open(output_path, "wb") as output_f:
+ for chunk in resp.iter_content(chunk_size=8192):
+ output_f.write(chunk)
+
+ logger.info(f"Downloaded file to {output_path}")
+
+ return resp, output_path
diff --git a/winterapi/configure_tests.py b/winterapi/configure_tests.py
index b749ecb..b0f885c 100644
--- a/winterapi/configure_tests.py
+++ b/winterapi/configure_tests.py
@@ -1,6 +1,7 @@
"""
This script is used to configure the environment variables for the tests.
"""
+
import os
from winterapi import WinterAPI
diff --git a/winterapi/credentials.py b/winterapi/credentials.py
index 7b78e72..21853bb 100644
--- a/winterapi/credentials.py
+++ b/winterapi/credentials.py
@@ -1,6 +1,7 @@
"""
Module for credentials
"""
+
import base64
import json
import logging
diff --git a/winterapi/endpoints.py b/winterapi/endpoints.py
index 7d9486c..3472459 100644
--- a/winterapi/endpoints.py
+++ b/winterapi/endpoints.py
@@ -1,10 +1,19 @@
"""
Module for storing the endpoints for the API.
"""
-BASE_URL = "http://127.0.0.1:7000"
-BASE_URL = "http://winter.caltech.edu:82"
+
+import os
+
+run_local = os.getenv("WINTER_API_LOCAL", "0") in ["True", "true", "1"]
+BASE_URL = "http://127.0.0.1:7000" if run_local else "http://winter.caltech.edu:82"
PING_URL = BASE_URL + "/ping"
+VERSION_URL = BASE_URL + "/validation/version"
USER_URL = BASE_URL + "/validation/user"
PROGRAM_URL = BASE_URL + "/validation/program"
WINTER_TOO_URL = BASE_URL + "/too/winter"
SUMMER_TOO_URL = BASE_URL + "/too/summer"
+SCHEDULE_SUMMARY_URL = BASE_URL + "/too/summary"
+SCHEDULE_DETAILS_URL = BASE_URL + "/too/details"
+SCHEDULE_DELETE_URL = BASE_URL + "/too/delete"
+IMAGE_QUERY_URL = BASE_URL + "/images/query"
+DOWNLOAD_LIST_URL = BASE_URL + "/images/download_list"
diff --git a/winterapi/fidelius.py b/winterapi/fidelius.py
index 77047f7..a814c72 100644
--- a/winterapi/fidelius.py
+++ b/winterapi/fidelius.py
@@ -1,6 +1,7 @@
"""
Fidelius is the keeper of secrets. It is the class that handles the secrets.
"""
+
import logging
import numpy as np
diff --git a/winterapi/messenger.py b/winterapi/messenger.py
index 0753c16..406b14a 100644
--- a/winterapi/messenger.py
+++ b/winterapi/messenger.py
@@ -1,16 +1,27 @@
"""
This module contains the messenger, which is used to communicate with the API
"""
+
import getpass
-import json
import logging
+from importlib import metadata
+from pathlib import Path
from typing import Optional
-import backoff
import pandas as pd
import requests
-from pydantic import BaseModel
-from wintertoo.models import Program
+from astropy import units as u
+from astropy.time import Time
+from packaging import version
+from wintertoo.data import DEFAULT_IMAGE_TYPE, WinterImageTypes
+from wintertoo.models import (
+ ConeImageQuery,
+ ImagePath,
+ Program,
+ ProgramImageQuery,
+ RectangleImageQuery,
+ TargetImageQuery,
+)
from wintertoo.models.too import (
AllTooClasses,
Summer,
@@ -21,30 +32,76 @@
WinterRaDecToO,
)
from wintertoo.schedule import concat_toos
+from wintertoo.utils import get_date
+from winterapi.base_api import MAX_TIMEOUT, BaseAPI
from winterapi.endpoints import (
+ DOWNLOAD_LIST_URL,
+ IMAGE_QUERY_URL,
PING_URL,
PROGRAM_URL,
+ SCHEDULE_DELETE_URL,
+ SCHEDULE_DETAILS_URL,
+ SCHEDULE_SUMMARY_URL,
SUMMER_TOO_URL,
USER_URL,
+ VERSION_URL,
WINTER_TOO_URL,
)
from winterapi.fidelius import Fidelius
logger = logging.getLogger(__name__)
-MAX_TIMEOUT = 30
-
-class WinterAPI:
+class WinterAPI(BaseAPI): # pylint: disable=too-many-public-methods
"""
Class to communicate with the Winter API
"""
def __init__(self):
self.fidelius = Fidelius()
- logger.info(f"API ping success is {self.ping()}")
+ ping = self.ping()
+ if not ping:
+ logger.warning("Could not successfully ping server")
+ logger.info(f"API ping success is {ping}")
self.auth = (None, None)
+ self.check_version()
+
+ @staticmethod
+ def ping():
+ """
+ Ping the API.
+
+ :return: boolean for success
+ """
+ try:
+ res = requests.get(PING_URL, timeout=MAX_TIMEOUT)
+ res.raise_for_status()
+ return res.status_code == 200
+ except requests.exceptions.ConnectionError:
+ return False
+
+ @staticmethod
+ def check_version():
+ """
+ Check the version of the API.
+
+ :return: API response
+ """
+ res = requests.get(VERSION_URL, timeout=MAX_TIMEOUT)
+ if res.status_code == 200:
+ server_version = version.parse(res.json()["body"])
+ local_version = version.parse(metadata.version("winterapi"))
+ logger.info(f"Server requires minimum winterapi version: {server_version}")
+ logger.info(f"Local winterapi version: {local_version}")
+ if server_version > local_version:
+ logger.warning(
+ f"Local winterapi version ({local_version}) is out of date! "
+ f"Server requires a minimum of {server_version}. "
+ f"Please update winterapi."
+ )
+ else:
+ logger.warning("Could not check minimum version of winterapi for server")
@staticmethod
def clear_cache():
@@ -65,79 +122,6 @@ def get_auth(self):
self.auth = (self.fidelius.get_user(), self.fidelius.get_password())
return self.auth
- @backoff.on_exception(
- backoff.expo, requests.exceptions.RequestException, max_time=MAX_TIMEOUT
- )
- def get(self, url, auth=None, **kwargs) -> requests.Response:
- """
- Run a get request.
-
- :param url: URL to get.
- :param auth: Authentication details.
- :param kwargs: additional arguments for API.
- :return: API response.
- """
- if auth is None:
- auth = self.get_auth()
- res = requests.get(url, auth=auth, params=kwargs, timeout=MAX_TIMEOUT)
-
- if res.status_code != 200:
- err = f"API call failed with '{res}: {res.text}'"
- logger.error(err)
- raise ValueError(err)
- return res
-
- @backoff.on_exception(
- backoff.expo, requests.exceptions.RequestException, max_time=MAX_TIMEOUT
- )
- def post(
- self, url, data: AllTooClasses | list[AllTooClasses], auth=None, **kwargs
- ) -> requests.Response:
- """
- Run a post request.
-
- :param url: URL to post to.
- :param data: Data to post.
- :param auth: Authentication details.
- :param kwargs: additional arguments for API.
- :return: Response.
- """
- if auth is None:
- auth = self.get_auth()
-
- if isinstance(data, list):
- convert = json.dumps([x.model_dump() for x in data])
- elif isinstance(data, BaseModel):
- convert = json.dumps([data.model_dump()])
- else:
- err = f"Unrecognised data type {type(data)}"
- logger.error(err)
- raise TypeError(err)
-
- res = requests.post(
- url, data=convert, auth=auth, params=kwargs, timeout=MAX_TIMEOUT
- )
-
- if res.status_code != 200:
- err = f"API call failed with '{res}: {res.text}'"
- logger.error(err)
- raise ValueError(err)
- return res
-
- @staticmethod
- def ping():
- """
- Ping the API.
-
- :return: boolean for success
- """
- try:
- res = requests.get(PING_URL, timeout=MAX_TIMEOUT)
- res.raise_for_status()
- return res.status_code == 200
- except ConnectionError:
- return False
-
def add_user_details(
self,
user: Optional[str] = None,
@@ -290,7 +274,7 @@ def submit_too(
if not isinstance(data, list):
data = [data]
for entry in data:
- assert isinstance(entry, Winter)
+ assert isinstance(entry, Winter), f"Entry {entry} is not a Winter ToO"
return self._submit_too(
program_name=program_name,
url=WINTER_TOO_URL,
@@ -335,3 +319,320 @@ def build_schedule_locally(
"""
program = self.get_program_details(program_name=program_name)
return concat_toos(data, program=program)
+
+ def get_observatory_queue(
+ self,
+ program_name: str,
+ ) -> tuple[requests.Response, pd.DataFrame]:
+ """
+ Function to get the observatory queue
+
+ :param program_name: Name of the program under which to check ToOs
+ :return: API response and TOO schedule
+ """
+
+ program = self.get_program_details(program_name=program_name)
+
+ res = self.get(
+ SCHEDULE_SUMMARY_URL,
+ program_name=program_name,
+ program_api_key=program.prog_key,
+ )
+
+ observatory_queue = pd.DataFrame(res.json()["body"])
+ return res, observatory_queue
+
+ def get_too_details(
+ self,
+ program_name: str,
+ too_schedule_name: str,
+ ) -> tuple[requests.Response, pd.DataFrame]:
+ """
+ Function to get the details of a single queued TOO schedule
+
+ :param program_name: Name of the program under which TOO was submitted
+ :param too_schedule_name: Name of the TOO schedule
+ :return: API response and TOO schedule
+ """
+
+ program = self.get_program_details(program_name=program_name)
+
+ res = self.get(
+ SCHEDULE_DETAILS_URL,
+ program_name=program_name,
+ program_api_key=program.prog_key,
+ schedule_name=too_schedule_name,
+ )
+
+ too_schedule = pd.DataFrame(res.json()["body"])
+ return res, too_schedule
+
+ def delete_too_request(
+ self,
+ program_name: str,
+ too_schedule_name: str,
+ ) -> requests.Response:
+ """
+ Function to delete a queued TOO schedule
+
+ :param program_name: Name of the program under which TOO was submitted
+ :param too_schedule_name: Name of the TOO schedule
+ :return: API response
+ """
+
+ program = self.get_program_details(program_name=program_name)
+
+ res = self.delete(
+ SCHEDULE_DELETE_URL,
+ program_name=program_name,
+ program_api_key=program.prog_key,
+ schedule_name=too_schedule_name,
+ )
+
+ return res
+
+ def query_images(
+ self,
+ query: (
+ TargetImageQuery | RectangleImageQuery | ConeImageQuery | ProgramImageQuery
+ ),
+ ) -> tuple[requests.Response, pd.DataFrame]:
+ """
+ Function to get the observatory queue
+
+ :param query: Query Request
+ :return: API response and TOO schedule
+ """
+
+ program = self.get_program_details(program_name=query.program_name)
+
+ res = self.get(
+ IMAGE_QUERY_URL,
+ program_name=query.program_name,
+ program_api_key=program.prog_key,
+ data=[query],
+ )
+
+ image_summary = pd.DataFrame(res.json()["body"])
+ return res, image_summary
+
+ @staticmethod
+ def check_query_dates(
+ start_date: str | None = None,
+ end_date: str | None = None,
+ ) -> tuple[str, str]:
+ """
+ Function to check the dates
+
+ :param start_date: Start date
+ :param end_date: End date
+ :return: Start and end date, in ISO format
+ """
+ if start_date is None:
+ start_date = get_date(Time.now() - 30.0 * u.day)
+
+ if end_date is None:
+ end_date = get_date(Time.now())
+
+ return start_date, end_date
+
+ def query_images_by_program(
+ self,
+ program_name: str,
+ start_date: str | None = None,
+ end_date: str | None = None,
+ image_type: WinterImageTypes = DEFAULT_IMAGE_TYPE,
+ ) -> tuple[requests.Response, pd.DataFrame]:
+ """
+ Function to get the observatory queue
+
+ :param program_name: Name of the program under which to check ToOs
+ :param start_date: Start date for images
+ :param end_date: End date for images
+ :param image_type: Type of image to query
+ :return: API response and TOO schedule
+ """
+
+ start_date, end_date = self.check_query_dates(
+ start_date=start_date, end_date=end_date
+ )
+
+ print(
+ f"Querying images for {program_name} between "
+ f"{start_date} and {end_date} of type '{image_type}'"
+ )
+
+ query = ProgramImageQuery(
+ program_name=program_name,
+ start_date=start_date,
+ end_date=end_date,
+ kind=image_type,
+ )
+
+ return self.query_images(query=query)
+
+ def query_images_by_target_name( # pylint: disable=too-many-arguments
+ self,
+ program_name: str,
+ target_name: str | None,
+ start_date: str | None = None,
+ end_date: str | None = None,
+ image_type: WinterImageTypes = DEFAULT_IMAGE_TYPE,
+ ) -> tuple[requests.Response, pd.DataFrame]:
+ """
+ Function to get the observatory queue
+
+ :param program_name: Name of the program under which to check ToOs
+ :param target_name: Name of the target
+ :param start_date: Start date for images
+ :param end_date: End date for images
+ :param image_type: Type of image to query
+ :return: API response and TOO schedule
+ """
+
+ start_date, end_date = self.check_query_dates(
+ start_date=start_date, end_date=end_date
+ )
+
+ print(
+ f"Querying images for {program_name} between "
+ f"{start_date} and {end_date} of type '{image_type}', "
+ f"with name {target_name}"
+ )
+
+ query = TargetImageQuery(
+ program_name=program_name,
+ target_name=target_name,
+ start_date=start_date,
+ end_date=end_date,
+ kind=image_type,
+ )
+
+ return self.query_images(query=query)
+
+ def query_images_by_cone( # pylint: disable=too-many-arguments
+ self,
+ program_name: str,
+ ra_deg: float,
+ dec_deg: float,
+ radius_deg: float = 1.0,
+ start_date: str | None = None,
+ end_date: str | None = None,
+ image_type: WinterImageTypes = DEFAULT_IMAGE_TYPE,
+ ) -> tuple[requests.Response, pd.DataFrame]:
+ """
+ Function to get the observatory queue
+
+ :param program_name: Name of the program under which to check ToOs
+ :param ra_deg: Right Ascension in degrees
+ :param dec_deg: Declination in degrees
+ :param radius_deg: Radius in degrees
+ :param start_date: Start date for images
+ :param end_date: End date for images
+ :param image_type: Type of image to query
+ :return: API response and TOO schedule
+ """
+
+ start_date, end_date = self.check_query_dates(
+ start_date=start_date, end_date=end_date
+ )
+
+ print(
+ f"Querying images for {program_name} between "
+ f"{start_date} and {end_date} of type '{image_type}', "
+ f"with a radius of {radius_deg} degrees around {ra_deg}, {dec_deg}"
+ )
+
+ query = ConeImageQuery(
+ program_name=program_name,
+ ra=ra_deg,
+ dec=dec_deg,
+ radius_deg=radius_deg,
+ start_date=start_date,
+ end_date=end_date,
+ kind=image_type,
+ )
+
+ return self.query_images(query=query)
+
+ def query_images_by_rectangle( # pylint: disable=too-many-arguments
+ self,
+ program_name: str,
+ ra_min_deg: float,
+ ra_max_deg: float,
+ dec_min_deg: float,
+ dec_max_deg: float,
+ start_date: str | None = None,
+ end_date: str | None = None,
+ image_type: WinterImageTypes = DEFAULT_IMAGE_TYPE,
+ ) -> tuple[requests.Response, pd.DataFrame]:
+ """
+ Function to get the observatory queue
+
+ :param program_name: Name of the program under which to check ToOs
+ :param ra_min_deg: Minimum Right Ascension in degrees
+ :param ra_max_deg: Maximum Right Ascension in degrees
+ :param dec_min_deg: Minimum Declination in degrees
+ :param dec_max_deg: Maximum Declination in degrees
+ :param start_date: Start date for images
+ :param end_date: End date for images
+ :param image_type: Type of image to query
+ :return: API response and TOO schedule
+ """
+
+ start_date, end_date = self.check_query_dates(
+ start_date=start_date, end_date=end_date
+ )
+
+ print(
+ f"Querying images for {program_name} between "
+ f"{start_date} and {end_date} of type '{image_type}', "
+ f"with RA between {ra_min_deg} and {ra_max_deg} and "
+ f"Dec between {dec_min_deg} and {dec_max_deg}"
+ )
+
+ query = RectangleImageQuery(
+ program_name=program_name,
+ ra_min=ra_min_deg,
+ ra_max=ra_max_deg,
+ dec_min=dec_min_deg,
+ dec_max=dec_max_deg,
+ start_date=start_date,
+ end_date=end_date,
+ kind=image_type,
+ )
+
+ return self.query_images(query=query)
+
+ def download_image_list(
+ self,
+ program_name: str,
+ paths: list[str] | str,
+ image_type: WinterImageTypes,
+ output_dir: str | None | Path = None,
+ ) -> tuple[requests.Response, Path]:
+ """
+ Download images as a zip file.
+
+ :param program_name: Name of the program under which to check ToOs
+ :param image_type: Type of image to query
+ :param output_dir: Directory to save the zip to
+ :param paths: List of paths to download
+ :return: API response
+ """
+
+ if not isinstance(paths, list):
+ paths = [paths]
+
+ program = self.get_program_details(program_name=program_name)
+
+ res, output_path = self.get_stream(
+ DOWNLOAD_LIST_URL,
+ savepath=output_dir,
+ program_name=program_name,
+ program_api_key=program.prog_key,
+ data=[ImagePath(path=x) for x in paths],
+ kind=image_type,
+ )
+
+ return res, output_path