|
30 | 30 | "source": [ |
31 | 31 | "**Learning objective:** How to use the Rubin image cutout service with DP1.\n", |
32 | 32 | "\n", |
33 | | - "**LSST data products:** `deep_coadd`\n", |
| 33 | + "**LSST data products:** `visit_image`\n", |
34 | 34 | "\n", |
35 | 35 | "**Packages:** `lsst.rsp.utils`, `pyvo`, `lsst.rsp.service`, `lsst.afw.display`\n", |
36 | 36 | "\n", |
37 | 37 | "**Credit:** Originally developed by the Rubin Community Science team.\n", |
38 | 38 | "Please consider acknowledging them if this notebook is used for the preparation of journal articles, software releases, or other notebooks.\n", |
39 | | - "This notebook builds on DP0.2 science demonstration of image cutouts (tutorial notebook 13a), and technical exploration of the cutout service developed by Leanne Guy (in preparation), and builds on an earlier notebook written by Alex Drlica-Wagner <a href=\"https://github.com/rubin-dp0/cst-dev/blob/main/ADW_gravelpit/TAP_Image_Access.ipynb\">linked here</a>.\n", |
40 | 39 | "\n", |
41 | 40 | "**Get Support:**\n", |
42 | 41 | "Everyone is encouraged to ask questions or raise issues in the \n", |
|
109 | 108 | "from pyvo.dal.adhoc import DatalinkResults, SodaQuery\n", |
110 | 109 | "\n", |
111 | 110 | "from astropy import units as u\n", |
112 | | - "from astropy.coordinates import Angle" |
| 111 | + "from astropy.coordinates import Angle\n", |
| 112 | + "from astropy.time import Time" |
113 | 113 | ] |
114 | 114 | }, |
115 | 115 | { |
|
160 | 160 | "id": "3d4d9571-2f48-440e-9c40-90f14f6eac8c", |
161 | 161 | "metadata": {}, |
162 | 162 | "source": [ |
163 | | - "## 2. Locating the image for cutout\n", |
| 163 | + "## 2. Find the visit image\n", |
164 | 164 | "\n", |
165 | | - "First, define a point on the sky as the center of the image cutout. Once the RA and Dec are defined, create a SpherePoint object to define the location on the sky. Use these in a SIA query to identify the overlapping deep_coadd image in Section 2.4. \n", |
| 165 | + "The cutout services needs the `access_url` for the image from which a cutout is desired.\n", |
| 166 | + "The SIA or TAP services can be used to find the desired image and retrieve its `access_url`.\n", |
166 | 167 | "\n", |
167 | | - "Define search coordinates right ascension (`target_ra`) and declination (`target_dec`), in degrees, to use in all queries.\n", |
168 | | - "These coordinates are the location of the Hubble Ultra Deep Field, near the center of the Extended Chandra Deep Field South (ECDFS) DP1 map." |
| 168 | + "For this example, make an r-band (effective wavelength 622.1 nm) cutout centered on a set of coordinates in the ECDFS field,\n", |
| 169 | + "for a visit image that was obtained between MJD 60623.256 and 60623.259.\n", |
| 170 | + "\n", |
| 171 | + "Define the coordinates right ascension (`target_ra`) and declination (`target_dec`) in degrees.\n", |
| 172 | + "Define the band and the start and end times." |
169 | 173 | ] |
170 | 174 | }, |
171 | 175 | { |
|
175 | 179 | "metadata": {}, |
176 | 180 | "outputs": [], |
177 | 181 | "source": [ |
178 | | - "target_ra = 53.1567053\n", |
179 | | - "target_dec = -27.7815854\n", |
180 | | - "\n", |
181 | | - "spherePoint = geom.SpherePoint(target_ra*geom.degrees, target_dec*geom.degrees)" |
| 182 | + "target_ra = 53.1246023\n", |
| 183 | + "target_dec = -27.7404715\n", |
| 184 | + "eff_wl = 622.1e-09\n", |
| 185 | + "time1 = Time(60623.256, format=\"mjd\", scale=\"tai\")\n", |
| 186 | + "time2 = Time(60623.259, format=\"mjd\", scale=\"tai\")" |
182 | 187 | ] |
183 | 188 | }, |
184 | 189 | { |
|
214 | 219 | "id": "08b71293-d3ab-49ca-9a95-2566488eec33", |
215 | 220 | "metadata": {}, |
216 | 221 | "source": [ |
217 | | - "Query for `deep_coadd` images by setting `calib_level=3` and `dpsubtype='lsst.deep_coadd'`.\n", |
218 | | - "\n", |
219 | | - "This query will return 6 `deep_coadd` images (one for each filter)." |
| 222 | + "This query will return 1 `visit_image` (by design)." |
220 | 223 | ] |
221 | 224 | }, |
222 | 225 | { |
|
226 | 229 | "metadata": {}, |
227 | 230 | "outputs": [], |
228 | 231 | "source": [ |
229 | | - "results = service.search(pos=circle, calib_level=3, dpsubtype='lsst.deep_coadd')\n", |
| 232 | + "results = service.search(pos=circle, calib_level=2, dpsubtype='lsst.visit_image',\n", |
| 233 | + " band=eff_wl, time=(time1, time2))\n", |
230 | 234 | "print(len(results))" |
231 | 235 | ] |
232 | 236 | }, |
|
235 | 239 | "id": "8f62bb47-7a7c-49cd-969a-6d60b5488abe", |
236 | 240 | "metadata": {}, |
237 | 241 | "source": [ |
238 | | - "Option to display the results as an Astropy table." |
| 242 | + "Display the results as an Astropy table." |
239 | 243 | ] |
240 | 244 | }, |
241 | 245 | { |
|
245 | 249 | "metadata": {}, |
246 | 250 | "outputs": [], |
247 | 251 | "source": [ |
248 | | - "# results.to_table()" |
249 | | - ] |
250 | | - }, |
251 | | - { |
252 | | - "cell_type": "markdown", |
253 | | - "id": "2e641dc9-57ae-4dc5-9bee-6e54f48d88dc", |
254 | | - "metadata": {}, |
255 | | - "source": [ |
256 | | - "Select the r-band deep coadd image." |
257 | | - ] |
258 | | - }, |
259 | | - { |
260 | | - "cell_type": "code", |
261 | | - "execution_count": null, |
262 | | - "id": "82a36217-98b7-4633-8535-1a055d7d2ff9", |
263 | | - "metadata": {}, |
264 | | - "outputs": [], |
265 | | - "source": [ |
266 | | - "tx = np.where(results['lsst_band'] == 'r')[0]\n", |
267 | | - "print(tx)" |
268 | | - ] |
269 | | - }, |
270 | | - { |
271 | | - "cell_type": "markdown", |
272 | | - "id": "98235dce-1afe-42c8-9d01-0a82d8b8ab2a", |
273 | | - "metadata": {}, |
274 | | - "source": [ |
275 | | - "Define the corresponding `index` for the `results`." |
276 | | - ] |
277 | | - }, |
278 | | - { |
279 | | - "cell_type": "code", |
280 | | - "execution_count": null, |
281 | | - "id": "59c760db-7ecd-42e2-b8bf-1ae4910ab4a5", |
282 | | - "metadata": {}, |
283 | | - "outputs": [], |
284 | | - "source": [ |
285 | | - "index = tx[0].item()" |
286 | | - ] |
287 | | - }, |
288 | | - { |
289 | | - "cell_type": "code", |
290 | | - "execution_count": null, |
291 | | - "id": "977ed070-845c-4145-908a-6d68f2c913bf", |
292 | | - "metadata": {}, |
293 | | - "outputs": [], |
294 | | - "source": [ |
295 | | - "results[index]" |
| 252 | + "results.to_table()" |
296 | 253 | ] |
297 | 254 | }, |
298 | 255 | { |
299 | 256 | "cell_type": "markdown", |
300 | 257 | "id": "5ddf1d6c-7acb-4467-8a32-4659bd45ab5b", |
301 | 258 | "metadata": {}, |
302 | 259 | "source": [ |
303 | | - "In the table, the `access_url` contains the web URL datalink for the r-band `deep_coadd`. This datalink will be needed to generate the image cutout." |
| 260 | + "In the table, the `access_url` contains the web URL datalink for the image. This datalink will be needed to generate the image cutout." |
304 | 261 | ] |
305 | 262 | }, |
306 | 263 | { |
|
315 | 272 | "An example TAP query using this method that retrieves the `access_url` is:\n", |
316 | 273 | "\n", |
317 | 274 | "```\n", |
318 | | - "SELECT dataproduct_type, dataproduct_subtype, calib_level, lsst_band,\n", |
319 | | - " instrument_name, access_url, access_format \n", |
| 275 | + "SELECT dataproduct_type,dataproduct_subtype,calib_level,lsst_band,em_min,em_max,lsst_tract,lsst_patch,\n", |
| 276 | + " lsst_filter,lsst_visit,lsst_detector,t_exptime,t_min,t_max,s_ra,s_dec,s_fov,obs_id,\n", |
| 277 | + " obs_collection,o_ucd,facility_name,instrument_name,obs_title,s_region,access_url,\n", |
| 278 | + " access_format \n", |
320 | 279 | "FROM ivoa.ObsCore \n", |
321 | | - "WHERE calib_level = 3\n", |
322 | | - "AND dataproduct_type = 'image'\n", |
323 | | - "AND dataproduct_subtype = 'lsst.deep_coadd'\n", |
324 | | - "AND CONTAINS(POINT('ICRS', 53.1567053, -27.7815854), s_region)=1\n", |
| 280 | + "WHERE CONTAINS(POINT('ICRS', 53.1567053, -27.7815854), s_region)=1\n", |
| 281 | + " AND obs_collection = 'LSST.DP1' AND calib_level = 2\n", |
| 282 | + " AND dataproduct_type = 'image' AND instrument_name = 'LSSTComCam'\n", |
| 283 | + " AND dataproduct_subtype = 'lsst.visit_image'\n", |
| 284 | + " AND ( t_min <= 60623.259 AND 60623.256 <= t_max )\n", |
| 285 | + " AND ( 622e-9 BETWEEN em_min AND em_max )\n", |
325 | 286 | "```" |
326 | 287 | ] |
327 | 288 | }, |
|
346 | 307 | "metadata": {}, |
347 | 308 | "outputs": [], |
348 | 309 | "source": [ |
349 | | - "datalink_url = results[index].access_url\n", |
| 310 | + "datalink_url = results[0].access_url\n", |
350 | 311 | "dl_result = DatalinkResults.from_result_url(datalink_url, session=get_pyvo_auth())\n", |
351 | 312 | "\n", |
352 | 313 | "f\"Datalink status: {dl_result.status}. Datalink service url: {datalink_url}\"" |
|
377 | 338 | "id": "c6fa46da-88c8-4b5e-b86c-4b5878f3badf", |
378 | 339 | "metadata": {}, |
379 | 340 | "source": [ |
380 | | - "The variable `sq` now holds the result of the SODA query using the data link (which currently still points the full LSST patch and tract deep_coadd image, at its remote location in the database). The cell below will now demonstrate how to extract a cutout from `sq`. \n", |
| 341 | + "The variable `sq` now holds the result of the SODA query using the data link (which currently still points the full LSST `visit_image`, at its remote location in the database). The cell below will now demonstrate how to extract a cutout from `sq`. \n", |
381 | 342 | "\n", |
382 | 343 | "### 3.1. Define cutout center and edge\n", |
383 | 344 | "\n", |
|
391 | 352 | "metadata": {}, |
392 | 353 | "outputs": [], |
393 | 354 | "source": [ |
394 | | - "Radius = 0.06 * u.deg\n", |
| 355 | + "spherePoint = geom.SpherePoint(target_ra*geom.degrees, target_dec*geom.degrees)\n", |
| 356 | + "Radius = 0.01 * u.deg\n", |
395 | 357 | "sq.circle = (spherePoint.getRa().asDegrees() * u.deg,\n", |
396 | 358 | " spherePoint.getDec().asDegrees() * u.deg,\n", |
397 | 359 | " Radius)" |
|
447 | 409 | "id": "458a4d25-ca95-4f92-b76e-986b7a03b320", |
448 | 410 | "metadata": {}, |
449 | 411 | "source": [ |
450 | | - "> Figure 1: The `deep_coadd` cutout image, displayed in grayscale with a scale bar at right.\n", |
| 412 | + "> Figure 1: The cutout image, displayed in grayscale with a scale bar at right.\n", |
451 | 413 | "\n", |
452 | 414 | "#### 3.2.1. Option to save cutout to disk\n", |
453 | 415 | "\n", |
|
502 | 464 | "\n", |
503 | 465 | "POLYGON=12 34 14 34 14 36 12 36\n", |
504 | 466 | "\n", |
505 | | - "Since the center of the cutout is already defined in RA and Dec in the cells above (`spherePoint`), this example will define each x,y set as RA+/-edge and Dec+/-edge. " |
| 467 | + "Since the center of the cutout is already defined in RA and Dec in the cells above (`spherePoint`), this example will define each x,y set as RA+/-edge and Dec+/-edge.\n", |
| 468 | + "\n", |
| 469 | + "> **Warning:** Visit images are rotated, and although it is the \"Declination edge\" that is defined to be smaller, that corresponds to the x-axis when the cutout is displayed below, due to image rotation." |
506 | 470 | ] |
507 | 471 | }, |
508 | 472 | { |
|
516 | 480 | " dl_result.get_adhocservice_by_id(\"cutout-sync\"),\n", |
517 | 481 | " session=get_pyvo_auth())\n", |
518 | 482 | "\n", |
519 | | - "edge1 = 0.06 * u.deg\n", |
520 | | - "edge2 = 0.02 * u.deg\n", |
| 483 | + "ra_edge = 0.02 * u.deg\n", |
| 484 | + "de_edge = 0.005 * u.deg\n", |
521 | 485 | "\n", |
522 | | - "sqp.polygon = (spherePoint.getRa().asDegrees() * u.deg - edge1,\n", |
523 | | - " spherePoint.getDec().asDegrees() * u.deg - edge2,\n", |
524 | | - " spherePoint.getRa().asDegrees() * u.deg - edge1,\n", |
525 | | - " spherePoint.getDec().asDegrees() * u.deg + edge2,\n", |
526 | | - " spherePoint.getRa().asDegrees() * u.deg + edge1,\n", |
527 | | - " spherePoint.getDec().asDegrees() * u.deg + edge2)\n", |
| 486 | + "sqp.polygon = (spherePoint.getRa().asDegrees() * u.deg - ra_edge,\n", |
| 487 | + " spherePoint.getDec().asDegrees() * u.deg - de_edge,\n", |
| 488 | + " spherePoint.getRa().asDegrees() * u.deg - ra_edge,\n", |
| 489 | + " spherePoint.getDec().asDegrees() * u.deg + de_edge,\n", |
| 490 | + " spherePoint.getRa().asDegrees() * u.deg + ra_edge,\n", |
| 491 | + " spherePoint.getDec().asDegrees() * u.deg + de_edge,\n", |
| 492 | + " spherePoint.getRa().asDegrees() * u.deg + ra_edge,\n", |
| 493 | + " spherePoint.getDec().asDegrees() * u.deg - de_edge)\n", |
528 | 494 | "\n", |
529 | 495 | "cutout_bytes = sqp.execute_stream().read()\n", |
530 | 496 | "sqp.raise_if_error()\n", |
|
551 | 517 | "id": "c83e5413-2edf-41fd-8542-b622ba8324b0", |
552 | 518 | "metadata": {}, |
553 | 519 | "source": [ |
554 | | - "> Figure 2: A rectangular polygon cutout from the same `deep_coadd` image used in Figure 1.\n", |
555 | | - "\n" |
| 520 | + "> Figure 2: A rectangular polygon cutout from a rotated `visit_image`." |
556 | 521 | ] |
557 | 522 | }, |
558 | 523 | { |
|
562 | 527 | "source": [ |
563 | 528 | "### 3.4. Correcting for cos(d)\n", |
564 | 529 | "\n", |
565 | | - "There is an important difference to note between the circle and polygon shape definitions. The angular distance on the sky that defines the circular cutout size already accounts for the difference in angular distance in the RA direction is smaller by a factor of cos(declination), where declination is in units radians. The difference increases with higher declination. However, the polygon definition does not automatically account for this cosine factor. Thus, circle and polygon cutout definitions using the same cutout edge length will not match size in the RA direction (for deep_coadds, the x-axis). The 2 cells below demonstrate how to make this correction to the polygon cutout definition to create symmetric cutouts with polygon. Here, reset the edge sizes to be the same as `Radius` from the circle definition above.\n", |
| 530 | + "There is an important difference to note between the circle and polygon shape definitions. The angular distance on the sky that defines the circular cutout size already accounts for the difference in angular distance in the RA direction is smaller by a factor of cos(declination), where declination is in units radians. The difference increases with higher declination. However, the polygon definition does not automatically account for this cosine factor. Thus, circle and polygon cutout definitions using the same cutout edge length will not match size in the RA direction. The 2 cells below demonstrate how to make this correction to the polygon cutout definition to create symmetric cutouts with polygon. Here, reset the edge sizes to be the same as `Radius` from the circle definition above.\n", |
566 | 531 | "\n", |
567 | 532 | "First, generate a polygon cutout without factoring in cos(dec)." |
568 | 533 | ] |
|
0 commit comments