From 63feb5bc13754418e99c58644aebc3c907a0a428 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Thu, 30 Apr 2026 04:01:38 +0000 Subject: [PATCH 01/27] adding 303 3 --- .../303_Galaxies/303_3_Color_selections.ipynb | 2078 +++++++++++++++++ 1 file changed, 2078 insertions(+) create mode 100644 DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb new file mode 100644 index 00000000..5d378560 --- /dev/null +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -0,0 +1,2078 @@ +{ + "cells": [ + { + "attachments": { + "697dbfa5-0793-4e9d-8401-2f3b86b0243c.png": { + "image/png": "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GPJmu7BUJEACJEACJEACJEACJEACJEACJEACJFBwApyVrOCIeQASIAESIAESIAESIAESIAESIAESIAES8CYBCkPebBeWigRIgARIgARIgARIgARIgARIgARIgAQKToDCUMER8wAkQAIkQAIkQAIkQAIkQAIkQAIkQAIk4E0CFIa82S4sFQmQAAmQAAmQAAmQAAmQAAmQAAmQAAkUnACFoYIj5gFIgARIgARIgARIgARIgARIgARIgARIwJsEKAx5s11YKhIgARIgARIgARIgARIgARIgARIgARIoOAEKQwVHzAOQAAmQAAmQAAmQAAmQAAmQAAmQAAmQgDcJUBjyZruwVCRAAiRAAiRAAiRAAiRAAiRAAiRAAiRQcAIUhgqOmAcgARIgARIgARIgARIgARIgARIgARIgAW8SoDDkzXZhqUiABEiABEiABEiABEiABEiABEiABEig4AQoDBUcMQ9AAiRAAiRAAiRAAiRAAiRAAiRAAiRAAt4kQGHIm+3CUpEACZAACZAACZAACZAACZAACZAACZBAwQlQGCo4Yh6ABEiABEiABEiABEiABEiABEiABEiABLxJgMKQN9uFpSIBEiABEiABEiABEiABEiABEiABEiCBghOgMFRwxDwACZAACZAACZAACZAACZAACZAACZAACXiTAIUhb7YLS0UCJEACJEACJEACJEACJEACJEACJEACBSdQXfAj8AAkQAIkUAACk4uLgr/k1N3cLPhj8i6BVG2XWGK2YyINfiYBEih3Aqnue7zXlXvLsvwkQAIkUBkEKAxVRjuyFiRQ8QTQqf7tjZvy1o0bliC0GonIaiR8T73rq6ulvrpGupqb5FBPjxzq7bWWXhKLUI83b1y/p+yZruhuatoQv1Av1NNL9UushxkMXRqfSNt2ifsltqM1cNI6P9vfL4e1PYuRcm2jTMuItntO61XI9jPXzoXxsUyLtbGdl861dPV4dm+/PL+vf6PsuX5Id7xitJ1dHS6Nj8tb12/IxNK9wnji9l4vX2JZ8/053+eC2/K5ue+Ze91B63nVI1gW6z6XSb3SXQdOeXjl/pGuDihnPp4v6a5NXJNfOHhQmmprnbDxNxIgARIoCQEKQyXBzoOSAAlkQsB05iAGDc3NyfjCgkzoH0ShdKlOBaITt25LW329PLn7Pnlkxw7PdLgvjI3JP370cboqpPy9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CWxeAr41TZu3+qw5CZBAORGIuzqsWAMXxOWwiytkZsDCbFjoqMOVqtjBZNMxNfVIt1263zHIq6+p2ZgBLN32hf4dbgAQ8LBEQvsgmDhmHUtsK8wgh2ntjSDixTbLVxulY27O0XTb5fJ7crsk5oVzKNtrJB2jYtQtsS52n53qnrh9qcrqVL5c2iaxbsmfndqtUMdMLkPyd6cylaptksvo9rtpW1O3xHtgYl7m/teqM0hipk3rvq7XpVeSqQeWySmX88VwSc7TfPdCuzuV0QvlM6y4JAESIIF8EKAwlA+KzIMESIAESCBjAhhg4I2E1wS7jCvADUmABEiABEiABEiABEiggghQGKqgxmRVSIAESIAESIAESIAESIAESIAESIAESMANAU5X74YWtyUBEiABEiABEiABEiABEiABEiABEiCBCiJAYaiCGpNVIQESIAESIAESIAESIAESIAESIAESIAE3BCgMuaHFbUmABEiABEiABEiABEiABEiABEiABEiggghQGKqgxmRVSIAESIAESIAESIAESIAESIAESIAESMANAQpDbmhxWxIgARIgARIgARIgARIgARIgARIgARKoIAIUhiqoMVkVEiABEiABEiABEiABEiABEiABEiABEnBDgMKQG1rclgRIgARIgARIgARIgARIgARIgARIgAQqiACFoQpqTFaFBEiABEiABEiABEiABEiABEiABEiABNwQoDDkhha3JQESIAESIAESIAESIAESIAESIAESIIEKIkBhqIIak1UhARIgARIgARIgARIgARIgARIgARIgATcEKAy5ocVtSYAESIAESIAESIAESIAESIAESIAESKCCCFAYqqDGZFVIgARIgARIgARIgARIgARIgARIgARIwA0BCkNuaHFbEiABEiABEiABEiABEiABEiABEiABEqggAhSGKqgxWRUSIAESIAESIAESIAESIAESIAESIAEScEOAwpAbWtyWBEiABEiABEiABEiABEiABEiABEiABCqIAIWhCmpMVoUESIAESIAESIAESIAESIAESIAESIAE3BCgMOSGFrclARIgARIgARIgARIgARIgARIgARIggQoiQGGoghqTVSEBEiABEiABEiABEiABEiABEiABEiABNwQoDLmhxW1JgARIgARIgARIgARIgARIgARIgARIoIIIUBiqoMZkVUiABEiABEiABEiABEiABEiABEiABEjADQEKQ25ocVsSIAESIAESIAESIAESIAESIAESIAESqCACFIYqqDFZFRIgARIgARIgARIgARIgARIgARIgARJwQ4DCkBta3JYESIAESIAESIAESIAESIAESIAESIAEKogAhaEKakxWhQRIgARIgARIgARIgARIgARIgARIgATcEKAw5IYWtyUBEiABEiABEiABEiABEiABEiABEiCBCiJAYaiCGpNVIQESIAESIAESIAESIAESIAESIAESIAE3BCgMuaHFbUmABEiABEiABEiABEiABEiABEiABEiggghQGKqgxmRVSIAESIAESIAESIAESIAESIAESIAESMANAQpDbmhxWxIgARIgARIgARIgARIgARIgARIgARKoIAIUhiqoMVkVEiABEiABEiABEiABEiABEiABEiABEnBDgMKQG1rclgRIgARIgARIgARIgARIgARIgARIgAQqiACFoQpqTFaFBEiABEiABEiABEiABEiABEiABEiABNwQoDDkhha3JQESIAESIAESIAESIAESIAESIAESIIEKIkBhqIIak1UhARIgARIgARIgARIgARIgARIgARIgATcEKAy5ocVtSYAESIAESIAESIAESIAESIAESIAESKCCCFAYqqDGZFVIgARIgARIgARIgARIgARIgARIgARIwA0BCkNuaHFbEiABEiABEiABEiABEiABEiABEiABEqggAhSGKqgxWRUSIAESIAESIAESIAESIAESIAESIAEScEOAwpAbWtyWBEiABEiABEiABEiABEiABEiABEiABCqIAIWhCmpMVoUESIAESIAESIAESIAESIAESIAESIAE3BCgMOSGFrclARIgARIgARIgARIgARIgARIgARIggQoiQGGoghqTVSEBEiABEiABEiABEiABEiABEiABEiABNwQoDLmhxW1JgARIgARIgARIgARIgARIgARIgARIoIIIUBiqoMZkVUiABEiABEiABEiABEiABEiABEiABEjADQEKQ25ocVsSIAESIAESIAESIAESIAESIAESIAESqCACFIYqqDFZFRIgARIgARIgARIgARIgARIgARIgARJwQ4DCkBta3JYESIAESIAESIAESIAESIAESIAESIAEKogAhaEKakxWhQRIgARIgARIgARIgARIgARIgARIgATcEKAw5IYWtyUBEiABEiABEiABEiABEiABEiABEiCBCiJAYaiCGpNVIQESIAESIAESIAESIAESIAESIAESIAE3BCgMuaHFbUmABEiABEiABEiABEiABEiABEiABEiggghQGKqgxmRVSIAESIAESIAESIAESIAESIAESIAESMANAQpDbmhxWxIgARIgARIgARIgARIgARIgARIgARKoIAIUhiqoMVkVEiABEiABEiABEiABEiABEiABEiABEnBDgMKQG1rclgRIgARIgARIgARIgARIgARIgARIgAQqiACFoQpqTFaFBEiABEiABEiABEiABEiABEiABEiABNwQoDDkhha3JQESIAESIAESIAESIAESIAESIAESIIEKIkBhqIIak1UhARIgARIgARIgARIgARIgARIgARIgATcEKAy5ocVtSYAESIAESIAESIAESIAESIAESIAESKCCCFAYqqDGZFVIgARIgARIgARIgARIgARIgARIgARIwA0BCkNuaHFbEiABEiABEiABEiABEiABEiABEiABEqggAtUVVJeyq8pSYFCm73wsgckbsjQ3ItV1TbLr0Bdl664nyq4uLDAJkAAJkAAJkAAJkAAJkAAJkAAJkED5EaAwVMI2W12clLnxT2R+6rbMTw9IdU2j9Nz3eAlLxEOTAAmQAAmQAAmQAAmQAAmQAAmQAAlsJgIUhkrZ2mtR8cmaNLR0SDQalEgoVMrS8NgkQAIkQAIkQAIkQAIkQAIkQAIkQAKbjACFoRI2eCS0LJHwsvir66SuoVVFoqUSloaHJgESIAESIAESIAESIAESIAESIAES2GwEGHy6hC2+JjHx+Xziq/Jbf6HVgKwuzRS0ROHVeQnrcZhIgARIgARIgARIgARIgARIgARIgARIgBZDSedAJLSowaAvy9LsLWntPiDtPUeStsjP19WlCQkuTUmVv1ZUFbKshtRkSJYXxiS4PCN1jZ35OVBCLqHVOY1ndFUWpwZUkKqXzh3HpGXLroQt+JEESIAESIAESIAESIAESIAESIAESGAzEaAwtN7a4eC8zgw2KAsz12Vh+pqsLoxr3J+wNLbtlNr69ryfE7FISNbWIpalkGicoZq6RqmpbZQVPS7EoUIIQzGtTyS8JIs6G9rc6G0ZuPBr2bbvKdl1+Helrqkj73VkhiRAAiRAAiRAAiRAAiRAAiRAAiRAAt4m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" + } + }, + "cell_type": "markdown", + "id": "325aa8a5-92fd-4913-a471-ad1617343be6", + "metadata": {}, + "source": [ + "# 303.3. Color Selections\n", + "\n", + "
\n", + "\n", + "![logo.png](attachment:697dbfa5-0793-4e9d-8401-2f3b86b0243c.png)\n", + "\n", + "
\n", + "\n", + "For the Rubin Science Platform at data.lsst.cloud.
\n", + "Data Release: Data Preview 1
\n", + "Container Size: large
\n", + "LSST Science Pipelines version: r29.2.0
\n", + "Last verified to run: 2025-09-02
\n", + "Repository: github.com/lsst/tutorial-notebooks
" + ] + }, + { + "cell_type": "markdown", + "id": "9da1a210-d858-42fe-8591-570965b8be1a", + "metadata": {}, + "source": [ + "**Learning objective:** Explore the available measurements of galaxy photometry produced by the LSST pipelines and their applications.\n", + "\n", + "**LSST data products:** `Object` table\n", + "\n", + "**Packages:** `lsst.rsp.get_tap_service `\n", + "\n", + "**Credit:**\n", + "This notebook benefitted from an earlier exploration of simulated data and notebook development by Melissa Graham and Dan Taranu, helpful discussions with Jim Bosch, and ideas from Douglas Tucker. \n", + "\n", + "**Get Support:**\n", + "Everyone is encouraged to ask questions or raise issues in the \n", + "Support Category \n", + "of the Rubin Community Forum.\n", + "Rubin staff will respond to all questions posted there." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "cfc73be0", + "metadata": {}, + "source": [ + "## 1. Introduction \n", + "\n", + "Photometry is the measurement of how much light is apparent from astronomical sources. The amount of light arriving on the telescope from the object is typically referred to as the flux density, or apparent magnitude (depending on units). Flux density is defined as the amount of energy arriving on the telescope per unit area, per unit time, per unit frequency (or wavelength) of the light.\n", + "\n", + "The LSST Science Pipelines makes a variety of photometric measurements for point-like and extended sources. This notebook will teach the user about the automated photometry measurements for extended sources that are measured on the deepCoadd images and appear in the Object Catalog as part of the LSST pipelines data products.\n", + "\n", + "The photometry measurements in the catalogs are flux densities in units of nano-Jansky [nJy]. 1 Jy = 10^{-23} ergs/s/cm^2/Hz." + ] + }, + { + "cell_type": "markdown", + "id": "dc36f107", + "metadata": {}, + "source": [ + "### 1.1. Import packages\n", + "\n", + "Import `numpy`, a fundamental package for scientific computing with arrays in Python\n", + "(numpy.org), and\n", + "`matplotlib`, a comprehensive library for data visualization\n", + "(matplotlib.org; \n", + "matplotlib gallery).\n", + "\n", + "From the `lsst` package, import modules for accessing the Table Access Protocol (TAP) service,\n", + "the butler, and image display functions from the LSST Science Pipelines (pipelines.lsst.io)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cddc1458", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from lsst.rsp import get_tap_service\n", + "\n", + "from scipy.stats import binned_statistic" + ] + }, + { + "cell_type": "markdown", + "id": "c217adff-25ed-4fce-95e7-8aa04630f6cc", + "metadata": {}, + "source": [ + "### 1.2. Define parameters and functions" + ] + }, + { + "cell_type": "markdown", + "id": "d3383f6e-8c34-4cb7-aa2f-12e9b7f8efc0", + "metadata": {}, + "source": [ + "Get an instance of the TAP service, and assert that it exists." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e8184089-8a3e-4666-a194-5362a8faa541", + "metadata": {}, + "outputs": [], + "source": [ + "service = get_tap_service(\"tap\")\n", + "assert service is not None" + ] + }, + { + "cell_type": "markdown", + "id": "557bbb99-3a37-4b15-ad6d-e86c6282866c", + "metadata": {}, + "source": [ + "## 2. Types of photometry\n", + "\n", + "This section will explore photometry measurements produced by the LSST pipelines, and provide some guidance for which are optimal for various applications for science with galaxies. \n", + "### 2.1. Explore the schema\n", + "\n", + "Numerous photometry measurements are produced by the LSST Pipelines. Two types of photometry are in the object table. The first are total fluxes (see Section 3), which aim to approximate (or model) all of the light coming from object. The second class of fluxes are measured inside an on-sky aperture but not corrected for flux that may fall outside: thus they are apparent fluxes but do not recover the intrisic (total) flux (see Section 4 and 5). The apparent fluxes are optimized for other purposes, such as for measuring accurate light profiles or accurate colors. \n", + "\n", + "Schema for the object catalog for DP1 is available here. It lists the catalog header and brief explanation of the parameters.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "1513ee4c-0a00-4868-8525-53aaccfff9b1", + "metadata": {}, + "source": [ + "First, see what is available in the object table by querying the `tap_schema` columns, and printing all the parameters available related to \"Flux\" measured in the i-band (as an example). For clarity, the return also omits errors and flags associated with the photometric measurements outlined in section 1.1. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d532f5a-52ad-408d-bce6-a5a4d346477f", + "metadata": {}, + "outputs": [], + "source": [ + "query = \"SELECT column_name, datatype, description, unit \" \\\n", + " \"FROM tap_schema.columns \" \\\n", + " \"WHERE table_name = 'dp1.Object'\"\n", + "\n", + "results = service.search(query).to_table()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84849d6b-527d-4ac7-9cbb-09df352f7b34", + "metadata": {}, + "outputs": [], + "source": [ + "search_string = 'Flux'\n", + "band = 'i_'\n", + "exclude1 = 'Err'\n", + "exclude2 = 'flag'\n", + "for cname in results['column_name']:\n", + " if cname.find(search_string) > -1 and cname.find(band) > -1 and \\\n", + " cname.find(exclude1) == -1 and cname.find(exclude2) == -1:\n", + "\n", + " print(cname)" + ] + }, + { + "cell_type": "markdown", + "id": "5dd9c7cb-8ab0-4f7c-9161-69fa29d46537", + "metadata": {}, + "source": [ + "The object catalog also has pre-computed AB magnitudes (`Mag` columns) for cModel and PSF. Query the `tap_schema` columns, and print all the parameters available related to `Mag` measured in the i-band. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6225c1c4-e324-4846-b49b-06471a4abe59", + "metadata": {}, + "outputs": [], + "source": [ + "search_string = 'Mag'\n", + "band = 'i_'\n", + "exclude1 = 'Err'\n", + "for cname in results['column_name']:\n", + " if cname.find(search_string) > -1 and cname.find(band) > -1 and \\\n", + " cname.find(exclude1) == -1:\n", + "\n", + " print(cname)" + ] + }, + { + "cell_type": "markdown", + "id": "ac0528ca-2ec6-405e-b4ea-e897ef96de67", + "metadata": {}, + "source": [ + "\n", + "### 2.2. Select a galaxy sample\n", + "\n", + "Below, query the DP1 `objectTable` for a selection of photometric measurements. \n", + "\n", + "Limit the search to contain galaxies using the `i_extendedness` flag (which will exclude point sources). Further, identify objects which have been detected at high signal to noise > 20 and whose photometric measurements have not been flagged as having an issue (`i_kronFlux_flag` or `i_cModel_flag` or `sersic_no_data_flag` = 0 means the photometry is ok). Also exclude very bright galaxies (i-band magnitude < 20).\n", + "\n", + "Search for the sample using the DP1 imaging obtained in the Extended Chandra Deep Field South (ECDFS; center ra, dec = 53.2, -28.1 in degrees) which was one of the deepest imaging obtained as part of DP1.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73dd5a5f-b761-4d4f-96b6-5767cffbb310", + "metadata": {}, + "outputs": [], + "source": [ + "target_ra = 53.2\n", + "target_dec = -28.1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75150971-e118-48d5-9db7-74c0fe600762", + "metadata": {}, + "outputs": [], + "source": [ + "query = \"SELECT obj.objectId, obj.coord_ra, obj.coord_dec, \" + \\\n", + " \"obj.detect_fromBlend, obj.detect_isIsolated, \" + \\\n", + " \"obj.i_blendedness, obj.i_extendedness, \" + \\\n", + " \"obj.u_sersicFlux, obj.u_sersicFluxErr, obj.u_gaap1p0Flux, \" + \\\n", + " \"obj.g_sersicFlux, obj.g_sersicFluxErr, obj.g_gaap1p0Flux, \" + \\\n", + " \"obj.r_sersicFlux, obj.r_sersicFluxErr, obj.r_gaap1p0Flux, \" + \\\n", + " \"obj.i_sersicFlux, obj.i_sersicFluxErr, obj.i_gaap1p0Flux, \" + \\\n", + " \"obj.i_kronFlux_flag, obj.i_cModel_flag, obj.sersic_no_data_flag \" + \\\n", + " \"FROM dp1.Object AS obj \" + \\\n", + " \"WHERE (obj.i_sersicFlux/obj.i_sersicFluxErr > 40) AND \" + \\\n", + " \"(obj.i_extendedness = 1) AND (obj.sersic_no_data_flag = 0) AND \" + \\\n", + " \"(obj.i_cModel_flag = 0) AND \" + \\\n", + " \"(scisql_nanojanskyToAbMag(obj.i_sersicFlux) > 20) AND \" + \\\n", + " \"CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), \" + \\\n", + " \"CIRCLE('ICRS',\"+str(target_ra)+\",\"+str(target_dec)+\", 0.5)) = 1 \"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "867871f3-d378-4cc5-88df-d91cfb01e259", + "metadata": {}, + "outputs": [], + "source": [ + "job = service.submit_job(query)\n", + "job.run()\n", + "job.wait(phases=['COMPLETED', 'ERROR'])\n", + "print('Job phase is', job.phase)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b6cd0ba-132a-4552-b389-32e54d8591dc", + "metadata": {}, + "outputs": [], + "source": [ + "if job.phase == 'ERROR':\n", + " job.raise_if_error()\n", + "assert job.phase == 'COMPLETED'" + ] + }, + { + "cell_type": "markdown", + "id": "f38080f1-9a2d-48af-834d-1b49de86944f", + "metadata": {}, + "source": [ + "Print the results of the search query." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e4a20e0-101d-4644-90e1-b0bd1058aae1", + "metadata": {}, + "outputs": [], + "source": [ + "results = job.fetch_result()\n", + "tab = results.to_table()\n", + "tab" + ] + }, + { + "cell_type": "markdown", + "id": "c9c94c7d-8635-4bbd-83e6-3eb64aea2b24", + "metadata": {}, + "source": [ + "Below, convert the fluxes (units $nJy$) extracted from the `objectTable` into AB magnitudes using: $m_{AB} = -2.5log( f_{nJy}) + 31.4$ (see e.g. AB Magnitudes Wikipedia page for the conversion between flux in Jy and AB magnitudes).\n", + "\n", + "> **Warning:** The following cell will produce warnings for invalid value encountered in log10, which happens if the source flux is negative. This occasionally happens from aperture photometry if the included pixels inside the aperture have negative values and can be safely ignored for this example. The log10 will return a NaN which can be filtered out later." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d58eacea-4573-433b-b9b1-382a24087dd1", + "metadata": {}, + "outputs": [], + "source": [ + "# old, does not re-set the flux to the upper limit when necessary\n", + "#cmodel_mag = -2.50 * np.log10(tab['i_cModelFlux']) + 31.4\n", + "#sersic_mag = -2.50 * np.log10(tab['i_sersicFlux']) + 31.4\n", + "#gaap_mag = -2.50 * np.log10(tab['i_gaap1p0Flux']) + 31.4\n", + "\n", + "# List of the filters you queried\n", + "#filters = ['u', 'g', 'r', 'i']\n", + "\n", + "# Temporarily ignore warnings for taking the log of negative/zero fluxes\n", + "#with np.errstate(divide='ignore', invalid='ignore'):\n", + "# for f in filters:\n", + " # 1. Convert Sersic Fluxes to AB Magnitudes\n", + " #tab[f'{f}_sersic_mag'] = -2.50 * np.log10(tab[f'{f}_sersicFlux']) + 31.4\n", + " \n", + " # 2. Convert GAAP Fluxes to AB Magnitudes\n", + " #tab[f'{f}_gaap_mag'] = -2.50 * np.log10(tab[f'{f}_gaap1p0Flux']) + 31.4\n", + " \n", + " # 3. Convert Sersic Flux Errors to Magnitude Errors\n", + " # The standard propagation of error formula for magnitudes is: \n", + " # mag_err = (2.5 / ln(10)) * (flux_err / flux)\n", + " #tab[f'{f}_sersic_magErr'] = 1.0857 * (tab[f'{f}_sersicFluxErr'] / tab[f'{f}_sersicFlux'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cdbbbc80-38e5-4ae9-bb84-6902828b13f5", + "metadata": {}, + "outputs": [], + "source": [ + "# this should be better\n", + "# List of the filters you queried\n", + "filters = ['u', 'g', 'r', 'i']\n", + "\n", + "# Use a zeropoint of 31.4 as per your specific dataset configuration\n", + "zp = 31.4\n", + "\n", + "# Temporarily ignore warnings for taking the log of negative/zero fluxes\n", + "with np.errstate(divide='ignore', invalid='ignore'):\n", + " for f in filters:\n", + " # 1. Apply Flux-Limit Logic: \n", + " # If flux is less than the error (S/N < 1), we replace it with the error \n", + " # value to calculate a 'Lower Limit' on the magnitude.\n", + " sersic_flux_robust = np.where(tab[f'{f}_sersicFlux'] < tab[f'{f}_sersicFluxErr'], \n", + " tab[f'{f}_sersicFluxErr'], \n", + " tab[f'{f}_sersicFlux'])\n", + " \n", + " #gaap_flux_robust = np.where(tab[f'{f}_gaap1p0Flux'] < tab[f'{f}_gaap1p0FluxErr'], \n", + " # tab[f'{f}_gaap1p0FluxErr'], \n", + " # tab[f'{f}_gaap1p0Flux'])\n", + "\n", + " # 2. Convert Robust Fluxes to AB Magnitudes\n", + " tab[f'{f}_sersic_mag'] = -2.50 * np.log10(sersic_flux_robust) + zp\n", + " #tab[f'{f}_gaap_mag'] = -2.50 * np.log10(gaap_flux_robust) + zp\n", + " \n", + " # 3. Convert Sersic Flux Errors to Magnitude Errors\n", + " # We use the original flux here to represent measurement uncertainty accurately\n", + " tab[f'{f}_sersic_magErr'] = 1.0857 * (tab[f'{f}_sersicFluxErr'] / tab[f'{f}_sersicFlux'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09d09866-9c0d-434b-844b-076cf34f93df", + "metadata": {}, + "outputs": [], + "source": [ + "# 1. Calculate the colors using the Sersic magnitudes you generated\n", + "# We wrap this in a mask to drop NaNs so matplotlib doesn't complain\n", + "valid_mask = np.isfinite(tab['g_sersic_mag']) & \\\n", + " np.isfinite(tab['r_sersic_mag']) & \\\n", + " np.isfinite(tab['i_sersic_mag'])\n", + "\n", + "g_mag = tab['g_sersic_mag'][valid_mask]\n", + "r_mag = tab['r_sersic_mag'][valid_mask]\n", + "i_mag = tab['i_sersic_mag'][valid_mask]\n", + "\n", + "g_minus_r = g_mag - r_mag\n", + "r_minus_i = r_mag - i_mag\n", + "\n", + "# 2. Define the z~4 LBG (g-dropout) selection criteria\n", + "# These are standard photometric cuts to isolate z~4 galaxies and exclude red dwarf stars\n", + "#is_z4_lbg = (\n", + "# (g_minus_r > 1.0) & \n", + "# (r_minus_i < 1.0) & \n", + "# (g_minus_r > 1.5 * r_minus_i + 0.8)\n", + "#)\n", + "\n", + "# 2. Define the STRICT z~4 LBG selection criteria (Purity over Completeness)\n", + "is_z4_lbg = (\n", + " (g_minus_r > 1.5) & \n", + " (r_minus_i < 1.0) & #(r_minus_i > 0) & \n", + " (g_minus_r > 1.5 * r_minus_i + 0.8)\n", + ")\n", + "\n", + "# 3. Create the Color-Color Diagram\n", + "fig, ax = plt.subplots(figsize=(8, 6))\n", + "\n", + "# Plot the background distribution of all objects (gray)\n", + "ax.scatter(r_minus_i, g_minus_r, s=5, color='gray', alpha=0.3, label='All Objects')\n", + "\n", + "# Highlight the selected z~4 LBGs (blue)\n", + "ax.scatter(r_minus_i[is_z4_lbg], g_minus_r[is_z4_lbg], \n", + " s=20, color='blue', alpha=0.8, edgecolor='white', linewidth=0.5, label='z~4 LBGs')\n", + "\n", + "# 4. Draw the Selection Boundaries for visual reference\n", + "# Calculate the vertices of the selection region\n", + "x_diag = np.linspace(0.133, 1.0, 50)\n", + "y_diag = 1.5 * x_diag + 0.8\n", + "\n", + "# Plot the bounding lines\n", + "#ax.plot([-1.5, 0.133], [1.0, 1.0], color='red', linestyle='--', lw=2, label='Selection Boundary') # Bottom horizontal cut\n", + "#ax.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut to avoid M-stars\n", + "#ax.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2)\n", + "\n", + "# Plot the updated bounding lines\n", + "# 4. Draw the NEW Selection Boundaries\n", + "# Calculate the new intersection between the horizontal and diagonal lines\n", + "intersect_x = (1.5 - 0.8) / 1.5\n", + "ax.plot([-1.5, intersect_x], [1.5, 1.5], color='red', linestyle='--', lw=2, label='Selection Boundary') # Raised horizontal cut\n", + "ax.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut\n", + "ax.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2) # Right vertical cut\n", + "\n", + "# 5. Formatting\n", + "ax.set_xlim(-1.5, 2.0)\n", + "ax.set_ylim(-1.0, 4.0)\n", + "\n", + "ax.set_xlabel(r'(r−i) [AB Mag]', fontsize=14)\n", + "ax.set_ylabel(r'(g−r) [AB Mag]', fontsize=14)\n", + "ax.set_title(r'z∼4 Lyman-Break Galaxy Selection (g-dropouts)', fontsize=16, fontweight='bold')\n", + "\n", + "ax.grid(True, linestyle=':', alpha=0.6)\n", + "ax.legend(loc='upper left', fontsize=12)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "# Print out the results\n", + "print(f\"Total objects plotted: {len(g_mag)}\")\n", + "print(f\"Identified z~4 candidates: {np.sum(is_z4_lbg)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81ade6bd-3b62-472b-a0b6-48656837bd22", + "metadata": {}, + "outputs": [], + "source": [ + "import io\n", + "import numpy as np\n", + "import astropy.units as u\n", + "from astropy.io import fits\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from pyvo.dal.adhoc import SodaQuery, DatalinkResults \n", + "from astropy.visualization import ZScaleInterval, LinearStretch, ImageNormalize\n", + "\n", + "from lsst.rsp import get_tap_service\n", + "from lsst.rsp.utils import get_pyvo_auth # <-- ADDED: The RSP auth utility\n", + "\n", + "# Initialize the TAP service AND the auth session\n", + "tap_service = get_tap_service(\"tap\")\n", + "session = get_pyvo_auth() # <-- ADDED: Define the session variable\n", + "\n", + "# Extract the coordinates of the high-purity candidates\n", + "cands_ra = tab['coord_ra'][valid_mask][is_z4_lbg]\n", + "cands_dec = tab['coord_dec'][valid_mask][is_z4_lbg]\n", + "\n", + "# Limit to the first 5 candidates so we don't spam the SODA service\n", + "n_plot = min(len(cands_ra), 15)\n", + "filters = ['u', 'g', 'r', 'i']\n", + "\n", + "# Set up the Matplotlib Grid & define Field of View\n", + "fig, axes = plt.subplots(n_plot, len(filters), figsize=(10, 2.5 * n_plot))\n", + "norm = ImageNormalize(stretch=LinearStretch(), interval=ZScaleInterval())\n", + "fov = 10.0 / 3600.0 # 10 arcseconds in degrees\n", + "\n", + "print(f\"Requesting DP1 SODA cutouts via TAP for {n_plot} candidates...\")\n", + "\n", + "for row_idx in range(n_plot):\n", + " ra = cands_ra[row_idx]\n", + " dec = cands_dec[row_idx]\n", + " \n", + " # Query the ivoa.ObsCore table using the image footprint (s_region)\n", + " query = f\"\"\"\n", + " SELECT lsst_band, access_url \n", + " FROM ivoa.ObsCore \n", + " WHERE dataproduct_subtype = 'lsst.deep_coadd' \n", + " AND obs_collection = 'LSST.DP1'\n", + " AND CONTAINS(POINT('ICRS', {ra}, {dec}), s_region) = 1\n", + " \"\"\"\n", + " \n", + " # Run the query synchronously\n", + " tap_job = tap_service.run_sync(query)\n", + " coadds = tap_job.to_table()\n", + " \n", + " for col_idx, f in enumerate(filters):\n", + " ax = axes[row_idx, col_idx] if n_plot > 1 else axes[col_idx]\n", + " \n", + " # Match the specific filter\n", + " band_match = coadds[coadds['lsst_band'] == f]\n", + " \n", + " if len(band_match) > 0:\n", + " try:\n", + " datalink_url = band_match['access_url'][0]\n", + " \n", + " # We now pass the active session to the Datalink & SODA tools\n", + " dl_result = DatalinkResults.from_result_url(datalink_url, session=session)\n", + " \n", + " # Execute the Synchronous SODA Cutout\n", + " sq = SodaQuery.from_resource(dl_result,\n", + " dl_result.get_adhocservice_by_id(\"cutout-sync\"),\n", + " session=session)\n", + " sq.circle = (ra * u.deg, dec * u.deg, fov * u.deg)\n", + " \n", + " cutout_bytes = sq.execute_stream().read()\n", + " sq.raise_if_error()\n", + " \n", + " # Open the byte stream into an Astropy FITS object\n", + " hdul = fits.open(io.BytesIO(cutout_bytes))\n", + " \n", + " # HDU 1 contains the actual science 'image' array\n", + " img_array = hdul[1].data\n", + " \n", + " # Plot the array\n", + " ax.imshow(img_array, origin='lower', cmap='gray')#, norm=norm)\n", + " \n", + " # SODA automatically centers the cutout on the requested RA/Dec\n", + " center_y, center_x = img_array.shape[0] // 2, img_array.shape[1] // 2\n", + " circle = plt.Circle((center_x, center_y), radius=5, color='red', fill=False, lw=1, alpha=0.5)\n", + " ax.add_patch(circle)\n", + "\n", + " except Exception as e:\n", + " print(f\"Error on Cand {row_idx+1} {f}-band: {e}\")\n", + " ax.text(0.5, 0.5, 'SODA Error', ha='center', va='center', transform=ax.transAxes, color='red')\n", + " else:\n", + " ax.text(0.5, 0.5, 'No Coverage', ha='center', va='center', transform=ax.transAxes, color='red')\n", + " \n", + " # Formatting\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + " \n", + " if row_idx == 0:\n", + " ax.set_title(f\"{f}-band\", fontsize=16, fontweight='bold')\n", + " if col_idx == 0:\n", + " ax.set_ylabel(f\"Cand {row_idx+1}\\nRA: {ra:.3f}\", fontsize=12, rotation=0, labelpad=40, ha='center')\n", + "\n", + "plt.subplots_adjust(wspace=0.05, hspace=0.05)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e5fd667-471d-46e0-96d1-cba433de8ead", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# 1. Identify the best candidate (the one with the reddest g-r color)\n", + "high_purity_ids = tab['objectId'][valid_mask][is_z4_lbg]\n", + "best_candidate_id = high_purity_ids[np.argmax(g_minus_r[is_z4_lbg])]\n", + "\n", + "# 2. Query all 6 bands using forced cModelFlux for accurate multi-band colors\n", + "sed_query = f\"\"\"\n", + "SELECT \n", + " u_cModelFlux, g_cModelFlux, r_cModelFlux, \n", + " i_cModelFlux, z_cModelFlux, y_cModelFlux,\n", + " u_cModelFluxErr, g_cModelFluxErr, r_cModelFluxErr, \n", + " i_cModelFluxErr, z_cModelFluxErr, y_cModelFluxErr\n", + "FROM dp1.Object \n", + "WHERE objectId = {best_candidate_id}\n", + "\"\"\"\n", + "\n", + "sed_job = tap_service.run_sync(sed_query)\n", + "sed_data = sed_job.to_table()[0] # Isolate the single row\n", + "\n", + "# 3. Define the filters and their effective wavelengths in Angstroms\n", + "filters = ['u', 'g', 'r', 'i', 'z', 'y']\n", + "wavelengths = [3671, 4826, 6223, 7545, 8691, 9710]\n", + "\n", + "mags = []\n", + "mag_errs = []\n", + "\n", + "# Convert to AB Magnitudes\n", + "with np.errstate(divide='ignore', invalid='ignore'):\n", + " for f in filters:\n", + " flux = sed_data[f'{f}_cModelFlux']\n", + " flux_err = sed_data[f'{f}_cModelFluxErr']\n", + " \n", + " mag = -2.50 * np.log10(flux) + 31.4\n", + " mag_err = 1.0857 * (flux_err / flux)\n", + " \n", + " mags.append(mag)\n", + " mag_errs.append(mag_err)\n", + " \n", + "# 4. Plot the SED\n", + "fig, ax = plt.subplots(figsize=(8, 5))\n", + "\n", + "# Plot the data (invert y-axis because lower magnitude = brighter!)\n", + "ax.errorbar(wavelengths, mags, yerr=mag_errs, fmt='o-', color='black', \n", + " markersize=8, capsize=4, linewidth=2)\n", + "ax.invert_yaxis()\n", + "\n", + "# Highlight the region absorbed by the Lyman Break\n", + "ax.axvspan(3000, 4826, color='lightblue', alpha=0.3, label='Absorbed by Neutral Hydrogen')\n", + "\n", + "# Formatting\n", + "ax.set_xticks(wavelengths)\n", + "ax.set_xticklabels(filters, fontsize=12)\n", + "ax.set_xlabel('Filter Band', fontsize=14)\n", + "ax.set_ylabel('AB Magnitude', fontsize=14)\n", + "ax.set_title(f'Spectral Energy Distribution (Candidate ID: {best_candidate_id})', fontsize=16, fontweight='bold')\n", + "\n", + "ax.grid(True, linestyle=':', alpha=0.6)\n", + "ax.legend(loc='upper right')\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c015634-0235-4329-92de-dcaf17954e3a", + "metadata": {}, + "outputs": [], + "source": [ + "import lsdb\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "print(\"Loading DP1 Photo-z LSDB catalog...\")\n", + "\n", + "# 1. Open the LSDB photo-z catalog from the RSP shared file system\n", + "pz_cat = lsdb.open_catalog(\"/rubin/lsdb_data/object_photoz\")\n", + "\n", + "# 2. Filter the catalog for our specific candidate IDs\n", + "# LSDB uses Dask under the hood for distributed computing. We access the Dask \n", + "# DataFrame (._ddf) to filter for our candidate IDs, then compute the result into a Pandas DataFrame.\n", + "pz_dask = pz_cat._ddf\n", + "matched_df = pz_dask[pz_dask['objectId'].isin(high_purity_ids)].compute()\n", + "\n", + "# Extract the redshift column. \n", + "# Note: Depending on the specific algorithm used for this DP1 release, the column \n", + "# might be named 'z_phot', 'z_mode', or 'photoZ'. If 'z_phot' throws a KeyError, \n", + "# you can use print(matched_df.columns) to check the correct name!\n", + "valid_pz = matched_df['bpz_z_mean'].dropna().values\n", + "\n", + "# 3. Plot the Histogram\n", + "fig, ax = plt.subplots(figsize=(8, 5))\n", + "\n", + "if len(valid_pz) > 0:\n", + " ax.hist(valid_pz, bins=15, color='rebeccapurple', alpha=0.8, edgecolor='white')\n", + "\n", + "# Draw a vertical line exactly at z=4 to show the target redshift\n", + "ax.axvline(4.0, color='red', linestyle='--', linewidth=2, label='Target Redshift (z=4)')\n", + "\n", + "# Formatting\n", + "ax.set_xlabel(r'Photometric Redshift (zphot)', fontsize=14)\n", + "ax.set_ylabel('Number of Galaxies', fontsize=14)\n", + "ax.set_title('Photo-z Distribution of High-Purity g-dropouts', fontsize=16, fontweight='bold')\n", + "\n", + "ax.legend()\n", + "ax.grid(True, linestyle=':', alpha=0.6)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "# Print the confirmation statistics\n", + "print(f\"Total candidates cross-matched: {len(valid_pz)}\")\n", + "if len(valid_pz) > 0:\n", + " print(f\"Median Photo-z of sample: {np.median(valid_pz):.2f}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "453cdb91-ed7d-4d32-8c3d-168648c5a976", + "metadata": {}, + "outputs": [], + "source": [ + "from astroquery.vizier import Vizier\n", + "import astropy.units as u\n", + "from astropy.coordinates import SkyCoord\n", + "import numpy as np\n", + "\n", + "print(\"Cross-matching candidates with the VANDELS DR4 Spectroscopic Catalog...\")\n", + "\n", + "# 1. Configure Vizier to search the VANDELS DR4 catalog\n", + "# We explicitly request the redshift (zspec) and the quality flag (zflg)\n", + "v = Vizier(columns=['ID', 'RAJ2000', 'DEJ2000', 'zspec', 'zflg', '_r'], \n", + " catalog=\"J/A+A/647/A150/vandels4\")\n", + "\n", + "# Optional: Remove the row limit just in case you have hundreds of candidates\n", + "v.ROW_LIMIT = -1 \n", + "\n", + "# 2. Convert your candidate coordinates into Astropy SkyCoord objects\n", + "#coords = SkyCoord(ra=cands_ra * u.deg, dec=cands_dec * u.deg, frame='icrs')\n", + "coords = SkyCoord(ra=cands_ra, dec=cands_dec, unit='deg', frame='icrs')\n", + "\n", + "# 3. Perform a cone search for every candidate using a 1 arcsecond radius\n", + "# We use a tight radius to ensure we don't accidentally match with a foreground neighbor!\n", + "try:\n", + " match_results = v.query_region(coords, radius=1.0 * u.arcsec)\n", + " \n", + " # query_region returns a list of tables. If our catalog had hits, it will be the first item.\n", + " if len(match_results) > 0:\n", + " vandels_matches = match_results[0]\n", + " \n", + " print(f\"\\nSuccess! Found {len(vandels_matches)} spectroscopic matches in VANDELS.\")\n", + " print(\"-\" * 65)\n", + " print(vandels_matches)\n", + " \n", + " # Filter for only highly reliable redshifts (zflg = 3 or 4)\n", + " reliable_mask = (vandels_matches['zflg'] == 3) | (vandels_matches['zflg'] == 4)\n", + " reliable_matches = vandels_matches[reliable_mask]\n", + " \n", + " print(f\"\\nOut of those, {len(reliable_matches)} have highly reliable redshift flags (zflg 3 or 4).\")\n", + " \n", + " else:\n", + " print(\"\\nNo spectroscopic matches found in VANDELS within 1 arcsec of these candidates.\")\n", + "\n", + "except Exception as e:\n", + " print(f\"An error occurred while querying VizieR: {e}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bdb1a87e-7af8-4d54-8588-d4e890c6b1ed", + "metadata": {}, + "outputs": [], + "source": [ + "# Search for tables related to VANDELS\n", + "tables_result = vizier_tap.search(\"SELECT table_name FROM tap_schema.tables WHERE table_name LIKE '%vandels%'\")\n", + "print(\"Found tables:\")\n", + "print(tables_result.to_table())\n", + "\n", + "# Pick the VANDELS DR4 table name from the output above (e.g., 'j/a+a/647/a150/vandels4')\n", + "# and let's check its columns\n", + "table_to_check = \"j/a+a/647/a150/vandels4\" # Update this if the print above shows a different name\n", + "cols_result = vizier_tap.search(f\"SELECT column_name FROM tap_schema.columns WHERE table_name = '{table_to_check}'\")\n", + "print(\"\\nAvailable columns:\")\n", + "print(cols_result.to_table())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "77a28f27-5a29-49ef-beb4-2eff7547a286", + "metadata": {}, + "outputs": [], + "source": [ + "from astroquery.vizier import Vizier\n", + "import astropy.units as u\n", + "from astropy.coordinates import SkyCoord\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# 1. Initialize Vizier with a clean setup\n", + "v = Vizier(columns=['RAJ2000', 'DEJ2000', 'zspec', 'zflg'])\n", + "v.ROW_LIMIT = -1\n", + "\n", + "# Use the most direct catalog identifier\n", + "cat_id = \"J/A+A/647/A150\" \n", + "\n", + "print(f\"Attempting to fetch {cat_id}...\")\n", + "\n", + "try:\n", + " # Fetch the whole catalog (it's only ~2500 rows, very light)\n", + " all_tables = v.get_catalogs(cat_id)\n", + " \n", + " # VizieR returns a list of tables; we want the one with 'vandels4' in the name or index 0\n", + " vandels_full = all_tables[0]\n", + " print(f\"Successfully retrieved {len(vandels_full)} rows.\")\n", + "\n", + " # 2. Filter locally for high-quality z~4 galaxies\n", + " # zspec: 3.5 to 4.5 | zflg: 3 or 4\n", + " mask = (vandels_full['zspec'] >= 3.5) & (vandels_full['zspec'] <= 4.5) & (vandels_full['zflg'] >= 3)\n", + " vandels_z4 = vandels_full[mask]\n", + " \n", + " print(f\"Found {len(vandels_z4)} confirmed VANDELS z~4 galaxies.\")\n", + "\n", + " # 3. Cross-match to your Rubin sample\n", + " v_coords = SkyCoord(ra=vandels_z4['RAJ2000'], dec=vandels_z4['DEJ2000'], unit='deg')\n", + " r_coords = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", + "\n", + " idx, d2d, _ = v_coords.match_to_catalog_sky(r_coords)\n", + " \n", + " # Only keep matches within 1 arcsecond\n", + " matches = d2d < 1.0 * u.arcsec\n", + " matched_idx = idx[matches]\n", + " \n", + " print(f\"Matched {len(matched_idx)} galaxies to your Rubin table.\")\n", + "\n", + " # 4. Extract colors for the Plot\n", + " ri_match = tab['r_sersic_mag'][matched_idx] - tab['i_sersic_mag'][matched_idx]\n", + " gr_match = tab['g_sersic_mag'][matched_idx] - tab['r_sersic_mag'][matched_idx]\n", + "\n", + " # 5. Plotting the results\n", + " fig, ax = plt.subplots(figsize=(8, 6))\n", + " \n", + " # Background\n", + " ax.scatter(tab['r_sersic_mag'] - tab['i_sersic_mag'], \n", + " tab['g_sersic_mag'] - tab['r_sersic_mag'], \n", + " s=1, color='gray', alpha=0.2)\n", + " \n", + " # Confirmed Gold Stars\n", + " ax.scatter(ri_match, gr_match, color='gold', marker='*', s=150, edgecolor='k', label='VANDELS z~4')\n", + " \n", + " # Your Strict Box\n", + " ax.axhline(1.5, color='blue', linestyle='--', label='Your Strict Selection')\n", + " ax.axhline(1.0, color='red', linestyle=':', label='Standard Selection')\n", + "\n", + " ax.set_xlim(-0.5, 1.5)\n", + " ax.set_ylim(-0.5, 3.5)\n", + " ax.set_xlabel('r - i')\n", + " ax.set_ylabel('g - r')\n", + " ax.legend()\n", + " plt.show()\n", + "\n", + "except Exception as e:\n", + " print(f\"Still failing: {e}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49c190e7-6426-4cc2-8d9e-b010c4d0f700", + "metadata": {}, + "outputs": [], + "source": [ + "from astroquery.vizier import Vizier\n", + "import astropy.units as u\n", + "from astropy.coordinates import SkyCoord\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# 1. Initialize Vizier \n", + "v = Vizier(columns=['**', '_r'], catalog=\"J/A+A/647/A150\")\n", + "v.ROW_LIMIT = -1\n", + "\n", + "print(f\"Attempting to fetch VANDELS Master Catalog...\")\n", + "\n", + "try:\n", + " all_tables = v.get_catalogs(\"J/A+A/647/A150\")\n", + " \n", + " # 2. Find the table that actually contains 'zspec'\n", + " vandels_data = None\n", + " for table in all_tables:\n", + " if 'zspec' in table.colnames:\n", + " vandels_data = table\n", + " break\n", + " \n", + " if vandels_data is None:\n", + " raise ValueError(\"Could not find 'zspec' column in any sub-tables.\")\n", + "\n", + " print(f\"Using table with {len(vandels_data)} entries and spectroscopic data.\")\n", + "\n", + " # 3. Filter locally for high-quality z~4 galaxies\n", + " # zspec: 3.5 to 4.5 | zflg (Quality): 3 or 4\n", + " # Note: VANDELS uses 'zflg' or 'f_zspec'—we check for either\n", + " flag_col = 'zflg' if 'zflg' in vandels_data.colnames else 'f_zspec'\n", + " \n", + " mask = (vandels_data['zspec'] >= 3.5) & (vandels_data['zspec'] <= 4.5) & (vandels_data[flag_col] >= 3)\n", + " vandels_z4 = vandels_data[mask]\n", + " \n", + " print(f\"Found {len(vandels_z4)} confirmed VANDELS z~4 galaxies.\")\n", + "\n", + " # 4. Cross-match to your Rubin sample\n", + " # Using 'RAJ2000' and 'DEJ2000' which are standard in VizieR tables\n", + " v_coords = SkyCoord(ra=vandels_z4['RAJ2000'], dec=vandels_z4['DEJ2000'], unit='deg')\n", + " r_coords = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", + "\n", + " idx, d2d, _ = v_coords.match_to_catalog_sky(r_coords)\n", + " \n", + " # Only keep matches within 1 arcsecond\n", + " matches = d2d < 1.0 * u.arcsec\n", + " matched_idx = idx[matches]\n", + " \n", + " print(f\"Matched {len(matched_idx)} galaxies to your Rubin table.\")\n", + "\n", + " # 5. Extract colors and Plot\n", + " # Ensure these column names match what you calculated in your parent 'tab'\n", + " ri_match = tab['r_sersic_mag'][matched_idx] - tab['i_sersic_mag'][matched_idx]\n", + " gr_match = tab['g_sersic_mag'][matched_idx] - tab['r_sersic_mag'][matched_idx]\n", + "\n", + " fig, ax = plt.subplots(figsize=(8, 6))\n", + " \n", + " # All background objects for context\n", + " ax.scatter(tab['r_sersic_mag'] - tab['i_sersic_mag'], \n", + " tab['g_sersic_mag'] - tab['r_sersic_mag'], \n", + " s=1, color='lightgray', alpha=0.3, label='Parent Sample')\n", + " \n", + " # The spectroscopic \"Truth\"\n", + " ax.scatter(ri_match, gr_match, color='gold', marker='*', s=150, \n", + " edgecolor='black', zorder=10, label='VANDELS Confirmed z~4')\n", + " \n", + " # Selection boundaries\n", + " ax.axhline(1.5, color='blue', linestyle='--', lw=2, label='Your Strict Cut (1.5)')\n", + " ax.axhline(1.0, color='red', linestyle=':', lw=1.5, label='Standard Cut (1.0)')\n", + "\n", + " ax.set_xlim(-0.5, 1.5)\n", + " ax.set_ylim(-0.5, 3.5)\n", + " ax.set_xlabel('$(r - i)$ color', fontsize=12)\n", + " ax.set_ylabel('$(g - r)$ color', fontsize=12)\n", + " ax.set_title('Demonstration: Validating g-dropouts with VANDELS', fontsize=14)\n", + " ax.legend(loc='upper left')\n", + " ax.grid(True, alpha=0.2)\n", + " plt.show()\n", + "\n", + "except Exception as e:\n", + " print(f\"Final Attempt Failed: {e}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14646c0e-76fd-4d28-82cb-ffdbf3dc4f9a", + "metadata": {}, + "outputs": [], + "source": [ + "from astroquery.vizier import Vizier\n", + "import astropy.units as u\n", + "from astropy.coordinates import SkyCoord\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# 1. Initialize Vizier - fetch EVERYTHING associated with the VANDELS ID\n", + "v = Vizier(columns=['**'], catalog=\"J/A+A/647/A150\")\n", + "v.ROW_LIMIT = -1\n", + "\n", + "print(\"Analyzing VANDELS Catalog Structure...\")\n", + "\n", + "try:\n", + " all_tables = v.get_catalogs(\"J/A+A/647/A150\")\n", + " \n", + " vandels_data = None\n", + " z_col_name = None\n", + " flag_col_name = None\n", + "\n", + " # 2. Iterate through all tables to find the spectroscopic data\n", + " for i, table in enumerate(all_tables):\n", + " cols = table.colnames\n", + " print(f\"\\nTable {i}: {table.meta.get('name', 'Unknown')}\")\n", + " print(f\"Columns: {cols[:10]}... ({len(cols)} total columns)\")\n", + " \n", + " # Look for the redshift column (case-insensitive)\n", + " # We look for 'z' followed by 'spec', 'mode', or just 'z'\n", + " for c in cols:\n", + " c_low = c.lower()\n", + " if c_low in ['zspec', 'z', 'z_spec', 'specz', 'z_mode']:\n", + " z_col_name = c\n", + " vandels_data = table\n", + " print(f\"--> Found Redshift Column: '{z_col_name}' in Table {i}\")\n", + " \n", + " # Now find the quality flag in the SAME table\n", + " for f in cols:\n", + " f_low = f.lower()\n", + " if f_low in ['zflg', 'f_zspec', 'q', 'qual', 'zflag']:\n", + " flag_col_name = f\n", + " print(f\"--> Found Quality Flag: '{flag_col_name}'\")\n", + " break\n", + " break\n", + " if vandels_data: break\n", + "\n", + " if vandels_data is None:\n", + " print(\"\\n[!] Error: No redshift column found. Printing all table summaries for debugging:\")\n", + " for i, t in enumerate(all_tables):\n", + " print(f\"Table {i} has columns: {t.colnames}\")\n", + " raise ValueError(\"Column discovery failed.\")\n", + "\n", + " # 3. Filter and Match (Standard workflow)\n", + " # We use a broad mask first to ensure we have data\n", + " mask = (vandels_data[z_col_name] >= 3.5) & (vandels_data[z_col_name] <= 4.5)\n", + " \n", + " # Only apply flag if we found one\n", + " if flag_col_name:\n", + " mask &= (vandels_data[flag_col_name] >= 3)\n", + " \n", + " vandels_z4 = vandels_data[mask]\n", + " print(f\"\\nFiltering complete. Found {len(vandels_z4)} high-quality z~4 candidates.\")\n", + "\n", + " # Cross-match using coordinates found in the same table\n", + " # VizieR usually uses RAJ2000/DEJ2000 or _RAJ2000/_DEJ2000\n", + " ra_col = 'RAJ2000' if 'RAJ2000' in vandels_z4.colnames else '_RAJ2000'\n", + " dec_col = 'DEJ2000' if 'DEJ2000' in vandels_z4.colnames else '_DEJ2000'\n", + "\n", + " v_coords = SkyCoord(ra=vandels_z4[ra_col], dec=vandels_z4[dec_col], unit='deg')\n", + " r_coords = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", + "\n", + " idx, d2d, _ = v_coords.match_to_catalog_sky(r_coords)\n", + " matches = d2d < 1.5 * u.arcsec # Slightly wider match for different astrometric systems\n", + " matched_idx = idx[matches]\n", + " \n", + " print(f\"Successfully matched {len(matched_idx)} galaxies to Rubin sample.\")\n", + "\n", + " # 4. Final Plot\n", + " ri_match = tab['r_sersic_mag'][matched_idx] - tab['i_sersic_mag'][matched_idx]\n", + " gr_match = tab['g_sersic_mag'][matched_idx] - tab['r_sersic_mag'][matched_idx]\n", + "\n", + " plt.figure(figsize=(8, 6))\n", + " plt.scatter(tab['r_sersic_mag'] - tab['i_sersic_mag'], \n", + " tab['g_sersic_mag'] - tab['r_sersic_mag'], \n", + " s=1, color='gray', alpha=0.2, label='Parent Sample')\n", + " plt.scatter(ri_match, gr_match, color='gold', marker='*', s=150, edgecolor='k', label='VANDELS Confirmed')\n", + " plt.axhline(1.5, color='blue', ls='--', label='Your Strict Cut')\n", + " plt.xlabel('r - i')\n", + " plt.ylabel('g - r')\n", + " plt.legend()\n", + " plt.show()\n", + "\n", + "except Exception as e:\n", + " print(f\"\\nDiscovery Failed: {e}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b46074c-d680-4a2c-8324-5b6fbcbbaa23", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from astropy.coordinates import SkyCoord\n", + "import astropy.units as u\n", + "\n", + "# 1. Select Table 0 (CDFS) and extract the confirmed high-z sample\n", + "vandels_data = all_tables[0]\n", + "\n", + "# Filter for spectroscopic redshift between 3.5 and 4.5\n", + "# We use q_zsp >= 3 (standard for high-confidence VANDELS spectra)\n", + "mask = (vandels_data['zsp'] >= 3.5) & (vandels_data['zsp'] <= 4.5) & (vandels_data['q_zsp'] >= 3)\n", + "vandels_z4 = vandels_data[mask]\n", + "\n", + "print(f\"Found {len(vandels_z4)} high-confidence VANDELS spectra in CDFS at z~4.\")\n", + "\n", + "# 2. Perform the spatial cross-match\n", + "v_coords = SkyCoord(ra=vandels_z4['RAJ2000'], dec=vandels_z4['DEJ2000'], unit='deg')\n", + "r_coords = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", + "\n", + "idx, d2d, _ = v_coords.match_to_catalog_sky(r_coords)\n", + "\n", + "# 1.0 arcsecond is usually safe for Rubin vs VLT astrometry\n", + "matches = d2d < 1.0 * u.arcsec\n", + "matched_idx = idx[matches]\n", + "\n", + "print(f\"Successfully matched {len(matched_idx)} of those to your Rubin Object table.\")\n", + "\n", + "# 3. Calculate colors for the matched objects\n", + "# Assuming 'tab' has the sersic_mags we defined earlier\n", + "ri_match = tab['r_sersic_mag'][matched_idx] - tab['i_sersic_mag'][matched_idx]\n", + "gr_match = tab['g_sersic_mag'][matched_idx] - tab['r_sersic_mag'][matched_idx]\n", + "\n", + "# 4. Plotting\n", + "plt.figure(figsize=(9, 7))\n", + "\n", + "# Background: All Rubin objects in your field\n", + "plt.scatter(tab['r_sersic_mag'] - tab['i_sersic_mag'], \n", + " tab['g_sersic_mag'] - tab['r_sersic_mag'], \n", + " s=2, color='gray', alpha=0.15, label='Rubin Parent Sample')\n", + "\n", + "# Foreground: The spectroscopic \"Truth\"\n", + "plt.scatter(ri_match, gr_match, color='gold', marker='*', s=150, \n", + " edgecolor='black', linewidth=0.8, zorder=5, label='Confirmed VANDELS z~4')\n", + "\n", + "# Draw your selection boundaries\n", + "plt.axhline(1.5, color='blue', linestyle='--', lw=2, label='Strict Selection (g-r > 1.5)')\n", + "plt.axhline(1.0, color='red', linestyle=':', lw=1.5, label='Standard Selection (g-r > 1.0)')\n", + "\n", + "# Box boundaries (approximating the dropout region)\n", + "plt.vlines(1.0, 1.0, 4.0, color='black', alpha=0.3) \n", + "\n", + "plt.xlim(-0.5, 1.5)\n", + "plt.ylim(-0.5, 3.5)\n", + "plt.xlabel('$(r - i)$ color', fontsize=12)\n", + "plt.ylabel('$(g - r)$ color', fontsize=12)\n", + "plt.title('VANDELS Spectroscopic Validation of Rubin Color Selection', fontsize=14)\n", + "plt.legend(loc='upper left', frameon=True, shadow=True)\n", + "plt.grid(True, linestyle=':', alpha=0.5)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f8819bbe-8098-41d5-b96b-6e9c85c634eb", + "metadata": {}, + "outputs": [], + "source": [ + "# 1. Take a small subset of VANDELS coordinates to test (the first 50)\n", + "test_coords = v_upload[:50]\n", + "\n", + "# 2. Build a query that fetches RAW data for these coordinates\n", + "# We are looking for why they might have been 'flagged' or 'filtered'\n", + "print(\"Investigating the 'Invisible' 218 galaxies...\")\n", + "\n", + "# We'll use a loop to check a few specific IDs if the upload continues to fail, \n", + "# but let's try a simpler 'JOIN' approach first.\n", + "discovery_query = f\"\"\"\n", + "SELECT \n", + " obj.objectId, obj.coord_ra, obj.coord_dec,\n", + " obj.g_cModelMag, obj.r_cModelMag, obj.i_cModelMag,\n", + " obj.g_extendedness, obj.r_extendedness,\n", + " obj.g_pixelFlags_saturated, obj.r_pixelFlags_saturated,\n", + " obj.g_pixelFlags_edge, obj.r_pixelFlags_edge\n", + "FROM dp1.Object AS obj\n", + "WHERE CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), \n", + " CIRCLE('ICRS', 53.125, -27.8, 0.1)) = 1\n", + " AND obj.g_cModelMag > 20 -- Just to keep the list manageable\n", + "\"\"\"\n", + "\n", + "# Run this broader query to see what the 'Total' population looks like\n", + "discovery_job = tap_service.run_sync(discovery_query)\n", + "discovery_tab = discovery_job.to_table()\n", + "\n", + "print(f\"Broad search found {len(discovery_tab)} total objects in the vicinity.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4efa3820-8dda-4d79-9b40-abcbe76fba4e", + "metadata": {}, + "outputs": [], + "source": [ + "# 1. List of RA/Dec for z~4 VANDELS confirmations\n", + "vandels_ra = vandels_z4['RAJ2000']\n", + "vandels_dec = vandels_z4['DEJ2000']\n", + "print(f\"VANDELS Truth List size: {len(vandels_ra)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e23b3a3b-bb85-4d0b-8cfb-f99132fcab3a", + "metadata": {}, + "outputs": [], + "source": [ + "# 2. Get all Rubin objects with i-band S/N > 10\n", + "# We use a 0.2 degree radius around the VANDELS center\n", + "rubin_query = \"\"\"\n", + "SELECT \n", + " objectId, coord_ra, coord_dec,\n", + " g_cModelMag, r_cModelMag, i_cModelMag,\n", + " g_cModelFlux, g_cModelFluxErr\n", + "FROM dp1.Object\n", + "WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec), \n", + " CIRCLE('ICRS', 53.125, -27.8, 0.2)) = 1\n", + " AND (i_cModelFlux / i_cModelFluxErr) > 10\n", + "\"\"\"\n", + "\n", + "print(\"Querying Rubin for all solid i-band detections...\")\n", + "rubin_job = tap_service.run_sync(rubin_query)\n", + "rubin_all = rubin_job.to_table()\n", + "print(f\"Rubin Detected List size: {len(rubin_all)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e00286f-7d96-4da5-a5dc-e0d527975a8e", + "metadata": {}, + "outputs": [], + "source": [ + "from astropy.coordinates import SkyCoord\n", + "import astropy.units as u\n", + "\n", + "# 1. Setup coordinates\n", + "c_vandels = SkyCoord(ra=vandels_ra, dec=vandels_dec, unit='deg')\n", + "c_rubin = SkyCoord(ra=rubin_all['coord_ra'], dec=rubin_all['coord_dec'], unit='deg')\n", + "\n", + "# 2. Match\n", + "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin)\n", + "match_mask = d2d < 1.0 * u.arcsec\n", + "matched_rubin = rubin_all[idx[match_mask]]\n", + "\n", + "print(f\"Found {len(matched_rubin)} matches!\")\n", + "\n", + "# 3. Handle 'NaN' in g-band (The Dropouts)\n", + "# If g is NaN, it means the flux was too low to measure a magnitude. \n", + "# We'll assign it a faint magnitude (e.g., 28) to visualize the dropout.\n", + "g_mags = matched_rubin['g_cModelMag']\n", + "r_mags = matched_rubin['r_cModelMag']\n", + "i_mags = matched_rubin['i_cModelMag']\n", + "\n", + "# Replace NaNs with 28.0 for visualization\n", + "g_plot = np.where(np.isnan(g_mags), 28.0, g_mags)\n", + "\n", + "g_r = g_plot - r_mags\n", + "r_i = r_mags - i_mags\n", + "\n", + "# 4. Plot\n", + "plt.figure(figsize=(8, 6))\n", + "\n", + "# Background (All objects from this new Rubin query)\n", + "plt.scatter(rubin_all['r_cModelMag'] - rubin_all['i_cModelMag'], \n", + " rubin_all['g_cModelMag'] - rubin_all['r_cModelMag'], \n", + " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", + "\n", + "# Matches\n", + "plt.scatter(r_i, g_r, color='gold', marker='*', s=100, edgecolor='k', label='VANDELS matches')\n", + "\n", + "plt.axhline(1.5, color='blue', linestyle='--', label='Your Strict Cut')\n", + "plt.xlabel('r - i')\n", + "plt.ylabel('g - r')\n", + "plt.xlim(-0.5, 1.5)\n", + "plt.ylim(-0.5, 3.5)\n", + "plt.title('VANDELS Confirmations in Rubin (Unfiltered)')\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7abcb043-865b-4c27-95c8-9a301b3a5ed7", + "metadata": {}, + "outputs": [], + "source": [ + "import io\n", + "import numpy as np\n", + "import astropy.units as u\n", + "from astropy.io import fits\n", + "import matplotlib.pyplot as plt\n", + "from pyvo.dal.adhoc import SodaQuery, DatalinkResults \n", + "from astropy.visualization import ZScaleInterval, LinearStretch, ImageNormalize\n", + "from lsst.rsp import get_tap_service\n", + "from lsst.rsp.utils import get_pyvo_auth \n", + "\n", + "# 1. Setup Services\n", + "tap_service = get_tap_service(\"tap\")\n", + "session = get_pyvo_auth() \n", + "\n", + "# 2. Extract coordinates and redshift reference\n", + "# match_mask was the boolean array from your local cross-match\n", + "cands_ra = vandels_z4['RAJ2000'][match_mask]\n", + "cands_dec = vandels_z4['DEJ2000'][match_mask]\n", + "cands_z = vandels_z4['zsp'][match_mask] \n", + "cands_objid = matched_rubin['objectId']\n", + "\n", + "n_plot = min(len(cands_ra), 15)\n", + "filters = ['u', 'g', 'r', 'i'] # Added u-band for the full dropout profile\n", + "\n", + "# 3. Setup Plotting\n", + "fig, axes = plt.subplots(n_plot, len(filters), figsize=(14, 3.5 * n_plot))\n", + "fov = 10.0 / 3600.0 # 10 arcseconds\n", + "\n", + "print(f\"Requesting 4-band SODA cutouts for {n_plot} VANDELS-confirmed sources...\")\n", + "\n", + "for row_idx in range(n_plot):\n", + " ra = cands_ra[row_idx]\n", + " dec = cands_dec[row_idx]\n", + " z_spec = cands_z[row_idx]\n", + " obj_id = cands_objid[row_idx]\n", + " \n", + " # Query ObsCore for deep coadds across all bands\n", + " query = f\"\"\"\n", + " SELECT lsst_band, access_url \n", + " FROM ivoa.ObsCore \n", + " WHERE dataproduct_subtype = 'lsst.deep_coadd' \n", + " AND obs_collection = 'LSST.DP1'\n", + " AND CONTAINS(POINT('ICRS', {ra}, {dec}), s_region) = 1\n", + " \"\"\"\n", + " \n", + " tap_job = tap_service.run_sync(query)\n", + " coadds = tap_job.to_table()\n", + " \n", + " for col_idx, f in enumerate(filters):\n", + " ax = axes[row_idx, col_idx] if n_plot > 1 else axes[col_idx]\n", + " \n", + " band_match = coadds[coadds['lsst_band'] == f]\n", + " \n", + " if len(band_match) > 0:\n", + " try:\n", + " datalink_url = band_match['access_url'][0]\n", + " dl_result = DatalinkResults.from_result_url(datalink_url, session=session)\n", + " \n", + " sq = SodaQuery.from_resource(dl_result,\n", + " dl_result.get_adhocservice_by_id(\"cutout-sync\"),\n", + " session=session)\n", + " sq.circle = (ra * u.deg, dec * u.deg, fov * u.deg)\n", + " \n", + " cutout_bytes = sq.execute_stream().read()\n", + " hdul = fits.open(io.BytesIO(cutout_bytes))\n", + " img_array = hdul[1].data\n", + " \n", + " # ZScale is best for seeing the noise level in dropout bands\n", + " norm = ImageNormalize(img_array, interval=ZScaleInterval(), stretch=LinearStretch())\n", + " ax.imshow(img_array, origin='lower', cmap='gray', norm=norm)\n", + " \n", + " # Marker to help identify the target in noisy u/g bands\n", + " cy, cx = img_array.shape[0]//2, img_array.shape[1]//2\n", + " ax.add_patch(plt.Circle((cx, cy), radius=4, color='cyan', fill=False, lw=1.5, alpha=0.7))\n", + "\n", + " except Exception as e:\n", + " ax.text(0.5, 0.5, 'SODA Error', ha='center', va='center', transform=ax.transAxes, color='red')\n", + " else:\n", + " ax.text(0.5, 0.5, 'No Coverage', ha='center', va='center', transform=ax.transAxes, color='red')\n", + " \n", + " ax.set_xticks([]); ax.set_yticks([])\n", + " if row_idx == 0:\n", + " ax.set_title(f\"{f}-band\", fontsize=15, fontweight='bold')\n", + " if col_idx == 0:\n", + " ax.set_ylabel(f\"z={z_spec:.2f}\\n{obj_id}\", rotation=0, labelpad=70, ha='center', fontweight='bold')\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "354dbbd9-f5df-47ee-962c-1384b7e21b29", + "metadata": {}, + "source": [ + "## 3. Total fluxes\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0cec2ebe-6134-4f86-b9de-67aa16dea0d5", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "sys.exit()" + ] + }, + { + "cell_type": "markdown", + "id": "7d75b896-770c-4d7e-94d9-7202af571209", + "metadata": {}, + "source": [ + "### 3.1. Comparing total fluxes\n", + "\n", + "This section will make several plots that shows how the different photometric measurements compare.\n", + "\n", + "First, compare `cModelFlux` (two component bulge+disk sersic model flux) to `sersicFlux` (single sersic model flux with shape parameters free), `bdFluxB` (sersic with n=4) and `bdFluxD` (sersic with n=1). " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9443b34f-9afe-4c12-b345-860896176cac", + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", + " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", + "\n", + "bins = np.arange(16, 27, 1)\n", + "\n", + "ylims = [-1.2, 1.2]\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-bdFluxD_mag), 's', alpha=.3,\n", + " label='cModel-bdFluxD', color='blue')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-bdFluxD_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='blue', lw=2, label='bin median', zorder=11)\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-bdFluxB_mag), '^', alpha=.3,\n", + " label='cModel-bdFluxB', color='r')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-bdFluxB_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='r', lw=2, label='bin median', zorder=11)\n", + "\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag - sersic_mag), 'o', alpha=.3,\n", + " label='cModel - sersic', color='g')\n", + "\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-sersic_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='g', lw=2, label='bin median', zorder=11)\n", + "\n", + "ax.axhline(0, linestyle='--')\n", + "ax.set_xlabel('cModel Magnitude')\n", + "ax.set_ylabel('cModel mag - other mag')\n", + "ax.set_ylim([-1, 1])\n", + "ax.legend()\n", + "\n", + "ax2.hist((cmodel_mag-bdFluxD_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='blue', stacked=True, fill=False, label='bdFluxD')\n", + "ax2.hist((cmodel_mag-bdFluxB_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='r', stacked=True, fill=False, label='bdFluxB')\n", + "ax2.hist((cmodel_mag-sersic_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='g', stacked=True, fill=False, label='Sersic')\n", + "\n", + "ax2.set_ylim(ylims)\n", + "ax2.axhline(0, linestyle='--', color='k')\n", + "ax.axhline(0, linestyle='--', color='k')\n", + "ax.set_xlabel('i-band AB magnitude [cModel]')\n", + "ax.set_ylabel('cModel mag - Other mag')\n", + "ax.set_ylim(ylims)\n", + "\n", + "ax.legend()\n", + "ax2.legend()" + ] + }, + { + "cell_type": "markdown", + "id": "f290d993-8645-406a-9e95-fabd852383c8", + "metadata": {}, + "source": [ + "> Figure 1: Left panel: a plot comparing the magnitude difference between cModel and dbFluxD (blue), bdFluxB (red) and sersic (green) vs i-band magnitude as measured by cModel. Right panel: a histogram showing the difference in color between cModel and the three other photometric measurements, across all magnitudes. The sersic fluxes are in best agreement with cModel (smallest scatter in right panel) with the bdFluxB returning systematically fainter magnitudes, and bdFluxD returning systematically brighter magnitudes.\n", + "\n", + "Below, explore how the BD fluxes compare to sersic fluxes as a function of the shape of the light profile, sersic index n." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c1fea6a9-fc32-43ce-bb7a-f7e23677f548", + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", + " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", + "\n", + "bins = np.arange(0, 7, 0.25)\n", + "\n", + "ylims = [-1.2, 1.2]\n", + "\n", + "ax.plot(sersic_index, (sersic_mag-bdFluxD_mag), 's', alpha=.3,\n", + " label='cModel-bdFluxD', color='blue')\n", + "x = sersic_index\n", + "y = (sersic_mag-bdFluxD_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='blue', lw=2, label='bin median', zorder=11)\n", + "\n", + "ax.plot(sersic_index, (sersic_mag-bdFluxB_mag), '^', alpha=.3,\n", + " label='cModel-bdFluxB', color='r')\n", + "x = sersic_index\n", + "y = (sersic_mag-bdFluxB_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='r', lw=2, label='bin median', zorder=11)\n", + "\n", + "ax.axhline(0, linestyle='--')\n", + "\n", + "ax.set_ylabel('sersic mag - BD mag')\n", + "ax.set_ylim([-1, 1])\n", + "ax.legend()\n", + "\n", + "\n", + "ax2.hist((cmodel_mag-bdFluxD_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='blue', stacked=True, fill=False, label='bdFluxD')\n", + "ax2.hist((cmodel_mag-bdFluxB_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='r', stacked=True, fill=False, label='bdFluxB')\n", + "\n", + "ax2.set_ylim(ylims)\n", + "ax2.axhline(0, linestyle='--', color='k')\n", + "ax.axhline(0, linestyle='--', color='k')\n", + "ax.set_xlabel('Sersic Index n')\n", + "ax.set_ylabel('Sersic mag - Other mag')\n", + "ax.set_ylim(ylims)\n", + "ax.set_xlim([0, 8])\n", + "ax.legend()\n", + "ax2.legend()" + ] + }, + { + "cell_type": "markdown", + "id": "3c44cfa4-7e2d-4c77-960d-f540683744b2", + "metadata": {}, + "source": [ + "> Fig 2: Comparison of the sersic mag (flux measured with sersic parameters left free) with the bdFlux that is measured with sersic index fixed to either n=1 (D) or n=4 (B) as a function of sersic index n. Fixing the sersic index can inject scatter in the flux relative to leaving it free, but the sersic flux converges on bdFluxD(B) for n=1 and n=4." + ] + }, + { + "cell_type": "markdown", + "id": "b7c9fdd5-3bb1-4d8c-abac-5cdafa8df188", + "metadata": {}, + "source": [ + "## 4. Apparent fluxes\n", + "\n", + "This section explores three types of apparent fluxes: Kron (elliptical apertures that typically includes more than 90% of intrinsic light), and aperture photometry (flux measured inside circles of varying size).\n", + "\n", + "Here, apparent fluxes refers to photometry that are not corrected for flux outside of the measurement aperture (i.e. not corrected to be a total flux). These measurements have their own applications but should not be used to measure mass or luminosity.\n", + " \n", + "##### Kron fluxes\n", + "\n", + "A decent summary of Kron fluxes in the NED documentation. The aperture used for the fluxes is 2.5 x R1 where R1 is the luminosity weighted radius (also called \"first moment\"; Kron et al. 1980).\n", + "\n", + "```\n", + "_kronFlux : Flux from Kron Flux algorithm. Measured on -band.\n", + "_kronFluxErr : Uncertainty of _kronFlux.\n", + "_kronFlux_flag : Failure flag for _kronFlux.\n", + "```\n", + "\n", + "The Kron radius, `_kronRad`, is also available. In this case of LSST pipeline output, the Kron flux is not corrected for light that is emitted outside of the Kron aperture. While in many cases it will collect the majority of light, it will not be as accurate as the cModel for science cases requiring total flux.\n", + "\n", + "\n", + "##### Aperture fluxes\n", + "This contains the enclosed flux inside a given aperture (and not corrected to total fluxes using an aperture correction that accounts for the flux falling outside the aperture). Fixed aperture size refers to the aperture radius in pixels.\n", + "\n", + "```\n", + "_apFlux : Flux within -pixel aperture. Forced on -band.\n", + "_apFluxErr : Uncertainty of _apFlux.\n", + "_apFluxFlag : Failure flag for _apFlux.\n", + "```\n", + "\n", + "The apertures are 3, 6, 9, 12, 17, 25, 35, 50, and 70 pixels. In the column name, apertures are `03`, `06`, `09`, `12`, and so on. While aperture fluxes are not corrected for the loss outside the aperture, if the aperture size is much larger than the galaxy size then it will approximate the total flux of the galaxy. The general application of these measurements are for measuring radial profiles (see Section 4 below).\n" + ] + }, + { + "cell_type": "markdown", + "id": "d0869336-562f-4909-8109-9a737f57877b", + "metadata": {}, + "source": [ + "### 4.1. Comparing total to apparent fluxes\n", + "\n", + "This section will make several plots that compare the `cModel` flux (which we take as the fiducial total flux, as commonly used for SDSS) to some of the apparent flux measurements. Kron, and aperture photometry are all measures of light within a fixed aperture. \n", + "\n", + "\n", + "Generally, magnitudes measured using aperture photometry in the LSST pipeline are fainter than those measured from cModel, because the fixed circular aperture systematically underestimates the flux in the galaxy wings (and the lost flux increases as the intrinsic size of the galaxy increases, e.g. as traced by the Kron radius).\n", + "\n", + "First, compare `cModel` to `Kron` which should typically enclose 90% of the light." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96dc3077-e086-430a-bace-47383bb60c97", + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", + " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", + "\n", + "bins = np.arange(16, 27, 1)\n", + "\n", + "ylims = [-1.2, 1.2]\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag - kron_mag), 's', alpha=.3,\n", + " label='cModel-Kron', color='blue')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-kron_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1]) / 2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='blue', lw=2, label='bin median', zorder=11)\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-sersic_mag), 'o', alpha=.3,\n", + " label='cModel - sersic', color='r')\n", + "\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-sersic_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='r', lw=2, label='bin median', zorder=11)\n", + "\n", + "ax.axhline(0, linestyle='--')\n", + "ax.set_xlabel('cModel Magnitude')\n", + "ax.set_ylabel('cModel mag - sersic mag')\n", + "ax.set_ylim([-1, 1])\n", + "ax.legend()\n", + "\n", + "\n", + "ax2.hist((cmodel_mag-sersic_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 50), align='mid',\n", + " histtype=\"step\", color='red', stacked=True, fill=False, label='Sersic')\n", + "ax2.hist((cmodel_mag-kron_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 50), align='mid',\n", + " histtype=\"step\", color='blue', stacked=True, fill=False, label='Kron')\n", + "\n", + "ax2.set_ylim(ylims)\n", + "ax2.axhline(0, linestyle='--', color='k')\n", + "ax.axhline(0, linestyle='--', color='k')\n", + "ax.set_xlabel('Kron Radius [i-band; pixels]')\n", + "ax.set_ylabel('cModel mag - Other mag')\n", + "ax.set_ylim(ylims)\n", + "\n", + "ax.legend()\n", + "ax2.legend()\n" + ] + }, + { + "cell_type": "markdown", + "id": "68e45fe0-9d1d-4d13-af74-9302c3f3c118", + "metadata": {}, + "source": [ + "> Figure 3: A figure comparing the difference between cModel and Kron magnitudes, compared to the difference between cModel and sersic magnitudes (left panel). Generally, both Kron and sersic the measurements are in comparable agreement with cModel. The right panel shows the histogram of magnitude differences, demonstrating that there are not systematic offsets but slightly higher scatter from Kron with respect to cModel.\n", + "\n", + "Below, explore how circular aperture photometry compares to cModel. Generally, magnitudes measured using aperture photometry in the LSST pipeline are fainter than those measured from cModel, because the fixed circular aperture systematically underestimates the flux in the galaxy wings (and the lost flux increases as the intrinsic size of the galaxy increases, e.g. as traced by the Kron radius)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f867380a-dac7-4a0b-a249-b8ee199cfdf3", + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", + " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", + "\n", + "bins = np.arange(2, 15, 1)\n", + "ylims = [-1.5, 1.5]\n", + "\n", + "ax.plot(i_kronRad, (cmodel_mag-ap06_mag), '^', alpha=.3,\n", + " label='6-pixel aperture', color='red')\n", + "ax.plot(i_kronRad, (cmodel_mag-ap09_mag), 's', alpha=.3,\n", + " label='9-pixel aperture', color='orange')\n", + "ax.plot(i_kronRad, (cmodel_mag-ap12_mag), 'o', alpha=.3,\n", + " label='12-pixel aperture', color='green')\n", + "ax.plot(i_kronRad, (cmodel_mag-ap17_mag), '.', alpha=.3,\n", + " label='17-pixel aperture', color='blue')\n", + "\n", + "ax2.hist((cmodel_mag-ap17_mag), edgecolor='blue', orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", stacked=True, fill=False)\n", + "ax2.hist((cmodel_mag-ap12_mag), edgecolor='green', orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", stacked=True, fill=False)\n", + "ax2.hist((cmodel_mag-ap09_mag), edgecolor='orange', orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", stacked=True, fill=False)\n", + "ax2.hist((cmodel_mag-ap06_mag), edgecolor='red', orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", stacked=True, fill=False)\n", + "\n", + "ax2.set_ylim(ylims)\n", + "ax.axhline(0, linestyle='--', color='k')\n", + "ax2.axhline(0, linestyle='--', color='k')\n", + "ax.set_xlabel('Kron Radius [i-band; pixels]')\n", + "ax.set_ylabel('cModel mag - Aperture mag')\n", + "ax.set_ylim(ylims)\n", + "ax.set_xlim([2, 12])\n", + "ax.legend()" + ] + }, + { + "cell_type": "markdown", + "id": "01de6505-06f2-4c80-a674-7a421613fd8c", + "metadata": {}, + "source": [ + "> Figure 4: A comparison of the difference between cModel photometry and aperture photometry measured by the LSST pipelines for four different aperture sizes as a function of galaxy size (as measured using the Kron radius). The left panel shows the scatter plot of difference in photometry vs Kron radius, and the right panel shows a histogram of these values that demonstrate that larger aperture sizes have photometry that is closer to the cModel. The right panel shows histograms of the data in the left panel, where the colors indicate for the same data in each panel." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40604f56-60f7-43d3-afe7-981950402813", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(7, 6))\n", + "ylims = [-1.2, 1.2]\n", + "bins = np.arange(16, 27, 1)\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-ap06_mag), '^', alpha=.1,\n", + " label='cModel 6-pix aperture', color='red')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-ap06_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='red', lw=2, label='bin median', zorder=10)\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-ap09_mag), 's', alpha=.1,\n", + " label='cModel 9-pix aperture', color='orange')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-ap09_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='orange', lw=2,\n", + " label='bin median', zorder=10)\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-ap12_mag), 'o', alpha=.1,\n", + " label='cModel 12-pix aperture', color='green')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-ap12_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='green', lw=2,\n", + " label='bin median', zorder=10)\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-ap17_mag), '.', alpha=.1,\n", + " label='cModel 17-pix aperture', color='blue')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-ap17_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='blue', lw=2,\n", + " label='bin median', zorder=10)\n", + "\n", + "ax.axhline(0, linestyle='--')\n", + "ax.set_xlabel('cModel Magnitude')\n", + "ax.set_ylabel('cModel mag - Aperture mag')\n", + "ax.set_ylim([-1, 1])\n", + "ax.set_xlim([20, 25])\n", + "ax.legend()" + ] + }, + { + "cell_type": "markdown", + "id": "84519e9a-0810-49b2-bcd6-1c7dd8e63124", + "metadata": {}, + "source": [ + "> Figure 5: A similar comparison of the difference between cModel photometry and aperture photometry measured by the LSST pipelines for four different aperture sizes, this time as a function of cModel magnitude. Running median is included." + ] + }, + { + "cell_type": "markdown", + "id": "d4e2093d-9d9a-41d4-9217-209519b0a6d9", + "metadata": {}, + "source": [ + "These two figures show that the aperture photometry typically under-estimates the flux relative to the total flux estimated using cModel. As expected, there is a general trend for larger apertures to get closer to the total flux from cModel for large galaxies (i.e. whose Kron Radius is larger). There is also a general trend for the aperture photometry to be less discrepant at fainter magnitudes, since faint galaxies tend to be small.\n" + ] + }, + { + "cell_type": "markdown", + "id": "3d3dd22a-80aa-4282-8c14-1f20c8525088", + "metadata": {}, + "source": [ + "### 4.2. Application of aperture photometry: radial profile\n", + "\n", + "A science application for the aperture photometry is easy visualization of the radial profile of galaxies. In the cell below, make this plot for both a large galaxy (first) and a smaller galaxy of similar brightness (second). The query looks for bright galaxies whose `cModel` magnitude ~ 20 ABmag. Dividing the aperture flux by the surface area of the aperture yields the surface brightness, which can be plotted as a function of radius from the center of the galaxy to compare radial light profiles." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "83fdc23c-6234-4156-ac4a-d340240f2762", + "metadata": {}, + "outputs": [], + "source": [ + "wh = np.where((tab['i_kronRad'] > 20) & (cmodel_mag > 20)\n", + " & (cmodel_mag < 20.5))[0]\n", + "\n", + "indx = 0\n", + "arcsec_per_pix = 0.2\n", + "\n", + "rad = np.array([3, 6, 9, 12, 17, 25, 35, 50]) * arcsec_per_pix\n", + "area = np.pi * rad**2\n", + "profile = np.array([tab['i_ap03Flux'][wh][indx], tab['i_ap06Flux'][wh][indx],\n", + " tab['i_ap09Flux'][wh][indx], tab['i_ap12Flux'][wh][indx],\n", + " tab['i_ap17Flux'][wh][indx], tab['i_ap25Flux'][wh][indx],\n", + " tab['i_ap35Flux'][wh][indx],\n", + " tab['i_ap50Flux'][wh][indx]]) / area\n", + "\n", + "plt.plot(rad, profile, linestyle=':',\n", + " label='Large Radius R='\n", + " + str(np.round(i_kronRad[wh][indx]*arcsec_per_pix, 2)))\n", + "plt.xlabel('Aperture Radius [arcsec]')\n", + "plt.ylabel(r'Surface Brightness [nJy arcsec−2]')\n", + "\n", + "wh2 = np.where((tab['i_kronRad'] < 8) & (tab['i_kronRad'] > 5)\n", + " & (cmodel_mag > 20) & (cmodel_mag < 20.5))[0]\n", + "\n", + "indx = 0\n", + "\n", + "profile = np.array([tab['i_ap03Flux'][wh2][indx], tab['i_ap06Flux'][wh2][indx],\n", + " tab['i_ap09Flux'][wh2][indx], tab['i_ap12Flux'][wh2][indx],\n", + " tab['i_ap17Flux'][wh2][indx], tab['i_ap25Flux'][wh2][indx],\n", + " tab['i_ap35Flux'][wh2][indx],\n", + " tab['i_ap50Flux'][wh2][indx]])/area\n", + "\n", + "plt.plot(rad, profile,\n", + " label='Small Radius R='\n", + " + str(round(i_kronRad[wh2][indx]*arcsec_per_pix, 2)))\n", + "plt.legend()\n", + "plt.yscale('log')" + ] + }, + { + "cell_type": "markdown", + "id": "f2fae258-ded9-4d7b-be5a-c77b1e5fbf9a", + "metadata": {}, + "source": [ + "> Figure 6: Plot demonstrating the use of aperture photometry to plot the surface brightness profile (as a function of aperture radius) for a galaxy with large Kron radius (green solid) and small Kron radius (blue dotted). " + ] + }, + { + "cell_type": "markdown", + "id": "fdc9dd4c-95fc-4ba8-96f7-3d85ea32b9f7", + "metadata": {}, + "source": [ + "## 5. Photometry for color\n", + "\n", + "This section will explore GaaP fluxes (which are optimized for measuring accurate colors between bands).\n", + "\n", + "##### GaaP fluxes\n", + "\n", + "These are the Gaussian-aperture-and-PSF flux that is defined in Kuijken et al. 2008. The main goal of this method is to measure accurate colors while accounting for the different spatial resolution between filters. This is sometimes achieved in other datasets by convolving all images to the largest PSF, but this process of PSF-matching is computationally very time consuming for large images, thus motivating GaaP as a faster alternative. It is not a measure of total flux in a filter. Several measurement apertures are available. \n", + "\n", + "**Aperture**\n", + "\n", + "```\n", + "_gaapFlux : GaaP flux with aperture after multiplying the seeing aperture. Forced on -band.\n", + "_gaapFluxErr : Uncertainty of _gaapFlux.\n", + "```\n", + "\n", + "Where the measurement apertures are 0.5, 0.7, 1.0, 1.5, 2.5, and 3.0 arcseconds. In the column name `` appears as `0p5`, `0p7`, etc. Multiplying by the \"seeing aperture\" refers to convolving the PSF with a kernel so that the PSF is as if the seeing were 1.15 arcseconds. This has the effect of smearing the images of all filters consistently so that the colors are accurate.\n", + "\n", + "For photometric redshifts, and other analysis where accurate colors are important, it is recommended to start with the GaaP fluxes with 1.0 aperture (optimal aperture was found to not perform as well, and should not be used). The largest aperture `gaap3p0` might work better for larger galaxies, but `gaap1p0` has better overall performance. Experiment yourself to see how it works for your science case.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "2468484d-3f81-4be4-b962-3a43a299f41d", + "metadata": {}, + "source": [ + "\n", + "#### 5.1. Kron and GaaP comparison\n", + "\n", + "In the next cell, compare the cModel instead to the Kron and GaaP measures. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08d1c010-a802-4d03-a035-25a07cb51c19", + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", + " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", + "ylims = [-2, 2]\n", + "\n", + "ax.plot(i_kronRad, (cmodel_mag-gaap_mag), 's', alpha=.3,\n", + " label='gaap1p0', color='orange')\n", + "\n", + "ax.plot(i_kronRad, (cmodel_mag-kron_mag), 'o', alpha=.3,\n", + " label='Kron', color='blue')\n", + "\n", + "ax2.hist((cmodel_mag-gaap_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='orange', stacked=True, fill=False, label='gaap1p0')\n", + "ax2.hist((cmodel_mag-kron_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='blue', stacked=True, fill=False, label='Kron')\n", + "\n", + "ax2.set_ylim(ylims)\n", + "ax.axhline(0, linestyle='--', color='k')\n", + "ax2.axhline(0, linestyle='--', color='k')\n", + "ax.set_xlabel('Kron Radius [i-band; pixels]')\n", + "ax.set_ylabel('cModel mag - Other mag')\n", + "ax.set_ylim(ylims)\n", + "ax.set_xlim([2, 15])\n", + "ax.legend()\n", + "ax2.legend()\n" + ] + }, + { + "cell_type": "markdown", + "id": "892f08f9-b64e-485b-8d24-97e9104778d8", + "metadata": {}, + "source": [ + "> Figure 7: The left panel figure shows the i-band magnitude difference between cModel and Kron (orange circles) and between cModel and gaap1p0 (blue squares) vs the Kron radius (a proxy for galaxy size) for the galaxies in the query. The dashed line indicates where the two magnitudes would have the same value. The gaap1p0 magnitude always underestimates the flux, but the offset becomes worse for larger galaxies (relative to the fixed aperture). The right panel shows the histogram of the magnitude differences in the left panel, illustrating that while cModel - Kron magnitudes are similar on average (blue histogram) the gaap1p0 systematically underestimates the flux relative to cModel (orange histogram). \n" + ] + }, + { + "cell_type": "markdown", + "id": "f17ac68e-312c-4d90-9191-0efe4154d8b6", + "metadata": {}, + "source": [ + "#### 5.2. CMD with GaaP\n", + "\n", + "This section demonstrates using GaaP photometry to calculate accurate galaxy colors to identify different types of galaxies. First, define magnitudes from g, r, and i band photometry. The second cell will then compare the colors of galaxies that overlap the galaxy cluster with that in the field. In clusters, galaxies tend to be old, red elliptical galaxies and thus exhibit a well defined red sequence in color space. \n", + "\n", + "The earlier query in Section 2 returned galaxies from a blank, \"field\" location (the ECDFS). These will be dominated by bluer star forming galaxies which are most common in field environments.\n", + "\n", + "Below, add a new query near a known galaxy cluster at redshift z=0.3. This is Abell 360 and sits in the DP1 data from the low ecliptic latitude field.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07de357a-44ff-448f-966b-b5c508b9dfa7", + "metadata": {}, + "outputs": [], + "source": [ + "cluster_ra = 37.83\n", + "cluster_dec = 6.98\n", + "\n", + "query = \"SELECT obj.objectId, obj.coord_ra, obj.coord_dec, \" + \\\n", + " \"obj.detect_fromBlend, obj.detect_isIsolated, \" + \\\n", + " \"obj.i_blendedness, obj.i_extendedness, \" + \\\n", + " \"obj.i_kronFlux, obj.i_kronFluxErr, obj.i_kronRad, \" + \\\n", + " \"obj.i_cModelFlux, obj.i_cModelFluxErr, obj.i_gaap1p0Flux, obj.i_gaap3p0Flux, \" + \\\n", + " \"obj.g_gaap1p0Flux, obj.g_gaap3p0Flux, \" + \\\n", + " \"obj.i_kronFlux_flag, obj.i_cModel_flag \" + \\\n", + " \"FROM dp1.Object AS obj \" + \\\n", + " \"WHERE (obj.i_cModelFlux/obj.i_cModelFluxErr > 20) AND \" + \\\n", + " \"(obj.i_extendedness = 1) AND \" + \\\n", + " \"(obj.i_kronFlux_flag = 0) AND (obj.i_cModel_flag = 0) AND \" + \\\n", + " \"CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), \" + \\\n", + " \"CIRCLE('ICRS',\"+str(cluster_ra)+\",\"+str(cluster_dec)+\", 0.2)) = 1 \"\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5973da2a-2a02-4ad0-8415-deccc55bb89c", + "metadata": {}, + "outputs": [], + "source": [ + "job = service.submit_job(query)\n", + "job.run()\n", + "job.wait(phases=['COMPLETED', 'ERROR'])\n", + "print('Job phase is', job.phase)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18bc593d-bf80-44c1-9a33-158606fa2c8c", + "metadata": {}, + "outputs": [], + "source": [ + "if job.phase == 'ERROR':\n", + " job.raise_if_error()\n", + "assert job.phase == 'COMPLETED'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32400242-e8f6-4461-941a-8617f75960de", + "metadata": {}, + "outputs": [], + "source": [ + "results = job.fetch_result()\n", + "tab2 = results.to_table()" + ] + }, + { + "cell_type": "markdown", + "id": "364f5aca-a4f7-4964-94cf-8c157b75f296", + "metadata": {}, + "source": [ + "First, calculate the magnitudes of galaxies in the 'field' location. Then, calculate the magnitudes for the other filters near the galaxy cluster from the query performed in the cell above. This will enable plotting their colors.\n", + "\n", + "> **Warning:** Like in Section 2, the following cell will produce warnings for invalid value encountered in log10, which happens if the source flux is negative. This happens for a small number of objects and since the goal of the plot is to see the distribution of the majority of sources, the warning can be safely ignored. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4fe037fb-3da7-4f82-bdc9-f62c2f701f7f", + "metadata": {}, + "outputs": [], + "source": [ + "g_field_gaap_mag = -2.50 * np.log10(tab['g_gaap1p0Flux']) + 31.4\n", + "i_field_gaap_mag = -2.50 * np.log10(tab['i_gaap1p0Flux']) + 31.4\n", + "i_field_cmodel_mag = -2.50 * np.log10(tab['i_cModelFlux']) + 31.4\n", + "i_cluster_gaap_mag = -2.50 * np.log10(tab2['i_gaap1p0Flux']) + 31.4\n", + "g_cluster_gaap_mag = -2.50 * np.log10(tab2['g_gaap1p0Flux']) + 31.4\n", + "i_cluster_cmodel_mag = -2.50 * np.log10(tab2['i_cModelFlux']) + 31.4" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "450d40b8-3e1d-4e84-81ca-8d882eef7c69", + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax, ax1) = plt.subplots(ncols=1, nrows=2, figsize=(10, 6))\n", + "\n", + "ax.plot(i_field_cmodel_mag, (g_field_gaap_mag-i_field_gaap_mag),\n", + " '.', alpha=.1, color='blue', label='Field Galaxies (ECDFS)')\n", + "ax.set_xlabel('i-band Magnitude [cModel]')\n", + "ax.set_ylabel('g-i color')\n", + "ax.set_ylim([-1, 4])\n", + "ax.legend()\n", + "\n", + "ax1.plot(i_cluster_cmodel_mag, (g_cluster_gaap_mag-i_cluster_gaap_mag),\n", + " '.', alpha=.1, color='r', label='Cluster Galaxies (Abell 360)')\n", + "ax1.set_xlabel('i-band Magnitude [cModel]')\n", + "ax1.set_ylabel('g-i color')\n", + "ax1.set_ylim([-1, 4])\n", + "ax1.legend()" + ] + }, + { + "cell_type": "markdown", + "id": "b4e3745a-8e04-4243-898c-10c8d25aae4b", + "metadata": {}, + "source": [ + "> Figure 8: The g − i vs. i color-magnitude diagram for galaxies selected in the queries. Top panel shows the galaxies selected from in a random field that does not contain a galaxy cluster (ECDFS). The bottom panel shows galaxies from a field with a galaxy cluster (A360). The cluster galaxies appear as a \"red sequence\" with red i-g colors, because the Balmer / 4000 Angstrom break spectral feature that traces older stars sits between the bands." + ] + }, + { + "cell_type": "markdown", + "id": "f4800e26-7f1f-4b50-bdf5-b3e7bba174c4", + "metadata": {}, + "source": [ + "A very nice red sequence appears from the red, old galaxies in the cluster! " + ] + }, + { + "cell_type": "markdown", + "id": "927a6cd3-5db6-4308-a7a6-2f13ccdb4568", + "metadata": {}, + "source": [ + "## 6. Exercise for the learner\n", + "\n", + "Compare the `_free_cModelFlux` measurements to `_cModelFlux` in the filters that are not the reference band where the `_cModelFlux` was measured (i.e. `refBand`). Investigate how leaving the cModel measurements free differs from the one measured with parameters fixed to the `refBand`, as a function of decreasing signal to noise. As an additional exercise, check how the signal to noise in colors measured using `_gaap1p0Flux` values compare to those measured with the larger 3.0\" aperture, `_gaap3p0Flux`, where the larger aperture may increase the noise. " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "LSST", + "language": "python", + "name": "lsst" + }, + "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.12.11" + }, + "toc-autonumbering": false + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 9fb39ff7941be6b6c2cc88601c0e99f6da853711 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Thu, 30 Apr 2026 18:16:19 +0000 Subject: [PATCH 02/27] adding 303 3 --- .../303_Galaxies/303_3_Color_selections.ipynb | 144 ++++++++++++------ 1 file changed, 95 insertions(+), 49 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 5d378560..48e7ec09 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -752,16 +752,16 @@ "outputs": [], "source": [ "# Search for tables related to VANDELS\n", - "tables_result = vizier_tap.search(\"SELECT table_name FROM tap_schema.tables WHERE table_name LIKE '%vandels%'\")\n", - "print(\"Found tables:\")\n", - "print(tables_result.to_table())\n", + "#tables_result = vizier_tap.search(\"SELECT table_name FROM tap_schema.tables WHERE table_name LIKE '%vandels%'\")\n", + "#print(\"Found tables:\")\n", + "#print(tables_result.to_table())\n", "\n", "# Pick the VANDELS DR4 table name from the output above (e.g., 'j/a+a/647/a150/vandels4')\n", "# and let's check its columns\n", - "table_to_check = \"j/a+a/647/a150/vandels4\" # Update this if the print above shows a different name\n", - "cols_result = vizier_tap.search(f\"SELECT column_name FROM tap_schema.columns WHERE table_name = '{table_to_check}'\")\n", - "print(\"\\nAvailable columns:\")\n", - "print(cols_result.to_table())" + "#table_to_check = \"j/a+a/647/a150/vandels4\" # Update this if the print above shows a different name\n", + "#cols_result = vizier_tap.search(f\"SELECT column_name FROM tap_schema.columns WHERE table_name = '{table_to_check}'\")\n", + "#print(\"\\nAvailable columns:\")\n", + "#print(cols_result.to_table())" ] }, { @@ -1103,42 +1103,6 @@ "plt.show()" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "f8819bbe-8098-41d5-b96b-6e9c85c634eb", - "metadata": {}, - "outputs": [], - "source": [ - "# 1. Take a small subset of VANDELS coordinates to test (the first 50)\n", - "test_coords = v_upload[:50]\n", - "\n", - "# 2. Build a query that fetches RAW data for these coordinates\n", - "# We are looking for why they might have been 'flagged' or 'filtered'\n", - "print(\"Investigating the 'Invisible' 218 galaxies...\")\n", - "\n", - "# We'll use a loop to check a few specific IDs if the upload continues to fail, \n", - "# but let's try a simpler 'JOIN' approach first.\n", - "discovery_query = f\"\"\"\n", - "SELECT \n", - " obj.objectId, obj.coord_ra, obj.coord_dec,\n", - " obj.g_cModelMag, obj.r_cModelMag, obj.i_cModelMag,\n", - " obj.g_extendedness, obj.r_extendedness,\n", - " obj.g_pixelFlags_saturated, obj.r_pixelFlags_saturated,\n", - " obj.g_pixelFlags_edge, obj.r_pixelFlags_edge\n", - "FROM dp1.Object AS obj\n", - "WHERE CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), \n", - " CIRCLE('ICRS', 53.125, -27.8, 0.1)) = 1\n", - " AND obj.g_cModelMag > 20 -- Just to keep the list manageable\n", - "\"\"\"\n", - "\n", - "# Run this broader query to see what the 'Total' population looks like\n", - "discovery_job = tap_service.run_sync(discovery_query)\n", - "discovery_tab = discovery_job.to_table()\n", - "\n", - "print(f\"Broad search found {len(discovery_tab)} total objects in the vicinity.\")" - ] - }, { "cell_type": "code", "execution_count": null, @@ -1194,7 +1158,7 @@ "\n", "# 2. Match\n", "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin)\n", - "match_mask = d2d < 1.0 * u.arcsec\n", + "match_mask = d2d < 1.0 * u.arcsec \n", "matched_rubin = rubin_all[idx[match_mask]]\n", "\n", "print(f\"Found {len(matched_rubin)} matches!\")\n", @@ -1212,6 +1176,8 @@ "g_r = g_plot - r_mags\n", "r_i = r_mags - i_mags\n", "\n", + "whblue = np.where(g_r < 1.5)[0]\n", + "\n", "# 4. Plot\n", "plt.figure(figsize=(8, 6))\n", "\n", @@ -1221,7 +1187,7 @@ " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", "\n", "# Matches\n", - "plt.scatter(r_i, g_r, color='gold', marker='*', s=100, edgecolor='k', label='VANDELS matches')\n", + "plt.scatter(r_i[whblue], g_r[whblue], color='gold', marker='*', s=100, edgecolor='k', label='VANDELS matches')\n", "\n", "plt.axhline(1.5, color='blue', linestyle='--', label='Your Strict Cut')\n", "plt.xlabel('r - i')\n", @@ -1233,6 +1199,86 @@ "plt.show()" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "1b4a125d-0bd3-4bbb-8376-85ac410855e1", + "metadata": {}, + "outputs": [], + "source": [ + "from astropy.coordinates import SkyCoord\n", + "import astropy.units as u\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# 1. Setup coordinates\n", + "c_vandels = SkyCoord(ra=vandels_ra, dec=vandels_dec, unit='deg')\n", + "c_rubin = SkyCoord(ra=rubin_all['coord_ra'], dec=rubin_all['coord_dec'], unit='deg')\n", + "\n", + "# 2. Match\n", + "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin)\n", + "match_mask = d2d < 1.0 * u.arcsec \n", + "matched_rubin = rubin_all[idx[match_mask]]\n", + "\n", + "# Extract the redshift for the matched objects!\n", + "# match_mask aligns with the VANDELS catalog\n", + "matched_z = vandels_z4['zsp'][match_mask] \n", + "\n", + "print(f\"Found {len(matched_rubin)} matches!\")\n", + "\n", + "# 3. Handle 'NaN' in g-band (The Dropouts)\n", + "g_mags = matched_rubin['g_cModelMag']\n", + "r_mags = matched_rubin['r_cModelMag']\n", + "i_mags = matched_rubin['i_cModelMag']\n", + "\n", + "# Replace NaNs with 28.0 for visualization\n", + "g_plot = np.where(np.isnan(g_mags), 28.0, g_mags)\n", + "\n", + "g_r = g_plot - r_mags\n", + "r_i = r_mags - i_mags\n", + "\n", + "whblue = np.where(g_r < 1.5)[0]\n", + "\n", + "# 4. Plot\n", + "# Slightly wider figure to accommodate the colorbar\n", + "plt.figure(figsize=(9, 6))\n", + "\n", + "# Background (All objects from this new Rubin query)\n", + "plt.scatter(rubin_all['r_cModelMag'] - rubin_all['i_cModelMag'], \n", + " rubin_all['g_cModelMag'] - rubin_all['r_cModelMag'], \n", + " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", + "\n", + "# Matches: Color-coded by spectroscopic redshift\n", + "# Note: Keeping your [whblue] index, but you can remove it to see all stars!\n", + "sc = plt.scatter(r_i, g_r, \n", + " c=matched_z, cmap='plasma', \n", + " marker='*', s=150, edgecolor='k', zorder=10, \n", + " label='VANDELS matches')\n", + "\n", + "# Add the colorbar\n", + "cbar = plt.colorbar(sc)\n", + "cbar.set_label('VANDELS z_spec', fontsize=12, fontweight='bold')\n", + "\n", + "plt.axhline(1.5, color='blue', linestyle='--', label='Your Strict Cut')\n", + "plt.xlabel('r - i', fontsize=12)\n", + "plt.ylabel('g - r', fontsize=12)\n", + "plt.xlim(-0.5, 1.5)\n", + "plt.ylim(-0.5, 3.5)\n", + "plt.title('VANDELS Confirmations in Rubin (Color-Coded by z)', fontsize=14)\n", + "plt.legend(loc='lower right')\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "e4fc8f40-cee2-465c-b7b4-c1a696e156d3", + "metadata": {}, + "source": [ + "Some points to consider here: the redshift window is 3.5 Date: Fri, 1 May 2026 00:44:01 +0000 Subject: [PATCH 03/27] updating 303 3 --- .../303_Galaxies/303_3_Color_selections.ipynb | 622 +++++++++++------- 1 file changed, 370 insertions(+), 252 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 48e7ec09..49b5860b 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -242,9 +242,17 @@ " \"obj.g_sersicFlux, obj.g_sersicFluxErr, obj.g_gaap1p0Flux, \" + \\\n", " \"obj.r_sersicFlux, obj.r_sersicFluxErr, obj.r_gaap1p0Flux, \" + \\\n", " \"obj.i_sersicFlux, obj.i_sersicFluxErr, obj.i_gaap1p0Flux, \" + \\\n", + " \"obj.u_cModelMag, obj.u_cModelMagErr, \" + \\\n", + " \"obj.g_cModelMag, obj.g_cModelMagErr, \" + \\\n", + " \"obj.r_cModelMag, obj.r_cModelMagErr, \" + \\\n", + " \"obj.i_cModelMag, obj.i_cModelMagErr, \" + \\\n", + " \"obj.u_cModelFlux, obj.u_cModelFluxErr, \" + \\\n", + " \"obj.g_cModelFlux, obj.g_cModelFluxErr, \" + \\\n", + " \"obj.r_cModelFlux, obj.r_cModelFluxErr, \" + \\\n", + " \"obj.i_cModelFlux, obj.i_cModelFluxErr, \" + \\\n", " \"obj.i_kronFlux_flag, obj.i_cModel_flag, obj.sersic_no_data_flag \" + \\\n", " \"FROM dp1.Object AS obj \" + \\\n", - " \"WHERE (obj.i_sersicFlux/obj.i_sersicFluxErr > 40) AND \" + \\\n", + " \"WHERE (obj.i_sersicFlux/obj.i_sersicFluxErr > 10) AND \" + \\\n", " \"(obj.i_extendedness = 1) AND (obj.sersic_no_data_flag = 0) AND \" + \\\n", " \"(obj.i_cModel_flag = 0) AND \" + \\\n", " \"(scisql_nanojanskyToAbMag(obj.i_sersicFlux) > 20) AND \" + \\\n", @@ -374,6 +382,14 @@ " tab[f'{f}_sersic_magErr'] = 1.0857 * (tab[f'{f}_sersicFluxErr'] / tab[f'{f}_sersicFlux'])" ] }, + { + "cell_type": "markdown", + "id": "8d2de168-5282-4a26-8740-930ce13e362b", + "metadata": {}, + "source": [ + "### do Lyman break selection" + ] + }, { "cell_type": "code", "execution_count": null, @@ -387,6 +403,7 @@ " np.isfinite(tab['r_sersic_mag']) & \\\n", " np.isfinite(tab['i_sersic_mag'])\n", "\n", + "#u_mag = tab['u_sersic_mag'][valid_mask]\n", "g_mag = tab['g_sersic_mag'][valid_mask]\n", "r_mag = tab['r_sersic_mag'][valid_mask]\n", "i_mag = tab['i_sersic_mag'][valid_mask]\n", @@ -404,7 +421,7 @@ "\n", "# 2. Define the STRICT z~4 LBG selection criteria (Purity over Completeness)\n", "is_z4_lbg = (\n", - " (g_minus_r > 1.5) & \n", + " (g_minus_r > 1.5) & (tab['u_sersicFlux']/tab['u_sersicFluxErr'] < 3) & \n", " (r_minus_i < 1.0) & #(r_minus_i > 0) & \n", " (g_minus_r > 1.5 * r_minus_i + 0.8)\n", ")\n", @@ -456,6 +473,14 @@ "print(f\"Identified z~4 candidates: {np.sum(is_z4_lbg)}\")" ] }, + { + "cell_type": "markdown", + "id": "29ae8710-01c3-44bb-8edc-64de3738857a", + "metadata": {}, + "source": [ + "## Sanity checks: plot cutouts and SEDs" + ] + }, { "cell_type": "code", "execution_count": null, @@ -484,7 +509,7 @@ "cands_dec = tab['coord_dec'][valid_mask][is_z4_lbg]\n", "\n", "# Limit to the first 5 candidates so we don't spam the SODA service\n", - "n_plot = min(len(cands_ra), 15)\n", + "n_plot = min(len(cands_ra), 5)\n", "filters = ['u', 'g', 'r', 'i']\n", "\n", "# Set up the Matplotlib Grid & define Field of View\n", @@ -540,7 +565,7 @@ " img_array = hdul[1].data\n", " \n", " # Plot the array\n", - " ax.imshow(img_array, origin='lower', cmap='gray')#, norm=norm)\n", + " ax.imshow(img_array, origin='lower', cmap='gray', norm=norm)\n", " \n", " # SODA automatically centers the cutout on the requested RA/Dec\n", " center_y, center_x = img_array.shape[0] // 2, img_array.shape[1] // 2\n", @@ -578,7 +603,8 @@ "\n", "# 1. Identify the best candidate (the one with the reddest g-r color)\n", "high_purity_ids = tab['objectId'][valid_mask][is_z4_lbg]\n", - "best_candidate_id = high_purity_ids[np.argmax(g_minus_r[is_z4_lbg])]\n", + "#best_candidate_id = high_purity_ids[np.argmax(g_minus_r[is_z4_lbg])]\n", + "best_candidate_id = high_purity_ids[0]#np.argmax(g_minus_r[is_z4_lbg])]\n", "\n", "# 2. Query all 6 bands using forced cModelFlux for accurate multi-band colors\n", "sed_query = f\"\"\"\n", @@ -600,12 +626,17 @@ "\n", "mags = []\n", "mag_errs = []\n", + "fluxes = []\n", + "flux_errs = []\n", "\n", "# Convert to AB Magnitudes\n", "with np.errstate(divide='ignore', invalid='ignore'):\n", " for f in filters:\n", " flux = sed_data[f'{f}_cModelFlux']\n", " flux_err = sed_data[f'{f}_cModelFluxErr']\n", + "\n", + " fluxes.append(flux)\n", + " flux_errs.append(flux_err)\n", " \n", " mag = -2.50 * np.log10(flux) + 31.4\n", " mag_err = 1.0857 * (flux_err / flux)\n", @@ -617,9 +648,9 @@ "fig, ax = plt.subplots(figsize=(8, 5))\n", "\n", "# Plot the data (invert y-axis because lower magnitude = brighter!)\n", - "ax.errorbar(wavelengths, mags, yerr=mag_errs, fmt='o-', color='black', \n", + "ax.errorbar(wavelengths, fluxes, yerr=flux_errs, fmt='o-', color='black', \n", " markersize=8, capsize=4, linewidth=2)\n", - "ax.invert_yaxis()\n", + "#ax.invert_yaxis() # for mags only\n", "\n", "# Highlight the region absorbed by the Lyman Break\n", "ax.axvspan(3000, 4826, color='lightblue', alpha=0.3, label='Absorbed by Neutral Hydrogen')\n", @@ -628,7 +659,7 @@ "ax.set_xticks(wavelengths)\n", "ax.set_xticklabels(filters, fontsize=12)\n", "ax.set_xlabel('Filter Band', fontsize=14)\n", - "ax.set_ylabel('AB Magnitude', fontsize=14)\n", + "ax.set_ylabel('Flux [nJy]', fontsize=14)\n", "ax.set_title(f'Spectral Energy Distribution (Candidate ID: {best_candidate_id})', fontsize=16, fontweight='bold')\n", "\n", "ax.grid(True, linestyle=':', alpha=0.6)\n", @@ -638,6 +669,14 @@ "plt.show()" ] }, + { + "cell_type": "markdown", + "id": "4c51bd19-e47d-4808-b334-3349d94a0924", + "metadata": {}, + "source": [ + "## Sanity check matching to Rubin photo-z catalogs" + ] + }, { "cell_type": "code", "execution_count": null, @@ -693,244 +732,12 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "id": "453cdb91-ed7d-4d32-8c3d-168648c5a976", - "metadata": {}, - "outputs": [], - "source": [ - "from astroquery.vizier import Vizier\n", - "import astropy.units as u\n", - "from astropy.coordinates import SkyCoord\n", - "import numpy as np\n", - "\n", - "print(\"Cross-matching candidates with the VANDELS DR4 Spectroscopic Catalog...\")\n", - "\n", - "# 1. Configure Vizier to search the VANDELS DR4 catalog\n", - "# We explicitly request the redshift (zspec) and the quality flag (zflg)\n", - "v = Vizier(columns=['ID', 'RAJ2000', 'DEJ2000', 'zspec', 'zflg', '_r'], \n", - " catalog=\"J/A+A/647/A150/vandels4\")\n", - "\n", - "# Optional: Remove the row limit just in case you have hundreds of candidates\n", - "v.ROW_LIMIT = -1 \n", - "\n", - "# 2. Convert your candidate coordinates into Astropy SkyCoord objects\n", - "#coords = SkyCoord(ra=cands_ra * u.deg, dec=cands_dec * u.deg, frame='icrs')\n", - "coords = SkyCoord(ra=cands_ra, dec=cands_dec, unit='deg', frame='icrs')\n", - "\n", - "# 3. Perform a cone search for every candidate using a 1 arcsecond radius\n", - "# We use a tight radius to ensure we don't accidentally match with a foreground neighbor!\n", - "try:\n", - " match_results = v.query_region(coords, radius=1.0 * u.arcsec)\n", - " \n", - " # query_region returns a list of tables. If our catalog had hits, it will be the first item.\n", - " if len(match_results) > 0:\n", - " vandels_matches = match_results[0]\n", - " \n", - " print(f\"\\nSuccess! Found {len(vandels_matches)} spectroscopic matches in VANDELS.\")\n", - " print(\"-\" * 65)\n", - " print(vandels_matches)\n", - " \n", - " # Filter for only highly reliable redshifts (zflg = 3 or 4)\n", - " reliable_mask = (vandels_matches['zflg'] == 3) | (vandels_matches['zflg'] == 4)\n", - " reliable_matches = vandels_matches[reliable_mask]\n", - " \n", - " print(f\"\\nOut of those, {len(reliable_matches)} have highly reliable redshift flags (zflg 3 or 4).\")\n", - " \n", - " else:\n", - " print(\"\\nNo spectroscopic matches found in VANDELS within 1 arcsec of these candidates.\")\n", - "\n", - "except Exception as e:\n", - " print(f\"An error occurred while querying VizieR: {e}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bdb1a87e-7af8-4d54-8588-d4e890c6b1ed", - "metadata": {}, - "outputs": [], - "source": [ - "# Search for tables related to VANDELS\n", - "#tables_result = vizier_tap.search(\"SELECT table_name FROM tap_schema.tables WHERE table_name LIKE '%vandels%'\")\n", - "#print(\"Found tables:\")\n", - "#print(tables_result.to_table())\n", - "\n", - "# Pick the VANDELS DR4 table name from the output above (e.g., 'j/a+a/647/a150/vandels4')\n", - "# and let's check its columns\n", - "#table_to_check = \"j/a+a/647/a150/vandels4\" # Update this if the print above shows a different name\n", - "#cols_result = vizier_tap.search(f\"SELECT column_name FROM tap_schema.columns WHERE table_name = '{table_to_check}'\")\n", - "#print(\"\\nAvailable columns:\")\n", - "#print(cols_result.to_table())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "77a28f27-5a29-49ef-beb4-2eff7547a286", - "metadata": {}, - "outputs": [], - "source": [ - "from astroquery.vizier import Vizier\n", - "import astropy.units as u\n", - "from astropy.coordinates import SkyCoord\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "# 1. Initialize Vizier with a clean setup\n", - "v = Vizier(columns=['RAJ2000', 'DEJ2000', 'zspec', 'zflg'])\n", - "v.ROW_LIMIT = -1\n", - "\n", - "# Use the most direct catalog identifier\n", - "cat_id = \"J/A+A/647/A150\" \n", - "\n", - "print(f\"Attempting to fetch {cat_id}...\")\n", - "\n", - "try:\n", - " # Fetch the whole catalog (it's only ~2500 rows, very light)\n", - " all_tables = v.get_catalogs(cat_id)\n", - " \n", - " # VizieR returns a list of tables; we want the one with 'vandels4' in the name or index 0\n", - " vandels_full = all_tables[0]\n", - " print(f\"Successfully retrieved {len(vandels_full)} rows.\")\n", - "\n", - " # 2. Filter locally for high-quality z~4 galaxies\n", - " # zspec: 3.5 to 4.5 | zflg: 3 or 4\n", - " mask = (vandels_full['zspec'] >= 3.5) & (vandels_full['zspec'] <= 4.5) & (vandels_full['zflg'] >= 3)\n", - " vandels_z4 = vandels_full[mask]\n", - " \n", - " print(f\"Found {len(vandels_z4)} confirmed VANDELS z~4 galaxies.\")\n", - "\n", - " # 3. Cross-match to your Rubin sample\n", - " v_coords = SkyCoord(ra=vandels_z4['RAJ2000'], dec=vandels_z4['DEJ2000'], unit='deg')\n", - " r_coords = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", - "\n", - " idx, d2d, _ = v_coords.match_to_catalog_sky(r_coords)\n", - " \n", - " # Only keep matches within 1 arcsecond\n", - " matches = d2d < 1.0 * u.arcsec\n", - " matched_idx = idx[matches]\n", - " \n", - " print(f\"Matched {len(matched_idx)} galaxies to your Rubin table.\")\n", - "\n", - " # 4. Extract colors for the Plot\n", - " ri_match = tab['r_sersic_mag'][matched_idx] - tab['i_sersic_mag'][matched_idx]\n", - " gr_match = tab['g_sersic_mag'][matched_idx] - tab['r_sersic_mag'][matched_idx]\n", - "\n", - " # 5. Plotting the results\n", - " fig, ax = plt.subplots(figsize=(8, 6))\n", - " \n", - " # Background\n", - " ax.scatter(tab['r_sersic_mag'] - tab['i_sersic_mag'], \n", - " tab['g_sersic_mag'] - tab['r_sersic_mag'], \n", - " s=1, color='gray', alpha=0.2)\n", - " \n", - " # Confirmed Gold Stars\n", - " ax.scatter(ri_match, gr_match, color='gold', marker='*', s=150, edgecolor='k', label='VANDELS z~4')\n", - " \n", - " # Your Strict Box\n", - " ax.axhline(1.5, color='blue', linestyle='--', label='Your Strict Selection')\n", - " ax.axhline(1.0, color='red', linestyle=':', label='Standard Selection')\n", - "\n", - " ax.set_xlim(-0.5, 1.5)\n", - " ax.set_ylim(-0.5, 3.5)\n", - " ax.set_xlabel('r - i')\n", - " ax.set_ylabel('g - r')\n", - " ax.legend()\n", - " plt.show()\n", - "\n", - "except Exception as e:\n", - " print(f\"Still failing: {e}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "49c190e7-6426-4cc2-8d9e-b010c4d0f700", + "cell_type": "markdown", + "id": "595f2e93-1577-4ba7-8023-877d25a24a51", "metadata": {}, - "outputs": [], "source": [ - "from astroquery.vizier import Vizier\n", - "import astropy.units as u\n", - "from astropy.coordinates import SkyCoord\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "# 1. Initialize Vizier \n", - "v = Vizier(columns=['**', '_r'], catalog=\"J/A+A/647/A150\")\n", - "v.ROW_LIMIT = -1\n", - "\n", - "print(f\"Attempting to fetch VANDELS Master Catalog...\")\n", - "\n", - "try:\n", - " all_tables = v.get_catalogs(\"J/A+A/647/A150\")\n", - " \n", - " # 2. Find the table that actually contains 'zspec'\n", - " vandels_data = None\n", - " for table in all_tables:\n", - " if 'zspec' in table.colnames:\n", - " vandels_data = table\n", - " break\n", - " \n", - " if vandels_data is None:\n", - " raise ValueError(\"Could not find 'zspec' column in any sub-tables.\")\n", - "\n", - " print(f\"Using table with {len(vandels_data)} entries and spectroscopic data.\")\n", - "\n", - " # 3. Filter locally for high-quality z~4 galaxies\n", - " # zspec: 3.5 to 4.5 | zflg (Quality): 3 or 4\n", - " # Note: VANDELS uses 'zflg' or 'f_zspec'—we check for either\n", - " flag_col = 'zflg' if 'zflg' in vandels_data.colnames else 'f_zspec'\n", - " \n", - " mask = (vandels_data['zspec'] >= 3.5) & (vandels_data['zspec'] <= 4.5) & (vandels_data[flag_col] >= 3)\n", - " vandels_z4 = vandels_data[mask]\n", - " \n", - " print(f\"Found {len(vandels_z4)} confirmed VANDELS z~4 galaxies.\")\n", - "\n", - " # 4. Cross-match to your Rubin sample\n", - " # Using 'RAJ2000' and 'DEJ2000' which are standard in VizieR tables\n", - " v_coords = SkyCoord(ra=vandels_z4['RAJ2000'], dec=vandels_z4['DEJ2000'], unit='deg')\n", - " r_coords = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", - "\n", - " idx, d2d, _ = v_coords.match_to_catalog_sky(r_coords)\n", - " \n", - " # Only keep matches within 1 arcsecond\n", - " matches = d2d < 1.0 * u.arcsec\n", - " matched_idx = idx[matches]\n", - " \n", - " print(f\"Matched {len(matched_idx)} galaxies to your Rubin table.\")\n", - "\n", - " # 5. Extract colors and Plot\n", - " # Ensure these column names match what you calculated in your parent 'tab'\n", - " ri_match = tab['r_sersic_mag'][matched_idx] - tab['i_sersic_mag'][matched_idx]\n", - " gr_match = tab['g_sersic_mag'][matched_idx] - tab['r_sersic_mag'][matched_idx]\n", - "\n", - " fig, ax = plt.subplots(figsize=(8, 6))\n", - " \n", - " # All background objects for context\n", - " ax.scatter(tab['r_sersic_mag'] - tab['i_sersic_mag'], \n", - " tab['g_sersic_mag'] - tab['r_sersic_mag'], \n", - " s=1, color='lightgray', alpha=0.3, label='Parent Sample')\n", - " \n", - " # The spectroscopic \"Truth\"\n", - " ax.scatter(ri_match, gr_match, color='gold', marker='*', s=150, \n", - " edgecolor='black', zorder=10, label='VANDELS Confirmed z~4')\n", - " \n", - " # Selection boundaries\n", - " ax.axhline(1.5, color='blue', linestyle='--', lw=2, label='Your Strict Cut (1.5)')\n", - " ax.axhline(1.0, color='red', linestyle=':', lw=1.5, label='Standard Cut (1.0)')\n", - "\n", - " ax.set_xlim(-0.5, 1.5)\n", - " ax.set_ylim(-0.5, 3.5)\n", - " ax.set_xlabel('$(r - i)$ color', fontsize=12)\n", - " ax.set_ylabel('$(g - r)$ color', fontsize=12)\n", - " ax.set_title('Demonstration: Validating g-dropouts with VANDELS', fontsize=14)\n", - " ax.legend(loc='upper left')\n", - " ax.grid(True, alpha=0.2)\n", - " plt.show()\n", - "\n", - "except Exception as e:\n", - " print(f\"Final Attempt Failed: {e}\")" + "## some failed attempts to retrieve VANDELS catalogs and spec-z columns\n", + "to clean up" ] }, { @@ -940,6 +747,8 @@ "metadata": {}, "outputs": [], "source": [ + "# dont delete, it displays the column names\n", + "\n", "from astroquery.vizier import Vizier\n", "import astropy.units as u\n", "from astropy.coordinates import SkyCoord\n", @@ -1008,6 +817,7 @@ "\n", " v_coords = SkyCoord(ra=vandels_z4[ra_col], dec=vandels_z4[dec_col], unit='deg')\n", " r_coords = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", + " #r_coords = SkyCoord(ra=cands_ra, dec=cands_dec, unit='deg')\n", "\n", " idx, d2d, _ = v_coords.match_to_catalog_sky(r_coords)\n", " matches = d2d < 1.5 * u.arcsec # Slightly wider match for different astrometric systems\n", @@ -1072,6 +882,7 @@ "# Assuming 'tab' has the sersic_mags we defined earlier\n", "ri_match = tab['r_sersic_mag'][matched_idx] - tab['i_sersic_mag'][matched_idx]\n", "gr_match = tab['g_sersic_mag'][matched_idx] - tab['r_sersic_mag'][matched_idx]\n", + "s2n_match = tab['i_sersicFlux'][matched_idx] / tab['i_sersicFluxErr'][matched_idx]\n", "\n", "# 4. Plotting\n", "plt.figure(figsize=(9, 7))\n", @@ -1129,7 +940,8 @@ "SELECT \n", " objectId, coord_ra, coord_dec,\n", " g_cModelMag, r_cModelMag, i_cModelMag,\n", - " g_cModelFlux, g_cModelFluxErr\n", + " g_cModelFlux, g_cModelFluxErr,\n", + " i_cModelFlux, i_cModelFluxErr\n", "FROM dp1.Object\n", "WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec), \n", " CIRCLE('ICRS', 53.125, -27.8, 0.2)) = 1\n", @@ -1187,9 +999,34 @@ " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", "\n", "# Matches\n", - "plt.scatter(r_i[whblue], g_r[whblue], color='gold', marker='*', s=100, edgecolor='k', label='VANDELS matches')\n", + "plt.scatter(r_i, g_r, color='gold', marker='*', s=100, edgecolor='k', label='VANDELS matches')\n", "\n", - "plt.axhline(1.5, color='blue', linestyle='--', label='Your Strict Cut')\n", + "# Highlight the selected z~4 LBGs (blue)\n", + "#plt.scatter(r_minus_i[is_z4_lbg], g_minus_r[is_z4_lbg], \n", + "# s=20, color='blue', alpha=0.8, edgecolor='white', linewidth=0.5, label='z~4 LBGs')\n", + "\n", + "\n", + "# 4. Draw the Selection Boundaries for visual reference\n", + "# Calculate the vertices of the selection region\n", + "x_diag = np.linspace(0.133, 1.0, 50)\n", + "y_diag = 1.5 * x_diag + 0.8\n", + "\n", + "# Plot the bounding lines\n", + "plt.plot([-1.5, 0.133], [1.0, 1.0], color='red', linestyle='--', lw=2, label='Selection Boundary') # Bottom horizontal cut\n", + "#ax.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut to avoid M-stars\n", + "#ax.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2)\n", + "\n", + "# Plot the updated bounding lines\n", + "# 4. Draw the NEW Selection Boundaries\n", + "# Calculate the new intersection between the horizontal and diagonal lines\n", + "intersect_x = (1.5 - 0.8) / 1.5\n", + "plt.plot([-1.5, intersect_x], [1.5, 1.5], color='red', linestyle='--', lw=2, label='Selection Boundary') # Raised horizontal cut\n", + "plt.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut\n", + "plt.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2) # Right vertical cut\n", + "\n", + "\n", + "plt.axhline(1.5, color='blue', linestyle='--', label='Strict Cut')\n", + "plt.axhline(1., color='green', linestyle='--', label='Standard Cut')\n", "plt.xlabel('r - i')\n", "plt.ylabel('g - r')\n", "plt.xlim(-0.5, 1.5)\n", @@ -1206,6 +1043,8 @@ "metadata": {}, "outputs": [], "source": [ + "# something might be wrong with the matching process, CHECK\n", + "\n", "from astropy.coordinates import SkyCoord\n", "import astropy.units as u\n", "import numpy as np\n", @@ -1214,11 +1053,13 @@ "# 1. Setup coordinates\n", "c_vandels = SkyCoord(ra=vandels_ra, dec=vandels_dec, unit='deg')\n", "c_rubin = SkyCoord(ra=rubin_all['coord_ra'], dec=rubin_all['coord_dec'], unit='deg')\n", + "#c_rubin_lbg = SkyCoord(ra=cands_ra, dec=cands_dec, unit='deg')\n", "\n", "# 2. Match\n", - "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin)\n", + "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin_lbg)\n", "match_mask = d2d < 1.0 * u.arcsec \n", "matched_rubin = rubin_all[idx[match_mask]]\n", + "#matched_rubin = tab[idx[match_mask]]\n", "\n", "# Extract the redshift for the matched objects!\n", "# match_mask aligns with the VANDELS catalog\n", @@ -1230,6 +1071,7 @@ "g_mags = matched_rubin['g_cModelMag']\n", "r_mags = matched_rubin['r_cModelMag']\n", "i_mags = matched_rubin['i_cModelMag']\n", + "s2n = matched_rubin['i_cModelFlux']/matched_rubin['i_cModelFluxErr']\n", "\n", "# Replace NaNs with 28.0 for visualization\n", "g_plot = np.where(np.isnan(g_mags), 28.0, g_mags)\n", @@ -1237,7 +1079,7 @@ "g_r = g_plot - r_mags\n", "r_i = r_mags - i_mags\n", "\n", - "whblue = np.where(g_r < 1.5)[0]\n", + "whblue = np.where(g_r > 1.5)[0]\n", "\n", "# 4. Plot\n", "# Slightly wider figure to accommodate the colorbar\n", @@ -1271,12 +1113,80 @@ "plt.show()" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ce194c9-55ac-44c7-bf29-702f2e7032bd", + "metadata": {}, + "outputs": [], + "source": [ + "from astropy.coordinates import SkyCoord\n", + "import astropy.units as u\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# 1. Setup coordinates\n", + "c_vandels = SkyCoord(ra=vandels_ra, dec=vandels_dec, unit='deg')\n", + "c_rubin = SkyCoord(ra=rubin_all['coord_ra'], dec=rubin_all['coord_dec'], unit='deg')\n", + "\n", + "# 2. Match\n", + "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin)\n", + "match_mask = d2d < 1.0 * u.arcsec \n", + "matched_rubin = rubin_all[idx[match_mask]]\n", + "\n", + "print(f\"Found {len(matched_rubin)} matches!\")\n", + "\n", + "# 3. Handle 'NaN' in g-band (The Dropouts)\n", + "g_mags = matched_rubin['g_cModelMag']\n", + "r_mags = matched_rubin['r_cModelMag']\n", + "i_mags = matched_rubin['i_cModelMag']\n", + "\n", + "# Replace NaNs with 28.0 for visualization\n", + "g_plot = np.where(np.isnan(g_mags), 28.0, g_mags)\n", + "\n", + "g_r = g_plot - r_mags\n", + "r_i = r_mags - i_mags\n", + "\n", + "# Keep only the stars below your 1.5 cut\n", + "whblue = np.where(g_r > 1.5)[0]\n", + "\n", + "# 4. Plot\n", + "plt.figure(figsize=(9, 6))\n", + "\n", + "# Background (All objects from this new Rubin query)\n", + "plt.scatter(rubin_all['r_cModelMag'] - rubin_all['i_cModelMag'], \n", + " rubin_all['g_cModelMag'] - rubin_all['r_cModelMag'], \n", + " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", + "\n", + "# Matches: Color-coded by r-band magnitude\n", + "sc = plt.scatter(r_i, g_r, \n", + " c=r_mags, cmap='viridis', \n", + " marker='*', s=150, edgecolor='k', zorder=10, \n", + " label='VANDELS matches')\n", + "\n", + "# Add the colorbar\n", + "cbar = plt.colorbar(sc)\n", + "cbar.set_label('r-band Magnitude', fontsize=12, fontweight='bold')\n", + "cbar.ax.invert_yaxis() # Invert so brighter (smaller number) is at the top\n", + "\n", + "plt.axhline(1.5, color='blue', linestyle='--', label='Your Strict Cut')\n", + "plt.xlabel('r - i', fontsize=12)\n", + "plt.ylabel('g - r', fontsize=12)\n", + "plt.xlim(-0.5, 1.5)\n", + "plt.ylim(-0.5, 3.5)\n", + "plt.title('VANDELS Confirmations in Rubin (Color-Coded by r-mag)', fontsize=14)\n", + "plt.legend(loc='lower right')\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, { "cell_type": "markdown", "id": "e4fc8f40-cee2-465c-b7b4-c1a696e156d3", "metadata": {}, "source": [ - "Some points to consider here: the redshift window is 3.5 0.15\n", + "ax.plot(z_line, z_line + 0.15*(1+z_line), color='red', linestyle=':', label='Outliers ($|\\Delta z| > 0.15(1+z)$)')\n", + "ax.plot(z_line, z_line - 0.15*(1+z_line), color='red', linestyle=':')\n", + "\n", + "# Formatting\n", + "ax.set_xlim(0, 5.5)\n", + "ax.set_ylim(0, 5.5)\n", + "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", + "ax.set_ylabel('Photometric Redshift (Rubin bpz_z_mean)', fontsize=14)\n", + "ax.set_title('Validation: Photo-z vs. Spec-z', fontsize=16, fontweight='bold')\n", + "ax.legend(loc='upper left', frameon=True)\n", + "ax.grid(True, linestyle=':', alpha=0.6)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "# 6. Calculate Standard Photo-z Quality Metrics\n", + "# dz = (z_phot - z_spec) / (1 + z_spec)\n", + "dz = (z_phot_clean - z_spec_clean) / (1 + z_spec_clean)\n", + "\n", + "# NMAD: Normalized Median Absolute Deviation (A robust measure of scatter)\n", + "nmad = 1.48 * np.median(np.abs(dz - np.median(dz)))\n", + "\n", + "# Outlier Fraction: Percentage of objects outside the red dotted lines\n", + "outlier_fraction = np.sum(np.abs(dz) > 0.15) / len(dz)\n", + "\n", + "print(f\"--- Photo-z Performance Metrics ---\")\n", + "print(f\"Robust Scatter ($\\sigma_{{NMAD}}$): {nmad:.3f}\")\n", + "print(f\"Catastrophic Outlier Fraction: {outlier_fraction:.1%}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "57b52d6b-2441-4b38-ae0f-cff23504b472", + "metadata": {}, + "outputs": [], + "source": [ + "import astropy.units as u\n", + "from astropy.coordinates import SkyCoord\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "print(\"Preparing VANDELS and LSDB catalogs for cross-matching...\")\n", + "\n", + "# 1. Extract the full VANDELS coordinates and spec-z\n", + "v_ra = vandels_data['RAJ2000']\n", + "v_dec = vandels_data['DEJ2000']\n", + "v_zspec = vandels_data['zsp']\n", + "v_coords = SkyCoord(ra=v_ra, dec=v_dec, unit='deg')\n", + "\n", + "# 2. Filter the massive LSDB catalog down to the CDFS region\n", + "print(\"Running LSDB cone search on the VANDELS footprint...\")\n", + "pz_regional = pz_cat.cone_search(ra=53.125, dec=-27.8, radius_arcsec=1800).compute()\n", + "\n", + "# 3. Setup the Rubin coordinates\n", + "rubin_coords = SkyCoord(ra=pz_regional['coord_ra'].values, \n", + " dec=pz_regional['coord_dec'].values, \n", + " unit='deg')\n", + "\n", + "# 4. Perform the spatial cross-match\n", + "print(\"Performing spatial cross-match...\")\n", + "idx, d2d, _ = v_coords.match_to_catalog_sky(rubin_coords)\n", + "match_mask = d2d < 1.0 * u.arcsec\n", + "\n", + "# Extract the matched data\n", + "matched_rubin_pz = pz_regional.iloc[idx[match_mask]]\n", + "matched_v_zspec = v_zspec[match_mask]\n", + "matched_v_zphot = matched_rubin_pz['bpz_z_mean'].values\n", + "\n", + "# Check the column name for i-band magnitude in the photo-z catalog\n", + "if 'i_cModelMag' in matched_rubin_pz.columns:\n", + " matched_i_mag = matched_rubin_pz['i_cModelMag'].values\n", + "elif 'mag_i' in matched_rubin_pz.columns:\n", + " matched_i_mag = matched_rubin_pz['mag_i'].values\n", + "else:\n", + " # If it throws an error here, print matched_rubin_pz.columns to find the exact name!\n", + " print(\"Warning: Could not find i-band magnitude column. Using placeholder.\")\n", + " matched_i_mag = np.zeros(len(matched_v_zphot))\n", + "\n", + "# Clean out any rows with NaNs in z_phot, z_spec, OR i_mag to keep arrays aligned\n", + "valid = ~np.isnan(matched_v_zphot) & ~np.isnan(matched_v_zspec) & ~np.isnan(matched_i_mag)\n", + "z_spec_clean = matched_v_zspec[valid]\n", + "z_phot_clean = matched_v_zphot[valid]\n", + "i_mag_clean = matched_i_mag[valid]\n", + "\n", + "print(f\"Successfully matched {len(z_spec_clean)} galaxies with Spec-z, Photo-z, and i-mag!\")\n", + "\n", + "# 5. Plot Photo-z vs Spec-z\n", + "fig, ax = plt.subplots(figsize=(9, 7)) # Slightly wider for the colorbar\n", + "\n", + "# Scatter plot: Color-coded by i-band magnitude\n", + "sc = ax.scatter(z_spec_clean, z_phot_clean, c=i_mag_clean, cmap='viridis', \n", + " s=35, alpha=0.8, edgecolor='k', linewidth=0.5, zorder=5)\n", + "\n", + "# Add the colorbar\n", + "cbar = plt.colorbar(sc, ax=ax)\n", + "cbar.set_label('i-band Magnitude', fontsize=12, fontweight='bold')\n", + "cbar.ax.invert_yaxis() # Invert so brighter (smaller number) is at the top\n", + "\n", + "# Perfect agreement line (1:1)\n", + "z_line = np.linspace(0, 6, 100)\n", + "ax.plot(z_line, z_line, color='black', linestyle='--', linewidth=2, label='1:1 Agreement')\n", + "\n", + "# Catastrophic outlier boundaries\n", + "ax.plot(z_line, z_line + 0.15*(1+z_line), color='red', linestyle=':', label='Outlier Boundary ($|\\Delta z| > 0.15(1+z)$)')\n", + "ax.plot(z_line, z_line - 0.15*(1+z_line), color='red', linestyle=':')\n", + "\n", + "# Formatting\n", + "ax.set_xlim(0, 5.5)\n", + "ax.set_ylim(0, 5.5)\n", + "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", + "ax.set_ylabel('Photometric Redshift (Rubin bpz_z_mean)', fontsize=14)\n", + "ax.set_title('Validation: Photo-z vs. Spec-z (Colored by i-mag)', fontsize=16, fontweight='bold')\n", + "\n", + "# Combine legends\n", + "handles, labels = ax.get_legend_handles_labels()\n", + "ax.legend(handles, labels, loc='upper left', frameon=True)\n", + "ax.grid(True, linestyle=':', alpha=0.6)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "# 6. Calculate Standard Photo-z Quality Metrics\n", + "dz = (z_phot_clean - z_spec_clean) / (1 + z_spec_clean)\n", + "nmad = 1.48 * np.median(np.abs(dz - np.median(dz)))\n", + "outlier_fraction = np.sum(np.abs(dz) > 0.15) / len(dz)\n", + "\n", + "print(f\"--- Photo-z Performance Metrics ---\")\n", + "print(f\"Robust Scatter ($\\sigma_{{NMAD}}$): {nmad:.3f}\")\n", + "print(f\"Catastrophic Outlier Fraction: {outlier_fraction:.1%}\")" + ] + }, { "cell_type": "markdown", "id": "354dbbd9-f5df-47ee-962c-1384b7e21b29", From 922b88a68ad748f513cbc9a1464badcb218abe55 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Fri, 22 May 2026 22:54:44 +0000 Subject: [PATCH 04/27] updating color selections --- .../303_Galaxies/303_3_Color_selections.ipynb | 2427 +++-------------- .../Color_selections_exploration.ipynb | 2242 +++++++++++++++ 2 files changed, 2696 insertions(+), 1973 deletions(-) create mode 100644 DP1/300_Science_Demos/303_Galaxies/Color_selections_exploration.ipynb diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 49b5860b..e979e53c 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -7,7 +7,7 @@ } }, "cell_type": "markdown", - "id": "325aa8a5-92fd-4913-a471-ad1617343be6", + "id": "ab80c8e2-f477-40df-ba82-d1cbbe2b5892", "metadata": {}, "source": [ "# 303.3. Color Selections\n", @@ -28,7 +28,7 @@ }, { "cell_type": "markdown", - "id": "9da1a210-d858-42fe-8591-570965b8be1a", + "id": "63df5e4e-1960-4622-8aab-ec4ad076c33b", "metadata": {}, "source": [ "**Learning objective:** Explore the available measurements of galaxy photometry produced by the LSST pipelines and their applications.\n", @@ -48,2173 +48,655 @@ ] }, { - "attachments": {}, "cell_type": "markdown", - "id": "cfc73be0", + "id": "938cb660-8449-4014-9610-b36a877aea6c", "metadata": {}, "source": [ - "## 1. Introduction \n", + "Cell 1: Imports and Initialization\n", "\n", - "Photometry is the measurement of how much light is apparent from astronomical sources. The amount of light arriving on the telescope from the object is typically referred to as the flux density, or apparent magnitude (depending on units). Flux density is defined as the amount of energy arriving on the telescope per unit area, per unit time, per unit frequency (or wavelength) of the light.\n", - "\n", - "The LSST Science Pipelines makes a variety of photometric measurements for point-like and extended sources. This notebook will teach the user about the automated photometry measurements for extended sources that are measured on the deepCoadd images and appear in the Object Catalog as part of the LSST pipelines data products.\n", - "\n", - "The photometry measurements in the catalogs are flux densities in units of nano-Jansky [nJy]. 1 Jy = 10^{-23} ergs/s/cm^2/Hz." - ] - }, - { - "cell_type": "markdown", - "id": "dc36f107", - "metadata": {}, - "source": [ - "### 1.1. Import packages\n", - "\n", - "Import `numpy`, a fundamental package for scientific computing with arrays in Python\n", - "(numpy.org), and\n", - "`matplotlib`, a comprehensive library for data visualization\n", - "(matplotlib.org; \n", - "matplotlib gallery).\n", - "\n", - "From the `lsst` package, import modules for accessing the Table Access Protocol (TAP) service,\n", - "the butler, and image display functions from the LSST Science Pipelines (pipelines.lsst.io)." + "This cell loads all the necessary libraries and sets up your Rubin Science Platform authentication." ] }, { "cell_type": "code", "execution_count": null, - "id": "cddc1458", + "id": "f08e4058-916b-4954-b1e5-554793159aac", "metadata": {}, "outputs": [], "source": [ + "import io\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "from astropy.io import fits\n", + "from astropy.coordinates import SkyCoord\n", + "import astropy.units as u\n", + "from astropy.visualization import ZScaleInterval, LinearStretch, ImageNormalize\n", + "from astroquery.vizier import Vizier\n", + "from pyvo.dal.adhoc import SodaQuery, DatalinkResults\n", + "import lsdb\n", "\n", "from lsst.rsp import get_tap_service\n", + "from lsst.rsp.utils import get_pyvo_auth\n", "\n", - "from scipy.stats import binned_statistic" - ] - }, - { - "cell_type": "markdown", - "id": "c217adff-25ed-4fce-95e7-8aa04630f6cc", - "metadata": {}, - "source": [ - "### 1.2. Define parameters and functions" + "# Initialize RSP services\n", + "tap_service = get_tap_service(\"tap\")\n", + "session = get_pyvo_auth()\n", + "\n", + "# Set our target field (ECDFS)\n", + "target_ra = 53.125\n", + "target_dec = -27.8" ] }, { "cell_type": "markdown", - "id": "d3383f6e-8c34-4cb7-aa2f-12e9b7f8efc0", + "id": "30d04fb9-a3a3-4c34-b6f8-496e7c648435", "metadata": {}, "source": [ - "Get an instance of the TAP service, and assert that it exists." + "Cell 2: Query Rubin Data & Calculate Robust MagnitudesThis retrieves the Rubin sources, enforces the $S/N > 10$ cut on the $i$-band, and creates \"robust\" magnitudes that properly handle dropouts." ] }, { "cell_type": "code", "execution_count": null, - "id": "e8184089-8a3e-4666-a194-5362a8faa541", + "id": "a22963fc-ef6b-40b7-8e95-1a07d7e264d3", "metadata": {}, "outputs": [], "source": [ - "service = get_tap_service(\"tap\")\n", - "assert service is not None" - ] - }, - { - "cell_type": "markdown", - "id": "557bbb99-3a37-4b15-ad6d-e86c6282866c", - "metadata": {}, - "source": [ - "## 2. Types of photometry\n", + "print(\"1. Querying Rubin DP1 Catalog...\")\n", + "query = f\"\"\"\n", + "SELECT obj.objectId, obj.coord_ra, obj.coord_dec,\n", + " obj.u_sersicFlux, obj.u_sersicFluxErr,\n", + " obj.g_sersicFlux, obj.g_sersicFluxErr,\n", + " obj.r_sersicFlux, obj.r_sersicFluxErr,\n", + " obj.i_sersicFlux, obj.i_sersicFluxErr\n", + "FROM dp1.Object AS obj\n", + "WHERE (obj.i_sersicFlux/obj.i_sersicFluxErr > 10) \n", + " AND (obj.i_extendedness = 1) \n", + " AND (obj.sersic_no_data_flag = 0) \n", + " AND (obj.i_cModel_flag = 0) \n", + " AND CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), CIRCLE('ICRS', {target_ra}, {target_dec}, 0.2)) = 1\n", + "\"\"\"\n", "\n", - "This section will explore photometry measurements produced by the LSST pipelines, and provide some guidance for which are optimal for various applications for science with galaxies. \n", - "### 2.1. Explore the schema\n", + "job = tap_service.run_sync(query)\n", + "tab = job.to_table()\n", + "print(f\" -> Retrieved {len(tab)} Rubin sources.\")\n", "\n", - "Numerous photometry measurements are produced by the LSST Pipelines. Two types of photometry are in the object table. The first are total fluxes (see Section 3), which aim to approximate (or model) all of the light coming from object. The second class of fluxes are measured inside an on-sky aperture but not corrected for flux that may fall outside: thus they are apparent fluxes but do not recover the intrisic (total) flux (see Section 4 and 5). The apparent fluxes are optimized for other purposes, such as for measuring accurate light profiles or accurate colors. \n", + "print(\"2. Calculating Robust Sersic Magnitudes...\")\n", + "filters = ['u', 'g', 'r', 'i']\n", + "zp = 31.4\n", + "\n", + "with np.errstate(divide='ignore', invalid='ignore'):\n", + " for f in filters:\n", + " # Replace flux with the error floor if S/N < 1\n", + " flux_robust = np.where(tab[f'{f}_sersicFlux'] < tab[f'{f}_sersicFluxErr'], \n", + " tab[f'{f}_sersicFluxErr'], \n", + " tab[f'{f}_sersicFlux'])\n", + " tab[f'{f}_mag_robust'] = -2.50 * np.log10(flux_robust) + zp\n", "\n", - "Schema for the object catalog for DP1 is available here. It lists the catalog header and brief explanation of the parameters.\n", - "\n" + "# Calculate global colors for the whole Rubin table\n", + "tab['g_minus_r'] = tab['g_mag_robust'] - tab['r_mag_robust']\n", + "tab['r_minus_i'] = tab['r_mag_robust'] - tab['i_mag_robust']" ] }, { "cell_type": "markdown", - "id": "1513ee4c-0a00-4868-8525-53aaccfff9b1", - "metadata": {}, - "source": [ - "First, see what is available in the object table by querying the `tap_schema` columns, and printing all the parameters available related to \"Flux\" measured in the i-band (as an example). For clarity, the return also omits errors and flags associated with the photometric measurements outlined in section 1.1. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3d532f5a-52ad-408d-bce6-a5a4d346477f", + "id": "34cc9127-8e63-4af0-abc0-9d926b91addd", "metadata": {}, - "outputs": [], "source": [ - "query = \"SELECT column_name, datatype, description, unit \" \\\n", - " \"FROM tap_schema.columns \" \\\n", - " \"WHERE table_name = 'dp1.Object'\"\n", + "Cell 3: Fetch VANDELS Truth & Rubin Photo-z\n", "\n", - "results = service.search(query).to_table()" + "This fetches your two validation datasets: the spectroscopic ground truth from VizieR, and the photometric redshifts from LSDB. It then maps the photo-z directly into your Rubin table." ] }, { "cell_type": "code", "execution_count": null, - "id": "84849d6b-527d-4ac7-9cbb-09df352f7b34", + "id": "1b5fb7c7-8db0-44e9-9552-874e77c62925", "metadata": {}, "outputs": [], "source": [ - "search_string = 'Flux'\n", - "band = 'i_'\n", - "exclude1 = 'Err'\n", - "exclude2 = 'flag'\n", - "for cname in results['column_name']:\n", - " if cname.find(search_string) > -1 and cname.find(band) > -1 and \\\n", - " cname.find(exclude1) == -1 and cname.find(exclude2) == -1:\n", - "\n", - " print(cname)" + "print(\"1. Fetching VANDELS Spectroscopic Catalog from VizieR...\")\n", + "v = Vizier(columns=['**'], catalog=\"J/A+A/647/A150\")\n", + "v.ROW_LIMIT = -1\n", + "all_tables = v.get_catalogs(\"J/A+A/647/A150\")\n", + "vandels_cdfs = all_tables[0] \n", + "\n", + "# Isolate high-confidence z~4 spectra (3.5 <= z <= 4.5)\n", + "is_vandels_z4 = (vandels_cdfs['zsp'] >= 3.5) & (vandels_cdfs['zsp'] <= 4.5) & (vandels_cdfs['q_zsp'] >= 3)\n", + "vandels_truth = vandels_cdfs[is_vandels_z4]\n", + "print(f\" -> Found {len(vandels_truth)} high-confidence VANDELS sources at z~4\")\n", + "\n", + "print(\"\\n2. Fetching regional Rubin Photo-z catalog via LSDB...\")\n", + "pz_cat = lsdb.open_catalog(\"/rubin/lsdb_data/object_photoz\")\n", + "# 1800 arcseconds = 0.5 degrees\n", + "pz_regional = pz_cat.cone_search(ra=target_ra, dec=target_dec, radius_arcsec=1800).compute()\n", + "print(f\" -> Found photo-z data for {len(pz_regional)} objects in this region.\")\n", + "\n", + "# Map the photo-z values directly into our main Astropy 'tab'\n", + "pz_series = pz_regional.set_index('objectId')['cmnn_z_mean'] # bpz seems to suck ['bpz_z_mean']\n", + "tab['z_phot'] = pz_series.reindex(tab['objectId']).values" ] }, { "cell_type": "markdown", - "id": "5dd9c7cb-8ab0-4f7c-9161-69fa29d46537", + "id": "fe011d0d-4077-402c-be5d-176d23c33439", "metadata": {}, "source": [ - "The object catalog also has pre-computed AB magnitudes (`Mag` columns) for cModel and PSF. Query the `tap_schema` columns, and print all the parameters available related to `Mag` measured in the i-band. " + "Cell 4: Lyman Break Selection & Cross-Matching\n", + "\n", + "Here we perform the strict LBG selection on the Rubin data, then match it against the VANDELS truth catalog to see what passed and what failed" ] }, { "cell_type": "code", "execution_count": null, - "id": "6225c1c4-e324-4846-b49b-06471a4abe59", + "id": "e33eb697-42d8-4f39-9e22-ce75b4b23e4c", "metadata": {}, "outputs": [], "source": [ - "search_string = 'Mag'\n", - "band = 'i_'\n", - "exclude1 = 'Err'\n", - "for cname in results['column_name']:\n", - " if cname.find(search_string) > -1 and cname.find(band) > -1 and \\\n", - " cname.find(exclude1) == -1:\n", - "\n", - " print(cname)" - ] - }, - { - "cell_type": "markdown", - "id": "ac0528ca-2ec6-405e-b4ea-e897ef96de67", - "metadata": {}, - "source": [ + "print(\"1. Performing Strict Lyman Break Selection...\")\n", + "is_z4_lbg = (\n", + " (tab['g_minus_r'] > 1.5) & \n", + " (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3) & \n", + " (tab['r_minus_i'] < 1.0) & \n", + " (tab['g_minus_r'] > 1.5 * tab['r_minus_i'] + 0.8)\n", + ")\n", + "print(f\" -> Identified {np.sum(is_z4_lbg)} photometric LBG candidates.\")\n", "\n", - "### 2.2. Select a galaxy sample\n", + "print(\"\\n2. Cross-matching VANDELS Truth to Rubin Object Table...\")\n", + "coord_v = SkyCoord(ra=vandels_truth['RAJ2000'], dec=vandels_truth['DEJ2000'], unit='deg')\n", + "coord_r = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", "\n", - "Below, query the DP1 `objectTable` for a selection of photometric measurements. \n", + "idx_rubin, d2d, _ = coord_v.match_to_catalog_sky(coord_r)\n", + "match_mask = d2d < 1.0 * u.arcsec\n", "\n", - "Limit the search to contain galaxies using the `i_extendedness` flag (which will exclude point sources). Further, identify objects which have been detected at high signal to noise > 20 and whose photometric measurements have not been flagged as having an issue (`i_kronFlux_flag` or `i_cModel_flag` or `sersic_no_data_flag` = 0 means the photometry is ok). Also exclude very bright galaxies (i-band magnitude < 20).\n", + "# Isolate the matched sources\n", + "matched_rubin_indices = idx_rubin[match_mask]\n", + "vandels_in_rubin = tab[matched_rubin_indices]\n", + "v_matched_truth = vandels_truth[match_mask]\n", "\n", - "Search for the sample using the DP1 imaging obtained in the Extended Chandra Deep Field South (ECDFS; center ra, dec = 53.2, -28.1 in degrees) which was one of the deepest imaging obtained as part of DP1.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "73dd5a5f-b761-4d4f-96b6-5767cffbb310", - "metadata": {}, - "outputs": [], - "source": [ - "target_ra = 53.2\n", - "target_dec = -28.1" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "75150971-e118-48d5-9db7-74c0fe600762", - "metadata": {}, - "outputs": [], - "source": [ - "query = \"SELECT obj.objectId, obj.coord_ra, obj.coord_dec, \" + \\\n", - " \"obj.detect_fromBlend, obj.detect_isIsolated, \" + \\\n", - " \"obj.i_blendedness, obj.i_extendedness, \" + \\\n", - " \"obj.u_sersicFlux, obj.u_sersicFluxErr, obj.u_gaap1p0Flux, \" + \\\n", - " \"obj.g_sersicFlux, obj.g_sersicFluxErr, obj.g_gaap1p0Flux, \" + \\\n", - " \"obj.r_sersicFlux, obj.r_sersicFluxErr, obj.r_gaap1p0Flux, \" + \\\n", - " \"obj.i_sersicFlux, obj.i_sersicFluxErr, obj.i_gaap1p0Flux, \" + \\\n", - " \"obj.u_cModelMag, obj.u_cModelMagErr, \" + \\\n", - " \"obj.g_cModelMag, obj.g_cModelMagErr, \" + \\\n", - " \"obj.r_cModelMag, obj.r_cModelMagErr, \" + \\\n", - " \"obj.i_cModelMag, obj.i_cModelMagErr, \" + \\\n", - " \"obj.u_cModelFlux, obj.u_cModelFluxErr, \" + \\\n", - " \"obj.g_cModelFlux, obj.g_cModelFluxErr, \" + \\\n", - " \"obj.r_cModelFlux, obj.r_cModelFluxErr, \" + \\\n", - " \"obj.i_cModelFlux, obj.i_cModelFluxErr, \" + \\\n", - " \"obj.i_kronFlux_flag, obj.i_cModel_flag, obj.sersic_no_data_flag \" + \\\n", - " \"FROM dp1.Object AS obj \" + \\\n", - " \"WHERE (obj.i_sersicFlux/obj.i_sersicFluxErr > 10) AND \" + \\\n", - " \"(obj.i_extendedness = 1) AND (obj.sersic_no_data_flag = 0) AND \" + \\\n", - " \"(obj.i_cModel_flag = 0) AND \" + \\\n", - " \"(scisql_nanojanskyToAbMag(obj.i_sersicFlux) > 20) AND \" + \\\n", - " \"CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), \" + \\\n", - " \"CIRCLE('ICRS',\"+str(target_ra)+\",\"+str(target_dec)+\", 0.5)) = 1 \"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "867871f3-d378-4cc5-88df-d91cfb01e259", - "metadata": {}, - "outputs": [], - "source": [ - "job = service.submit_job(query)\n", - "job.run()\n", - "job.wait(phases=['COMPLETED', 'ERROR'])\n", - "print('Job phase is', job.phase)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5b6cd0ba-132a-4552-b389-32e54d8591dc", - "metadata": {}, - "outputs": [], - "source": [ - "if job.phase == 'ERROR':\n", - " job.raise_if_error()\n", - "assert job.phase == 'COMPLETED'" - ] - }, - { - "cell_type": "markdown", - "id": "f38080f1-9a2d-48af-834d-1b49de86944f", - "metadata": {}, - "source": [ - "Print the results of the search query." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7e4a20e0-101d-4644-90e1-b0bd1058aae1", - "metadata": {}, - "outputs": [], - "source": [ - "results = job.fetch_result()\n", - "tab = results.to_table()\n", - "tab" + "# Define success/fail masks based on whether the matched objects passed the LBG cut\n", + "lbg_success_mask = is_z4_lbg[matched_rubin_indices]\n", + "failed_lbg = ~lbg_success_mask\n", + "\n", + "print(f\" -> VANDELS z~4 sources detected in Rubin catalog: {len(matched_rubin_indices)}\")\n", + "print(f\" -> VANDELS sources successfully recovered by LBG selection: {np.sum(lbg_success_mask)}\")\n", + "print(f\" -> VANDELS sources missed by LBG selection: {np.sum(failed_lbg)}\")" ] }, { "cell_type": "markdown", - "id": "c9c94c7d-8635-4bbd-83e6-3eb64aea2b24", + "id": "d0e7c80f-0587-4c17-93d8-a52096d4c99e", "metadata": {}, "source": [ - "Below, convert the fluxes (units $nJy$) extracted from the `objectTable` into AB magnitudes using: $m_{AB} = -2.5log( f_{nJy}) + 31.4$ (see e.g. AB Magnitudes Wikipedia page for the conversion between flux in Jy and AB magnitudes).\n", + "Cell 5: Validation Color-Color Plot\n", "\n", - "> **Warning:** The following cell will produce warnings for invalid value encountered in log10, which happens if the source flux is negative. This occasionally happens from aperture photometry if the included pixels inside the aperture have negative values and can be safely ignored for this example. The log10 will return a NaN which can be filtered out later." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d58eacea-4573-433b-b9b1-382a24087dd1", - "metadata": {}, - "outputs": [], - "source": [ - "# old, does not re-set the flux to the upper limit when necessary\n", - "#cmodel_mag = -2.50 * np.log10(tab['i_cModelFlux']) + 31.4\n", - "#sersic_mag = -2.50 * np.log10(tab['i_sersicFlux']) + 31.4\n", - "#gaap_mag = -2.50 * np.log10(tab['i_gaap1p0Flux']) + 31.4\n", - "\n", - "# List of the filters you queried\n", - "#filters = ['u', 'g', 'r', 'i']\n", - "\n", - "# Temporarily ignore warnings for taking the log of negative/zero fluxes\n", - "#with np.errstate(divide='ignore', invalid='ignore'):\n", - "# for f in filters:\n", - " # 1. Convert Sersic Fluxes to AB Magnitudes\n", - " #tab[f'{f}_sersic_mag'] = -2.50 * np.log10(tab[f'{f}_sersicFlux']) + 31.4\n", - " \n", - " # 2. Convert GAAP Fluxes to AB Magnitudes\n", - " #tab[f'{f}_gaap_mag'] = -2.50 * np.log10(tab[f'{f}_gaap1p0Flux']) + 31.4\n", - " \n", - " # 3. Convert Sersic Flux Errors to Magnitude Errors\n", - " # The standard propagation of error formula for magnitudes is: \n", - " # mag_err = (2.5 / ln(10)) * (flux_err / flux)\n", - " #tab[f'{f}_sersic_magErr'] = 1.0857 * (tab[f'{f}_sersicFluxErr'] / tab[f'{f}_sersicFlux'])" + "This visually summarizes everything: your parent Rubin sample, your LBG candidates, and the VANDELS ground-truth objects (color-coded by magnitude)." ] }, { "cell_type": "code", "execution_count": null, - "id": "cdbbbc80-38e5-4ae9-bb84-6902828b13f5", + "id": "e48c98c3-ac97-43af-99af-74b96fa40731", "metadata": {}, "outputs": [], "source": [ - "# this should be better\n", - "# List of the filters you queried\n", - "filters = ['u', 'g', 'r', 'i']\n", + "# Extract parameters for plotting\n", + "v_r_minus_i = vandels_in_rubin['r_minus_i']\n", + "v_g_minus_r = vandels_in_rubin['g_minus_r']\n", + "v_i_mag = vandels_in_rubin['i_mag_robust']\n", + "vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", "\n", - "# Use a zeropoint of 31.4 as per your specific dataset configuration\n", - "zp = 31.4\n", + "fig, ax = plt.subplots(figsize=(11, 8))\n", "\n", - "# Temporarily ignore warnings for taking the log of negative/zero fluxes\n", - "with np.errstate(divide='ignore', invalid='ignore'):\n", - " for f in filters:\n", - " # 1. Apply Flux-Limit Logic: \n", - " # If flux is less than the error (S/N < 1), we replace it with the error \n", - " # value to calculate a 'Lower Limit' on the magnitude.\n", - " sersic_flux_robust = np.where(tab[f'{f}_sersicFlux'] < tab[f'{f}_sersicFluxErr'], \n", - " tab[f'{f}_sersicFluxErr'], \n", - " tab[f'{f}_sersicFlux'])\n", - " \n", - " #gaap_flux_robust = np.where(tab[f'{f}_gaap1p0Flux'] < tab[f'{f}_gaap1p0FluxErr'], \n", - " # tab[f'{f}_gaap1p0FluxErr'], \n", - " # tab[f'{f}_gaap1p0Flux'])\n", + "#cmapcolor = v_i_mag\n", + "cmapcolor = \n", "\n", - " # 2. Convert Robust Fluxes to AB Magnitudes\n", - " tab[f'{f}_sersic_mag'] = -2.50 * np.log10(sersic_flux_robust) + zp\n", - " #tab[f'{f}_gaap_mag'] = -2.50 * np.log10(gaap_flux_robust) + zp\n", - " \n", - " # 3. Convert Sersic Flux Errors to Magnitude Errors\n", - " # We use the original flux here to represent measurement uncertainty accurately\n", - " tab[f'{f}_sersic_magErr'] = 1.0857 * (tab[f'{f}_sersicFluxErr'] / tab[f'{f}_sersicFlux'])" - ] - }, - { - "cell_type": "markdown", - "id": "8d2de168-5282-4a26-8740-930ce13e362b", - "metadata": {}, - "source": [ - "### do Lyman break selection" + "# 1. Background (All Rubin Data)\n", + "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Parent Sample (Rubin)')\n", + "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", + " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates (g-r > 1.5)')\n", + "\n", + "# 2. VANDELS Truth - Missed Sources ('+')\n", + "sc1 = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", + " s=120, c=v_i_mag[failed_lbg], cmap='viridis', vmin=vmin, vmax=vmax, \n", + " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", + " label='VANDELS Truth (Missed)')\n", + "\n", + "# 3. VANDELS Truth - Confirmed Sources ('*')\n", + "sc2 = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", + " s=250, c=v_i_mag[lbg_success_mask], cmap='viridis', vmin=vmin, vmax=vmax, \n", + " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", + " label='Confirmed LBG Candidates')\n", + "\n", + "# --- Colorbar ---\n", + "cbar = plt.colorbar(sc2, ax=ax)\n", + "cbar.set_label('i-band [Robust Sersic Mag]', fontsize=12, fontweight='bold')\n", + "cbar.ax.invert_yaxis()\n", + "\n", + "# --- Selection Boundaries (Strict Cut: g-r > 1.5) ---\n", + "x_diag = np.linspace(0.133, 1.0, 50)\n", + "y_diag = 1.5 * x_diag + 0.8\n", + "intersect_x = (1.5 - 0.8) / 1.5\n", + "\n", + "ax.plot([-1.5, intersect_x], [1.5, 1.5], color='black', linestyle='--', lw=1.5) \n", + "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", + "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", + "\n", + "# --- Formatting ---\n", + "ax.set_xlim(-1.0, 2.0)\n", + "ax.set_ylim(-1.0, 4.0)\n", + "ax.set_xlabel('$(r - i)$ [Robust Sersic Mag]', fontsize=14)\n", + "ax.set_ylabel('$(g - r)$ [Robust Sersic Mag]', fontsize=14)\n", + "ax.set_title('Validation of Strict Lyman Break Selection (g-r > 1.5)', fontsize=16, fontweight='bold')\n", + "\n", + "handles, labels = ax.get_legend_handles_labels()\n", + "ax.legend(handles, labels, loc='upper left', framealpha=1)\n", + "ax.grid(True, linestyle=':', alpha=0.6)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" ] }, { "cell_type": "code", "execution_count": null, - "id": "09d09866-9c0d-434b-844b-076cf34f93df", + "id": "65e165d0-e1da-4ce5-9225-8f47e024bf6d", "metadata": {}, "outputs": [], "source": [ - "# 1. Calculate the colors using the Sersic magnitudes you generated\n", - "# We wrap this in a mask to drop NaNs so matplotlib doesn't complain\n", - "valid_mask = np.isfinite(tab['g_sersic_mag']) & \\\n", - " np.isfinite(tab['r_sersic_mag']) & \\\n", - " np.isfinite(tab['i_sersic_mag'])\n", - "\n", - "#u_mag = tab['u_sersic_mag'][valid_mask]\n", - "g_mag = tab['g_sersic_mag'][valid_mask]\n", - "r_mag = tab['r_sersic_mag'][valid_mask]\n", - "i_mag = tab['i_sersic_mag'][valid_mask]\n", - "\n", - "g_minus_r = g_mag - r_mag\n", - "r_minus_i = r_mag - i_mag\n", - "\n", - "# 2. Define the z~4 LBG (g-dropout) selection criteria\n", - "# These are standard photometric cuts to isolate z~4 galaxies and exclude red dwarf stars\n", - "#is_z4_lbg = (\n", - "# (g_minus_r > 1.0) & \n", - "# (r_minus_i < 1.0) & \n", - "# (g_minus_r > 1.5 * r_minus_i + 0.8)\n", - "#)\n", - "\n", - "# 2. Define the STRICT z~4 LBG selection criteria (Purity over Completeness)\n", - "is_z4_lbg = (\n", - " (g_minus_r > 1.5) & (tab['u_sersicFlux']/tab['u_sersicFluxErr'] < 3) & \n", - " (r_minus_i < 1.0) & #(r_minus_i > 0) & \n", - " (g_minus_r > 1.5 * r_minus_i + 0.8)\n", - ")\n", + "# Extract parameters for plotting\n", + "v_r_minus_i = vandels_in_rubin['r_minus_i']\n", + "v_g_minus_r = vandels_in_rubin['g_minus_r']\n", + "v_z_phot = vandels_in_rubin['z_phot'] # Changed to use photo-z\n", + "vmin, vmax = np.nanmin(v_z_phot), np.nanmax(v_z_phot)\n", "\n", - "# 3. Create the Color-Color Diagram\n", - "fig, ax = plt.subplots(figsize=(8, 6))\n", + "fig, ax = plt.subplots(figsize=(11, 8))\n", "\n", - "# Plot the background distribution of all objects (gray)\n", - "ax.scatter(r_minus_i, g_minus_r, s=5, color='gray', alpha=0.3, label='All Objects')\n", + "# 1. Background (All Rubin Data)\n", + "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Parent Sample (Rubin)')\n", + "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", + " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates (g-r > 1.5)')\n", "\n", - "# Highlight the selected z~4 LBGs (blue)\n", - "ax.scatter(r_minus_i[is_z4_lbg], g_minus_r[is_z4_lbg], \n", - " s=20, color='blue', alpha=0.8, edgecolor='white', linewidth=0.5, label='z~4 LBGs')\n", + "# 2. VANDELS Truth - Missed Sources ('+')\n", + "sc1 = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", + " s=120, c=v_z_phot[failed_lbg], cmap='plasma', vmin=vmin, vmax=vmax, \n", + " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", + " label='VANDELS Truth (Missed)')\n", "\n", - "# 4. Draw the Selection Boundaries for visual reference\n", - "# Calculate the vertices of the selection region\n", - "x_diag = np.linspace(0.133, 1.0, 50)\n", - "y_diag = 1.5 * x_diag + 0.8\n", + "# 3. VANDELS Truth - Confirmed Sources ('*')\n", + "sc2 = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", + " s=250, c=v_z_phot[lbg_success_mask], cmap='plasma', vmin=vmin, vmax=vmax, \n", + " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", + " label='Confirmed LBG Candidates')\n", "\n", - "# Plot the bounding lines\n", - "#ax.plot([-1.5, 0.133], [1.0, 1.0], color='red', linestyle='--', lw=2, label='Selection Boundary') # Bottom horizontal cut\n", - "#ax.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut to avoid M-stars\n", - "#ax.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2)\n", + "# --- Colorbar ---\n", + "cbar = plt.colorbar(sc2, ax=ax)\n", + "cbar.set_label('Photometric Redshift (Rubin z_phot)', fontsize=12, fontweight='bold')\n", + "# Inverted Y-axis removed so higher redshift is at the top\n", "\n", - "# Plot the updated bounding lines\n", - "# 4. Draw the NEW Selection Boundaries\n", - "# Calculate the new intersection between the horizontal and diagonal lines\n", + "# --- Selection Boundaries (Strict Cut: g-r > 1.5) ---\n", + "x_diag = np.linspace(0.133, 1.0, 50)\n", + "y_diag = 1.5 * x_diag + 0.8\n", "intersect_x = (1.5 - 0.8) / 1.5\n", - "ax.plot([-1.5, intersect_x], [1.5, 1.5], color='red', linestyle='--', lw=2, label='Selection Boundary') # Raised horizontal cut\n", - "ax.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut\n", - "ax.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2) # Right vertical cut\n", "\n", - "# 5. Formatting\n", - "ax.set_xlim(-1.5, 2.0)\n", - "ax.set_ylim(-1.0, 4.0)\n", + "ax.plot([-1.5, intersect_x], [1.5, 1.5], color='black', linestyle='--', lw=1.5) \n", + "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", + "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", "\n", - "ax.set_xlabel(r'(r−i) [AB Mag]', fontsize=14)\n", - "ax.set_ylabel(r'(g−r) [AB Mag]', fontsize=14)\n", - "ax.set_title(r'z∼4 Lyman-Break Galaxy Selection (g-dropouts)', fontsize=16, fontweight='bold')\n", + "# --- Formatting ---\n", + "ax.set_xlim(-1.0, 2.0)\n", + "ax.set_ylim(-1.0, 4.0)\n", + "ax.set_xlabel('$(r - i)$ [Robust Sersic Mag]', fontsize=14)\n", + "ax.set_ylabel('$(g - r)$ [Robust Sersic Mag]', fontsize=14)\n", + "ax.set_title('Validation of Strict Lyman Break Selection (Color-Coded by Photo-z)', fontsize=16, fontweight='bold')\n", "\n", + "handles, labels = ax.get_legend_handles_labels()\n", + "ax.legend(handles, labels, loc='upper left', framealpha=1)\n", "ax.grid(True, linestyle=':', alpha=0.6)\n", - "ax.legend(loc='upper left', fontsize=12)\n", "\n", "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# Print out the results\n", - "print(f\"Total objects plotted: {len(g_mag)}\")\n", - "print(f\"Identified z~4 candidates: {np.sum(is_z4_lbg)}\")" + "plt.show()" ] }, { "cell_type": "markdown", - "id": "29ae8710-01c3-44bb-8edc-64de3738857a", + "id": "fbff5f57-9f6e-4847-84c3-582083035bf2", "metadata": {}, "source": [ - "## Sanity checks: plot cutouts and SEDs" + "Cell 6: Visual Inspection with SODA\n", + "\n", + "Finally, we pull the image cutouts directly from the Rubin archives for the missed and confirmed subsets to inspect the pixels." ] }, { "cell_type": "code", "execution_count": null, - "id": "81ade6bd-3b62-472b-a0b6-48656837bd22", + "id": "dbf5ce01-96b4-49f4-81a9-19c791da0e47", "metadata": {}, "outputs": [], "source": [ - "import io\n", - "import numpy as np\n", - "import astropy.units as u\n", - "from astropy.io import fits\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from pyvo.dal.adhoc import SodaQuery, DatalinkResults \n", - "from astropy.visualization import ZScaleInterval, LinearStretch, ImageNormalize\n", - "\n", - "from lsst.rsp import get_tap_service\n", - "from lsst.rsp.utils import get_pyvo_auth # <-- ADDED: The RSP auth utility\n", + "# Isolate the missed and confirmed subsets\n", + "missed_v_truth = v_matched_truth[failed_lbg]\n", + "missed_r_data = vandels_in_rubin[failed_lbg]\n", "\n", - "# Initialize the TAP service AND the auth session\n", - "tap_service = get_tap_service(\"tap\")\n", - "session = get_pyvo_auth() # <-- ADDED: Define the session variable\n", - "\n", - "# Extract the coordinates of the high-purity candidates\n", - "cands_ra = tab['coord_ra'][valid_mask][is_z4_lbg]\n", - "cands_dec = tab['coord_dec'][valid_mask][is_z4_lbg]\n", + "confirmed_v_truth = v_matched_truth[lbg_success_mask]\n", + "confirmed_r_data = vandels_in_rubin[lbg_success_mask]\n", "\n", - "# Limit to the first 5 candidates so we don't spam the SODA service\n", - "n_plot = min(len(cands_ra), 5)\n", - "filters = ['u', 'g', 'r', 'i']\n", + "# --- SODA Plotting Function ---\n", + "def plot_soda_cutouts_with_pz(r_data, v_data, n_max=10, title_label=\"Candidate\"):\n", + " n_plot = min(len(r_data), n_max)\n", + " if n_plot == 0:\n", + " print(f\"No sources to plot for {title_label}.\")\n", + " return\n", "\n", - "# Set up the Matplotlib Grid & define Field of View\n", - "fig, axes = plt.subplots(n_plot, len(filters), figsize=(10, 2.5 * n_plot))\n", - "norm = ImageNormalize(stretch=LinearStretch(), interval=ZScaleInterval())\n", - "fov = 10.0 / 3600.0 # 10 arcseconds in degrees\n", + " filters = ['u', 'g', 'r', 'i']\n", + " fig, axes = plt.subplots(n_plot, len(filters), figsize=(12, 3.5 * n_plot))\n", + " if n_plot == 1: axes = [axes] # Ensure 2D array structure\n", "\n", - "print(f\"Requesting DP1 SODA cutouts via TAP for {n_plot} candidates...\")\n", + " print(f\"Requesting SODA cutouts for {n_plot} sources: {title_label}...\")\n", "\n", - "for row_idx in range(n_plot):\n", - " ra = cands_ra[row_idx]\n", - " dec = cands_dec[row_idx]\n", - " \n", - " # Query the ivoa.ObsCore table using the image footprint (s_region)\n", - " query = f\"\"\"\n", - " SELECT lsst_band, access_url \n", - " FROM ivoa.ObsCore \n", - " WHERE dataproduct_subtype = 'lsst.deep_coadd' \n", - " AND obs_collection = 'LSST.DP1'\n", - " AND CONTAINS(POINT('ICRS', {ra}, {dec}), s_region) = 1\n", - " \"\"\"\n", - " \n", - " # Run the query synchronously\n", - " tap_job = tap_service.run_sync(query)\n", - " coadds = tap_job.to_table()\n", - " \n", - " for col_idx, f in enumerate(filters):\n", - " ax = axes[row_idx, col_idx] if n_plot > 1 else axes[col_idx]\n", - " \n", - " # Match the specific filter\n", - " band_match = coadds[coadds['lsst_band'] == f]\n", - " \n", - " if len(band_match) > 0:\n", - " try:\n", - " datalink_url = band_match['access_url'][0]\n", - " \n", - " # We now pass the active session to the Datalink & SODA tools\n", - " dl_result = DatalinkResults.from_result_url(datalink_url, session=session)\n", - " \n", - " # Execute the Synchronous SODA Cutout\n", - " sq = SodaQuery.from_resource(dl_result,\n", - " dl_result.get_adhocservice_by_id(\"cutout-sync\"),\n", - " session=session)\n", - " sq.circle = (ra * u.deg, dec * u.deg, fov * u.deg)\n", - " \n", - " cutout_bytes = sq.execute_stream().read()\n", - " sq.raise_if_error()\n", - " \n", - " # Open the byte stream into an Astropy FITS object\n", - " hdul = fits.open(io.BytesIO(cutout_bytes))\n", - " \n", - " # HDU 1 contains the actual science 'image' array\n", - " img_array = hdul[1].data\n", - " \n", - " # Plot the array\n", - " ax.imshow(img_array, origin='lower', cmap='gray', norm=norm)\n", - " \n", - " # SODA automatically centers the cutout on the requested RA/Dec\n", - " center_y, center_x = img_array.shape[0] // 2, img_array.shape[1] // 2\n", - " circle = plt.Circle((center_x, center_y), radius=5, color='red', fill=False, lw=1, alpha=0.5)\n", - " ax.add_patch(circle)\n", - "\n", - " except Exception as e:\n", - " print(f\"Error on Cand {row_idx+1} {f}-band: {e}\")\n", - " ax.text(0.5, 0.5, 'SODA Error', ha='center', va='center', transform=ax.transAxes, color='red')\n", - " else:\n", - " ax.text(0.5, 0.5, 'No Coverage', ha='center', va='center', transform=ax.transAxes, color='red')\n", + " for row_idx in range(n_plot):\n", + " ra = r_data['coord_ra'][row_idx]\n", + " dec = r_data['coord_dec'][row_idx]\n", + " obj_id = r_data['objectId'][row_idx]\n", " \n", - " # Formatting\n", - " ax.set_xticks([])\n", - " ax.set_yticks([])\n", - " \n", - " if row_idx == 0:\n", - " ax.set_title(f\"{f}-band\", fontsize=16, fontweight='bold')\n", - " if col_idx == 0:\n", - " ax.set_ylabel(f\"Cand {row_idx+1}\\nRA: {ra:.3f}\", fontsize=12, rotation=0, labelpad=40, ha='center')\n", + " # Pull data from our aligned tables\n", + " z_spec = v_data['zsp'][row_idx]\n", + " z_phot = r_data['z_phot'][row_idx]\n", + " g_r = r_data['g_minus_r'][row_idx] \n", + " r_i = r_data['r_minus_i'][row_idx]\n", + " z_phot_str = f\"{z_phot:.2f}\" if np.isfinite(z_phot) else \"NaN\"\n", + "\n", + " query = f\"\"\"\n", + " SELECT lsst_band, access_url\n", + " FROM ivoa.ObsCore\n", + " WHERE dataproduct_subtype = 'lsst.deep_coadd'\n", + " AND obs_collection = 'LSST.DP1'\n", + " AND CONTAINS(POINT('ICRS', {ra}, {dec}), s_region) = 1\n", + " \"\"\"\n", + " coadds = tap_service.run_sync(query).to_table()\n", + "\n", + " for col_idx, f in enumerate(filters):\n", + " ax = axes[row_idx][col_idx]\n", + " band_match = coadds[coadds['lsst_band'] == f]\n", + "\n", + " if len(band_match) > 0:\n", + " try:\n", + " datalink_url = band_match['access_url'][0]\n", + " dl_result = DatalinkResults.from_result_url(datalink_url, session=session)\n", + " sq = SodaQuery.from_resource(dl_result,\n", + " dl_result.get_adhocservice_by_id(\"cutout-sync\"),\n", + " session=session)\n", + " sq.circle = (ra * u.deg, dec * u.deg, 10.0 / 3600.0 * u.deg)\n", + " \n", + " cutout_bytes = sq.execute_stream().read()\n", + " hdul = fits.open(io.BytesIO(cutout_bytes))\n", + " img_array = hdul[1].data\n", + "\n", + " norm = ImageNormalize(img_array, interval=ZScaleInterval(), stretch=LinearStretch())\n", + " ax.imshow(img_array, origin='lower', cmap='gray', norm=norm)\n", + " cy, cx = img_array.shape[0]//2, img_array.shape[1]//2\n", + " ax.add_patch(plt.Circle((cx, cy), radius=4, color='cyan', fill=False, lw=1.5, alpha=0.7))\n", + "\n", + " except Exception:\n", + " ax.text(0.5, 0.5, 'SODA Error', ha='center', va='center', transform=ax.transAxes, color='red')\n", + " else:\n", + " ax.text(0.5, 0.5, 'No Coverage', ha='center', va='center', transform=ax.transAxes, color='red')\n", + "\n", + " ax.set_xticks([]); ax.set_yticks([])\n", + " if row_idx == 0: ax.set_title(f\"{f}-band\", fontsize=15, fontweight='bold')\n", + " if col_idx == 0:\n", + " label_str = f\"z_sp: {z_spec:.2f}\\nz_ph: {z_phot_str}\\nID:{obj_id}\\ng-r: {g_r:.2f}\\nr-i={r_i:.2f}\"\n", + " ax.set_ylabel(label_str, rotation=0, labelpad=70, ha='center', fontweight='bold')\n", + "\n", + " plt.tight_layout()\n", + " plt.show()\n", "\n", - "plt.subplots_adjust(wspace=0.05, hspace=0.05)\n", - "plt.show()" + "# Execute the plots\n", + "plot_soda_cutouts_with_pz(missed_r_data, missed_v_truth, n_max=10, title_label=\"Missed VANDELS Truth\")\n" ] }, { "cell_type": "code", "execution_count": null, - "id": "0e5fd667-471d-46e0-96d1-cba433de8ead", + "id": "25b4985a-9006-4cf8-a7dd-f217562ee164", "metadata": {}, "outputs": [], "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "# 1. Identify the best candidate (the one with the reddest g-r color)\n", - "high_purity_ids = tab['objectId'][valid_mask][is_z4_lbg]\n", - "#best_candidate_id = high_purity_ids[np.argmax(g_minus_r[is_z4_lbg])]\n", - "best_candidate_id = high_purity_ids[0]#np.argmax(g_minus_r[is_z4_lbg])]\n", - "\n", - "# 2. Query all 6 bands using forced cModelFlux for accurate multi-band colors\n", - "sed_query = f\"\"\"\n", - "SELECT \n", - " u_cModelFlux, g_cModelFlux, r_cModelFlux, \n", - " i_cModelFlux, z_cModelFlux, y_cModelFlux,\n", - " u_cModelFluxErr, g_cModelFluxErr, r_cModelFluxErr, \n", - " i_cModelFluxErr, z_cModelFluxErr, y_cModelFluxErr\n", - "FROM dp1.Object \n", - "WHERE objectId = {best_candidate_id}\n", - "\"\"\"\n", - "\n", - "sed_job = tap_service.run_sync(sed_query)\n", - "sed_data = sed_job.to_table()[0] # Isolate the single row\n", - "\n", - "# 3. Define the filters and their effective wavelengths in Angstroms\n", - "filters = ['u', 'g', 'r', 'i', 'z', 'y']\n", - "wavelengths = [3671, 4826, 6223, 7545, 8691, 9710]\n", - "\n", - "mags = []\n", - "mag_errs = []\n", - "fluxes = []\n", - "flux_errs = []\n", - "\n", - "# Convert to AB Magnitudes\n", - "with np.errstate(divide='ignore', invalid='ignore'):\n", - " for f in filters:\n", - " flux = sed_data[f'{f}_cModelFlux']\n", - " flux_err = sed_data[f'{f}_cModelFluxErr']\n", - "\n", - " fluxes.append(flux)\n", - " flux_errs.append(flux_err)\n", - " \n", - " mag = -2.50 * np.log10(flux) + 31.4\n", - " mag_err = 1.0857 * (flux_err / flux)\n", - " \n", - " mags.append(mag)\n", - " mag_errs.append(mag_err)\n", - " \n", - "# 4. Plot the SED\n", - "fig, ax = plt.subplots(figsize=(8, 5))\n", - "\n", - "# Plot the data (invert y-axis because lower magnitude = brighter!)\n", - "ax.errorbar(wavelengths, fluxes, yerr=flux_errs, fmt='o-', color='black', \n", - " markersize=8, capsize=4, linewidth=2)\n", - "#ax.invert_yaxis() # for mags only\n", + "# --- Visual Inspection: True Positives (Confirmed VANDELS LBGs) ---\n", + "# These are the galaxies that have a VANDELS spec-z ~ 4 AND successfully passed your Rubin g-r > 1.5 cut.\n", "\n", - "# Highlight the region absorbed by the Lyman Break\n", - "ax.axvspan(3000, 4826, color='lightblue', alpha=0.3, label='Absorbed by Neutral Hydrogen')\n", - "\n", - "# Formatting\n", - "ax.set_xticks(wavelengths)\n", - "ax.set_xticklabels(filters, fontsize=12)\n", - "ax.set_xlabel('Filter Band', fontsize=14)\n", - "ax.set_ylabel('Flux [nJy]', fontsize=14)\n", - "ax.set_title(f'Spectral Energy Distribution (Candidate ID: {best_candidate_id})', fontsize=16, fontweight='bold')\n", + "# Re-authenticate the RSP session just in case it timed out\n", + "#from lsst.rsp.utils import get_pyvo_auth\n", + "#session = get_pyvo_auth()\n", "\n", - "ax.grid(True, linestyle=':', alpha=0.6)\n", - "ax.legend(loc='upper right')\n", + "print(f\"Total confirmed VANDELS LBGs available to plot: {len(confirmed_r_data)}\")\n", "\n", - "plt.tight_layout()\n", - "plt.show()" + "# Execute the plotter specifically for the confirmed overlap\n", + "plot_soda_cutouts_with_pz(\n", + " confirmed_r_data, \n", + " confirmed_v_truth, \n", + " n_max=10, \n", + " title_label=\"Confirmed LBG Selection (True Positives)\"\n", + ")" ] }, { "cell_type": "markdown", - "id": "4c51bd19-e47d-4808-b334-3349d94a0924", + "id": "8b7702fb-ec6d-4776-8559-6d0b663f015d", "metadata": {}, "source": [ - "## Sanity check matching to Rubin photo-z catalogs" + "Do some photo-z validation " ] }, { "cell_type": "code", "execution_count": null, - "id": "1c015634-0235-4329-92de-dcaf17954e3a", + "id": "11096ef6-e3a3-41ad-857a-7372844cf606", "metadata": {}, "outputs": [], "source": [ - "import lsdb\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "from astropy.coordinates import SkyCoord\n", + "import astropy.units as u\n", "\n", - "print(\"Loading DP1 Photo-z LSDB catalog...\")\n", + "print(\"1. Isolating all high-quality VANDELS spectra...\")\n", + "# Keep all redshifts with quality flag >= 3 (standard for secure spec-z)\n", + "is_vandels_hq = vandels_cdfs['q_zsp'] >= 3\n", + "vandels_all_hq = vandels_cdfs[is_vandels_hq]\n", "\n", - "# 1. Open the LSDB photo-z catalog from the RSP shared file system\n", - "pz_cat = lsdb.open_catalog(\"/rubin/lsdb_data/object_photoz\")\n", + "print(\"2. Cross-matching to the Rubin Object Table...\")\n", + "coord_v_all = SkyCoord(ra=vandels_all_hq['RAJ2000'], dec=vandels_all_hq['DEJ2000'], unit='deg')\n", + "coord_r = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", + "\n", + "idx_rubin_all, d2d_all, _ = coord_v_all.match_to_catalog_sky(coord_r)\n", + "match_mask_all = d2d_all < 1.0 * u.arcsec\n", + "\n", + "# Extract the matched data\n", + "matched_rubin_all = tab[idx_rubin_all[match_mask_all]]\n", + "matched_v_all = vandels_all_hq[match_mask_all]\n", + "\n", + "# Extract redshifts and i-band magnitude\n", + "z_spec_all = matched_v_all['zsp']\n", + "z_phot_all = matched_rubin_all['z_phot']\n", + "i_mag_all = matched_rubin_all['i_mag_robust']\n", + "\n", + "# Clean out any rows where the photo-z pipeline failed (returned NaN)\n", + "valid_pz = ~np.isnan(z_phot_all) & ~np.isnan(z_spec_all) & ~np.isnan(i_mag_all)\n", + "z_spec_clean = z_spec_all[valid_pz]\n", + "z_phot_clean = z_phot_all[valid_pz]\n", + "i_mag_clean = i_mag_all[valid_pz]\n", + "\n", + "print(f\" -> Found {len(z_spec_clean)} global matches with valid Photo-z and Spec-z.\")\n", "\n", - "# 2. Filter the catalog for our specific candidate IDs\n", - "# LSDB uses Dask under the hood for distributed computing. We access the Dask \n", - "# DataFrame (._ddf) to filter for our candidate IDs, then compute the result into a Pandas DataFrame.\n", - "pz_dask = pz_cat._ddf\n", - "matched_df = pz_dask[pz_dask['objectId'].isin(high_purity_ids)].compute()\n", + "# --- 3. Build the Plot ---\n", + "fig, ax = plt.subplots(figsize=(10, 8))\n", "\n", - "# Extract the redshift column. \n", - "# Note: Depending on the specific algorithm used for this DP1 release, the column \n", - "# might be named 'z_phot', 'z_mode', or 'photoZ'. If 'z_phot' throws a KeyError, \n", - "# you can use print(matched_df.columns) to check the correct name!\n", - "valid_pz = matched_df['bpz_z_mean'].dropna().values\n", + "# Scatter plot: Color-coded by i-band magnitude\n", + "sc = ax.scatter(z_spec_clean, z_phot_clean, c=i_mag_clean, cmap='viridis', \n", + " s=25, alpha=0.8, edgecolor='k', linewidth=0.5, zorder=5)\n", "\n", - "# 3. Plot the Histogram\n", - "fig, ax = plt.subplots(figsize=(8, 5))\n", + "# Add the colorbar\n", + "cbar = plt.colorbar(sc, ax=ax)\n", + "cbar.set_label('i-band [Robust Sersic Mag]', fontsize=12, fontweight='bold')\n", + "cbar.ax.invert_yaxis() # Invert so brighter (smaller number) is at the top\n", "\n", - "if len(valid_pz) > 0:\n", - " ax.hist(valid_pz, bins=15, color='rebeccapurple', alpha=0.8, edgecolor='white')\n", + "# Perfect agreement line (1:1)\n", + "z_line = np.linspace(0, 7, 100)\n", + "ax.plot(z_line, z_line, color='black', linestyle='--', linewidth=2, label='1:1 Agreement')\n", "\n", - "# Draw a vertical line exactly at z=4 to show the target redshift\n", - "ax.axvline(4.0, color='red', linestyle='--', linewidth=2, label='Target Redshift (z=4)')\n", + "# Catastrophic outlier boundaries\n", + "# The standard definition in astronomy is |dz| / (1+z) > 0.15\n", + "ax.plot(z_line, z_line + 0.15*(1+z_line), color='red', linestyle=':', label='Outlier Boundary ($|\\Delta z| > 0.15(1+z)$)')\n", + "ax.plot(z_line, z_line - 0.15*(1+z_line), color='red', linestyle=':')\n", "\n", "# Formatting\n", - "ax.set_xlabel(r'Photometric Redshift (zphot)', fontsize=14)\n", - "ax.set_ylabel('Number of Galaxies', fontsize=14)\n", - "ax.set_title('Photo-z Distribution of High-Purity g-dropouts', fontsize=16, fontweight='bold')\n", + "ax.set_xlim(0, 6.5)\n", + "ax.set_ylim(0, 6.5)\n", + "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", + "ax.set_ylabel('Photometric Redshift (Rubin bpz_z_mean)', fontsize=14)\n", + "ax.set_title('Global Validation: Rubin Photo-z vs. VANDELS Spec-z', fontsize=16, fontweight='bold')\n", "\n", - "ax.legend()\n", + "handles, labels = ax.get_legend_handles_labels()\n", + "ax.legend(handles, labels, loc='upper left', frameon=True)\n", "ax.grid(True, linestyle=':', alpha=0.6)\n", "\n", "plt.tight_layout()\n", "plt.show()\n", "\n", - "# Print the confirmation statistics\n", - "print(f\"Total candidates cross-matched: {len(valid_pz)}\")\n", - "if len(valid_pz) > 0:\n", - " print(f\"Median Photo-z of sample: {np.median(valid_pz):.2f}\")" - ] - }, - { - "cell_type": "markdown", - "id": "595f2e93-1577-4ba7-8023-877d25a24a51", - "metadata": {}, - "source": [ - "## some failed attempts to retrieve VANDELS catalogs and spec-z columns\n", - "to clean up" + "# --- 4. Calculate Standard Photo-z Quality Metrics ---\n", + "if len(z_spec_clean) > 0:\n", + " dz = (z_phot_clean - z_spec_clean) / (1 + z_spec_clean)\n", + " \n", + " # NMAD: Normalized Median Absolute Deviation (A robust measure of scatter)\n", + " nmad = 1.48 * np.median(np.abs(dz - np.median(dz)))\n", + " \n", + " # Outlier Fraction: Percentage of objects outside the red dotted lines\n", + " outlier_fraction = np.sum(np.abs(dz) > 0.15) / len(dz)\n", + " \n", + " print(f\"--- Global Photo-z Performance Metrics ---\")\n", + " print(f\"Robust Scatter (\\u03c3_NMAD): {nmad:.3f}\")\n", + " print(f\"Catastrophic Outlier Fraction: {outlier_fraction:.1%}\")" ] }, { "cell_type": "code", "execution_count": null, - "id": "14646c0e-76fd-4d28-82cb-ffdbf3dc4f9a", + "id": "ac5967f1-3e2d-41cc-a089-d597ff050583", "metadata": {}, "outputs": [], "source": [ - "# dont delete, it displays the column names\n", - "\n", - "from astroquery.vizier import Vizier\n", - "import astropy.units as u\n", - "from astropy.coordinates import SkyCoord\n", - "import matplotlib.pyplot as plt\n", "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from astropy.coordinates import SkyCoord\n", + "import astropy.units as u\n", "\n", - "# 1. Initialize Vizier - fetch EVERYTHING associated with the VANDELS ID\n", - "v = Vizier(columns=['**'], catalog=\"J/A+A/647/A150\")\n", - "v.ROW_LIMIT = -1\n", + "print(\"1. Isolating all high-quality VANDELS spectra...\")\n", + "# Keep all redshifts with quality flag >= 3 (standard for secure spec-z)\n", + "is_vandels_hq = vandels_cdfs['q_zsp'] >= 3\n", + "vandels_all_hq = vandels_cdfs[is_vandels_hq]\n", "\n", - "print(\"Analyzing VANDELS Catalog Structure...\")\n", + "print(\"2. Cross-matching to the Rubin Object Table...\")\n", + "coord_v_all = SkyCoord(ra=vandels_all_hq['RAJ2000'], dec=vandels_all_hq['DEJ2000'], unit='deg')\n", + "coord_r = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", "\n", - "try:\n", - " all_tables = v.get_catalogs(\"J/A+A/647/A150\")\n", - " \n", - " vandels_data = None\n", - " z_col_name = None\n", - " flag_col_name = None\n", - "\n", - " # 2. Iterate through all tables to find the spectroscopic data\n", - " for i, table in enumerate(all_tables):\n", - " cols = table.colnames\n", - " print(f\"\\nTable {i}: {table.meta.get('name', 'Unknown')}\")\n", - " print(f\"Columns: {cols[:10]}... ({len(cols)} total columns)\")\n", - " \n", - " # Look for the redshift column (case-insensitive)\n", - " # We look for 'z' followed by 'spec', 'mode', or just 'z'\n", - " for c in cols:\n", - " c_low = c.lower()\n", - " if c_low in ['zspec', 'z', 'z_spec', 'specz', 'z_mode']:\n", - " z_col_name = c\n", - " vandels_data = table\n", - " print(f\"--> Found Redshift Column: '{z_col_name}' in Table {i}\")\n", - " \n", - " # Now find the quality flag in the SAME table\n", - " for f in cols:\n", - " f_low = f.lower()\n", - " if f_low in ['zflg', 'f_zspec', 'q', 'qual', 'zflag']:\n", - " flag_col_name = f\n", - " print(f\"--> Found Quality Flag: '{flag_col_name}'\")\n", - " break\n", - " break\n", - " if vandels_data: break\n", - "\n", - " if vandels_data is None:\n", - " print(\"\\n[!] Error: No redshift column found. Printing all table summaries for debugging:\")\n", - " for i, t in enumerate(all_tables):\n", - " print(f\"Table {i} has columns: {t.colnames}\")\n", - " raise ValueError(\"Column discovery failed.\")\n", - "\n", - " # 3. Filter and Match (Standard workflow)\n", - " # We use a broad mask first to ensure we have data\n", - " mask = (vandels_data[z_col_name] >= 3.5) & (vandels_data[z_col_name] <= 4.5)\n", - " \n", - " # Only apply flag if we found one\n", - " if flag_col_name:\n", - " mask &= (vandels_data[flag_col_name] >= 3)\n", - " \n", - " vandels_z4 = vandels_data[mask]\n", - " print(f\"\\nFiltering complete. Found {len(vandels_z4)} high-quality z~4 candidates.\")\n", + "idx_rubin_all, d2d_all, _ = coord_v_all.match_to_catalog_sky(coord_r)\n", + "match_mask_all = d2d_all < 1.0 * u.arcsec\n", "\n", - " # Cross-match using coordinates found in the same table\n", - " # VizieR usually uses RAJ2000/DEJ2000 or _RAJ2000/_DEJ2000\n", - " ra_col = 'RAJ2000' if 'RAJ2000' in vandels_z4.colnames else '_RAJ2000'\n", - " dec_col = 'DEJ2000' if 'DEJ2000' in vandels_z4.colnames else '_DEJ2000'\n", + "# Extract the matched data\n", + "matched_rubin_all = tab[idx_rubin_all[match_mask_all]]\n", + "matched_v_all = vandels_all_hq[match_mask_all]\n", "\n", - " v_coords = SkyCoord(ra=vandels_z4[ra_col], dec=vandels_z4[dec_col], unit='deg')\n", - " r_coords = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", - " #r_coords = SkyCoord(ra=cands_ra, dec=cands_dec, unit='deg')\n", + "z_spec_all = matched_v_all['zsp']\n", + "i_mag_all = matched_rubin_all['i_mag_robust']\n", + "obj_ids_all = matched_rubin_all['objectId']\n", "\n", - " idx, d2d, _ = v_coords.match_to_catalog_sky(r_coords)\n", - " matches = d2d < 1.5 * u.arcsec # Slightly wider match for different astrometric systems\n", - " matched_idx = idx[matches]\n", - " \n", - " print(f\"Successfully matched {len(matched_idx)} galaxies to Rubin sample.\")\n", - "\n", - " # 4. Final Plot\n", - " ri_match = tab['r_sersic_mag'][matched_idx] - tab['i_sersic_mag'][matched_idx]\n", - " gr_match = tab['g_sersic_mag'][matched_idx] - tab['r_sersic_mag'][matched_idx]\n", - "\n", - " plt.figure(figsize=(8, 6))\n", - " plt.scatter(tab['r_sersic_mag'] - tab['i_sersic_mag'], \n", - " tab['g_sersic_mag'] - tab['r_sersic_mag'], \n", - " s=1, color='gray', alpha=0.2, label='Parent Sample')\n", - " plt.scatter(ri_match, gr_match, color='gold', marker='*', s=150, edgecolor='k', label='VANDELS Confirmed')\n", - " plt.axhline(1.5, color='blue', ls='--', label='Your Strict Cut')\n", - " plt.xlabel('r - i')\n", - " plt.ylabel('g - r')\n", - " plt.legend()\n", - " plt.show()\n", + "# --- 3. Identify Available Photo-z Algorithms in LSDB ---\n", + "print(\"3. Scanning LSDB for available Photo-z columns...\")\n", "\n", - "except Exception as e:\n", - " print(f\"\\nDiscovery Failed: {e}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6b46074c-d680-4a2c-8324-5b6fbcbbaa23", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "from astropy.coordinates import SkyCoord\n", - "import astropy.units as u\n", - "\n", - "# 1. Select Table 0 (CDFS) and extract the confirmed high-z sample\n", - "vandels_data = all_tables[0]\n", - "\n", - "# Filter for spectroscopic redshift between 3.5 and 4.5\n", - "# We use q_zsp >= 3 (standard for high-confidence VANDELS spectra)\n", - "mask = (vandels_data['zsp'] >= 3.5) & (vandels_data['zsp'] <= 4.5) & (vandels_data['q_zsp'] >= 3)\n", - "vandels_z4 = vandels_data[mask]\n", - "\n", - "print(f\"Found {len(vandels_z4)} high-confidence VANDELS spectra in CDFS at z~4.\")\n", - "\n", - "# 2. Perform the spatial cross-match\n", - "v_coords = SkyCoord(ra=vandels_z4['RAJ2000'], dec=vandels_z4['DEJ2000'], unit='deg')\n", - "r_coords = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", - "\n", - "idx, d2d, _ = v_coords.match_to_catalog_sky(r_coords)\n", - "\n", - "# 1.0 arcsecond is usually safe for Rubin vs VLT astrometry\n", - "matches = d2d < 1.0 * u.arcsec\n", - "matched_idx = idx[matches]\n", - "\n", - "print(f\"Successfully matched {len(matched_idx)} of those to your Rubin Object table.\")\n", - "\n", - "# 3. Calculate colors for the matched objects\n", - "# Assuming 'tab' has the sersic_mags we defined earlier\n", - "ri_match = tab['r_sersic_mag'][matched_idx] - tab['i_sersic_mag'][matched_idx]\n", - "gr_match = tab['g_sersic_mag'][matched_idx] - tab['r_sersic_mag'][matched_idx]\n", - "s2n_match = tab['i_sersicFlux'][matched_idx] / tab['i_sersicFluxErr'][matched_idx]\n", - "\n", - "# 4. Plotting\n", - "plt.figure(figsize=(9, 7))\n", - "\n", - "# Background: All Rubin objects in your field\n", - "plt.scatter(tab['r_sersic_mag'] - tab['i_sersic_mag'], \n", - " tab['g_sersic_mag'] - tab['r_sersic_mag'], \n", - " s=2, color='gray', alpha=0.15, label='Rubin Parent Sample')\n", - "\n", - "# Foreground: The spectroscopic \"Truth\"\n", - "plt.scatter(ri_match, gr_match, color='gold', marker='*', s=150, \n", - " edgecolor='black', linewidth=0.8, zorder=5, label='Confirmed VANDELS z~4')\n", - "\n", - "# Draw your selection boundaries\n", - "plt.axhline(1.5, color='blue', linestyle='--', lw=2, label='Strict Selection (g-r > 1.5)')\n", - "plt.axhline(1.0, color='red', linestyle=':', lw=1.5, label='Standard Selection (g-r > 1.0)')\n", - "\n", - "# Box boundaries (approximating the dropout region)\n", - "plt.vlines(1.0, 1.0, 4.0, color='black', alpha=0.3) \n", - "\n", - "plt.xlim(-0.5, 1.5)\n", - "plt.ylim(-0.5, 3.5)\n", - "plt.xlabel('$(r - i)$ color', fontsize=12)\n", - "plt.ylabel('$(g - r)$ color', fontsize=12)\n", - "plt.title('VANDELS Spectroscopic Validation of Rubin Color Selection', fontsize=14)\n", - "plt.legend(loc='upper left', frameon=True, shadow=True)\n", - "plt.grid(True, linestyle=':', alpha=0.5)\n", - "\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4efa3820-8dda-4d79-9b40-abcbe76fba4e", - "metadata": {}, - "outputs": [], - "source": [ - "# 1. List of RA/Dec for z~4 VANDELS confirmations\n", - "vandels_ra = vandels_z4['RAJ2000']\n", - "vandels_dec = vandels_z4['DEJ2000']\n", - "print(f\"VANDELS Truth List size: {len(vandels_ra)}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e23b3a3b-bb85-4d0b-8cfb-f99132fcab3a", - "metadata": {}, - "outputs": [], - "source": [ - "# 2. Get all Rubin objects with i-band S/N > 10\n", - "# We use a 0.2 degree radius around the VANDELS center\n", - "rubin_query = \"\"\"\n", - "SELECT \n", - " objectId, coord_ra, coord_dec,\n", - " g_cModelMag, r_cModelMag, i_cModelMag,\n", - " g_cModelFlux, g_cModelFluxErr,\n", - " i_cModelFlux, i_cModelFluxErr\n", - "FROM dp1.Object\n", - "WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec), \n", - " CIRCLE('ICRS', 53.125, -27.8, 0.2)) = 1\n", - " AND (i_cModelFlux / i_cModelFluxErr) > 10\n", - "\"\"\"\n", - "\n", - "print(\"Querying Rubin for all solid i-band detections...\")\n", - "rubin_job = tap_service.run_sync(rubin_query)\n", - "rubin_all = rubin_job.to_table()\n", - "print(f\"Rubin Detected List size: {len(rubin_all)}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1e00286f-7d96-4da5-a5dc-e0d527975a8e", - "metadata": {}, - "outputs": [], - "source": [ - "from astropy.coordinates import SkyCoord\n", - "import astropy.units as u\n", - "\n", - "# 1. Setup coordinates\n", - "c_vandels = SkyCoord(ra=vandels_ra, dec=vandels_dec, unit='deg')\n", - "c_rubin = SkyCoord(ra=rubin_all['coord_ra'], dec=rubin_all['coord_dec'], unit='deg')\n", - "\n", - "# 2. Match\n", - "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin)\n", - "match_mask = d2d < 1.0 * u.arcsec \n", - "matched_rubin = rubin_all[idx[match_mask]]\n", - "\n", - "print(f\"Found {len(matched_rubin)} matches!\")\n", - "\n", - "# 3. Handle 'NaN' in g-band (The Dropouts)\n", - "# If g is NaN, it means the flux was too low to measure a magnitude. \n", - "# We'll assign it a faint magnitude (e.g., 28) to visualize the dropout.\n", - "g_mags = matched_rubin['g_cModelMag']\n", - "r_mags = matched_rubin['r_cModelMag']\n", - "i_mags = matched_rubin['i_cModelMag']\n", - "\n", - "# Replace NaNs with 28.0 for visualization\n", - "g_plot = np.where(np.isnan(g_mags), 28.0, g_mags)\n", - "\n", - "g_r = g_plot - r_mags\n", - "r_i = r_mags - i_mags\n", - "\n", - "whblue = np.where(g_r < 1.5)[0]\n", - "\n", - "# 4. Plot\n", - "plt.figure(figsize=(8, 6))\n", - "\n", - "# Background (All objects from this new Rubin query)\n", - "plt.scatter(rubin_all['r_cModelMag'] - rubin_all['i_cModelMag'], \n", - " rubin_all['g_cModelMag'] - rubin_all['r_cModelMag'], \n", - " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", - "\n", - "# Matches\n", - "plt.scatter(r_i, g_r, color='gold', marker='*', s=100, edgecolor='k', label='VANDELS matches')\n", - "\n", - "# Highlight the selected z~4 LBGs (blue)\n", - "#plt.scatter(r_minus_i[is_z4_lbg], g_minus_r[is_z4_lbg], \n", - "# s=20, color='blue', alpha=0.8, edgecolor='white', linewidth=0.5, label='z~4 LBGs')\n", - "\n", - "\n", - "# 4. Draw the Selection Boundaries for visual reference\n", - "# Calculate the vertices of the selection region\n", - "x_diag = np.linspace(0.133, 1.0, 50)\n", - "y_diag = 1.5 * x_diag + 0.8\n", - "\n", - "# Plot the bounding lines\n", - "plt.plot([-1.5, 0.133], [1.0, 1.0], color='red', linestyle='--', lw=2, label='Selection Boundary') # Bottom horizontal cut\n", - "#ax.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut to avoid M-stars\n", - "#ax.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2)\n", - "\n", - "# Plot the updated bounding lines\n", - "# 4. Draw the NEW Selection Boundaries\n", - "# Calculate the new intersection between the horizontal and diagonal lines\n", - "intersect_x = (1.5 - 0.8) / 1.5\n", - "plt.plot([-1.5, intersect_x], [1.5, 1.5], color='red', linestyle='--', lw=2, label='Selection Boundary') # Raised horizontal cut\n", - "plt.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut\n", - "plt.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2) # Right vertical cut\n", - "\n", - "\n", - "plt.axhline(1.5, color='blue', linestyle='--', label='Strict Cut')\n", - "plt.axhline(1., color='green', linestyle='--', label='Standard Cut')\n", - "plt.xlabel('r - i')\n", - "plt.ylabel('g - r')\n", - "plt.xlim(-0.5, 1.5)\n", - "plt.ylim(-0.5, 3.5)\n", - "plt.title('VANDELS Confirmations in Rubin (Unfiltered)')\n", - "plt.legend()\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1b4a125d-0bd3-4bbb-8376-85ac410855e1", - "metadata": {}, - "outputs": [], - "source": [ - "# something might be wrong with the matching process, CHECK\n", - "\n", - "from astropy.coordinates import SkyCoord\n", - "import astropy.units as u\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "# 1. Setup coordinates\n", - "c_vandels = SkyCoord(ra=vandels_ra, dec=vandels_dec, unit='deg')\n", - "c_rubin = SkyCoord(ra=rubin_all['coord_ra'], dec=rubin_all['coord_dec'], unit='deg')\n", - "#c_rubin_lbg = SkyCoord(ra=cands_ra, dec=cands_dec, unit='deg')\n", - "\n", - "# 2. Match\n", - "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin_lbg)\n", - "match_mask = d2d < 1.0 * u.arcsec \n", - "matched_rubin = rubin_all[idx[match_mask]]\n", - "#matched_rubin = tab[idx[match_mask]]\n", - "\n", - "# Extract the redshift for the matched objects!\n", - "# match_mask aligns with the VANDELS catalog\n", - "matched_z = vandels_z4['zsp'][match_mask] \n", - "\n", - "print(f\"Found {len(matched_rubin)} matches!\")\n", - "\n", - "# 3. Handle 'NaN' in g-band (The Dropouts)\n", - "g_mags = matched_rubin['g_cModelMag']\n", - "r_mags = matched_rubin['r_cModelMag']\n", - "i_mags = matched_rubin['i_cModelMag']\n", - "s2n = matched_rubin['i_cModelFlux']/matched_rubin['i_cModelFluxErr']\n", - "\n", - "# Replace NaNs with 28.0 for visualization\n", - "g_plot = np.where(np.isnan(g_mags), 28.0, g_mags)\n", - "\n", - "g_r = g_plot - r_mags\n", - "r_i = r_mags - i_mags\n", - "\n", - "whblue = np.where(g_r > 1.5)[0]\n", - "\n", - "# 4. Plot\n", - "# Slightly wider figure to accommodate the colorbar\n", - "plt.figure(figsize=(9, 6))\n", - "\n", - "# Background (All objects from this new Rubin query)\n", - "plt.scatter(rubin_all['r_cModelMag'] - rubin_all['i_cModelMag'], \n", - " rubin_all['g_cModelMag'] - rubin_all['r_cModelMag'], \n", - " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", - "\n", - "# Matches: Color-coded by spectroscopic redshift\n", - "# Note: Keeping your [whblue] index, but you can remove it to see all stars!\n", - "sc = plt.scatter(r_i, g_r, \n", - " c=matched_z, cmap='plasma', \n", - " marker='*', s=150, edgecolor='k', zorder=10, \n", - " label='VANDELS matches')\n", - "\n", - "# Add the colorbar\n", - "cbar = plt.colorbar(sc)\n", - "cbar.set_label('VANDELS z_spec', fontsize=12, fontweight='bold')\n", - "\n", - "plt.axhline(1.5, color='blue', linestyle='--', label='Your Strict Cut')\n", - "plt.xlabel('r - i', fontsize=12)\n", - "plt.ylabel('g - r', fontsize=12)\n", - "plt.xlim(-0.5, 1.5)\n", - "plt.ylim(-0.5, 3.5)\n", - "plt.title('VANDELS Confirmations in Rubin (Color-Coded by z)', fontsize=14)\n", - "plt.legend(loc='lower right')\n", - "\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2ce194c9-55ac-44c7-bf29-702f2e7032bd", - "metadata": {}, - "outputs": [], - "source": [ - "from astropy.coordinates import SkyCoord\n", - "import astropy.units as u\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "# 1. Setup coordinates\n", - "c_vandels = SkyCoord(ra=vandels_ra, dec=vandels_dec, unit='deg')\n", - "c_rubin = SkyCoord(ra=rubin_all['coord_ra'], dec=rubin_all['coord_dec'], unit='deg')\n", - "\n", - "# 2. Match\n", - "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin)\n", - "match_mask = d2d < 1.0 * u.arcsec \n", - "matched_rubin = rubin_all[idx[match_mask]]\n", - "\n", - "print(f\"Found {len(matched_rubin)} matches!\")\n", - "\n", - "# 3. Handle 'NaN' in g-band (The Dropouts)\n", - "g_mags = matched_rubin['g_cModelMag']\n", - "r_mags = matched_rubin['r_cModelMag']\n", - "i_mags = matched_rubin['i_cModelMag']\n", - "\n", - "# Replace NaNs with 28.0 for visualization\n", - "g_plot = np.where(np.isnan(g_mags), 28.0, g_mags)\n", - "\n", - "g_r = g_plot - r_mags\n", - "r_i = r_mags - i_mags\n", - "\n", - "# Keep only the stars below your 1.5 cut\n", - "whblue = np.where(g_r > 1.5)[0]\n", - "\n", - "# 4. Plot\n", - "plt.figure(figsize=(9, 6))\n", - "\n", - "# Background (All objects from this new Rubin query)\n", - "plt.scatter(rubin_all['r_cModelMag'] - rubin_all['i_cModelMag'], \n", - " rubin_all['g_cModelMag'] - rubin_all['r_cModelMag'], \n", - " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", - "\n", - "# Matches: Color-coded by r-band magnitude\n", - "sc = plt.scatter(r_i, g_r, \n", - " c=r_mags, cmap='viridis', \n", - " marker='*', s=150, edgecolor='k', zorder=10, \n", - " label='VANDELS matches')\n", - "\n", - "# Add the colorbar\n", - "cbar = plt.colorbar(sc)\n", - "cbar.set_label('r-band Magnitude', fontsize=12, fontweight='bold')\n", - "cbar.ax.invert_yaxis() # Invert so brighter (smaller number) is at the top\n", - "\n", - "plt.axhline(1.5, color='blue', linestyle='--', label='Your Strict Cut')\n", - "plt.xlabel('r - i', fontsize=12)\n", - "plt.ylabel('g - r', fontsize=12)\n", - "plt.xlim(-0.5, 1.5)\n", - "plt.ylim(-0.5, 3.5)\n", - "plt.title('VANDELS Confirmations in Rubin (Color-Coded by r-mag)', fontsize=14)\n", - "plt.legend(loc='lower right')\n", - "\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "e4fc8f40-cee2-465c-b7b4-c1a696e156d3", - "metadata": {}, - "source": [ - "Some points to consider here: the redshift window is 3.5 1 else axes[col_idx]\n", - " \n", - " band_match = coadds[coadds['lsst_band'] == f]\n", - " \n", - " if len(band_match) > 0:\n", - " try:\n", - " datalink_url = band_match['access_url'][0]\n", - " dl_result = DatalinkResults.from_result_url(datalink_url, session=session)\n", - " \n", - " sq = SodaQuery.from_resource(dl_result,\n", - " dl_result.get_adhocservice_by_id(\"cutout-sync\"),\n", - " session=session)\n", - " sq.circle = (ra * u.deg, dec * u.deg, fov * u.deg)\n", - " \n", - " cutout_bytes = sq.execute_stream().read()\n", - " hdul = fits.open(io.BytesIO(cutout_bytes))\n", - " img_array = hdul[1].data\n", - " \n", - " # ZScale is best for seeing the noise level in dropout bands\n", - " norm = ImageNormalize(img_array, interval=ZScaleInterval(), stretch=LinearStretch())\n", - " ax.imshow(img_array, origin='lower', cmap='gray', norm=norm)\n", - " \n", - " # Marker to help identify the target in noisy u/g bands\n", - " cy, cx = img_array.shape[0]//2, img_array.shape[1]//2\n", - " ax.add_patch(plt.Circle((cx, cy), radius=4, color='cyan', fill=False, lw=1.5, alpha=0.7))\n", - "\n", - " except Exception as e:\n", - " ax.text(0.5, 0.5, 'SODA Error', ha='center', va='center', transform=ax.transAxes, color='red')\n", - " else:\n", - " ax.text(0.5, 0.5, 'No Coverage', ha='center', va='center', transform=ax.transAxes, color='red')\n", - " \n", - " ax.set_xticks([]); ax.set_yticks([])\n", - " if row_idx == 0:\n", - " ax.set_title(f\"{f}-band\", fontsize=15, fontweight='bold')\n", - " if col_idx == 0:\n", - " ax.set_ylabel(f\"z={z_spec:.2f}\\n{obj_id}\\n{gr}\\n{s2n}\", rotation=0, labelpad=70, ha='center', fontweight='bold')\n", - "\n", - "\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "b2f95d66-b972-4d69-ab4a-cd2314e263cb", - "metadata": {}, - "source": [ - "## Comparison between VANDELS spec-z and Rubin photo-z sanity check" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "24942ae5-e69b-46a4-902e-d93e73f298ab", - "metadata": {}, - "outputs": [], - "source": [ - "import astropy.units as u\n", - "from astropy.coordinates import SkyCoord\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "print(\"Preparing VANDELS and LSDB catalogs for cross-matching...\")\n", - "\n", - "# 1. Extract the full VANDELS coordinates and spec-z\n", - "# (Assuming your unfiltered VANDELS table from VizieR is stored as 'vandels_data')\n", - "v_ra = vandels_data['RAJ2000']\n", - "v_dec = vandels_data['DEJ2000']\n", - "v_zspec = vandels_data['zsp']\n", - "v_coords = SkyCoord(ra=v_ra, dec=v_dec, unit='deg')\n", - "\n", - "# 2. Filter the massive LSDB catalog down to the CDFS region\n", - "# lsdb updated its API to require 'radius_arcsec' to avoid unit confusion.\n", - "# We want a 0.5 degree radius, which is 1800 arcseconds.\n", - "print(\"Running LSDB cone search on the VANDELS footprint...\")\n", - "pz_regional = pz_cat.cone_search(ra=53.125, dec=-27.8, radius_arcsec=1800).compute()\n", - "\n", - "# 3. Setup the Rubin coordinates from the regional Photo-z catalog\n", - "# Note: LSDB uses 'coord_ra' and 'coord_dec' by default\n", - "rubin_coords = SkyCoord(ra=pz_regional['coord_ra'].values, \n", - " dec=pz_regional['coord_dec'].values, \n", - " unit='deg')\n", - "\n", - "# 4. Perform the spatial cross-match\n", - "print(\"Performing spatial cross-match...\")\n", - "idx, d2d, _ = v_coords.match_to_catalog_sky(rubin_coords)\n", - "\n", - "# Keep only confident matches within 1 arcsecond\n", - "match_mask = d2d < 1.0 * u.arcsec\n", - "\n", - "# Extract the matched data\n", - "matched_rubin_pz = pz_regional.iloc[idx[match_mask]]\n", - "matched_v_zspec = v_zspec[match_mask]\n", - "matched_v_zphot = matched_rubin_pz['bpz_z_mean'].values\n", - "\n", - "# Clean out any rows where the photo-z pipeline failed (returned NaN)\n", - "valid = ~np.isnan(matched_v_zphot) & ~np.isnan(matched_v_zspec)\n", - "z_spec_clean = matched_v_zspec[valid]\n", - "z_phot_clean = matched_v_zphot[valid]\n", - "\n", - "print(f\"Successfully matched {len(z_spec_clean)} galaxies with both Spec-z and Photo-z!\")\n", - "\n", - "# 5. Plot Photo-z vs Spec-z\n", - "fig, ax = plt.subplots(figsize=(8, 7))\n", - "\n", - "# Scatter plot of the matches\n", - "ax.scatter(z_spec_clean, z_phot_clean, s=20, color='teal', alpha=0.5, \n", - " edgecolor='k', linewidth=0.5, label='Matched Galaxies')\n", - "\n", - "# Perfect agreement line (1:1)\n", - "z_line = np.linspace(0, 6, 100)\n", - "ax.plot(z_line, z_line, color='black', linestyle='--', linewidth=2, label='1:1 line')\n", - "\n", - "# Catastrophic outlier boundaries\n", - "# The standard definition in astronomy is |dz| / (1+z) > 0.15\n", - "ax.plot(z_line, z_line + 0.15*(1+z_line), color='red', linestyle=':', label='Outliers ($|\\Delta z| > 0.15(1+z)$)')\n", - "ax.plot(z_line, z_line - 0.15*(1+z_line), color='red', linestyle=':')\n", - "\n", - "# Formatting\n", - "ax.set_xlim(0, 5.5)\n", - "ax.set_ylim(0, 5.5)\n", - "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", - "ax.set_ylabel('Photometric Redshift (Rubin bpz_z_mean)', fontsize=14)\n", - "ax.set_title('Validation: Photo-z vs. Spec-z', fontsize=16, fontweight='bold')\n", - "ax.legend(loc='upper left', frameon=True)\n", - "ax.grid(True, linestyle=':', alpha=0.6)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# 6. Calculate Standard Photo-z Quality Metrics\n", - "# dz = (z_phot - z_spec) / (1 + z_spec)\n", - "dz = (z_phot_clean - z_spec_clean) / (1 + z_spec_clean)\n", - "\n", - "# NMAD: Normalized Median Absolute Deviation (A robust measure of scatter)\n", - "nmad = 1.48 * np.median(np.abs(dz - np.median(dz)))\n", - "\n", - "# Outlier Fraction: Percentage of objects outside the red dotted lines\n", - "outlier_fraction = np.sum(np.abs(dz) > 0.15) / len(dz)\n", - "\n", - "print(f\"--- Photo-z Performance Metrics ---\")\n", - "print(f\"Robust Scatter ($\\sigma_{{NMAD}}$): {nmad:.3f}\")\n", - "print(f\"Catastrophic Outlier Fraction: {outlier_fraction:.1%}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "57b52d6b-2441-4b38-ae0f-cff23504b472", - "metadata": {}, - "outputs": [], - "source": [ - "import astropy.units as u\n", - "from astropy.coordinates import SkyCoord\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "print(\"Preparing VANDELS and LSDB catalogs for cross-matching...\")\n", - "\n", - "# 1. Extract the full VANDELS coordinates and spec-z\n", - "v_ra = vandels_data['RAJ2000']\n", - "v_dec = vandels_data['DEJ2000']\n", - "v_zspec = vandels_data['zsp']\n", - "v_coords = SkyCoord(ra=v_ra, dec=v_dec, unit='deg')\n", - "\n", - "# 2. Filter the massive LSDB catalog down to the CDFS region\n", - "print(\"Running LSDB cone search on the VANDELS footprint...\")\n", - "pz_regional = pz_cat.cone_search(ra=53.125, dec=-27.8, radius_arcsec=1800).compute()\n", - "\n", - "# 3. Setup the Rubin coordinates\n", - "rubin_coords = SkyCoord(ra=pz_regional['coord_ra'].values, \n", - " dec=pz_regional['coord_dec'].values, \n", - " unit='deg')\n", - "\n", - "# 4. Perform the spatial cross-match\n", - "print(\"Performing spatial cross-match...\")\n", - "idx, d2d, _ = v_coords.match_to_catalog_sky(rubin_coords)\n", - "match_mask = d2d < 1.0 * u.arcsec\n", - "\n", - "# Extract the matched data\n", - "matched_rubin_pz = pz_regional.iloc[idx[match_mask]]\n", - "matched_v_zspec = v_zspec[match_mask]\n", - "matched_v_zphot = matched_rubin_pz['bpz_z_mean'].values\n", - "\n", - "# Check the column name for i-band magnitude in the photo-z catalog\n", - "if 'i_cModelMag' in matched_rubin_pz.columns:\n", - " matched_i_mag = matched_rubin_pz['i_cModelMag'].values\n", - "elif 'mag_i' in matched_rubin_pz.columns:\n", - " matched_i_mag = matched_rubin_pz['mag_i'].values\n", - "else:\n", - " # If it throws an error here, print matched_rubin_pz.columns to find the exact name!\n", - " print(\"Warning: Could not find i-band magnitude column. Using placeholder.\")\n", - " matched_i_mag = np.zeros(len(matched_v_zphot))\n", - "\n", - "# Clean out any rows with NaNs in z_phot, z_spec, OR i_mag to keep arrays aligned\n", - "valid = ~np.isnan(matched_v_zphot) & ~np.isnan(matched_v_zspec) & ~np.isnan(matched_i_mag)\n", - "z_spec_clean = matched_v_zspec[valid]\n", - "z_phot_clean = matched_v_zphot[valid]\n", - "i_mag_clean = matched_i_mag[valid]\n", - "\n", - "print(f\"Successfully matched {len(z_spec_clean)} galaxies with Spec-z, Photo-z, and i-mag!\")\n", - "\n", - "# 5. Plot Photo-z vs Spec-z\n", - "fig, ax = plt.subplots(figsize=(9, 7)) # Slightly wider for the colorbar\n", - "\n", - "# Scatter plot: Color-coded by i-band magnitude\n", - "sc = ax.scatter(z_spec_clean, z_phot_clean, c=i_mag_clean, cmap='viridis', \n", - " s=35, alpha=0.8, edgecolor='k', linewidth=0.5, zorder=5)\n", - "\n", - "# Add the colorbar\n", - "cbar = plt.colorbar(sc, ax=ax)\n", - "cbar.set_label('i-band Magnitude', fontsize=12, fontweight='bold')\n", - "cbar.ax.invert_yaxis() # Invert so brighter (smaller number) is at the top\n", - "\n", - "# Perfect agreement line (1:1)\n", - "z_line = np.linspace(0, 6, 100)\n", - "ax.plot(z_line, z_line, color='black', linestyle='--', linewidth=2, label='1:1 Agreement')\n", - "\n", - "# Catastrophic outlier boundaries\n", - "ax.plot(z_line, z_line + 0.15*(1+z_line), color='red', linestyle=':', label='Outlier Boundary ($|\\Delta z| > 0.15(1+z)$)')\n", - "ax.plot(z_line, z_line - 0.15*(1+z_line), color='red', linestyle=':')\n", - "\n", - "# Formatting\n", - "ax.set_xlim(0, 5.5)\n", - "ax.set_ylim(0, 5.5)\n", - "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", - "ax.set_ylabel('Photometric Redshift (Rubin bpz_z_mean)', fontsize=14)\n", - "ax.set_title('Validation: Photo-z vs. Spec-z (Colored by i-mag)', fontsize=16, fontweight='bold')\n", - "\n", - "# Combine legends\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "ax.legend(handles, labels, loc='upper left', frameon=True)\n", - "ax.grid(True, linestyle=':', alpha=0.6)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# 6. Calculate Standard Photo-z Quality Metrics\n", - "dz = (z_phot_clean - z_spec_clean) / (1 + z_spec_clean)\n", - "nmad = 1.48 * np.median(np.abs(dz - np.median(dz)))\n", - "outlier_fraction = np.sum(np.abs(dz) > 0.15) / len(dz)\n", - "\n", - "print(f\"--- Photo-z Performance Metrics ---\")\n", - "print(f\"Robust Scatter ($\\sigma_{{NMAD}}$): {nmad:.3f}\")\n", - "print(f\"Catastrophic Outlier Fraction: {outlier_fraction:.1%}\")" - ] - }, - { - "cell_type": "markdown", - "id": "354dbbd9-f5df-47ee-962c-1384b7e21b29", - "metadata": {}, - "source": [ - "## 3. Total fluxes\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0cec2ebe-6134-4f86-b9de-67aa16dea0d5", - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "sys.exit()" - ] - }, - { - "cell_type": "markdown", - "id": "7d75b896-770c-4d7e-94d9-7202af571209", - "metadata": {}, - "source": [ - "### 3.1. Comparing total fluxes\n", - "\n", - "This section will make several plots that shows how the different photometric measurements compare.\n", - "\n", - "First, compare `cModelFlux` (two component bulge+disk sersic model flux) to `sersicFlux` (single sersic model flux with shape parameters free), `bdFluxB` (sersic with n=4) and `bdFluxD` (sersic with n=1). " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9443b34f-9afe-4c12-b345-860896176cac", - "metadata": {}, - "outputs": [], - "source": [ - "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", - " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", - "\n", - "bins = np.arange(16, 27, 1)\n", - "\n", - "ylims = [-1.2, 1.2]\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-bdFluxD_mag), 's', alpha=.3,\n", - " label='cModel-bdFluxD', color='blue')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-bdFluxD_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='blue', lw=2, label='bin median', zorder=11)\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-bdFluxB_mag), '^', alpha=.3,\n", - " label='cModel-bdFluxB', color='r')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-bdFluxB_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='r', lw=2, label='bin median', zorder=11)\n", - "\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag - sersic_mag), 'o', alpha=.3,\n", - " label='cModel - sersic', color='g')\n", - "\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-sersic_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='g', lw=2, label='bin median', zorder=11)\n", - "\n", - "ax.axhline(0, linestyle='--')\n", - "ax.set_xlabel('cModel Magnitude')\n", - "ax.set_ylabel('cModel mag - other mag')\n", - "ax.set_ylim([-1, 1])\n", - "ax.legend()\n", - "\n", - "ax2.hist((cmodel_mag-bdFluxD_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='blue', stacked=True, fill=False, label='bdFluxD')\n", - "ax2.hist((cmodel_mag-bdFluxB_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='r', stacked=True, fill=False, label='bdFluxB')\n", - "ax2.hist((cmodel_mag-sersic_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='g', stacked=True, fill=False, label='Sersic')\n", - "\n", - "ax2.set_ylim(ylims)\n", - "ax2.axhline(0, linestyle='--', color='k')\n", - "ax.axhline(0, linestyle='--', color='k')\n", - "ax.set_xlabel('i-band AB magnitude [cModel]')\n", - "ax.set_ylabel('cModel mag - Other mag')\n", - "ax.set_ylim(ylims)\n", - "\n", - "ax.legend()\n", - "ax2.legend()" - ] - }, - { - "cell_type": "markdown", - "id": "f290d993-8645-406a-9e95-fabd852383c8", - "metadata": {}, - "source": [ - "> Figure 1: Left panel: a plot comparing the magnitude difference between cModel and dbFluxD (blue), bdFluxB (red) and sersic (green) vs i-band magnitude as measured by cModel. Right panel: a histogram showing the difference in color between cModel and the three other photometric measurements, across all magnitudes. The sersic fluxes are in best agreement with cModel (smallest scatter in right panel) with the bdFluxB returning systematically fainter magnitudes, and bdFluxD returning systematically brighter magnitudes.\n", - "\n", - "Below, explore how the BD fluxes compare to sersic fluxes as a function of the shape of the light profile, sersic index n." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c1fea6a9-fc32-43ce-bb7a-f7e23677f548", - "metadata": {}, - "outputs": [], - "source": [ - "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", - " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", - "\n", - "bins = np.arange(0, 7, 0.25)\n", - "\n", - "ylims = [-1.2, 1.2]\n", - "\n", - "ax.plot(sersic_index, (sersic_mag-bdFluxD_mag), 's', alpha=.3,\n", - " label='cModel-bdFluxD', color='blue')\n", - "x = sersic_index\n", - "y = (sersic_mag-bdFluxD_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='blue', lw=2, label='bin median', zorder=11)\n", - "\n", - "ax.plot(sersic_index, (sersic_mag-bdFluxB_mag), '^', alpha=.3,\n", - " label='cModel-bdFluxB', color='r')\n", - "x = sersic_index\n", - "y = (sersic_mag-bdFluxB_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='r', lw=2, label='bin median', zorder=11)\n", - "\n", - "ax.axhline(0, linestyle='--')\n", - "\n", - "ax.set_ylabel('sersic mag - BD mag')\n", - "ax.set_ylim([-1, 1])\n", - "ax.legend()\n", - "\n", - "\n", - "ax2.hist((cmodel_mag-bdFluxD_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='blue', stacked=True, fill=False, label='bdFluxD')\n", - "ax2.hist((cmodel_mag-bdFluxB_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='r', stacked=True, fill=False, label='bdFluxB')\n", - "\n", - "ax2.set_ylim(ylims)\n", - "ax2.axhline(0, linestyle='--', color='k')\n", - "ax.axhline(0, linestyle='--', color='k')\n", - "ax.set_xlabel('Sersic Index n')\n", - "ax.set_ylabel('Sersic mag - Other mag')\n", - "ax.set_ylim(ylims)\n", - "ax.set_xlim([0, 8])\n", - "ax.legend()\n", - "ax2.legend()" - ] - }, - { - "cell_type": "markdown", - "id": "3c44cfa4-7e2d-4c77-960d-f540683744b2", - "metadata": {}, - "source": [ - "> Fig 2: Comparison of the sersic mag (flux measured with sersic parameters left free) with the bdFlux that is measured with sersic index fixed to either n=1 (D) or n=4 (B) as a function of sersic index n. Fixing the sersic index can inject scatter in the flux relative to leaving it free, but the sersic flux converges on bdFluxD(B) for n=1 and n=4." - ] - }, - { - "cell_type": "markdown", - "id": "b7c9fdd5-3bb1-4d8c-abac-5cdafa8df188", - "metadata": {}, - "source": [ - "## 4. Apparent fluxes\n", - "\n", - "This section explores three types of apparent fluxes: Kron (elliptical apertures that typically includes more than 90% of intrinsic light), and aperture photometry (flux measured inside circles of varying size).\n", - "\n", - "Here, apparent fluxes refers to photometry that are not corrected for flux outside of the measurement aperture (i.e. not corrected to be a total flux). These measurements have their own applications but should not be used to measure mass or luminosity.\n", - " \n", - "##### Kron fluxes\n", - "\n", - "A decent summary of Kron fluxes in the NED documentation. The aperture used for the fluxes is 2.5 x R1 where R1 is the luminosity weighted radius (also called \"first moment\"; Kron et al. 1980).\n", - "\n", - "```\n", - "_kronFlux : Flux from Kron Flux algorithm. Measured on -band.\n", - "_kronFluxErr : Uncertainty of _kronFlux.\n", - "_kronFlux_flag : Failure flag for _kronFlux.\n", - "```\n", - "\n", - "The Kron radius, `_kronRad`, is also available. In this case of LSST pipeline output, the Kron flux is not corrected for light that is emitted outside of the Kron aperture. While in many cases it will collect the majority of light, it will not be as accurate as the cModel for science cases requiring total flux.\n", - "\n", - "\n", - "##### Aperture fluxes\n", - "This contains the enclosed flux inside a given aperture (and not corrected to total fluxes using an aperture correction that accounts for the flux falling outside the aperture). Fixed aperture size refers to the aperture radius in pixels.\n", - "\n", - "```\n", - "_apFlux : Flux within -pixel aperture. Forced on -band.\n", - "_apFluxErr : Uncertainty of _apFlux.\n", - "_apFluxFlag : Failure flag for _apFlux.\n", - "```\n", - "\n", - "The apertures are 3, 6, 9, 12, 17, 25, 35, 50, and 70 pixels. In the column name, apertures are `03`, `06`, `09`, `12`, and so on. While aperture fluxes are not corrected for the loss outside the aperture, if the aperture size is much larger than the galaxy size then it will approximate the total flux of the galaxy. The general application of these measurements are for measuring radial profiles (see Section 4 below).\n" - ] - }, - { - "cell_type": "markdown", - "id": "d0869336-562f-4909-8109-9a737f57877b", - "metadata": {}, - "source": [ - "### 4.1. Comparing total to apparent fluxes\n", - "\n", - "This section will make several plots that compare the `cModel` flux (which we take as the fiducial total flux, as commonly used for SDSS) to some of the apparent flux measurements. Kron, and aperture photometry are all measures of light within a fixed aperture. \n", - "\n", - "\n", - "Generally, magnitudes measured using aperture photometry in the LSST pipeline are fainter than those measured from cModel, because the fixed circular aperture systematically underestimates the flux in the galaxy wings (and the lost flux increases as the intrinsic size of the galaxy increases, e.g. as traced by the Kron radius).\n", - "\n", - "First, compare `cModel` to `Kron` which should typically enclose 90% of the light." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "96dc3077-e086-430a-bace-47383bb60c97", - "metadata": {}, - "outputs": [], - "source": [ - "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", - " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", - "\n", - "bins = np.arange(16, 27, 1)\n", - "\n", - "ylims = [-1.2, 1.2]\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag - kron_mag), 's', alpha=.3,\n", - " label='cModel-Kron', color='blue')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-kron_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1]) / 2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='blue', lw=2, label='bin median', zorder=11)\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-sersic_mag), 'o', alpha=.3,\n", - " label='cModel - sersic', color='r')\n", - "\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-sersic_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='r', lw=2, label='bin median', zorder=11)\n", - "\n", - "ax.axhline(0, linestyle='--')\n", - "ax.set_xlabel('cModel Magnitude')\n", - "ax.set_ylabel('cModel mag - sersic mag')\n", - "ax.set_ylim([-1, 1])\n", - "ax.legend()\n", - "\n", - "\n", - "ax2.hist((cmodel_mag-sersic_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 50), align='mid',\n", - " histtype=\"step\", color='red', stacked=True, fill=False, label='Sersic')\n", - "ax2.hist((cmodel_mag-kron_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 50), align='mid',\n", - " histtype=\"step\", color='blue', stacked=True, fill=False, label='Kron')\n", - "\n", - "ax2.set_ylim(ylims)\n", - "ax2.axhline(0, linestyle='--', color='k')\n", - "ax.axhline(0, linestyle='--', color='k')\n", - "ax.set_xlabel('Kron Radius [i-band; pixels]')\n", - "ax.set_ylabel('cModel mag - Other mag')\n", - "ax.set_ylim(ylims)\n", - "\n", - "ax.legend()\n", - "ax2.legend()\n" - ] - }, - { - "cell_type": "markdown", - "id": "68e45fe0-9d1d-4d13-af74-9302c3f3c118", - "metadata": {}, - "source": [ - "> Figure 3: A figure comparing the difference between cModel and Kron magnitudes, compared to the difference between cModel and sersic magnitudes (left panel). Generally, both Kron and sersic the measurements are in comparable agreement with cModel. The right panel shows the histogram of magnitude differences, demonstrating that there are not systematic offsets but slightly higher scatter from Kron with respect to cModel.\n", - "\n", - "Below, explore how circular aperture photometry compares to cModel. Generally, magnitudes measured using aperture photometry in the LSST pipeline are fainter than those measured from cModel, because the fixed circular aperture systematically underestimates the flux in the galaxy wings (and the lost flux increases as the intrinsic size of the galaxy increases, e.g. as traced by the Kron radius)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f867380a-dac7-4a0b-a249-b8ee199cfdf3", - "metadata": {}, - "outputs": [], - "source": [ - "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", - " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", - "\n", - "bins = np.arange(2, 15, 1)\n", - "ylims = [-1.5, 1.5]\n", - "\n", - "ax.plot(i_kronRad, (cmodel_mag-ap06_mag), '^', alpha=.3,\n", - " label='6-pixel aperture', color='red')\n", - "ax.plot(i_kronRad, (cmodel_mag-ap09_mag), 's', alpha=.3,\n", - " label='9-pixel aperture', color='orange')\n", - "ax.plot(i_kronRad, (cmodel_mag-ap12_mag), 'o', alpha=.3,\n", - " label='12-pixel aperture', color='green')\n", - "ax.plot(i_kronRad, (cmodel_mag-ap17_mag), '.', alpha=.3,\n", - " label='17-pixel aperture', color='blue')\n", - "\n", - "ax2.hist((cmodel_mag-ap17_mag), edgecolor='blue', orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", stacked=True, fill=False)\n", - "ax2.hist((cmodel_mag-ap12_mag), edgecolor='green', orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", stacked=True, fill=False)\n", - "ax2.hist((cmodel_mag-ap09_mag), edgecolor='orange', orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", stacked=True, fill=False)\n", - "ax2.hist((cmodel_mag-ap06_mag), edgecolor='red', orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", stacked=True, fill=False)\n", - "\n", - "ax2.set_ylim(ylims)\n", - "ax.axhline(0, linestyle='--', color='k')\n", - "ax2.axhline(0, linestyle='--', color='k')\n", - "ax.set_xlabel('Kron Radius [i-band; pixels]')\n", - "ax.set_ylabel('cModel mag - Aperture mag')\n", - "ax.set_ylim(ylims)\n", - "ax.set_xlim([2, 12])\n", - "ax.legend()" - ] - }, - { - "cell_type": "markdown", - "id": "01de6505-06f2-4c80-a674-7a421613fd8c", - "metadata": {}, - "source": [ - "> Figure 4: A comparison of the difference between cModel photometry and aperture photometry measured by the LSST pipelines for four different aperture sizes as a function of galaxy size (as measured using the Kron radius). The left panel shows the scatter plot of difference in photometry vs Kron radius, and the right panel shows a histogram of these values that demonstrate that larger aperture sizes have photometry that is closer to the cModel. The right panel shows histograms of the data in the left panel, where the colors indicate for the same data in each panel." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "40604f56-60f7-43d3-afe7-981950402813", - "metadata": {}, - "outputs": [], - "source": [ - "fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(7, 6))\n", - "ylims = [-1.2, 1.2]\n", - "bins = np.arange(16, 27, 1)\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-ap06_mag), '^', alpha=.1,\n", - " label='cModel 6-pix aperture', color='red')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-ap06_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='red', lw=2, label='bin median', zorder=10)\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-ap09_mag), 's', alpha=.1,\n", - " label='cModel 9-pix aperture', color='orange')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-ap09_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='orange', lw=2,\n", - " label='bin median', zorder=10)\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-ap12_mag), 'o', alpha=.1,\n", - " label='cModel 12-pix aperture', color='green')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-ap12_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='green', lw=2,\n", - " label='bin median', zorder=10)\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-ap17_mag), '.', alpha=.1,\n", - " label='cModel 17-pix aperture', color='blue')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-ap17_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='blue', lw=2,\n", - " label='bin median', zorder=10)\n", - "\n", - "ax.axhline(0, linestyle='--')\n", - "ax.set_xlabel('cModel Magnitude')\n", - "ax.set_ylabel('cModel mag - Aperture mag')\n", - "ax.set_ylim([-1, 1])\n", - "ax.set_xlim([20, 25])\n", - "ax.legend()" - ] - }, - { - "cell_type": "markdown", - "id": "84519e9a-0810-49b2-bcd6-1c7dd8e63124", - "metadata": {}, - "source": [ - "> Figure 5: A similar comparison of the difference between cModel photometry and aperture photometry measured by the LSST pipelines for four different aperture sizes, this time as a function of cModel magnitude. Running median is included." - ] - }, - { - "cell_type": "markdown", - "id": "d4e2093d-9d9a-41d4-9217-209519b0a6d9", - "metadata": {}, - "source": [ - "These two figures show that the aperture photometry typically under-estimates the flux relative to the total flux estimated using cModel. As expected, there is a general trend for larger apertures to get closer to the total flux from cModel for large galaxies (i.e. whose Kron Radius is larger). There is also a general trend for the aperture photometry to be less discrepant at fainter magnitudes, since faint galaxies tend to be small.\n" - ] - }, - { - "cell_type": "markdown", - "id": "3d3dd22a-80aa-4282-8c14-1f20c8525088", - "metadata": {}, - "source": [ - "### 4.2. Application of aperture photometry: radial profile\n", - "\n", - "A science application for the aperture photometry is easy visualization of the radial profile of galaxies. In the cell below, make this plot for both a large galaxy (first) and a smaller galaxy of similar brightness (second). The query looks for bright galaxies whose `cModel` magnitude ~ 20 ABmag. Dividing the aperture flux by the surface area of the aperture yields the surface brightness, which can be plotted as a function of radius from the center of the galaxy to compare radial light profiles." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "83fdc23c-6234-4156-ac4a-d340240f2762", - "metadata": {}, - "outputs": [], - "source": [ - "wh = np.where((tab['i_kronRad'] > 20) & (cmodel_mag > 20)\n", - " & (cmodel_mag < 20.5))[0]\n", - "\n", - "indx = 0\n", - "arcsec_per_pix = 0.2\n", - "\n", - "rad = np.array([3, 6, 9, 12, 17, 25, 35, 50]) * arcsec_per_pix\n", - "area = np.pi * rad**2\n", - "profile = np.array([tab['i_ap03Flux'][wh][indx], tab['i_ap06Flux'][wh][indx],\n", - " tab['i_ap09Flux'][wh][indx], tab['i_ap12Flux'][wh][indx],\n", - " tab['i_ap17Flux'][wh][indx], tab['i_ap25Flux'][wh][indx],\n", - " tab['i_ap35Flux'][wh][indx],\n", - " tab['i_ap50Flux'][wh][indx]]) / area\n", - "\n", - "plt.plot(rad, profile, linestyle=':',\n", - " label='Large Radius R='\n", - " + str(np.round(i_kronRad[wh][indx]*arcsec_per_pix, 2)))\n", - "plt.xlabel('Aperture Radius [arcsec]')\n", - "plt.ylabel(r'Surface Brightness [nJy arcsec−2]')\n", - "\n", - "wh2 = np.where((tab['i_kronRad'] < 8) & (tab['i_kronRad'] > 5)\n", - " & (cmodel_mag > 20) & (cmodel_mag < 20.5))[0]\n", - "\n", - "indx = 0\n", - "\n", - "profile = np.array([tab['i_ap03Flux'][wh2][indx], tab['i_ap06Flux'][wh2][indx],\n", - " tab['i_ap09Flux'][wh2][indx], tab['i_ap12Flux'][wh2][indx],\n", - " tab['i_ap17Flux'][wh2][indx], tab['i_ap25Flux'][wh2][indx],\n", - " tab['i_ap35Flux'][wh2][indx],\n", - " tab['i_ap50Flux'][wh2][indx]])/area\n", - "\n", - "plt.plot(rad, profile,\n", - " label='Small Radius R='\n", - " + str(round(i_kronRad[wh2][indx]*arcsec_per_pix, 2)))\n", - "plt.legend()\n", - "plt.yscale('log')" - ] - }, - { - "cell_type": "markdown", - "id": "f2fae258-ded9-4d7b-be5a-c77b1e5fbf9a", - "metadata": {}, - "source": [ - "> Figure 6: Plot demonstrating the use of aperture photometry to plot the surface brightness profile (as a function of aperture radius) for a galaxy with large Kron radius (green solid) and small Kron radius (blue dotted). " - ] - }, - { - "cell_type": "markdown", - "id": "fdc9dd4c-95fc-4ba8-96f7-3d85ea32b9f7", - "metadata": {}, - "source": [ - "## 5. Photometry for color\n", - "\n", - "This section will explore GaaP fluxes (which are optimized for measuring accurate colors between bands).\n", - "\n", - "##### GaaP fluxes\n", - "\n", - "These are the Gaussian-aperture-and-PSF flux that is defined in Kuijken et al. 2008. The main goal of this method is to measure accurate colors while accounting for the different spatial resolution between filters. This is sometimes achieved in other datasets by convolving all images to the largest PSF, but this process of PSF-matching is computationally very time consuming for large images, thus motivating GaaP as a faster alternative. It is not a measure of total flux in a filter. Several measurement apertures are available. \n", - "\n", - "**Aperture**\n", - "\n", - "```\n", - "_gaapFlux : GaaP flux with aperture after multiplying the seeing aperture. Forced on -band.\n", - "_gaapFluxErr : Uncertainty of _gaapFlux.\n", - "```\n", - "\n", - "Where the measurement apertures are 0.5, 0.7, 1.0, 1.5, 2.5, and 3.0 arcseconds. In the column name `` appears as `0p5`, `0p7`, etc. Multiplying by the \"seeing aperture\" refers to convolving the PSF with a kernel so that the PSF is as if the seeing were 1.15 arcseconds. This has the effect of smearing the images of all filters consistently so that the colors are accurate.\n", - "\n", - "For photometric redshifts, and other analysis where accurate colors are important, it is recommended to start with the GaaP fluxes with 1.0 aperture (optimal aperture was found to not perform as well, and should not be used). The largest aperture `gaap3p0` might work better for larger galaxies, but `gaap1p0` has better overall performance. Experiment yourself to see how it works for your science case.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "id": "2468484d-3f81-4be4-b962-3a43a299f41d", - "metadata": {}, - "source": [ + "# Dynamically find ANY column that is a photo-z mean or mode estimate\n", + "available_pz_cols = [col for col in pz_regional.columns if ('z_mean' in col.lower() or 'z_mode' in col.lower())]\n", "\n", - "#### 5.1. Kron and GaaP comparison\n", + "# Fallback just in case nothing matches\n", + "if not available_pz_cols:\n", + " available_pz_cols = ['bpz_z_mean']\n", "\n", - "In the next cell, compare the cModel instead to the Kron and GaaP measures. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08d1c010-a802-4d03-a035-25a07cb51c19", - "metadata": {}, - "outputs": [], - "source": [ - "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", - " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", - "ylims = [-2, 2]\n", - "\n", - "ax.plot(i_kronRad, (cmodel_mag-gaap_mag), 's', alpha=.3,\n", - " label='gaap1p0', color='orange')\n", - "\n", - "ax.plot(i_kronRad, (cmodel_mag-kron_mag), 'o', alpha=.3,\n", - " label='Kron', color='blue')\n", - "\n", - "ax2.hist((cmodel_mag-gaap_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='orange', stacked=True, fill=False, label='gaap1p0')\n", - "ax2.hist((cmodel_mag-kron_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='blue', stacked=True, fill=False, label='Kron')\n", - "\n", - "ax2.set_ylim(ylims)\n", - "ax.axhline(0, linestyle='--', color='k')\n", - "ax2.axhline(0, linestyle='--', color='k')\n", - "ax.set_xlabel('Kron Radius [i-band; pixels]')\n", - "ax.set_ylabel('cModel mag - Other mag')\n", - "ax.set_ylim(ylims)\n", - "ax.set_xlim([2, 15])\n", - "ax.legend()\n", - "ax2.legend()\n" - ] - }, - { - "cell_type": "markdown", - "id": "892f08f9-b64e-485b-8d24-97e9104778d8", - "metadata": {}, - "source": [ - "> Figure 7: The left panel figure shows the i-band magnitude difference between cModel and Kron (orange circles) and between cModel and gaap1p0 (blue squares) vs the Kron radius (a proxy for galaxy size) for the galaxies in the query. The dashed line indicates where the two magnitudes would have the same value. The gaap1p0 magnitude always underestimates the flux, but the offset becomes worse for larger galaxies (relative to the fixed aperture). The right panel shows the histogram of the magnitude differences in the left panel, illustrating that while cModel - Kron magnitudes are similar on average (blue histogram) the gaap1p0 systematically underestimates the flux relative to cModel (orange histogram). \n" - ] - }, - { - "cell_type": "markdown", - "id": "f17ac68e-312c-4d90-9191-0efe4154d8b6", - "metadata": {}, - "source": [ - "#### 5.2. CMD with GaaP\n", + "print(f\" -> Comparing {len(available_pz_cols)} measurements: {available_pz_cols}\")\n", "\n", - "This section demonstrates using GaaP photometry to calculate accurate galaxy colors to identify different types of galaxies. First, define magnitudes from g, r, and i band photometry. The second cell will then compare the colors of galaxies that overlap the galaxy cluster with that in the field. In clusters, galaxies tend to be old, red elliptical galaxies and thus exhibit a well defined red sequence in color space. \n", + "# Set up index lookup for fast mapping from the LSDB dataframe\n", + "pz_regional_indexed = pz_regional.set_index('objectId')\n", "\n", - "The earlier query in Section 2 returned galaxies from a blank, \"field\" location (the ECDFS). These will be dominated by bluer star forming galaxies which are most common in field environments.\n", + "# --- 4. Build the Multi-Panel Plot ---\n", + "# Dynamically size the figure based on how many algorithms we found\n", + "fig, axes = plt.subplots(1, len(available_pz_cols), figsize=(6 * len(available_pz_cols), 6))\n", "\n", - "Below, add a new query near a known galaxy cluster at redshift z=0.3. This is Abell 360 and sits in the DP1 data from the low ecliptic latitude field.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "07de357a-44ff-448f-966b-b5c508b9dfa7", - "metadata": {}, - "outputs": [], - "source": [ - "cluster_ra = 37.83\n", - "cluster_dec = 6.98\n", - "\n", - "query = \"SELECT obj.objectId, obj.coord_ra, obj.coord_dec, \" + \\\n", - " \"obj.detect_fromBlend, obj.detect_isIsolated, \" + \\\n", - " \"obj.i_blendedness, obj.i_extendedness, \" + \\\n", - " \"obj.i_kronFlux, obj.i_kronFluxErr, obj.i_kronRad, \" + \\\n", - " \"obj.i_cModelFlux, obj.i_cModelFluxErr, obj.i_gaap1p0Flux, obj.i_gaap3p0Flux, \" + \\\n", - " \"obj.g_gaap1p0Flux, obj.g_gaap3p0Flux, \" + \\\n", - " \"obj.i_kronFlux_flag, obj.i_cModel_flag \" + \\\n", - " \"FROM dp1.Object AS obj \" + \\\n", - " \"WHERE (obj.i_cModelFlux/obj.i_cModelFluxErr > 20) AND \" + \\\n", - " \"(obj.i_extendedness = 1) AND \" + \\\n", - " \"(obj.i_kronFlux_flag = 0) AND (obj.i_cModel_flag = 0) AND \" + \\\n", - " \"CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), \" + \\\n", - " \"CIRCLE('ICRS',\"+str(cluster_ra)+\",\"+str(cluster_dec)+\", 0.2)) = 1 \"\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5973da2a-2a02-4ad0-8415-deccc55bb89c", - "metadata": {}, - "outputs": [], - "source": [ - "job = service.submit_job(query)\n", - "job.run()\n", - "job.wait(phases=['COMPLETED', 'ERROR'])\n", - "print('Job phase is', job.phase)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "18bc593d-bf80-44c1-9a33-158606fa2c8c", - "metadata": {}, - "outputs": [], - "source": [ - "if job.phase == 'ERROR':\n", - " job.raise_if_error()\n", - "assert job.phase == 'COMPLETED'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "32400242-e8f6-4461-941a-8617f75960de", - "metadata": {}, - "outputs": [], - "source": [ - "results = job.fetch_result()\n", - "tab2 = results.to_table()" - ] - }, - { - "cell_type": "markdown", - "id": "364f5aca-a4f7-4964-94cf-8c157b75f296", - "metadata": {}, - "source": [ - "First, calculate the magnitudes of galaxies in the 'field' location. Then, calculate the magnitudes for the other filters near the galaxy cluster from the query performed in the cell above. This will enable plotting their colors.\n", + "# Handle the 1D axes case if only 1 code is found\n", + "if len(available_pz_cols) == 1:\n", + " axes = [axes]\n", "\n", - "> **Warning:** Like in Section 2, the following cell will produce warnings for invalid value encountered in log10, which happens if the source flux is negative. This happens for a small number of objects and since the goal of the plot is to see the distribution of the majority of sources, the warning can be safely ignored. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4fe037fb-3da7-4f82-bdc9-f62c2f701f7f", - "metadata": {}, - "outputs": [], - "source": [ - "g_field_gaap_mag = -2.50 * np.log10(tab['g_gaap1p0Flux']) + 31.4\n", - "i_field_gaap_mag = -2.50 * np.log10(tab['i_gaap1p0Flux']) + 31.4\n", - "i_field_cmodel_mag = -2.50 * np.log10(tab['i_cModelFlux']) + 31.4\n", - "i_cluster_gaap_mag = -2.50 * np.log10(tab2['i_gaap1p0Flux']) + 31.4\n", - "g_cluster_gaap_mag = -2.50 * np.log10(tab2['g_gaap1p0Flux']) + 31.4\n", - "i_cluster_cmodel_mag = -2.50 * np.log10(tab2['i_cModelFlux']) + 31.4" + "for i, pz_col in enumerate(available_pz_cols):\n", + " ax = axes[i]\n", + " \n", + " # Extract photo-z for the specific algorithm\n", + " z_phot_all = pz_regional_indexed.reindex(obj_ids_all)[pz_col].values\n", + " \n", + " # Clean out any rows where this specific pipeline failed (returned NaN)\n", + " valid_pz = ~np.isnan(z_phot_all) & ~np.isnan(z_spec_all) & ~np.isnan(i_mag_all)\n", + " z_s = z_spec_all[valid_pz]\n", + " z_p = z_phot_all[valid_pz]\n", + " i_m = i_mag_all[valid_pz]\n", + " \n", + " # Scatter plot: Color-coded by i-band magnitude\n", + " sc = ax.scatter(z_s, z_p, c=i_m, cmap='viridis', \n", + " s=25, alpha=0.8, edgecolor='k', linewidth=0.5, zorder=5)\n", + " \n", + " # Perfect agreement line (1:1)\n", + " z_line = np.linspace(0, 7, 100)\n", + " ax.plot(z_line, z_line, color='black', linestyle='--', linewidth=2, label='1:1 Agreement')\n", + " \n", + " # Catastrophic outlier boundaries\n", + " ax.plot(z_line, z_line + 0.15*(1+z_line), color='red', linestyle=':')\n", + " ax.plot(z_line, z_line - 0.15*(1+z_line), color='red', linestyle=':')\n", + " \n", + " # Formatting\n", + " ax.set_xlim(0, 6.5)\n", + " ax.set_ylim(0, 6.5)\n", + " ax.set_xlabel('VANDELS z_spec', fontsize=13)\n", + " if i == 0:\n", + " ax.set_ylabel('Rubin z_phot', fontsize=13)\n", + " ax.set_title(f'{pz_col}', fontsize=14, fontweight='bold')\n", + " \n", + " # Calculate & display Standard Photo-z Quality Metrics on the plot\n", + " if len(z_s) > 0:\n", + " dz = (z_p - z_s) / (1 + z_s)\n", + " nmad = 1.48 * np.median(np.abs(dz - np.median(dz)))\n", + " outlier_fraction = np.sum(np.abs(dz) > 0.15) / len(dz)\n", + " \n", + " # Add a text box with the statistics\n", + " textstr = f\"Matches: {len(z_s)}\\n$\\sigma_{{NMAD}}$: {nmad:.3f}\\nOutliers: {outlier_fraction:.1%}\"\n", + " props = dict(boxstyle='round', facecolor='white', alpha=0.9, edgecolor='gray')\n", + " ax.text(0.05, 0.95, textstr, transform=ax.transAxes, fontsize=11,\n", + " verticalalignment='top', bbox=props)\n", + "\n", + "# Add a shared colorbar\n", + "cbar = fig.colorbar(sc, ax=axes, pad=0.02)\n", + "cbar.set_label('i-band [Robust Sersic Mag]', fontsize=12, fontweight='bold')\n", + "cbar.ax.invert_yaxis() \n", + "\n", + "plt.suptitle('Multi-Code Validation: Rubin Photo-z vs. VANDELS Spec-z', fontsize=18, fontweight='bold')\n", + "plt.subplots_adjust(top=0.88, wspace=0.15)\n", + "plt.show()" ] }, { "cell_type": "code", "execution_count": null, - "id": "450d40b8-3e1d-4e84-81ca-8d882eef7c69", + "id": "6f76f775-b947-44ec-acb2-e5b590e029fd", "metadata": {}, "outputs": [], - "source": [ - "fig, (ax, ax1) = plt.subplots(ncols=1, nrows=2, figsize=(10, 6))\n", - "\n", - "ax.plot(i_field_cmodel_mag, (g_field_gaap_mag-i_field_gaap_mag),\n", - " '.', alpha=.1, color='blue', label='Field Galaxies (ECDFS)')\n", - "ax.set_xlabel('i-band Magnitude [cModel]')\n", - "ax.set_ylabel('g-i color')\n", - "ax.set_ylim([-1, 4])\n", - "ax.legend()\n", - "\n", - "ax1.plot(i_cluster_cmodel_mag, (g_cluster_gaap_mag-i_cluster_gaap_mag),\n", - " '.', alpha=.1, color='r', label='Cluster Galaxies (Abell 360)')\n", - "ax1.set_xlabel('i-band Magnitude [cModel]')\n", - "ax1.set_ylabel('g-i color')\n", - "ax1.set_ylim([-1, 4])\n", - "ax1.legend()" - ] - }, - { - "cell_type": "markdown", - "id": "b4e3745a-8e04-4243-898c-10c8d25aae4b", - "metadata": {}, - "source": [ - "> Figure 8: The g − i vs. i color-magnitude diagram for galaxies selected in the queries. Top panel shows the galaxies selected from in a random field that does not contain a galaxy cluster (ECDFS). The bottom panel shows galaxies from a field with a galaxy cluster (A360). The cluster galaxies appear as a \"red sequence\" with red i-g colors, because the Balmer / 4000 Angstrom break spectral feature that traces older stars sits between the bands." - ] - }, - { - "cell_type": "markdown", - "id": "f4800e26-7f1f-4b50-bdf5-b3e7bba174c4", - "metadata": {}, - "source": [ - "A very nice red sequence appears from the red, old galaxies in the cluster! " - ] - }, - { - "cell_type": "markdown", - "id": "927a6cd3-5db6-4308-a7a6-2f13ccdb4568", - "metadata": {}, - "source": [ - "## 6. Exercise for the learner\n", - "\n", - "Compare the `_free_cModelFlux` measurements to `_cModelFlux` in the filters that are not the reference band where the `_cModelFlux` was measured (i.e. `refBand`). Investigate how leaving the cModel measurements free differs from the one measured with parameters fixed to the `refBand`, as a function of decreasing signal to noise. As an additional exercise, check how the signal to noise in colors measured using `_gaap1p0Flux` values compare to those measured with the larger 3.0\" aperture, `_gaap3p0Flux`, where the larger aperture may increase the noise. " - ] + "source": [] } ], "metadata": { @@ -2234,8 +716,7 @@ "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.11" - }, - "toc-autonumbering": false + } }, "nbformat": 4, "nbformat_minor": 5 diff --git a/DP1/300_Science_Demos/303_Galaxies/Color_selections_exploration.ipynb b/DP1/300_Science_Demos/303_Galaxies/Color_selections_exploration.ipynb new file mode 100644 index 00000000..c5512fa9 --- /dev/null +++ b/DP1/300_Science_Demos/303_Galaxies/Color_selections_exploration.ipynb @@ -0,0 +1,2242 @@ +{ + "cells": [ + { + "attachments": { + "697dbfa5-0793-4e9d-8401-2f3b86b0243c.png": { + "image/png": "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GPJmu7BUJEACJEACJEACJEACJEACJEACJEACJFBwApyVrOCIeQASIAESIAESIAESIAESIAESIAESIAES8CYBCkPebBeWigRIgARIgARIgARIgARIgARIgARIgAQKToDCUMER8wAkQAIkQAIkQAIkQAIkQAIkQAIkQAIk4E0CFIa82S4sFQmQAAmQAAmQAAmQAAmQAAmQAAmQAAkUnACFoYIj5gFIgARIgARIgARIgARIgARIgARIgARIwJsEKAx5s11YKhIgARIgARIgARIgARIgARIgARIgARIoOAEKQwVHzAOQAAmQAAmQAAmQAAmQAAmQAAmQAAmQgDcJUBjyZruwVCRAAiRAAiRAAiRAAiRAAiRAAiRAAiRQcAIUhgqOmAcgARIgARIgARIgARIgARIgARIgARIgAW8SoDDkzXZhqUiABEiABEiABEiABEiABEiABEiABEig4AQoDBUcMQ9AAiRAAiRAAiRAAiRAAiRAAiRAAiRAAt4kQGHIm+3CUpEACZAACZAACZAACZAACZAACZAACZBAwQlQGCo4Yh6ABEiABEiABEiABEiABEiABEiABEiABLxJgMKQN9uFpSIBEiABEiABEiABEiABEiABEiABEiCBghOgMFRwxDwACZAACZAACZAACZAACZAACZAACZAACXiTAIUhb7YLS0UCJEACJEACJEACJEACJEACJEACJEACBSdQXfAj8AAkQAIkUAACk4uLgr/k1N3cLPhj8i6BVG2XWGK2YyINfiYBEih3Aqnue7zXlXvLsvwkQAIkUBkEKAxVRjuyFiRQ8QTQqf7tjZvy1o0bliC0GonIaiR8T73rq6ulvrpGupqb5FBPjxzq7bWWXhKLUI83b1y/p+yZruhuatoQv1Av1NNL9UushxkMXRqfSNt2ifsltqM1cNI6P9vfL4e1PYuRcm2jTMuItntO61XI9jPXzoXxsUyLtbGdl861dPV4dm+/PL+vf6PsuX5Id7xitJ1dHS6Nj8tb12/IxNK9wnji9l4vX2JZ8/053+eC2/K5ue+Ze91B63nVI1gW6z6XSb3SXQdOeXjl/pGuDihnPp4v6a5NXJNfOHhQmmprnbDxNxIgARIoCQEKQyXBzoOSAAlkQsB05iAGDc3NyfjCgkzoH0ShdKlOBaITt25LW329PLn7Pnlkxw7PdLgvjI3JP370cboqpPy9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CWxeAr41TZu3+qw5CZBAORGIuzqsWAMXxOWwiytkZsDCbFjoqMOVqtjBZNMxNfVIt1263zHIq6+p2ZgBLN32hf4dbgAQ8LBEQvsgmDhmHUtsK8wgh2ntjSDixTbLVxulY27O0XTb5fJ7crsk5oVzKNtrJB2jYtQtsS52n53qnrh9qcrqVL5c2iaxbsmfndqtUMdMLkPyd6cylaptksvo9rtpW1O3xHtgYl7m/teqM0hipk3rvq7XpVeSqQeWySmX88VwSc7TfPdCuzuV0QvlM6y4JAESIIF8EKAwlA+KzIMESIAESCBjAhhg4I2E1wS7jCvADUmABEiABEiABEiABEiggghQGKqgxmRVSIAESIAESIAESIAESIAESIAESIAESMANAU5X74YWtyUBEiABEiABEiABEiABEiABEiABEiCBCiJAYaiCGpNVIQESIAESIAESIAESIAESIAESIAESIAE3BCgMuaHFbUmABEiABEiABEiABEiABEiABEiABEiggghQGKqgxmRVSIAESIAESIAESIAESIAESIAESIAESMANAQpDbmhxWxIgARIgARIgARIgARIgARIgARIgARKoIAIUhiqoMVkVEiABEiABEiABEiABEiABEiABEiABEnBDgMKQG1rclgRIgARIgARIgARIgARIgARIgARIgAQqiACFoQpqTFaFBEiABEiABEiABEiABEiABEiABEiABNwQoDDkhha3JQESIAESIAESIAESIAESIAESIAESIIEKIkBhqIIak1UhARIgARIgARIgARIgARIgARIgARIgATcEKAy5ocVtSYAESIAESIAESIAESIAESIAESIAESKCCCFAYqqDGZFVIgARIgARIgARIgARIgARIgARIgARIwA0BCkNuaHFbEiABEiABEiABEiABEiABEiABEiABEqggAhSGKqgxWRUSIAESIAESIAESIAESIAESIAESIAEScEOAwpAbWtyWBEiABEiABEiABEiABEiABEiABEiABCqIAIWhCmpMVoUESIAESIAESIAESIAESIAESIAESIAE3BCgMOSGFrclARIgARIgARIgARIgARIgARIgARIggQoiQGGoghqTVSEBEiABEiABEiABEiABEiABEiABEiABNwQoDLmhxW1JgARIgARIgARIgARIgARIgARIgARIoIIIUBiqoMZkVUiABEiABEiABEiABEiABEiABEiABEjADQEKQ25ocVsSIAESIAESIAESIAESIAESIAESIAESqCACFIYqqDFZFRIgARIgARIgARIgARIgARIgARIgARJwQ4DCkBta3JYESIAESIAESIAESIAESIAESIAESIAEKogAhaEKakxWhQRIgARIgARIgARIgARIgARIgARIgATcEKAw5IYWtyUBEiABEiABEiABEiABEiABEiABEiCBCiJAYaiCGpNVIQESIAESIAESIAESIAESIAESIAESIAE3BCgMuaHFbUmABEiABEiABEiABEiABEiABEiABEiggghQGKqgxmRVSIAESIAESIAESIAESIAESIAESIAESMANAQpDbmhxWxIgARIgARIgARIgARIgARIgARIgARKoIAIUhiqoMVkVEiABEiABEiABEiABEiABEiABEiABEnBDgMKQG1rclgRIgARIgARIgARIgARIgARIgARIgAQqiACFoQpqTFaFBEiABEiABEiABEiABEiABEiABEiABNwQoDDkhha3JQESIAESIAESIAESIAESIAESIAESIIEKIkBhqIIak1UhARIgARIgARIgARIgARIgARIgARIgATcEKAy5ocVtSYAESIAESIAESIAESIAESIAESIAESKCCCFAYqqDGZFVIgARIgARIgARIgARIgARIgARIgARIwA0BCkNuaHFbEiABEiABEiABEiABEiABEiABEiABEqggAhSGKqgxWRUSIAESIAESIAESIAESIAESIAESIAEScEOAwpAbWtyWBEiABEiABEiABEiABEiABEiABEiABCqIAIWhCmpMVoUESIAESIAESIAESIAESIAESIAESIAE3BCgMOSGFrclARIgARIgARIgARIgARIgARIgARIggQoiQGGoghqTVSEBEiABEiABEiABEiABEiABEiABEiABNwQoDLmhxW1JgARIgARIgARIgARIgARIgARIgARIoIIIUBiqoMZkVUiABEiABEiABEiABEiABEiABEiABEjADQEKQ25ocVsSIAESIAESIAESIAESIAESIAESIAESqCACFIYqqDFZFRIgARIgARIgARIgARIgARIgARIgARJwQ4DCkBta3JYESIAESIAESIAESIAESIAESIAESIAEKogAhaEKakxWhQRIgARIgARIgARIgARIgARIgARIgATcEKAw5IYWtyUBEiABEiABEiABEiABEiABEiABEiCBCiJAYaiCGpNVIQESIAESIAESIAESIAESIAESIAESIAE3BCgMuaHFbUmABEiABEiABEiABEiABEiABEiABEiggghQGKqgxmRVSIAESIAESIAESIAESIAESIAESIAESMANAQpDbmhxWxIgARIgARIgARIgARIgARIgARIgARKoIAIUhiqoMVkVEiABEiABEiABEiABEiABEiABEiABEnBDgMKQG1rclgRIgARIgARIgARIgARIgARIgARIgAQqiACFoQpqTFaFBEiABEiABEiABEiABEiABEiABEiABNwQoDDkhha3JQESIAESIAESIAESIAESIAESIAESIIEKIkBhqIIak1UhARIgARIgARIgARIgARIgARIgARIgATcEKAy5ocVtSYAESIAESIAESIAESIAESIAESIAESKCCCFAYqqDGZFVIgARIgARIgARIgARIgARIgARIgARIwA0BCkNuaHFbEiABEiABEiABEiABEiABEiABEiABEqggAtUVVJeyq8pSYFCm73wsgckbsjQ3ItV1TbLr0Bdl664nyq4uLDAJkAAJkAAJkAAJkAAJkAAJkAAJkED5EaAwVMI2W12clLnxT2R+6rbMTw9IdU2j9Nz3eAlLxEOTAAmQAAmQAAmQAAmQAAmQAAmQAAlsJgIUhkrZ2mtR8cmaNLR0SDQalEgoVMrS8NgkQAIkQAIkQAIkQAIkQAIkQAIkQAKbjACFoRI2eCS0LJHwsvir66SuoVVFoqUSloaHJgESIAESIAESIAESIAESIAESIAES2GwEGHy6hC2+JjHx+Xziq/Jbf6HVgKwuzRS0ROHVeQnrcZhIgARIgARIgARIgARIgARIgARIgARIgBZDSedAJLSowaAvy9LsLWntPiDtPUeStsjP19WlCQkuTUmVv1ZUFbKshtRkSJYXxiS4PCN1jZ35OVBCLqHVOY1ndFUWpwZUkKqXzh3HpGXLroQt+JEESIAESIAESIAESIAESIAESIAESGAzEaAwtN7a4eC8zgw2KAsz12Vh+pqsLoxr3J+wNLbtlNr69ryfE7FISNbWIpalkGicoZq6RqmpbZQVPS7EoUIIQzGtTyS8JIs6G9rc6G0ZuPBr2bbvKdl1+Helrqkj73VkhiRAAiRAAiRAAiRAAiRAAiRAAiRAAt4mQFey9fZZi4ZkefaGzE9cVPFkRXz+almcuaki0fW8t2BoZdYSoLD0qbXQmh4By+raBl1/Q2cqu5j3Y0Yjq7KyOCZLgSEJB6e1jjMSWpmWKnVjq65ryvvxmCEJkAAJkAAJkAAJkAAJkAAJkAAJkID3CVAYWm+jmro2qYVAElkS31pMaurbVECZl3l1KwutzOW1JYPLk7I8f0ctkjAL2Ro8yKzU2NJtWQ3NjJ5XQerm+tr8LBDkellFoUUVukLL0xJViyVYJcGVzF+t7mxMJEACJEACJEACJEACJEACJEACJEACm44AhaH1Jvf5a6Sp835patkqEl22Yv9gtrC41dC1vJ0YweUpdRcbk6haJUUjQXUn+zTrKj1efXOHZTU0cOHHusyPOITYQnCRg8UQrKFCq8sagDokbT0PSMe2g58WgJ9IgARIgARIgARIgARIgARIgARIgAQ2FQEKQwnN7a9tFn9Nk/hiaskTi6prV7OEQwsyNfS+LGow6lwShCDkEZi8pALNqBXrR9QyKTHBcqi+oU0aWzqt7YYu/kyFqduJm7j+bAWc1phJ81NXNIbSgESCC3rYNaltaJeWzl1qGdXsOk/uQAIkQAIkQAIkQAIkQAIkQAIkQAIkUBkEGHw6oR1r6lo12PR9sjRzTa151KWsts0Sh+bV2mbt8s+kb/8XVUzpT9gj/cdIaEkFmduWKAORJqyznmEd3MiMsVDiErGNaupbLYul5flBuXb6b6V1yz7p2fOcNHfcl/6ACVvERaGrlii0MH1DVhfHVe8Ka90iGmx6qzS19SZszY8kQAIkQAIkQAIkQAIkQAIkQAIkQAKbjQCFoYQW91XViL+uWQNPa8wdteZBQOiauhZ194qqBc9Ftd65oa5XD8mWvuPS1K7WNhqXKDkhLlF4dV7dxUbjrlsqAoVWZyQWC2uWMf2LWvnBhwwWQhCFkpdVelxfTb3uE1ERZ1HmJs5b1kb1zT3WcWs1/lGTzpaGMiQnWCZFNNB0OBiwXNIww9qyzraGOElr0Yi1eSwKSyW/VDG2UDI+ficBEiABEiABEiABEiABEiABEiCBTUWAwtA9za2ijM7U5YvG7XjwubahQwM010tweUZmR89YggsEo2q1MPLXNKhA1Ko6T0zCKr5E1CIoprGDYggs7fNZ+1nyj36GGITtTDKWQsnfzXqfz2/tDzEJQk9odVYtj27p5pjBrEmDR29Ry58uK4h0lYpaEJ+i4VXruNh+ceaWBBcnVVxaVUEqLgrhWL4qn85Gpl6EUKSYSIAESIAESIAESIAESIAESIAESIAENi0BCkNJTQ8roaoqxaJijEk+n7p3qfhTXdtouWIhYDSsiCC+RHW2r/BqwBJ8LDFIbYBCwaAszs3J4vy8xhIKa34+1YhiOutZnbR3bdUYQq1W1sZSaOM4+gGikFkf1X0joZDEVEwKabDoWBRxj1alusYvNREcd1Ytk4bjcZFUwFqDmxhc1FQEwh+sh6wyocAmU80fohAsm4LL+Z1tzdSDSxIgARIgARIgARIgARIgARIgARIggfIgQGEoqZ0i4SV1xQqqelKvv6iFjyoqPrNUq5xqf52KPFBZsBb/6tISbpZlZnxcJkdH9Hu9CknN0t79gGzZtheGQ7K6NC1BtSianx2Whdkx6ezZqYJOfJp45IOUuFyeC8jM6KiWo8EKFF1dr5ZBLR2ysjQnARWdVldmJapuai1tTSo0NUlDU61UV2tZLFc1tUpKsE5KzBfH8ddU65T1M7IyP46vTCRAAiRAAiRAAiRAAiRAAiRAAiRAApuUAIWhhIYPLo3L6sKIqj01GmeoTn+B7BNPZrmxOSyLVPEJB1dkbnJIluYXpVmDRB977gsq1GxVq55adfFqkfrGuHUQpqaPhoMyeOlX+veqLC/MSGtn77q4dLelUGhZA19Xtcj9jz2nMY32W7GA/BoPyK/T2Uc0j0g4pOJVSJbnJ9WtbUiFpjuyrC5j1dVBtUqCxdO6yIRCqypkLcxSV0EYqqoOy8LUdf27JS1dezaqxQ8kQAIkQAIkQAIkQAIkQAIkQAIkQAKbhwCFoYS2XgkMqmuWWvxU1aqeorGGEn6D1c2n3+OfVhanVZSZ0Dg/fbLjwKNqIdQvja1dloCTsOv6xxZr2alCz9TwqbiLV9JGxrJnWV3QfNIu7T39svW+I0lbffo1quJQcGVR3cyWZHb8mty5/p4Eg6PS0PDpNvhk8jVrYfFUXVcj89NXZfTG21Lb1CF1On09EwmQAAmQAAmQAAmQAAmQAAmQAAmQwOYiQGFovb2Dy5MqCt3RGD0aW0hjCn0qAmGDTy2HzOkRVNew6eEL0t77kOx75BvS0JJKEDJ7xJeYIr65Y5taJg3e/YN+wzEh4mA6+Y6eXdLRu++ebRJXwIqosaXT+mtq3aLeY2syfvttjUk0q7KWzoK2XgufDy5xmhIUIn81YhKFZG7svNbhgApQjydmzc8kQAIkQAIkQAIkQAIkQAIkQAIkQAKbgIA6HTGFVqZlfvy8umaNSEyncYegEtdQ1gUV/WY0FSzxDa5h9S090r3zERV6+lJYCd3LNhxcVPezRSu/xDyx5cb32JoVo6i2IW5ldG8u966pqWtUa6Ut1n6YzcxK6xki9jSSyR+fIXX5a2rU2mhS7lx5VabvnMVqJhIgARIgARIgARIgARIgARIgARIggU1EoCyFoYgGXca08PlIYQ3ivDB5SaeBv62xe3Ra9/VM4xZDn1oKGQsis8QMZVX++BTxbsqBWcIQA6imtn7dniduKYQ8TN4QcoyY4y7voLqoLWo+sBZChvh33W5IP5r88RN+wbT1vqqYLAduyfClV2Ts5tsqFAXwc9YptKrBsScuq/XVWNZ5cEcSIAESIAESIAESIAESIAESIAESIIHiECg7V7KITg8/M/qxChiz0rntEbWS6cuKVEwtflY12PTi7A1Zmh3QWD0BCa6uyGJAZ/uKRqSuvl7j7iB4dLOVvyWkrB8JchGsclYWJmQpoMGqXaYqnVo+bpl09444BpJlyRNc0Pxn1EWtM74yzb/LWpblwJBqQSsq+uisZAnJ5ItV4XBELZYgHKlVEqa917+1tYjFIXRh2lpu639Bmtp3JeSQ2UeIQrNqeTU1eE4Fpzbpe+BZaet2n09mR+NWJEACJEACJEACJEACJEACJEACJEACuRIoK2EoGtYZwCYuyOzYWQmtzEhYxZytu591LWJAwFieG1TXsSH9u6Ozit2RyRENOq1uZD33HdWYPe0qPl2Q4MyoWvf0SW19813WNoBeY0AOtwAAQABJREFUXYtp5JslMHVTxZCrGhPogYzaAtPER8NLUlPfYOWZKNrAoscSoNSkCOIUZiDLNC0FRmVlEeX16b5x6yCTt5Wv/rO0EJTxkRmJxRqkqbVTt5/VMixJY3OdNDbWqEAU1rhJH2ghorJt3++64vqpKPSeBte+LovzMZmdmZEDj/6+bNnWn2k1uB0JkAAJkAAJkAAJkAAJkAAJkAAJkEARCZSNMBSNrEpAZ9EKTFxUUWhOwqsLluUQ3Mq27fs9ae7ckxYbrI1WVAhanBvQ4M+jsjA3poKQikOLQRV2DsjOB55QEWOfNdX8lm0HZPjKL3Va+Qnre5VOFQ+BJZ7UPUutfprbtsnknWsyPnA6rTC0FBhT66JxmRrRKeIDyyKBJVlc0TLMz1lBoKVapxKrqpHmhhpprK2SoNbz+pmfSN++zwgCVje19ZiD37NcWZyyXOHCGi8oFl359Pd1ZQiLcDAi0+MBFXv2y6EnXpLWLdtVoArK0vyECls3ZfjahzI1PixdPSHd+kMt65Ba+xyS7vtw/J2f5pn0Ce2ysjgm81PXZFYtuQLjFyQWWVBrrLBcOf2GClDbKAwlMeNXEiABEiCB0hGY12f//Nz4XQVobe+V1vbUz9m7NuYXEiABEiCB8iMQi4gsj8ra6pRVdl/jNpHG3vKrB0tMAgUiUDbCUGh1WYWas3Ln6glpbtXZuFrrrCnfZ0Y+koDGCGrfelh6+z+rAtHeu1AhFtHijLqLWTGEVlS0CFpxdOamxmX45m1p6rhPjjzzNdmiM4AheDNm+kKClRBEj5Hrv5aQBotuUGHo7uTTaeo7VBzaKpNDH6vQske29z9pbQIR6M7Nj2RwUGP3TC7I5NyKBH1tambUJpPTizIa2CuLkXpZVbEmGFIhRpWb2JoGvNYbVl11ldTV+qXRNy+9l6Zk77ZfS0fdstTVVEtjVUDamuvlvgcek77+4xti0eqiupHND+t0ZhojSa19kCxNyDIVilsPBVfD0tC6Q+5/5POy5/BTKnbF6xMJh2T7noc0rz65ce4NWVSrI5FpjeG0rALcrLqW3ZTW7gMqKO3UwNatUqt/qoqpK53Oe6bubss6k9uSWl/Naxsszt6WKFzglsMqeK1KZ+8x6dl1wCoP/yEBEiABEiCBQhOA6LMWmZK18JQMD+ikCtFpaWnyqxD0qRgUi8U2npUoz/xiVK1tq6StJf783xCJqrt0ktIu/T0i7d1HZIdaFDORAAmQAAmUKYFQQGJX/6us3fpn8XUfF9/B/4nCUJk2JYtdGAI+neJ83a6kMAfIV67RiLo5jVyVS+//WEWIy9LZ0y51jbUq9KxuBKKua9yiAsZuqW/Szpxa9FRVVUtYhaHg8pQl8qCqiA+0MB+QmYmAbOl7WO5/+EVpU+sZI5Qklhfxg26f/7HG+hnUmcd2qBiC2EJxUSQujvgsd6+pkZu6W7Ms+zrl1uCQzAabZKnhmCwF62VqJiArKxrTR4Wf4YWojC7EJBiOWe5ea2vaOdUZyMxSv+j/6LDGpEoFnj6t48E9W6W9qVaWl1ekvsYnvV1t0iFD0rqmZWqsli0aAmlrl3ZmtfMbDS2owKTCkNYz3qwaa2j98+jQtGzZ+aw8/nt/rnGT7p3tLLi8oO5f0zJ2+5xc+/jnKvCMyJbuZo2zVK9ub8pamdY2dKoLXbNUV9eLX13pIuratzRzU2M03bZEJAhpwdWITIwFpUU70Y88/03ZtudBW7aJnPmZBEiABEiABLIlANFn6PqvpKX6pkSC43Lpyi190seksX5NFhb1RcVyRMUhfenij0qjvhNpaYq/E1MPauslyrK+n4H4o+9q9HlVrY/3KllcRteoSlqba63nqU8teju2aD+g/oBUNRxQkegYLYyybTDuRwIkQAKlIKCWQrHz/0HWrv+D+HqelKoH/0oHUY+XoiQ8Jgl4kkDZWAz5q2tky/YH5OCTfyhXTv5E5qau6Bu8NhU5GgRuXrC2gQg0P3lRLVgwYxg6d9rrg5gD9BosGsLO4sKCzE4tSu+eJzX+zUtqKdOVsmEamrultWuvuq3p28dYWLOIv03EDsGVRRWkwjIxFZBLd2Jyc6FOxmJbZCDQp28qw9JVG5Fm/4LV66xWgQqpud4v9VG1tNFOqM+IQBCC9C+GwEAbIlF8XWNLi1oxtekcY1USqfZLWGcZu3ZHrY9CbdLVdlzq5n1WJ3fn6CfSGrwpDf4l6d3WpjGSWqw6r89HpgKOlkUtfrbtPmYrCqFsdSoW4a+5bYuyq5VLynh6SsWhLpQtJCEV13xaDyOMQXiDgAXLolhELbFiURWFojI1EVQhqU/2P/IiRSGAZSIBEiABEsgrAWMVFJj8RIZvvKEvRSZkDu7ZS0Hp6aySvg6f1EhEanxRWWtYU6vfiIzORGRqLmY9GzEj57i+pJla0pcnmvB6rFuFo+5mn/S0xJfdLdX6IsQvtbUhgXA0s7Qmt27O6zPwqj7A/7vcPlcjh488oQ/PB8TfeJDWRHltYWZGAiRAAiRAAiRQbAJlIwwBjBGH7jv8nIpDcxoraErf7rVp561GrYP0zw/3KJVD1KrHEkUstyq/duJ0fnjt+S2pKBSYgSj0GdkPUag1tSiE42E6+qbW7TJX06BuU4sqnHTKqgpCI6PTMjCk7mKr7XIlekQGl1plZqVGgmvVelztlGrHsr0xItXqtraR9Pg99WrYo/GDBpd8ltWQZR1kiULaWVVh6K7vKrTEtNzottaqe1ljk8Y40jyaampkVTu3tydUkNF9a6urZaL1AXV12yUtvgnpHbwjHTXT0lY3J10dtdLQ3KRl1l5tVV1KUWijjPoBM7HtffAZrfcWuXLqFQ0gfV46OnQONT1T0HkG3/gHzGuGr/jX+qSWWCG1JOqTw0/9kew+9BlaCoEPEwmQAAmQQF4IQBAKjL0pMyO/keHhIZlfWJWm+qhs7aiSvV0R8W9RAWg2LG+dDcmF0YhMLq7J+GJMJvQvpi9e9P940rdFcN/e+K5rVSva+PNbb5P0RbI+y49s90t3Y5Uc6vXL0Z110tBUL9Oa74yGCjx/5jfa33hbWtTFe/DyEdl14BsUiPLS0syEBEiABEiABEig2ATKShgCHIhDvRoTZ2b0hrp5va5uYyFpVmEICebfln0QhKC4mZB22uI9vJXFBRkfGtRZx+KWQo1pRCErQ/2nvrlLxZWtGsfoqoyMDagrWJ2cXdkvp+efkJlgjays1csajtcYP6Qa9UikRjugdWq2rp1JSzOBeKJ/dfq3s61eQvNVMjS9rEGnVVxRcQeiUCwatxISXVoika6b01g9oXBUrYMaZHHVJ8sQeLQz29rWrCbvURkYnlTz92VZ7uuWnb1dEoi1yXh4j1oOBWXbylXpWbwuXY0zUusLSuvWByyxx9TLaVmns6319R9T4W1cbpwdkUhk3hKGLJToWCtSVGm972xlFVb3uBU11+/bf1T2HXsuIxHKqQz8jQRIgARIgARAIFEQGtLYffU1IdndERV/e0RGZsLqwh2xhKA3rodlTF229fEoEX1GwT5IH7NxAWijXyDS21olvSr6jKnVEPoIrdqFmFOxJxBak1W8jcFzTv+Zm1ErobmICkZran2kbmb+FTm6vVoObVWhqMcvx/ubtA9SL7NLOhnG3Em5eeq8RGcfk7aeZy13MwazBkcmEiABEiABEiCBciBQdsIQoNbWN0lb1w4rGHIkpEEBEhL6c5ZgYT6sLyMao6i5fbsGiH5U3bOcLYUSstPYRCrA3BqUoZFxmW1TMUhn9bqjlkHT6lW2qroPDrZxvHUBaE67owENYr2lWTud6oKGOEKWkqK/N2r8gkXdbXKpWq2G4sKQqHuZD8IQrIb82iuNaiBqXbcUisnHNyZkUmcx8+vrzNEpDey8ojOotTRIQ121dGu8IRz8yuC4dnzXNCZRl4SkTvOtkYXQMRmoul92hq5Kd9VV2dOyZMVaEtmdWL2UnxGEu6Nnl7R2bpfwEkqs5QJLTeuL+Jf176FgVC232jT2k8Z4solhtLExP5AACZAACZBABgQQQDq2+I5MXf2lXLx0zRKE9myJysTMivz9O6tyYVzj9s1HLbewiL400ceQaBhp6WlVlzB9OTOu7l+71bXsDx7wS0eDT355LSonR9fk9w/UyG7d5taCTw711UqbWvI2acChjgZ1OdcXTBeGgvLdE3NyaSYqqhVpWpMVPMc1/3cGo/LBENzURPrag3Kkt1qe76+WR/Y2yvJaRAauvS0jJ96SXXt1koj7HqKbWQbtzE1IgARIgARIgARKT6AshSFg69Rp5bf07ddp0i+oeBNTtyV1GVOVxFgIQTCx0voyGlHLovb7dPay3es/OC8ws9hHJ36sgtCAzDYdlontz0qwqklNlmqkr2tNurWzObsck2sTYZnTV4yWYxU6kPrXWOeX1tY1qW/QuEQxdWvTDqURh6AldTXp/vqK8o52aPG7+NXxTS2H1qJ+jdej6zR+T6xKRSIVigIrUVkZCWh19E2mWgwhEPXWzhZ9c+mTgMZUiGpnuEnjLC2rQDYzv6TlalOjIjWRV3FpKdoi11aOyZAKRHPjKmz96pdy7JFVOfboM86VX/81psy0EOqmB7YqDIGl1m99Ed9Kv8BKKqQiVn3TVg3krVM/MpEACZAACZBAlgQgCM2py9jFM6+qy9gt6W6LSqIg9MurYRme1xh3+uyBgU93s1/ua6uS/V1Vcr8+m5v0mdqsQtBvBmLyixsiuxer5H9UMahT3wkFPgzL+zr55sB0TMLadxiY1PiE6pL9L56ot55lv760qHGGamRfb6NcWlB/MT3GV453ye/sa9ag1lMyH/HJ5UBMTt+YkyvTa3JTXdd+cSUsj+wIyzeO1lgCUXNfnT6fT8m7b3xgCUTR5UsUiLI8F7gbCZAACZAACZBAcQiUrTDU3LnNshpamL6kxjjac9P/oVjgY6LL08Z6jdkzP31b/wY0aPUeR7o3Ln8gZz/4qUyF62Ws+RlZqt2qwQcQyNr635odrEk/N+tbRp9Uy9XJsIpEKIAmtexZVSFIjYGkrl7xokAJwpBl166dUbxurNI/SzDCm0gVhqRKZyPT/dfUeki08xmzgh7EJKRiEdbFMFNKKCozi6uyq6dVp9bdIlu3tKrZPOIq4dCapwpGMf2s3/S7zn4WUwulSItcmGmUAQ20ObZ8VWdv+VAefuxZa8p7bGmXFmZHZGbsvE77O6GzkOlrUqT1Kq4vzFfrJ8RvqK6rZVwhiwb/IQESIAEScEvAuIzNjf5GBtVlrLYqqBY9GiR6Vi2E3l2VX6kgdEcFoVV9yHU360sXfeZNqnazfYtf/vhhv2yv88k/nI/JxYBPdmkg6QW1CNLHprqIVcnAuEh/T6386fFa+ZkKOWpEbL2cOTO7Jv1tfp2xrE6W9Jl7cmZJJgaWBI/pmAaf/hcPdclffKZbTl2cklevL8tnjm6Vf3WkWeP6qcXRTNB6ho/MrMoJtSL6aCQqj/StC0R7GqWtXgWi+Y/k/AcfS1XTEcXxp4xB5Pak4PYkQAIkQAIkQAJFIVC2wpBfLXeqa+t1RjKdKQuKjZWskNP6Sb+bVevLlg6NwTM1LiPXfist6lLW0fvA+j6fLmAl9PHpt+Xq2KxMND4jAX+HennVquii5uXrm1mik36BOAIjpZ3t1ZYgc2VKxaEV7UnqlnBuQ4e1ToNGmx19lvijlkMqFK1phzSs0+b6atSiyJqdTMutrmNxNzINOK2WQt0ai6hVhaV5nWVlNrBquZDBxSysv82qMNTb1Swd7RrfQDueEe3BGqskBKT2qVAUUzMeK/a2LvE5qvvCsunMWI/MLQRl9M7fSf++D+SJ5/9IZ2brWa9dfLEUGJfRG+/IwuQZ8fuWtAqaF34CBP2wvohXbV0lgqUWZnpBGAcmEiABEiABEnBDIDB5XgYu/b0M3jwVjyHUGXcZ+8cTcUEIFkJBCEItfvnK/X452O6TX91ck7f0efrJlE/OjIjcf9AnnRo76OlmdTmvqZKXZ6pkTgUcBMn79aDIpbk1+eajLfpSJSanbizLyIo+r7UX1LmlQbq2NMvAnUWZ0kDVY1ipz+on7m+Xbzy5TZr0pc1Ho0G5FamSHfMRebGpRh67r0ln4ozIt57fqcGna+Sf3xrUPAMqEKkL+FhQHtkela8/uCKP7NEYgQ11+vLonExf/08SW/mctPc+x6nu3Zwc3JYESIAESIAESKDgBMpWGAKZKn+V+P2YdexTTtAprK8bH+K/VdfWSVt3rywH7sjFE9+VvQ99Rbbt/czGjrfUSujCJ+/LQGy7DNcdU4MdRbMhCCVkph8hREEgwrJWO5072v2ytbVa4watqWl5SAWiqNRpLKEGjXEQhfWPtS36mWtSq+WNqoC0EFtVYUhVFJj3WNuoOKRuYWsqrsBqaEmNdNo0j6P9LRpgelUuDc6qQKTTwuuBa9Uyp66uRsuAjHUeNN0e0g1kKdgwxZeaNb7hd/0EXQoFCaoF0dXALhla2ibTMi6rqz+Uhx9/XqeWf1jCoSV1zRuQqTsfqRn/xxIL6RT1anUEoycrrS/N1/W1lmhUo3WJhOZldXHWrOaSBEiABEiABNISgIXQwMUfysDAdY3zoy9N1kJqIbRoWQgZQQizdIo+b7d3+OXJ3X7Z0ypyWl25YioKhfRZOK9Puuomv3zjIVjQVsmlsTXpvYPZw/zW8zyiz8LXbkekoy0sX3u4TZaCVfKrOwv6HNZnc5U+1fBSQ5/Pa9aUZNqv0FW1tdVSr1ZDl0YW5ZPJVVnTF1FRNUFq0Rc3bR2NsqU7rBM/NOvzck526/T2T39ulwyq9dDr1+fl3Tsh+Wg8JMdVIPrmQ2E5sL1eZ+7USTNmh8V/6yO579A3aT2U9szgBiRAAiRAAiRAAsUiULbC0OLcqCzPj6vrUrX25bRHpxoJ/jExhqCZJCZ8rVFxqLm9U5YXZuXK+9+T8dvvye4H/0CuXf1Erlx8X8abH5aphj1qmKNWSNBcrAwg/+hn810/bHzXD6rJWK5ljdoRba5DB7NOLqn1UEAtdAJhzHaCreMJe04F12RUYxPt7KrXmAi1srASkdtTKzK9EIq7lWmGPu2YwtrIr2LL5JLGFWqslacf3CbDk0syPbes4hK28Wu9NW89LsSbGGIVYZYz7fxCLNI1VtlQWEhD+Fd1J+v3mNTIUtiv1kN9OtvZsMYmelUeOh6Qnq2tMjnwnixOX5FIEAIPJKZ43S1xCFVB9vEFfrK+4JC1KoKtzE3LYmAivp7/kgAJkAAJkIADAbiODV76Bw3Y/KoEVxZlm8YSGpwOyg9OLstHdzTws7446VILoc/dXy0ttT759a01WQyKWs2KHOutUretNfloSuT2il9OT/jk3FSVdOpz6x/PqbWRWgPd31MnvWtVKvDoCxe1zl1Uy9wf34jInt412dbdIp2dOuPYYkhqNE4frIpgkevT/kRVFSyG9PmuZsFLyyGZmFWrXX1Z49P+xhP9bbKzXuTnowtyfE+b7NIZSV9TS6FXLs3LS482yo7tLdIwtKzxjyKyoNZM7wytyZAe48X+iHz+YIO0NcT0mXtapm+rwKRCVlvXYQdC/IkESIAESIAESIAEikOgbIWhaFjf3ulbxWpY3RilAsIHhIv1JdZDtLDEEazXj/6aenWd6tKp2MdkavBDGbh9XWakV4Zbn5MFjSWkkXKs7dAptJKVgX6CNQ9EofX88FuNdiDnVegJqyDT2aDT2cJyRzufQbUAUot0qda3kIfa1Uxd4x4ghbSDelunxB1ZWZMejY/Q1apWTA01MrqovUed6h3WPdbB9Titaqq+vVM7q+oahgCZCK69f2ebTOh6yDxb2xus48I+CIITjmCVTQGg/nDrskQc/ABE68qOxQdvR7U+wZhfLk/3ycxKs0wF3tL4CyvS074kYRWF1hAMW3e10voHKwusMN8TPqMdauu0I788KatLsxqIusPalf+QAAmQAAmQQDIBuI6d//DvZODmSWmvD8rOloi8c21V/v7jkAzMxXRWT1jiVsmT2/3yhf1+6VQLob6ONfnVgApBGhdoel5dvXZUycfTVTJ4u1pm1VU6sFojOzs1zl9tVJp0gofPH6qViD5b/Sr67NtaL13Ny/LPN4Lyn0/PyxGdS2JSA0f36QuafrX2mRlblprZJbnfH5G5kF9nHa3SGERhGQmEZFlfwKxW18gT9zXLU/2tosZA0rqtXR5SsyW1MZLPPdQtD+/tkLN3luT181MaBzAkMX2501atfQN9cTOrbnDfO+eTs/oS6DuPidynj8fZ8Q815uEn4tfYQ7sOfIPWQ8knCL+TAAmQAAmQAAkUlUDZCkMri5M6/fqkxhiKW8NEwlF94xhS1y2dDayxTurUysZKEEY0QSyxlvoPpmKva+yQMbXsmYzUyUT3cVmq26bbIGBzfDvdwxJbrH10nRVDZz0DbAKXsBV9+3h9LowZbKVO30i2qvU5PquxkDVb2ICKQDPagexVfWeLWhOtqqAysqoCkR5nfDUq7w4tWlZCc0G17kHAIlj86BtSiDKzGmR6RK2I6nX1lMYY6m6uVfGpWqehR4e5Vuvt1zegOBrKqQxUkELacB+DC5i1Jm73ozXT3yAiIYGZftZyRKMqTC11qPvbIVlZfFsWW4dle49aYWkn2No2QQSyGOp3MI7qm9U1XSKwZ7UG4YY7W2Njlbrq3dQO9jXZ3v+4dST+QwIkQAIkQAKJBGIrl2V68B8lvPCx3N8blSV9OfLjsyvy6tWIDAbW5MFtNfLVw9Wyrd4n79yKyltXo/LZA355erdPdqqocuGOT67M+eV4Z7Uc2RKTExpfqFpNdtvb62X/tir5i4NLclMtj967HJIPpkXm1aLWX7UiAV2u6MQOp3XCiLNqaYQA0/pqR350SY+PFzv6TAtF6yW83hEYmg3JP5+flUeqV+Uv99XI0cPtsqhuYy+fnZW+7W36XPfJT09PyLw+9Ou1y/HGtYDc0EkeorDg1d5VWJ/Lf/xcn+zva5L/9NtxeW9kWWKnVuXbBzDNvV/m1X37zsTbMjevHQMGpk48RfiZBEiABEiABEigyATKUhiCKLQ0N6w9uqBO765uW9OLOsNIrTR37FBXsQ5ZnFU3s8Vpae1s1hm1VFlRhQP6hhGHQqsrMnRnVsaq9slI7+9IxN+gm0As0bS+YVxAMfuYDOKbIMObgajcCITVVFx3WN94qwojsyG12EGnUg+mdkAyo/9oP1GGViDF6AxjMEdXFzD8NhWMiyvI1acC15qKOT6oSirYhFQcgjCEaeyDwYjOTLYmLRqMes+2Zi2pdmCxD1zK8J9+qVJrJDiQWZ/jn+LWU/pbKBTWgNYa30hZxItq7R23MNIVa3q8lWiTnA08o+U7qXGMBqRPYyfATQ8JW1tJP6yoa9uCzhBTW98uDS2dKsbNqoXQvFoIqSWTqkSrC2MyM3JJtmzfL3UNbWZPLkmABEiABEhAgy9fVvex78utyyekLrYo16eCaiUUlI9HYtKulrR//HCNPKWWQBfuxOTnKvjM6jNxr04zH70clf4uvzzar3H69Dn662G/WvjUyLN7Ie1oEOrRNXn55IL8kz5vR6LqArZWbU1nD3e07vqYdKkLV7cGkd6uU4oe0fy2tSKen1/GdVazcQ3qFwmrpe/Cmn73yfiKunGv+vRdjbqqTYTkvD51m/QozTeHZVmfos8f6pRvP94usfklOaMvmO7oyx08Y28EtWz6HETMP0wscXRXixzf1yb7dNazf/1Qq7zsi8oHoyH5d7N+eVjnfPjTYyp0da3JwORJOXcSJwdnLeMlQgIkQAIkQAIkUBoCZSkMLQdGZGVhSN8Aqq/+dEBFkxa5/+EXpXf3gypm1Mrk0BW5ff7XsjAzK60604h/QxCBsLEsd8YXZNB/RMZbH5NoTaMllhjRCELL+v9WiyRbCkHwmVfxZ1jVnintDKqmAmVFhpajMq7ftW9pxSiwMl1vU4hAWI+EOD8QdKykO8N9TDUdy1oIx0LwaQSj1v6jNQ19DC5s2tGcV0uhkfmQNKk41FKn1kJWFrqjpdrgH1gIISPtoCJffNNOLcSiRn2VubKyqlP+anhO/a2lUWdz0zzjv+sWVl6YArhJLiw+IbGqerUCGpcdWzXPmM5KptnjCMsI7uDvlYNPvyDdOw6pW16dWgiNy+1z/10CY2ekvkWnq68Oy9LsVVmYuil1Ox/WvZhIgARIgARIQJ9O66LQjUsqCkUX5cPbK/JDFYUG1S3soFqq/sEDNdKrljddamV7QC1/3p/2ybUFv1r3inTUr8nyrAo2N2EpFNOp4KvUZatKLi9F5MOhqFyYVyve/5+99wCM87iuRs9i0RvRQRAAAbD3XkUVqliyZBWry7ZcFLfYURy/yOUlzvPLb//Osx0nf2LHLY7jFlvVVbJ6LxQp9l5AAkSvRO/Y8s6ZxYAflrvAAgSLJAy5+Nr0r8ydM+feS5qOxqrcJD/uKPbjerJ8CtNjIOcI0Rw0ozjGaqwX21aLLn4fF2c4FsIdzzFToya9lNFTw6DHa1S4a9rpvaxmEDvrvNhP+0WVfQJ9gGcPtGCgbxALowfQ1dCBowOx6OPY6hPzl+ldHMPXFSTjc5dnozjRj5++XEdX9n24fm4MlmQADx/1YEs9QST6MP34ihgUZbumwKGpF2SqB6Z6YKoHpnpgqgemeuCC9sDbDhjq6aghY6WUq3sd6O5sowpWJuYuvQolSy4lQ4U+ahli45Mp/Lm4Kvky2SzttCmUYNgz3W0tqCWFvCpmORpSltMGAKVPY3SHkqKkPQOQcMt9c2iO/aDWF+EV2tAhwNRMAKi8k4AUwaEU6nkJpOki6qMftdlMoHxo0uvAZhm4cvqvzhsQiDtS6VIKw/hRCqFHBuSxUA+vkfNe19GPNjJ2CqbRoCZ/MlAdI9bQUGVdtB0kz2YSfGPovaWNIFgzbSakUrUukV7MhCZV1DWjp6ePNowSyArKQEoCrWiqOPOT3aFEHG5fxZXSA2QaHUdhNu0zsN19soEUMwPFS2+kN5XL2dcpTETPadnFSM2il7ODz6H+xIusexcGe6vReeoYpuXMQUxcIJ6JPPVnqgememDSe6CyshIPP/ywAXvvvpu2SgoKJr2MqQyneuBseyAUKPQ/u/pR1cG1EDJ3+qji1Ud965cIBsV0uPDBpS7czLGt5SAXXvqj0cehRMyfZ04AR2nQuZWMnANlNB7NsSuOnsNmZ7roIt6FG+bHooS627Fk4GKgF7WkBDXQbT1xINS2uNFIFbTG9mj+qN89NELn0lNZdhrHOo6hudzmpHkxg/ktyInC4umJuJfxunoG8WbFAJ464TVGrp88QXtCHLU93jhyiQgqsa5mIYljssb2TXNSsCo3Fsfp+WyA7Nu4xBh0UE7oI2iUT9tJLtr429bIRDSU/fHl0QSHMAUOne1DNpV+qgememCqB6Z64IweqKltRG1dE1WgczAjj4PNGEHxd+w4aNLYqPn5OVizenFE6W2aqS1g+762ZugeXOT9+LYChqS21NlyAv1d9TQe3YK2FhqsXHApQaFNw6CQHsLY+CTMmLPKqHTVHHuVtnPayIDx07PIAKr9s1CXsILICVcIhaAwaKPVwqH/5thc4B+SdHCS9HLZ/HG7ZViaq5b8pdKuzhwaFcrmqqWXlB+aGsJJwyIKoEOBnG0u9kjrkaeD2ZdNIYPskCXEikity0RiGYKjVBmxfORuXquYA0Sp+gZ6UH2qF3lpcSjJTqK9I65iUkgWmCSTS/XNnThe3YKOjl709g0gnyp1mamJBHiiMbtoOprIsurv60dffy+Safw6PparnVRXEzgl6bbPF4cj7UsQ72tElKcVmdNcaGnuowe3K0aAQmqJ7DWlZhVh9upbMdBPewlHnkKUu5PA0BGq+y1GWu4SRZsKEfaAJvnV1dWYOXPm1AQ/wj57t0azgNBvfvMblJaW4stf/jLy8vLerd0x1e6LuAecoFBbewd2kin0DO0JCRTK4jgqr2MlHGcqWoD9ZAUNdLqwgiDPlcUgm8iFR07SLh89aV5GL2S+/kE8XhmNeqqKZdHpww2zgZsXxmFmehyi6QnM19+HqpN9eG5XPF7aNw0NBIC0sKOBVQxcH81Fm60WYMyijNZMFINjMMdAxYjimOzmLzdtAEuKenHtyl6smkcGEr2KXbMgCt19ZPxU9OMX+33Yf4osIUfIp9HrNQUJ2FCUiF3VHKspHFxdQpZuZy92lveimV5P5YjiWnpGK+1yYXszpY/9XvzFUvcUOOTox6ndqR6Y6oGpHpjqgbPrgbe2H8CP/vMRvLXjAFWwOfpxvugmS3btmiX4zKfvwupVi0YU8Ic/vYgf/eRRzkMakEPyQG5uJmqGAA2ljeEix4Z1y0KmHZHR1IHpAfXnD370MKrYnz6uTtl7sGnjCvzVZ+45o/8vhm572wBDA31t9OBxjGpKFVwEbENrUzPZ3zORP3vVMHvF2aEGHOK1gd5O1JW+iJrqWtR6ClA9bQ2RIxpvHoocDNQEjk//HSQi00n7PsSUKD1SaCRQo3/ZNIpZSK8msTwnenoajU930xbCqQEJmyEyF87DeCYE8JfAvslTu0rHWmnZ0YQA0GN2ecpF2VOqXwKI+ggQ9RKoiqJQnUFD1Dn0bmaYQrzWS6G5toXqck2yu+QxoJG8plU3taO9s4eroklIiI1GelYa7Tkk0uhlD+rJqkqMiyNIlGAMSbv8bgwO0vVv56Vsmwc9vTUomLkcJWRmWabQUCWHN/HJmSha8h70djSgo2kPAbxynKp+C7EJ6UhMzR+OdyF2Xn/9dTzyyCMGcAlXfmFhIe655x5s3LgxXBQ8+OCDePTRR8NejySP4MR2ci/GhwAhGfXWz03j5vpt2rQJd911l9lOBhMkXBtUznjYJrbeb775ZnCTho/Hm+dwwqmdMXtA/f/Nb34Tv/zlL8my6DPPjBLpmZkKUz1wMfWAExSS+tjJpn48dZR2eTphbAZdXhSD1flRmMVFzC5WvKWOqtMeN35/nOMsScDXzScjiGpkJ5oG8DPa4amj/aA4jr8fmgXctiTBAEr1DQPYu6cLu8viCAZlEAyKpZ2+GP5iCfNQzJG6GFlJZgzWOKx9M+YGoCCzCMPxVXaBjCMHjcNUM+s85cXJU4N4bi9t7kV5sbSoB9cs78aqBQSk5ifgihLg1bJe/IwA0QGykRQK02Jw19JUlNAz2vd3tuMIPZ8V0WPnvmYfyvsSWB+QSeTG5oVRWMXFrfZ9PrzVxDpeBOCQJhGP//llrhJTd2+UsG7NYtx04+YRK8djpb315itx4/uuGCXXMy9ppfWPj7+MnbsOcdW1AXW1XPEeWm3Nmx5Y9d7OCc+G9cvwqU/ccWYGZ3HGWfZo2eTPyIati61bJCvyY/XXaGXaa8F9GmmeE62zLddZjvK65aYrI57gONPa/EJtx1PHSO9VqHKc55xtGauezrjOPMLta4L4+J9fDXk5OK+xyg6ZiePkePILjuvIxuyOVhdn2tHiBec52nGob8to8d/O1/TcWlZObZ3YJIHvrvrVflPWrV0S8bsV3Be6J9/9/q9JBBjAd771AIc0H35IkEjf0+deeBMVlbX4m/s/ZL7L9h169LFnkJ6eauKvI3gkMKiyqh7f+8GDeOLPr5gilHbligUTrldwPd+px3rn//17v8aSxXNMfwpss/3/wkvbMH16Fhdzs0eMoxdDX7wtgCGfp5+AQy1BoZPo6axF26kGxCRkkym0Gem5RWH7MSYukYyiS7Bv7ys42UEXs2mbKWGm0g6ObPsYjhBFQwEy5n9AZtTBUDDyIynhM2g7J5as8zrjUp7qUwSBchOiEMdrJh9GJIEIGWQPpRBA6pKrE0c+Nr/TWwmg9ojlEe0J/OOKJe+InwCTVSKjBGsiBtzNRyGRdY+LijYveArp8wJ5Ynmu3wi0LJV18QtAUvs4SZTxzAECQ3FUB/Pwo1BR12pYRWIZZaQmITdzGhlIg2hsaUdxXg7BoiQCQT1k/3jgjUvG0c6ViEn1YmbSDNoVmmcrHXIr1bHckrXmPvV2tOJUzQ56T4vnuSsuKDg0ffp0XH/99Th58iQeeughbN26dbj+YuYIELn00kuJjNMa6Chh1apVSE1NhSblznzGk4cze4E03/72t5GTk4P77rsPGzZsMCwh5b9lyxZTxhNPPIFjx47hK1/5igGunOknsq82tLW1jai/8jly5AgF7vyIy1DcG2+8EcnJyaauqq+ALQXbH+973/suCINF/ScbWpMBpJkGXYR/1P+f/exn0dzcPCpYeRFWfapK76IeCAaFAjaFBgwotHhGNEGfaBym17B/2eXDfauors3xKkqsHo5dezui8FKDC+/N9VCw9WFfVzRVpIGb5gLvXxyH2Rk0HN0wiJ+97Mazu9MMGOTxCwwiQyiKhooE/nDc87tjOB5yq4UXfhfECdJ/M8ZqkFcw47GucAw2oJC2tNenn4/OH3ykBHOc3HI8ATvKUhFDkGjV7B585NoeXL8oEZcW+fDKiV788pAfO2t68bU/VeKqDD8KMxNRn+AmM8iHnpgYDLIdq+iN7IPzqaKW7sdrZEf1sQyJDG81sX5B4FDF0elInZaL1LTRx6ZAI87+b05OBr/pSTh0eBtqOWkJFfLzc5GelmJWlJ0AyOAgnXF0djPtiRFpFV/x+vq1uhZ5sCutZeXVHCMzkcvfJVxlLWB+e/YewW8eespkpnKXLR1dNom81NMxtbLb09N7RntOxwjsaeIkI+YKzhX1m2/aPKraRSR9HSgh/N/ly0a2O9w9UA72PmgC+NLL20LWORSDILh0pX/sd8/hsd8+S3OYAQaC7k0w8yA4nT2OpI6Ke/RoOeob+HFgUL9qhV0sh1ATZd2r0tIKPM8J69mEmYV5WLE8MOEd6/6oTh4u0kYysdME/ZFHn8Ebb+45o3q6L6kpNG3PhVwbRusjG2e0rermvCejtUVxKyrq8Ln7PxjyHo6WVoCsrXdFRS2fq+1kRtSPVrUxr2UQlBCz4p0cLAjzhz++QHCmzrBIfFwQns7vpOZvzvczloOevnuRvJvOPrOgUFlZDT77l3fj6ivXm8uNTS2oo0qZ1MqO8B0rO1ljzv/298/ju//xa/MtvZ9MlssuXW3YQbq4iGPC3/7Nh008gUO65yd5v5WHcwwwEab+mB6w77xAtttvvQaLCQ4tXDALzv4vK6s6Yxy9GLrP/Y8MF0NFwtXB09+F7vYqo0LW2VKG/u5mtDS2IG36CixcdwMBm8RwSc35gwfewu7SZhzomQt3Zj6iqTol1+oGEFIMASjamN/QWR5YeTGGsloqgaBE7fBkGuXNuSlRhjFEMz4GiFFcATLyRtJBTbIuAjGBc4F8ztxXAhXOwK3fRBhGiobP2zpKTo0n+LMgOxHLZiQjnypk+enxyKGdIRmjVtDHRMJtJZlCJ+o6jOFMnffxfP+Ah/aEUgn8pKG9u4/MIaqYUUjrpA2int5+2kbyoLOL+1QvS4iNob2GWLR1dqCp5RTd7RJIo9pdkrsdyRy8snILlW3IIOFIBqm76RWuu62ScZj3QIcx8BmXmEF7Q6kh053rk9OmTUNxcTGWL1/OD9ogdu/ejdZWuhvm5PqLX/wi7r//fsyZM4coeTqfDd7nMEHXS0pKRuSTkpIyrjxs1mIxfe973zMMjwceeAC33XabqY/yE5C1YsUKc3z8+HFT18svv9yUa9NPdKs2LF26FHfccQeys7Oxb98+k7/6o7u7G7NmzYKYT2MF9VNGRobJa9GiRSgrK8PevXsNuPX1r38dH/nIRwzQdj4ZLOrTz33uc/iHf/gHHDhwAEVFRRG1Zay2XozX1f+ZmZkG5NuzZw/VRjtw5ZVX4oorrrgYqztVp3dhD1Sd3INDO3+B1vpdSPB3Y1tZD/5n1wDVx/yYk0VD03OiCahEIS/Fj0SOsbNogHl+mgvTNb4mRaHQP4hpHLteanDjOTJqNhW48A9XxOFGsoQy3AN48jU//vnRVLx6aBpO9aag35UCT3QK/LQd6Oc45ItNgIfOJXzR3KfKs5+q1H6OUdPJ6PnAlbPwv++/EV/+xA1YvZjM49x0AxzVnOo2cfxuLr4IUOJPwJLfzYFfeUTFUQ2MqtfeGKpzx9J+kZ+T1wGybYHLFsUif1oMUl1caOmTrSQqp3E8vX1BAlanUdWczKHcadFYk+pHV68XSWxjUzsFbBq4Xk9HDyluP3bIBhJBpLmZBLY5XNbWHKdqfDpyZiw7L09QCsd4TfDvvuM6jg/pOHy4DO3tXWaipsmawI6v/eNf4Zabr0JhQa6ZsNuKaYX7ck4mZs0q4OJJHaprGrCGeX3pgfvwWaosLF40O+Al1iYYZSuh+qc/+x127j6EFcvmmzz+6jN349prN5lJ0gquVjdSDjx46Lip26ZLVhrW0ChZjvtSMhnVq1YsDNkXeXlZ+OLffgzf+fYXcMP1l2FWSQFms90Cv8rouU6TJk2Sjx+v5AJFABgLroDt60tZ91NcmDtypHy4n9Vvn/rkHfjA3deb1XwxrVayLvPmFHGBz2v6VvejaOYMsxqtvBRC3QPF008Twy9/4S/wqY/fjo//xW1YTjBN9dSvl3Kgtg0NLZhZOH3Uyd6hQyfw5FOvoZwTSuUrcESAilbFbT2C2+o8Hq2OC+aXmEnsZz51J+65671YumTucB01gd7G50KT2uA6tnd04Y0tu3Hg4HHzzKnvvvB/fRQP8LeSQI/ACj2Pti80yf7xD76K991wOebOnslxtNNc72A+KnP9uqWmLXoXQt0f2+5OsvCLi2ZA9R4tbCEg9NQzr6OFDmBsHbS178eH773JtEkgjcJofRTJs6F7snH98uF3YrRnTXHVP9H8Pi5cOOuMexgqrerwv/7fz5r3Ws+g6r3/QCle5z1QX+o78cDnP4JPf/JOcw8EJIjZZ9tu0//j//OZM+6BQOcli+dS/s0ZrUsnfs3TA38jF4dbDsCVXABXDgGTpPOn1aBv2ze//VM88tjTHDua8d7rLsXnP3evYTz+JfvrQ/fcMOL91Humd3P3niPGidAM2giK5D17lMDtwwQj580twg3vvYxzoMB9WjB/lvlGa844f14xrr1mI9/7U4z7NE6cqMIdt78Hd9/53mFQSB2tOXN6+jQuGiSYb7uOb3v/NeY9kcbMVDizB9T/j/BXSOD38stWD7/fzv6/5uqNuObqDSPG0TNzOv9nAqjCeSzXM9hrAIxoCm1jhcG+DnS1VPBXRoPTx2lIupFexbrp/WoG8oqXhVVrsvnWlu3E8YPb6C0sDe60mXCTYWNAIT7I9lnWVo+1c6v05lHnnzh5ECO9J5b2hVK4z7UhJHBLnOY0+MPYip/O3pyV6DL2A1rpxp44jQkmL+7ZY7MzfGCyD6xmmgtCyjU4cKs4XD2NYnnTqTI2m65akglQaXXER5aRV7+hfQFTMjgtjyp9XH50aQWLL75UzAYZp66lGykFVPfKyyQYNMBfHwXTeMyckWUMWJeeFGuojXYVXJhDwUCofUtbK0qrKnk+Hs1tHlblacTTiHXxPKrjhQkp6QXIotpZx6lSDPa3oa+rkSpl203sSJhDnsFuepyrJ2vKg4SUPJqCOnswyaplqRLx8fEGjNF+cXExFixYwH4ICFU6N1oIlY/Ah/HkofwFYPzTP/0Thcbj+NKXvoRrrrmG2o2ceAwFlZNAtb7rrrvOnPnWt76Fqqoqe/mstjZv5S8W1bZt2wx7SOprzz//vOkTAUMFBWMbMLZ5LVy4EJs3bzbtUjvEqoq0T8+qMUGJBfoJ4BKL5qmnnjLAWqRtCcrqbXGo/o8hC0HbqTDVAxdbD3i69qG/fQ8ykzw4XuvFM0cHjPcxPycRZdQZ+wHVrxroxOEDyzjmUCuovMWFerqOv6qELKF44Pmj0XiszIUexv8g7e/cuSQOhfGD2L67F//zYjJ2lycToIkn4MPIBH8MM4gAjpeMWg70HK808gZG37zUXrxvWTvesyoX+YXzyR6twI5nv4O+FZtxybJLcPnyNdiyLRb/1rALuyrpsSx5eiAp8zD2iQgUeamWJhaRPJpFeQc5Ie7HrqoY7K1Mxs4TnfjoVe1YQxWzNXSr9lr5AH6824ctNf0oa+rDenpRu2VuHPpofPqZEx4U5kQjkXaN6rqBZKrFrc/10m7iINq7Yskconp46SDume9GXhYdXlQ/g+r0GSiYfeU5v8Wa4CXSa6l+KVwljuKxM8wmAKJVT9moCA6yPaGfAAipKuhXxMnIPE4+pk0bnxMKTaTFrpB8c8klK7D5irUjJioL5pWMWMEOrstkHI/WF27KV5qcZWelU1aaBtVHk16BE9/9/m9M2zUZlrqAJt1WXcNZL5v/ooWzcdmmVdjF/tIKvIL6cQH7bd3apcNJArKej8S1QWjS8eP/fHRI/jvNrrD3QEDFzJl5ph42A40VKSmJXNCZZk69hxNC5+q16vvyq9tDMnJsHtpu3bbP2CsJPqeJv1TKxgq2js7nxKbRc5WUmDD8vKiOiu/sU9VRoIGTqSN2mwAjnb/j9mtxx23vQQzZ9Mpv2rTkEc+OylIZznu3ceNyo/IhNoTUbRSc92dWcWjg4GRFjWF8mARh/ogdsnX7fgM8BUdR2/QcpRCEdIbR+kjXwj0b5ayPVFesyo/N09mWu++8zvSV3k8bdO8fekT2QaMI9tw9Ahh0prX9oDqk8Z0O9V5L/egu3gOBtcpP90DfE2ew6Z33IJrsTt1D+5w7479T9sWC/N73H8TxE5WGdfP+W67C5//6XpTw+bJ9ZduqZ1/fPvuui93zz//6C1QR4Ay+RzaN3eqZk5qY7qv6X/fQhnh6qda7JwaeJrHxcbH4/g+pScH3WiGW3wndn+CgPAT8CyzVO5JEB0bKeyqc2QMC/97cttf0f/BVZ//HcuEoVF8Hpznfx2fe/XNcg/b6YwQKDiApLQ8JpEgnpGTzNxIZ9tCTSHebPFudNCpkfd21VG1q4cDrIdhA+ytkCcUnjQ4YNFTswc5tL2F3fTIaUISkhDi+eG6+BwFBUaCL2Rf4MnQqXNMF+6ijUqINCX04vs6bf0rPfGO4zaeQ10fDkv09fnBR0BECaQ2zh/EE2CgY7IdgjosIrIAcP88HruhYMaQa5kJzr4eroh5Mi4ujgMpr5j/TsVzTJB6LHZRIBlFyYiwZQHQtz3oYWjzzaemiQU7aGRLzSF7GlIjRjRqZ+PmaXMq4dV0zjVZ3dRrDm2KQ9NOQZzsNZNY2ecmcakd66vPIJmsoifcuVIjiqmpmwVK01B5CS80WeInOiz3kGSDzq/WkMUadOK3AgD4CfhQEFno9vby3BAIZp73pOJlh3VRB24Tc4vAgVKjyxzpnjTpXVFSYNo/GEBotL5uP+m28eZw4cYI06aMGfJk7d+4IUMhZpkAWgS4CnwTcTHZQ/hIWbRgYGMALL7yAyy67LGKVMqV1AhTql0gYR7bMydw6QSC1RSp6U8aYJ7OHp/Ka6oHIekAqZG1N+xBD1uiJun789LUO7K7jggYFSRcFTA/VugZ9UfgjgZ9EOoa4YwkBIBqF/nU5AZhSF3KjCCb1ugkyu/C5FTQ6XRLDVc1+/NOj8bT3k4peD8dBsne4OkRgiHaEBAiJ2WMEVQ6GjrCqoBWf3HgC64tPISljEeIzilEwYz1WruXkMSEPKRzLXEx31RWb4B3sw7//+iXsreX4SbDpdGCeHKOlfkYJhGWTecwyfV7aK/TEEyCKx8FfJWNVcQc+8p4eXDmfhrCjB/GDHYPY3xhFhq4P6TH9TAuqlQGrSyiQU57JSfBhRbYfb1QC25oTkEObSsW0TfRUVTQZQz68r9hLNboalB/5M+uTiYKi88McOt3u03uadBcUTB9zMiBB1wq7AlCck5LTuYXfCxaqm5pa0dTcesZkdS7ZMxZQCZ/b5FyRzY8ZZETJRkRwUPvcfBYUBGDNYD/ZybkmZprQ/eu//8pcD2VjSenVX8EgXGBcPS2i26Ga0m9I0M4UMPSnkPdJK9WjBZUpdZFtBC3++KeXTFTVV+yEcCoi9t5IvchPudUCWQJItmzda1S9IlUtcT4n4eqpOHPJeHCCXKpjsAqGsc1IYE7t1iRbk69Igr13AvbCPUuKU0hGlNolOd3ZboEYVbS/Eq6/VAddr2Sfrl65yKjeOQEZPSsCuMKFcH0U7tkYrR0qQ20REKB8g0Mf7dC88soOrKXXqVAAn7MfQtW7hoCFgB2BcgKFQpURXKaO7T2wz2Iz3/d3YtC7I3XCY6UnjW0ZgTsCMQWahQJY1H8C3z78wZvMdRkw1nP2mwf/bDyLfeZTd4XtJj1zob5VNkHwcyWwWe/VWMHWaax47/brWqQerT+D+/9i668zvw7nsIa9nY2c9JeSAXQCPR0VVFEi4hjNVSmu+MXQno2AkEGqjsnDlnewh4BBOyfEojH38RxFKoIZ8iaSkJSBxJSMUWt64HgN3jiZgNKeGcjIiqOKEyfwYvwIgDH/TwMqPAwALGarbC04M/K8zloQxu7rWOCMstUvnvuZsS6kkjHUH0B2An/ZtpE5GxzI/AkAVGIYyf6BTyQhA+r4yVISe0imEXrJAipt7TcMptwkCsDMT4MUbVeb+JKHffJkxsgSMCR8K1IAGGLe7L56soZUQj9XLSUId4v2XNPMczSf0E9BWMI6y2kjPdZP7y7M0ABYoi57eP6PexKQlulF0eEDWLshvNCRnJ6PlMwigkNvcRClbQYXPaB1NxhwqLezDnFJWXTdS6YSVcuiKMxrdddFGxBeT58Bjzqay9HR2o2YxPxJB4Y0oOp3tqG4uNgANnV1dePOqry8nDrdFQZQqq2tHTV9SUkJ/u7v/s7QfEeNeBYXBeZotVM2gsRi+sY3vmH66M477xx3rqqvgKwLEVT2hz70IcyYMcOAU9dee+2k3OsL0ZapMqd64O3aA+1N+1F55Ne0MbeTKmR92HqsGzurOYboO69vL7diDelHjioeLgMSuKB8G93TJ8ZwnNnrxa5WNwppi+fTa2JwSUEUdh3y4OfPJmNHeSpdw5NtHBtgCknVSyCNVMQCg7Oj1ziOckQ0gNDCzHrU1HFMq9+DvN44zFg4E3HZxQRb0plMI6BYGjGk1s9Fcf4h7KmqhiuGwJAyOCMwY469smPkIzspSlsCRAN0W7/lRBz66cnzPk+HUS3LS4zCf2ylh7STwKNkAbHW6KEhQXk9m5EVhSW9Pvz3ARdeoFpaBj2s3TSHTKQeL351LBZPlEdRNc2FNVQza+nai5bq58+rvaFgMGQiIM8ZXRfBCYEOWWTi2KCV7FBsFE0oJWAHAyo23WRutfgTSTmqj3NyromcwIPS4xV4jWyiVVxtjxQ4Ga3+srVz841XhgVA1DeR1jeGKkTOMBpjQ0wu3Y+bb9xsVNosoKQ0W7bswSUblocEFZz5j3c/FMgVro6yeSMbROMNYz1Ltj/Xk8Eledi2W+WEez5tHXRdHqHEpIminOUMk/1OqZ6yRyO1u9EAJ9VBbBV5nHr8cRmbDzDVBPA99tvnjB2vUDajbD+EqrfsTQn8kgqb3oPxBqnkFRGAeycCQwKFZATasiD1TM+bW3wGUyxUnwnkvOLytdi+86B57gTgPfzI0wb4DQU0Kw8LlIbKL/ic2EUC9BQsEy84ztTxu6sHxv/2nkX/+Lx9FN4GaGB5gAAQ7df0E9hw040rhTsXhSWBHV6vmC4ER7S2JjRDKlXGUrPQEspjFCzjEpIIKoVfEag+vgMHyk5hSxVty8xMZFwKfkJtCNpIzlNORtGLBxRVzXnHBRPBxAsUGUigwh310KEN/Vw58VIwTVD+3G8iKNTBLQ9NMBt7wDNiDRlgxxTNNOaYBzpJNpCJqrKUcOhH8g8NYHM73GgAAEAASURBVAYMSSvTQHbKYCje0MmMlDhkpMTTftAAhWXmxYRxZAllJiUaUGmABjT9FGDlxr6FHslkY4idzqIFvAUyZs1Zl0DBAZBK+0AnKVBvHu7E0uL9KMjNQF7JSnM++E9PRyNVyAg4GQCG9VBnMn+xhrxkB/XSgLjAQK24SuUtSveeq6dePh8Ch3q7etHe4kFLfTWNjbeMCQIGl38+ji3ANBGGjEAY8+Fmv2t/tKByxBo6l0H2iwQC/c///I8xZHz48GH8/Oc/N4ym0by0OetkGVQSoCcDeHPmHem+ypVanuzsqB5O9bxI85iKN9UDUz0w8R7oaKvH/t1/RmvNW8hL9ZAt5MEeqpF5OGDdsTgGi/PceKPCj32nXGTyEszhO9vGRYE/1XPBJ4HsmE4vDvZEY2ZBLD67Nhbrsn3Yvs+Dnz2Xit0VqfC4E2k/SHaD4ocYQmcCQhqz5HxBKmBSJ3vyUBZe2jHbDPErFkRjRmkZLm3bio1XzeYYRDVi12k1h+KifBRmJ8HT3wlXwjQzzmpxxYyGZiAL6ht+ZwxARBkmiuMqjRphZ1UUDv0sATeu6cRHruvH//ceF5bupGHq/X7UUQTKI9k5l17WKusH8dgBsoVoP2lhlh8fmT+A1VnyAkr8qtuD31fF4o/HyCpi3PlZoO2OXWhvXnbeDFFHCoYE9chZH5oxhP1qgyarX/q7/4PHn3jlDAOs76etI9kuShCyeJEEOznfsnXPMIAwWcCJJnHyYqRJvzUGGxchO+Zsu8eyhWSzR8ZU5X55Oye8TlBBgMRkB9lhaWgMGKEOl7dU7r7+v+439jEnAkoo30ieJYHHYs0J3HO2OxxbyvaZwE7Z5ZJ6j4CicxGCnw09h6OFeGofbCbgUF/fPOI5ffX1nVxYm26esfGAmLcSaFpFYEjsrokE1ff2267BGgJoY4FaE8n/QqYRoPra67uGWSTjBTAFml2yYcXw+3aCRotHA5pr6b3Rgj1jtVvfJv0UQgF+Y6Wfun5mD4yn/89MfeHPnFdgqLFyLw699WcaJB5EWkYKklLoutVPdgrdz5ogAIHBgDZGjONBAJMw5/UnljTIwb5TNEhdT8CA0lJQ0Pk9NKj71qEm2h8oIG2SKycERgyLhkIi/weEPP41+0P5232eNTkaFg/3huNzZ3jfpJVNHxqP9LhwvI9qYxQap0mXjFKp7CZ4GGdYthlqlzLWrvIOyJiBlgrbIRZmaPBiCZmzArKEBgkk0z4BI+UXsJGkTLTPyyzP1IuZaCsbQ/rpYkqcG7n0qKZfalw0k/AaPwB+MosGB71Gjay5rRsna06hld5EtHLqp90Dk7lWUUVHUl6msjxm/gerPNi2twyZ6Sm4MQQwNNjXiY7mE1SlayQbbKjBQxsxwfQDWURe2mewfczL5ryHdeqhCl4H7Rl1d3mR2FBFW0V1FyUwpDorWIAocDS+v/Ke9cYbbxijwQUFBWETn2ugRQDKkiVL8LGPfczYMpLXNtkbkoD+93//94gEHDqbfgjbcMeFSD2NqS1TgJCj46Z2p3rgPPaAt+cgTtXtQgxB/iqC+7/c1oM99T7kpEZhZroLm2a6cMUcF7hugT30zPt6Bb2NtbrQ1ufG08f8aKOb+pWz4vCXa+NRkDCAx1/145cvZaCqLRneaIFCCfDqRyBGDFdnEBjkNWMYByqGgFMHjs/dVFX3S1Zw4SjV1KI4xv3+QDW+0PsW7rhzJB3fTfUxqUNz1DNqb9pxcWyN4hio0rQ9M2gwJhDlijUqcvJ+NjgQjd9udaPmVDs+fr0PH13PBaroHvx0xwABHi9e2d6L15lmS3csFmd7cd8CL+bQS9lzR1x4tSEGM2kGZmWWj+pl0SgkkJYW76Pn0zqcPPo0mUxU6bqAKmVntn9yz+TTuKpzQqpJi7ydyUWy6Pl2UiVGg1bTZaNHssnFFCz7wVkn1X009QJn3HD7AhV+T09GMvw6EWZMcL7WNo/zvHGVHUK9yapHCHiJj48zzJRg8Gsr1clkuyQU28RZxnj2Q6nFrA1y4W2ZWmfzHET6LOn5E1hpWUOjgX6WYaX+kIqbXJKfqyCvUn/444u4/7MfiPjZ0HMq1S+pHVkVNz2j4ewNjVb3WSWFNMQdsJUzWrzRrk1GHqPlfyGuWXDQvvtijo2XVRUMNod65gQMWrBSdojE4FKoIRtoB9lGxoRIiA7Q++UEkZSP2EnhQm3N6XLEMFpD1UPn9zpUOuX5RzLT7DNm4+hbI7XFSL4XwXmY7xTVe0N5KbT5T2QbXI7yiKQspYu0/4PHuInU81ymOa/AUE7RGk74e3Bkx3MoO1pB3f5kZOdlECAaaXjNgjNmtJccJsRjKHDeBx+p2jWlLxMcqqUL9WW0d0NDkUNhx+49eHpPK16gW9miQtoUovAlAEI5OLKx0QNbm70pSxFPn7bpbBRzZehABqDTaPB5IQ1OnyA4VENhV5cG+TdQ1lBEIT8MkikFzgw3SUub5iS3RieMkQQCCRCKElLEmAJ+1Ab+uslEOtBEls9AHIpSY2kHKNAmbsxOH4EVAT/RRN6T6X1tQW4SCjOoRsd8VAV9KKRupnr7aJgvOT6GP9pmoJpYL8G6PrGHTBjKmGUnUADIz8xACo02d3R3GU9lu6viMJc2cra99Fusv/J2k8Iz0E1AqIweaA6jo+kYgaFqng+4p1V7Az0T2DPtYi8IczKB9eunDYbWU2QNIRV5c1ajcN46pOcUYVrmjKFI75yNtYUj1a1f/vKXBsiQEeqCUcChc916y7YRk0mGsQUOPfvss6bYSMGhc1lHsZnq6+uNse4L2U/nso1TeU/1wNu5B2RXqLX2BUQP1iARfXjlWP+wCllzH9XBqDWbwO/8ABdrFpVE4b1zgWsIEjW2+fHkYXoZq3WjIC+O9obiENs3iG/+NgZP75pGm31kCJElZEAhMoWkPuYczAUAefkTMGRc0ltwiMcBNTHygglya5zUwigVpOGjpy/Eki1kzjp73YWi6Rko4K/KE1jZEKPXjJ0WIOJxSIBIdYgO1E1OHPoHo7ClVOrZwCff14MPrqQ9JI61P9s5iBeaXbiS2thfXuHF3AI30ph3baMX7T1RqOmlwVx6alud0o+mDh+21sZgSfoAVmVwjO7aSZWyGedVpczZO+dj3zIH5EbZaURXEysZHpY6hsAHJ0B0Puo1njLUhkhUucaTpyYeYqaUlQe8gY0nbbi4wSonmrSKfRPK5sl2MpU0sfsrurLWRE4LR1L9cYaTZAyJNRTJRM+ZLty+2vy7P7wwwth1uIm1+vxsQyR5BLM3VGYoG0tOQMA+q2+8uftsqxgyvcqS4fOenr4xWejODNReGRS24ICd2I5lb8iZh91XXpH0n40fajsZeYTK90Kes4CqrYMMSut5GG8IBpv1zDkZerqHMiK9g++oyuynqRCFqqo6/BsNksfQRlGoIK2FPnqkVqipbTDGsX9Ew/bhQkDjIQA6iTm4amV4jQa9vwKE/kAwu79/0Hi6FIgkD4H6luh+S3XxzjuuNR7sQgFMerZ/9J+PmG9AZkaayUP5vvTyNn6D3CihgwOBmzdRvTVU+nDtCHVexsFly6msvJo2SjOH8ztKO3H19NwWS1Bcqpryahj8jRtP/3/u/g9iNBtRoep2Ps+dV2AoaVoe5q68ATkzV6D2xB4c3/Mcyo9WIjMnjW7Q5c6cKmVWUKNgFSrotNvVR6p3Pdoae2ikuJbpUhCfnEWg6BSO0z19KYGL6Pgiw2pxkdXjIoJyGiCSsBiQK1WCZa2cBo+GaqA4uj5UI5NmKL6NS9SGxjX9NEwtoZSU8qE6G/d9FvRQI3SewiT/60B/uM8DCoNi/Agp0iXhQeZ104FQH61RkmFjgSEPX+A2CtaV7QPGM1paPO3lKBajNnb0o7S+E109A8SU/FicPw2zsmjUjDnKPpDAoCgDOKkwlqIxlMdxBIiKZ7Dv2U/VjfQiRo9lfbQ3pJ/qJ5tDcbG0yUDX5plypZ6eYZLWtRxDWel+2pOh4U7WXp7EOmk7qru1nCqC7QSg9KFhOaybWhJoO3cUhvpD5xW6yA5qbmKbUouxeN3NKF60AUmpmVQBJDX/HRikunXppZcab2C9vb34r//6L7qArMSXv/zliNg556pLxLSxntCc4JBVl5tMQCZSBpDaKi9uL730EinKM40KXiTtVxqBXZGwnSLJL1QctUHgnlWjCxVn6txUD7xbeqC6fDuqy3dQbdmHN48N4NljtJfDb30u2UJFaVFo7gEO0SX7sjw/DlX68MoRN+bmyGsm8OqpGOTnROEvV7mxPG0AP30iBk/sSMegi4BQbEB9zMvxQDZ9bNDQqXFXoNAwICQAiOc0Mmoc1j83VdXMmMyEGnO0X9tIRhPlh1DBR0cIoEdUlyvZuLoHGUaGTctxMxKAyEeqrJ/1VrmDBIe2nyRI8JQLn76xD9cspBpdbTueLPWhotsFanPQHbwX/3UAyKFb03VkD7VTSE/yciGIamctfS60kJX8VDlXLVPIuqLb+8qyt+BOXoTFae8NVf13xDkxB6yqVDA4FAwQScgOFtIvhk7InxFwU28n25p02f2x6iebNH/xya+OsNWiZ6+nu9dMWMZKP9p1TapUD638P/q7Z4dX8a1Hr1CTVgtySI3MyXawRpltuzQJlTFr5TGRSZqT3SAgShPK48crDdNK9bvlpquoxnY15tDF/IUKmsxqchjMlqogkCnmjW23BQTCAVkTrX+oZ2OAoGkPdVDl5n68QWyre+663gBK1sCx8hDwMJq9ofGW826NbwFV2/5wXr/s9XBbPXfO902sIYERevf0zOkb+H9/+ePGnbyeEWs7SnafbropPGhSw+/AHx9/yXwHpk/PMu/Y6lWhwR5nXNVT3+JwQd+Z7/3gQT5Dz2LZ0nn44t/eZdg9MjEiQNp6W1P9f/Xrx83YGuxtTd8d2WaSGt77brgcn/3Lu41tJbVd7MkfEjDas/dIxN7aRqurnn3VVR67BTLZspTGWZ5lrgaPO+PpfzlOuJjDaSnrPNUyLiEFOQXzDRMkf/YKHN/7Ek7sf54fpVPIket0AhVGfBtGEijaEaAIiHS2kgQc/PTwQTtF3QNtxlZNX+c07Nt7AEfLPdhRtxyp6TRMSDYPZUCTVjkYWz4WhZGIqGu8YOIYoCZwwpQmqVOHzrIDmTkSUajje1FOwa3JG1iRtFGURyAE9rSqKQBFIVAUj3hoSrRlqEhbJreqQqAOJtnQHxda6Z1sT72HoBQDX7CsRMJT9CgmU0pzc5KQRbZQCg1gu1meRwaph4L2An1gmj1UGxrMpmHuguxpyEhOoMFvLxlEXpxq76INhGZ6JOtED0EiD93Hx3I1NIaCufKo7SpAXt1+7Hj1MeTluNHf22rsB8mOlJ9GqxVMyaf/mHOBC4E6iTvVR+ObpwgKpU1fiRWX30m7RUsRnzg+17anM3577M2ZMwcf/vCHcfLkScPMETgk9+r6WN57773YtGnTBWMPWXCoqqrKgB4CPn72s58ZkOVsWU0CUh5++GHzk/FtBYE3au8XvvCFM0AcG/9Xv/qV8eJWUlKCz33ucyaNvdNKe/fdd5v+svFVRllZ2ZhA24MPPmhsKlmAR3kK5BGYdM8995xRH1umLec3v/mNKVeAnlZRVO6bb75pQD71m0K4ttm87FZA1iOPPEIDnltMv48nrc1jajvVAxeqB6pO7kFF2U6kJQwGXNMTFKruAJblu3HvqhisyI/C1irgLb4Wg1zJaCQr5vH6WBQSmxFzNIm+Jz65Mhprc4A/v+7GkztTMBCVCFdssgGGPFLvItBig1NtTJ7IZHzaAkJuAUOMG83zBhziOGoXczQKaz+7cCaN1Id2Qa3xTQRejXUCorwEhAgJmaHYrNXwuhS+AyOc3NcHxjNbN21VH08MF2ZYFzYE2074kftaMz7xPh/uvzyFizXteLHch98d9WJ+ZhQq++kMohUcd93Y2haD+FguNDHbVVn0bkLm7Ws0Tr2qkXnQs1mMvw6ezgNUuV553uwNOdt2PvY1CZLw/C/fegDvp6qBJgBONQRNSCxApPoEC+nno45jlaE2OFlDmlxYV+hjpZVNmjWrTqtoaJIldZCWlvaxkoa9/oc/vYBnn99irpu6DDEF1I8CXf76sx/EnbfTUx+BguBgVaLEFnICR9qXWlckalXBeYY6drIbLOtBdZWhZE3UZhUXQDaVQjGaQuV3rs6FYg1VEhQSE8Kq+FlAILjPzrZO4Z6N9vbOCWcdbOBYGanfJ2pvaMIVeYcl1Htr3caraXrPzsZ+0szCXGMY3AKx9j1W3ladch6/my0tHcPfnsD5YsMEVLzgUElwaTfBFcPg4bg1d85MXHPVhuBo5ljlyd6X81scMiJPSrXxERrJFih0P78b8jrn/LZctXk9du0+bL4dYqj1cCXEaXM1GBT6/F/fi9mzC4ff/fdcs9Hk993v/8bUZzSPeuHqaM+rrg8+9CQJEQPmWxNcluKpvMamFqN2J+aqgnPcGU//O8cFk9FF9ufMEeA8VVAAUTYBoqRUgUFxKD/wLLrpDSs9c9rIGggcCRFcFNYkmMlmjf61UHe3uqkbr1dORx8p4DOTY5GeTAaSWUEM4CvKxmAtBqTRvoTEM88pkoln4g/FsWmGtjShjVMEg2r5a6H9H61airmj/BSsrBgwW6kT/AkA4gXFcRzyQDWhsGkAIqUOZKT8JABLkDXe1NgWH1XMxBzqHGCryebx80WVYDo3PY42CmKNgWniYUYAIc7AnGz9VTeWzUxVDKMEjpU/z8VRGIjhJF32h/zMP5kuFDNTk2jEWpI7bRexHLf1XsHjLm8GytoK+GKeJEDVQXCJy5um0UPtGypDrVFpAoGGg+mAACjU1DCAuORiLFx7PdXHVr9jWULDbedOKLUtuVeX6tarr75qbA5dSPaQwKH77rvPAFXf/va3DVAhVpPCRMEhgTAPPfQQVq9ejY997GPGK5vAEKmsPfHEE3TfSfe6hYXDgJiufetb3zJMob4+GiXnwyyPafLo5gw9PT1Yv369GVC++c1vGtU8G199GioI2Pnnf/5nE/fWW2/FT37yE+PJTPae/vVf/9UcC4y68sorzwCsguvV1dVl6ikgqJ8Aam5uLpqbaSyzocEUrbapHuHU8ZTfd77zHQMSrly5EldffbV5Bmy/jJY2VNumzk31wIXoAU/XPni6D9ITZz/K63pR0+5HNhkuq7hoUE2zGh3dPszi0L6NbJp93dGYzf2NuX66bqcrd1b4UwtisDHfhZ2HfHhieypqO7k4QKaQN5b2hMKAQj6Oh5R+ObyQH2R+UQSDAoCQVLmiCMoYQEiDHYMFh7Rfkp+JmVQXCxUEDhfNLKTzg4BbegFDXrJrDUBEJwqSPSR3iMEhy0Oyy6cxeHj4tpmyfK9xea+xz4sndtNOUFw7PvbeKNy1xoOGzk5sPenhQk40bp4HVLS5aJQ7Cq2UJ1wDLqxL9+DmEi/qemUnyYPt9epPejKjYe7Kpj2IrljyjmYNCVhJSUkyArnUL+T1KhRAJCHdTrgsW8Pegotpa+sYSZ3ktejuO68bnsxp/BOA89s/PI8nn3o9kizOiJOZmWbAJgGfehfUV3I7LvfkBXRtn5SUQAYbbTUEhXBsIUULVm/RuVBqVTofSbDsBgEslvGgdPv3l+LEiSosWTQnkmzOeRw9m8VFeSMm6U62lJhDb27bi2CG1WRULNyzoQny08+8MeEidC/Hsjc04czfpQkFpOhnw9kadw52CFArFiINTev9VdBzaX+2zMB59whQxnlNgIYTaFV6J4AzMq7e+Xzz7bDglPO63dc3Q6qNAlr07Q4GhRQvGFwNbos12K136K7brx0BCim96rj5irVGxUxA1US/O866it0XqixbntohRqSA8FDjju17bZ1Bc75wfeqMd7HsXzBgyHZAIlWGSpZchramcnSeOoTk1ER2oOHCMAolOslUQ4KdTaOt87SEtPLKRtS0RGN/cx7VymhsOTme+oC8OQYBCcTXgOhMqDwUbPaGoeM45uhprtsYVrDU6S7ycaqpRNbCd16vvWTU0CFQinLicMy/gT2BKAEWkVIFYBOKgzpglEDrzFmeUnmmbirDHpt4geMsuq+fmRZnBFYvlxm1KmXbZrN0RDenDEgUSM5jB3BjynKRHUS7B8mJtEEURxYRqfTKYChT7cvjS3VXCTLiGmnYuoN2GRQhEIbLHnGsVENXdB8Y+vt8tA9VgoXrb0PJoo3vClDINJx/LDNHx1ZtSyCAfmIPiU30la98xXgLs2nO5zYhIQFy9y4GiwAdsZoEXF1yySWGTRNpXSy75he/+AVuu+02PPDAA8Y2gVYGXnzxxeG2Hzt2zLS5oKDAZL1u3ToD3Cjdv/zLvxhw6q677jLpbRxFVD8mJSUZsO3GG2/E7t27DdgUrn4W2JFxbYFCX/ziF7FgwYLh9LNnz8Y3vvENwyQKBVipXtdffz327Nlj6iSgSoDW1772NcMw0gAgIV4An8Ana6tJk00n8KX6qS669wKyvv71rxtvakovAMzWQX0utcNzqRIXrq+mzk/1QCQ9ILZQ9cldVCfuxsH6Ljx3bIBetYDlBS7augN206HQYGcUNhHD6fCRHdMVjZUk6yz2e7CXBqhvXBqLW+ZHYc8x4L/pkn5P5TTaFKI9HmNPaCRTyMuB1qiODYFC8mYazZ9lCIklJFDIAkJiDAVYQ2YEM+NYVuIAbto0G2uWzw3ZvMICTvhypmFPdQvV1Plt4eDrZb0FDHkMQOQxayBmHLTgEMc2MXTlwWxEYPk+AlsufxL6Gfe1gwNYNLMf162Lp4FqH374ahdePsLvfmc08mnyyE8j3EuoLvahBT6syPCRict86cxiXlIUXjkVjV1kDc3P6MdAVxWBqz3oKLq4WUPhDBmP6KMxDiRQp01LMQCR9u0KsU0mwESqBuvXLTWGTO35C72tIbjhNOqqCb2dwI1VN03UZOA5kQt0zpCSrLEurLDpjHrG/oZ1y3D/X30AM6RuxOdSZWiiKZa+c2IYnNCqRIlV8OnPfu2MCU633Og5gibCE3Vdr/u7YF4xPkDVpkJOdq1qkyZ9/047KapnOBfdjiqcl90NdMsutpTUdhSc7S6nHSipumiiOdkTwnDPhhh2e/fxIzrBoOdqLHtDE8z6XZss2Lj7DBpbnoi6X7gO1DPnZNmEizeZ5/WcjMV4sQzD0dQolY9UMj0eOjR6az8u3bQKK1csMFW1YLS+7Xp/9C0M9Y3SNSdQNZHvjq2rCh6tLF0PBrMuxnFH9TzbcMGBITUgLXsmZi3djNKdrejt7kRMGoEhDlyjBeflno42unKPR2VfAdflYszAGW3tClEUVE7mNySzKa05q+3Qvq6bs+ZY54fS8ZiEmhHHXQRFan1utHNlT9RyM0xz1xns6mEADCLEw7JNFAFCQnn0n+f8+qN8VDftKzN7nQVzMXIIFNJ+gDkk4Vhcdx0LXIphW6kNRhUwWxcBPcyO+Zl2MLqyHmYLmWPmZ8/beKqg6mUi8zojqB/JUyKLiIATBVsFkzf/+uhNrql3OnL7WgkedRHYYSVUzlAcE1n56ViJbFCn88QgCR2p02cib9ZSxL3D1cds051bCw5p4i8bOhZIEDh04MABfOITnzDAjMAUJxjizONc7s+ZM8eAUwI6Hn300WHAQuCF3NtHEgScCNwQs2fWrFkGxLHpFi5caM4JPBEQJvUy9YWC+kY/eUsrKioyIIzAqqysLMPKsXk4t3JVL0BG+VkgxnldIJWYQKrP2rVr8dGPfnQYFFI8W95Xv/pVk0xtfuGFF3DZZZcNg2GKM2/evOE6bdiwwbCKVLau2SCQSsayxSTSz7KY7HULCil/scNk28mmV5vFHJJamtLqeZgKUz1wsfaAZQvlpLvR2u3GAJmqS+mW/t6VVH8iOLSq0Ye9VT4cKI/CMdrMiZ1Go8xVZMJ0uVE4PRaXlcTgcJkPP306HrtPpg55HyNbSMBQ1GkRJQAKSW0soDoWRUAoRj+xhChkGhUyjpkWDLKAkFll1ZjDkJXQj/tuXIHbrl3HNIRyOA5pjHQGCX/5mXHw97YhhrYLxeTViKqxWIEjI+UMsXelXkaQiOOihnDlwpqZsdZEHPojFTjDHCKwVEfm1M+ek92+Tly5gg4rWj34ry29ONDqIxjlxt8v8SMneRDxHJv3VPjxu1I3F2dcyIrxIS86wBpaTaZVYRrlD9pZbG+rO2/qZOOxkWPbr7EilEBvr4faWhs4wZ5bJLRrhViTcad9CuUh4MBpiDVUvuf7nBhlI9kCgdX8s6mHXKpLNSMhIW7c2WjBNSkxwbCwIk2se2G9CWnlPpwtJ4EjTvWSs7kfemYEiF1BV+ryjqTVefVj6fEKPPzoM0YVJ1w9Im3XZMQLnpQqTwtgeWiOQZPaYO9pk1FuuDyk1pdLW62zZxWGi2LOW1famlAHB7VJ9oZku0bsPBvULtkbkg2aqRB5D6i/cnIzhxPIgLFUsd7JIRjU0TMVLpixdsYNhqkWG0tTJUNxLRitdGI1jqZ+5wSq9M7pF2kIVvUb631VWU6m4HjLi7ReFzpe+Dt2Hmvm5opaZt5c1Kbl0atVAxLJVJHakgQwE0bKbeaUgAYrz1U29GBfXRzeqCQ1nEKjS8KkwBMGsW4U9/TPAjNCKliCrg0XEzgwx0ZgVAZDIAvzCVSHxiC5ethE45CSE00d+MdWUbmaoBOmUB3xOo8lhA7bGlK+EjhVmCrBIPEzkI9qbU7wj67rrI2jC+asOZORQGYPjVALs1GM079AfBPZ7PKPPaV6OYKOTJtN4Y5rpl72eGhrIvPP0GFdTxGK+0rR3uFFZgaBIeXliGrjDScYiiDbQnCnIXfmIqRmjPRsYTJ5l/wRGKCfgAQJbpY9JDCmo6MDP/7xj0mTzzfgw/nuEgloAm8+9rHTbuwPHz5s2DGqy1jgkIAY2eEROCQ7QLK34wwlJSUoLi42p9ReCzw645iJBesRSbB9qbih0gk0EgAnoOWqq64yqmKK5wy2zRaYEXvn5ZdfNoBVQUGAzaQ6C6yS6pnKFGNJW2fQsfJ47bXXDONKfSG7TUqncOLECcPCEotKxsid6VUHPQvBdXPmP7U/1QMXQw842UKHSBN68mg/DjaR1UKj0k8d8OD1ky7csMyNuy+Jws6maHgO+FFB5wn7++mGPdWPjy910dj0IH7yWix2nAiAQvJANhooJPUxt0v27vie6Mf3RWpjUreOdp1mQgwzh9hR2h/oacGNVy/B7detIzBjWcln9qJc1q9fuQBvHTmFg839cNNWkKQAAzQFzOcNJ6IowOHZa+zqBS6xHpQMhob04XiyOeRjPh6qolUQBPrjFi9mZPhx6ZwBvFXehxfLvGikMepoMpKOVALVNCWTkBCF3MxoJNBeYK5rEIe7/GRfsR8bfMhP9KKtZS+Z1vtRWLxiuJzJ3MknY8MpkGty7jR2Gq4sCdtOpky4eOHOi2khpsjGjcsRbIxUEwexh5z2KZRPpHULV+Zkn9fkyAmUKP+xJh2R1EG2YOaTUSOxUGXIW48AgU994o5Iko87ju53OT30CBSSPQ2xZEKFRx57xtxzq14yGfcjeHVeeV5sNm9C2VgSgKUwGlsiVB+e7Tn118zC6YbNoWfj8T+/jPX0MBfMsDKApSYMYYKesXvufi/k8twafrd9L5B3kAyPqRBZD2hRwgmMS5sjlJwbWW5vj1hOUGesGgtocbtjyQgaKT9b8FLpH3/iZbzw4rYR/ejMVx7VZDBaYbyLF/q+Se3ThkgMgzvV+cZbni3nYt9eFMCQOik5LRfZ+QvR1XqciN8gogkMefkB6qYR5D5SVQUUuTlZiqcedAKBI46Lw6FzIBnlp+Lo6pXjJV3h9tH2jlYtXRTGhuMZtCKAWOichWAoLwaC3eGxua7joWuBSwFwR2yhVpLGtXoZgJ5spKFsWIRKMWeZ0IBBuqTyeSyB0YAwiqSfjc0ElGvFzeE5pTYXh+qia/J8ZrIIgEyqFH8ZNDwt49M6lPnrQOqAEHs6Ps+a+Mqa+yrIRNT5oUtDp0w8RgucF3gVuC56kUtLpoo3lJc2PjGn+lLQ3puETAqvylfn1Vwf7RUN9ssWkgoDoingxsQFMvSyclHueN7PaWQajfwomMjn4Y81sHweihqzCAEDYo2IMeNUn5IKl9SeBKpcCHUigRNiwwi4saCVwKGf//znhsU0Wp0EaIkFJSBGbJ/4+JG0eOV9PsEPgTxlZWXmXgh4cYIxzhukOllgRu1+mcDQ5s2bh1lDkdZb+SsfBeWjnw1Si7v55ptN+4P7xcaZ2k71wMXeA9Oz3OjNdCPVH0e7d4PoHaTHUH7uK9sIIpA91NvmNnaErp3hx+XzvPjf743Hs0f9+NkhP4qyYjGb6feX+bGrjI4Povh9oAqZT0whh0t62dnTz69xi2N6VBTfXTGF+J7KppCb5wX8GDWyIUFc46UEcqedobn5MVhWFB8SFJLKrAQ+fbPEILr80vXGrt6PHtuGA7SRFCVwSHMpqliLqStPajZozBbLNmDvUEOk/gXGPBtHWx+ZQ4imbh3Zt2+VebDqSB8+fE00NsyKx56aHuwii4qkIGQlR2FRngtFiT4s8w1SHc+FN6uj0OmJon1B9S1BIcrB2WQNtTbsRnXFchQUjd/9sbNuofaDJzWKIzsqTs9LodJZYVsT43DMDoFHO+h1qqAg94w4OdnpSKGMF2yM1FmWAKIYyoTOMJ0r87mO1XldG60cZ9rJ3neqJyjvyQQJNJlSUBkvvLTNMIjMiXPwRyCd2EAyoBzKTogt0ml7w55T2u1MewuNh08kqJ3B3r+0Qn8h1DeC1QJte4LBK50XiKIwUbfkJvEE/gQm2aefjZdf2YHly+ZPICdAXgFl40oArwU4DTtiQrlNJTpXPTAWm+ZclRtpvhOtnxO8XLZk3qhe1YLrMh6PX0YuHwUkDc5bx84FE73rkToUCJXXxXpu5Mh6AWsp1pC8UUWJdi0qGOWnrrYO2i2gccai1UhIyUJN6Q40VJXTLk0KMknRS6Jx5K72VtS1R+OtyjQqkQVctUdRd7+3IxptzR7jqt5NYS4qmkIif/p4JmWkIpl5UMy0eI32+NMZu+GxQUVYD1r77+noppFMelOhXSEDDHF/KHYgjeOve1oqolNTeSbAARL/x7KBDBeI+Xo62vnrREZ/DzIGepBLA5TZ/KlCbrqFr6fb+F0nGtDkom5ldg5c8TRAQIHV29yArFPVWJQdh3p3KlyebKTEcYWVEmNXZxe6maeXeRjVL20pwPpIYfdRGDWsIv7x2fN2X9fUfINmM42azhOGIq8xzlwPHA/vy0i10vDPCVchclJ7qE5WS0CPwitnBn3dLNifguTMEoI/6ejramMfltOwUAd12gPgUVJqBhJTQhsAZc7nPOijMFH0XgwQqfmUlJRMWj0FJOj36U9/2gAG1vCzWC4yhDwaCDNplQiRkeoU7MZeYJUmDuGMKisbASip5j0IkWnQqWD7O0GXz/pQqlti+Oieh1IzCy7AAnFSbxOwJbB6MoOAMv2mwlQPvF17oKOtHpWHn0HNke3o5LjzzJF+HKLa2PIZ0bh9cQxauqPwWBnIdHHTBmA0ttKI8g35Puxv4YIGbUvfOMuFnOgB/G5/LPZV0C1ZbDztClGFy81xkGOdghYhvFyUkFt6DuA8LfWxAEtIbCEDCvE7JFBIqmECiAQIBUAhqV4HDFAvnZOFD113OdbM53jjH8TWt/YZWWDtmpXYtm0b/u3fvk8bYAVYR0P29XV13M9DZmYW1s5Lx6nuNjQMEpxiFdwcD6VibVaFAvM/1ZKglQZD7mlMHboog9QjAusmwCsqhnb7vPF462gc1i7w4tK5BIpO9OO5Ex6zuPXRVUBxshvPHAYOtVLdOpnGp/uiUTkQYDfubYnCWrKO1k33oInAUGvuynMCDEmVay3BHQEQlgnyJif73//hQ+y70C7ixVT4jx8+aMAEeZKaOfNMNrDiKA9zD3h/Pv+5e0cwXnTPZMNCoIImpaHs8gTb7hDwso7sCOfqfHA5d95xLT79yTuH3YmPuDeTeKByZXhYE2kF1S3AtgkP3oUDHsJVy5YhD1VOVpeNf7asLeXjLKNo5gwucoSfLoQC6qR+tGXrXvMMTdQouICXYIPIVq1Jz0U44NH2w2RtrVpgsIHcUOCVygwFBE7GPYmkPfa+ZRNgDWXPxj5rwW1x5q12hbI35IxzNvs1BJzsN+Vs8rnY0warw54tw8TJpFHbZ8puGcH1iyk469hAz9YNVJ8rCjEORFrnouIZuGrzupDjQKg8xrJ/FCrNeM4FL5jovdazPNFv3HjKPl9xw3/pz1cNHOXEJ6cTAEqHp78RA6SH9RHoyC25FIsu/QBlwjgUzL8MtSd24/ie51BFDwXJaalo7HLhcFUyls/Jxh1XLUIBjXtJpjTCIe3jDAfuBo4Yv6KRDKMWxGVlMC4BHl3TlpFP/3QykLqltROFpHVvmJdHEXDs8PT+SmxtbELi3NmBPAgEBVYU6d2rvQOpTfW4cnoiJ9vzkJuRjB66hB/s7yWwMkicxc8JIxlRWg2NWYH9pXXYdegk3dPXYU9dJ1aVZOOTt78XCZ4u/PjJvailB6TB3GRjwyRusAMr56XRfXx6oJJBgulw3Yd3TrfFnAqKf/oq9xghOFkHwa3te8pwtNyFjt54tLQB8RT0fb4U5Mxchfx5l2Ba1kwyveII9g2g6vArqD32FBHWdk7QJbwnGI90I8o5xweTBUAIULIgg1UxmqyqCzBwGn4WMCHVIwFRk11WpHUOBQ7JVo+CwKHxBgFrcu8uOz4KApH0wT1XQcCO+lEhEsaP2mvZPlYN7FzVzZmv7RexxnS/p8JUD1ysPeAdaMCppkokxvvRQdWwyrYeDHKQmEUbQrVUJ6sibVe2cE7RpML66X4siBvEllI/Dg3G4vrFBEXIitl9LAa7y5LIwCVbiGO8l7RyHwEfBY03Iw1NExAyNoVocHoIFAoAQg5vZPyGGFCIW2s7aMEMN+I6juCpP1fhqT91YnpmMj2YeuikIpUEpXT87sltONycjmpXFt4o282FDS+/EfXISvIgPTUZUbSlF+Xpg4usIYMF8Y/KsGxgmZ2mMhnBoUCtOTQwiL8rlbKgUZNyhsAhF1lRuyrS8OdtPnzsWg82zqF9pRrykaP9SE10UR0PeLbOjR4uaq3nuY05XmQ0e3GwLQo1PTHYWe/BrKQBpCdy3aa/jq7rGybd1lCoSa/ADuuqV2o0zlBLz7Bb3tyL4ycqjerRrbSHE2rSIqBJeVjgpPR4ZUjBOhwAIEFcnmHkucoGTR6CQajgcjrp9XaiC0HW9bgtz7m1E4PaGtnjeYmg0D7a1AsYZLag0GhsG6VXWyzTxJm3c9+Wo7r89nfPmX4WMBIKOLOsLWf60YA2Zzztq6zHWIZYPwIX9CyMFoInwIqr9oxmDFYAhmWj2LyDAQMLUKgeNq7ylUqZ5AWnu2ibRyRb25eRTOYU16pGBrukV1kCr4oIJDuDAcqCgLSJ3JNQfeQsx+7b9jifDT17wfdN+YkBpj4M1Rabn7ZqQyh7Q844kew7+8/GfzeoVKmt6n8tMug5E3igftdzMFEgwcmkkZfDAgJDTjDc9u+F3DrrqPZO9Jtr2yBPbqHeJ3v9bLZO9s9E8wnFVJ1oXhdLuosKGIomgCDX9V66ah2kp57EaTOQN2ctktNnmP5KTMlECu3R5M1agdqyvag68iK6e1rRM8hVOApPOTRavXxeFlkK0+h2M7xxvg0rZuPpNw9jS0UAHBpCb4buSQANEllIi4BdXJ2so7pUb1UdCmK9WL1sFvJy05k/KelDZQzQJV9Lawsq+MLXNbSio6YG/YN0/ZmbA3cqmUnMSwanezkZvjzBg4/cuAwF2anwDPTh5MkKPPvGIRwqb0Bjey/bEY2FBH/mTp+G1YuKsHFpES5bNQeDZO0MkqUTQ0ZOYlwMDh4shdtDhtSg21Depbbl5eS3pqYePtL5VzBtMVFaW8dwD5zAqA66ze3t7TETZwm7bq3Ychtt6NoyCEajhcnJZ6jeNNIld/nJarzVUYNyP20dcUV33uwSzF97BzJnzEFiahZVAE+rifm8m9DRXIb2hq3Mn2Vo5dWib+EqOMnnnaDA2Uz4lVaCiWzGKM/JDnPmzMHmzZuN5yoBBIby6FBFmuzyIsnPgkNWBU/1suBQJGwmC3oIENJzJkPSUpW72MP56HvbN7LJJLf3MtatcqfCVA9ctD0w2Ijk2BZ4emgU+XgP9td5sSw/2nwXX6xzYQENT39+eRQOcv7+WoOL40EckgigZFEN6pJiN45VR+MXz9GTaDXpQ6SRykCz09i03NGLKeTnT3YD5X3MqI9R2A4whcgO4n4+x9KlJRmo4wROapn5Mygs+3qQk5GIHYfqyWIlQ6lgBc/10h6fl4sZJwgIpdCTZyGee+MgbfTMwsr+DKZN4CQ4Cx2napFEnKqqrg3JHPfmLM9B+6k6I5uU17SilQtFCYlxqO3wo6EnMFZacEiq2nJfL1augCl5KjMIl+MmSqXMRVln0JuAN4/EY9W8AQJDcdh6gp4fS704QBtCs9Oj8OHFfqye4SVQBY7NflzNheFtDVH4fS0BNbKG1he6sS4jGu2ttefMCHUoxoYFh94gwOMMPn6vZH9ELsc1Yd90ycqQk5bs7AxkZ6WbyZHSh5s86LwAAAECxQR+8vJyTHFSZyuj3Zt+yl2aHN1y01W4i2ygYBAquJzRGBLOdjj3//CnF2mr5VWUllYMA1m6rpX/r3z1e/j6N35MonXAyLQmQLJ3IRbP5svX4JabyfIleJZIg8+a2AQHTZhl2PkPf3yBjh0qR1zW5P0vPvnVEelsOVrkUNvVP4EF0NOgjSb+si1jATpnpgLa5NlL/bmGLur1CwWMqM2y8aQ66V6rrTret/+YUQsLZunYdjz59OvO4sy+yvzS3/0f2gl5BZ/59F2G4WPjW3DLmUj39j9+8CD20AOas466vzIubm3e2GdQYOTGDctD1sveu5MnawyI5iznt79/zrTHerILbpPi2no674+zflKRU7rgyb95JgmK2jxtPqHa67wnNj9n2aHSRPpsONsbqg6h2uJMo/1Q9oaC44Q7tmU6+8/Gte/P08+8gZtv2hz2WbTx387bYDtU6vex1HFDtVf9KWPsFqQcj5fDUPmdq3PyRCnPh2pjMNA7kTLHA2iPN/+JsH+C2apmTklZ5Z0UzhytLmDrBKDE0Cikh96t+nr7kVmwCLnFK0fUKI4CXXbBfKRmzqDqWRyOdB3F9toe9Pl7cOS7r+L2TWX45N1XYHZJgbFTNCLx0EEMV+FWzMnDETKHKvjwZtNgmwUoBLzEUNiU23cPB95E1mVa/nSc6O5D6bZKuF4+ioXZCbj3ulXYuGYRB85BtLa04Jkth/CHHRVopw0Bj5sA15Cqmh48TYL7KggKxQ/i45fTE1NBNjoJxmzZcQgPv3gQ++ni18MVRp+WHPv9qD7chBcOUGVsSxluWl+Cm69YSgFIVN6AvZKAagtBIfZXPFlR3FCtLhmt/X3YerQcza8cxvziUnzgpnU0ojmPggnV0EKELjKVXt92EM8TmDpa3kjGT+9pGZbybEZaAubMTOeqaQIWzCZtd+lseiWYboRlZeelG7RBMoFkW6G1PxtJ+bOx5PJ1NCi9jKDSmcBcanYh1QAL0XhyC1eHXejv6aTKGa1snsfgVCPSxPvkyZMTYuLIoLIEf2tMOJImSJ3pkUceMV6uxjLcrI+NXKcr/4uJOSJw6L777jOghVV1EzgkRpMAjVAhGPS45ZZbjDFq9d83v/lN440sVLrJPHc2TDHnMzOZdbL9YoEy9ct///d/G7f2Dz74IGz/TmaZU3lN9cBk9UBVtZge1aTB+lDbTlfuHIkK0qJw+wqCFjSkXEUG6QtHQKPT9DwqL1q+aBzv8mJjcRRWZHqx46APnb0JZAVRfYwMGj9tB5lVFFZQKmTk25gtkSaeHmIFcWu9j4k1pN+Nm+bgo+9bgrITFQaUSk9P5QRd7BAvZmXR5Xu/h7Zn0pCRXmjGrMvWzkIW1cSSk1MIwHYR6GnBVZf4qTqWieSkZIIw/WhpaUYfJ99Kq3EiO2uxcavbT9ZhejpVoBMT8fsX9uJHf+ACVZtgIQJC/BuwN0TKEOvPYZ/nND5zxxnUNrZVLOiatkRsP9KLZSXx2Dg3EbuqO/HkES+9uQF3LIhGab0fL1RFobSbivLMdlkWDXsneXGC9hRpkYgq5F4M9NfCN0BDSOcgaNIrlRJNcsX++BMNgdZRPUDqKE5VEE2GZxC4kerZ7bdejTmzZ44ANZxVm1mYa1zLV5NhI2Di5huvCKkOJVW0VSsWYgcnQ7v2HMHBQydMNmKwLF40x5T1/luuxKziAsTReGnwyrkmZLKN87s/vID6hmYa4d087A7ZWZ9w+5qIldHteDtNCWRmpvG+yzzAmUFtMD/TB9n8fk+n6gTl0zixTsOL2AJ2xCxKSkrEUnoam0iQ+2tnkDza2dnNxdFkrKDB6OAgefTosZN8PwYwPTcrJDCka8F1UjoxrizLy5mvGBACkUbroyQirTatjT9WHZXfqpULTVHW5o1sh+n5s8G2R6CRBWJ0zXnvRisnXJuUR7j7E6pMPWvvv+Vqo/5YSNWekuL84XsfSXuD6zFWGtVvrLCG76JVM7RtCe6LUG0Jztf2vdPeUHCcUMe2DcHPkjNuG9+tcgJ39j47r71T9oMZZWMxtcK1W/1ZWVFrnkvF0TO3jh4aL7YghlS+1NsIbgsEE7tTdQ0FQoeruxNcEnh6vjxO6j0Zi+FkFooDtGCjMur87oRrz9vtfPhR6wK0ZLCfdncGqGZE4au/u5eGiunth0BQqCCAqNubiFpSq9tpu4BOStDW48VvXzxM/XQ3Pvuha8iYEeATOszMz8Idm5fiyV3lqO3uocpTuvE2VkpTIn1coUvmyt90lwcJFArd8XGIn1WCwWnT4COT6RDVxJ7fRw9DFABSk2KxbfcxvHi0EQ0xSYjLm46k6VrZ4mohVy8F2vRUVqGEVO8brlhkQCEN3tv3lOI3z+2nN7VOFpaCWAI/7rR0Gs+mgKyVN4JNdfTQ9pNnDmL3oRp8+q4rsGH10EBPiVNgk5E8jUAaED9TKbBOL/IhNjEZLQSJ3thTgcK8LMyZFRoYEsC082AlXtlZYVZk3QS1EpJSCKhRCOXKVzvtHG0/1Ea38vX48yulmDvzoAGbNl+6woBDqkPgB3R4Mmh8NAZtZD3lhwCFdBfEHkqclou4hAwK0F2k0w9SrSygh6/r5yMIcCkuLjYqWQJc5KlKgM0999wTcfHWXo0Ag/EAQwLV2trauPpYGlFZBokeYiOprIICzhYmMQiYUB+oHKfHrLGKCKXqduzYsZDJ1Fff+ta3jDewW2+9FQ888ADmzp1rVvZVvgU7QyaexJPOvlS5sjcku03h+tT2jaqg52U89zmSajv7ZfXq1cbr3FVXXWX6RXWVpzNtzxUoFUkdp+JM9UC4HpA3srZGesTKov2bWj/quwJgSDIB/yiOoUuozXwpWUH1LYDc2Df3UbWsugeZbj/Wz0ih561o/Poluqmv4/hO20I+giRWhUxlGmPTLo6eYguRYUPXE0OAkAxKc2wVQMTJalK0F2kJfhpojsW8OTMJ3gwaZmt0dKYZmwb6B40Ti7lU647jRF3jVQ/ZsQKxaQ2PwBKNPWeko7GJboTrapE6ZxZJP1Qhk5o63Qprf8Fcjv0cszWY61xzYwPmMt7ly2di19EG1G2rojDJdjOCX4s7rJuTNcQjEYlGBLGgZGTb60nEW8d6sH6hFxtK+vHG0W48e5yQGIvbXu7D9tYoVFGVzadxgCBNJgXXZPZhGw1R76E9p7lJfi6w1FCVrG5E/pN5IHBDnsDec81GGiBeZQRnCdBisNhgmSv6nocCaWw8beXZSqCFBHDJagJQnKCObAX990++Zr5/MjAtI7gCFWx5kZalCVk+XSHf+v6rjYHQJDouGQ2ocdZR+wJO/pI2iT7+sfcHXxpxrDaoTppkC0iTjQtne0ZEdhxI/Upe1z75F7c5zo5v1/afTaW+kzv7sSY3welsem3fT7bL9ddtcp4y++HSaGK0eNHsUct0po0kvgq0z5L2LUAp9ahQbYunjO4M47l3ev5ChbHuj7NMPWt/+zcfNt8JZ1uVbyTtnUiaUHV2nnP233ja4sxD+7bv1Q4L7qntiYmkVY4SImm3kjvrOUp2b9tL6j8BI2JYiq03UbDEGoJXR4SyYXWxdJD5DvJbqKBxYjR1UltnMR2dHhad4JLy2EpbZZs2rhgB/tq0zq1s1+kbH6mXRr0XTjt6kbCTnDaUVNZ4xhRnXS/m/YsKGBroob2cvmZj+Dg1qwhpubNH7buq+nZU8udy8cNOYdFHL1ddfCAffbkU8bTT8pkPXnXa3k5QThq4Z83MwcrGNpwkgPLKILuCwE8fVb4klHaQiSP7Bvm+gPAYwxWYmBTaG6BwiPlz0DHQhsZe2imgCtu+yhYca+pByvKlSJpVRPtAYglptVD/XFiSEoO7Fi/AhpVzjPAg4bW6tYuAlAfunBwkzpsLd3omwRJhPUzDF8FFcMedm4fB5lPYfrIcmS/tRTbtEYkJNUAh1Qiqis+f4QyxXlGscwZp2tMy0swL2dbZivK6DgJDjBQUPKR8y5aCXjoPV3ynZU5DVu4MAwwZw9U8L2q4nypqPV0dtCVRj4NlLfjVH7cilgPp5k0rOImNM6pqLtMpURSYq8jAicLiVZcHlXb6MKtgIZoqF+BUzVsc4Lso1Hadvnie9uQeXN6/HnroIa50HcevfvUrM/GPVB1K8YUaf+ADHzgDMBCgIA83AhKC89NEX0Fg1HiNSQeEzkB65eEELiYKGknAUjsU7NYcRPBnzpw5+MpXvmLSyU5QqPSqo/pKjKK1a9fi3nvv5cooDYQO9UMExUxaFPWRDErLkLfAMDGcxBYLBww5++aKK64waW1lnH1vz413q/IPHTqE7u5uKH8Z9xYbywZbhup9IfrL1mNqO9UDoXpA3siOewfR0BpgCZJgiwR+nl4r8+GVGh9yU9zYVODDVQticMeKeI5DPvwnmTX9sdGQZ9peetbq6qPTBBCsiZJdIY6/HG8VQrGFDBjA6wFvYwSGOOZE8+fj2L+7tB0ryig3UH6opy2+efNmm/eqtraOgE8bmpta0U57eEVFBQR2msgsqkZTcwuFzCVkd8xAbW0tGRRsC0EfLZbMnlWMDtoClIr4CbKQ9G1btXI5WQhNSKKDjM7OOhw7dgIpKYnw95MWRftDbrKEpT7mIwIk49OyKaj2SA7QCB0YqbU/FHhNQJgMUYs1VNnYi81LqJqcxX441o+EGD8auWZS1g28r9hDEAl4ujEWi9Lpqp5gWHlHDOtM2YTpc3JiyBhqOCd2hmx1tZ0sIXisfHRdQJQNwa6M7fmxtpqQhXKFPFY6e13pA5Pf0SfANv54t+ci/7H6NpI6qr/H0+fjLXO88W2dx5NuMvp2PHmMFnc89Z5IW22a0baj1W+0dPaa2uB8J+350bYTafdo+b2dr0mt9iTZPmJdiWkpsEQGmQXCRsKkEXBiDdqLnXnH7dcasGky+sSpGnW2xrFVn2CwRYyfx377nLGFJrAwOKht3/3+r9FPpuLCBYHJqtTkNqxbRscQ+0x/CVQTgBjOpphVW5SKsfo00qD3wun5MBJ2UqVUAYfs260lYytUmyIt/2KNR3Hj4giDfe18MFoInHD1hRNH2QCIjT8tHATXsqFiD1ppC6DilAVHKJ/RcKU/NoWCZT+O1XRSv7ElLDCk/CRsblw5F3Vd9KZyvB3tZMsYAZTS9FPvAABAAElEQVQCp2jxzfRzlkgQRLYO4KFQSuBFgqk8o9Q39qDhlBuFyWlk0lMUpCcyGbOO4gdU4I4NveWVrEM85i+eTftAgYm9Ltc1dqCF+SfNn4+YLIFCFB4JxkiSFJhk7CqQuROdRaowWURvNVRi0e4TXMUKrISqDNUljnU1YJLSGVlUK1cSRLUeSnBLEnvIoPMqS//+f/beO06yq7oWXlXVOeccpifnnJVGiSAEEgIERsY4gpGe/IyNzR/+2T/7vWf84R98zx9+GGNsY2wQIEQQMo8gpBmUZjQ555nu6ZxzqFzfWufW7ampqeowsWXdM3PrphP3ra6z7zpr701TtNw8mqMVWO3TNIyVsDSVV97N4hgz+CxGR4dwiaYDP/vVMcwjWyo/N/oiq4aZr3O0HF6yuMaGumgyRiphgpSamU3gLNuATi63n1HU+jBBc7JMhq2/VWkhQY2PfexjBhjYs2ePCQcv4GWqCFvqm17WZfr07//+7/iTP/kTA+7EvrTbLBABP7r+53/+5/j0pz89OSyb/SHTIZmJTWfepPrUPztC1mRFPPjmN7+JL3zhC+aSAJc//dM/TQpyxJZLdGz7DEp0L9k1jW/ZsmX4i7/4C5PFdiIdm18vVPIhpJetLvqj6qWj9Fh52eCHysykD2L57N69+yowLrbNZMdqd8eOHdi1a5cBBAUKKeKYAML4pH4JNLRlLyAxFrSJBY3iy870XLKxwbTOzk6+sHZf8fzsNtQXycZJjgTmkgQ6mg/T7Pks8ul4+qWTY/QjRJCZSlZliRsPLHFjQ40b/f4U/MtRYH5bBPmpLlwgOfbBFW4Dbvzb7gycassk2kBzKDpjnhFbiPVrblPksdIsRvLMHic4RMYwTUv+7ksvEZ8ZRVouo5XufAWBCQZ0SMlHSsQHP02W9x87zGBkE0jLKyUw5THX9h0+SACGDFuW0fxlTJt/HkJWGn23pGeaeTXAuPQCYHI4TmPuxnxaUBkbIyDGvkx4crGykhFCaSLXPpZhWEMChiIGGFK0T87m7G8iX0Oa4yMExEIEt1p63Yx+loq6YgI9WdRf+iOM7ObCE9Sj0+ns8JXuCNlBIVykvnOJDCoP6z/H43NDEbx3uRtN/UfRcukQVhS8ay59TZy+OBJwJOBI4G0vAYFkckAv81n5XBIA8f/+3X8Y0EOswanAIRs4EWNIoND7H32A/tvWTslUsSPPSfDT+fkxuijfYZVEFJgu/Hps3aZQ3Ec82KI6bWfxYk5pDLaJo+0sfYKuY578/Q9Pgl3xdYippoAFYvQIyJFfqtg6JFOBQp/6xOOTdcR1K+mp2H7bt67FPgJUAu2mYifpWdjO26dibcXKaDr5J+3YbbwxZ4Ah3wSdWHqHaW7ElTeyWdxUmKYKOxcM+DDASFjnuwmCUPGyVuUI4FBRDKblI5CWM0k9nkq+qfQh9OidKxBwncS3GnswXFphFDmBLtnpKSjMz0A+VzlrBLCwGSmlo2TYDHTTRwBBLDvJB4KYQlICTdKORSpL87G2Po9K7GU2gO6bkPGsUM6m1WcDCumGmjFNURHlXmPz0EfQcFkdvn+sk1HMzuKBbUvNi6qa0sppomRftfeJ8uiawB/1WcCIlG6Ft9eKrcZq7uuQ190EtbJzLPDmTFM/Dhy9gDs3LTBlzZg5funKPjoOl8+hZCkzpwiZOcWmXEqK8jGKGRlUtzIJJHjggQfMi/nnPvc5AwCI1aJks4li2T56OReYI8fAp0+fhkyiPvrRj14BFqiszQIZHh7WKU6dOnWF/yK1O2/ePK7wluHrX/86/TS04bOf/exVzKLY9sS0EWClftlJgJGYLwMDA+aS+r59+/ZZmcOpoA08aWIQSDLbpPEIHPrN3/xNA14ISIlNNhCma/LJJPnNnz+fE0O1YVUJYBPYY99/9dVXDXtGoIi+j2LzxIJn8ewuyUnsH7WjvLEgSuyxaYAfsYDgvn37DMgnwCfe35NAN/VNpn+/8Ru/cYXs7brs/VSAlt0/5Z0qX6w5o8rou2YDbXo2NsNMcrPlYrefqI1kLCi7jLN3JHA9ElCY+oG+VkbS9OJMhw+H28g+5Vy1psqNR5a4UEfzplQ6S15T5mKEshSGXffj2fOcG2i3VZ9HwIhu5Zo5bwe5MMKQlZz/Ls+jlyce9lBzKrdJtpDmSzNXsY3icTyx8TSWl3dbzFb+ZmiBRHORi3vxdrh0Yh1zPrIXT+C+wDyc45RHyrApw/mX87t8EslcyYSc131uyqLADjxkFs5tNBnTtegaDttgZdxeOlmI755eiU5UsVUq19Zl3oou3DAPj64Uu+5Rz5EMDp1Px7FGPzbWp2FNtQcvXQzjdE8IS/Lpb5H5Uv1kBzGoYlMkFe+vZUQyzrXPt6WieSiEjh4vF2ToR+nmEFuu7LNz5kjAkYAjAUcCs5aAbW64ccNyyORJZmXPfPsnUDRD+VOLdQYvBoxAChs4UaRHObV/+smP4oOPPWjMdZN1IBa8UB6Zrv2QftbEUErEblEb6oud9tInkM4T5Y2vO5nplcaqfsoBteqygR0xfwT6SI9VkuVLSXEh3kdH/fFgV6I65JPqxZd249XXD15Rh5zxv/fhHXT4f9+UgJk9xti9DULJj5EApkTsJJuRZDuDFygk9pKArvgUL6Pp5B9ffi6czxlgKEKlTEqUy5PCHVkqeWUGQEgmpO7+UbSSdTPho5bG1ciofmZll8LFTUkh1X30l5OXR0YPff4kSukEfrYvrMDhph680tqOFFLO0/nlrcrW6h1ptQRG/FQcfdyyeD2PYJKHZaSkKukrXpzuRmEaHfSZK5c/iv3jKA0SRLKymhuKFFZdSmeGqZ1cpRyDm76FjM5IvVGqo9nsD7ZpGERcwWRgYLx5aQArF1iAQJj3/FRaLxfioU6jmxpTNTNKyqhy1odVSWxp3pPSnZWVR5YPqewdXiwdGDPKs1HI2eioP5+AWQvOn9iDtXe8P2Gz8jOUU1hB31FFdO7tY5SyFvqqaCHDSKu2ty4JEJD5jpL9Yi6ARYCL7mkT4CCQQqCJmC8CdJ5++ml8/OMfN35y4nurF/fKykpcvHjR3LLPY/PZwJMYKT/96U8nX/q3bt1qsglAEEAiHxiPPvqoMVdbutQCAu16BFioL3YqLy+nc9XEDC07j70XGCQH2DJ3E8glNo/S3/zN3+BHP/qRAVhkIhcPltjl4/fxIJsNgAic0D2N9+WXXzbg2y9/+UvD+NF1jUHOlvUMbHaOwJjvf//7hiH1mc98xvSloaHB1KFnJBDIrkPPRzITI0syt501a0xKAlTsMX34wx82zq7VJwGCei4ycXvuuefwu7/7u6Z91aW+23IR+CcWVqzsbdntIuvozJkzph0BXmKR7d271wBzAhST5XvyySfxgx/8wPgTsllg+m4J8PrkJz+JP/zDPzR9k1yeeuopfOtb3zJy03dS9UsWYqrJH5bG+8UvftE8Q41VSYDWgQMHDGipMTsAkRGL83GDJaAw9WFGJCsvTMHAGKNicgrW3E2LJhxpBv6Bzqa9nJPn54bwgcUelGXQFxD94pTm0zl1HoMr9HjQ3sfMZN4KGImQAaPySsReDHvWXpwgtGMWYwQOGdCH9zXvEmMirDSObirQB8970TWWYKZLcMk0Em3L6Az60Dn/W0kHZha0L5j51J4KY6ssI4toKcGvojwP0kODcPtp95UmAIidM7HrCTJRl1FEUtWZKCnqmpvAkC+Uigkvi1NuGdQjZMb9clMYr3dSl+GiTDrHX5jjwocagnhndRAvN5ItzGipnRMpZBqFeJ8h63uPY7h83Q0PW5+o3841RwKOBBwJOBKYuQQEQMg09f57t5jFDttn0Es734yCESmooyWGSAMCVMS0sYGT3/udDxI8uheL6NRfvvISJUXh+8evfY/vKx3Gqb2dx2bsCKBRdEcxlMrKik30QkU5s6MP2vkFjBw+cmYy78PvuQcCO15IEO1QzCdFHfwq21VUPYEzYj9prApaIPbRl778zCQ4JIAoNok9JKZQIrDLrqOCkUIVTTE2ImFsParDjkzZ0FAdW/2Mj+NBO5udJKaXkhaMFHFSINZD77oLH/rAg4YBZt9XnpnKP1ZOKjcX05wBhrzjPfCTNeSmsuhJdRM8qEYmwaFkqa1niMCQ/AtRCaNiZymNUsDszSrZyXyv7z2BenpJ375puXHumqjOejqj/sS9K5Cy6wR2tbQhraEO7eN+DJJKLlaOFFUBNFJIpZi6uIInQERJvg6yeaOUDCOw7yMBasoGnWFvuNcWm2Qr2cDIHFVFbbjIei4rjcynrNGydikzIrVZWIJ9Xf1Ye66TCrbI6S4EmEl/QFaKlmABo4tyr7LTJamyJqMysx2DdPFjeKAHlflae2XUGTr5zskuMHLOyimknyMCZURpM2jmpmdg/Ayx7LA3g0ouTQSmSPKLYEUtG4N3pAU9rWcY3n4+Mm6hOZm6Z4ND9913nwEvBD4o2SwMARhKv/Vbv2VYPQ0NDZOOk+17JkP0QyCIGEB6QZePIb2cx+cTa+WrX/0q/uiP/siAEAIiZEYkwEOpqqrKgBUCDmwnzfF1qB9PPPGEyStGzY4dOwyAEe3GlLvNmzczQlDBJGMqNrPa0bZ48eLYy9Me23JURh0LqLGTfCkJfJJsJVetFAg8kaw0Pp3Pnz9/8r7kJtM4ATJK6o9YOwK+xC6KrcMet/KsX78ef/VXf2UAIbttu7zGY/dJ/Vu5ciX+8i//0gAoAuFk5iZASSCgnrVAIvXNdgBt15dMdmpf9drgXLJ8qsfOp3HqeyAATgwhgV565mKi2XJRHltuOtY9Wy4ar8z4bFDI7qP6Iufg8dft+87ekcD1SiAvWxE0I/TD40PnYAA9o2QHkS20qMyDI70udAU4V3ICOjriwVizG+s5h2TQZ876Cg9WFgHf2JuK4y1Z/GNIRYSgSIS/AXaadDrN+UdOpwmbmDmHH/pPkIhXzMZzTnftg2H86GwYh2hWNaNk5jf2j3M2J3ZN5twYPp7H1sZz6RTTpPKMMJ5YGEBRvii2zKx5ngcqKZxMnTXm4LyufxpXUnMyyqBnNAtHGkewYXEqNszLwJ5L9D/IsnlUKQa5z0yL4H0Lwri3LMwoaDRz97qRTkffLYwGNxJ2oySXz4T+EKdi66pbTnIk4EjAkYAjgdsnAYEJO+7ZRIbMOuMvVv6GBNqIldLVzWgNTHfdsd4ALFUEPbZsXoVkkRdjR7Fq5WJ8+g8+ZvTY2Ouxx9K3Fy+qN/5+FKHuTrYjvTdRsvPq3rq1S02kw2T5lXfB/FrqwMWTVdnjlB+e2DEqqqDAo40bV5ixTQV2qY6lixvwxc//MR4l8CQ5KUlWeue365iJfCY7luBA79A2aCcWkN3fRG0lizg5U/nHyylBd277pTkBDHlHuzE+1MoIHT4qNhGkMEpJaiYdPVNhSpbGx31ERZkfivxFzSyqnJkD1mEnfen3H2/B0TPtjD6Sg8VEXDMSMIe0IrmAzqjfvawfXYfacGGQ5kCF+Yx8xiC09C10ecWSiiNTNrnzditBMne6vfRN4A8xwJgbAZYZ5zKqDRzZfYndb6dvoyBBp6+/cR7nu3roS4i+g8QO0qb+yxzL7HUYvc4/hFb6bWj18WWaSrXM0Jr6fMiiA9AFRXypZwNm6EYW0SpiG01yPDkSU05tW9vKRZXYsbYI+4824kJLO5HqDMohlfIGGluH0dSWSwVYlVp9VjHfWA/NDKj0T5FclLWUcA8jvkSCYxjoPMNtKSoXrJ2i1M25pRd1bWKuCCBS0kt17Iu17gvM00u3tmTJrkfOhJUv4feM18Ve04u9AAoBEbFtqZzaUl3J2tJ1MV/Ujn6Qp8ob31fllfnXVOBPsnbj64o9t8eua7Hl7euSrT3O+PHZstd9lZXcYusQ0PHQQw/hwQcfTFqHADcBZomS6oqtT8c5OTlYs2aNkYV+I5L1Lba+6WRntzGTfMqr78HDDz88CdKpXOzYp5LLVONVn+2+xPbfOXYkcCMkMDLUiRH6kZP5lcLUd46EUcn5Z0WtGx/ezAhkIwSF+tw4O0zAlIslfh8Dq7tDqCdjKJXupicmGPAgQmZwlC0kSMVK0b12nOtsMzLOFiaHWZAx161zlZFJF6vnfGvVMNWnFEmBUFZ7gnDUkFW7arRq5afAoimSmEKPLw7hgVp6BmS7FINJKi8gy+I8CRjiYXQsmtPVrtFVrOzWp+kT/QzRAff+cwxZvyyIeaU+VOW6QDeGeN9KN+6pV52sijrBa80u/LA1lcxk+kni2IPM002QaAHdAw7QxG+YzyW/8DIwbzXifDoScCTgSMCRwFyRgAAPbVl8f1W0RwFF0kFtkEZR6vTOKf0+ldYpOp4uifUixtF0yY6auIhRPBfMr5kyu+3ORX2dLr9db2yFKmdHtIwdo8aniJMzGZtAm9zc7Ek5qX6jr3PunGkdsX2a6ji+v7Npa7byn6oft/venACGxkfa6LC4hQCIBYa49RKekhwUGqNiOsrw78NjMoOJmodFFTBboLGqXYAK6Mv7mohSFtERdAHDsaeYzc5r7/XHt339EhDXwTOXxnApkm/YPi5peFHlz1LvVCJ6QaoeD73UUPupoWZwC0hTjN5OZaSzVDqmjk9yRH33JrIiWPW/7DqFczQdSimP/lHbVasao1Dqgk6khLqw98gFtO4fwpnGPoylFOFkzwTSCRTNz6ejbJnkzSClUL6SA/+2DPI6KS9zQe2xLQJ1cmHNA3gnxhAiDdAjGiMzd/aO4ZevnzEOqfuHxlFUXGLqGpig82kCdlM5oA546RiUjkL5mLn5CSa1oq/9PIoq5yOdpmq3I+mlXNv1ppnWoxd3AR7ariXNtJ1EdavtmwEcJJPfdH2d7r7GMF2eaxmT/QwSySjZtZm2M9N8U41rqnszrT/ZOJzrjgSuVQJipeRm0UcQ/dwEyHjlrG1m4TY6SA5NEAAqSsG7Fqfj/dlZnGNS8b39ozjVyfhjNME+3pyGE80MLc1AEWEuMkTkX0hzDpOmWQVhsMzIbJgmOj8pCzdltXAba941BZN8VBOI0kzWQQfNKmhAIRU2c5xVXw2nG7GHOmgFNpO0vjIHv7Uigg0Fgwhz/AKk1DWTWK/pHwdixmHuaDxsX4OzlYJodntnm5P5aU7mY5CL+ex3ZZ4L5+ljaGSUDCGCbBd6w3R07UYB58yHqkPITA/i6IAHh0dSJoGpMJ+LMcm3K3b2jgQcCTgScCQwpyUgMELb9SYBKNpmmm52/th+3Igx3og6Yvs01fG1tDVbeU7V/u2+d/3fxuscgdhCY8NtVDIJPDDsqwyXhCZGwgEE6Z8nJe1q9slIfxtGJ/xo7p9UyaxeSAuUDqgPHduJx+O0x//pnosoKcjEe+5dj6KiooTgkJxR37VhCXp9J/FtOu0ar6hiX6zqIowOIh1P6TIbyOLb6NwAQoYppPvcWC7AsLdBrqACV/uAUVt3b1yKjasX4E2ycv6NZmynUwqQWlZulVdb2qR5m2N+ZGbh8IQLh7pGuRJLCjxXZMfJVGobIa093YMs/i4YMEkdmEEy/bSrN3JjOf4fHujDEoJohXmZxrZSrKVoJ8w+K6sATaTzDRIUSknJnJTLsD8XYU8B+6BOX51G+lroC6GJCnSIK7MRpDNKWYBLn52Nb9CULBu1y+7gtdsDDl3dW+eKIwFHAo4EHAnESqCFZo/tHe0oJ6ZtTTMuRtECGunnZ4QAiDs9gurMCayvCtIBtQfnOkLI48RUlsk5cojmzyHOh1oB5SZzKztdnrE0XwoYiv93+ao1F9kTo10DUFOYgU312ajM9RNA8tLULII3myOcH1nCBoW0Z9uba1k/9wfox2czXRNU5IVxoMuTFCSqyJI5lw/bK8PwjQTpRJsRyjiWHI5LSb02n9YBG7QPrN6a24k+DJpkyUJ+A2mVjhSylMfpwfpYa5AR34AD41TVtHJMnaGea2EPFPuRTsZxBs3IlDK5phHop58hMbmc5EjAkYAjAUcCjgQcCTgSuAYJ3FZgyEuzo8GeExgdaIZ3fIgOLf2GKSR1yjveRVZQI8ECASpUvKJAx/hwB7ov7cYgIz91jaYTYGBuo5fxQ6iNCiu7ddESia5xaxr04+cHW1FRVog7N2Qgl6YciZIAm0e2L0P3y8fxbHMrcubVGaDDRUVNTUnfM4CKTphETjf8pkmURR1gD7h1jdMHwxQ8d7WVz+3ejYuxZXUD9hy9iH/beRInwVC7pWXWOEyjVltakgylpSNSXg9XMWmAWiWko8v2YT9y6bhycQFNkJhVQ54+WbmkWk76aNLYKEcxqzauZgSpCkYii8rV0nOjZYhM5+SXMsw8nUbwhv4JwPIF6GOJbK7ui7swks3oY6TIhxgxJcxN9L/R/maMDZwkhTCoodD59iDZSAGOcxDt518jODiO6kXb6GOqavruOzkcCTgScCTgSOCWSiA7kz71MuhLiCZk8i+kn/4+RiETdSVMjULT1QjnpMZm4DgBmQAv5ufQJJsLAX7OAfI/ZMy6DChkzSeTA4g7NRMZr2muMHPMZEYesCG1pc1O2xYU4oPrSlCT24eK7DD2NLE9mrHtaaE/IvbF8inEiIcFbppqubCF4NB7l0VwhFHSdC7MKFFaUxLBJ9anY2sVxzA8jh6Gkz/QyjHRp+D6qsvmxSpu9TNa0aR+YvUzUfUyMZN3op5h+hoaEouX/SAwpMWYfVr8IuhDC3JjtiZzurM0HRvsyTDM5v4Qy3klT9ZvdIHECzKJxuRccyTgSMCRgCMBRwKOBBwJxErgtgBD/okBjPRfxPhoJ8aH28kgacTEcLcxb9EKXsA3gpG+C4ZBlJqeZwAWE0I25KcJ0jCGes+yrI9mU4zm5RFpm8pQVEOcZMvEaIs2iBOi0+QDXQyN/sJ++rYJ4s4tq4yfj1iB2MfppPa9e3kVWjtPYHdTC7IYqUzKl5J2asdWIgWs5POjipHJxnlxkM6nTT+o2PWlZuFYvxfruwcItrC/SZINEN23cQm2EpDZc+Qi/vWlEzgRzoGnuJRjJdCkTYAT6zAOO6mPRkg9l2y83M52jWNsLID5hWnIJ3vI7l+SJlULAsEQwRwp69G6uR/q72VUuDCjoCwyXvF9Xr8Z8xUroOyEi8q/h43Y/VJ9o/48Pp9TaDr+GoGjEirOZBOBdHeauAUDE+bZBgNyGh606ma0L5kjuF0TGO3js4z4uIVQUD4f2QXV3Bx/Ccmfn3PHkYAjAUcCt1YCmleCNCv2k6kqJ9TWfGj3gWf8L3jCRwDoJF316XwTTaM0gXYPpqCH5k86tiOP2SW1N9M2s+r+5X9X5eB8pbz6MCVMBrGF7lhQhLsXcZ4NjoKkVMwvYWj7Ijf2tjOfJmp2vpprHY+tUB9d6JsA5yygjtdkViZ8q200tj1gbakLT27KxtaKEMboe7CbJl4H2uj0+nwQy8pdWF9tATMqZboe3ZuTy92zr3J/xUXrOkGyMJd0gvRdWEpmUhkdfCsFtBojYXLu11g1T8vUvZsLMKpFm24Nj5KBy3+52bdFpWMvnORIwJGAIwFHAo4EHAm81SVwy7QImYkFA2Pwjw/QdKyVTJE+TIz2EhQiQDTM8LehgOUfh8AQI74yXx/Ny0bIOLFW4yz9jxqQVsUIMrgYvezKZClNVgQwW2WycljKGq+lZCBIltDB7laUvXnBADXyeJ7Mz8s8Rip719IKdB9tRzMVwqyCPBSQ560tInvOaAekwqk34h9l8qKPyp2cVqvPbvoY2nfuFJanBfC+BzdFSyTfTQJEmwgQrbEAon958TiOB7PgLiyNaoIsr8qNUDRW63CMgFQjQajuYS8KMlJQGJrAnYqQliTJ/4Obm5xnSxGXWuubGEddSRo+8OBybCBA1dHeGtV2pXbGJNOsdcUUVXd4WyufoYCXEeaGMOEmoKRVYWVgX8MEfPT8pOkKKAowqplAISm74UgAPm8P3DQ16G0J0xn5RZqUFSC3eB5BqssO1RThKjO3HPml9TGdcQ4dCTgScCTgSOBmS2BYDo7JCM0jANHF3+puMob0u2/PDTtIYm0gLvMKLZoa6YOHU6G5V05TslKamDXR1DpE8yeZkJltsmRsz6OQkMAhu+LJ29ELrNdMgZPXhflEcKh5AItLZMY2wn5F0EGW0MF2+hkSW0iV8X9dgQtHOuWPASjLAeg2COVkNL1wniyoMQJHuZqPWGbUhXXlKXhqczY2lwW4mDWM3r4gDnWE8fyFII7R788SBk6lymKS6au6J4EwRXtqjtQXYTwmRe9Hz6xLLCx5dA16MDCeSp8T0UpVmZnnge2MSLa4MIg9Ay6cG7O1D4JHBOkymD8y0mM5BY+t2Dl2JOBIwJGAIwFHAo4EHAnMUALx6MoMi02fbbjvPAa7TxAAIEOHSWBOhE6MQyGfAYfGh3sIQgwZ30IChew8Ad8EGSNUhuif0jij1g1bO+Re/wLeCaQZwEgaVpyWZfQofaiglaSUiXGjqB6RrFwEPTV48XQzXOE38fH3RbBM4FDW1b6M5Iz6jvWLjV72wulujJARVFSUb4ArBgabVPzUlMANaZN5pMtnZ6ZgmApw+0QQdLuA/oIy7O0bxZLzl7BgXnVC30Z2X+19PEC0+/BF/MsvjuKYlwycfEYwY3tq0toItpiDMKn6EXh9YQzShC3o8VMJV+8SJwFiGXRaHfD70Np4ES7fEB68YzneeddyNNSW0uM7fT2ZNqy2rqhFSq5MzJhBLVibda4mtZIcIRCkZ657VrKOwmQpeckU8nmtKHT2PeX1jvfQt9QwzQhzaKZWSCZZEwGifJoYpmOCTq17e0ZQv+J+BxiyRersHQk4EnAkcIskIEBfJkshMm4txhAbjiIixekyzUrHUq6QnOsPGWDIniTlM0dMo86BFPQOU+2gKdrlGdTqvGEQ2QXixqOZQzONtYjA+Tx6bM0+VuY2moq/dq6bZmQpqCAQVcl+aC4S+FNOxlK7fP0RfDnQ4cL7lzOyCZEaHaenRrA5JYL1FREUZ4Wwr8ONgwSO1ld6DCi0scTPBaxB9A2EcESgEJlCR3sYWY3TriKYWWbY1hQcM9nFjWCKU4lCiXIMGHN19j0/hcwhoJdsJo09zxPBlmqGsi8GWsgOOje5LEX2EH0O9voILEkqZuHF1OZ8OBJwJOBIwJGAIwFHAo4EZiWBmwYMjQ12oPX0q2QJDREIodISXS4zCh6Vy2CAoAD9DVhqT7TPVIyk2Pj9XqMkpaZncjXu8sqYPbLRAFcquQJo6VNRrYpAhFQjswnNiNHQlEPXTVI/CDgEirny19mHZadaDHMohSGyFEY7PgmguXPDYgyRNv9a1wjxKnLOo+1cmVdKq8jgYg9FUEhFuCA3DUGOqSmlBK+cGULnc7vx63ctwbaNyxn6ncjXDJINEN2/eQnqKwrw/IFm/LTJi84gkSmN2QAwrMiMWT2zxh7UyqyAmymSxvvBh7bi4fs3oKq8yHi0T6eDS20Kk6gknd/Ijx+TK57WHfNp8qjNaCZal1G5TSNAlc5QjEzR8tHukRkWAwopCh0bUFHTEHcCCQMEiIJkmPm8QxgdajesMfVnZJiRWbx0LLpgq0o4yZGAIwFHAo4EbqEEDGOIDo4LyBjKzY6Zm/kj3k+G0LOHvchJc6M5RNUi5nZ5NlCSLkCJbFHZdBGgsX/z7e5bczTnEjOnibVjbWYW04c5sHJrPjFzSsw1LYJcIiD1RhPNwUbcxonzRbJrXm+RSRbLaaLhfCPw5YWzPCGos46WyiWcqBTt83C3G/sJCjGwKNZVpeJJMoU2FPow0kNQaDCEY900HyNT6DD3BhRiXZqX5A/ImsSu6KLprpqcUTLy8HD+0xwof0wUH7fodI4ROrn+4XE/dma40RKWnmIPyAK/fOx0FllDVzyTGTXsZHIk4EjAkYAjAUcCjgQcCVgSuGnAUJAmPxMjjMhFYCiNkbNik1HozAVLq5PyZI6iNww4RFaQVgfT0mlCJc63rXnxyE+tzEdnAAYEIRgjJpCpgfktJg1rs6rmdR7qlOFxofC4AiOIXrholtVF5fHZ1y7CTbDisXduRkkpTbUSJIEz797G0PK7z+D1tjakV1WRgRSTkQ3oXEpdSA4AmNQP+d+RbrcwJw0FSxfg3PEQvrHzlLk/G3BIBdSHxQ0V+IOaUlTuPIF/3t2Kzki2aUcDNH5+qBjb/n7Uvhm4aS3xRyAQICjGZVVmdbOvAoriwTFTDWUvyM3UZ9dr781TiMpdFfG6OzJBYIcry3ozMOIwH4x6H8KEYQox+hz7ainNLMsjwxITCsWkqiXMIKOV+ckqMvghb9HKjeAUn6OTHAk4EnAk4Ejglksgh2HqQ/xtHiUQIUfIsUk/25fos4erIYgwEEJ1IZ1Oc99OhksqF4dSyKbVPwMKcWa0ZoCYOlRBzGls3TrWbasGfkbnuvg8mn5fb4zgjWZOyJzTtPRk/PTwWO2qy2L4FBMM0kKH1j8OdLnxsyY3ShhdjCRfbGkowyc2ZKI80oXhniGCQmG8TCfWPzoXROswffyYqjlGgTlcuNLcqepjkxnn5AX1fOokWWjrpilZ7whNvKMLM3YpzYnNfjdaI1x2UtgyTq3zGLJeakiQrCIXL6RSzxohaGdM/QoUtMNJjgQcCTgScCTgSMCRgCOBmUvgSsRm5uWmzSnTLb+PpkF0Eu1nBKoUAhupaVSipNRIiaKiYymGMUqTtDaDCmgXpg8aMoeY0jIIDrkTdNUuqjLcBIYYgMHUYd+UIshK7DZt8ESKaU4eVxYH8Mv9F1FZkou7t9FpM30CJUpyRr2GCuOplhNobGxBPqnnVrIr13isPpg77ENAWir/e9iBAo5/6fKFaLyQhm+8eo4h4L304bOAzq/zZ8wekmlbFs3ZPnj3Usgd9L/u7kS3FEU1aDVldUkXuOnfVGmEwN1XvvlLPPfzo4zUVoCV80tw//aluGvramQzdLySZGc2c6JnJ4WY1ceykaJUIsNeYr+CyObzSuWR1FZTkOAOvwsChSaioJDEZpJ9YO+JCbEYsxogiBYL1viYV9dpCegkRwKOBBwJOBK4DRJwp5VyjixHyuhJYODKDlTmebCkPA3VRekoyU1HPak457om8PypUeL8Wtzh9GEAD85LZv6Yen6arN1MZ5pbOQeYzZrb4hc/rHnKBa4nWHMGpyuzMqO9EjMYfiqnmk76EtK9XmMTboEyF3n/fSvL8KmNmSgLdzCIwjD6hsLYSVDoh+dCBIXUPmtgUZm9RYgGaTwWY0jGbbxuNn1emTS7aUueWEYDVL2aOaOnsflzKUL5QtpYFcSmoiAGyKD9z05GIU1NwzgHrcif5XmljLaaeIErtq63y3FbezfaO3pu+XCrq8pQVZn4OVxLn6aqL9ngrqUd1ZWorWutK1nfZno9UV9iy96Mfk3XZmz7N/rYHk97Wzf2HzzB726vaaKtvYv+PntQXV2GysoyPiMuEFeUYvOmldiwfvkV3fjyV76Df/rn5/DoI/fhk7/3oRv6PYxtaCZysscTW26q45nUOVV5554jAUcC1y+BBGjL9VeqGvKK61Gz+G76iqEXSqo6g91N6G5rNJWLQZSdn0nAJ850S4pRTJKPGvkcUkrLINjgsbqbmxZBhaKcKJkyUS1KzCGzxddDRdJolLxPdCHCJb8IqdkR+q1xFVfiWOclfIvgiNgyd29bjawsCxSxGrj8WVddjA/esRT/ebwD51r4g11vmZVJTQ2zzjDrFiCmZA3FUmbFndF5FsGhBQvq0d2ahr/58TEs+MURPP6ONbMGiLKzFH2lEPuOX8IvL40ikpHL+tmArU2qC/ZmDkyXrvgIGh8RdKg57qcTUT8G/GNcqYxgz7EOLPv5Efz2h3dg64alk+I1hdnGpDKu+ieTVFlJwUppdDqd5qFdAaznqzD1E2PyKSRQiM/A5I5XlLkSy2cyQX8JEwwb7EnLR0ZeIUoqF6KsdrFZmVXtcphdWrtEh05yJOBIwJGAI4FbKgECIWTJeOkWcEIhvKLT8EPL0/B7d+ajno5x0tIyuAiUQbZvOv7v8WG81OwnEENfOFznKS8IETQKoJdBERIBJbpmzSOaT2xzMhmfWQwjzT+aYy0fdpfnHEsEnIVYgVlwEnpjb2pJbCFl0jUeac3GxcxhmpXJT5DSuxam43dW+ggKDWCwbwT9BhQKR0EhtWnlCzO/OdQ6CYEhBVjQ/Gf9j+mTBqJ52U7m3D6J2zOfFlLKC8IoyQviLCOfqZ9lVEXuW+TG9mqBQmFkpoVBNYL+EYH9AQ/8fBYakqKR+ScYFZSbBb7F1f82Pf3+D3+Jr3z12Vs6er28P/3kr+GR996bsN1r6dO2Lavx1Kc+chUIkLCB6MWWlk4IJNh/kCDuLNIf/LeP4lOfePyKEtda1xWVXMPJBx57AE9+8sNJwY1rkeV03fDQhrOutgIbN6xICr5MV8ds7wtAef6FXfjR8y+hpZXBeKgnB/wBshOlL+u1hWa4fMfoHxjCiZMXjNsH/Q6nccF6+7a1eN97dxAwKsW+/Sfw3e/9HD29jPw8Mm7KJevL9cpuuu+kxvT3//BtPP/jncm6cMX16f5ursjsnDgScCRw0yRw84ChkjospC+fEHnO0o383lGyRahstV/AhSO/wHBfK8OZU4kkOGRYRBqiNJwYRUp+coI0d/JOBKhoBsgWyUN6Rjpp6W46jKRWxnqNqsYyUhgttpCq4I2YekzVPDehdaMAUYSRUVSenUCkch6OtJ7HT149iZLCHCxfOj8hOCTGzvy6Mmygz4GWwx2MnKU4ZFEKC/suP0p2s+qDqlfSNZ1pn85Jp6qmEjnZmeg6dQb/6xuvYknlEXxolgDRgrpybKnPw6GWdvREcli3acE0ZrWlRu0eWP2I/TQyYp8sx5kuOsnOQEVRLerIHGrtacfzLx5AcUEW5cxSErIRtPWI9JyMYhy9Zu6Zpqz2BOgpnLEAHj+jjo2N+MmQYkh6Zkyng1K5crKLqk86DlFBH6Fz0DAKULdsI+avvgcFJdV0PJ2LjGzJ+XKJFK6QOsmRgCMBRwKOBG6PBPRLX5bjNlvlRBiLuEbS3k520JtjaCag4k2hGVlOCkGgNPqsc9Mnj4IQeIy/QQVmd+mFJ9H8pIrNdTFwuNDCYx3Zl+15btL/ULQOqQ5KZga6PFVYF+1zOxPPNe+ZKSV67z2L0vHUxnTUpI1yXh/FGKNGDNGPoRZLRrjGIUfVYgiZeU8FVU6AEM3cxRhSffa8a/pqWja9sfowzadKa1ErhUxkQWAdQyH0jIVRX+jBPJq9ldMlYVuf5ms5n3bh5KDadmOCfasiU6uMZnCNQ4rwOU1Db7PbXpqiD+lB3sI0OjqGS80dSVu8lj69tPNNVFSUmJf/ZEyk+Aa1IDc2PjHr8fu8tE2MS9daV1w1sz4dH/NOCW5ciyxn0gl9Z06faTQguA2+fOqTj88KmJtJO3v3Hcc//tOz2Lv/OHVkH3yM1CsAKFnSPW18LTKJ3hXw4ku78errB9lXN68zui/rmEm6XtmNjIyZiIjJ2lI/x7kgPNO/v/y8nCnrS9aOc92RgCOBGyuBmwYMKYpUJunk8amkajEq5q9FZ+NBXDz6Ivq725FXlG2xh6JajfzTjFEbGxmcIHMkF1k0+RroH4Kvsdv8+GXnpWNkgjFxpTJSmTI+hqKh0AVKuCKKpnWlhmTO+UMl58dmlU/Hbh5TqXPnEhwqr8FLZy/C9cI+/A6BB4FD8f52NBaBQ9vWLmJIdoaINaiJpccathD7otVMtWy3b3rBj8lzHkunzKXJWtbGdRiqqUbzmfP4nwSIllYRIHpwZgwiTQJrFpVjxdlu7GwdIuLE0CtaSVX72jR+07h6nTwpn/5J+R6n6Z+i2xeUVqGlrx+HT7Viy+oargATiGG+eODNlGVbatccqz3mk2+gwQE/XTplM7JYGXKK81GSU4T+zgtkjl1AJpXYzEw66qbPCauTLowTRApFCrF8y/uwYut7kFNQSvPDjOQdd+44EnAk4EjAkcAtlUB+QSXnrnL4+kji5NqKyDbZnEPPdITw4nkfLtBEKyivyQT/3QRVUnoZiZRoxsJCzjH8uZdfIgOCcL7RMoA2QSFKBmuJjkYzg8CfEO+H6RPQEIHJlNErk5xMa77V3M/CMYk1CDlRMpXp3DrVdXNorl++X1OYi/csysBjSyKYl+OjX0QfgtQNglyoGOTL1yUynfoY7CJsLOGi9dkVafDyM2TXyWrNjGb6pZ6aM9MBUyTm3FyM/eBYNcjygqBhDIWClrxaRoGd7TwmxSnEtnwU+plBF/YOp5pjAVYUP+domupnMWRZCjcnTUpALJvf+vijEHthP9kUz7+wEwdmyaCZrGyGB3ohFoM8WbL7tI+gwFcICsykPwHqm6++dhBbNq9KykSKb2/zplX416/9DzRdap9y7GJqPPLe+/C+h+8xwFN2VmZ8VTRZmlldVxW8yRdsWc7m+crE6r3vucf0rI0mWx1RU0OBM/azsAAYC2CxwZc3dh827JwbARDZDKHv/+BFnL/QfBUgEv9MbDHa41Sf7f7qu6FttsmW3Wy+h5s3rsR7yU7aRDZVfV0lF9Cv/q7Y/ZBZ2F//j6fx53/2Sfzoxy/jq//0vavMOu1xbli/DLVkaS1aUGcXd/aOBBwJ3CYJ3DRgKNl40sgAKanORW5RBfLJKjq154cEDI4hvzhnEhwaG/Yhq2ApVt39IE3O6M+AQE0w4KdDYz/Gh/vR134MmYMDVMhkrmQnKVY2QCGFUUpZNEUPBYAYEENKpUzJqMAaszIqeO7icq4GuhiOth1vHDyDEoJVZWXlCcEhE6ls0zKjEPZ0dU7qnloElTKrpLYmBofRe6mVK5DDKK6rQRFBIHNXH1Tm3DSLKqikol1SiqHuHrRduIjP/cfrWFRhAUSb1y2hD6I8riJe/ZgEWmWkpyHFL2c8NFYjCGPGbBRMNhA7ftOjRB/WSmdUZTagkoAlOfv2hjMwQKXYzwlHzjWNwm0r3dGqjJsIabzamLSaWpw9huraKqxZsRFl87aaZ5eSwn6mphvG2PkjL6Px6E/5LHsJ+ll0eT8Vb/kUWrDmLqy5+wMkcZVaFTqfjgQcCTgScCQwZyRgfOoQnJjgO5M2JS9/+MXgVYwJrxYJhJVwCsriy/G20hSM0+ShayyIHq8b5UVhlOYF0M3IXgbtsaqY/BRopM2YHGvhgBVZ7CCak/FUIJGmG2NOprYmS1pTlEpX57vw6Co3zc3deP50BPvbohOUmb+ix9FytQXpWFiajtxM+kFMoTNn1umjWtFOf0LPNzLCWRfbV4sqZopGD4RlqT79N9fZJ/aGkIDZq2f2QoqZJ3Ue09crDs0g+EFgKEULVbQTs0xILJO3/Z0RHGF0tdUVLry7WmHrXTRxYQQ2MrOO9EVBNVUuBpOAqv8CSS/A8g0k05jOzp5rNukRyKGtqDAfSxc3mJfZL335mUkAIF5UelGV6dLDUeAg/r59nugF3b433d7u04MPbMP27Wvxve//IuFLc3w9TZfa8Nz3X0RNdfmMmCupNDMqyM/FqhWLzNi3bVuD/+/vv4X//Mmvrqh66+bV+Mjj70JDQ7VZ+LziZvQkvi6BAlPJUcUEwPw+fdzIxClZuh45qk5blvbzTUnxGKAnmV8pPd+77liPB+6zItsaEE+KO5OfbJs33jicEKwT8DJIFpHYOWVlRbNibpnKYz7EEpKJ3+u7D13FELKBkkcfuRfz59XQQoI+xITAR5M9TgHjr79xCDIH239Avohm70fLlp2+h3q+0z1PdaF+XhXu27EZdXz+sf2y+xe7l0lebm622e7bsQUHD526wqxMIJPAqTu2rzPtu5l/ujpj63eOHQk4Erg5Ergacbg57VxVa3pmHqoWbqSJ2RjGXumjL6JOAw4pnG1mThUWrH4ADSvvNoBCbGEBRKVVdQRwXsG80rNo6o2CQFISqVgZinr0h/5yOSldvK9VHG4RN5U3/ti62FaYWp1lTsUlwZwCdI8O49lXz3MFLhWPvSsbhYViJl2dBA7ZSWwZregZP0NyXsAkxXCEdr7vXk5b5YbleO7VU7jY1Iyi2lreUXfUJ/MfLgI/eeVlyC4uxkh3L5oJEP3Pb7yGxfRB9Nvvv4Ph7ZclBIdKi3JQnEmNcJSMocxCAjPsk8ZpZCF5RBswPUr0YeVRX1XG6wuQmh5ABk31UtOy0N03hpExP3LJ2EKkQ1WbzRqA1Xd9yhG17hklWa6nSxbRFGw7gb+GqxoV6DQ60Iruxl3mniKOjXGVObdoEeYt3+aAQldJzLngSMCRgCOBuSUB/d5bpmQu/JIh3HsIrjy6MhNP8EUmSMZuFn/n04kUhfii9gJ9DJ3sDaCLrNAiLjK4hJRojjaTxuVxWaAQz3ndAlsskMU2G+MUxfmdcw3fk8w1HXMTJqKkKUhJhKUsRkMTYVkW51ckO7O56MKBlgFkpWRhPlnIBaFxjA4HcJHuA589E8autgjW1hKEyWVkNQJFbdzaZZWkOvSypu0KcIj9sRvT2Mz4dOVyH+3bV+55n7pLGX0vleZTTmRaddGxtNpZWe7GfQs8GKJ/ple7XPji6RSszg3jgwv8yEEKATeg0BMgY4Cme/kVhs11Zd1vrTMBBbavFT3j0pJCyL9NZ1ffpD+Va2Fs6CXVw8i0ixbVm5damxkSLx0PQUy9zKrdqVL8C/pMXqrj67PBlkQvzfF5dS4Q45XXDvBr54b8AMU7HU5URtfssQsYEyhykIwpG0jQy/kH3k9dewpQKLZeu64d92wyLCwxV+y6YvPpOIM+xoqK8qeUZawcBcz83Ze+aRwnx9c13bndr7vu3IA39x27AoCILavnK7lrU5JbAztlIQPTgSTXwtyy69de3+/nyBLa9cq+hCyfDzz6AJ/tE1cBQnYd9jh1rmewlb6nXieTSUBTsu+0XTbZXrJQXUrTfY8PHjyFo8fOomEenZ7NIvX09KO3h4v50aTvnb7Del72s7DvOXtHAo4Ebq8EbhswpGF7yCSpWbIVIwN05rz/eTJKaH7ECVx+ZbLJGhHLJD6JPaT7qQRuUqRkiqZikhSxqLI5qZTZpZnH6GlUwAQMebhRMY2QLm6YQ6xHDiXF4EFRKTpaR/GzPedRQh9I92xfg4KCArui5Pto/ZZzZWUTUBQyK6lZpHlP9A9gLBRAYU0N9UVl5n+jOJqs1AGluLiQV1aK7KJC9LR14eDR4wg8+4oBhQQOxad0MoZqKoroF8mHblao+qQoU2u2NjUyZaL8jJYrGdL3D5X4NOPZkr2hznu6sQeLajK5EGndV1VGYbdPmUcynGyGzeWljSEzvdg4H0/UdIZ8BmXlRRV/KjsMbZxbNA9LtzyG2sUbEhVxrjkScCTgSMCRwByRQB7NyWSyNDp0yZiSCePZd8mHo11BAjL0IMR5xMfFDjdfONYXp2CCc7RZk+GiSXlBAOX5HjDGQZRRw0lD84lS9JDTCs2KBbJwDuWcLnOyENEgN4/dZMTICbRAA2v6tArrU7OdNqU2hpU3TFfrNMlnBCuLI3hiuRuLcybQ3zOK81x4/87ZCHa2kUHANrsJvMwvdqG+iDiQ1oK4aQ6U2tFBMy+zqGRqpy7Bxs0cLD0kpjfCwewtUUcMIMbCHjKFUqn/yFehzOUklwUEpYK0ZdnVSt9CZDmHUxR1LYILvRGcJoAUpEzlA6WPxwO8XvkWZgzFMilWr1psHCAr6pJYEf/wj981AIQYG+vWLp0xKBIv79qaCtSScXO9Kf4FXS/8U4EkU7U3r74K9bX8m5pBEjAhUEHMEjFxZupvSFWrz/PqKw3jyAZz9FKeQb+ds2Vq2OWkr19PipWjgJknfu0h85zjWU0zbUP9Sk3AsJ9N+elAr9kyt2Lb3vPmUQPkJDL9Elgi9kwWg8vMJJmxcrz337uFrLrea/7+qS3VNd24lU9jn8p/lvIkShq3TN/sJKacAwrZ0nD2jgTmlgSu71f9BoxFIE/tkm0oKF+C8VEvGUSBKe2z1WS2/BzkpKOuSMqhAB7STqSdmlVImlWZva0isoBRInnO68YXkMAh+jEKc4sQvAmLOaRNbJ/MfLjojPr4sBvP/OIo3th3gowWaodTJLVk12uxhuQgjn2Tcsf/ZcW5WFpfgmyyabwjCt2rttgu95Y9uo6tTcqlixpogE6xgwtX40CgED98ncworprFJz+jFgRZwCUH3xPjZtwG8IqOV3VNnaR6q4/awsgggJXJCcJSbiMIUCYnTjfi7PlmKw8rM1lNEWt8BtyKXhydGMOwdxg++XlKoqBm5hYhO49atlxsUgEWbd+dUoDC0hoCRk4s+qmfl3PXkYAjAUcCt1cCo+NhMkkJZHCu8KRxvuC/AOe6UUYp6/ZF0MNtmNuQN4yirBTMyyZ7iHNdkHlSyeTRRid9XKQJGqZM4tFwkuF8rfld/0LcW76FBBZFt+g6kFWedUaTTMnKOZUIXLoqxVxbX5WDp7aVYFNZEKN9QzjfGcK3aXpmQCFWV13EevKpInGVpIOs1i4CNH+w3Y0Xf9uDRwkmyXRL6I1atlpnv4w0xADSJMnr2kwn1BdtCRLHhnAAlYV+VBQGjePprhEyiHJcGCYY9Eo3fR2RMcRZlZW50BlJRVswBSMErnLJGC700N8h17Sysy6zmBO0MucvyYeLQI+Vyxfiv9HERC+q+TSFuufuTdhEgEhJL9TymWMDG7MdlICI6wUz4tvUS7Vecu0+xt+f7ny2fbJZK/tiXrSna8O+L7ZR7PirogCTff927+c31BpW02wAr9g+34hw53qeC+bXGAAttm77WDr7hcbWWQMkAj7lU6i5ud2uanJvM2jEAJptut7vn93eTOrR2PfsOTIrdpLGvfvNI5MMKY1125Y1DlPIFryzdyQwxyQgzea2p4KyelTSIXUGo5hp4gp4h+AdvUw7jO+gQIfCtAnMK4ldmaN6apQxKl9UtMxxTEGtylGjNOAJ0RgLROGPnA3kCCQy4JBAJTqjDhdX0FxtAv+XJmAnTl2YAhyismZ0Ptat+qLgk/FdJGCINzMzM3EnfRItZOzZke4+q+1oX+x8ApHsbYwRvIYnggR9uDpaWIG9XIk9dK4rZjRSkAKM+CW/SxbAxMJsSmNXk9pHtytKxZ9QqY2hAKmuAGVjVFmCNu7UAhyin4XjF0fI7qLmaWm4lyvRucpzG/GOo7m7g868Q8jPTb7iIZaYwhnLCWnA72YkBheKKxehtGbJ5XqdI0cCjgRuigSam5vpR+ENtLaSguAkRwLXIAFNLbkEe/IYdayckclKCWBU5aegkpvA/mr67fn4hiL8/ftr8QfvacCGVWUIpmfiUCcdpKYGsWY+HSzn+ggMERzSoo7mrGjSPG2ilrERA64IFhIoNLlxntQ/zpeaqmOK2lWgg2yhLpp8GdMvmn9NJnU8mqoLcvH+JWnYUDCIcYaAPtcZwDNngJfJZPLLJNuTwoWnFGyt96B1xI197R6anXvwiwsu/O83gOPdmju5jpQeYdQ19UjAjQArjSc6F5urHAf38VOn3Q/tZf4uWVSXhlBKRlVTr9+YrnnI1C3NdiGf4I/xc8Ra1GYFWURLKiR/vuTzXI6n5e/Jk1r6ljUli3151AuqnNpqrxTPqKkoL0Y5t7mU4vt4PX0TG2g6YMRmrVyr+ZDdP5lWCZiaK0l90XO3wav29i5GO5y5/5zZgmzJxl1LBld1TXJmWUtLB1rJ6p9psk3IZPYlcCU+xX/n4+9Pd67v3/ata6f93sykng8+9uCUjDyNQSy+mYKzAnzFGLKT2ELXAoDZ5Z29IwFHAjdXArfVlMwemsCCTPr38aRkcOHMS/WHkUyCpJJMkXIJmLjShLzTv44UMKOMERCStmg0xstKoO5boAvvC7yRUBpoEwAAQABJREFUdkXatkAR42PIqHTMxXOVImEdbkbFEshztLcH+09eQiXDuKfRIDlVEbquSCohJZVtiCXEaCJKUhUN6MNTOYqWAjfa24sxXwYKqiqpQFv5tPppGuXeHPI0FAiZzZSnNNq9qejwXrka6CPVxuv1onfYiz469ozkioGjuiQD1sXN1Gt9mD5d/RFtU31luXGytbSlUelXZyIE4DKzi1FWSa4TgSi322ITWf01gzRtDJMp1NzVju7BPlQUl6KGspoqSfwejxhJERSWN6B64RqHLTSVwJx7jgSuUwIChL773e/imWeeQQ3NWT/72c+a/XVW6xR/G0ogv2QlXBlL4BvrRG1xKioIUMgv3Yc3F2NBdR4udI7jQNMwUuqyUJnpxnjPMIIjXoxPCOAg4FJOk7I8H/q6BAyRNcSrdmQyzS2cHjgDcx6M+iIyPgE5X8vxtJwya/7Q9Ga/XuncmuzMgblXScZQBV3jXegn20YqQmxi2a11Gdhe50FwwouzHQF887QLL3VwUYqVCRdSnQfp0+cY/Q2VMVx8GetrHyXgRPLwbmKqal+ZUtILkEpwCDTmNonzpsUW0p7j4KZeWT2zslzxyfxuyoChPFFbEiTTyYfmHj86aRrmIrNKC1e/sdCFbVVunGf4+izK4Z4G1peVil3dHoaqZxvUOybYwoKaOhQUVl1R/VvlJPblUcybWP85etl/mv5I3vWuO82C0kJGLpqt6dPNloP6KDBBgM5MX5iT9UnmbhvWLceevUeTMjMELlyLv6FqmtFN5Qw6WZ9u5fVNZJTo+be2dlmMeunztzhpgXqq75jkr7/NmSb5yWokyyiRCZnqiP/Oz7ReO5++f9u3rcUbew4n9a9k551qr3ruJvtN/U1mGmkz1mYSIS8W8FW7DltoKuk79xwJzA0JzAlgSKIoqlyIkqol6G3db3wDJFWkonLLT/Ohhrb/+mcBFdTADDCiFTuBKFLWYpPAEgs0ioQJovA4TJq2mCsWUMR6ogsnpm0quq5cOqMeG8X3fnXW+Dd4+L71XKlipLKrwCEpfqxfCq4BqKx2TQ+i3airKsXKBZW4sP8Saet9jLpGZ9Hqo/4rj9nzCk9GCc6MkDFkAzxSQlu6+tHRPUCAynKKODo6in2Hz+HkxT4q0AJsWAczToJDRhamhVghXHVsQWEcMf+P+/wErvwoyCbjR0Iw856bK5KZ9HNEQEx95DWrViMlyHyspasD3QP9ZBuFjePG/Fxq0kmSd2wA/okB84wFpqVlFBB8yk+S++ZdtpkTNntC5zaL4o477sDWrVtx5513Ytu2bTevE07N00rgtddew+7du6fNlyxDXV0d9DwFhrxd0+c//3l84QtfYOS/CQMmy6F+yDAD364SccZ9PRJwcYEgj56dA34PCgn8VJAxdI4Rss72+bGruQe/ap7Ah9YWY+uiIuw61Y/vHh9CF+O9H2GgiKN9LqwqC6GGIMiJdka8JCASTkk3EUJj+2RYNprTNNtw0hETR6ZUmnVc9GvnIqNHCxUlWWTVcIud6TbXurC5luZfBHI8QmaiSUcCazbPy8IjS+nY2D2ArkECMaNpiNBpdlFukPM99QehQkyErWgiB7TShGxTZZiMKDqrpu+hKCpEfYH94AukJspwagYimiM1adoTOntljYONmmu8HZfkdFpsoTV1I1g334tj7SEcaqE5PfM1pBPUIlniIKfjBxdE8GBOiHMxMMz+/MdpNw4TGPqd1R6sq3PjUn8BxoNF0f7ENTLHT2NfHpO9OCqCkqJr6Qsw1Qv77RyqnDivXrXIMEkWLay/5q5ofHfftd74EUr2cq7K9YI+W39D0wEe19zpG1hQ7Jf/TgfM73t4h1lUnetA1kyGHu9jJ7ZMsu98bJ6ZHN8o1prYS9M58RZj7Q2alAnEm4rdFgv4agwOW8hyQL6f0Rb3HzzBqUYRJkvN45U/NRsQ12+iQDr7fCbPfzZ5bCf/ivj4yHvvvWntzKZPTt65I4E5AwzJ11BmTiEdTqci4BvBUE8TBCLIvCxRql24AflH+1BT2I+WATFcqGAJtTDgj8AhqYFAVTlDS5ayjuAF+uKhwkVzKWkXUryk/l3eS4kjXZzFLAq7nFfSfKqkCu0Mrfvy4RaG2s3FjjsYqaxIPnIuJ4ExxiSNdSuqGhs3N+U3yD6Wo+jt6xfh8JlWHD9zDtUrViA1gxofsyq3zRwa9wUxMOpj6MyoiRg7FCY4VZ5ThvISC0ARKDQ8PIzD53txvIlLotklrIN91wqGAC8jAynU0cpNb678MOHuMwT48CugfGxnbHwCfQzJWZSdiTQ6EDXKNu+Zeigd7c1m7qjuCPqHB9HV30f2TwCbGwL0ixCA2FzJ0sRwF/0sdRtgKEDH02lZxfQ5VJIs+025LrBBL8tNTU147LHH8M53vtO8KDc2NhpwaO/evfirv/orLFy4EH/2Z3+GD33oQzelH06lU0tAYN3Fixdx+vRpY/7U0tIyWUCATy0j/MUnlYnN9+u//usG5IvP93Y6f+qppxghKh1f/OIXJ8HPt9P4nbHeWAnk08dfXcNaHO85zKhfXlSTNfQynU+/cGwQQbJM19Xl4ZENpThJ5tA/7+9HQUkOdhCgOdQ2RpOsANatZp4FARxoJNvVl0Wgh/Okh3NtNGn+FdyiGVmsITOv00SNPGJe5azNaa5tkCzaoXQGiLACJZiinJIU8aybTqEPt3Pe5DkriSYduLCmzIVPbcnBXQvz4Bvy0wzMg9oUP5amhnCJL0Q90eAL0g2qyBLaSECI3UHvhAd9BGSgbmqe1UVmSnMN85LOeZ3JREXlvVi2kHUn8aelswRRV0bH0cUh7LkYQOsgTdSo0jy41IOGshQcJTj0zCmNn2Zu6R40kUF8aYTmZPlhLCVY1NTuwpC7DLX5lYkbmeNXY18e9VKqLVHSi9JcSnq5stlBtm+b5csWYOmShklTqGvtr/Szjzz+bsPc+Mo/PZu0mtmwN5JWcptvJJKjgLUF86353TYru83dvObmY4HPRJVM9Z1PlD/ZNf193CjWmm2ato8Ahf0dj21XjKk33jhM87U1BliIvWcfx4/7RgFgdv1vtb3k8Y/8W5YTbv3dlpUWmfcpRVxUUhABsb4qK0vwxu4jeOzR+28aYCNTwC/9n2+Zd8XdBPgExD78nnveaiJ1+nuTJJB4Br5JjU1VbUZ2gQEIFHUs5PcRwBknyELD+SQpt7gWxYXZWFTpJjBErUyKGoEhARdSLC0wgwoW/ftk0TOjm84dLdDIAk9IE6KpFxU5rvoZ5hDbIbREhVQqodE9rRVBrQLml+BYdzM8Lx1nGMl0Ripbi+zsbJNPH1YJNs/6DCspqiQafdE+Zr4FjAjxyL1rMfyzQxjo6jah61XeMvuyMvoJLvmNI2yORZotQZ6Nq+Zj0+oFBFMsxUigkGELXaIiTvAqQjvxCFdPldeM28gigiqyi2yGkdqJT/n5+Vi6sI75LuBif8SAIxp/KkMNm6QuaXDa7HHYx9zLr1D/yLDll4jId0FuGnIKypEzBZ09zNXRSJieNKXks84Umg8mij7HDDclCRT63Oc+Z5gT2t93331mVUqNiUUhUO3ll182ebq6CGLRXO9GJbX97LPPGpDjrrvuwh//8R+/rZks08m1urragHKPPvoovvGNb+Bv//ZvDbAhUOjpp5/GRz7ykauq0DN85ZVXjNmU2GDyxfV2Tzk5OXj3u9+NN998E9/5znfmhDi+/e1vG6Cqvr4en/nMZxxm3px4KjPrhFgyYzQLG6YD6jzOA5WMMlaczQheE2FsWpSP33+gDml8SfnJuQGsqswk2yUHHT0T6Oqd4OIDFy4IpWTSUbJHc4BMybRp7jbOnK0+iGkjX0MyHzMLFJrbOFeHXMYFM/w0n+LayeS0pFIqIzCpeTCC9qNhmn7JBIz+j4wZmHJE0Mv2f3Koi9EzU7GqJJtz7QAujrvxq4EUXKS5dkwXDNuon+NsG+Wqbg7N33KAZvobMibnfDEqTpcPoBSCUX50DbjQO0hh5GmitDb1R7qItdCk9uOS7mnsIT8ZVH4uqngtMzIynVZWeRgNzYPVpS6sM+ssjERGt4uneW9VIUE1ztFDmphp95aWmYIc6imK2PZWTApTrhclpbnmDHkqeYoFomhp0iGffvLXzAuyXs5vFICVQRbbRz78LrTQl81UUbpsf0M1NBO7WQyDqeRwvfdktqRw6/sPnjQhzD/1iceNDG+UHK+lf+3RKHPJygrkmKmspYPY3+9k9d2o6/Ld8+gj90OOyatopXCtSbKfzjRtOtZQLOAreSk8/dvVt9CPfvwy/v7L38b5C814z0N34/d/70OTzs1lHi0ATgCwoi6KMRgIBm/ad0ZArMwax8etd5vTZxpxsantWr8qTrn/ghKYM8CQmyuGWWSOZBEgCod8GBtqwVDXRYatT+wATg6oy4vzyAaithahh0kCEwJlXFQcUxjtpL4004AiWnnZtm4xdh9pxp5GaoqK4CWqODdFWme8Vypu9pPVBUvBNMoc/0Bd/IF0k80UyCslxbsJRa+cQHFBDlZyZSibL1xKwmHE1lH7EcMYslRDw+DRzWjSj62cUOvSv/9kP3q4OljMFyPbH5Byjk0EMDrOPqo+ZRzsRV1tCLV5FlgzMjKCi4zK8fKBS4YtFM6go2wPaexqW/mjm85TIn5ulsJl9yF2LxpjCplBMqdzETjLSM9AFplNOreBtaiOa+rVNVVvX9Nkpx8w++LC2lIsmVdO0SZXUH00I/NN9BuMLsQHkMUIZdpuRbJBoZdeesn4WBFTKC2BWaCui3UiICKWfXK9fdy5cye+9rWvGbBCrK8tW7YkBDeut53/KuU9fPkRsKvtHe94hwHUBGzousAOmUQlSg8//DAWL16Mv/7rv050+215Td9z/RbOhaS/QwF9hw8fxrFjx7B582YHGJoLD2YWfcgrXomly9YhQMfNKzjXrKoMoHk4FR/bUob1NVkYGPBiJeesn50ZxP8mopFDxtB4wE1zMhf99gFrGnxYRROol07m0EcOmbxkDUU4P04mzjOajQULcWYzn5p3FKpeXok6xjPRza2wnnoAHTSnsg9BvqBrLrL8C7kw3sKyXAey1lMs0KiDPoI6yLjxMnpmX7cPb7ZF8KP2VJwcJUyluS0u6ZoAKCWPpR4YIEAIUlkOATGa0mlCDHGBI+Sh7Zf6zc34Fooem8IJPlxcSZIp3eqaITKo/DjWEcLBZi6KsZ0BqipfO0gIjRraqgo3VvEdbzV9M21YQBDrIhfDGCXtfjrPXsUAHEMTIdQtWofq+jUJWpnbl7SKHutAuY7+dWqmcPo7l0Yj/WdkdMwAcjfrxV9Ruj78oXcafy+xcoqVg+1vqLa2YtYh7GPruV3HWswRW32IbHWfN/li8K3sn/qkF/ZkaTYsHznPlklgsnQjwVAxff7ov3/M6Jia79MJLl5rUl1yRC1fT4m+e1OxhuLZQpJXrEP5a+3TW7GcZPHs936Os+eajO+wxz/wDqxYsfAKk9gHH9hmzOy+9/1f4Kv/9D3D0rKZdFOZ6l2LPCrKSww76PyFFvNc5c9s3Zql11KVU+a/qATmDDAk+aYyWlV6Vg68BA7GB9vR20IQpmYZryV2ZpwbaUNNzgCBCIbNpfropkbGQO+4c1U9PvDgatRUWoDD9o1LDKsl8s1d2NvYg5BMr1yZRvMUSCSAJEJ/Q9TjjFImVU/KHRcrjaIZpmbpJmtI4XZfPtVMRXMvfp23BA7FJgPORCcT1TUJrvBYEcSU9IJ21+ZlqKooxOGzHXiDW5uPPhuKizE0HkD3sI9gC1Vh1TPUiw2FITyypQE15QXopfPqoyfO4js/O4pfHe9BICMPYcomkkofDVF2EfxeuOnAe8viEjz56HqsXzXPtJvs45EHaZKXl42//9YrOHiuFyHfKPyk9+tZaAyxiZLiqRRsKwW42hkgCKfLhXlZdPbpR0akA0EfHY+m0ytmguQb64NvtMeSDSsSQ+xWMYYuXLiAM2fO0NHfJtx9990JQSF1Wc/o/vvvx6uvvmpYRAmGcU2XKioqUFJSYlgv8lWlzUkzk8BsgA3lXbZsGXbs2MHQqnsMuCdmipPmhgT0d3ju3DnztyUF3P5tnBu9c3oxEwkUFNVisKMCYz10PE1Gbgp98g3QL95Pdrfjx3s6cGwohFHOxoxaz3nUja3zcrCQaMn+1jHspR+dtWs92LQ0iCOXxtHr42IEGS+G+RqzqKAZWVOw5hxjFsY5kRAM6CIQfvos6hjNQd9ENtk8QwSHaF42YaYi1NG8bGM9JyX+F2tIe5XXcWVBHt69NB3z0obw6nkvvncpFcdHEoNCark6N4J15WEq8aAZnNUbXZfOUEST8vycdBw6O8HInVSlCEppQUlgljZLo2DDiZLyERBzBSfIsvJh9Xwf9p4Lwkfzag06SMfTS2n2RhdI+EWbGz/tYQS40yHcX0fQiMhRJxd7ZfWWmZGCzrECTARLCJjfGnXOfmFpb4sxpWIkrY0bVkzpbySRGOLZFAL956oPofj+t5HJoxf+6qqbN49rMXE6Z8Dql4Cp7zz7U2PC9uQnPzzr5xA/trfzub7fz7+wKyEYIrmI/fKpTz4+Y8ZQ8zQRzG4kGKrvS1YWXVRA2/WlmXz3krGG4tlCs5HX9fV67pWWLOxodPKxdMf2dVf9xgk4K8jPxX07tuDgoVPGgbhxcD4FOHmtI7Wfq4gLza2dxhxQDv2d5EjAlsCt0STs1qbZu6kUWEABu+WimVLHSQx0nEXFgs1XlAz6RzA6cBGZafQRkOJDbYEPd2/bTjBoDf3w5KGaIEoGfQeMjjJmbTRtJFj09b/5TbR2DeLAsUb84I0mvNk6QTiJABGTm4pamE6rqZYZBc8oeVRkLUeXBEO4GunKyoOfQMxBhjpZfPQCKssLjemR8ppoZzIBizKGTDV86RE4JJaPHBuLJZKXl0eKZxUWNVSioZbgQMFZHCDYNBgaQAsddw619pKan4EN8wqwYVs9tq5dgNryfHR2duDVN0/guz8/SmWa4I0rjU47M7lZbCEBQttr0/DI1kUMDzyf5mH5lA0joY0M0emsRRlUn2KTfoxSGIZ+86pafOP/+RjaOukvqHcYXT2U0ekhtPdxXNSozSYFX+PkJkV9lGZk3QN9jDRDxwu8tjS/WbZl8PYOovtsBEX1O5CRVxvbHMYGmjHWd5Eyo8NR4y/isqJ9RcabdCIfQpcuXYJAgunYEwsXWv6FjA+mG9SfhoYGfPSjHzW+jQQ8ySmyk26OBPSCIWBIz1p/b06aOxJ4/PHHITNWmZPp+Tg+vObOs5lpT2RO5kotx7Avn2ZZE1hbk4pDPQG82OY1c2WQ5s0uUmyqizPwAE3J5Ix6lPPDyIgfu1uC2FLtwZZlQew7PYZfnsjgC206ma8Eh4TA2IlTjeZjgSwkCvGT58ZcnEAPjwOcd8ToWcl5b3kfw8qf1+ILHUS3hkHLNTqOptdAVcBNZCKljTTRWsGIaHsvefGdRg+OD9M8zbp1xacAoSqaj3XSjKyb7BwlYkHGpKyD15RWFAWxKDuIA+OMEJpajUhmngUKsV9TmpCxrCKRuQMTWF3dj63L/Djd6ce/vT6C4/RnuKoiBR9dk4I15W6cJdHgm+dcODjqRjMjuu3v9rO/Icwv8mB5QRgTZGGlZlUh5xb4F7JfmH/0/EtoIYtAZtd6eVHSy8Yd9I/x6CP3TQkQ2X42bAaCn4DGONkidpJJ0de/8SP7FE996iP4xO9+cPJ8LhxIDnIeK18h9vhvZr+kp83E35CXbJtf/Wo/NhGgk0PZt0LS90EmNPb3YS70Wf5XniNzIxELrJoA6AfJ+JBzZj2XmSQxj6b6nsxlMFRjnMoRtcYV72soni0kMGQ28pqJTN8qefRbcam53XyX9N2pr6ua8nsT69vpZo5Rz3XHPZvM9zI1jcQKzudOciRgS2Bmv2x27pu899CsSS/sUjJS6GTRN96Frgt7LL81xfUM4T5GJlETRvvPY3yoHd7RDpRmDGJpKcPO+klF7e8iPbyVzmqpuFFhlCJpJa3e8Ro1O9XvpyLiGetFymiAPgtKqXRmGEVz0r+QwA8pdwKG2Bet/Lm4TOmiPx9XcSW6CJg898oF+i7KwNY1Qlqj7RkQxVKUTPvqALfBwUHs3HMGP3vjHAq4wji/mqDPqgZs27CMvoPmYcvahWZF088fWSlbMuVKo0YbJhtnaGgAb+47jJffPItfHSG7aIgsnZQshDJyEU7PJmijrnL1keXCATqtHh3E6RMncOyw5VvlMpgTFUXsju2w50Yu2ssBtoCisVE/Bvq60N8borlcEenspMgrRW3uRsbGcamT4en7+6N0WxdWVIyjPINRXpoHEAmMwjvcTJ/Yy5BftQUZudV0KD6MfkacG+w+wXaifl+kaVs9MNXfzA85JRYoJIaCzMPsCGTJ2tRkLdbJjUxiKSnKmfogVos2J908CSxcuBANDQ3G9OzmteLUPFsJyDTwoYceMv699HeWISf8TnrLSSCvoIrsnRKCM70MOJANVxoXLPwRLCxIQ3VRJlkw+Xj/mmI0FKebOeV89yCqPEEcHY5gT2sAa9enYcuKkMUa8qbTrCoBa0hzMVPU6x3naZqLa57l1HGkuwjHe4uxobgJeQRaNEuJodREf3mXhjkxan4RA8kjczRGFqtJwzvrxtHa68O3zrlxlH6BQkSMaugXSD6ElNro1FnATywgZG5EP9i0SSuK0xjyPh9ZaeM41JiBkx05cDE6mxaYpgOFjG4R9S20eUkAq+eNYc9ZgmZcvwlyYGW0+Nx7IYydl8hOqPXg3gZgPaOF1lKuI6EM/LQxjOx0N03zPOgnCyq/ohpyCH4zk172BNq8vvsQSooL8cSvvYdRo+4xpku2f4yXdr5pVsYFEAnQSeSDpaysCAsX1aOvf8h0V6wbmRAp6cWpqrLMHOtDJhTLls6fPL8VB23tXcZv0E9//nrC5nRfpjUCDbxe0rluUXor+huSn5s//8svT/rGjBWV5NhBEysbGEwEwsTmv9nHNtj3/As78cprB+Dl31t80vfz6Sc/ig994MEpX+5jy6neqczIYvPO1eNYsCKRI+p41lA8W2jbljUzltdclcG19kvAmQ0Kdnb24uDhUwTJ1idl9Ond1/btdK1tzrScwKE54l1gpl128t0iCcwtYIgvCR5+WaXMeVLkAyhogIQL+8dRWNHAF2n6BhjrwvBAO0aHe+irZgyFaYPYVJeOHxw7gTf2nbbQIOqDJhlaOsEPG4AweqKBeUjZJhCSRv88fEl30c+QAJwwFUhFJpNiZ8AWAUM8dnPlMeKmQqpVUjfVz+xiKpdj+OkbZ0nF68Lpi70EdLjiST8Jxq+QGpcCyR+F9s5+7Bztw68ONHEV04PxjBy0nhvDz/f+CtnffA3LFzLCSwXZPfwLLaLvIp/Ph/5BKkos39YzhCMMR9895DP99bMfITeZQllFCAkUUhtChqithgha7edq7cnGU/D4x1icN839aGc0Jh0qWQXNGK3j6CXmyMnMQLZe1OjUMp3gU+x9FROra3B8FJ19NGWjcqRGllX4UZHrRSpZXsNU+r3eM8jpbUdxBR2cDZxHeg5fIAhyDbSfxMRoN8McX14hnBgdwPhIP7Jyb66fITkytpkjYg7JTOyee+6Z0vmzXlpvZHLAoBspzenrMitxN/gZTt+qk2MmEnD+FmYipbmdx51WZgCJyOh5LMoPYUWp25g43bu0AE/tqCI1PhNdncP44S/byNAZQx/nlKycLNTTGetuhmTfXBWGgJF9pybwi2NZBIboX0esIQV8iEmag5XsX2OBM/Il2D6cifaRbJpXuRltjP6LuoI4T4fYnHbp64+TvRZBOYczNzbU5uG31zBQAxct/uNUBIf73FhPImFlbpi+iqzIZo8uCsFHVeArh1IMOJTI55D6oZRDcDMrNYBDZ8ZwsCmL0djIemI/Le3C6q+V8+pPmy20rnYQW5f4cLzVj6+/PmaxhSrJBCKrqU3BIAIROreOYG15CKkEgsbo3PvrJ0M4SwfYv93gxg5uxy9ykaukGAVTBHy4ugezuyJQ6Etf/hZefe2g8UUh0EfmEPJfopVm+cfQS8aXvvyMYX4IIKqoKEno76aWPoT+kBFwAjTFUfrS/3nGMEZ0rHuqe+P65To1ukYGfR7eyqSXuHPnL+HCxZaEzcaypBJmuIkX32r+hgQYyIwqUbqdctT3uadngH5cZArZi3iwLx6kEiD0yHvvIxvuXiyiyY0iDM80xQIDMy0z1/LFghXP/3jnVd3TGG3WkEKv737zyCTbyglPf1lcsXKaitEnIK6+thLd/I5Ol2xAc//BE+a7XE2H43oGmzdN7Rxd5QTy7SPz0cPFkfc+vCMpWGX34VrbUvmp2tM923Rzpv23+xS7j61H12db1/WML7Yf/xWO5xQwJAVOjosNkEMwh2x0+oYexnD/WbKH2umHgB6ESL/2eccQDNBBM1ky2dn0ryPHjzRPGhgjo8eAQFQMzWqhBQopaoTAJgE7zGDaMB4pqagSzTH16LpJ0ukIEAnwEINGuqUcXrq0RCmFU2ARQZlQUTWOkFVzobebIXvpRJnmXxFqksY3kCpiFXmlZTjQ3o+fN16kfyIPyhctQlYBfQKxXj9ZN319/djVOIgA/QVxQOwS1UqWC0WXJcPcB/ijK9AnonC+VEZD6bnsA8+VkZtl6qWOcbWU0V4C4Qx4CMKY+7zIywY4MnlNGfVN+TlunSsPZaD72iTjnNxssoRIL4zxWWBJx4WRsTH0Dw1ZTqfNRa5wZjG+bsRHppOciLoIDE0gyPGMc4zd7U3IzqWPKMp/dIi+o8aGmMfy2cCmTOQ5PcubnQQSzJs3zwBBYgvt2rULO3bscJw/32zBO/W/rSTw+c9/3jDhPv3pT7+txv12HGx+QTUKylajpf8YyrJ7sa0hHccHAjjTPobXDrTj/HAILzQxJH2A/ngY3OAOmpu9a0UB3mgiOHPUjz3NDF2/0YX3bPWjhSbMp7rFFo6yhjT5x6RYcEhTtaZIRRPtHM3kgksmlleOYU23G62NEUwInrGmNk1vJm2o4BTERaB/PxbEQTrAlgPrw13AMR5XMnLZ+wgKyWdPD6OQ1dCMzDYXi+nC5OGq0jQ8sTINS3LHsO/8GHwp5Zybc40ZmelntM3JAjEHMoVzM7iGi4sjGxdNYFX9BL6604u9zSE6z3ZjeYkH71hAk/rFQBfXT9q6I/gy2U0n6YfQS6JtP6fqpTQhW1PEuZgLTdkla1Fdt9bSbWLauVGHsaCQ2D4yo5EJgoAgO+lY12RaJZMgvVgLRNqyedVVJk16ybR9oEgR76fzcjvJebJ8XeTT18btTHP1ZV6yeyv5G5qLchQI9NwPfkFdm15J+XsgM69kIJXMIu3oURmMRmwDobfzu3m72p7OEbVAwOe+/6J541C0PqW3e3j6RM/KltNUEQT1d/40I7jp/c/6rby6JhsEkVlvkMSGkhLLrcmZM43o7OpDGn+TxTyK9e1kl/nxf+40rEf9fcrHm57TurX0e0uGZqJkl1Nbl5o7UFZaxPfyEHbuetP8HSVqy65H0dj+8WvfS9je/8/ee8DXdZRp488t6l2y1SzZknuTe4ud4hTSC0kIJdQlQD522eXbj7IsW37ssruwu8DCP9/y0ZaeQEhCgCQkIc0EYsd2nMRx712WrN7bLf/nmXNHPrq+V7qSLccOd+yjc86cmXdm3jPnzswzb9H6U4CQ6B6klzSNG2q7vs3qqnJ8khsIN990hSUV96wx6ltUR9X4U1SYj4kTCwwQlUj9RDSR9t31jmtxLz3JxeNR3MpdpA9Oj+4XQAOCgV7ukvXYuRxncs7srp9xA3ymEObESj/kdsbnp6RNCY0ezyzuwr6GCQb4cUAgzvK8dCXLTuYx58g10QgPAQ+PJAkUz+mcJoymUO0uChTSrFIH7/VxClhypIWca2OwOpWubgsmQQJEE+mmPZV0fQRvQgOq2+mQmp2PoqmzWC8aNc6kuL3+cWablplJC5rcBQxkYSCT5VMNjF8GdzodwIsiU6wCM7EaIbYhTBCLlwya9CrSAXR07dgAYrmMC0rNjJUSn0waAUCMFxDExhgQyDyjRxQDCIkOpaE4Spo86TlFKClju0wWls/g0A/TPXEXjpw8gYbmJlOvyB+UZbbT+Ge7SWsqyWwBeisLBjlp7qOL4k451qW0EwGrEOuha/0X7tRavx9NtfuQW8iZ+zgHqXJdeumlxmX3/v37ce+99xoX3m+G23iptnm5EKioqDinrR4vuue0kueB2MUEUMhLl4BLqRlezEE2g374wx8aO1qJtuN89FeVITB48uTJ5/x7S7Sdb8V0GhMLihdTqncrelvW0eZN2LhX33xyAD2vtaCDY9bRPlkIArq5afHoCXrcTGnHpRVUwa7Kwka6CFtF4OOauZQa2t2DXScImPgpAcNvIUgJHLf7evHPgkParNH4oWFta90EbKOXlauqerCkjBI0DUHspsCth3MHye8oLOS0INTXgR9t9WLLKY5NjJ+UR3tDkzgp7BIYREPOhigliCihs5KSTPMLQjhGtbJnjw0FqEQvN7eMHlEzuQFzAFuO5GJXQxHnARzVzLxBKeIEPpcXMi9BoSVVnVg1O4jtbPOmQ5zfsE6l6R4crg/hvvVBzKLDxdVVHlw2x4MZbWEcbAliXZ0Pf+Qe0urKFKys8GLHoV5kT6nB5KlL4xR4dtFuUEiT9lUrFlBSaNEQUMiWIHCoagqlcrm40E60FkBaRAwX5KZcalk2nEsjvJbmaM+SDpHx5ngLEi0iZF9IKkdvhl0c8Xk4my+2vReCvSELrJTFWHBaPkrNygKKtu7jeXbAqsQ2IpubWrnJ2U8j8/yxuECC+PbNbz2Ix5/4/ahrtHyURrPdBVhQUqBPrH4vvkoFT0G/FQpJaSFJrVDa7NYrcYju4MU3yyfN/f+K4E8sdVvxLiszQ6eYQb/LVq33husuxb0fuwuVk7g5wbCB70fPVNYzz20w78KWo7Lz87Jx2eoleHnT6feo9+Wsqc8sTv3tvm/+zNjcWlAzE9/42t8YIEkp1Rd+8/g6vLJlxxll6bny9lElM1Z5x2j0+pcEhGTLS6rJ8+ZOh9SKraribgJcX/vGT0Qm7m+xngl4uu+/f0Y7un341P/+gNmIUF9VWx/51bODHt7EC21s6LfIDe64eRmrfdb+2U/uf8yAyH8qhv0vGGCot7MOPe3H+UMsr1g0aGyCJnaaVgoMUoTQCjMnNLGKUSjlhHRacS8q6JbkWCsBFwXNGj0CQohACmCKgEwCUiTyLekfM3kkIHI6MF6BJyWRQJGT1Zn0ybaBAxARnGHVPDSYGaR6my+LLrUp6i3Aw5EYciakDi2CQBl0mRKpuwirlCCli/oClBySvDqlaSgrToCGR6okeXQwkUAbXSjP4DUrHnVvgSInvUpi+aygU1Lk7JBxqqRr8VNn88cpJ502bzIJWPkJmImm4b7K4j9JCh05WYu65sYh0kLLyuowo6iVYvURPkaabiW3BKyFCHhZjmi3V0GnVLa1u/0YTh7ahtKq+cjI5mx4HMP06dPx/ve/3xh/lreq9vZ2fPvb38ahQ4eM+/rRLsy14HzwwQexYcMGU2u7yBUdAT4Codw09Xz9+vUGmFKGT3/603EXqjat0uvQQCJa7373u4fQtOyydXnggQdw2WWX4bOf/ayhbeNtHSsrK+PSsLTs2V0HLax1b+sRq33ufEr/0ksvDfJG5Q6Xx+Y9F2fVc/fu3Zg6dWpccu62ufkbr45Kb3lg38l73/teREvGRKdTnve85z0xDSwLEPrKV75i+uNnPvMZ816V3/YpXVt+x3vv0Q1UHls/W1/RKCsrw65du6KTx72ProeMRMtotAymi0fuYNPKBb28jem9/+d//qc7ScxvQe1UfxUf9S3EC5a++rCuLU/ivStLR2nFi/vvv99E/c3f/M0Z34SbXqI8tvSTZ0DeyfKLF+JY03ZMzKyjcecwdtCg87ZejTs6nFCWl4p3z83FnTUFyCaIcpL2/V47AUoP9WNpcRruuCyIE3Rc8MIuH8drbYIQHJJKmR0wInSiwaET7Vl4rX4CaoobMaekG4tKwzhKdbIuZ/TCwokeLKLZmtcJQL3eyI0TbQRx8KmkXaFqCrKeIihUG7ErtLyMqt+0L7SVkkfCifrNnCNScOS0qDQNH6ZHtXk5rdiwqZdtKKcHsVxj92hoyjPv5IXM29+NBeWNuOfaDiyY0otvPtuNV2ksu5Ru799Lg9Mz8uiB7BDw0Ek/ft/qxdXFA7hyphelkzLR0ezB9KJ+LCwKoZ3SQhlFC1ExZSmBtPGZxmk3ubu71ywutKt85+3XEFyNb8tocmUJtBOuyb0m5gJ+dO2eiLu5Eu0S3Kj+8rfqzQw+bsLlUGJ6InfgY4XCgjzMnkn7kJcsxDfuu39MC/RYdEcTJ+kN7aaLx8MBBIlIJ4ym3NGmTU9LM6BKLF5aPmpB+ouHnzZ2eOyicLTljCa9Bf4WL54zIsBnF9k+X/wF/GjKPhdp9c47OrrQ0DiymlF0ebLlNRABbaKfJXIvUFL2w+KBQ27aSWkhh6MWUNNvoUBQ9XHxad2Lm6nGtf0MqZ6R3oMbrL/pxsvxl39xN6ZNqxw0Hn31lSvpqKhxsCyVY9XKBFLd8fZrDAiU6DcnQ+y/+MVTEGjyCar5uo2IS4V46tRKfOP//tR4UXOXpXaUcsNGKpjR37iA4De278OihbPwf7/xeQM0xQJzpNL7h/WvYQlVi2ONIeLFLx56mhKm2fjcZz6Myy9bOkTN0+3hTTyPJcUqe1iq9+KFs2O2T33eqkhfbIb9R+pLwz0fnxnFcCXGedbbUUvv7PvR291u7NE4yZxpJbGJISHqlqCMH1MK+1BT1k5gSEiroAwZqRT8QEkYzQQjE0zF2Amrpq20ZiScxQk68zCgiCKFnnD3UpI7xjuZxGgIdBgJIkPSgz5K/fT100gz3fWqVIFNCs5f94WuB2PRTSNHXZQNDwkYMmUxN8+DoJDiDBjkBolYHxPnpFW+09JAkbx8rnoLoHIkg0THubfxOg/N69wPUKWrqaXV2HLo6+9HD1XCBHaJdUaFjEa0B6giZoLqx1Cd346irF4j/ePE8y/T67HDcqUT14cGxfr9YUoW9eLU0Tdw6tgiTJmzemiic3yniec111xjFuJaNOvo6enBk08+iRdffBFXXnmlWaC6wZxYVbALVS1qZRNq2bJlZsE5g6qCWhR/97vfNYvXD37wg7CAiEAASbGonN7eXrPA1sQ4VrBpDx8+jDvuuAP/+I//aBbEv/zlL/GTn/zkjHpKUuM//uM/zKJctJcsWULvJL/HQw89ZOqjNmqSryAeiIbqFk9Syt0+SX6pfbNnz8Zw7bPtUN4vf/nLZkGuut9zzz2m7hs3bsTvfvc70/7Pf/7zMcEtS+NszwL6ZGg8HjBk+aW2qY4f+hC9FbIvbNq0Cf/zP/9jVKGi+4Joisd6N3KvLn7edtttZ1Q1Op0GRfHPHSwgpL7QRcBV9q/0rgWmqE8JXBF92z+2b9+OgwcPYji+Rb8ztUvG00VXffKpp54apOeuS/S1paM6Tpw4kaq6WWhsbMS2bdvw7LPPmn5jQUfltX31hRdeMP1adda14t3hH/7hH8w7t21XndQv1V91jhVsXex3pjZdddVVQ96V3lMsvth62e9N0kKKE7g0Vh7HquOfepxbaijQ0oiawiDmU9Xp+To/5hb6UZZLlavybNxOQKiYOM9re5uw4VAnMrNSsWRSFh4/3EPvogF8ZIkXd1zeR3t6rdhRx1GZmyWSGArRGUJ0EDjkwE60Q8ixeXtDMXbREcLlFUdw/XR6I+2j4eZabmbwGYdl7KSA6+sNHGs0KnN81qYFfTtQDU0jU5hqcGEjHfTEAXo2I0gkx6LySnacAJc7lOX4CWzlYVVJJ7a81oQfriukKloRQKBrpCBQyEdQqITOMm5d0UXbSr3YvK8DGwmMDbCds4t8lMj14OH6MPZ2+XCKHlKben04eDIFx6njlsNx90BtiMa80420UFt3GJVTl4+rtJDdLVXbNEGWOs1w3msE2Hq5W2uDFrHxdqKVppbGh7VYUtCCPZZkiXl4Af3RAsbnSzXg0GVrluBV7syf76A6zJg+Be+66zrDv1gSHKqT+C8pDqnoRe+Un+86R5dn+aj4aVMrBgHF6HTn+t4CfzXzZowI8NkFvO2bsRanI9VPi/GR8kmyYjgANbqM5bQfI7BN+SStMRKgpvovWzIPl6xaeNbfmGyLHT5SOwg8RNfN3ielhSwnnN9OeRXUb6GkvSw41Eqgzkr1rFq5YBDAOZ3zzCsBGdbW2zup1usGhZRav9NuiUL1YR0K7m9Ov+Xu32qTIOqPgJeXCMzIEHssz3Iqa8b0yXR3vwhyQKB2Kb3aIkkod3nub1z1MaDWn7/HqA6Ljg3vv/sWM8ZYPh2hpJWkSqO/IQuQvUR+CIQUmB9t+yvaaLpUzCSdZINoWHtY8donFWl9Zxqn3myg3db7fJxPv5HzUVqcMuRprKNpD7pppLm3R3LgTCjkIHIhgCGCQ5goYS/mcYSenpdT537axH5UnKTXkTZHZctkYkYDkEgyiAkF8IQpSeRItNjppeIixEjZKV4lcJJjTozRTpZBO1R4JB+jO3vCnMzSixivs+hJzQZTP4eQjTpdaT7so8pZ34DUuVgvJTb1PA34mPsICGSvbRqdDchj8lmwSECQE2+BH4FITjoBP046N63BdCafjHbSECcn2C2UpJGxaKl+KagZQaMaRhr25TByaWkdZha1ISNFE0AZ8GR5SqxUkbMiXJeRhzZZmIvwoPFgdnTnH406WUHJVCfNOP2V0ds/+7M/M4aoBdRIckgLfR2PP/64OcdaaNrqWOBDNooEDLzrXe8yAIQAFwWpqAl4kTSEFr12cV9aWkoVhFwjpWRpxToLtPjSl75kwJ0vfvGLBoyRJz3RkSTQv/7rv+LXv/41jXuWDoJOdgEvkEFBNE6ePIlbb70VWpBXVFQYcEZ10iEQRGDYypUrz7CxZNv34x//GLfffrsBj6ZS8sa2T3ySZMhXv/pV7N271wAPoq9gF+Na6KvuWsTbuksqRPm+/vWv49/+7d9iLuYNkQT+qI6f+MQncN9998WUXhGIIl4INIgOeucqf9GiRQYEVB21oNGg7W6b+oKbxwILlU/8F+AWL8RKZ/uAzbNixQpce+212LJlC1paWsy7kVSLJFa+//3vDxpJt5I36qMC1QRuWKDR0tLZ8v3AgQODfVIgnm2X+uRI9XbTER8++clPGikfxT///PMG1LT1WL169WC/EY+kkilPY5Yvd9555xkSUtbDn7vtApxsm1SOO9g2CWSy/TBWm/QtiE/RQGf09ybATn16rDx21y15PZQDQ6SGsuo4LoSxrZWODLg580ECKavnT8SRU12476V6PHWgE1NLs3Fzbgqa23vpSSyMF4+FUTOhHzfMpY08eh793pMe7KTUjgMO0cmCL8Y0RUMNxy1qeeN4czqeOVCJ0qwuSq824obZHjRwbH2ZIMsbPMJEgcxIdhqzoPcxZ0ivJRgj8OhoBASamBnGKye9lEKiOLqGO1e4vaYMd85Lx0DLIby03ct09LaZNbKaiYdjvG+gl9JCnbjp0nbctLIbWw524tsvduG1k3RPT4PTpblebCRGUk4D3ndWU4XtJMErYmK53DzZfCxAb2TA5AIa2aa00K7DA2gJzcbqufP4uxyDN646j/XSLkDsokKL0XhqD7aMSZQWcoM7tbTnIvBHUkSxggwTH6f6gIIMT8dLFyvvmx2nRY8WNCMtrsarnip/LPaGxqs+Z0M3GlA8G1qJ5rWLVkl//Z9Pvt9kiyV9pf4fS9JgNOWM1EdGAlDdZQlouuuOa818RfMKLYyt6pA7nb3WolkG3VcRFJLdULkmP5ugPu9e5MeilZQWOpMr8ip497tv4tyueMj7Uv+SxIreo6SxrNrXmRToqdIFZEyhDZ7q6oqYQL3bHpSA/JF+t2OVpTjrXU7A4pTJ5eb3LjqtvqOqKWWDwO5hqg9LhTi6TPc3rv4hUGvmzKoz6i8+ZVKNzn4z8b4NK80q9bDbbr3qjPJUT9VNdpa0Abxx0zbDr4qK02ORbd9w/VX93YJoqssB2kKK1b5ovlzs92f3K3GWrZf7+S6CQm10Yd7RfDRKWkjEOfvTX+dkrhXlvg0QYOno6GPefkzKTsElU9Lw0NZMpomAGFzwCaQweXi20IaJiQAizjUX9rQvFA5T1Jwgiodnukgx9ncMmMQPzKiREZUKy+YQiQpM0oKyka5xc1K8yE6h23t3ZV0VZS5Tf6mOtXYP4BRdwnf10KYQ86t84TYOsKNbC/LYONVLaUyiSDrSi9R/UDrIAEmRvEobuTf0zL3yO4ehZejJtpBoOVJF/ZzEamFoaItbqrZpk1N/9/XsikxUllci2NOKTi5wUwkQEcPgQbf3vHbAN+UjoyLB3tmzz8sZLzrRcPRV7N+SgRnLbqJqwviCQ9ZdtsAOLfa14FVQu7UAlzv7v/u7vztjcWtBkx/84AfQAvfqq69GTU3NIGgiGvPnz8cXvvAFY2clLS1tELiorq42KjMCLWx5Su8OWgwLPCkoKDDqR7Foa3Gsej733HMGKNJCV7aT7r77biMlI9BHEkMCTgSMCAhTOydMmIDs7Gzq8Z4YtLGkukSHn/70p1D7li5dive9731ntE8SJAICqqqqDG3xwQYt4gXISC1Iklkq2wbxXHk1mRGPo9XsbLpEzqKRTyPuM2fONMCCO49cn9fX1xvAxR2va/FXUi9SIZRHuuuuu25IHVW/G264wdid+vnPf274oPem9qgterfiv0I8QMOmU9+QdIreR3RQGj2XZzyVo/ZY8EP1tyDczTffTLFg2eFwpNuigTjRVZvUh9UfVE+Bmm4aSqN6S+pMwYI35sb1x01HKlfu9yfX8uqzOtT3rPSZsos/4oX6lW3vrFmzcNNNN7moa5B2gFO1XcCsgBqp0SnePnNnUF9SP1m+fHnMfqg2fehDHzLfquoVDXSqXn/7t39r6qo2J8pjN5jrrk/yOj4HYkkN1eQHsbkujFePdeNQ3WE8sKMNR2hvSF6/0ura8TM+WzQtD++a5cNjNAr0na2UIE0J4JoFXpxs6kbDc6lo7KMRZo67AU8Gx9zYUxWjWkaarxzhTmBwOu5eEMLs4ma8YzY9gFL0Z2uLRhoeEhFyhWNtlFLJ82AJQaxX6jxGUkgpJDFUTtf1Aoi2UHLJhpump+O2afSa1tGE37zQj6f3TiMoRB01TS6GCZpL+CkVK1Do+sXtePsaeSHrwbde6MAmAmITqEJ2fZUPV8/041XaP9rDTaYsSiBdMiGElqAX87nhtYnVeJpA1arJPiMt1Nzpx9TJazCJamTjFfopsWhBoeEmzu7ypcJwioZPbYg3qR98zvmH0ihoAaOJfDIkzgEtWtzSAfFy9vb2U4L4FSxfOs8YmY2X7s2KjwYUz2c91OckfWWlv2JJ30hSQGqD6qPxbE8NV+dJ5SVG4iEWbeUbCUB101Z9JbFmg1SHJDEWT2pMfUTSFDn0BnmugnuRH4umytSRDEM5INBD70sSfBs2bB20U6bfWQsQDadepnmX/U0ezh6b+ohAY4EzGp0EtIw2SErmyNFaU95IoH0lPahNEuBCFbFjLrA/XpnqG8NJn8qbWDk9q0lS6AQldWJ9N/Kmpj4vD2zia7z+JpBsUvmNeMcdbzPzTBmQV3CDbCP1V9nmEi9Vn0TaF6/dF1P8m/b19nWdQlv9NgMMdbadpOexE+infaGhQd1aot8RbCLyMEgr7J3tfejs6IU/NQdl1StRWDqdswsaf355O3Y1NtCoo1yua1LIiQcBEt4QyCGgQ9Uy87UwWrEmkL5KMjGMHMRBFE+ASECQiRQdY5U5QkuZSLOf8R09/ejN4A9i1ATUkI38aaf62EnWu41p+wloiZwBZVQTe82zAWkMWKNrpXHAHgfAYYSTkQ8F5gg0ctoY/dzEm2dqLA8SU5pB9TPRNQXouQpWElOgLsx/E6d2Rh47jOLEdWoAK+dOwKpL1yC3qIrvrw6NJ3bj+L5NaGs4xI81TNE+WnQgv5RVJHRh5tH2rDg+8PkIkAUb0HDkFQR7WzCxch5Kpq1EdqEjiaJk5zpogSpgQACFFqFS47ELX6nu/PM//7Mp8q677hosWotZ2a4RaKLFswCZ6EWt7gXALFy40OSzz3UWkDF16tS4wJDqoUN2XBoaGgxAYQsXKCV7Kc8884yJkhSIBXbUFjcYMH36dKP6JTDGBlv+2rVrDZggsOEw1Yx0rnBJ/Kh8tU8Ag4AlW39LR2cLrOlaZSsIWJDajkC1N954wwA35gH/qO6KF3ih8rRIl3SLu2ybNpGzgIjPfe5zBmiLrp9oC1yT2pc7WOBDdRR/9e5s3d3pxDs3j75PCR7Z11E/UFm2PPe1O7+u9UySUjZt9HPdq2ylUVB7BDgJmHIHpXEDSHpfUpFTn7VB70t8FYCi9xVNQ+lUD8Wrj8QLbjrRvFE9pk2bNih5pndpg+WDu72aOMbirc2j/uPumzbenm1fEgglia5Y/VDlCrzS+9R3q+9h3bp1hjfqz9Ft1juPxZ9oHtu+qneeDIlzQFJDMoJ8dOcuTAyfMFJD2+ms8tc7mpFOAODYgBe9GkcZDvd6saIiA2+bX4DZtKmjceH+nV14ZOcAyrJTcefaAL2etOKn6zwEhwgY8XkgheCQL/50JUAPZa8co4v0nF6U5vRj8aROdAToCXNnGAfkF4E0zNjmVAFB7upsruW34ac0Ea+DfH4sIjUUrUJ26+xsfGJVNsp87Vi/pQOP7yjH8X46S/APD2R4QgH46TjD29+FxZPbcMcaXnMT5OGN7dh4LGS8kPk4X9jbQjCK0kKLJgCzqIb32AEvHj/pw5xy/q63BbGPxzwaw15YRACLdpJagrNRkzuffTw+P8TnsQYrOm/zjzRxtun02yup40RCdBnlF4kqmbttb+dO9bW0s6GQRTuTb0YYrb2hkOaOF1jQwvPL//JJfOEfPj6s0d3xqrYW0pIsWP/y68ZWSnQ5Ai9l7+RB2jORRFy0NER0+uh7t+2t6Ge6P8oFpyTnZAtmtGGkb/Ni/K5Gy4OLKb3el6TUplVXUgqnbNB+jdog0MetXhYtPeRWvTXzLs6z4gWVk38W3h3djgEEwHz0f30hLvii3/zurh5TFX0rI9mWi1dnG+8GHkOkF62O7AatygkiCRyKFyyQKvDIHdwgm2weffij/5hw+1Snt3oYn5lFHK4FBrohtbGu1iPo72lGb2cjOlpr0d3RQG/tfQQsJD3iDs4gZjELPemlXZ6+3lQUVSxBzfTlyMkvRVZuIb185XKSl4JTLe1YQXe524+Lll6g1L4o7ROh7VDk7FDiPq6gMoztAl4YMMgAQpIeihxENMKSFiKYYmwXCeGQ0WhNdqma1tcfMIdfPm8tadcY3EU7RLUUnW/s6o/skokWK6A/zn/nWnVinAPq6FLXShA5IqCQnjvxDqhzBuCjCZpJq3S6ds4OXeURKOTkFW0nnmU4M+jTZ0XZOF0bsI1qZPPKsXLNMsxcciXF/vworpyDyhlLeE+994Ov4uiO36GnbT+BIHpZM/lF53QwpAZvyVP6renrOUwPZc3ooyHyhmM7kFlUjYpZawj6TR1MeS4vtCjUIckMLWyt9JAmuDLUqwW3VIO00NSCUbZJpLaiRaYW2sMtfvXDHR3Mj3mMeKVzL4a18FZZ+oG0QXXSj5nUxgoLCw2Y4JbWsel0jleO4rXA16LXAjSia4PAAQucjNQ+d9vFG6nPKdk6aHUAAEAASURBVK/s5YiO2mODyrCqWlJfU9BZBpHHEtQOgW9SzYsVpKYlEM0dBETt2bPHSLxMJ/gjgC5WEO21a9cakEHSPJIg0TGeoaqqyryTWGW462r5aNO5+4w7nX0+mrOMaH/sYx8zfToeuCTe6P2Wl5ePhvSo09p+qIz6Lt19zU1M8RawUn9eR2BI705SdNFBaS0QN9wz8dj9TUSnTd7H5oCkhvxZNfBkzEGgpx7XVXMnvDuEn+3l+MnxNxQBhZT7ysnp+MvVhSigtOjjL56Ap30A84v82EQD0d96tR+fWJ6Gd11Ji0ChZtz/ItDYG6ZPM9oICmdQiJdTFrO7cGY9AnQ08dvdEq8P453z9+OyyVSt5Vj8011U8aXqWHQYoPrzAAElS07gkII9l+f6ccscGsyem4Yybxs2EBT64e+L8HrTJITShgcCPMEBBxTq68SiyhZ87MZeLKQnsm8924YndhL44tzBqJBRYujVRg9eawzh6pIQ1ek8+PByLxYRLGpoDhij2dks6s9qvJQW8qOFTSqevGpcpYXciwKHI2P7O9yiNLqM4XbAx1b6+OfSYiN6waFSpdrzne89jLPxApVo7bXwGY29IS2q+vojdiITLWSc06kNRqqFki3uoF19uaHWwlTqUB/7yDvcj8/ptVv9Jpb0jRa8Y7XX5JaoiFXpWIvfWOnixQ0nkXQxflfx2vlWibdghezXSEV3/frX4bbnJoBI6mXRtq3cqrfjzQszD4qA/FLXko2qaDs/8epw2aVLUFJSFO/xWce7x45zIWk62vaNFhg+6wa/CQTOKzDUcOQNHN/9LBe8RBc9BFJ6uigl1MGJeMR9pGZoAkAGA+85IbTRfT10NOubiJnL34bJs1YjK28Cxc/TBlPrYtHSK3Di6CHUUuLiqR0caEhO0JC5EBhiDFITEGGwE0IVGcE7TLxSq2QFBz8itMGJnAxLD0oQKYUykZ7o9FBct7vXj0x6KosO/RxUTgkUorRQwOzYMJ/AGFOACjFXrrjIc6XRs6jDxOmjNfECfETDdR8NCqnd5jnTDAJLEbrm/nR7nUo5pFU9y3tdO0zx4NJZtAkxswLzFl9hQCE98qekwp9HY7U88iaUIz2NyPG2NtqNqj89EbFMtaR4Fi4hOS4ft4XD4T5KUrWgjbPf/voD6N7xKuW76NlinIAh1VtBi0ZJD0lyw9oH0kJTNkm04JaKjqSFZBRYUgxKJ1sv5zII9BFtgU6SRnJLhcQqR4v04SRAYuVRnPLpiA5ukGG07XPzRh64xK+RgiRGYtVjpHyJPNc7E0AgVT4bVEdJ2yhUV1fHBWL03A0iWAkSxY9XEB/cIKC7nHjvS2kEdh08eNAkH6lNbpqxrgW06RgpDFefkfIm8ny0/VDSTfpWBOJFq7klUl4yzbnjQF5BJfIm0kNZ43b+ojfimoo+nGiXm3U/JtGmUBmPFXRV/475eSjy9OEH6xvxk90BrJ6SgZsn+eE/0o8NkuLZMoCPL0vBu98GlBQ24sfPD2A33bj7aaQ6lJJpvJVFu7K3reijlNBjOytxso3gUs0+XEZQhiaN8NPdBN/rbKqRzwKF/mJ1Bd4+OwWBtqMEhbrwg5cmYUtbNQKpUstwDWZuchyMZWjaT0PT6OvAdYtace/NvZhU0I1fb2rBr7dxY4tAWU25D++jF7IMkmnd48GWVj9+3uTDIX7O9+QANM2ERw/2G1tHty1Kx4zcEPafDMKfMx8FOeNnW0hNcS8KdD8cwKPnNrh3tBU33KI0ugzzu0Jw8WIPAjMEIMhrVKJeoKKlp0bLAy00E7U3JMmXiyXIBshzL2w0bqbzzkL6IZH2JsJDLdjHYm9IElGrViygBPgbMdViTtAW12YakZbUUqKLb3ebVHdrk8Udr+u3yncV3a63wn1KRKpH3r10bb1fqW2x+pokcwRQnu+g/itD9yuW1yRUtNoiwGa8gnvsiKdqNpqyx9K+0dC/GNOeV2AoLbOAxqWDlArZTQAhnaADRdCoDtbX60gtGICDXNSPXGa2H2npzgLWxuujSE3LQgFt0ORNmBST38XlU7Fq9VVo7l2P3aeacZjeSISbGOCE35Smc+be+N7SDe+kHmZiBaD4DPhDuXUjZaOdULm8h5fPDDgUJTFEglJRC9EegOoXopqbgA6nDKCLkkQn2cYmSgoN6KOOPDAn2zBF6r/uI3Hm2ok0YI59Zs9qj6MSZsEj1V35VYYOxfNM4EeSWIMSQa7nVopIaU0w50gdItfmiY1nohVV/bh1STZWLqg2YJCTcejftIxcFEwoQTN3gHq6h/5ACAjq7fOwH1B8n7u1hjR5qA1leorlojxINZMeevuimmBGCbLzaMfhPASBAbJbcg+9aFk7PDKiLLsuAokk8aIfJIWzXYTHao4ACJUjgEA2cGRn6HwGC0ypzNEu/t28EVh1vusezSfV/wMf+AB/X/S1O6psAoXs+xOPlSZecANjyhOtchcv3/mOd4NdI7XpbOomsOYXv/iF6Z/izXgGdz+sqoovSWXrcL5BPFtu8nwmBzRWTplF7yv9tIu150FU5Kfhtpm0p9cb4vcWxkcW5eDq2Xl4dW8LJXuaMbMkHf+03IODHZS4JViyujKN6mZe/PF4P39v+3EvPZVds0ISY234n6dC2ElgxKvxCwKH0s14fGYtiMcQHNp4rJg0PHjPwr2YNbEFn1rGDQ3aEnr0EKiaFSvX6bhlBK8+vjIPl5R3I9BCm0LraHB/QyWOBqoQ8ElSyPldOZ3DuZI9IS83ueR9rDi9BR+4vgW3X9aHprZufPvZdjy2PUAbRhxRJSFBNTQvx8HJlIK/c44XPfu92NHmw4YGD7J3MT6F3v2a/ATGYAxO91HIowuzMX/2e8dVWii6TbqXJyctPkcK7h1t7XZXcEERb4HgBpHszvhI9C+G50eO1FK6+OSoqqp549ku+LQYS8Te0NmWM6qGnUVitw2QRPvfWRRnsibCw7F4JtK3M5KqWjzvS2fbpmT+C58D6neSHhIAL1tW1gi6+poMHccKApNle2csQGIsesPF1dFuXDM1cTIz45siGC7/eD47W2k71e1Cbt948m442ucVGMqbWIXC8rmoPbgdPV00QMCFm9eXiZT0ImRk5yM9K9/UteXUUZw6cQwZmTScVpBmACIBCP4ULwb6KIXS0Ry3TR6CN7MXXkbpgAO4YrYDDBkwRnM5A4rwgot8yv4M0jCPIvcSAnIAFlaPk1TBSsYFvYxR86FAINXbOThJZXm6lsRQL1XcwumyG6JcTmjtpgve9h5HUshG6pHKsakMOmLLVSI9dA7zyPkTqRfjBfaYtuisdBYUcq6V1wGFToNHirOHyUMa5t6pZuTaFWeY4nDGYQ2vSWPJnDKslgrZvFU2Z8xzKNDNd9VJWxFOK6XJ10fjoz0EhPxpVIWauwwTJ80kGuRFd3sLj0a+10Y0nTyIJu62CUOrmbcIlTPHz8BmdMUFFsgO0Nq1p+3wGHSa4IAFbpRHwJG8fknF7FwFu8jXwjtap/ZclXE+6EgNTgDXueTNWOrttmFj32GidKKBsdHmT7Scs03nBuTOllZ0fvV368VOXh06OiTZ6QCj0WnP5b37O6utraVhToqQJBgu1PeUYPXfEsl8lJgtqrgO7a0n0Vr/ImbSwPMNU8L42b4BPLy7E02dAbx0qAud4RRkDPhoC7AXW0/1Iz3cjeun0nPLzAw8wPFsfS29YnKT5WOLgSsW0026rxPf+22I6Qkycfz2cAMh6KOzB19s1TKplW0+4dgeEDg0p7iFKmy0BUNc5+f7QPf2sdm9jLaPPrG6FCsm9uLI/lo8sTEVv905DUf7yyitNAwoFKQ9oYDsCXVjflkTPvy2dqyZT1WwwzSsvY6Gpo8GDfiVRkBIwNBe2jPaQXtB2dyUmkbw50PzgvjJPvKjxYuXjofwMucUk/PDVCGTwWk/jtQHUFG9DJNpe8+nNo9jcIM2iRajhbxsNVjgQbuww3kZc4NII6VNtA5vdjot1l7evG3Q01riklaOO+Szrf9I6lBnS/985rceg1TmSHZEzmW9xEO3++1o2urfY1EpE90pNNIbL2ygNJEMD4/FzlA8msn4N58DUis91dCMez9617AgjsAh2R6SZI5co0udUX0tnr0ePRvPdYLbIPyFZnDZXTdJ28UyTj2aN38uwKXRlHcxpB3fGUYUB3xU+yqpWoATB7ai4fheTJq+FFNmX4LsghKqEtF7EtWRFPqpYnby4BtortuH9qYjaK87gZy8VGIIHnS2nUJHS2wU1RbnpRHqRcvX4nh9G/bVHcf6vXpC0IMgjgAT48nEwDKcpBlwRlJCAlPkhUyQEdPquewLGWkh3lNiSPkdb2QOMOQYs1Y8DVhyd7Kb4FB/XwoNUAsscqSFWrt6jViganA6iDbvzKE/Cjyb/5F7A/wo2qbVQ5ale/2zwA7jHJBIae21k3bQMLUKU14BYvba0GWcguKMPSadGcy9c+lcO/FSIVs0PQfTZ84joBe/6/TQhlRn8wGqdlB1jipSAoW6umTEuwhV81di6oLLUVwxA+m0CyVGBWlfSjamdDTXH8XJwzsIFDWhgjaL0jMpV3+WQRIP8pgklRPZDBouCBRw2+HRQlVgh2yryCbOwYMHzQL5XC+SLX1b3nB1HI9nbjfotg5jMcD7VlycC6x7s4Gukd75uQDk9N5lm0lqWaJ32223GW9mav/9999vvIiNVI+zfb5q1Srj8c9+Z6OZ/Kie51rF82zb86eYP79wCibPvAFHAo0IduykxEuQKlFB/P5QN7LCQSymUeVnj/Xja7TZo42DAXr/XF6ehiWzMzCNal9pAQ8eoDTpy/QKdvIPBIcW9eLG+emYVEhvXo+F8Nw2qpQH+qhaRoPU9AQa9KbFBIgsOLT9VCEWlTXiLtodWk3poRRKJ91PEGYnJXRskOrYzbMycNusXFSktmLDxmb8aF0BtjRWoS8ln6CQ5graKBkaPAKEgn3wcOwCjUwvqGijPaFuOmYIYPPednyLoNDmoyEMcANE6mPvqfFTPdqDDcdILYVtbKJL+tYQrpkdxEdqQlh3xEOgjAa6e7y4q9KHBfROdqKRNtoyqUJWvHDcQSG1rrS0CCXFRXF3q4dywLmTpJ/UH2xYtXLBsItct1rEubATYct9M88vc3Gvw4Jjw6nSuetpxkzOzWwYq3qEVYfSQsetlmLpXixnt7SQ6jya/nEu1PKGk+5RfdTPR6tSpnejb0JuyWPZMBLNl9a/ZtL8KdgwER//FEJXdw+ef2ETliyeg9tuuXLYJquPTJtKJw40Sm37iAFlaJxckkFuW1ICEZVmOPB92MJGeGgk0DlmKQwHUI1AZlwen4u6RYNLZ6PKOS6NfJOJxl/dj1PF8oursPy6j9C+UCcycwqNnSCBQtEht6gcfd2rUUsQacfLv0Zb83HkUnoohbZopIrWeGIvJkjiJE4onTQNl65civaWerR3dWJ7LcXgCHgY0EfzO4EfkrwxgAjvGedM+xzgxaQlSCSD0w4g49gYclzVC/hRBlGzGT1o7+5FW5ofE7JYFqO9Kk9laNCPYC5OdSM3Im1AGHvvSmRAnkg9I2kcUIf0dK/D1j9y7wBEincAoMF7gUJMM5jPVMbUfGi9jEElpw6Df8UUxq+sHsBty6hCtnQx1fiGl5TpaNrDd7SNEkIEymg+qrubXpEKZmDuqttQNZdA4Bm2oU6DP6JdXj2fIFE/DYqfjnf4Nra/paWl6OzsNKDOSMCQSnBLjCi9jDxr0SygRMandQhoGgtwEq8FtkxNEmXEWR6UEqlrPHqjjbflK5/KVxtHsnNky3CDSuPBG1vOWM/RgMFoQBTl1XsWf9zBgmfuuPN9bfkuCS29MwGgsQwvJ1IvtefLX/6yAYDkle4LX/iC8QhmvY25JbASoTfWNKNVDVO91X6FqqqRVc/GWq9kvsQ5IEnbotJlXEGdwoE36jExqx63zPSijirj6w52E3gJ4x+XZeKZPQE8sLsXk8szcO/SdHr9CuC7L3VjfyddyWd50US38VL7+qc/hvBGXRfuWZaOf/kocP0bp/DjZzKx7VguvAO9lB6i5JA/gxJEadx84HeqsTkSBA51UFJ1w9ESglBeo1q2guDQklIfdnT5cf9eSrByQ+qji1KxpLAb4b5m/OYPPvx4wyQCW1MQ8Me2JyRnFt4A1cYoJeTp70FJTic+eFMHbrsshBTaT3p5Ryu++8cebKL0T4D8mDnBh+vobn5qlge5PJaVAk3tYZzo9GB9YwqeOe7BmtIgUmlo+1S3H9dWUVKK2vJ1FKzu9c3GvEXvQ2X1+ZGejTaWm4g7bes+WGwfyb199OI9UcmayCu9IE8CMx755TOcJ5yWcDRjamRxNVyl3bxTurPZwbZqKZbHZ7ubPly9x+OZ+Pj//ff9BmAbC30tYi0wFyt/IhIGiUhejcWF/ZrViw2oFA+0E2ik8TbaG1WsdlzIcWMFNi/kNo21bgJzZOx9/ctbjTH6kVS/3KCHyiwpnTBoyFnAkbUlpf6XCE19T3X1jVi2NHHj0Sp3Unmxqa8k9/QbIsBbYNRI4NZYy1OZiQbVzc3HROv2q988j3qqxd1y81pISrVyUokpUr8XMgC+etXCC6J9ifJhPNOdd2BIxqILSqpGbFNaRjbMQXBA6mHbN/yK4JDUy3xoqduF/a8/h8zcCQZcikVMeWYtuBStTcfQ2fMKTjT3oaWHE8eIpzKTh2AJrQMxjpNJgUDcubSeySQ5JGBFdIy6mIAV2kSSBFGY0kPGfomZgHISqjOP7p4QerNpO4nEZWsolXHZFB1vIR0ZoD4dCLu4QBgHNCJ958KAOAbIUYZB0Ed5nGMQ4DH3UVJAoiIgyEgUuQEhxamtETqWtr0XLRN0VhrdOHHzS7tww+JsrL3ybZhVs8bhiUl75p9uGupsb9iDDkr8dHZ2GdWxzPwZWHDZOzF94doRJYAcI9YTziR8FjGaoGkB+corrxhvVKMBXKxXJDdwItfYMlItwGA4WipTP/SJSJvI6LRoyRaOvDJJasku/M+i6QlndYMnMuKrOsiwbyLtGwtvEq7YOUio+lVVVZn3kAiIYiXMVLTyuQFA+05EZzipMTdgMVITLFA1Urro59F8X7futLv26LQj3f/0pz/FD37wA+OBTYCgjLELpDnfwd0Pxd+R7Du51emqq4c3Kn6+2/KnXJ7HS2PS2QuRmlODpmP1mEW39PfUAN/fRk9le3rw5L5utFHKdlppOu6lqtj0tCDuf7UbvzwSRlF6iCAJRx+CPHtaA+jsC+MXO0M42tqJjyz24yqORZfU9OKPW7vxk2ezseN4DqWN++Gl9FCYm0whbwoPP4fYyAYOX0S09NA7aw5gaVk7SmvoNIF5J6d34vgRAlW/z8VTB6ahJ62EUkjaMdVo7gQDBtEFvYxLy+sY6Iq+JKsD11/SidvWhGgvqB/H6jvw2GvdVD8bwBECP1myk0g6Bygx+83dHlxJIOhqts3P+UEJh7nLZvpwimPE63sGcHB/AFvDmZhaFMbN1R5Myffijf39KJ6x6LyokNl2uifNihvJnbYWAxs2bjWLXoFCWthKOiJecHuVUZpEJWvi0RtNvOpqd+NHky9WWoEvv35sHX7z+Asct09yA6xnWFAiFg037+zzszVGnIitHFvWWM9qu3bZpfZyLoLlpcC1/QeODpE+Gw1wWMt6DVenRKQfrOSVFpzx+orojNaFvQXtxK9Y4JCkhuSNSiERcEg8++a3HsTDj/yOa49ek+98/BlJ1fRCUz06HzyJV4b6ktZRiQIP0f3X/dsoL4eSJjtOCSL1v4ceftoYrf7ze981BCixddFvi0DWFctqcNONl9vohM6qd9WUMiORJGAoEdtaZ1NeQpWKJFLdtHkhcCiRutnflsOHT+CWmy43QJukEEdDQ0Wfr/aNhhfjlfa8A0OjbUhaRg7Vj9YYHGXn+l+jv/sYJ3I0aHnkVdQfnovqmivikpRK2bLL34ljtGn09poj+MFml5tlgSceTvpkO8gYZ+YtLwUICVQx6mbsPEZiyDE8xOeUEDLXzKe8PAxwpBrwOsiju6cPvRl0jcy8mlJmp/qRleqjlDknku5AIMaBXVQHPdCfyMGTAX94b/AaAwCZSMXoYeSwoFDkmdpkMkTOvB4iNWTzmrO7TF6rsiTjBLVNNx4UZvRi5eRmivFnU9e7clgVsoG+drSc2ILG2u00Lt3NRWYI2YWzMH9NYqCQLf1cn7XYlIttuYAfCexQ2QIGXn75ZeMhzAIjoiFpDHkm07Nnn5V3PS8+//nPxwRPREPSMwJ8EgGGpk+fjrVrT9s20iJdtozkoczWwfJFtL/yla/giiuugNyMn4sgkEG8ef755037BAwJFEukfaqf2qk8AkyG440AE9muEe/e9a53JcQbtc8NtOhaYMpowvve9z5jSFx8E7A3HIhivX3pnb/3ve81bbNlucEYC+hEv1/Vz23s2uaNdxYAMhqVKUvHDSaKhtqkPhRLasjNP5vffe7t7TWgkNo8derUswKF4vHFXV68a/FX70rf2UMPPTSiJJT7W5VHPDeIF6+M4eJt3YdLk3yWGAfkpSy//Gq0tdYS3NmLmok+3DwjgB9sC6Kln7aHOBy/Z6EPZbSx8zhBnqeOBNEGPxbk0gV3ESWG+oJI59hMyz00KM3f5aNhbDnRjxVlzbhnRTretiwLa2q68dIbnfjJcw5A5CEw5PfR1p+PwBDH/zBBoqBAIoJMAaqndYRSBqWH7sY+zKb0UEMrVcteTMVz+6spJTQZ/dbrGIdAD1XfvC4wyCMPqpQUKs6hTaRLunDrmiABoQBOnGrH/3u6E08REDrWFjb2hOaV+nG3VMc4L3hgD7CD5TxTT3V1Sj1PZxuf2BFGyWHQSDfT56RhfUsmZheG8P7ZYcwjT9romr56zvWomnfjeVEhs29VE2+32osWehtpO0dx7p1apbeTZS2iZUT6EnpWmjZtslmwWHrRZ/1WSZXMBvObyvFgvIO7rvHKEiijxfaTT78ULwmU5mRtg2lDb2+fkYzWQs0dEjGoHa8+dtHXQOcpctM+FtWiRKRe3PUdzbUWWvd982d49NFnhwXCJGHwD1/4bzPWx6Jv+ahn6g/xeOleHMeiY+NUr1/+6jlj68rGxTqrr8r2yx1vvzoubwXirGFfHgkckr0hzWXuvOOahKQyEgWHxDuptN16y1qaMHBspdm21J44hVde3YGNm7ZxLnOUzlz4mxQjJNIHY2QbNkp99tFfPzdoRytWYvXflykhI/6Npe/GonmxxyUCrKiN7t9GgezyBGYN+Efbv+ql6ZIHfvYE1B/efttVg/3PAiECWQsLcrF40exBGqPh46qVCw3d4yccOz7q6wJKbb+UFJLWqQJnJPWYaHnnQqLsztuvoQbIMfy/7/zC/AbZ71BjlOx0qd+JD6rbI/ydEnj68Y+9k2MY1bEjY00sGpKuuoSSQ2rbWNs3Gh5fqGkveGBIjJPkUPW8NQQuPNj58q8Q6ONu/UADjuxch9yiMhSVz4zL30BvE6ZWl6D2+G5cO6MWv9vH2agBT4SE6JIDugF4hIs4AMugBzLZGGInsuBQmOXLk5pjZ4gTGeYzUkQ8OxuLHk7metCaloIiWnBXCZyawi+AhpOhocGU5kQJgzF10q3AHOesa92Ye/2JHI7EUGQiYp7zWmeTntdSMTNpnXjzTPcReuZsr01ZtjzX2aQHbpx+GDPyOF3vCtLTzHrjjj49q0AJzwhdzfsJ2G2knaDD6ODurjySTZm/OCFJoTOIncMITTyrqqro9rQY//Iv/4K6ujp86lOfiglKaKEptZzly5cbUERgiYJoXHPNNYMSDAJAfve73xmAQgDN6tWrB+2bCBCSRNFdd91l1NBsU9yL8+gFqOiv5aJei3vZeJFHtCeffNIMFKqDFuySVrG0J0yYgJoabsGPMrjrEJ1V6msCRdS26PYJ/Iiug21fdN0lcRSPN5JMURmf+cxnjM2m6DrEu3dLhmjwHEmSJJqOVKE+/OEPG8BGgEM8EEXv/2c/+5lJJ+BlxowZQ0AS8UC8EPCjtsgL22c/+9nBviT+SiVL79AGq17nBviGew82n85Kp74SKwhMfP/73294IbBSgNe9995rAJVPf/rTg4CiaKhdqrNCdN9TnJWEEhgp/syaNcvkV14BeYpT0L3ao74SDYiZBPwTrdamPPEk5/Qsun0yAP+hD33IxG/evDmudJ7ek8BeqYrKC53qpL5og2irHyvEanOsdOpbYwHpLK3k+TQHNHbKWHKIY+yxXQ+grXsPrqQhZQmz/nh7EOvrQphd1IftdQM0Th3EsaAfi0u8dOPu4wZEGG90yBoPvXZNA2jaDodOhfFacxi/PxzG5mO041PRg4+sSse1K3Nw6aIevLy9F6/v8+C1A2nYeTwbHgJDNEREWjwTGHIkiJxx+7VD2dh1YiHKMltpB6mZKl15GEibwFHRwzGbruY5/klCyBjIk3QQAaGSnB5cXdOBJTOCqK7gjuPEAdQ1deG7z3Tiie19DiBEKagQ2y0pITBbmKphS6Z4kc1u+cg+4JU2D55v5LQrNYSaKWE0Us3txTpgO+NnFoYNKLS0jDUI+NHjnUODtdeicMLk00w9T1dSezl8pNZIX2hyHWvH2wIbsreyeOFsA2IoX1r68JKGbomD8Vi8ulkk9YFvffchA+T0UyJDUj0DPMcLWtRKEuQAFx3xgjMWcW41TBjOoLZAie9872EMVx8t+uSqXcCEwAQt/EYyYOuujsA9ubA/V/aG9K6/xUWYFoYCcbo5z40HSNh6aDEsI+PxQiJ8VF79ptvFXDQt9/u19Rru/Sq/6iVQ6lGCSOKt+qCkLm6+6Yoh5KO/gSEPIzcqS1I+L29y3pPqOdK7SgQcam3rwDPPbcAfXnr1DGBNfBugetIAnUJEA5Kqltpz2y1XsR5XYgZB2rMJeu+PPbHOkQ4jGGr7bKxy3eVILe71rXsG+atFttSQ/lSBIvHLghfxQET15fv++2dGYk7v8B13XjtE8lLf9F2Mkz03gdf6Xba/E44aouMm3oKsC2pm4uP3Cgw5U3rzBMEeK1kXD6hRP3V7OlRfd/dLPVdQ21Sn4cpzq8uORlVW32ks+z/pHGMuu3SJAYH1m2S/Q/EhlfVS3cQH1a2P4L3qJpDN1ln1Fo13v+t6HCMv5AlONHbvOWR++x98yJHGSrR9SvdWCj7akvjCxdAgqRjlFNJOAA0at9QdZpX7KD3UwmmcD/kTq5CSJlsAQ0N/dwM66l9DZ8MOBGk7wM88A5zrnWiLpOWsUxNPHU4YREmcOPNAU0Ub9Nymca6NzSKBKJHoABcWkhbKTk2Bj4ARp4c0Ngn0yDgjxcc14XQOkeL1IIhj40WIkw4+c8AdxTv3Jk4FDdJwwKDTUkHOs2hQSOmNNSR7ZglOfQV0qf3uNp5u7YqKU5hf0ozSvB74wn0I8cPJLaxATtGZNoZ6Wo+i4dDzqDu8GS2NjfRiRDH6wpmYs+ImlFTOUolvamhpacHrr79uQImtW7diz549g4tFuYfXwlGL+S996UsQiCBJHQFBbnUaTVDk0l4LVy2ydTSyraL329/+1uTXQlUL9FtuuQV33303xRZLzGL6O9/5jgEMXnvtNQP2tLW1GfBHXpe0aNbCXG7e58yZY2ju3CmvBA4A8oc//AFPPPGEoS+JnrVr1+KLX/wiZAtGto4kBaNyDx48aPrM7t27jcSFAMz8/Hzk5uYO1uGb3/ym4YH6SHQ6lR+vfVrs2zpEt08vVnmlfiRATQvyeLwRPyXlpEW8JJKGC6IjcEy8+9a3vmX4LJ4o7Nq1a8g7tO0cjl5hYSFycnIMn7Zv346nn37aqBcqj/qAff/19fUGRPrc5z6HJUuWDAEbKioqDP8Ejshb17Zt2/D9738fDz/8ML797W8bGosXL8aiRYtMn7J9S8DKpk2bTPXUJoFHti/I45ckdtx9QQkF5qjd6wgWNjc3G89g7nQCqSQhI2k4ebVTH+7r6zP1U3n/9V//ZfqG+qYALD1TGvU99X/VW3zUOxdf9X3Yfq38jzzyiLE5lJaWZtqjZ8qrvimpMPFPfXfevHl0ZZppyhVfW1tbzbNHH33UvD/xSHxTfdUm9dfHHnvM9HP1Q/UDefmz34HOtl3q0+L1xo0bTV3FT/uu7rvvPkycONGAvXfccQdUTwX1m0S+t1jp4r0LQzj5Z9Qc8BKQySsop/ROAdroNKKfGzWzKQ2USzN8rzYCG05yDOvow5qJYVw/y4+75vpQGA7gd6/3YENtGPOLPVhdHGJaj5HCWT2Zjh4GaJunJYSDLdytbArgZFM30rwBrJjhwSUL/bhpdQBXzm/H5IIOtLf1oaGJvxkB2iKi6pexSUTD1WHasBugGFJ7lw/tfZkI0vGEJ5LGQ89i6KO4jtzOZ7Xh7cub8Nk7W3HvLf24fFEIU4p70M5v9sH1rfjGc514bt8AGuhtc4AixxNzaU8vw4cuqpwHIgvaHrqlLyWwdU01MJGYyTGWeZybJjMyw8jgnGBjgxdl+R58kJJCblBo8pz3YvLUFcS0ToOdo34BY8ygRcjsWVMpPVhhpAM0YV734it48qk/4Pl1m6k+tc7sEL++dbcBhaT6csXly8xk26tJxTDhqaf/iN89u8GMVfPmTsP1167B5Erq141DeOK3L+Ix1rWTQIZsHiYC+uo3SeniHWZ+NUJdp9CArICFigrHjoU7uYAEGaQdqT4qX+BLN21XzpxRZRZ4ubm0zp5g0DucTJWLAPvYrt0H0dHJfh0V5s+bYXbIR6IrMOWF32/G3n1HOG+ho5DIOBxFbsjtueCjFsjXvW0N5s+bPoS2vXG/39HUSzyxvG2gF9y57IcrVwzdaBP/cnKyaYS9luPlYVvkGWe9p34CNSo/0Xdl343AKIGqkm6wC3VbgKWrfuI+VJb47+6H4tP733sLvviFv8Bf/K93m0VzKe3TuBfClu5ozrIx8/NfPGXA0tF8Q+6+K/62tnZwbjsVc2ZPHU3x45M2QFtyp14GmrfDk10BT/FKIGvSuJS1fcd+o2abk5OFzIx07Nx1AC/w9/OBn/8W3yZgLdDtJw88jv/86g+h30VJrJSUFOEv//xuvPMd13L9MXSO7Pf7yMNpg7/L6jO2n9j+p7P61F/+xXsMsOPuAwKf/vNrP8L6DVvR1EQDdgwdHV2cux0zgIh+I1RXHQp5/L1Zy9/1RQtmDfZRd3kqS31zpPJkWL2R/UChs6vbGG/XWNLJ8sppM0jl2bo9+uvnsWPnftMu9fG9ew+b9AL1bVrRkQFpOUk4drzOfDuql8Ad+13but188xX4/Oc+YsAhfXfukJ+Xi1kzp6Cpuc38tqk8/TbY79nSiNc+N6230rUD+V0kLZLk0ORZy423suYTr3ASEoDOtXsnoHLuVUjNyBvSkp7242g+uQ1dHU2g6R/MLAtwN7DeACsbjxYZcMSY+jEoCSczuqEKlfFQZlTGCMhwsudIBbFD8dqRFlK80kpiiOCKoCMzGXLUyVrZ2XOpQlaUmaEnyPJ5kEE1tC7tPLqDMCAGwTskYOplInTPDmqemDS6163ODhhkzpF7AUlmkLD35hyJE0HdOwSck6FvHphYE6kkgyEMgUJrppxEZX4X0vzauaVh7aZ92LflV/BxcV9StWQwdU/rYdTv+y0aDm+gy/lmflRB5BfPwpxV7zyv7uYHKxTjQlI3WoxK3Ulgihbp//RP/2QW/dXV1WbhKtT7pptuglRSZs+ePQQUsiQFGt14o0T7fUYyQotLeXLSYlaLX0mZCBCSpIkW4wpatHd10U7TDTcY8MTS0oK4qIgeYAgeKYimgKHvfe97Rh1I9XTTl+qVDtHOysoy6VXnvLw8U2/Rt0G0BSJYIMXWQe0bLt1Y2mfrLgDq5ptvNgt9AUnuulveSE0oHm9t3e1ZdZfklNoXzTulURvFV3c7bd5YZ/FXYJ8kd2w/kPSYQDa/32/eg/hjeaz3pzzuIGDr7//+740kmCRp7LsXWGhV6vR+BNQpr8AQ0dMz2Y0STYEP0e2J7gvinUARgVm33367GSRVD9tmSWUpqD4C5GQXyLZJ4ItAJstz9Ue1T6CnQBZ5wFu4cKGpk0BGeduTNJ3AUElBudukuksiTv1bbfj3f/93Q1v97/rrrzcAqOoxfbojvaTB2eZXW+fOnWu+J/HEtknv89ZbbzV9RXmj26S46Hbpe9W7+tGPfmTqIimhj3/847jsssvO6E+2r4/EY/UvAZojpVN9kmHsHPBRYqdquuMNUpJDHT17cHWlH8XpYfxwewi/a0vFSc5EFoUHKNlLqZ8OH17vTAWFaXB1XgBLS8Ko55r298c5hucCV1V4UJXvx67GEDaeCOJVurD//qYBLCnrwqJyL5ZVEcickoHZ1Wl45zVUkSTAc7LJi/pmD88e1PEcDHA3kZsy9W30Ucaht4TllFKNS4fPT6BG1xM8SOc4nprC8T7YSy+ntB1EyaCtx4M40U4pqFaqgPFRiPOCmVSTu6GaXsQo8XSqJ4yHDxL4avWhmzuWJ3oIPDd4cF1WEO9Y6EF1ZQhbj3kIbAFvsJ3FeWdKChlQ6Dy4ph/urWpH9eorV3LTopRj5la8Qpsy9VRvamvrMNmuvmoV/usrn4FAkEzOddwLkOHo2p1cpZGERfRkfbi8o30mCYWP3fOO0WY76/RTppSfoQJkiUpFRGoNownaHY9WKUokv96Jdv2PU91E6knRQa7gEwlahEniQwuk8xnU94Zz4X6u3m+8dlmVvPLSxPgk3iT6rvRu8vNy8LZrLqHE+SKzqN1MCR1JQBigqK6R5gTOdMctEKi8rNi8BsfuzBzzjU6tqjDSevGkq8by3uSh8IbrLh2cf4yFhvLoPUql6U8x6Hu30lJWNdG+35N8xwLSq6omGWPPS5c471KSXmlpsSUv7e+y3rPoWVqWt+oTd95+NaZHqfQqnUCcGdMqMZXlve3qVTaLmVOlaM1amGeAKfvAAUezTB9Vf40uT6rFy5bNM4abR1Oe6GtOmcf+rzljdN0ERrmDO62NV33WXrGcm9HzOed0vP25eWG/DXl6m8Y2x/ou1L4Z06fgq//+Kbydv2/ub0/lDNc+W4+34pkYiEENLpq2Banff3T3y9j7yqO0/XgU6bTnU1g8FZOmX4qCiqVIzXR+MLtbD+Hk/mdph2gLutrpNjcYID4SQmt7Pw7VhfH0vhJsPEJwSMiN+cOLyLXAH4FADvjjgEHmmh1ZZz03skAmnTKdzqvn6oAFWRmYkEcD2rR10ElRtlNtneiMLOYGmT0IxkSAm8i9OQ2COUxtgB7BN3zCa+fMGamNZ7ucaxcdxjnpVJor3hRuSnCi7TMTr6QEhSadwlVTj6M8r4v2kSh2rXYyeDw+pKYVonTKMlTVvA0TpyymWl8b6vc8RlDoj2hqrOekkbup7R7MXvFOrLzhoyMamzaEz+MfLagFpuhsF9dawFsAQAvSWIBAdBUtHS0u3XRi5bdpo2noXj94ymPLt2lsHjd9gTbRdbPpbD732U070XQ2v03vLl91jNU+m8eezyavpaGzLVsDx3DB3c7h0rmfnW0dlV+AlM4K4osADvsuJZHT3d1tJMH03vTMvmPlidUmdztGarstK1abRF/53e9L6SQdJKkhSeNE11fPY7VJ/U1p7XMBcZa27Y/mYYz87vJ1PZY22XL1zSq/DgXRszzQtTuoHUofKyTKY3e6WHSScaPnQJAbI4f3bzBqZZ6+Pcij4O62hgH8Dw1S723zwm+GUbqv5wZNFm39FdMIdVlGCHfMCGEW7fD8+LUwDrUDt86gXR7GE3PBUQJGz+4awBsng+hgPj/HvRTSqcj1YOEkH66fm4rFk9PgJTDqUT8xY7jzey/7gKKh0c3DjaAwbQnJppBE3YMB9h+qktW2BAwY9MxuglY0Jt0XZP2kLsY8IY6LK8qoOkJJpwHaL3rhcBjNrEMOG3KEEkHHac/o5qoQLi0hWHqC97Q99J4aDwrSaHOIa/TXCIBVFXioPhY6U1LoTQaF3G/XURUImG/K/bul709qY7Em3O787mtN3L/ytR9CovoK//uv3oe//qv3JwwquWklcq0dZB3nO+j3QwutWLwZS520CNIxlmDUKbggjPWbmOg7tH3A/f7HUpfR5hmOj6I1Fl7GqsNw/B1tGcPRilW2O86WpXFOvBbfBaS6g/qUBVP1/lSevFXF6mvufGO5tvUZS153npHeozvtuF/3NiK07esI7/85PCWr4J3/V0DxinEpVqpeUvlLJ8ij92T56X6/Kljvc7TvMpqWbUC8bzqRb3i4vhurPEmzpnBsjfVbl0h5tl9oGSr6w/2+2LSx+nmsup0Lfg7XPsvvt+L5ogOG9BL6ezux/7WncHTnb4m2dhIcykQ+9fBzJ1QjPbvEQB0dTYfRdHInOlvrOMmzEwNO/gh8nAaHih1waAiwoxI0QzXTRZ50bUEigULR1056k86ZYprsZlFEsT8vtyP1gcgrWUhAzpCge9I38a5numTcYIxAHqUxEeah89zEnb43eSwtc7aFKa8O1/3gZSR/5P6OmnosKjuFvJRWZKVxoqx48sCcdUnVgLQ0qicVViInv4TqclwgdxyngdE64xlBoFBa7iysvO4ezFi0VrmTIcmBPzkOuAGMC6XxF2KdLhTeJOtxfjgwHDi0k8aZbVgyMYSFWQG8QRWysnwv/mxuAIfqA/j+dnr5pPdQL8fEO6h6dX1FCPVUK9tP0OZX+8LYRrtFnF1ShZsqiiSWRltFAoo09pXkeDAx20u1Lg+v5foXKKMRaA7NqGsjnQ4dlCLqpMv4TmcxRhzIGL6mHWwDBmVQ+leGsecXe5FPgKep14MagkPzJoTxgx1mqKS0sBePn0xBK9XTJlOFbEEGvZXRK1mjJwVTUgK0K0T5W06or5wMXD+FdaABImtT6EKQFLLvYDzO2nH+6n/9CLIFoZ30T/31B42ExXiUlaSZ5ECSA0kOnMGB8wgMnVF2MiLJgYuAA2PbgniTG5aank2X91Nx6mgJeto70N/Xjab6A+jubKatoSwCQdTJ7aHdju42bvoR3LDYC+stACc/NwXV6MctvhPITx/A03vLIi3iLJA7fkpvgJTIhNJMCRmvBzrpLDqOUWoTEVEpExnnmVD+HgtIKYkJgxeRe6c850ZAEO8VdCKQ49wpjY7BB7zVjY2PnM3jiK0gk1YRkWDvI8Wb7BHqEeTHeB+7btoRzCluR3FmP/y02eCurUjoXlJXfX2taGnoRkfzQSLdmocHaJROEjiSOvBR/3XxBaNCZlmQPCc5cD45EC3Fcj7LjlfWhVineHVNxr81ORCtVtbYtgPTM4P4DG33PHk4iBfq/Ggg2DIhNEAbPASDstLwB6qQzaO/g+pCPzcdfDhJtayFE6hWNiGAY/TS/BSlcYp9IUyiWQRPuR+3TqNkUVMIfzgcRhtd3TdJ34sDWEsT7RXQ3hCxHSM4pDipkSlQq8wcAoLMtSI1EdBznTlTqiKgdCPVxdoCXhztJOBDlbZF1BY+Sc2qzqAXN03nmWpkonl4wIP1zV509dPD2MwU3EZPqj/YFcArnSmYmx/Cn9d4sag0hfOTMOpaaO/ENwPzltGm0AUkKSQWnOsgcNpKQAy3O32uy03SS3IgyYEkB5IcSHIgyYGROXBRAkNqVjalVbLyStHVchAhH8Uu+2lPJXCKczgvJ3Y0zEZgJiyvIgyc65lgz5rtZdNAZEFmCFdPa8WM4gDu31KMlm5HZWIwnRAUTQoNKCRCvJZXMv6TbSFn4sgz780RmUgO2h1SqXrk/NFFnEAQaLBQJdGNjeO1fRYFCBnoyDxTGpsokt/e2+eKtsHSidxXFARxa00nKribmkLDdvLAIltLpn0mjQAn0xDeqawQDXT1URKq32GP0pBmiAY3C8umo2LGkgtOhcw0I/knyYEkB5IcSHLgTeXAUHDofnoN2YNM2g3/IO3vLK8ggEK7Q+taUtEU9GFhfgCXLggTlKEB6gNhHKetoDB3I+YWBFBNVbNn9gIvHea4k+XH3KIg3k1QaHkp7fkFfFhbDVzFQ/Y76ygJtJ/Gqo1EUFcY1Cg3Q5llhIZJSQppCF9T6cN0GoMuYJ3eoCe03x4mwESgp4wmDDMoJbSV6mwbaaco64QHd9NsRl4q6REQqqD9owdqU7CbanE9VDcTsUJ6H6s9FcSG3hRs6fbhahrP/nBNKso51rZTDa4nPBFF1WtRMZ3exyZWc6Plop2SWVYOe3Z7p5FtiD9VL0XDMin5MMmBJAeSHEhyIMmBN4kDF+0sJDOXE6rS6Wg/tZ2AkKyrC5ggEESPJgpW3kbXxo60ziaeDkooO97W2k9L6OVYuPZWLOAksbR8Ix7b3IuNB8USg6Y4OXRpCfDSCQJHnImfmUlqNskgd/a6121EdsfcO3lO/82iXSSFrh7NTqMCARandJVhn0WuLaBj4hVnE+gcubZRNquqpnrZ5zrrVn+Yf9XUAO5cNoAaqn1VzVyG5qNv4MDWJ9HRtJe6owHurDoE9ddki/wVPUkuOfHOkwFOnjNTcgkKcYacDEkOJDmQ5ECSA0kOxOCABYfy8stwbN9TaKt7Ed19jVhYnIJ7ahy7Q1vb/DhEN+5lPo5D/HecLtzbaF9jYVEIl0wKoZHSQq92UMKIYEqOJ4giD731EPSpo9evUoI4nX10Eb8nREPVNPw81Svv8ZiST8mhZtqFC4RxyQwfjtAA9P4Guo6nPaLtjWGOyVQ9oxTPo9uDqCz2Y1YBjVMWApubKaFEx1lzyjzYzDoN0CbEFoJDC6nGNjU7iONUoc7Ppm29ghC2tPhwtM+ZWh3u9eFEvRdFNLT9rpnA22f6qDrmRSudnnXTHf3kOe9GZfVyAkJpVNM+rUoXg2UXTZR1bS6bEHKXbMEfxW/YuNXYkpAa2SUrF47Zbs5Fw4xkRZMcSHIgyYEkB5IcuIg4cNECQz5/Kr2QZcOfmkZgyAEmLPZhoRX7Hhxow7nr75XaUzrKKLI9reZqlFbPp+GsdBQV5CEz/QV67+nBS3vdOU5DIg64QmkhQ0pl8hh8LJka3psonXlE7p2Snb9lhVmYVVmCFs5atx444X50+toUoD88zH/nbO+dQm1ypWMYBImc2yH3JkkknUAuBZ5uXpKGm5flYdmKSzFn0eX0xpJGgIx2mrLysGP9IwSH9nC3tY9NieRxcp5ucuRepxB3SAMUsS+ixNDECloHTYYkB5IcSHIgyYEkB+JwQOBQ0cRpyC/8CI4cqMGx3T8nYLOHzg9SsJhSvBuODeCBvV7sbnU2UiSrW5wRxurCAUoLBfDHIx7slgQRbfnNnxBERSZt/tB+z2RqjjX2ePHYUS+aqcr1wQl0Y0svZOuPESziXCGbgEUe00pZei+BnRfrPdhHQImCx/TE6cNEupFHug87msNUb6M7X22s0KB0d38Iudwoqcry4BXeN9OG0BF6JyumOvUbrX6Eme/KKSRCQg8e8mJfJ+0XkdQcGs7+MFXH5hWSRm8Ie46TTumVmLf0AyiYUPWWkxKSi+vnXtho3ro8EVlgSMaPZSRUQV6YVq1cYK6Tf5IcSHIgyYEkB5IcSHLgwuDARQsMiX1plExJz8qnMeoGaTcZHEaohQAaNzhkJHgY308Lkv0DGZgy7zrMWnojVdEmwJ9CeXGGeYvX0qq/D/k56zFjihe/2dyJZnrYGiRqrgzqY6IMfZUl/GdQIocRujZxvNaFrt2Bz1P9KawvtztlzGAwuK7NZeSeJwPMuOOYx7bPM1j2ICE+tE8jcUOAHQ8qi2i0c2EqrlhWjUtW0111xXQa4nS6gqR9ptWspaQQ3QFvfBTtjTvhC/ewDmJw/GBxKeVPz6TFzWRIciDJgSQHkhxIcmAYDkhKxu/NQNWMNRzoKBW0+wH0tu1hDj/VyniU9BqA6MHDKdjZSjCnM4DDTcAOqo7JFtEAPaK8rSyIQm8ILzen0LU9gZr0ILZxXOzjeJ5JNa+8FDqcoHBu44APmwgkSS7n2slhgjYhFKZ78I7ZHtR3e/DgXnpGIQZ1NyV73jmfZXGzY0+DjFpTSoiu5+v7vOigzcI5eSFMyfRhL9XVUtJCoOMyBDnQN9Lr2LdPpWBDix+n+mmgmtJD750ZwspK6rJx+JTqWFPvBORNWsv5xi0oJCj0VpESsq9YXseOHK0dBIAOH6lF7ckG4/bXqpG9/barcMfbr0lKC1mmJc9JDiQ5kORAkgNJDlwgHLiogSHtOEpyyAGCyNEIOhEFixgJl/4+SgoFOAGtuR5zV9xmQCH3O/CS1uyFl6Fi2lLM2LkJ88t/j0e56fXSHiIyg3SVQwiNRXtYkrm193rOawsO6dYAOroAinKzMauiBBUTciC3z+GI2pt56Epn7t1/9MwiL26CjHfaGpV5MK0l4jyvoueUG+d3Y96UDNSsvAazay5BTnYWQZ+hIuwC3KrnX47+nnbs3tyK/u7jbJVAMgW3vSEnJvk3yYEkB5IcSHIgyYGxcsCqllVWLcaxQ69QeuhBtHXv4biThlXVabikso8AUR8eOuzH8wRe/kg7P+X+EN4zqR+XEBh64aQX61tS0EYQqKJoAOkcpzI4FOfR61iJJIkG/GilN7MAVcAUwjRWrbGzLFt2gwjYUNIoQCDpJaqH1b5Gj2gcK+cR2JlN1bNrKYJ0asCLTe2pyD8Yxi3lAbybHtH29gSQxw2Tl5p82NiaAi/V0rTXMysvjP+zwoM1U7O4ARRGS1sQdc2UT8qYg3mr3ofJVB3zUzr3rQYKia+lJROwZPFc/OGPrxpASF7IfvWb5/nEg1/+6jksXjgb77zzWlRXT1LyZEhyIMmBJAeSHEhyIMmBC4gDFzUwJM9gcgdvpHbE1Iho0BkSQ5ys9WoSVzwd1XMvOwMUsu9D4FBuXh6WrliLCRPLML16E27YtRtPvMJdywOcUBrJG4FAFoiJAEICYgYrEXlmk0SIZ6SlEpCZiKml+fSKwkkkJXIyaRWzuy+GnSHlicrvkHEiSwoI5jCirpmGCoYkjGSKVMvkiYBEl8wI4c7FfZg5YybmLLsJkybPHJQScmgP/ZtGNT2phNUdrkTj8TrQnrcp0/4dmvr0XXd7M3Rk5tIwQzIkOZDkQJIDSQ4kOZAAB8xGD8fgqhmXcpihbZ7DryLUs5uGnU8DRFfO8WDD0QH8aAdVstp8OF7rxVPHB+ChqlghVblmEJQpoNTPKdoRzKSYTma6H+k0GF1Pw9NtBH88VDszmyxUCdNouYNSSK83eNHP8a2MhqKnZ0lhjcalG1LwZGMarq8IotQfpGRSCgboXOGZ1nQcoeTxpNQgiPXgWD+NZNO2ngxVX1UWwA3T/Jg6kTck3tIW4BgdRFtPPjecrsbchTe+5Q1M+wi8rb5kEda//Dp+/ZsXcPjICXzt6z/BpPJiXH/dpbj9tisxfdpkSmcP3YxKoHskkyQ5kORAkgNJDiQ5kOTAOHPgogaGujvq0NVey3leBBCJMGvonQOdaB6SkZ1L9bOR1ZwEEFVNm4uKydMxqeIPmJT+Q9w6qwWPvJ6PV2qLB1+JAJoS2ibKo9SNmWVK8oYAUUtHF13W0q07PXw1tPcgnQDQ5OIilBUW0T0tvabRvXvlxDyKW5fj9f3H0SNPYO7ABmSkpaC8KB9Ty4qQlyUbC2H0DXD2yrOXwFL/QAi+GZzsdvXy6EJrZzeOnuKWZVSYX9KMK6tOoHryJFx+/T2YNY+7lbSpFC0lFJXN3PZ0NKKv6xTLo2FvVwLx1409uR5hoL+HB2XmkQSG3HxJXic5kORAkgNJDozMASs9JMmao4c2DwGIOqmBPTsriK9f7sFrVCnbUhvAThp73klpIU+/B48dCGJXrY82iID5dAs/q7COfbhgAAAaj0lEQVQflSkhhAgOVXDoP0kj0Rq90sOUKiJ45A9SFpYqY4srPTRgHcaRVi+WFgdxOT2eHe0YQC7VzV5u9hMAIqDE0E9p4F09fkoL+cyYOEFGpauB2+amUTIpA41NfTjREOSGD8fm3gIDCK1YcD0Kiia/ZaWEDGNcf6qmlOM//u2vce9H78JJqpEpVFaWYmpVBdLSU5OgkItXycskB5IcSHIgyYEkBy4kDly0wFBny2G0NexCcEAqWW7YwgEt3OCQhHlSUnzobDqI5tp9yCkoG/EdCDiRUeqZc5Ygy9uAV//4CN6/6CBumX0Uj++twv62KZhSXIxJRQU00EwbAgzeiJh6cW4OwR+6dOcxlYd2xzIpMZRCN7sDAYE7qqMfkwoLkTIrhbYJOmhnIYxeGmcsys0gzVyCQLSF4E0x+bQLp5ASEX/3cjc1ixNShQzWsTA7G55SGt+cWIhdR+rRQqCohjudN808joKUZoqzBzC1fCJKJrC8tEyTb6Q/Hc3H0XpqNwZovykU7HFwrxiZLEAk72UpFONvqd+HhhP7kDehIkbqZFSSA0kOJDmQ5ECSA8NzYFB6aPolRvXKAkRBShAFezkuUdB2No05Ly9PIeACI0W0pZYbMT00SE1D0G8QKFJ4vhP46eEQsrlR00Jj0QolHqqVdwTx+yNUH+NwvDQ3gBSme7UnFVu7/dhDg9V5/jDBHdoFInDUyLHYGbVB+0VhIxm0YKIH08ozMSnXx80pbs7wqKWHtA5qXHszZmPu6rsplbvIOHR4q6qNGWbG+KP5Sk5OFmrmzcC8OdNMCs2NklJCMZiVjEpyIMmBJAeSHEhy4ALiwEULDPV0nKLKEqWF6KJ+UGIoIjnkCImf5rIglJQ0Pwb6TmH/q49SYiYVk2asOp1gmKtQoAvB/lYapSZQE8xEehcNSi5l2cE+1FE0vSlYbCaXgnpC3IE0kA9tFRAlQip3IB3gxPkbMBI/FkoJEwyi/YO8HBRkZTAvjWESRNIEipAUslIpWURqQdJ06DpCSaoqIafBGyrTIU3AVDgFU/ObsCTvAIoymw1wlOHrRoaPM1XZVuhqQHebs3snGsOFrlYajNz3e4JobyDQ30H+yn/L6XqfvnaqoScC31Ipit/ddgwnDryGMnp7y8qdOFwxyWdJDiQ5kORAkgNJDsTlQDRApLHI2iBqaNqBJqqSF2WFMY2ewmbNSUE+7QkJKdpIj2YWKJKR6ka6jW/udTZYGsJ+PEuX9l4JtrrCACcKAUoEHe7SqApMpNTQBNIuoh71ohIvrqkEKvK0YZOJFCboonr6CUos5eenc4gNoCs0A/MvvRsVVUvp1CLjLedtzMWqhC4FENlNrYQyJBMlOZDkQJIDSQ4kOZDkwJvKgYsSGOpsOYKWk6+jt7OBruppX4BzQWFCgQDVrXoHaE9oAAJhfH56PIkcabQ1kEKNrO62g9i76RfM40H59JUjMj840Im+7mZTjiY5eTke5DNvf7AXhd2vU11sK7ro6ezUwEzUD8wjSORI8gwl7MQJQLFQkQOpKBW9lFF1DWYz00kX5uQ0yAYNAbgsWYfIYHY/OpGfegoTUw/QDW8t0r3tSPMH4KfL3FCwn4dKoC2j9v+/vTt7buu+7gD+JQFiIwmQBHdKXESKlkRRoiU5oupYthIn6ThJx55pp50+9LGP/YP63j40mXYyfYjbvMR1Y8d2FSuyLYmbTHETF3EDQOxLv+dSEEGKFJyItkTweycQQGwX+FzPAPni/M5ZRDxaPhhKRB5i5cFHWJ7+GJuPpui43XQ6x3J7G0lv1naeZ78FN0v0a3gqbm7+yprNpvDgqw/Q3HEKQ9feLd6kcwlIQAISkMCfJVAMiOzB1oPoZN8VzNz/DHMPbnP51hcoJDlSjJ90SVYS+Wuy6K9jNdGVAH802W4IbR/L1hg6y3Hp8xwxb2HRAs8XWDlkVT8d/OHHNqsI6mTDaneNm0uo+bFsn7fc4gyBNiIMf+J2GzDNUWSRZAMK7mbUtL6KCzd+jPqGLgVC21z6VwISkIAEJCCBIyhw5IKhdGIDq/M3sfbwNsfUby8jsxBoK5pCdDPJMKiOjY/bUc9lUz5/iN8VC1hbnGbYMc0x6m4Eg15sbUzhy9/+M5b4xbJ3+Edo7HjlwEOXTW85gUo6tR2Q2B3tV0t3VQYhP4MQjrt1b26hib8sXuYkkxibUS5vujEXacF6vJYBSjHRKd3F42+bpVc5l3lfm2j2JBLajpGePAMvWDFSU2ALA433uc8MGps74WPFENsBIbqyzibR2z+DWiBU3PgqWXmUQCJiPYM24K3lqJV9tvjGA5p8gIdTn2D14V0GYpt8XIH9jNxIpdy8vP26LbiyIM6Wj1nvJguH/P6cs5TM62GZfnoF92+9j1C4AycGy4dv+7wUXSUBCUhAAhJ4SqAYEvUNvoGe/mv8jGWPPqskmr6F+Rl+L0jcdYKiNS4Ps08sP38QslM2zUpbbidDNajnDye9HDlfe8rD5eisOs7yM93DMIiPiLBpdA17EgVrXYgwaLKwaSPKB7rbEcuG0dA4jKujDIJCXJLOJef2eo7bcjEHUv9IQAISkIAEJFBRAkcqGLJQaOnrD7H84GMkGVrkc1nEY2lsrG4hEOrCyFs/RlvvMCuDvHDV8MQvbLbMLJXYwtzk5xi/+V9YXLgPPwOi+rokvyiuw5aKta1f4sSy0wyTencdXGu8vLE8xtBpjb82liQtxXvxW2eB01DCrb0YvPxX6BwcRSrrxvz9W9h4eI89hlJY24hhld9QE4k0oqlajsXt4HQUC4zsF0zWBFnq8yT54fdMPqeFLfZLZdAbY/i0xfM4wr5l1AZ8CAQ8CDa1cync33HCSRdquQwtl1jG13/8T0wmZhGL7KmPd14rd1CVw8biPQZqY+jYUyllfZqij+5ide4m5iY+xfLcXSTiacTZb6HGF4Y/2MypIoPoOXOVy8N2mkpvcfrYyvwkZsc+Yb+ncScc8noLbDCZQWx9Anc/+oVTSt7R/1pRTOcSkIAEJCCB5xYoBkSMfZznKgZF9sNNZH0OcwyKIptLYNshLG0uMhlaRZ4/WiC3ijp+B7DP2jibWXNRNyIMkaJxTi5taOco+zCi6zlUbfIzOMTP2p6LrCJqQ7CxE8GGDn4+Kwh67oOnJ5CABCTwogQ4wAdufm5wOrQ2CUhgt0AVg5OSWGL3jS/bXwsTH2P8/37BSpZ5VgZxjT8nfiXiLrScHEH/xbfRzr42vgCrhPbZUvEoNlcXMDP2GcZuvs9laPNobPKirj7EsCWM5u4LaD55EbWNPQxCOp3eOusPP8fi1P9gaeZLhkMsyaFUkcs5J12CfQv6ht/DpR/+A7z+oLPnfC7jhFZ2nxg7WMZiCX7RXOTyt6+wsTSJRwvjsB5J9nMmF2VxMq+fDazZ4DITZXPqPHsNufn+atHR/z10DV5DbX0rQk0tHLvrgY9TPTyccmbBV3GymO1vfuwD3P39vzKoucPlXPyWy41P/2RzVXv5PJ3oGfohBi6/64Rg2XQM8fX7iCzfweKDPziBUGRthe81jWSqhgHSKM5zOZhV/vg4za021MxSeY7ifbxl2QE0FY/wcRMY+8NvMDf+CfsxPWJYxffA6WvZbD36zr+JkRt/j6b27SaUxcfqXAISkIAEJPBtCBT4y0uOn4vFwRR5p4SWv8Y4gyr4mctUKLKxyNOSs/v6UBvqeKq2klx+cha/FdlnrAVQVfy1xoY+2Lk2CUhAAhI4ogL2GcAVFMjyVwGG/NsBEc+1SUACjsCRikttyVdD2zCmbs1yKkmUS8Y6MfT6X6L7zOtPhRZ7j6+NqW8NvIIgQ45wRx9u/++/Y3Xhc37RizDESSA/k+RSqxlW43Sx+qiNXyqzDHPmsbb8NXsWRfY+nfO3La1qaDmNzv5LT0Ihu8HG3dvJtkZOAWtsbEThRDvy54ZYWTONO7/7F8zce8Avn+wDxOZCruo0gyD2FUIanuoUx9hzdG5TB86/+n0GK2/wNfILKb+gHrTZvtrYc2F96WueptkPyaqGdnr/2OPyeYY4yTU8mv2cVU4xeoV5LX9ZXZvhsrEJxDbZUHsr5fRQCDWfw8hr76D37DVOF+vcFQbZcxU3N5s2uRkWnQwE0dTWjene8/jyo1/xPY45X6xDrZ1oP3WJX7hbiw/RuQQkIAEJSOBbFbAAx80fQ561hVtDaGwZcO6i0OdZUrpNAhKQQIUI2P+X4g/vzqlC3pLehgQOU+BIBUP+uiYMXvk5g48cK1xu49SFH7Ba58aBVUL7QfkYYpwcfI0BURfDmY8w+cf/ZvPKOTTklll9tM4gaIqhjpvBBqeEsbF1OhXncjM2uOaT7S2tynMSWGv3JU7gurDfrnZd5/zy6PbC3kOgPsyeBB5W1ERRzbL3Avv4ZHgqViNZY2dXTRAe9kgqBky7nmyfPzz+Br6nXngDrQyyNhkkcdZuyWaNrDNspP1o6S5DoFku9wow/ErzPUcZGCXZQ4iNO9lHqJPjgUfe/Ft09g07VUIlT3HgRQuIQs1dOHP5R06I9Plv/417K2Dk+t/g1PB1vo/6Ax+rGyQgAQlIQALftYCFR5xN9l3vVvuTgAQkIAEJSEACL6XAkQqGTDDAfjdnR99F34UbzuWDlo49S9uCjHB7r9Mvx+Orx1e//w8u95pDfX2e4QkDFYZC2yFN8fzpZysUXAxD+tHWcx4eX93TdzjgGm+ggdVAnXyMH9mYdbTc2XbCJ5v+ZWXrpYvBdu530CXrBRQItnLJ3NRTd3Gem+X02XQCW5wclohv8D2y3J5L1xJJVjh52jDw6ijOfe8ddJ4aPrBK6KknLrnCqrIGLlxn8NXkBEN/SrhU8jS6KAEJSEACEpCABCQgAQlIQAISkMB3JHDkgiFzsXDITs+7WfXQwMW32Fegmo2pf4VkcoaVNCW/IJaUCJVc3N4tyxH9dY3w1+7f0+ig12YVQF5/LSd4cUzKnq24j0KhmuFKM3sC2XKvb75ZL4RihZE9V2msVHxup+6JS9hyOTbT5nSxVJqPqWnHEMO2odF3yi7JK/dqLBw6OXiZd2NLz5J+ROUep9slIAEJSEACEpCABCQgAQlIQAIS+O4FSlKQ737nL8MevVzmZMudeoduMCdp5Kh1e1UWo+xEKfu9TivmSW0tIbIyiUxyd+XPfvcvvc7t5lQTjpg/aLOeQjWsKLLpat90i3EKy8Lkx4isTjMRYnPNAx64c30VsmwQnU67+d7fwMU33nOWgx1GmOP0HlIodMAR0NUSkIAEJCABCUhAAhKQgAQkIIGXR+BIVgwdNp+FQ6df/QmSW2uYufNrFNzlgyF2cGYgtMoR75+Aw8LQ0H4OPk79cnnY1OwZWyq2hNjGNPsLsSv+AZubg1FcPFmfnnLb9qj5SU4l+xBzY7/jtLM5PiRz4MPsGav4j4VCiaSHk8eusVLop06l0IEP0g0SkIAEJCABCUhAAhKQgAQkIAEJVKSAgqHHh9X64nT1X0bk0QQSm1Ps8WPhysHBjIU2mVQUy7O3WTm0gpa1Sfhqm9louQU1gWZW/IS4ZIzLzDgW10bj8n9IJ1YQW7nLKqN7SCdtctjuzap5bI/sfY1kZBaxtVnUN3bsulMuE0c2s4V0/BESGw8YBD3E8swdLEx/gVhkxRnRW7VnIpk9QWmlkP2dybjY62gAZ678BK0nB+0qbRKQgAQkIAEJSEACEpCABCQgAQkcMwEFQyUHvLX7PMe9X8L0l7OsqsmxOTP78Dxjy7OZcyoVwypH2kc3Frn0y88wqJHBToBLxQK8XM+ePxxH7+b0Ey4PYzSE6Po8lucnOQns6WCoGEMV8klsrU9icfx9JkRfswqpzgmMspkEHxdjwBTj8yzg0cIYq5zWnZDJmZ6Wfzyi/nEKtBMGlUZc1lC7mgFSNSeYsRF2Q6t6AT3jGOsmCUhAAhKQgAQkIAEJSEACEpBAJQsoGCo5ujZdzMau14ZakYotcoLX0+GN3T2XLXApmIUwNtLeLltjohRH0EcYBq1yGZhFMlWoZoNq26xayP6282wmDQtxCgyVDt7yiMdWMPnFbzAz/uH21DM+OJWIIs+m0RZI2fMkEwme5/k3eGL4xP1WVxec/TjnvLx3s5eSy1Uhx/u3dJ1Gy4lX9t5Ff0tAAhKQgAQkIAEJSEACEpCABCRwTAQUDO050G42fLapYZnEbhoLVLIMgeLxHLZiFswU4K9v4FSyJlYKbT9JPLaG9fV1J5ix6zw1nMzFfkXWZ7pgGQ3/KdgF5489O97zZy6XYTi0jq1ogWGPVRvZ/vM8ubkMrJo9guxvF6MpFwKcjsYUClsR2zeDIV52MZOy/Xt9WQZGOyGU8zJsYRknktkEMR9P2iQgAQlIQAISkIAEJCABCUhAAhI4ngK704/jabDrXXv9QdRxeZVVDKWTvOlx0U18K4/IRhbVniB6zr2GnrOjCDZ1cBnW41SId7Uqnlw2hZX5Kaw+nMDa4iSXe03Ay+FiFg65XRYU8Y6WMtn2+Lm3/9i+es9VzJCqkUxWI8PpYVYV5K8LY+D8VYQ7TvNyE6ubwk9eg+3ftkcLk1iZm+CyuElsLo/D48mjxp1maGQBUXHnzl31jwQkIAEJSEACEpCABCQgAQlIQALHWEDB0J6D73Z7GOC4GchwfVYxFGKVUCpTi+6hKzh1/rrTrLku1Hxgb5627jNIxqNI8bS6NM2QaBKz458iwpDG59sOh6q3V5nt2vveUCjHiqBUqoaNrFswMDSKboZRIYZRFgZ5A0EnENpvvHx7z1nuO8KlZzHMT36GqVvvs5H1BKuIUnxf2V371B8SkIAEJCABCUhAAhKQgAQkIAEJHF8BBUN7jn0yvsLGzrOs0LFyISCxxVAoXYvTl36Gc1d/hmcFQsWnsqbTdkIYaGrvQ/fpyzg98jYWpm5i7OavOZVsEn6/jaTfWeJVfKydF/JVSKdd7EVUg86BUZx//T20nhh0RsrvFwSVPtYu2/Kw4hKxULgDgfpGjH/6S+73DueV5bnqLM/lZuxjFFnj8rNV1Ab5QrVJQAISkIAEJCABCUhAAhKQgAQkcOwEFAyVHHIbP2/TvqIba2w8nWG1Tg6RzQxae8+i/8JbaGBj6j91s6VmblYX1fLUEO7kOPsQbn/4S0RXx+Bn9VA1A5q9m4VCqG7FwMhVnBv9OTpODR9YnbT3sXv/tsqivqHr7Jm0jonPVhGPzqPgSrF6KM/wi82redImAQlIQAISkIAEJCABCUhAAhKQwPEU2GdB0/GEsHcdjy5jY2XWGf9uS64SXEIWCPXhlUtvI9ze+9ww1ux54MJ1XHzjrxFqeQXpjMfpIVR8Yuv+k2EolEy60Tv0JkZ/+o/PFQoVn9fD6qWu01fRcvICgyjrieRitVLB6YO0zF5E2iQgAQlIQAISkIAEJCABCUhAAhI4ngIKhkqOuzWLXnrwFQOhFOJcQmbBUOepi+g9d+3PrtgpeXrnoi0x62c41DVwhc2kPTztFG1ls1VOKNTYOshg6BpCrFD6JkvH9u5jv7+DzT1o7RmBJ9DCMKrGmZwWWZ3B3OQtZznZfo/RdRKQgAQkIAEJSEACEpCABCQgAQlUtoCCoZLj6/GF2HunDtFIGutrGdQ29uHE6UtP+vWU3PW5Llo4dKJ/BM0dZ9jfmuPKHm95jpDPs79Q18AlnBy8XLz6UM5dbKptwVC4a5hj7n2sVvKihhPWrNl2cZrZoexITyIBCUhAAhKQgAQkIAEJSEACEpDAkRHYKVc5Mi/523uhLSeGcPWdf3KqaBYf3EMXq4UOO6ApvvqG1m6nMXVsbZwT5NlTiEvXctlqNLQMMIwaOfQwyvZbH+5GW8+rWFt+iGBzH3rOfX+7qXWwqfiydC4BCUhAAhKQgAQkIAEJSEACEpDAMRJQMFRysD2+eoQ76lHX0I7es3/BkfA7071K7nYoF+sb2xBiM2qXywcuIEM2l3OCoca2Xr6GvkPZx94nsaqh3vM30NI9DHuvAU4jO6ylanv3pb8lIAEJSEACEpCABCQgAQlIQAISePkFFAztc4yejJvf57bDuspCmrqGVtSF2pCIxpHLJXmqQpDj5YMMjL6tzV8fhp20SUACEpCABCQgAQlIQAISkIAEJCAB9Rh6gf8N1Hi8qHa5GQjl2RCaq8n4Wtxur6p4XuAx0a4lIAEJSEACEpCABCQgAQlIQALHSUAVQy/4aGeyWSTTOTaEdsFX28BqnoYX/Iq0ewlIQAISkIAEJCABCUhAAhKQgASOi4Aqhl7gkbZKoVQqg3iiComUmz2o/XB7fC/wFWnXEpCABCQgAQlIQAISkIAEJCABCRwngaoCt+P0hl+m95qIrmFz9SEy6QSXkhWcJWTWX6gu1PwyvUy9FglIQAISkIAEJCABCUhAAhKQgAQqVEDBUIUeWL0tCUhAAhKQgAQkIAEJSEACEpCABCRQTkBLycoJ6XYJSEACEpCABCQgAQlIQAISkIAEJFChAgqGKvTA6m1JQAISkIAEJCABCUhAAhKQgAQkIIFyAgqGygnpdglIQAISkIAEJCABCUhAAhKQgAQkUKECCoYq9MDqbUlAAhKQgAQkIAEJSEACEpCABCQggXICCobKCel2CUhAAhKQgAQkIAEJSEACEpCABCRQoQIKhir0wOptSUACEpCABCQgAQlIQAISkIAEJCCBcgIKhsoJ6XYJSEACEpCABCQgAQlIQAISkIAEJFChAgqGKvTA6m1JQAISkIAEJCABCUhAAhKQgAQkIIFyAgqGygnpdglIQAISkIAEJCABCUhAAhKQgAQkUKECCoYq9MDqbUlAAhKQgAQkIAEJSEACEpCABCQggXICCobKCel2CUhAAhKQgAQkIAEJSEACEpCABCRQoQIKhir0wOptSUACEpCABCQgAQlIQAISkIAEJCCBcgIKhsoJ6XYJSEACEpCABCQgAQlIQAISkIAEJFChAgqGKvTA6m1JQAISkIAEJCABCUhAAhKQgAQkIIFyAgqGygnpdglIQAISkIAEJCABCUhAAhKQgAQkUKECCoYq9MDqbUlAAhKQgAQkIAEJSEACEpCABCQggXIC/w/0zoxX9FG74gAAAABJRU5ErkJggg==" + } + }, + "cell_type": "markdown", + "id": "325aa8a5-92fd-4913-a471-ad1617343be6", + "metadata": {}, + "source": [ + "# 303.3. Color Selections\n", + "\n", + "
\n", + "\n", + "![logo.png](attachment:697dbfa5-0793-4e9d-8401-2f3b86b0243c.png)\n", + "\n", + "
\n", + "\n", + "For the Rubin Science Platform at data.lsst.cloud.
\n", + "Data Release: Data Preview 1
\n", + "Container Size: large
\n", + "LSST Science Pipelines version: r29.2.0
\n", + "Last verified to run: 2025-09-02
\n", + "Repository: github.com/lsst/tutorial-notebooks
" + ] + }, + { + "cell_type": "markdown", + "id": "9da1a210-d858-42fe-8591-570965b8be1a", + "metadata": {}, + "source": [ + "**Learning objective:** Explore the available measurements of galaxy photometry produced by the LSST pipelines and their applications.\n", + "\n", + "**LSST data products:** `Object` table\n", + "\n", + "**Packages:** `lsst.rsp.get_tap_service `\n", + "\n", + "**Credit:**\n", + "This notebook benefitted from an earlier exploration of simulated data and notebook development by Melissa Graham and Dan Taranu, helpful discussions with Jim Bosch, and ideas from Douglas Tucker. \n", + "\n", + "**Get Support:**\n", + "Everyone is encouraged to ask questions or raise issues in the \n", + "Support Category \n", + "of the Rubin Community Forum.\n", + "Rubin staff will respond to all questions posted there." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "cfc73be0", + "metadata": {}, + "source": [ + "## 1. Introduction \n", + "\n", + "Photometry is the measurement of how much light is apparent from astronomical sources. The amount of light arriving on the telescope from the object is typically referred to as the flux density, or apparent magnitude (depending on units). Flux density is defined as the amount of energy arriving on the telescope per unit area, per unit time, per unit frequency (or wavelength) of the light.\n", + "\n", + "The LSST Science Pipelines makes a variety of photometric measurements for point-like and extended sources. This notebook will teach the user about the automated photometry measurements for extended sources that are measured on the deepCoadd images and appear in the Object Catalog as part of the LSST pipelines data products.\n", + "\n", + "The photometry measurements in the catalogs are flux densities in units of nano-Jansky [nJy]. 1 Jy = 10^{-23} ergs/s/cm^2/Hz." + ] + }, + { + "cell_type": "markdown", + "id": "dc36f107", + "metadata": {}, + "source": [ + "### 1.1. Import packages\n", + "\n", + "Import `numpy`, a fundamental package for scientific computing with arrays in Python\n", + "(numpy.org), and\n", + "`matplotlib`, a comprehensive library for data visualization\n", + "(matplotlib.org; \n", + "matplotlib gallery).\n", + "\n", + "From the `lsst` package, import modules for accessing the Table Access Protocol (TAP) service,\n", + "the butler, and image display functions from the LSST Science Pipelines (pipelines.lsst.io)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cddc1458", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from lsst.rsp import get_tap_service\n", + "\n", + "from scipy.stats import binned_statistic" + ] + }, + { + "cell_type": "markdown", + "id": "c217adff-25ed-4fce-95e7-8aa04630f6cc", + "metadata": {}, + "source": [ + "### 1.2. Define parameters and functions" + ] + }, + { + "cell_type": "markdown", + "id": "d3383f6e-8c34-4cb7-aa2f-12e9b7f8efc0", + "metadata": {}, + "source": [ + "Get an instance of the TAP service, and assert that it exists." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e8184089-8a3e-4666-a194-5362a8faa541", + "metadata": {}, + "outputs": [], + "source": [ + "service = get_tap_service(\"tap\")\n", + "assert service is not None" + ] + }, + { + "cell_type": "markdown", + "id": "557bbb99-3a37-4b15-ad6d-e86c6282866c", + "metadata": {}, + "source": [ + "## 2. Types of photometry\n", + "\n", + "This section will explore photometry measurements produced by the LSST pipelines, and provide some guidance for which are optimal for various applications for science with galaxies. \n", + "### 2.1. Explore the schema\n", + "\n", + "Numerous photometry measurements are produced by the LSST Pipelines. Two types of photometry are in the object table. The first are total fluxes (see Section 3), which aim to approximate (or model) all of the light coming from object. The second class of fluxes are measured inside an on-sky aperture but not corrected for flux that may fall outside: thus they are apparent fluxes but do not recover the intrisic (total) flux (see Section 4 and 5). The apparent fluxes are optimized for other purposes, such as for measuring accurate light profiles or accurate colors. \n", + "\n", + "Schema for the object catalog for DP1 is available here. It lists the catalog header and brief explanation of the parameters.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "1513ee4c-0a00-4868-8525-53aaccfff9b1", + "metadata": {}, + "source": [ + "First, see what is available in the object table by querying the `tap_schema` columns, and printing all the parameters available related to \"Flux\" measured in the i-band (as an example). For clarity, the return also omits errors and flags associated with the photometric measurements outlined in section 1.1. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d532f5a-52ad-408d-bce6-a5a4d346477f", + "metadata": {}, + "outputs": [], + "source": [ + "query = \"SELECT column_name, datatype, description, unit \" \\\n", + " \"FROM tap_schema.columns \" \\\n", + " \"WHERE table_name = 'dp1.Object'\"\n", + "\n", + "results = service.search(query).to_table()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84849d6b-527d-4ac7-9cbb-09df352f7b34", + "metadata": {}, + "outputs": [], + "source": [ + "search_string = 'Flux'\n", + "band = 'i_'\n", + "exclude1 = 'Err'\n", + "exclude2 = 'flag'\n", + "for cname in results['column_name']:\n", + " if cname.find(search_string) > -1 and cname.find(band) > -1 and \\\n", + " cname.find(exclude1) == -1 and cname.find(exclude2) == -1:\n", + "\n", + " print(cname)" + ] + }, + { + "cell_type": "markdown", + "id": "5dd9c7cb-8ab0-4f7c-9161-69fa29d46537", + "metadata": {}, + "source": [ + "The object catalog also has pre-computed AB magnitudes (`Mag` columns) for cModel and PSF. Query the `tap_schema` columns, and print all the parameters available related to `Mag` measured in the i-band. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6225c1c4-e324-4846-b49b-06471a4abe59", + "metadata": {}, + "outputs": [], + "source": [ + "search_string = 'Mag'\n", + "band = 'i_'\n", + "exclude1 = 'Err'\n", + "for cname in results['column_name']:\n", + " if cname.find(search_string) > -1 and cname.find(band) > -1 and \\\n", + " cname.find(exclude1) == -1:\n", + "\n", + " print(cname)" + ] + }, + { + "cell_type": "markdown", + "id": "ac0528ca-2ec6-405e-b4ea-e897ef96de67", + "metadata": {}, + "source": [ + "\n", + "### 2.2. Select a galaxy sample\n", + "\n", + "Below, query the DP1 `objectTable` for a selection of photometric measurements. \n", + "\n", + "Limit the search to contain galaxies using the `i_extendedness` flag (which will exclude point sources). Further, identify objects which have been detected at high signal to noise > 20 and whose photometric measurements have not been flagged as having an issue (`i_kronFlux_flag` or `i_cModel_flag` or `sersic_no_data_flag` = 0 means the photometry is ok). Also exclude very bright galaxies (i-band magnitude < 20).\n", + "\n", + "Search for the sample using the DP1 imaging obtained in the Extended Chandra Deep Field South (ECDFS; center ra, dec = 53.2, -28.1 in degrees) which was one of the deepest imaging obtained as part of DP1.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73dd5a5f-b761-4d4f-96b6-5767cffbb310", + "metadata": {}, + "outputs": [], + "source": [ + "target_ra = 53.2\n", + "target_dec = -28.1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "75150971-e118-48d5-9db7-74c0fe600762", + "metadata": {}, + "outputs": [], + "source": [ + "query = \"SELECT obj.objectId, obj.coord_ra, obj.coord_dec, \" + \\\n", + " \"obj.detect_fromBlend, obj.detect_isIsolated, \" + \\\n", + " \"obj.i_blendedness, obj.i_extendedness, \" + \\\n", + " \"obj.u_sersicFlux, obj.u_sersicFluxErr, obj.u_gaap1p0Flux, \" + \\\n", + " \"obj.g_sersicFlux, obj.g_sersicFluxErr, obj.g_gaap1p0Flux, \" + \\\n", + " \"obj.r_sersicFlux, obj.r_sersicFluxErr, obj.r_gaap1p0Flux, \" + \\\n", + " \"obj.i_sersicFlux, obj.i_sersicFluxErr, obj.i_gaap1p0Flux, \" + \\\n", + " \"obj.u_cModelMag, obj.u_cModelMagErr, \" + \\\n", + " \"obj.g_cModelMag, obj.g_cModelMagErr, \" + \\\n", + " \"obj.r_cModelMag, obj.r_cModelMagErr, \" + \\\n", + " \"obj.i_cModelMag, obj.i_cModelMagErr, \" + \\\n", + " \"obj.u_cModelFlux, obj.u_cModelFluxErr, \" + \\\n", + " \"obj.g_cModelFlux, obj.g_cModelFluxErr, \" + \\\n", + " \"obj.r_cModelFlux, obj.r_cModelFluxErr, \" + \\\n", + " \"obj.i_cModelFlux, obj.i_cModelFluxErr, \" + \\\n", + " \"obj.i_kronFlux_flag, obj.i_cModel_flag, obj.sersic_no_data_flag \" + \\\n", + " \"FROM dp1.Object AS obj \" + \\\n", + " \"WHERE (obj.i_sersicFlux/obj.i_sersicFluxErr > 10) AND \" + \\\n", + " \"(obj.i_extendedness = 1) AND (obj.sersic_no_data_flag = 0) AND \" + \\\n", + " \"(obj.i_cModel_flag = 0) AND \" + \\\n", + " \"(scisql_nanojanskyToAbMag(obj.i_sersicFlux) > 20) AND \" + \\\n", + " \"CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), \" + \\\n", + " \"CIRCLE('ICRS',\"+str(target_ra)+\",\"+str(target_dec)+\", 0.5)) = 1 \"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "867871f3-d378-4cc5-88df-d91cfb01e259", + "metadata": {}, + "outputs": [], + "source": [ + "job = service.submit_job(query)\n", + "job.run()\n", + "job.wait(phases=['COMPLETED', 'ERROR'])\n", + "print('Job phase is', job.phase)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b6cd0ba-132a-4552-b389-32e54d8591dc", + "metadata": {}, + "outputs": [], + "source": [ + "if job.phase == 'ERROR':\n", + " job.raise_if_error()\n", + "assert job.phase == 'COMPLETED'" + ] + }, + { + "cell_type": "markdown", + "id": "f38080f1-9a2d-48af-834d-1b49de86944f", + "metadata": {}, + "source": [ + "Print the results of the search query." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e4a20e0-101d-4644-90e1-b0bd1058aae1", + "metadata": {}, + "outputs": [], + "source": [ + "results = job.fetch_result()\n", + "tab = results.to_table()\n", + "tab" + ] + }, + { + "cell_type": "markdown", + "id": "c9c94c7d-8635-4bbd-83e6-3eb64aea2b24", + "metadata": {}, + "source": [ + "Below, convert the fluxes (units $nJy$) extracted from the `objectTable` into AB magnitudes using: $m_{AB} = -2.5log( f_{nJy}) + 31.4$ (see e.g. AB Magnitudes Wikipedia page for the conversion between flux in Jy and AB magnitudes).\n", + "\n", + "> **Warning:** The following cell will produce warnings for invalid value encountered in log10, which happens if the source flux is negative. This occasionally happens from aperture photometry if the included pixels inside the aperture have negative values and can be safely ignored for this example. The log10 will return a NaN which can be filtered out later." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d58eacea-4573-433b-b9b1-382a24087dd1", + "metadata": {}, + "outputs": [], + "source": [ + "# old, does not re-set the flux to the upper limit when necessary\n", + "#cmodel_mag = -2.50 * np.log10(tab['i_cModelFlux']) + 31.4\n", + "#sersic_mag = -2.50 * np.log10(tab['i_sersicFlux']) + 31.4\n", + "#gaap_mag = -2.50 * np.log10(tab['i_gaap1p0Flux']) + 31.4\n", + "\n", + "# List of the filters you queried\n", + "#filters = ['u', 'g', 'r', 'i']\n", + "\n", + "# Temporarily ignore warnings for taking the log of negative/zero fluxes\n", + "#with np.errstate(divide='ignore', invalid='ignore'):\n", + "# for f in filters:\n", + " # 1. Convert Sersic Fluxes to AB Magnitudes\n", + " #tab[f'{f}_sersic_mag'] = -2.50 * np.log10(tab[f'{f}_sersicFlux']) + 31.4\n", + " \n", + " # 2. Convert GAAP Fluxes to AB Magnitudes\n", + " #tab[f'{f}_gaap_mag'] = -2.50 * np.log10(tab[f'{f}_gaap1p0Flux']) + 31.4\n", + " \n", + " # 3. Convert Sersic Flux Errors to Magnitude Errors\n", + " # The standard propagation of error formula for magnitudes is: \n", + " # mag_err = (2.5 / ln(10)) * (flux_err / flux)\n", + " #tab[f'{f}_sersic_magErr'] = 1.0857 * (tab[f'{f}_sersicFluxErr'] / tab[f'{f}_sersicFlux'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cdbbbc80-38e5-4ae9-bb84-6902828b13f5", + "metadata": {}, + "outputs": [], + "source": [ + "# this should be better\n", + "# List of the filters you queried\n", + "filters = ['u', 'g', 'r', 'i']\n", + "\n", + "# Use a zeropoint of 31.4 as per your specific dataset configuration\n", + "zp = 31.4\n", + "\n", + "# Temporarily ignore warnings for taking the log of negative/zero fluxes\n", + "with np.errstate(divide='ignore', invalid='ignore'):\n", + " for f in filters:\n", + " # 1. Apply Flux-Limit Logic: \n", + " # If flux is less than the error (S/N < 1), we replace it with the error \n", + " # value to calculate a 'Lower Limit' on the magnitude.\n", + " sersic_flux_robust = np.where(tab[f'{f}_sersicFlux'] < tab[f'{f}_sersicFluxErr'], \n", + " tab[f'{f}_sersicFluxErr'], \n", + " tab[f'{f}_sersicFlux'])\n", + " \n", + " #gaap_flux_robust = np.where(tab[f'{f}_gaap1p0Flux'] < tab[f'{f}_gaap1p0FluxErr'], \n", + " # tab[f'{f}_gaap1p0FluxErr'], \n", + " # tab[f'{f}_gaap1p0Flux'])\n", + "\n", + " # 2. Convert Robust Fluxes to AB Magnitudes\n", + " tab[f'{f}_sersic_mag'] = -2.50 * np.log10(sersic_flux_robust) + zp\n", + " #tab[f'{f}_gaap_mag'] = -2.50 * np.log10(gaap_flux_robust) + zp\n", + " \n", + " # 3. Convert Sersic Flux Errors to Magnitude Errors\n", + " # We use the original flux here to represent measurement uncertainty accurately\n", + " tab[f'{f}_sersic_magErr'] = 1.0857 * (tab[f'{f}_sersicFluxErr'] / tab[f'{f}_sersicFlux'])" + ] + }, + { + "cell_type": "markdown", + "id": "8d2de168-5282-4a26-8740-930ce13e362b", + "metadata": {}, + "source": [ + "### do Lyman break selection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09d09866-9c0d-434b-844b-076cf34f93df", + "metadata": {}, + "outputs": [], + "source": [ + "# 1. Calculate the colors using the Sersic magnitudes you generated\n", + "# We wrap this in a mask to drop NaNs so matplotlib doesn't complain\n", + "valid_mask = np.isfinite(tab['g_sersic_mag']) & \\\n", + " np.isfinite(tab['r_sersic_mag']) & \\\n", + " np.isfinite(tab['i_sersic_mag'])\n", + "\n", + "#u_mag = tab['u_sersic_mag'][valid_mask]\n", + "g_mag = tab['g_sersic_mag'][valid_mask]\n", + "r_mag = tab['r_sersic_mag'][valid_mask]\n", + "i_mag = tab['i_sersic_mag'][valid_mask]\n", + "\n", + "g_minus_r = g_mag - r_mag\n", + "r_minus_i = r_mag - i_mag\n", + "\n", + "# 2. Define the z~4 LBG (g-dropout) selection criteria\n", + "# These are standard photometric cuts to isolate z~4 galaxies and exclude red dwarf stars\n", + "#is_z4_lbg = (\n", + "# (g_minus_r > 1.0) & \n", + "# (r_minus_i < 1.0) & \n", + "# (g_minus_r > 1.5 * r_minus_i + 0.8)\n", + "#)\n", + "\n", + "# 2. Define the STRICT z~4 LBG selection criteria (Purity over Completeness)\n", + "is_z4_lbg = (\n", + " (g_minus_r > 1.5) & (tab['u_sersicFlux']/tab['u_sersicFluxErr'] < 3) & \n", + " (r_minus_i < 1.0) & #(r_minus_i > 0) & \n", + " (g_minus_r > 1.5 * r_minus_i + 0.8)\n", + ")\n", + "\n", + "# 3. Create the Color-Color Diagram\n", + "fig, ax = plt.subplots(figsize=(8, 6))\n", + "\n", + "# Plot the background distribution of all objects (gray)\n", + "ax.scatter(r_minus_i, g_minus_r, s=5, color='gray', alpha=0.3, label='All Objects')\n", + "\n", + "# Highlight the selected z~4 LBGs (blue)\n", + "ax.scatter(r_minus_i[is_z4_lbg], g_minus_r[is_z4_lbg], \n", + " s=20, color='blue', alpha=0.8, edgecolor='white', linewidth=0.5, label='z~4 LBGs')\n", + "\n", + "# 4. Draw the Selection Boundaries for visual reference\n", + "# Calculate the vertices of the selection region\n", + "x_diag = np.linspace(0.133, 1.0, 50)\n", + "y_diag = 1.5 * x_diag + 0.8\n", + "\n", + "# Plot the bounding lines\n", + "#ax.plot([-1.5, 0.133], [1.0, 1.0], color='red', linestyle='--', lw=2, label='Selection Boundary') # Bottom horizontal cut\n", + "#ax.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut to avoid M-stars\n", + "#ax.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2)\n", + "\n", + "# Plot the updated bounding lines\n", + "# 4. Draw the NEW Selection Boundaries\n", + "# Calculate the new intersection between the horizontal and diagonal lines\n", + "intersect_x = (1.5 - 0.8) / 1.5\n", + "ax.plot([-1.5, intersect_x], [1.5, 1.5], color='red', linestyle='--', lw=2, label='Selection Boundary') # Raised horizontal cut\n", + "ax.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut\n", + "ax.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2) # Right vertical cut\n", + "\n", + "# 5. Formatting\n", + "ax.set_xlim(-1.5, 2.0)\n", + "ax.set_ylim(-1.0, 4.0)\n", + "\n", + "ax.set_xlabel(r'(r−i) [AB Mag]', fontsize=14)\n", + "ax.set_ylabel(r'(g−r) [AB Mag]', fontsize=14)\n", + "ax.set_title(r'z∼4 Lyman-Break Galaxy Selection (g-dropouts)', fontsize=16, fontweight='bold')\n", + "\n", + "ax.grid(True, linestyle=':', alpha=0.6)\n", + "ax.legend(loc='upper left', fontsize=12)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "# Print out the results\n", + "print(f\"Total objects plotted: {len(g_mag)}\")\n", + "print(f\"Identified z~4 candidates: {np.sum(is_z4_lbg)}\")" + ] + }, + { + "cell_type": "markdown", + "id": "29ae8710-01c3-44bb-8edc-64de3738857a", + "metadata": {}, + "source": [ + "## Sanity checks: plot cutouts and SEDs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81ade6bd-3b62-472b-a0b6-48656837bd22", + "metadata": {}, + "outputs": [], + "source": [ + "import io\n", + "import numpy as np\n", + "import astropy.units as u\n", + "from astropy.io import fits\n", + "import matplotlib.pyplot as plt\n", + "\n", + "from pyvo.dal.adhoc import SodaQuery, DatalinkResults \n", + "from astropy.visualization import ZScaleInterval, LinearStretch, ImageNormalize\n", + "\n", + "from lsst.rsp import get_tap_service\n", + "from lsst.rsp.utils import get_pyvo_auth # <-- ADDED: The RSP auth utility\n", + "\n", + "# Initialize the TAP service AND the auth session\n", + "tap_service = get_tap_service(\"tap\")\n", + "session = get_pyvo_auth() # <-- ADDED: Define the session variable\n", + "\n", + "# Extract the coordinates of the high-purity candidates\n", + "cands_ra = tab['coord_ra'][valid_mask][is_z4_lbg]\n", + "cands_dec = tab['coord_dec'][valid_mask][is_z4_lbg]\n", + "\n", + "# Limit to the first 5 candidates so we don't spam the SODA service\n", + "n_plot = min(len(cands_ra), 5)\n", + "filters = ['u', 'g', 'r', 'i']\n", + "\n", + "# Set up the Matplotlib Grid & define Field of View\n", + "fig, axes = plt.subplots(n_plot, len(filters), figsize=(10, 2.5 * n_plot))\n", + "norm = ImageNormalize(stretch=LinearStretch(), interval=ZScaleInterval())\n", + "fov = 10.0 / 3600.0 # 10 arcseconds in degrees\n", + "\n", + "print(f\"Requesting DP1 SODA cutouts via TAP for {n_plot} candidates...\")\n", + "\n", + "for row_idx in range(n_plot):\n", + " ra = cands_ra[row_idx]\n", + " dec = cands_dec[row_idx]\n", + " \n", + " # Query the ivoa.ObsCore table using the image footprint (s_region)\n", + " query = f\"\"\"\n", + " SELECT lsst_band, access_url \n", + " FROM ivoa.ObsCore \n", + " WHERE dataproduct_subtype = 'lsst.deep_coadd' \n", + " AND obs_collection = 'LSST.DP1'\n", + " AND CONTAINS(POINT('ICRS', {ra}, {dec}), s_region) = 1\n", + " \"\"\"\n", + " \n", + " # Run the query synchronously\n", + " tap_job = tap_service.run_sync(query)\n", + " coadds = tap_job.to_table()\n", + " \n", + " for col_idx, f in enumerate(filters):\n", + " ax = axes[row_idx, col_idx] if n_plot > 1 else axes[col_idx]\n", + " \n", + " # Match the specific filter\n", + " band_match = coadds[coadds['lsst_band'] == f]\n", + " \n", + " if len(band_match) > 0:\n", + " try:\n", + " datalink_url = band_match['access_url'][0]\n", + " \n", + " # We now pass the active session to the Datalink & SODA tools\n", + " dl_result = DatalinkResults.from_result_url(datalink_url, session=session)\n", + " \n", + " # Execute the Synchronous SODA Cutout\n", + " sq = SodaQuery.from_resource(dl_result,\n", + " dl_result.get_adhocservice_by_id(\"cutout-sync\"),\n", + " session=session)\n", + " sq.circle = (ra * u.deg, dec * u.deg, fov * u.deg)\n", + " \n", + " cutout_bytes = sq.execute_stream().read()\n", + " sq.raise_if_error()\n", + " \n", + " # Open the byte stream into an Astropy FITS object\n", + " hdul = fits.open(io.BytesIO(cutout_bytes))\n", + " \n", + " # HDU 1 contains the actual science 'image' array\n", + " img_array = hdul[1].data\n", + " \n", + " # Plot the array\n", + " ax.imshow(img_array, origin='lower', cmap='gray', norm=norm)\n", + " \n", + " # SODA automatically centers the cutout on the requested RA/Dec\n", + " center_y, center_x = img_array.shape[0] // 2, img_array.shape[1] // 2\n", + " circle = plt.Circle((center_x, center_y), radius=5, color='red', fill=False, lw=1, alpha=0.5)\n", + " ax.add_patch(circle)\n", + "\n", + " except Exception as e:\n", + " print(f\"Error on Cand {row_idx+1} {f}-band: {e}\")\n", + " ax.text(0.5, 0.5, 'SODA Error', ha='center', va='center', transform=ax.transAxes, color='red')\n", + " else:\n", + " ax.text(0.5, 0.5, 'No Coverage', ha='center', va='center', transform=ax.transAxes, color='red')\n", + " \n", + " # Formatting\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + " \n", + " if row_idx == 0:\n", + " ax.set_title(f\"{f}-band\", fontsize=16, fontweight='bold')\n", + " if col_idx == 0:\n", + " ax.set_ylabel(f\"Cand {row_idx+1}\\nRA: {ra:.3f}\", fontsize=12, rotation=0, labelpad=40, ha='center')\n", + "\n", + "plt.subplots_adjust(wspace=0.05, hspace=0.05)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e5fd667-471d-46e0-96d1-cba433de8ead", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# 1. Identify the best candidate (the one with the reddest g-r color)\n", + "high_purity_ids = tab['objectId'][valid_mask][is_z4_lbg]\n", + "#best_candidate_id = high_purity_ids[np.argmax(g_minus_r[is_z4_lbg])]\n", + "best_candidate_id = high_purity_ids[0]#np.argmax(g_minus_r[is_z4_lbg])]\n", + "\n", + "# 2. Query all 6 bands using forced cModelFlux for accurate multi-band colors\n", + "sed_query = f\"\"\"\n", + "SELECT \n", + " u_cModelFlux, g_cModelFlux, r_cModelFlux, \n", + " i_cModelFlux, z_cModelFlux, y_cModelFlux,\n", + " u_cModelFluxErr, g_cModelFluxErr, r_cModelFluxErr, \n", + " i_cModelFluxErr, z_cModelFluxErr, y_cModelFluxErr\n", + "FROM dp1.Object \n", + "WHERE objectId = {best_candidate_id}\n", + "\"\"\"\n", + "\n", + "sed_job = tap_service.run_sync(sed_query)\n", + "sed_data = sed_job.to_table()[0] # Isolate the single row\n", + "\n", + "# 3. Define the filters and their effective wavelengths in Angstroms\n", + "filters = ['u', 'g', 'r', 'i', 'z', 'y']\n", + "wavelengths = [3671, 4826, 6223, 7545, 8691, 9710]\n", + "\n", + "mags = []\n", + "mag_errs = []\n", + "fluxes = []\n", + "flux_errs = []\n", + "\n", + "# Convert to AB Magnitudes\n", + "with np.errstate(divide='ignore', invalid='ignore'):\n", + " for f in filters:\n", + " flux = sed_data[f'{f}_cModelFlux']\n", + " flux_err = sed_data[f'{f}_cModelFluxErr']\n", + "\n", + " fluxes.append(flux)\n", + " flux_errs.append(flux_err)\n", + " \n", + " mag = -2.50 * np.log10(flux) + 31.4\n", + " mag_err = 1.0857 * (flux_err / flux)\n", + " \n", + " mags.append(mag)\n", + " mag_errs.append(mag_err)\n", + " \n", + "# 4. Plot the SED\n", + "fig, ax = plt.subplots(figsize=(8, 5))\n", + "\n", + "# Plot the data (invert y-axis because lower magnitude = brighter!)\n", + "ax.errorbar(wavelengths, fluxes, yerr=flux_errs, fmt='o-', color='black', \n", + " markersize=8, capsize=4, linewidth=2)\n", + "#ax.invert_yaxis() # for mags only\n", + "\n", + "# Highlight the region absorbed by the Lyman Break\n", + "ax.axvspan(3000, 4826, color='lightblue', alpha=0.3, label='Absorbed by Neutral Hydrogen')\n", + "\n", + "# Formatting\n", + "ax.set_xticks(wavelengths)\n", + "ax.set_xticklabels(filters, fontsize=12)\n", + "ax.set_xlabel('Filter Band', fontsize=14)\n", + "ax.set_ylabel('Flux [nJy]', fontsize=14)\n", + "ax.set_title(f'Spectral Energy Distribution (Candidate ID: {best_candidate_id})', fontsize=16, fontweight='bold')\n", + "\n", + "ax.grid(True, linestyle=':', alpha=0.6)\n", + "ax.legend(loc='upper right')\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "4c51bd19-e47d-4808-b334-3349d94a0924", + "metadata": {}, + "source": [ + "## Sanity check matching to Rubin photo-z catalogs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c015634-0235-4329-92de-dcaf17954e3a", + "metadata": {}, + "outputs": [], + "source": [ + "import lsdb\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "print(\"Loading DP1 Photo-z LSDB catalog...\")\n", + "\n", + "# 1. Open the LSDB photo-z catalog from the RSP shared file system\n", + "pz_cat = lsdb.open_catalog(\"/rubin/lsdb_data/object_photoz\")\n", + "\n", + "# 2. Filter the catalog for our specific candidate IDs\n", + "# LSDB uses Dask under the hood for distributed computing. We access the Dask \n", + "# DataFrame (._ddf) to filter for our candidate IDs, then compute the result into a Pandas DataFrame.\n", + "pz_dask = pz_cat._ddf\n", + "matched_df = pz_dask[pz_dask['objectId'].isin(high_purity_ids)].compute()\n", + "\n", + "# Extract the redshift column. \n", + "# Note: Depending on the specific algorithm used for this DP1 release, the column \n", + "# might be named 'z_phot', 'z_mode', or 'photoZ'. If 'z_phot' throws a KeyError, \n", + "# you can use print(matched_df.columns) to check the correct name!\n", + "valid_pz = matched_df['bpz_z_mean'].dropna().values\n", + "\n", + "# 3. Plot the Histogram\n", + "fig, ax = plt.subplots(figsize=(8, 5))\n", + "\n", + "if len(valid_pz) > 0:\n", + " ax.hist(valid_pz, bins=15, color='rebeccapurple', alpha=0.8, edgecolor='white')\n", + "\n", + "# Draw a vertical line exactly at z=4 to show the target redshift\n", + "ax.axvline(4.0, color='red', linestyle='--', linewidth=2, label='Target Redshift (z=4)')\n", + "\n", + "# Formatting\n", + "ax.set_xlabel(r'Photometric Redshift (zphot)', fontsize=14)\n", + "ax.set_ylabel('Number of Galaxies', fontsize=14)\n", + "ax.set_title('Photo-z Distribution of High-Purity g-dropouts', fontsize=16, fontweight='bold')\n", + "\n", + "ax.legend()\n", + "ax.grid(True, linestyle=':', alpha=0.6)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "# Print the confirmation statistics\n", + "print(f\"Total candidates cross-matched: {len(valid_pz)}\")\n", + "if len(valid_pz) > 0:\n", + " print(f\"Median Photo-z of sample: {np.median(valid_pz):.2f}\")" + ] + }, + { + "cell_type": "markdown", + "id": "595f2e93-1577-4ba7-8023-877d25a24a51", + "metadata": {}, + "source": [ + "## some failed attempts to retrieve VANDELS catalogs and spec-z columns\n", + "to clean up" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14646c0e-76fd-4d28-82cb-ffdbf3dc4f9a", + "metadata": {}, + "outputs": [], + "source": [ + "# dont delete, it displays the column names\n", + "\n", + "from astroquery.vizier import Vizier\n", + "import astropy.units as u\n", + "from astropy.coordinates import SkyCoord\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "# 1. Initialize Vizier - fetch EVERYTHING associated with the VANDELS ID\n", + "v = Vizier(columns=['**'], catalog=\"J/A+A/647/A150\")\n", + "v.ROW_LIMIT = -1\n", + "\n", + "print(\"Analyzing VANDELS Catalog Structure...\")\n", + "\n", + "try:\n", + " all_tables = v.get_catalogs(\"J/A+A/647/A150\")\n", + " \n", + " vandels_data = None\n", + " z_col_name = None\n", + " flag_col_name = None\n", + "\n", + " # 2. Iterate through all tables to find the spectroscopic data\n", + " for i, table in enumerate(all_tables):\n", + " cols = table.colnames\n", + " print(f\"\\nTable {i}: {table.meta.get('name', 'Unknown')}\")\n", + " print(f\"Columns: {cols[:10]}... ({len(cols)} total columns)\")\n", + " \n", + " # Look for the redshift column (case-insensitive)\n", + " # We look for 'z' followed by 'spec', 'mode', or just 'z'\n", + " for c in cols:\n", + " c_low = c.lower()\n", + " if c_low in ['zspec', 'z', 'z_spec', 'specz', 'z_mode']:\n", + " z_col_name = c\n", + " vandels_data = table\n", + " print(f\"--> Found Redshift Column: '{z_col_name}' in Table {i}\")\n", + " \n", + " # Now find the quality flag in the SAME table\n", + " for f in cols:\n", + " f_low = f.lower()\n", + " if f_low in ['zflg', 'f_zspec', 'q', 'qual', 'zflag']:\n", + " flag_col_name = f\n", + " print(f\"--> Found Quality Flag: '{flag_col_name}'\")\n", + " break\n", + " break\n", + " if vandels_data: break\n", + "\n", + " if vandels_data is None:\n", + " print(\"\\n[!] Error: No redshift column found. Printing all table summaries for debugging:\")\n", + " for i, t in enumerate(all_tables):\n", + " print(f\"Table {i} has columns: {t.colnames}\")\n", + " raise ValueError(\"Column discovery failed.\")\n", + "\n", + " # 3. Filter and Match (Standard workflow)\n", + " # We use a broad mask first to ensure we have data\n", + " mask = (vandels_data[z_col_name] >= 3.5) & (vandels_data[z_col_name] <= 4.5)\n", + " \n", + " # Only apply flag if we found one\n", + " if flag_col_name:\n", + " mask &= (vandels_data[flag_col_name] >= 3)\n", + " \n", + " vandels_z4 = vandels_data[mask]\n", + " print(f\"\\nFiltering complete. Found {len(vandels_z4)} high-quality z~4 candidates.\")\n", + "\n", + " # Cross-match using coordinates found in the same table\n", + " # VizieR usually uses RAJ2000/DEJ2000 or _RAJ2000/_DEJ2000\n", + " ra_col = 'RAJ2000' if 'RAJ2000' in vandels_z4.colnames else '_RAJ2000'\n", + " dec_col = 'DEJ2000' if 'DEJ2000' in vandels_z4.colnames else '_DEJ2000'\n", + "\n", + " v_coords = SkyCoord(ra=vandels_z4[ra_col], dec=vandels_z4[dec_col], unit='deg')\n", + " r_coords = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", + " #r_coords = SkyCoord(ra=cands_ra, dec=cands_dec, unit='deg')\n", + "\n", + " idx, d2d, _ = v_coords.match_to_catalog_sky(r_coords)\n", + " matches = d2d < 1.5 * u.arcsec # Slightly wider match for different astrometric systems\n", + " matched_idx = idx[matches]\n", + " \n", + " print(f\"Successfully matched {len(matched_idx)} galaxies to Rubin sample.\")\n", + "\n", + " # 4. Final Plot\n", + " ri_match = tab['r_sersic_mag'][matched_idx] - tab['i_sersic_mag'][matched_idx]\n", + " gr_match = tab['g_sersic_mag'][matched_idx] - tab['r_sersic_mag'][matched_idx]\n", + "\n", + " plt.figure(figsize=(8, 6))\n", + " plt.scatter(tab['r_sersic_mag'] - tab['i_sersic_mag'], \n", + " tab['g_sersic_mag'] - tab['r_sersic_mag'], \n", + " s=1, color='gray', alpha=0.2, label='Parent Sample')\n", + " plt.scatter(ri_match, gr_match, color='gold', marker='*', s=150, edgecolor='k', label='VANDELS Confirmed')\n", + " plt.axhline(1.5, color='blue', ls='--', label='Your Strict Cut')\n", + " plt.xlabel('r - i')\n", + " plt.ylabel('g - r')\n", + " plt.legend()\n", + " plt.show()\n", + "\n", + "except Exception as e:\n", + " print(f\"\\nDiscovery Failed: {e}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b46074c-d680-4a2c-8324-5b6fbcbbaa23", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from astropy.coordinates import SkyCoord\n", + "import astropy.units as u\n", + "\n", + "# 1. Select Table 0 (CDFS) and extract the confirmed high-z sample\n", + "vandels_data = all_tables[0]\n", + "\n", + "# Filter for spectroscopic redshift between 3.5 and 4.5\n", + "# We use q_zsp >= 3 (standard for high-confidence VANDELS spectra)\n", + "mask = (vandels_data['zsp'] >= 3.5) & (vandels_data['zsp'] <= 4.5) & (vandels_data['q_zsp'] >= 3)\n", + "vandels_z4 = vandels_data[mask]\n", + "\n", + "print(f\"Found {len(vandels_z4)} high-confidence VANDELS spectra in CDFS at z~4.\")\n", + "\n", + "# 2. Perform the spatial cross-match\n", + "v_coords = SkyCoord(ra=vandels_z4['RAJ2000'], dec=vandels_z4['DEJ2000'], unit='deg')\n", + "r_coords = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", + "\n", + "idx, d2d, _ = v_coords.match_to_catalog_sky(r_coords)\n", + "\n", + "# 1.0 arcsecond is usually safe for Rubin vs VLT astrometry\n", + "matches = d2d < 1.0 * u.arcsec\n", + "matched_idx = idx[matches]\n", + "\n", + "print(f\"Successfully matched {len(matched_idx)} of those to your Rubin Object table.\")\n", + "\n", + "# 3. Calculate colors for the matched objects\n", + "# Assuming 'tab' has the sersic_mags we defined earlier\n", + "ri_match = tab['r_sersic_mag'][matched_idx] - tab['i_sersic_mag'][matched_idx]\n", + "gr_match = tab['g_sersic_mag'][matched_idx] - tab['r_sersic_mag'][matched_idx]\n", + "s2n_match = tab['i_sersicFlux'][matched_idx] / tab['i_sersicFluxErr'][matched_idx]\n", + "\n", + "# 4. Plotting\n", + "plt.figure(figsize=(9, 7))\n", + "\n", + "# Background: All Rubin objects in your field\n", + "plt.scatter(tab['r_sersic_mag'] - tab['i_sersic_mag'], \n", + " tab['g_sersic_mag'] - tab['r_sersic_mag'], \n", + " s=2, color='gray', alpha=0.15, label='Rubin Parent Sample')\n", + "\n", + "# Foreground: The spectroscopic \"Truth\"\n", + "plt.scatter(ri_match, gr_match, color='gold', marker='*', s=150, \n", + " edgecolor='black', linewidth=0.8, zorder=5, label='Confirmed VANDELS z~4')\n", + "\n", + "# Draw your selection boundaries\n", + "plt.axhline(1.5, color='blue', linestyle='--', lw=2, label='Strict Selection (g-r > 1.5)')\n", + "plt.axhline(1.0, color='red', linestyle=':', lw=1.5, label='Standard Selection (g-r > 1.0)')\n", + "\n", + "# Box boundaries (approximating the dropout region)\n", + "plt.vlines(1.0, 1.0, 4.0, color='black', alpha=0.3) \n", + "\n", + "plt.xlim(-0.5, 1.5)\n", + "plt.ylim(-0.5, 3.5)\n", + "plt.xlabel('$(r - i)$ color', fontsize=12)\n", + "plt.ylabel('$(g - r)$ color', fontsize=12)\n", + "plt.title('VANDELS Spectroscopic Validation of Rubin Color Selection', fontsize=14)\n", + "plt.legend(loc='upper left', frameon=True, shadow=True)\n", + "plt.grid(True, linestyle=':', alpha=0.5)\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4efa3820-8dda-4d79-9b40-abcbe76fba4e", + "metadata": {}, + "outputs": [], + "source": [ + "# 1. List of RA/Dec for z~4 VANDELS confirmations\n", + "vandels_ra = vandels_z4['RAJ2000']\n", + "vandels_dec = vandels_z4['DEJ2000']\n", + "print(f\"VANDELS Truth List size: {len(vandels_ra)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e23b3a3b-bb85-4d0b-8cfb-f99132fcab3a", + "metadata": {}, + "outputs": [], + "source": [ + "# 2. Get all Rubin objects with i-band S/N > 10\n", + "# We use a 0.2 degree radius around the VANDELS center\n", + "rubin_query = \"\"\"\n", + "SELECT \n", + " objectId, coord_ra, coord_dec,\n", + " g_cModelMag, r_cModelMag, i_cModelMag,\n", + " g_cModelFlux, g_cModelFluxErr,\n", + " i_cModelFlux, i_cModelFluxErr\n", + "FROM dp1.Object\n", + "WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec), \n", + " CIRCLE('ICRS', 53.125, -27.8, 0.2)) = 1\n", + " AND (i_cModelFlux / i_cModelFluxErr) > 10\n", + "\"\"\"\n", + "\n", + "print(\"Querying Rubin for all solid i-band detections...\")\n", + "rubin_job = tap_service.run_sync(rubin_query)\n", + "rubin_all = rubin_job.to_table()\n", + "print(f\"Rubin Detected List size: {len(rubin_all)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1e00286f-7d96-4da5-a5dc-e0d527975a8e", + "metadata": {}, + "outputs": [], + "source": [ + "from astropy.coordinates import SkyCoord\n", + "import astropy.units as u\n", + "\n", + "# 1. Setup coordinates\n", + "c_vandels = SkyCoord(ra=vandels_ra, dec=vandels_dec, unit='deg')\n", + "c_rubin = SkyCoord(ra=rubin_all['coord_ra'], dec=rubin_all['coord_dec'], unit='deg')\n", + "\n", + "# 2. Match\n", + "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin)\n", + "match_mask = d2d < 1.0 * u.arcsec \n", + "matched_rubin = rubin_all[idx[match_mask]]\n", + "\n", + "print(f\"Found {len(matched_rubin)} matches!\")\n", + "\n", + "# 3. Handle 'NaN' in g-band (The Dropouts)\n", + "# If g is NaN, it means the flux was too low to measure a magnitude. \n", + "# We'll assign it a faint magnitude (e.g., 28) to visualize the dropout.\n", + "g_mags = matched_rubin['g_cModelMag']\n", + "r_mags = matched_rubin['r_cModelMag']\n", + "i_mags = matched_rubin['i_cModelMag']\n", + "\n", + "# Replace NaNs with 28.0 for visualization\n", + "g_plot = np.where(np.isnan(g_mags), 28.0, g_mags)\n", + "\n", + "g_r = g_plot - r_mags\n", + "r_i = r_mags - i_mags\n", + "\n", + "whblue = np.where(g_r < 1.5)[0]\n", + "\n", + "# 4. Plot\n", + "plt.figure(figsize=(8, 6))\n", + "\n", + "# Background (All objects from this new Rubin query)\n", + "plt.scatter(rubin_all['r_cModelMag'] - rubin_all['i_cModelMag'], \n", + " rubin_all['g_cModelMag'] - rubin_all['r_cModelMag'], \n", + " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", + "\n", + "# Matches\n", + "plt.scatter(r_i, g_r, color='gold', marker='*', s=100, edgecolor='k', label='VANDELS matches')\n", + "\n", + "# Highlight the selected z~4 LBGs (blue)\n", + "#plt.scatter(r_minus_i[is_z4_lbg], g_minus_r[is_z4_lbg], \n", + "# s=20, color='blue', alpha=0.8, edgecolor='white', linewidth=0.5, label='z~4 LBGs')\n", + "\n", + "\n", + "# 4. Draw the Selection Boundaries for visual reference\n", + "# Calculate the vertices of the selection region\n", + "x_diag = np.linspace(0.133, 1.0, 50)\n", + "y_diag = 1.5 * x_diag + 0.8\n", + "\n", + "# Plot the bounding lines\n", + "plt.plot([-1.5, 0.133], [1.0, 1.0], color='red', linestyle='--', lw=2, label='Selection Boundary') # Bottom horizontal cut\n", + "#ax.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut to avoid M-stars\n", + "#ax.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2)\n", + "\n", + "# Plot the updated bounding lines\n", + "# 4. Draw the NEW Selection Boundaries\n", + "# Calculate the new intersection between the horizontal and diagonal lines\n", + "intersect_x = (1.5 - 0.8) / 1.5\n", + "plt.plot([-1.5, intersect_x], [1.5, 1.5], color='red', linestyle='--', lw=2, label='Selection Boundary') # Raised horizontal cut\n", + "plt.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut\n", + "plt.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2) # Right vertical cut\n", + "\n", + "\n", + "plt.axhline(1.5, color='blue', linestyle='--', label='Strict Cut')\n", + "plt.axhline(1., color='green', linestyle='--', label='Standard Cut')\n", + "plt.xlabel('r - i')\n", + "plt.ylabel('g - r')\n", + "plt.xlim(-0.5, 1.5)\n", + "plt.ylim(-0.5, 3.5)\n", + "plt.title('VANDELS Confirmations in Rubin (Unfiltered)')\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1b4a125d-0bd3-4bbb-8376-85ac410855e1", + "metadata": {}, + "outputs": [], + "source": [ + "# something might be wrong with the matching process, CHECK\n", + "\n", + "from astropy.coordinates import SkyCoord\n", + "import astropy.units as u\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# 1. Setup coordinates\n", + "c_vandels = SkyCoord(ra=vandels_ra, dec=vandels_dec, unit='deg')\n", + "c_rubin = SkyCoord(ra=rubin_all['coord_ra'], dec=rubin_all['coord_dec'], unit='deg')\n", + "c_rubin_lbg = SkyCoord(ra=cands_ra, dec=cands_dec, unit='deg')\n", + "\n", + "# 2. Match\n", + "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin_lbg)\n", + "match_mask = d2d < 1.0 * u.arcsec \n", + "matched_rubin = rubin_all[idx[match_mask]]\n", + "#matched_rubin = tab[idx[match_mask]]\n", + "\n", + "# Extract the redshift for the matched objects!\n", + "# match_mask aligns with the VANDELS catalog\n", + "matched_z = vandels_z4['zsp'][match_mask] \n", + "\n", + "print(f\"Found {len(matched_rubin)} matches!\")\n", + "\n", + "# 3. Handle 'NaN' in g-band (The Dropouts)\n", + "g_mags = matched_rubin['g_cModelMag']\n", + "r_mags = matched_rubin['r_cModelMag']\n", + "i_mags = matched_rubin['i_cModelMag']\n", + "s2n = matched_rubin['i_cModelFlux']/matched_rubin['i_cModelFluxErr']\n", + "\n", + "# Replace NaNs with 28.0 for visualization\n", + "g_plot = np.where(np.isnan(g_mags), 28.0, g_mags)\n", + "\n", + "g_r = g_plot - r_mags\n", + "r_i = r_mags - i_mags\n", + "\n", + "whblue = np.where(g_r > 1.5)[0]\n", + "\n", + "# 4. Plot\n", + "# Slightly wider figure to accommodate the colorbar\n", + "plt.figure(figsize=(9, 6))\n", + "\n", + "# Background (All objects from this new Rubin query)\n", + "plt.scatter(rubin_all['r_cModelMag'] - rubin_all['i_cModelMag'], \n", + " rubin_all['g_cModelMag'] - rubin_all['r_cModelMag'], \n", + " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", + "\n", + "# Matches: Color-coded by spectroscopic redshift\n", + "# Note: Keeping your [whblue] index, but you can remove it to see all stars!\n", + "sc = plt.scatter(r_i, g_r, \n", + " c=matched_z, cmap='plasma', \n", + " marker='*', s=150, edgecolor='k', zorder=10, \n", + " label='VANDELS matches')\n", + "\n", + "# Add the colorbar\n", + "cbar = plt.colorbar(sc)\n", + "cbar.set_label('VANDELS z_spec', fontsize=12, fontweight='bold')\n", + "\n", + "plt.axhline(1.5, color='blue', linestyle='--', label='Your Strict Cut')\n", + "plt.xlabel('r - i', fontsize=12)\n", + "plt.ylabel('g - r', fontsize=12)\n", + "plt.xlim(-0.5, 1.5)\n", + "plt.ylim(-0.5, 3.5)\n", + "plt.title('VANDELS Confirmations in Rubin (Color-Coded by z)', fontsize=14)\n", + "plt.legend(loc='lower right')\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ce194c9-55ac-44c7-bf29-702f2e7032bd", + "metadata": {}, + "outputs": [], + "source": [ + "from astropy.coordinates import SkyCoord\n", + "import astropy.units as u\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "# 1. Setup coordinates\n", + "c_vandels = SkyCoord(ra=vandels_ra, dec=vandels_dec, unit='deg')\n", + "c_rubin = SkyCoord(ra=rubin_all['coord_ra'], dec=rubin_all['coord_dec'], unit='deg')\n", + "\n", + "# 2. Match\n", + "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin)\n", + "match_mask = d2d < 1.0 * u.arcsec \n", + "matched_rubin = rubin_all[idx[match_mask]]\n", + "\n", + "print(f\"Found {len(matched_rubin)} matches!\")\n", + "\n", + "# 3. Handle 'NaN' in g-band (The Dropouts)\n", + "g_mags = matched_rubin['g_cModelMag']\n", + "r_mags = matched_rubin['r_cModelMag']\n", + "i_mags = matched_rubin['i_cModelMag']\n", + "\n", + "# Replace NaNs with 28.0 for visualization\n", + "g_plot = np.where(np.isnan(g_mags), 28.0, g_mags)\n", + "\n", + "g_r = g_plot - r_mags\n", + "r_i = r_mags - i_mags\n", + "\n", + "# Keep only the stars below your 1.5 cut\n", + "whblue = np.where(g_r > 1.5)[0]\n", + "\n", + "# 4. Plot\n", + "plt.figure(figsize=(9, 6))\n", + "\n", + "# Background (All objects from this new Rubin query)\n", + "plt.scatter(rubin_all['r_cModelMag'] - rubin_all['i_cModelMag'], \n", + " rubin_all['g_cModelMag'] - rubin_all['r_cModelMag'], \n", + " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", + "\n", + "# Matches: Color-coded by r-band magnitude\n", + "sc = plt.scatter(r_i, g_r, \n", + " c=r_mags, cmap='viridis', \n", + " marker='*', s=150, edgecolor='k', zorder=10, \n", + " label='VANDELS matches')\n", + "\n", + "# Add the colorbar\n", + "cbar = plt.colorbar(sc)\n", + "cbar.set_label('r-band Magnitude', fontsize=12, fontweight='bold')\n", + "cbar.ax.invert_yaxis() # Invert so brighter (smaller number) is at the top\n", + "\n", + "plt.axhline(1.5, color='blue', linestyle='--', label='Your Strict Cut')\n", + "plt.xlabel('r - i', fontsize=12)\n", + "plt.ylabel('g - r', fontsize=12)\n", + "plt.xlim(-0.5, 1.5)\n", + "plt.ylim(-0.5, 3.5)\n", + "plt.title('VANDELS Confirmations in Rubin (Color-Coded by r-mag)', fontsize=14)\n", + "plt.legend(loc='lower right')\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "e4fc8f40-cee2-465c-b7b4-c1a696e156d3", + "metadata": {}, + "source": [ + "Some points to consider here: the redshift window is 3.5 1 else axes[col_idx]\n", + " \n", + " band_match = coadds[coadds['lsst_band'] == f]\n", + " \n", + " if len(band_match) > 0:\n", + " try:\n", + " datalink_url = band_match['access_url'][0]\n", + " dl_result = DatalinkResults.from_result_url(datalink_url, session=session)\n", + " \n", + " sq = SodaQuery.from_resource(dl_result,\n", + " dl_result.get_adhocservice_by_id(\"cutout-sync\"),\n", + " session=session)\n", + " sq.circle = (ra * u.deg, dec * u.deg, fov * u.deg)\n", + " \n", + " cutout_bytes = sq.execute_stream().read()\n", + " hdul = fits.open(io.BytesIO(cutout_bytes))\n", + " img_array = hdul[1].data\n", + " \n", + " # ZScale is best for seeing the noise level in dropout bands\n", + " norm = ImageNormalize(img_array, interval=ZScaleInterval(), stretch=LinearStretch())\n", + " ax.imshow(img_array, origin='lower', cmap='gray', norm=norm)\n", + " \n", + " # Marker to help identify the target in noisy u/g bands\n", + " cy, cx = img_array.shape[0]//2, img_array.shape[1]//2\n", + " ax.add_patch(plt.Circle((cx, cy), radius=4, color='cyan', fill=False, lw=1.5, alpha=0.7))\n", + "\n", + " except Exception as e:\n", + " ax.text(0.5, 0.5, 'SODA Error', ha='center', va='center', transform=ax.transAxes, color='red')\n", + " else:\n", + " ax.text(0.5, 0.5, 'No Coverage', ha='center', va='center', transform=ax.transAxes, color='red')\n", + " \n", + " ax.set_xticks([]); ax.set_yticks([])\n", + " if row_idx == 0:\n", + " ax.set_title(f\"{f}-band\", fontsize=15, fontweight='bold')\n", + " if col_idx == 0:\n", + " ax.set_ylabel(f\"z={z_spec:.2f}\\n{obj_id}\\n{gr}\\n{s2n}\", rotation=0, labelpad=70, ha='center', fontweight='bold')\n", + "\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "b2f95d66-b972-4d69-ab4a-cd2314e263cb", + "metadata": {}, + "source": [ + "## Comparison between VANDELS spec-z and Rubin photo-z sanity check" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24942ae5-e69b-46a4-902e-d93e73f298ab", + "metadata": {}, + "outputs": [], + "source": [ + "import astropy.units as u\n", + "from astropy.coordinates import SkyCoord\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "print(\"Preparing VANDELS and LSDB catalogs for cross-matching...\")\n", + "\n", + "# 1. Extract the full VANDELS coordinates and spec-z\n", + "# (Assuming your unfiltered VANDELS table from VizieR is stored as 'vandels_data')\n", + "v_ra = vandels_data['RAJ2000']\n", + "v_dec = vandels_data['DEJ2000']\n", + "v_zspec = vandels_data['zsp']\n", + "v_coords = SkyCoord(ra=v_ra, dec=v_dec, unit='deg')\n", + "\n", + "# 2. Filter the massive LSDB catalog down to the CDFS region\n", + "# lsdb updated its API to require 'radius_arcsec' to avoid unit confusion.\n", + "# We want a 0.5 degree radius, which is 1800 arcseconds.\n", + "print(\"Running LSDB cone search on the VANDELS footprint...\")\n", + "pz_regional = pz_cat.cone_search(ra=53.125, dec=-27.8, radius_arcsec=1800).compute()\n", + "\n", + "# 3. Setup the Rubin coordinates from the regional Photo-z catalog\n", + "# Note: LSDB uses 'coord_ra' and 'coord_dec' by default\n", + "rubin_coords = SkyCoord(ra=pz_regional['coord_ra'].values, \n", + " dec=pz_regional['coord_dec'].values, \n", + " unit='deg')\n", + "\n", + "# 4. Perform the spatial cross-match\n", + "print(\"Performing spatial cross-match...\")\n", + "idx, d2d, _ = v_coords.match_to_catalog_sky(rubin_coords)\n", + "\n", + "# Keep only confident matches within 1 arcsecond\n", + "match_mask = d2d < 1.0 * u.arcsec\n", + "\n", + "# Extract the matched data\n", + "matched_rubin_pz = pz_regional.iloc[idx[match_mask]]\n", + "matched_v_zspec = v_zspec[match_mask]\n", + "matched_v_zphot = matched_rubin_pz['bpz_z_mean'].values\n", + "\n", + "# Clean out any rows where the photo-z pipeline failed (returned NaN)\n", + "valid = ~np.isnan(matched_v_zphot) & ~np.isnan(matched_v_zspec)\n", + "z_spec_clean = matched_v_zspec[valid]\n", + "z_phot_clean = matched_v_zphot[valid]\n", + "\n", + "print(f\"Successfully matched {len(z_spec_clean)} galaxies with both Spec-z and Photo-z!\")\n", + "\n", + "# 5. Plot Photo-z vs Spec-z\n", + "fig, ax = plt.subplots(figsize=(8, 7))\n", + "\n", + "# Scatter plot of the matches\n", + "ax.scatter(z_spec_clean, z_phot_clean, s=20, color='teal', alpha=0.5, \n", + " edgecolor='k', linewidth=0.5, label='Matched Galaxies')\n", + "\n", + "# Perfect agreement line (1:1)\n", + "z_line = np.linspace(0, 6, 100)\n", + "ax.plot(z_line, z_line, color='black', linestyle='--', linewidth=2, label='1:1 line')\n", + "\n", + "# Catastrophic outlier boundaries\n", + "# The standard definition in astronomy is |dz| / (1+z) > 0.15\n", + "ax.plot(z_line, z_line + 0.15*(1+z_line), color='red', linestyle=':', label='Outliers ($|\\Delta z| > 0.15(1+z)$)')\n", + "ax.plot(z_line, z_line - 0.15*(1+z_line), color='red', linestyle=':')\n", + "\n", + "# Formatting\n", + "ax.set_xlim(0, 5.5)\n", + "ax.set_ylim(0, 5.5)\n", + "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", + "ax.set_ylabel('Photometric Redshift (Rubin bpz_z_mean)', fontsize=14)\n", + "ax.set_title('Validation: Photo-z vs. Spec-z', fontsize=16, fontweight='bold')\n", + "ax.legend(loc='upper left', frameon=True)\n", + "ax.grid(True, linestyle=':', alpha=0.6)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "# 6. Calculate Standard Photo-z Quality Metrics\n", + "# dz = (z_phot - z_spec) / (1 + z_spec)\n", + "dz = (z_phot_clean - z_spec_clean) / (1 + z_spec_clean)\n", + "\n", + "# NMAD: Normalized Median Absolute Deviation (A robust measure of scatter)\n", + "nmad = 1.48 * np.median(np.abs(dz - np.median(dz)))\n", + "\n", + "# Outlier Fraction: Percentage of objects outside the red dotted lines\n", + "outlier_fraction = np.sum(np.abs(dz) > 0.15) / len(dz)\n", + "\n", + "print(f\"--- Photo-z Performance Metrics ---\")\n", + "print(f\"Robust Scatter ($\\sigma_{{NMAD}}$): {nmad:.3f}\")\n", + "print(f\"Catastrophic Outlier Fraction: {outlier_fraction:.1%}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "57b52d6b-2441-4b38-ae0f-cff23504b472", + "metadata": {}, + "outputs": [], + "source": [ + "import astropy.units as u\n", + "from astropy.coordinates import SkyCoord\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "print(\"Preparing VANDELS and LSDB catalogs for cross-matching...\")\n", + "\n", + "# 1. Extract the full VANDELS coordinates and spec-z\n", + "v_ra = vandels_data['RAJ2000']\n", + "v_dec = vandels_data['DEJ2000']\n", + "v_zspec = vandels_data['zsp']\n", + "v_coords = SkyCoord(ra=v_ra, dec=v_dec, unit='deg')\n", + "\n", + "# 2. Filter the massive LSDB catalog down to the CDFS region\n", + "print(\"Running LSDB cone search on the VANDELS footprint...\")\n", + "pz_regional = pz_cat.cone_search(ra=53.125, dec=-27.8, radius_arcsec=1800).compute()\n", + "\n", + "# 3. Setup the Rubin coordinates\n", + "rubin_coords = SkyCoord(ra=pz_regional['coord_ra'].values, \n", + " dec=pz_regional['coord_dec'].values, \n", + " unit='deg')\n", + "\n", + "# 4. Perform the spatial cross-match\n", + "print(\"Performing spatial cross-match...\")\n", + "idx, d2d, _ = v_coords.match_to_catalog_sky(rubin_coords)\n", + "match_mask = d2d < 1.0 * u.arcsec\n", + "\n", + "# Extract the matched data\n", + "matched_rubin_pz = pz_regional.iloc[idx[match_mask]]\n", + "matched_v_zspec = v_zspec[match_mask]\n", + "matched_v_zphot = matched_rubin_pz['bpz_z_mean'].values\n", + "\n", + "# Check the column name for i-band magnitude in the photo-z catalog\n", + "if 'i_cModelMag' in matched_rubin_pz.columns:\n", + " matched_i_mag = matched_rubin_pz['i_cModelMag'].values\n", + "elif 'mag_i' in matched_rubin_pz.columns:\n", + " matched_i_mag = matched_rubin_pz['mag_i'].values\n", + "else:\n", + " # If it throws an error here, print matched_rubin_pz.columns to find the exact name!\n", + " print(\"Warning: Could not find i-band magnitude column. Using placeholder.\")\n", + " matched_i_mag = np.zeros(len(matched_v_zphot))\n", + "\n", + "# Clean out any rows with NaNs in z_phot, z_spec, OR i_mag to keep arrays aligned\n", + "valid = ~np.isnan(matched_v_zphot) & ~np.isnan(matched_v_zspec) & ~np.isnan(matched_i_mag)\n", + "z_spec_clean = matched_v_zspec[valid]\n", + "z_phot_clean = matched_v_zphot[valid]\n", + "i_mag_clean = matched_i_mag[valid]\n", + "\n", + "print(f\"Successfully matched {len(z_spec_clean)} galaxies with Spec-z, Photo-z, and i-mag!\")\n", + "\n", + "# 5. Plot Photo-z vs Spec-z\n", + "fig, ax = plt.subplots(figsize=(9, 7)) # Slightly wider for the colorbar\n", + "\n", + "# Scatter plot: Color-coded by i-band magnitude\n", + "sc = ax.scatter(z_spec_clean, z_phot_clean, c=i_mag_clean, cmap='viridis', \n", + " s=35, alpha=0.8, edgecolor='k', linewidth=0.5, zorder=5)\n", + "\n", + "# Add the colorbar\n", + "cbar = plt.colorbar(sc, ax=ax)\n", + "cbar.set_label('i-band Magnitude', fontsize=12, fontweight='bold')\n", + "cbar.ax.invert_yaxis() # Invert so brighter (smaller number) is at the top\n", + "\n", + "# Perfect agreement line (1:1)\n", + "z_line = np.linspace(0, 6, 100)\n", + "ax.plot(z_line, z_line, color='black', linestyle='--', linewidth=2, label='1:1 Agreement')\n", + "\n", + "# Catastrophic outlier boundaries\n", + "ax.plot(z_line, z_line + 0.15*(1+z_line), color='red', linestyle=':', label='Outlier Boundary ($|\\Delta z| > 0.15(1+z)$)')\n", + "ax.plot(z_line, z_line - 0.15*(1+z_line), color='red', linestyle=':')\n", + "\n", + "# Formatting\n", + "ax.set_xlim(0, 5.5)\n", + "ax.set_ylim(0, 5.5)\n", + "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", + "ax.set_ylabel('Photometric Redshift (Rubin bpz_z_mean)', fontsize=14)\n", + "ax.set_title('Validation: Photo-z vs. Spec-z (Colored by i-mag)', fontsize=16, fontweight='bold')\n", + "\n", + "# Combine legends\n", + "handles, labels = ax.get_legend_handles_labels()\n", + "ax.legend(handles, labels, loc='upper left', frameon=True)\n", + "ax.grid(True, linestyle=':', alpha=0.6)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "# 6. Calculate Standard Photo-z Quality Metrics\n", + "dz = (z_phot_clean - z_spec_clean) / (1 + z_spec_clean)\n", + "nmad = 1.48 * np.median(np.abs(dz - np.median(dz)))\n", + "outlier_fraction = np.sum(np.abs(dz) > 0.15) / len(dz)\n", + "\n", + "print(f\"--- Photo-z Performance Metrics ---\")\n", + "print(f\"Robust Scatter ($\\sigma_{{NMAD}}$): {nmad:.3f}\")\n", + "print(f\"Catastrophic Outlier Fraction: {outlier_fraction:.1%}\")" + ] + }, + { + "cell_type": "markdown", + "id": "354dbbd9-f5df-47ee-962c-1384b7e21b29", + "metadata": {}, + "source": [ + "## 3. Total fluxes\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0cec2ebe-6134-4f86-b9de-67aa16dea0d5", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "sys.exit()" + ] + }, + { + "cell_type": "markdown", + "id": "7d75b896-770c-4d7e-94d9-7202af571209", + "metadata": {}, + "source": [ + "### 3.1. Comparing total fluxes\n", + "\n", + "This section will make several plots that shows how the different photometric measurements compare.\n", + "\n", + "First, compare `cModelFlux` (two component bulge+disk sersic model flux) to `sersicFlux` (single sersic model flux with shape parameters free), `bdFluxB` (sersic with n=4) and `bdFluxD` (sersic with n=1). " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9443b34f-9afe-4c12-b345-860896176cac", + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", + " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", + "\n", + "bins = np.arange(16, 27, 1)\n", + "\n", + "ylims = [-1.2, 1.2]\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-bdFluxD_mag), 's', alpha=.3,\n", + " label='cModel-bdFluxD', color='blue')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-bdFluxD_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='blue', lw=2, label='bin median', zorder=11)\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-bdFluxB_mag), '^', alpha=.3,\n", + " label='cModel-bdFluxB', color='r')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-bdFluxB_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='r', lw=2, label='bin median', zorder=11)\n", + "\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag - sersic_mag), 'o', alpha=.3,\n", + " label='cModel - sersic', color='g')\n", + "\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-sersic_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='g', lw=2, label='bin median', zorder=11)\n", + "\n", + "ax.axhline(0, linestyle='--')\n", + "ax.set_xlabel('cModel Magnitude')\n", + "ax.set_ylabel('cModel mag - other mag')\n", + "ax.set_ylim([-1, 1])\n", + "ax.legend()\n", + "\n", + "ax2.hist((cmodel_mag-bdFluxD_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='blue', stacked=True, fill=False, label='bdFluxD')\n", + "ax2.hist((cmodel_mag-bdFluxB_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='r', stacked=True, fill=False, label='bdFluxB')\n", + "ax2.hist((cmodel_mag-sersic_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='g', stacked=True, fill=False, label='Sersic')\n", + "\n", + "ax2.set_ylim(ylims)\n", + "ax2.axhline(0, linestyle='--', color='k')\n", + "ax.axhline(0, linestyle='--', color='k')\n", + "ax.set_xlabel('i-band AB magnitude [cModel]')\n", + "ax.set_ylabel('cModel mag - Other mag')\n", + "ax.set_ylim(ylims)\n", + "\n", + "ax.legend()\n", + "ax2.legend()" + ] + }, + { + "cell_type": "markdown", + "id": "f290d993-8645-406a-9e95-fabd852383c8", + "metadata": {}, + "source": [ + "> Figure 1: Left panel: a plot comparing the magnitude difference between cModel and dbFluxD (blue), bdFluxB (red) and sersic (green) vs i-band magnitude as measured by cModel. Right panel: a histogram showing the difference in color between cModel and the three other photometric measurements, across all magnitudes. The sersic fluxes are in best agreement with cModel (smallest scatter in right panel) with the bdFluxB returning systematically fainter magnitudes, and bdFluxD returning systematically brighter magnitudes.\n", + "\n", + "Below, explore how the BD fluxes compare to sersic fluxes as a function of the shape of the light profile, sersic index n." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c1fea6a9-fc32-43ce-bb7a-f7e23677f548", + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", + " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", + "\n", + "bins = np.arange(0, 7, 0.25)\n", + "\n", + "ylims = [-1.2, 1.2]\n", + "\n", + "ax.plot(sersic_index, (sersic_mag-bdFluxD_mag), 's', alpha=.3,\n", + " label='cModel-bdFluxD', color='blue')\n", + "x = sersic_index\n", + "y = (sersic_mag-bdFluxD_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='blue', lw=2, label='bin median', zorder=11)\n", + "\n", + "ax.plot(sersic_index, (sersic_mag-bdFluxB_mag), '^', alpha=.3,\n", + " label='cModel-bdFluxB', color='r')\n", + "x = sersic_index\n", + "y = (sersic_mag-bdFluxB_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='r', lw=2, label='bin median', zorder=11)\n", + "\n", + "ax.axhline(0, linestyle='--')\n", + "\n", + "ax.set_ylabel('sersic mag - BD mag')\n", + "ax.set_ylim([-1, 1])\n", + "ax.legend()\n", + "\n", + "\n", + "ax2.hist((cmodel_mag-bdFluxD_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='blue', stacked=True, fill=False, label='bdFluxD')\n", + "ax2.hist((cmodel_mag-bdFluxB_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='r', stacked=True, fill=False, label='bdFluxB')\n", + "\n", + "ax2.set_ylim(ylims)\n", + "ax2.axhline(0, linestyle='--', color='k')\n", + "ax.axhline(0, linestyle='--', color='k')\n", + "ax.set_xlabel('Sersic Index n')\n", + "ax.set_ylabel('Sersic mag - Other mag')\n", + "ax.set_ylim(ylims)\n", + "ax.set_xlim([0, 8])\n", + "ax.legend()\n", + "ax2.legend()" + ] + }, + { + "cell_type": "markdown", + "id": "3c44cfa4-7e2d-4c77-960d-f540683744b2", + "metadata": {}, + "source": [ + "> Fig 2: Comparison of the sersic mag (flux measured with sersic parameters left free) with the bdFlux that is measured with sersic index fixed to either n=1 (D) or n=4 (B) as a function of sersic index n. Fixing the sersic index can inject scatter in the flux relative to leaving it free, but the sersic flux converges on bdFluxD(B) for n=1 and n=4." + ] + }, + { + "cell_type": "markdown", + "id": "b7c9fdd5-3bb1-4d8c-abac-5cdafa8df188", + "metadata": {}, + "source": [ + "## 4. Apparent fluxes\n", + "\n", + "This section explores three types of apparent fluxes: Kron (elliptical apertures that typically includes more than 90% of intrinsic light), and aperture photometry (flux measured inside circles of varying size).\n", + "\n", + "Here, apparent fluxes refers to photometry that are not corrected for flux outside of the measurement aperture (i.e. not corrected to be a total flux). These measurements have their own applications but should not be used to measure mass or luminosity.\n", + " \n", + "##### Kron fluxes\n", + "\n", + "A decent summary of Kron fluxes in the NED documentation. The aperture used for the fluxes is 2.5 x R1 where R1 is the luminosity weighted radius (also called \"first moment\"; Kron et al. 1980).\n", + "\n", + "```\n", + "_kronFlux : Flux from Kron Flux algorithm. Measured on -band.\n", + "_kronFluxErr : Uncertainty of _kronFlux.\n", + "_kronFlux_flag : Failure flag for _kronFlux.\n", + "```\n", + "\n", + "The Kron radius, `_kronRad`, is also available. In this case of LSST pipeline output, the Kron flux is not corrected for light that is emitted outside of the Kron aperture. While in many cases it will collect the majority of light, it will not be as accurate as the cModel for science cases requiring total flux.\n", + "\n", + "\n", + "##### Aperture fluxes\n", + "This contains the enclosed flux inside a given aperture (and not corrected to total fluxes using an aperture correction that accounts for the flux falling outside the aperture). Fixed aperture size refers to the aperture radius in pixels.\n", + "\n", + "```\n", + "_apFlux : Flux within -pixel aperture. Forced on -band.\n", + "_apFluxErr : Uncertainty of _apFlux.\n", + "_apFluxFlag : Failure flag for _apFlux.\n", + "```\n", + "\n", + "The apertures are 3, 6, 9, 12, 17, 25, 35, 50, and 70 pixels. In the column name, apertures are `03`, `06`, `09`, `12`, and so on. While aperture fluxes are not corrected for the loss outside the aperture, if the aperture size is much larger than the galaxy size then it will approximate the total flux of the galaxy. The general application of these measurements are for measuring radial profiles (see Section 4 below).\n" + ] + }, + { + "cell_type": "markdown", + "id": "d0869336-562f-4909-8109-9a737f57877b", + "metadata": {}, + "source": [ + "### 4.1. Comparing total to apparent fluxes\n", + "\n", + "This section will make several plots that compare the `cModel` flux (which we take as the fiducial total flux, as commonly used for SDSS) to some of the apparent flux measurements. Kron, and aperture photometry are all measures of light within a fixed aperture. \n", + "\n", + "\n", + "Generally, magnitudes measured using aperture photometry in the LSST pipeline are fainter than those measured from cModel, because the fixed circular aperture systematically underestimates the flux in the galaxy wings (and the lost flux increases as the intrinsic size of the galaxy increases, e.g. as traced by the Kron radius).\n", + "\n", + "First, compare `cModel` to `Kron` which should typically enclose 90% of the light." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96dc3077-e086-430a-bace-47383bb60c97", + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", + " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", + "\n", + "bins = np.arange(16, 27, 1)\n", + "\n", + "ylims = [-1.2, 1.2]\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag - kron_mag), 's', alpha=.3,\n", + " label='cModel-Kron', color='blue')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-kron_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1]) / 2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='blue', lw=2, label='bin median', zorder=11)\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-sersic_mag), 'o', alpha=.3,\n", + " label='cModel - sersic', color='r')\n", + "\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-sersic_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", + "ax.plot(binctr, bin_mean, color='r', lw=2, label='bin median', zorder=11)\n", + "\n", + "ax.axhline(0, linestyle='--')\n", + "ax.set_xlabel('cModel Magnitude')\n", + "ax.set_ylabel('cModel mag - sersic mag')\n", + "ax.set_ylim([-1, 1])\n", + "ax.legend()\n", + "\n", + "\n", + "ax2.hist((cmodel_mag-sersic_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 50), align='mid',\n", + " histtype=\"step\", color='red', stacked=True, fill=False, label='Sersic')\n", + "ax2.hist((cmodel_mag-kron_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 50), align='mid',\n", + " histtype=\"step\", color='blue', stacked=True, fill=False, label='Kron')\n", + "\n", + "ax2.set_ylim(ylims)\n", + "ax2.axhline(0, linestyle='--', color='k')\n", + "ax.axhline(0, linestyle='--', color='k')\n", + "ax.set_xlabel('Kron Radius [i-band; pixels]')\n", + "ax.set_ylabel('cModel mag - Other mag')\n", + "ax.set_ylim(ylims)\n", + "\n", + "ax.legend()\n", + "ax2.legend()\n" + ] + }, + { + "cell_type": "markdown", + "id": "68e45fe0-9d1d-4d13-af74-9302c3f3c118", + "metadata": {}, + "source": [ + "> Figure 3: A figure comparing the difference between cModel and Kron magnitudes, compared to the difference between cModel and sersic magnitudes (left panel). Generally, both Kron and sersic the measurements are in comparable agreement with cModel. The right panel shows the histogram of magnitude differences, demonstrating that there are not systematic offsets but slightly higher scatter from Kron with respect to cModel.\n", + "\n", + "Below, explore how circular aperture photometry compares to cModel. Generally, magnitudes measured using aperture photometry in the LSST pipeline are fainter than those measured from cModel, because the fixed circular aperture systematically underestimates the flux in the galaxy wings (and the lost flux increases as the intrinsic size of the galaxy increases, e.g. as traced by the Kron radius)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f867380a-dac7-4a0b-a249-b8ee199cfdf3", + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", + " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", + "\n", + "bins = np.arange(2, 15, 1)\n", + "ylims = [-1.5, 1.5]\n", + "\n", + "ax.plot(i_kronRad, (cmodel_mag-ap06_mag), '^', alpha=.3,\n", + " label='6-pixel aperture', color='red')\n", + "ax.plot(i_kronRad, (cmodel_mag-ap09_mag), 's', alpha=.3,\n", + " label='9-pixel aperture', color='orange')\n", + "ax.plot(i_kronRad, (cmodel_mag-ap12_mag), 'o', alpha=.3,\n", + " label='12-pixel aperture', color='green')\n", + "ax.plot(i_kronRad, (cmodel_mag-ap17_mag), '.', alpha=.3,\n", + " label='17-pixel aperture', color='blue')\n", + "\n", + "ax2.hist((cmodel_mag-ap17_mag), edgecolor='blue', orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", stacked=True, fill=False)\n", + "ax2.hist((cmodel_mag-ap12_mag), edgecolor='green', orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", stacked=True, fill=False)\n", + "ax2.hist((cmodel_mag-ap09_mag), edgecolor='orange', orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", stacked=True, fill=False)\n", + "ax2.hist((cmodel_mag-ap06_mag), edgecolor='red', orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", stacked=True, fill=False)\n", + "\n", + "ax2.set_ylim(ylims)\n", + "ax.axhline(0, linestyle='--', color='k')\n", + "ax2.axhline(0, linestyle='--', color='k')\n", + "ax.set_xlabel('Kron Radius [i-band; pixels]')\n", + "ax.set_ylabel('cModel mag - Aperture mag')\n", + "ax.set_ylim(ylims)\n", + "ax.set_xlim([2, 12])\n", + "ax.legend()" + ] + }, + { + "cell_type": "markdown", + "id": "01de6505-06f2-4c80-a674-7a421613fd8c", + "metadata": {}, + "source": [ + "> Figure 4: A comparison of the difference between cModel photometry and aperture photometry measured by the LSST pipelines for four different aperture sizes as a function of galaxy size (as measured using the Kron radius). The left panel shows the scatter plot of difference in photometry vs Kron radius, and the right panel shows a histogram of these values that demonstrate that larger aperture sizes have photometry that is closer to the cModel. The right panel shows histograms of the data in the left panel, where the colors indicate for the same data in each panel." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40604f56-60f7-43d3-afe7-981950402813", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(7, 6))\n", + "ylims = [-1.2, 1.2]\n", + "bins = np.arange(16, 27, 1)\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-ap06_mag), '^', alpha=.1,\n", + " label='cModel 6-pix aperture', color='red')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-ap06_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='red', lw=2, label='bin median', zorder=10)\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-ap09_mag), 's', alpha=.1,\n", + " label='cModel 9-pix aperture', color='orange')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-ap09_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='orange', lw=2,\n", + " label='bin median', zorder=10)\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-ap12_mag), 'o', alpha=.1,\n", + " label='cModel 12-pix aperture', color='green')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-ap12_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='green', lw=2,\n", + " label='bin median', zorder=10)\n", + "\n", + "ax.plot(cmodel_mag, (cmodel_mag-ap17_mag), '.', alpha=.1,\n", + " label='cModel 17-pix aperture', color='blue')\n", + "x = cmodel_mag\n", + "y = (cmodel_mag-ap17_mag)\n", + "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", + " statistic='median', bins=bins)\n", + "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", + "ax.plot(binctr, bin_mean, color='blue', lw=2,\n", + " label='bin median', zorder=10)\n", + "\n", + "ax.axhline(0, linestyle='--')\n", + "ax.set_xlabel('cModel Magnitude')\n", + "ax.set_ylabel('cModel mag - Aperture mag')\n", + "ax.set_ylim([-1, 1])\n", + "ax.set_xlim([20, 25])\n", + "ax.legend()" + ] + }, + { + "cell_type": "markdown", + "id": "84519e9a-0810-49b2-bcd6-1c7dd8e63124", + "metadata": {}, + "source": [ + "> Figure 5: A similar comparison of the difference between cModel photometry and aperture photometry measured by the LSST pipelines for four different aperture sizes, this time as a function of cModel magnitude. Running median is included." + ] + }, + { + "cell_type": "markdown", + "id": "d4e2093d-9d9a-41d4-9217-209519b0a6d9", + "metadata": {}, + "source": [ + "These two figures show that the aperture photometry typically under-estimates the flux relative to the total flux estimated using cModel. As expected, there is a general trend for larger apertures to get closer to the total flux from cModel for large galaxies (i.e. whose Kron Radius is larger). There is also a general trend for the aperture photometry to be less discrepant at fainter magnitudes, since faint galaxies tend to be small.\n" + ] + }, + { + "cell_type": "markdown", + "id": "3d3dd22a-80aa-4282-8c14-1f20c8525088", + "metadata": {}, + "source": [ + "### 4.2. Application of aperture photometry: radial profile\n", + "\n", + "A science application for the aperture photometry is easy visualization of the radial profile of galaxies. In the cell below, make this plot for both a large galaxy (first) and a smaller galaxy of similar brightness (second). The query looks for bright galaxies whose `cModel` magnitude ~ 20 ABmag. Dividing the aperture flux by the surface area of the aperture yields the surface brightness, which can be plotted as a function of radius from the center of the galaxy to compare radial light profiles." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "83fdc23c-6234-4156-ac4a-d340240f2762", + "metadata": {}, + "outputs": [], + "source": [ + "wh = np.where((tab['i_kronRad'] > 20) & (cmodel_mag > 20)\n", + " & (cmodel_mag < 20.5))[0]\n", + "\n", + "indx = 0\n", + "arcsec_per_pix = 0.2\n", + "\n", + "rad = np.array([3, 6, 9, 12, 17, 25, 35, 50]) * arcsec_per_pix\n", + "area = np.pi * rad**2\n", + "profile = np.array([tab['i_ap03Flux'][wh][indx], tab['i_ap06Flux'][wh][indx],\n", + " tab['i_ap09Flux'][wh][indx], tab['i_ap12Flux'][wh][indx],\n", + " tab['i_ap17Flux'][wh][indx], tab['i_ap25Flux'][wh][indx],\n", + " tab['i_ap35Flux'][wh][indx],\n", + " tab['i_ap50Flux'][wh][indx]]) / area\n", + "\n", + "plt.plot(rad, profile, linestyle=':',\n", + " label='Large Radius R='\n", + " + str(np.round(i_kronRad[wh][indx]*arcsec_per_pix, 2)))\n", + "plt.xlabel('Aperture Radius [arcsec]')\n", + "plt.ylabel(r'Surface Brightness [nJy arcsec−2]')\n", + "\n", + "wh2 = np.where((tab['i_kronRad'] < 8) & (tab['i_kronRad'] > 5)\n", + " & (cmodel_mag > 20) & (cmodel_mag < 20.5))[0]\n", + "\n", + "indx = 0\n", + "\n", + "profile = np.array([tab['i_ap03Flux'][wh2][indx], tab['i_ap06Flux'][wh2][indx],\n", + " tab['i_ap09Flux'][wh2][indx], tab['i_ap12Flux'][wh2][indx],\n", + " tab['i_ap17Flux'][wh2][indx], tab['i_ap25Flux'][wh2][indx],\n", + " tab['i_ap35Flux'][wh2][indx],\n", + " tab['i_ap50Flux'][wh2][indx]])/area\n", + "\n", + "plt.plot(rad, profile,\n", + " label='Small Radius R='\n", + " + str(round(i_kronRad[wh2][indx]*arcsec_per_pix, 2)))\n", + "plt.legend()\n", + "plt.yscale('log')" + ] + }, + { + "cell_type": "markdown", + "id": "f2fae258-ded9-4d7b-be5a-c77b1e5fbf9a", + "metadata": {}, + "source": [ + "> Figure 6: Plot demonstrating the use of aperture photometry to plot the surface brightness profile (as a function of aperture radius) for a galaxy with large Kron radius (green solid) and small Kron radius (blue dotted). " + ] + }, + { + "cell_type": "markdown", + "id": "fdc9dd4c-95fc-4ba8-96f7-3d85ea32b9f7", + "metadata": {}, + "source": [ + "## 5. Photometry for color\n", + "\n", + "This section will explore GaaP fluxes (which are optimized for measuring accurate colors between bands).\n", + "\n", + "##### GaaP fluxes\n", + "\n", + "These are the Gaussian-aperture-and-PSF flux that is defined in Kuijken et al. 2008. The main goal of this method is to measure accurate colors while accounting for the different spatial resolution between filters. This is sometimes achieved in other datasets by convolving all images to the largest PSF, but this process of PSF-matching is computationally very time consuming for large images, thus motivating GaaP as a faster alternative. It is not a measure of total flux in a filter. Several measurement apertures are available. \n", + "\n", + "**Aperture**\n", + "\n", + "```\n", + "_gaapFlux : GaaP flux with aperture after multiplying the seeing aperture. Forced on -band.\n", + "_gaapFluxErr : Uncertainty of _gaapFlux.\n", + "```\n", + "\n", + "Where the measurement apertures are 0.5, 0.7, 1.0, 1.5, 2.5, and 3.0 arcseconds. In the column name `` appears as `0p5`, `0p7`, etc. Multiplying by the \"seeing aperture\" refers to convolving the PSF with a kernel so that the PSF is as if the seeing were 1.15 arcseconds. This has the effect of smearing the images of all filters consistently so that the colors are accurate.\n", + "\n", + "For photometric redshifts, and other analysis where accurate colors are important, it is recommended to start with the GaaP fluxes with 1.0 aperture (optimal aperture was found to not perform as well, and should not be used). The largest aperture `gaap3p0` might work better for larger galaxies, but `gaap1p0` has better overall performance. Experiment yourself to see how it works for your science case.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "2468484d-3f81-4be4-b962-3a43a299f41d", + "metadata": {}, + "source": [ + "\n", + "#### 5.1. Kron and GaaP comparison\n", + "\n", + "In the next cell, compare the cModel instead to the Kron and GaaP measures. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08d1c010-a802-4d03-a035-25a07cb51c19", + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", + " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", + "ylims = [-2, 2]\n", + "\n", + "ax.plot(i_kronRad, (cmodel_mag-gaap_mag), 's', alpha=.3,\n", + " label='gaap1p0', color='orange')\n", + "\n", + "ax.plot(i_kronRad, (cmodel_mag-kron_mag), 'o', alpha=.3,\n", + " label='Kron', color='blue')\n", + "\n", + "ax2.hist((cmodel_mag-gaap_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='orange', stacked=True, fill=False, label='gaap1p0')\n", + "ax2.hist((cmodel_mag-kron_mag), orientation=\"horizontal\",\n", + " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", + " histtype=\"step\", color='blue', stacked=True, fill=False, label='Kron')\n", + "\n", + "ax2.set_ylim(ylims)\n", + "ax.axhline(0, linestyle='--', color='k')\n", + "ax2.axhline(0, linestyle='--', color='k')\n", + "ax.set_xlabel('Kron Radius [i-band; pixels]')\n", + "ax.set_ylabel('cModel mag - Other mag')\n", + "ax.set_ylim(ylims)\n", + "ax.set_xlim([2, 15])\n", + "ax.legend()\n", + "ax2.legend()\n" + ] + }, + { + "cell_type": "markdown", + "id": "892f08f9-b64e-485b-8d24-97e9104778d8", + "metadata": {}, + "source": [ + "> Figure 7: The left panel figure shows the i-band magnitude difference between cModel and Kron (orange circles) and between cModel and gaap1p0 (blue squares) vs the Kron radius (a proxy for galaxy size) for the galaxies in the query. The dashed line indicates where the two magnitudes would have the same value. The gaap1p0 magnitude always underestimates the flux, but the offset becomes worse for larger galaxies (relative to the fixed aperture). The right panel shows the histogram of the magnitude differences in the left panel, illustrating that while cModel - Kron magnitudes are similar on average (blue histogram) the gaap1p0 systematically underestimates the flux relative to cModel (orange histogram). \n" + ] + }, + { + "cell_type": "markdown", + "id": "f17ac68e-312c-4d90-9191-0efe4154d8b6", + "metadata": {}, + "source": [ + "#### 5.2. CMD with GaaP\n", + "\n", + "This section demonstrates using GaaP photometry to calculate accurate galaxy colors to identify different types of galaxies. First, define magnitudes from g, r, and i band photometry. The second cell will then compare the colors of galaxies that overlap the galaxy cluster with that in the field. In clusters, galaxies tend to be old, red elliptical galaxies and thus exhibit a well defined red sequence in color space. \n", + "\n", + "The earlier query in Section 2 returned galaxies from a blank, \"field\" location (the ECDFS). These will be dominated by bluer star forming galaxies which are most common in field environments.\n", + "\n", + "Below, add a new query near a known galaxy cluster at redshift z=0.3. This is Abell 360 and sits in the DP1 data from the low ecliptic latitude field.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07de357a-44ff-448f-966b-b5c508b9dfa7", + "metadata": {}, + "outputs": [], + "source": [ + "cluster_ra = 37.83\n", + "cluster_dec = 6.98\n", + "\n", + "query = \"SELECT obj.objectId, obj.coord_ra, obj.coord_dec, \" + \\\n", + " \"obj.detect_fromBlend, obj.detect_isIsolated, \" + \\\n", + " \"obj.i_blendedness, obj.i_extendedness, \" + \\\n", + " \"obj.i_kronFlux, obj.i_kronFluxErr, obj.i_kronRad, \" + \\\n", + " \"obj.i_cModelFlux, obj.i_cModelFluxErr, obj.i_gaap1p0Flux, obj.i_gaap3p0Flux, \" + \\\n", + " \"obj.g_gaap1p0Flux, obj.g_gaap3p0Flux, \" + \\\n", + " \"obj.i_kronFlux_flag, obj.i_cModel_flag \" + \\\n", + " \"FROM dp1.Object AS obj \" + \\\n", + " \"WHERE (obj.i_cModelFlux/obj.i_cModelFluxErr > 20) AND \" + \\\n", + " \"(obj.i_extendedness = 1) AND \" + \\\n", + " \"(obj.i_kronFlux_flag = 0) AND (obj.i_cModel_flag = 0) AND \" + \\\n", + " \"CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), \" + \\\n", + " \"CIRCLE('ICRS',\"+str(cluster_ra)+\",\"+str(cluster_dec)+\", 0.2)) = 1 \"\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5973da2a-2a02-4ad0-8415-deccc55bb89c", + "metadata": {}, + "outputs": [], + "source": [ + "job = service.submit_job(query)\n", + "job.run()\n", + "job.wait(phases=['COMPLETED', 'ERROR'])\n", + "print('Job phase is', job.phase)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18bc593d-bf80-44c1-9a33-158606fa2c8c", + "metadata": {}, + "outputs": [], + "source": [ + "if job.phase == 'ERROR':\n", + " job.raise_if_error()\n", + "assert job.phase == 'COMPLETED'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32400242-e8f6-4461-941a-8617f75960de", + "metadata": {}, + "outputs": [], + "source": [ + "results = job.fetch_result()\n", + "tab2 = results.to_table()" + ] + }, + { + "cell_type": "markdown", + "id": "364f5aca-a4f7-4964-94cf-8c157b75f296", + "metadata": {}, + "source": [ + "First, calculate the magnitudes of galaxies in the 'field' location. Then, calculate the magnitudes for the other filters near the galaxy cluster from the query performed in the cell above. This will enable plotting their colors.\n", + "\n", + "> **Warning:** Like in Section 2, the following cell will produce warnings for invalid value encountered in log10, which happens if the source flux is negative. This happens for a small number of objects and since the goal of the plot is to see the distribution of the majority of sources, the warning can be safely ignored. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4fe037fb-3da7-4f82-bdc9-f62c2f701f7f", + "metadata": {}, + "outputs": [], + "source": [ + "g_field_gaap_mag = -2.50 * np.log10(tab['g_gaap1p0Flux']) + 31.4\n", + "i_field_gaap_mag = -2.50 * np.log10(tab['i_gaap1p0Flux']) + 31.4\n", + "i_field_cmodel_mag = -2.50 * np.log10(tab['i_cModelFlux']) + 31.4\n", + "i_cluster_gaap_mag = -2.50 * np.log10(tab2['i_gaap1p0Flux']) + 31.4\n", + "g_cluster_gaap_mag = -2.50 * np.log10(tab2['g_gaap1p0Flux']) + 31.4\n", + "i_cluster_cmodel_mag = -2.50 * np.log10(tab2['i_cModelFlux']) + 31.4" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "450d40b8-3e1d-4e84-81ca-8d882eef7c69", + "metadata": {}, + "outputs": [], + "source": [ + "fig, (ax, ax1) = plt.subplots(ncols=1, nrows=2, figsize=(10, 6))\n", + "\n", + "ax.plot(i_field_cmodel_mag, (g_field_gaap_mag-i_field_gaap_mag),\n", + " '.', alpha=.1, color='blue', label='Field Galaxies (ECDFS)')\n", + "ax.set_xlabel('i-band Magnitude [cModel]')\n", + "ax.set_ylabel('g-i color')\n", + "ax.set_ylim([-1, 4])\n", + "ax.legend()\n", + "\n", + "ax1.plot(i_cluster_cmodel_mag, (g_cluster_gaap_mag-i_cluster_gaap_mag),\n", + " '.', alpha=.1, color='r', label='Cluster Galaxies (Abell 360)')\n", + "ax1.set_xlabel('i-band Magnitude [cModel]')\n", + "ax1.set_ylabel('g-i color')\n", + "ax1.set_ylim([-1, 4])\n", + "ax1.legend()" + ] + }, + { + "cell_type": "markdown", + "id": "b4e3745a-8e04-4243-898c-10c8d25aae4b", + "metadata": {}, + "source": [ + "> Figure 8: The g − i vs. i color-magnitude diagram for galaxies selected in the queries. Top panel shows the galaxies selected from in a random field that does not contain a galaxy cluster (ECDFS). The bottom panel shows galaxies from a field with a galaxy cluster (A360). The cluster galaxies appear as a \"red sequence\" with red i-g colors, because the Balmer / 4000 Angstrom break spectral feature that traces older stars sits between the bands." + ] + }, + { + "cell_type": "markdown", + "id": "f4800e26-7f1f-4b50-bdf5-b3e7bba174c4", + "metadata": {}, + "source": [ + "A very nice red sequence appears from the red, old galaxies in the cluster! " + ] + }, + { + "cell_type": "markdown", + "id": "927a6cd3-5db6-4308-a7a6-2f13ccdb4568", + "metadata": {}, + "source": [ + "## 6. Exercise for the learner\n", + "\n", + "Compare the `_free_cModelFlux` measurements to `_cModelFlux` in the filters that are not the reference band where the `_cModelFlux` was measured (i.e. `refBand`). Investigate how leaving the cModel measurements free differs from the one measured with parameters fixed to the `refBand`, as a function of decreasing signal to noise. As an additional exercise, check how the signal to noise in colors measured using `_gaap1p0Flux` values compare to those measured with the larger 3.0\" aperture, `_gaap3p0Flux`, where the larger aperture may increase the noise. " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "LSST", + "language": "python", + "name": "lsst" + }, + "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.12.11" + }, + "toc-autonumbering": false + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 46126e84325112a1f96f2524218324bab2accaa5 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Thu, 28 May 2026 23:17:17 +0000 Subject: [PATCH 05/27] updating --- .../303_Galaxies/303_3_Color_selections.ipynb | 167 ++++++++++++++++-- 1 file changed, 151 insertions(+), 16 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index e979e53c..e991c0e2 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -31,14 +31,14 @@ "id": "63df5e4e-1960-4622-8aab-ec4ad076c33b", "metadata": {}, "source": [ - "**Learning objective:** Explore the available measurements of galaxy photometry produced by the LSST pipelines and their applications.\n", + "**Learning objective:** Explore high redshift galaxy selections with DP1.\n", "\n", - "**LSST data products:** `Object` table\n", + "**LSST data products:** `Object` table, `deep_coadd` images\n", "\n", "**Packages:** `lsst.rsp.get_tap_service `\n", "\n", "**Credit:**\n", - "This notebook benefitted from an earlier exploration of simulated data and notebook development by Melissa Graham and Dan Taranu, helpful discussions with Jim Bosch, and ideas from Douglas Tucker. \n", + "This notebook benefitted from ... \n", "\n", "**Get Support:**\n", "Everyone is encouraged to ask questions or raise issues in the \n", @@ -52,9 +52,13 @@ "id": "938cb660-8449-4014-9610-b36a877aea6c", "metadata": {}, "source": [ - "Cell 1: Imports and Initialization\n", + "# 1. Introduction\n", "\n", - "This cell loads all the necessary libraries and sets up your Rubin Science Platform authentication." + "Blurb about color color selection of high-redshift galaxies\n", + "\n", + "Lyman break galaxies in the Canada-France-Hawaii Telescope Legacy Survey (CFHTLS) (Hildebrandt et al., 2009; van der Burg et al., 2010).\n", + "\n", + "GOLDRUSH from HSC Ono et al. 2018" ] }, { @@ -77,12 +81,43 @@ "\n", "from lsst.rsp import get_tap_service\n", "from lsst.rsp.utils import get_pyvo_auth\n", - "\n", - "# Initialize RSP services\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "c69dc44e-06f1-41ab-815c-a06833a4db82", + "metadata": {}, + "source": [ + "Initialize the TAP service, and store the authorization as session" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb892ea6-028a-48ef-b40d-a9d1b8ef961f", + "metadata": {}, + "outputs": [], + "source": [ "tap_service = get_tap_service(\"tap\")\n", - "session = get_pyvo_auth()\n", - "\n", - "# Set our target field (ECDFS)\n", + "session = get_pyvo_auth()\n" + ] + }, + { + "cell_type": "markdown", + "id": "5a454c77-f8b1-41ca-ac25-290df2c557a7", + "metadata": {}, + "source": [ + "Set the target field to be the ECDFS, where many spectroscopic redshift data exist." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34cbab57-1ab5-4d13-8a3d-aaa1c1607250", + "metadata": {}, + "outputs": [], + "source": [ "target_ra = 53.125\n", "target_dec = -27.8" ] @@ -92,7 +127,10 @@ "id": "30d04fb9-a3a3-4c34-b6f8-496e7c648435", "metadata": {}, "source": [ - "Cell 2: Query Rubin Data & Calculate Robust MagnitudesThis retrieves the Rubin sources, enforces the $S/N > 10$ cut on the $i$-band, and creates \"robust\" magnitudes that properly handle dropouts." + "# 2. Query and setup\n", + "\n", + "Cell 2: Query Rubin Data & Calculate Robust Magnitudes\n", + "This retrieves the Rubin sources, enforces the $S/N > 10$ cut on the $i$-band, and creates \"robust\" magnitudes that properly handle dropouts." ] }, { @@ -194,13 +232,23 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"1. Performing Strict Lyman Break Selection...\")\n", + "#print(\"1. Performing Strict Lyman Break Selection...\")\n", + "#is_z4_lbg = (\n", + "# (tab['g_minus_r'] > 1.5) & \n", + "# (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3) & \n", + "# (tab['r_minus_i'] < 1.0) & \n", + "# (tab['g_minus_r'] > 1.5 * tab['r_minus_i'] + 0.8)\n", + "#)\n", + "\n", + "print(\"1. Performing Standard Lyman Break Selection (Ono et al. 2018)...\")\n", "is_z4_lbg = (\n", - " (tab['g_minus_r'] > 1.5) & \n", - " (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3) & \n", + " (tab['g_minus_r'] > 1.0) & \n", + " (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3) & # should this go before re-assigning upper lims to colors?\n", " (tab['r_minus_i'] < 1.0) & \n", " (tab['g_minus_r'] > 1.5 * tab['r_minus_i'] + 0.8)\n", ")\n", + "\n", + "\n", "print(f\" -> Identified {np.sum(is_z4_lbg)} photometric LBG candidates.\")\n", "\n", "print(\"\\n2. Cross-matching VANDELS Truth to Rubin Object Table...\")\n", @@ -250,7 +298,7 @@ "fig, ax = plt.subplots(figsize=(11, 8))\n", "\n", "#cmapcolor = v_i_mag\n", - "cmapcolor = \n", + "#cmapcolor = \n", "\n", "# 1. Background (All Rubin Data)\n", "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Parent Sample (Rubin)')\n", @@ -283,6 +331,26 @@ "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", "\n", + "\n", + "# --- Selection Boundaries (Ono et al. 2018 Cut: g-r > 1.0) ---\n", + "# Ono et al. 2018 criteria for z~4 LBGs:\n", + "# 1. g - r > 1.0\n", + "# 2. r - i < 1.0\n", + "# 3. g - r > 1.5 * (r - i) + 0.8\n", + "\n", + "# Calculate the new intersection between the horizontal line (g-r = 1.0) and the diagonal\n", + "intersect_x = (1.0 - 0.8) / 1.5 # This equals ~0.133\n", + "x_diag = np.linspace(intersect_x, 1.0, 50)\n", + "y_diag = 1.5 * x_diag + 0.8\n", + "\n", + "# Draw the boundaries\n", + "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='purple', linestyle='--', lw=1.5) \n", + "ax.plot(x_diag, y_diag, color='purple', linestyle='--', lw=1.5)\n", + "ax.plot([1.0, 1.0], [2.3, 4.0], color='purple', linestyle='--', lw=1.5)\n", + "\n", + "\n", + "\n", + "\n", "# --- Formatting ---\n", "ax.set_xlim(-1.0, 2.0)\n", "ax.set_ylim(-1.0, 4.0)\n", @@ -690,10 +758,77 @@ "plt.show()" ] }, + { + "cell_type": "markdown", + "id": "6f76f775-b947-44ec-acb2-e5b590e029fd", + "metadata": {}, + "source": [ + "### purity and completeness and other stuff\n", + "\n", + "I think this is not insulated from any biases in the VANDELS slit assignment... TBD" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "6f76f775-b947-44ec-acb2-e5b590e029fd", + "id": "73ec3135-52b0-4cfb-9125-3d7d4ed0ffc0", + "metadata": {}, + "outputs": [], + "source": [ + "#import numpy as np\n", + "#from astropy.coordinates import SkyCoord\n", + "#import astropy.units as u\n", + "\n", + "print(\"--- Calculating LBG Selection Metrics (Completeness & Purity) ---\")\n", + "\n", + "# 1. Isolate ALL high-quality VANDELS spectra (not just z~4)\n", + "is_vandels_hq = vandels_cdfs['q_zsp'] >= 3\n", + "vandels_all_hq = vandels_cdfs[is_vandels_hq]\n", + "\n", + "# 2. Cross-match to the Rubin Object Table\n", + "coord_v_all = SkyCoord(ra=vandels_all_hq['RAJ2000'], dec=vandels_all_hq['DEJ2000'], unit='deg')\n", + "coord_r = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", + "\n", + "idx_rubin_all, d2d_all, _ = coord_v_all.match_to_catalog_sky(coord_r)\n", + "match_mask_all = d2d_all < 1.0 * u.arcsec\n", + "\n", + "matched_rubin_all = tab[idx_rubin_all[match_mask_all]]\n", + "matched_v_all = vandels_all_hq[match_mask_all]\n", + "\n", + "# 3. Define the \"Ground Truth\" (3.5 <= spec-z <= 4.5)\n", + "is_true_z4 = (matched_v_all['zsp'] >= 3.5) & (matched_v_all['zsp'] <= 4.5)\n", + "\n", + "# 4. Define the \"Photometric Selection\" (Ono et al. 2018 Criteria)\n", + "# Applying the exact same mask to the matched Rubin data\n", + "is_selected_lbg = (\n", + " (matched_rubin_all['g_minus_r'] > 1.0) & \n", + " (matched_rubin_all['u_sersicFlux'] / matched_rubin_all['u_sersicFluxErr'] < 3) & \n", + " (matched_rubin_all['r_minus_i'] < 1.0) & \n", + " (matched_rubin_all['g_minus_r'] > 1.5 * matched_rubin_all['r_minus_i'] + 0.8)\n", + ")\n", + "\n", + "# 5. Calculate Confusion Matrix Elements\n", + "true_positives = np.sum(is_true_z4 & is_selected_lbg) # Real z~4 and Selected\n", + "false_positives = np.sum(~is_true_z4 & is_selected_lbg) # Not z~4 but Selected (Interlopers)\n", + "false_negatives = np.sum(is_true_z4 & ~is_selected_lbg) # Real z~4 but Missed\n", + "\n", + "# 6. Calculate Metrics\n", + "completeness = true_positives / (true_positives + false_negatives) if (true_positives + false_negatives) > 0 else 0\n", + "purity = true_positives / (true_positives + false_positives) if (true_positives + false_positives) > 0 else 0\n", + "\n", + "print(f\"Total VANDELS spectra evaluated: {len(matched_v_all)}\")\n", + "print(f\"True Positives (Recovered): {true_positives}\")\n", + "print(f\"False Negatives (Missed): {false_negatives}\")\n", + "print(f\"False Positives (Contaminants): {false_positives}\\n\")\n", + "\n", + "print(f\"COMPLETENESS: {completeness:.1%} <-- (Fraction of real z~4 galaxies we successfully found)\")\n", + "print(f\"PURITY: {purity:.1%} <-- (Fraction of our photometric candidates that are truly at z~4)\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39d7a901-d2a4-4e92-96e1-acbe8d263d0f", "metadata": {}, "outputs": [], "source": [] From 1373980176df6040aab87c853292727cfd0b9503 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Fri, 29 May 2026 00:06:20 +0000 Subject: [PATCH 06/27] updating --- .../303_Galaxies/303_3_Color_selections.ipynb | 232 +++++++++++++----- 1 file changed, 171 insertions(+), 61 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index e991c0e2..f69492e4 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -80,8 +80,7 @@ "import lsdb\n", "\n", "from lsst.rsp import get_tap_service\n", - "from lsst.rsp.utils import get_pyvo_auth\n", - "\n" + "from lsst.rsp.utils import get_pyvo_auth" ] }, { @@ -127,7 +126,7 @@ "id": "30d04fb9-a3a3-4c34-b6f8-496e7c648435", "metadata": {}, "source": [ - "# 2. Query and setup\n", + "# 2. Query and photometric validation \n", "\n", "Cell 2: Query Rubin Data & Calculate Robust Magnitudes\n", "This retrieves the Rubin sources, enforces the $S/N > 10$ cut on the $i$-band, and creates \"robust\" magnitudes that properly handle dropouts." @@ -176,6 +175,52 @@ "tab['r_minus_i'] = tab['r_mag_robust'] - tab['i_mag_robust']" ] }, + { + "cell_type": "markdown", + "id": "8baf7434-aee5-459b-8282-4926978dc4ce", + "metadata": {}, + "source": [ + "### 2.1 perform the LBG color selection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c55bcc2f-8530-4234-8f4c-f585617867f7", + "metadata": {}, + "outputs": [], + "source": [ + "#print(\"1. Performing Strict Lyman Break Selection...\")\n", + "#is_z4_lbg = (\n", + "# (tab['g_minus_r'] > 1.5) & \n", + "# (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3) & \n", + "# (tab['r_minus_i'] < 1.0) & \n", + "# (tab['g_minus_r'] > 1.5 * tab['r_minus_i'] + 0.8)\n", + "#)\n", + "\n", + "print(\"1. Performing Standard Lyman Break Selection (Ono et al. 2018)...\")\n", + "is_z4_lbg = (\n", + " (tab['g_minus_r'] > 1.0) & \n", + " (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3) & # should this go before re-assigning upper lims to colors?\n", + " (tab['r_minus_i'] < 1.0) & \n", + " (tab['g_minus_r'] > 1.5 * tab['r_minus_i'] + 0.8)\n", + ")\n", + "\n", + "print(f\" -> Identified {np.sum(is_z4_lbg)} photometric LBG candidates.\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "e3e6685e-98a1-4612-9869-082ecdab43af", + "metadata": {}, + "source": [ + "### 2.2 Fetch validation data \n", + "\n", + "#### 2.2.1 First fetch a spec-z catalog\n", + "\n", + "This will serve as validation" + ] + }, { "cell_type": "markdown", "id": "34cc9127-8e63-4af0-abc0-9d926b91addd", @@ -203,7 +248,26 @@ "is_vandels_z4 = (vandels_cdfs['zsp'] >= 3.5) & (vandels_cdfs['zsp'] <= 4.5) & (vandels_cdfs['q_zsp'] >= 3)\n", "vandels_truth = vandels_cdfs[is_vandels_z4]\n", "print(f\" -> Found {len(vandels_truth)} high-confidence VANDELS sources at z~4\")\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "a528f722-9ff5-4fbc-903c-fe91da18cdbc", + "metadata": {}, + "source": [ + "#### 2.2.2 Photo-z catalog\n", "\n", + "Now fetch the photo-z catalog that was measured by commissioning team for DP1. See notebook 310.1. Take my word for it that the cmnn measurements perform best at z>3." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69903bab-db67-4728-8647-f81f62c1ba6e", + "metadata": {}, + "outputs": [], + "source": [ "print(\"\\n2. Fetching regional Rubin Photo-z catalog via LSDB...\")\n", "pz_cat = lsdb.open_catalog(\"/rubin/lsdb_data/object_photoz\")\n", "# 1800 arcseconds = 0.5 degrees\n", @@ -220,6 +284,8 @@ "id": "fe011d0d-4077-402c-be5d-176d23c33439", "metadata": {}, "source": [ + "#### 2.2.3 Cross-match\n", + "\n", "Cell 4: Lyman Break Selection & Cross-Matching\n", "\n", "Here we perform the strict LBG selection on the Rubin data, then match it against the VANDELS truth catalog to see what passed and what failed" @@ -232,24 +298,7 @@ "metadata": {}, "outputs": [], "source": [ - "#print(\"1. Performing Strict Lyman Break Selection...\")\n", - "#is_z4_lbg = (\n", - "# (tab['g_minus_r'] > 1.5) & \n", - "# (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3) & \n", - "# (tab['r_minus_i'] < 1.0) & \n", - "# (tab['g_minus_r'] > 1.5 * tab['r_minus_i'] + 0.8)\n", - "#)\n", - "\n", - "print(\"1. Performing Standard Lyman Break Selection (Ono et al. 2018)...\")\n", - "is_z4_lbg = (\n", - " (tab['g_minus_r'] > 1.0) & \n", - " (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3) & # should this go before re-assigning upper lims to colors?\n", - " (tab['r_minus_i'] < 1.0) & \n", - " (tab['g_minus_r'] > 1.5 * tab['r_minus_i'] + 0.8)\n", - ")\n", - "\n", "\n", - "print(f\" -> Identified {np.sum(is_z4_lbg)} photometric LBG candidates.\")\n", "\n", "print(\"\\n2. Cross-matching VANDELS Truth to Rubin Object Table...\")\n", "coord_v = SkyCoord(ra=vandels_truth['RAJ2000'], dec=vandels_truth['DEJ2000'], unit='deg')\n", @@ -277,15 +326,19 @@ "id": "d0e7c80f-0587-4c17-93d8-a52096d4c99e", "metadata": {}, "source": [ + "## 2.3 plot color-color selection\n", + "\n", "Cell 5: Validation Color-Color Plot\n", "\n", - "This visually summarizes everything: your parent Rubin sample, your LBG candidates, and the VANDELS ground-truth objects (color-coded by magnitude)." + "This visually summarizes everything: your parent Rubin sample, your LBG candidates, and the VANDELS ground-truth objects (color-coded by magnitude).\n", + "\n", + "First, store some shorthand variables for the color (TBD if you can consolidate this more with above)" ] }, { "cell_type": "code", "execution_count": null, - "id": "e48c98c3-ac97-43af-99af-74b96fa40731", + "id": "36e4a911-5454-4794-b8ea-9fbdb02ac7d8", "metadata": {}, "outputs": [], "source": [ @@ -293,13 +346,19 @@ "v_r_minus_i = vandels_in_rubin['r_minus_i']\n", "v_g_minus_r = vandels_in_rubin['g_minus_r']\n", "v_i_mag = vandels_in_rubin['i_mag_robust']\n", - "vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", + "vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e48c98c3-ac97-43af-99af-74b96fa40731", + "metadata": {}, + "outputs": [], + "source": [ "\n", "fig, ax = plt.subplots(figsize=(11, 8))\n", "\n", - "#cmapcolor = v_i_mag\n", - "#cmapcolor = \n", - "\n", "# 1. Background (All Rubin Data)\n", "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Parent Sample (Rubin)')\n", "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", @@ -323,13 +382,12 @@ "cbar.ax.invert_yaxis()\n", "\n", "# --- Selection Boundaries (Strict Cut: g-r > 1.5) ---\n", - "x_diag = np.linspace(0.133, 1.0, 50)\n", - "y_diag = 1.5 * x_diag + 0.8\n", - "intersect_x = (1.5 - 0.8) / 1.5\n", - "\n", - "ax.plot([-1.5, intersect_x], [1.5, 1.5], color='black', linestyle='--', lw=1.5) \n", - "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", - "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", + "#x_diag = np.linspace(0.133, 1.0, 50)\n", + "#y_diag = 1.5 * x_diag + 0.8\n", + "#intersect_x = (1.5 - 0.8) / 1.5\n", + "#ax.plot([-1.5, intersect_x], [1.5, 1.5], color='black', linestyle='--', lw=1.5) \n", + "#ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", + "#ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", "\n", "\n", "# --- Selection Boundaries (Ono et al. 2018 Cut: g-r > 1.0) ---\n", @@ -344,9 +402,9 @@ "y_diag = 1.5 * x_diag + 0.8\n", "\n", "# Draw the boundaries\n", - "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='purple', linestyle='--', lw=1.5) \n", - "ax.plot(x_diag, y_diag, color='purple', linestyle='--', lw=1.5)\n", - "ax.plot([1.0, 1.0], [2.3, 4.0], color='purple', linestyle='--', lw=1.5)\n", + "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5) \n", + "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", + "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", "\n", "\n", "\n", @@ -374,8 +432,8 @@ "outputs": [], "source": [ "# Extract parameters for plotting\n", - "v_r_minus_i = vandels_in_rubin['r_minus_i']\n", - "v_g_minus_r = vandels_in_rubin['g_minus_r']\n", + "#v_r_minus_i = vandels_in_rubin['r_minus_i']\n", + "#v_g_minus_r = vandels_in_rubin['g_minus_r']\n", "v_z_phot = vandels_in_rubin['z_phot'] # Changed to use photo-z\n", "vmin, vmax = np.nanmin(v_z_phot), np.nanmax(v_z_phot)\n", "\n", @@ -403,15 +461,11 @@ "cbar.set_label('Photometric Redshift (Rubin z_phot)', fontsize=12, fontweight='bold')\n", "# Inverted Y-axis removed so higher redshift is at the top\n", "\n", - "# --- Selection Boundaries (Strict Cut: g-r > 1.5) ---\n", - "x_diag = np.linspace(0.133, 1.0, 50)\n", - "y_diag = 1.5 * x_diag + 0.8\n", - "intersect_x = (1.5 - 0.8) / 1.5\n", - "\n", - "ax.plot([-1.5, intersect_x], [1.5, 1.5], color='black', linestyle='--', lw=1.5) \n", + "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5) \n", "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", "\n", + "\n", "# --- Formatting ---\n", "ax.set_xlim(-1.0, 2.0)\n", "ax.set_ylim(-1.0, 4.0)\n", @@ -432,6 +486,8 @@ "id": "fbff5f57-9f6e-4847-84c3-582083035bf2", "metadata": {}, "source": [ + "# 3. Visual inspection\n", + "\n", "Cell 6: Visual Inspection with SODA\n", "\n", "Finally, we pull the image cutouts directly from the Rubin archives for the missed and confirmed subsets to inspect the pixels." @@ -440,7 +496,7 @@ { "cell_type": "code", "execution_count": null, - "id": "dbf5ce01-96b4-49f4-81a9-19c791da0e47", + "id": "02008640-c02d-475e-924f-505fa2813276", "metadata": {}, "outputs": [], "source": [ @@ -449,8 +505,16 @@ "missed_r_data = vandels_in_rubin[failed_lbg]\n", "\n", "confirmed_v_truth = v_matched_truth[lbg_success_mask]\n", - "confirmed_r_data = vandels_in_rubin[lbg_success_mask]\n", - "\n", + "confirmed_r_data = vandels_in_rubin[lbg_success_mask]\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dbf5ce01-96b4-49f4-81a9-19c791da0e47", + "metadata": {}, + "outputs": [], + "source": [ "# --- SODA Plotting Function ---\n", "def plot_soda_cutouts_with_pz(r_data, v_data, n_max=10, title_label=\"Candidate\"):\n", " n_plot = min(len(r_data), n_max)\n", @@ -505,7 +569,7 @@ " norm = ImageNormalize(img_array, interval=ZScaleInterval(), stretch=LinearStretch())\n", " ax.imshow(img_array, origin='lower', cmap='gray', norm=norm)\n", " cy, cx = img_array.shape[0]//2, img_array.shape[1]//2\n", - " ax.add_patch(plt.Circle((cx, cy), radius=4, color='cyan', fill=False, lw=1.5, alpha=0.7))\n", + " ax.add_patch(plt.Circle((cx, cy), radius=6, color='cyan', fill=False, lw=1.5, alpha=0.7))\n", "\n", " except Exception:\n", " ax.text(0.5, 0.5, 'SODA Error', ha='center', va='center', transform=ax.transAxes, color='red')\n", @@ -520,7 +584,24 @@ "\n", " plt.tight_layout()\n", " plt.show()\n", - "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "e855ba72-793a-47d1-8871-1ca6faac0246", + "metadata": {}, + "source": [ + "Now plot the 4-filter cutouts for the real high redshift galaxies confirmed by VANDELS but that the Rubin color selection missed. They are a mix of galaxies with too-blue g-r colors and too-red r-i colors." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d34a329-15fc-433f-942e-6b6e7e396ff3", + "metadata": {}, + "outputs": [], + "source": [ "# Execute the plots\n", "plot_soda_cutouts_with_pz(missed_r_data, missed_v_truth, n_max=10, title_label=\"Missed VANDELS Truth\")\n" ] @@ -555,6 +636,8 @@ "id": "8b7702fb-ec6d-4776-8559-6d0b663f015d", "metadata": {}, "source": [ + "## 4. Photo-z validation\n", + "\n", "Do some photo-z validation " ] }, @@ -649,15 +732,24 @@ " print(f\"Catastrophic Outlier Fraction: {outlier_fraction:.1%}\")" ] }, + { + "cell_type": "markdown", + "id": "f84560ee-c33a-45b6-b8b9-137cac8adc21", + "metadata": {}, + "source": [ + "A quick test to decide which photo-z measurement performs best at z>3" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "ac5967f1-3e2d-41cc-a089-d597ff050583", + "id": "05d839a7-d226-4334-81d3-97fae5246d92", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", + "import math\n", "from astropy.coordinates import SkyCoord\n", "import astropy.units as u\n", "\n", @@ -696,16 +788,23 @@ "# Set up index lookup for fast mapping from the LSDB dataframe\n", "pz_regional_indexed = pz_regional.set_index('objectId')\n", "\n", - "# --- 4. Build the Multi-Panel Plot ---\n", - "# Dynamically size the figure based on how many algorithms we found\n", - "fig, axes = plt.subplots(1, len(available_pz_cols), figsize=(6 * len(available_pz_cols), 6))\n", + "# --- 4. Build the 3-Row Multi-Panel Plot ---\n", + "# Calculate columns and rows for the layout (Targeting 3 rows)\n", + "n_plots = len(available_pz_cols)\n", + "n_rows = min(3, n_plots) # Use up to 3 rows\n", + "n_cols = math.ceil(n_plots / n_rows)\n", + "\n", + "# Size the figure dynamically based on the grid shape\n", + "fig, axes = plt.subplots(n_rows, n_cols, figsize=(6 * n_cols, 5 * n_rows))\n", "\n", - "# Handle the 1D axes case if only 1 code is found\n", - "if len(available_pz_cols) == 1:\n", - " axes = [axes]\n", + "# Flatten the axes array for easy 1D iteration\n", + "if isinstance(axes, np.ndarray):\n", + " axes_flat = axes.flatten()\n", + "else:\n", + " axes_flat = [axes]\n", "\n", "for i, pz_col in enumerate(available_pz_cols):\n", - " ax = axes[i]\n", + " ax = axes_flat[i]\n", " \n", " # Extract photo-z for the specific algorithm\n", " z_phot_all = pz_regional_indexed.reindex(obj_ids_all)[pz_col].values\n", @@ -732,8 +831,11 @@ " ax.set_xlim(0, 6.5)\n", " ax.set_ylim(0, 6.5)\n", " ax.set_xlabel('VANDELS z_spec', fontsize=13)\n", - " if i == 0:\n", + " \n", + " # Add Y-labels only to the leftmost plot of each row\n", + " if i % n_cols == 0:\n", " ax.set_ylabel('Rubin z_phot', fontsize=13)\n", + " \n", " ax.set_title(f'{pz_col}', fontsize=14, fontweight='bold')\n", " \n", " # Calculate & display Standard Photo-z Quality Metrics on the plot\n", @@ -748,13 +850,21 @@ " ax.text(0.05, 0.95, textstr, transform=ax.transAxes, fontsize=11,\n", " verticalalignment='top', bbox=props)\n", "\n", - "# Add a shared colorbar\n", - "cbar = fig.colorbar(sc, ax=axes, pad=0.02)\n", + "# Hide any empty subplots if there are blank spaces in the grid\n", + "for j in range(n_plots, len(axes_flat)):\n", + " axes_flat[j].set_visible(False)\n", + "\n", + "# --- 5. Custom Colorbar Placement ---\n", + "# Adjust the subplots to leave exactly 15% of the figure width empty on the right side\n", + "plt.subplots_adjust(top=0.90, right=0.85, wspace=0.2, hspace=0.35)\n", + "\n", + "# Add a dedicated axis for the colorbar [left, bottom, width, height]\n", + "cbar_ax = fig.add_axes([0.88, 0.15, 0.02, 0.7])\n", + "cbar = fig.colorbar(sc, cax=cbar_ax)\n", "cbar.set_label('i-band [Robust Sersic Mag]', fontsize=12, fontweight='bold')\n", "cbar.ax.invert_yaxis() \n", "\n", "plt.suptitle('Multi-Code Validation: Rubin Photo-z vs. VANDELS Spec-z', fontsize=18, fontweight='bold')\n", - "plt.subplots_adjust(top=0.88, wspace=0.15)\n", "plt.show()" ] }, From 9a3d129cd3a12b54332c81abfa46df9bbaf7b2cf Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Mon, 1 Jun 2026 05:03:46 +0000 Subject: [PATCH 07/27] updating --- .../303_Galaxies/303_3_Color_selections.ipynb | 254 ++++++++++++++---- 1 file changed, 208 insertions(+), 46 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index f69492e4..f9687a41 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -54,11 +54,38 @@ "source": [ "# 1. Introduction\n", "\n", - "Blurb about color color selection of high-redshift galaxies\n", + "Color selections have served as a key method of identifying galaxies of different populations over decades. Especially at redshift z > 2.5, the Lyman-break is a strong spectral feature that is exploited to identify galaxies at high redshift. Lyman-break selections make use of the fact that intergalactic hydrogen in the foreground absorbs all the light of background galaxies that is emitted blueward of the Lyman limit (912A) or at very high redshifts, Lyman-alpha (1216A). More details about why this works can be found at this blog-post. \n", "\n", - "Lyman break galaxies in the Canada-France-Hawaii Telescope Legacy Survey (CFHTLS) (Hildebrandt et al., 2009; van der Burg et al., 2010).\n", + "Such galaxies can be identified by their very red colors between filters that bridge the Lyman break feature. Since intergalactic hydrogen absorbs all the light blueward of the Lyman break, true z > 3 galaxies should be undetected in the LSST u-band, and at z > 4 undetected in the LSST g-band.\n", "\n", - "GOLDRUSH from HSC Ono et al. 2018" + "This notebook demonstrates this color selection on DP1 data for galaxies at 3.5 < z < 4.5 as an example, and provides some validation metrics for its performance. It makes use of color selections defined and used in the literature with data from facilities with similar filtersets (bandpass shapes and effective wavelengths). These are using the Canada-France-Hawaii Telescope Legacy Survey (CFHTLS) as presented in Hildebrandt et al., 2009 and van der Burg et al., 2010. A similar selection was performed using Subaru Hyper-Suprime Cam data in the GOLDRUSH survey Ono et al. 2018\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "658b87f7-6184-4d86-9f10-d5420930c932", + "metadata": {}, + "source": [ + "**Related tutorials:** See also the 303-series tutorials on galaxy science, specifically the 303.1 tutorial that overviews the various galaxy photometry measurements produced by the LSST pipelines, and their science use cases. " + ] + }, + { + "cell_type": "markdown", + "id": "b4ce8a67-a3c9-4609-aaeb-6b62f865943e", + "metadata": {}, + "source": [ + "## 1.1 Import packages\n", + "\n", + "Import common scientific analysis packages `numpy`, `matplotlib`, and `astropy`.\n", + "\n", + "Import LSST Science Pipelines package utilities for remote data access `lsst.rsp`.\n", + "\n", + "Import `pyvo` packages for working with the virtual observatory cutout service.\n", + "\n", + "Import `astroquery` to allow access to publicly available external science products (spectroscopic redshift catalogs).\n", + "\n", + "Import the [LSDB package](https://github.com/astronomy-commons/lsdb/) to work with LSDB-formatted files, along with standard astronomy packages and LSST software for data access." ] }, { @@ -75,12 +102,14 @@ "from astropy.coordinates import SkyCoord\n", "import astropy.units as u\n", "from astropy.visualization import ZScaleInterval, LinearStretch, ImageNormalize\n", - "from astroquery.vizier import Vizier\n", - "from pyvo.dal.adhoc import SodaQuery, DatalinkResults\n", - "import lsdb\n", "\n", "from lsst.rsp import get_tap_service\n", - "from lsst.rsp.utils import get_pyvo_auth" + "from lsst.rsp.utils import get_pyvo_auth\n", + "\n", + "from pyvo.dal.adhoc import SodaQuery, DatalinkResults\n", + "from astroquery.vizier import Vizier\n", + "\n", + "import lsdb" ] }, { @@ -88,7 +117,9 @@ "id": "c69dc44e-06f1-41ab-815c-a06833a4db82", "metadata": {}, "source": [ - "Initialize the TAP service, and store the authorization as session" + "### 1.2. Define parameters and functions\n", + "\n", + "Create an instance of the TAP service, and store the authorization as `session`." ] }, { @@ -99,7 +130,16 @@ "outputs": [], "source": [ "tap_service = get_tap_service(\"tap\")\n", - "session = get_pyvo_auth()\n" + "session = get_pyvo_auth()" + ] + }, + { + "cell_type": "markdown", + "id": "30d04fb9-a3a3-4c34-b6f8-496e7c648435", + "metadata": {}, + "source": [ + "# 2. Query and photometric validation \n", + "\n" ] }, { @@ -123,13 +163,10 @@ }, { "cell_type": "markdown", - "id": "30d04fb9-a3a3-4c34-b6f8-496e7c648435", + "id": "e9c07b17-bc81-42e2-991c-0ab3a7d30eb8", "metadata": {}, "source": [ - "# 2. Query and photometric validation \n", - "\n", - "Cell 2: Query Rubin Data & Calculate Robust Magnitudes\n", - "This retrieves the Rubin sources, enforces the $S/N > 10$ cut on the $i$-band, and creates \"robust\" magnitudes that properly handle dropouts." + "Define a query to retrieve galaxies in this field using an 0.2 degree radius from the object table using the `extendedness`=1 flag. To ensure good detections, include the $S/N > 10$ cut on the $i$-band." ] }, { @@ -139,7 +176,6 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"1. Querying Rubin DP1 Catalog...\")\n", "query = f\"\"\"\n", "SELECT obj.objectId, obj.coord_ra, obj.coord_dec,\n", " obj.u_sersicFlux, obj.u_sersicFluxErr,\n", @@ -152,25 +188,91 @@ " AND (obj.sersic_no_data_flag = 0) \n", " AND (obj.i_cModel_flag = 0) \n", " AND CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), CIRCLE('ICRS', {target_ra}, {target_dec}, 0.2)) = 1\n", - "\"\"\"\n", - "\n", - "job = tap_service.run_sync(query)\n", - "tab = job.to_table()\n", - "print(f\" -> Retrieved {len(tab)} Rubin sources.\")\n", - "\n", - "print(\"2. Calculating Robust Sersic Magnitudes...\")\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "d972de3e-c2d7-4297-801d-41bb933dda01", + "metadata": {}, + "source": [ + "Run the query." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14d7986a-ff5c-40dd-9d36-98829a172075", + "metadata": {}, + "outputs": [], + "source": [ + "job = tap_service.submit_job(query)\n", + "job.run()\n", + "job.wait(phases=['COMPLETED', 'ERROR'])\n", + "print('Job phase is', job.phase)\n", + "assert job.phase == 'COMPLETED'" + ] + }, + { + "cell_type": "markdown", + "id": "4926b530-4757-4732-833a-32660f432e0d", + "metadata": {}, + "source": [ + "Retrieve the query results and save as an `astropy` table." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8f33b19f-bfac-4376-aaa9-e5c5ff8d9201", + "metadata": {}, + "outputs": [], + "source": [ + "tab = job.fetch_result().to_table()\n", + "print(f\" -> Retrieved {len(tab)} Rubin sources.\")" + ] + }, + { + "cell_type": "markdown", + "id": "34047a4c-0412-4944-9c19-8dd14d6edf03", + "metadata": {}, + "source": [ + "Galaxy colors may be inaccurate for galaxies whose S/N is very low in one or more filters. To ensure that (in particular) the dropout color is robust, if the S/N is less than 1 then set the flux to the flux error (this will use the 1-sigma lower limit to the color, replacing flux with the error floor if S/N < 1). " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a17417e1-8ea1-4fb8-8a0a-b94d9a121a8a", + "metadata": {}, + "outputs": [], + "source": [ "filters = ['u', 'g', 'r', 'i']\n", "zp = 31.4\n", "\n", "with np.errstate(divide='ignore', invalid='ignore'):\n", " for f in filters:\n", - " # Replace flux with the error floor if S/N < 1\n", " flux_robust = np.where(tab[f'{f}_sersicFlux'] < tab[f'{f}_sersicFluxErr'], \n", " tab[f'{f}_sersicFluxErr'], \n", " tab[f'{f}_sersicFlux'])\n", - " tab[f'{f}_mag_robust'] = -2.50 * np.log10(flux_robust) + zp\n", - "\n", - "# Calculate global colors for the whole Rubin table\n", + " tab[f'{f}_mag_robust'] = -2.50 * np.log10(flux_robust) + zp\n" + ] + }, + { + "cell_type": "markdown", + "id": "6ed23adb-f5ff-409c-b8b9-e63251d1d77a", + "metadata": {}, + "source": [ + "Store these colors as new columns in the table." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1f109d4d-3cb9-44f8-9bac-6230a2eaf812", + "metadata": {}, + "outputs": [], + "source": [ "tab['g_minus_r'] = tab['g_mag_robust'] - tab['r_mag_robust']\n", "tab['r_minus_i'] = tab['r_mag_robust'] - tab['i_mag_robust']" ] @@ -180,7 +282,11 @@ "id": "8baf7434-aee5-459b-8282-4926978dc4ce", "metadata": {}, "source": [ - "### 2.1 perform the LBG color selection" + "### 2.1 perform the LBG color selection\n", + "\n", + "Now, perform the color selection to identify the high-redshift galaxy candidates. Use a typical Lyman Break Selection for a camera with similar filter properties to the LSST (e.g. Ono et al. 2018) which require very red g-r colors (to identify galaxies with strong lyman breaks), and relatively blue r-i colors (which excludes stars). \n", + "\n", + "Also add another criteria requiring that the u-band flux be undetected (S/N < 3), since all u-band flux should also be absorbed by the intergalactic medium since it is blueward of the Lyman limit at z > 3." ] }, { @@ -190,15 +296,6 @@ "metadata": {}, "outputs": [], "source": [ - "#print(\"1. Performing Strict Lyman Break Selection...\")\n", - "#is_z4_lbg = (\n", - "# (tab['g_minus_r'] > 1.5) & \n", - "# (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3) & \n", - "# (tab['r_minus_i'] < 1.0) & \n", - "# (tab['g_minus_r'] > 1.5 * tab['r_minus_i'] + 0.8)\n", - "#)\n", - "\n", - "print(\"1. Performing Standard Lyman Break Selection (Ono et al. 2018)...\")\n", "is_z4_lbg = (\n", " (tab['g_minus_r'] > 1.0) & \n", " (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3) & # should this go before re-assigning upper lims to colors?\n", @@ -247,8 +344,7 @@ "# Isolate high-confidence z~4 spectra (3.5 <= z <= 4.5)\n", "is_vandels_z4 = (vandels_cdfs['zsp'] >= 3.5) & (vandels_cdfs['zsp'] <= 4.5) & (vandels_cdfs['q_zsp'] >= 3)\n", "vandels_truth = vandels_cdfs[is_vandels_z4]\n", - "print(f\" -> Found {len(vandels_truth)} high-confidence VANDELS sources at z~4\")\n", - "\n" + "print(f\" -> Found {len(vandels_truth)} high-confidence VANDELS sources at z~4\")\n" ] }, { @@ -412,9 +508,9 @@ "# --- Formatting ---\n", "ax.set_xlim(-1.0, 2.0)\n", "ax.set_ylim(-1.0, 4.0)\n", - "ax.set_xlabel('$(r - i)$ [Robust Sersic Mag]', fontsize=14)\n", - "ax.set_ylabel('$(g - r)$ [Robust Sersic Mag]', fontsize=14)\n", - "ax.set_title('Validation of Strict Lyman Break Selection (g-r > 1.5)', fontsize=16, fontweight='bold')\n", + "ax.set_xlabel('$(r - i)$ [AB Mag]', fontsize=14)\n", + "ax.set_ylabel('$(g - r)$ [AB Mag]', fontsize=14)\n", + "ax.set_title('Validation of Lyman Break Selection (g-r > 1.5)', fontsize=16, fontweight='bold')\n", "\n", "handles, labels = ax.get_legend_handles_labels()\n", "ax.legend(handles, labels, loc='upper left', framealpha=1)\n", @@ -469,9 +565,75 @@ "# --- Formatting ---\n", "ax.set_xlim(-1.0, 2.0)\n", "ax.set_ylim(-1.0, 4.0)\n", + "ax.set_xlabel('$(r - i)$ [Sersic Mag]', fontsize=14)\n", + "ax.set_ylabel('$(g - r)$ [Sersic Mag]', fontsize=14)\n", + "ax.set_title('Validation of Lyman Break Selection (Color-Coded by Photo-z)', fontsize=16, fontweight='bold')\n", + "\n", + "handles, labels = ax.get_legend_handles_labels()\n", + "ax.legend(handles, labels, loc='upper left', framealpha=1)\n", + "ax.grid(True, linestyle=':', alpha=0.6)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f555b639-0d0c-4826-a7b5-d7e3c2b11c0c", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract parameters for plotting\n", + "v_r_minus_i = vandels_in_rubin['r_minus_i']\n", + "v_g_minus_r = vandels_in_rubin['g_minus_r']\n", + "\n", + "# --- CHANGED: Use spectroscopic redshift from the matched VANDELS truth catalog ---\n", + "v_z_spec = v_matched_truth['zsp'] \n", + "vmin, vmax = np.nanmin(v_z_spec), np.nanmax(v_z_spec)\n", + "\n", + "fig, ax = plt.subplots(figsize=(11, 8))\n", + "\n", + "# 1. Background (All Rubin Data)\n", + "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Parent Sample (Rubin)')\n", + "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", + " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates (g-r > 1.5)')\n", + "\n", + "# 2. VANDELS Truth - Missed Sources ('+')\n", + "sc1 = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", + " s=120, c=v_z_spec[failed_lbg], cmap='plasma', vmin=vmin, vmax=vmax, \n", + " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", + " label='VANDELS Truth (Missed)')\n", + "\n", + "# 3. VANDELS Truth - Confirmed Sources ('*')\n", + "sc2 = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", + " s=250, c=v_z_spec[lbg_success_mask], cmap='plasma', vmin=vmin, vmax=vmax, \n", + " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", + " label='Confirmed LBG Candidates')\n", + "\n", + "# --- Colorbar ---\n", + "cbar = plt.colorbar(sc2, ax=ax)\n", + "# --- CHANGED: Updated label to Spec-z ---\n", + "cbar.set_label('Spectroscopic Redshift (VANDELS z_spec)', fontsize=12, fontweight='bold')\n", + "# Inverted Y-axis removed so higher redshift is at the top\n", + "\n", + "# --- Selection Boundaries ---\n", + "x_diag = np.linspace(0.133, 1.0, 50)\n", + "y_diag = 1.5 * x_diag + 0.8\n", + "intersect_x = (1.5 - 0.8) / 1.5\n", + "\n", + "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5) \n", + "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", + "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", + "\n", + "\n", + "# --- Formatting ---\n", + "ax.set_xlim(-1.0, 2.0)\n", + "ax.set_ylim(-1.0, 4.0)\n", "ax.set_xlabel('$(r - i)$ [Robust Sersic Mag]', fontsize=14)\n", "ax.set_ylabel('$(g - r)$ [Robust Sersic Mag]', fontsize=14)\n", - "ax.set_title('Validation of Strict Lyman Break Selection (Color-Coded by Photo-z)', fontsize=16, fontweight='bold')\n", + "# --- CHANGED: Updated title to Spec-z ---\n", + "ax.set_title('Validation of Strict Lyman Break Selection (Color-Coded by Spec-z)', fontsize=16, fontweight='bold')\n", "\n", "handles, labels = ax.get_legend_handles_labels()\n", "ax.legend(handles, labels, loc='upper left', framealpha=1)\n", @@ -777,11 +939,11 @@ "print(\"3. Scanning LSDB for available Photo-z columns...\")\n", "\n", "# Dynamically find ANY column that is a photo-z mean or mode estimate\n", - "available_pz_cols = [col for col in pz_regional.columns if ('z_mean' in col.lower() or 'z_mode' in col.lower())]\n", + "available_pz_cols = [col for col in pz_regional.columns if ('z_mean' in col.lower() or 'z_median' in col.lower())]\n", "\n", "# Fallback just in case nothing matches\n", - "if not available_pz_cols:\n", - " available_pz_cols = ['bpz_z_mean']\n", + "#if not available_pz_cols:\n", + "# available_pz_cols = ['bpz_z_mean']\n", "\n", "print(f\" -> Comparing {len(available_pz_cols)} measurements: {available_pz_cols}\")\n", "\n", @@ -861,7 +1023,7 @@ "# Add a dedicated axis for the colorbar [left, bottom, width, height]\n", "cbar_ax = fig.add_axes([0.88, 0.15, 0.02, 0.7])\n", "cbar = fig.colorbar(sc, cax=cbar_ax)\n", - "cbar.set_label('i-band [Robust Sersic Mag]', fontsize=12, fontweight='bold')\n", + "cbar.set_label('i-band [Sersic Mag]', fontsize=12, fontweight='bold')\n", "cbar.ax.invert_yaxis() \n", "\n", "plt.suptitle('Multi-Code Validation: Rubin Photo-z vs. VANDELS Spec-z', fontsize=18, fontweight='bold')\n", From 24a120505f8cdfe7951bc518db870bb7cb115eb3 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Tue, 2 Jun 2026 22:53:21 +0000 Subject: [PATCH 08/27] updating --- .../303_Galaxies/303_3_Color_selections.ipynb | 73 +- .../Color_selections_exploration.ipynb | 2242 ----------------- 2 files changed, 70 insertions(+), 2245 deletions(-) delete mode 100644 DP1/300_Science_Demos/303_Galaxies/Color_selections_exploration.ipynb diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index f9687a41..a3e2a029 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -517,7 +517,11 @@ "ax.grid(True, linestyle=':', alpha=0.6)\n", "\n", "plt.tight_layout()\n", - "plt.show()" + "plt.show()\n", + "\n", + "# note: could these below horizontal line be in a shallow are of g? Could be a data thing\n", + "# use the survey depth map to cut out the edges. or use a smaller search radius from the center. survey property maps will show\n", + "# depth at given location and use that instead of the \n" ] }, { @@ -749,6 +753,69 @@ "\n" ] }, + { + "cell_type": "markdown", + "id": "965fe3c3-5d32-42a6-b2cf-260a8275af44", + "metadata": {}, + "source": [ + "Spec-z histogram of color selected?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28a47c0b-ac22-40bc-93d3-f46471382f0f", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "\n", + "print(\"Isolating VANDELS galaxies that passed the Rubin LBG color cut...\")\n", + "\n", + "# Re-apply the Ono et al. 2018 LBG selection mask to the cross-matched catalog\n", + "is_selected_lbg = (\n", + " (matched_rubin_all['g_minus_r'] > 1.0) & \n", + " (matched_rubin_all['u_sersicFlux'] / matched_rubin_all['u_sersicFluxErr'] < 3) & \n", + " (matched_rubin_all['r_minus_i'] < 1.0) & \n", + " (matched_rubin_all['g_minus_r'] > 1.5 * matched_rubin_all['r_minus_i'] + 0.8)\n", + ")\n", + "\n", + "# Extract the true spectroscopic redshifts of ONLY the galaxies inside our color box\n", + "selected_spec_z = matched_v_all['zsp'][is_selected_lbg]\n", + "\n", + "print(f\" -> Found {len(selected_spec_z)} VANDELS sources inside the color selection box.\")\n", + "\n", + "fig, ax = plt.subplots(figsize=(10, 6))\n", + "\n", + "# Define the redshift bins (e.g., from z=0 to z=6.5 in steps of z=0.2)\n", + "z_bins = np.arange(0, 6.6, 0.2)\n", + "\n", + "# Plot the histogram\n", + "ax.hist(selected_spec_z, bins=z_bins, color='dodgerblue', edgecolor='black', alpha=0.8, zorder=3)\n", + "\n", + "# Highlight our target ground-truth window (3.2 <= z <= 4.5)\n", + "ax.axvspan(3.2, 4.5, color='mediumseagreen', alpha=0.2, label='Target Window ($3.5 < z < 4.5$)')\n", + "ax.axvline(3.2, color='darkgreen', linestyle='--', linewidth=1.5, zorder=4)\n", + "ax.axvline(4.5, color='darkgreen', linestyle='--', linewidth=1.5, zorder=4)\n", + "\n", + "# Formatting\n", + "ax.set_xlim(0, 6.5)\n", + "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", + "ax.set_ylabel('Number of Selected Candidates', fontsize=14)\n", + "ax.set_title('True Redshift Distribution of LBG Candidates (g-dropout)', fontsize=16, fontweight='bold')\n", + "\n", + "ax.legend(loc='upper right', fontsize=12, framealpha=1)\n", + "ax.grid(axis='y', linestyle=':', alpha=0.7, zorder=0)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "# andres added some things about the g-band leak to the documentation. can cite that dp1. then change it for dp2 updated nb\n", + "# rthat is def not expected to be a problem for dp2\n", + "# it was something related to camera temperature. \n" + ] + }, { "cell_type": "markdown", "id": "e855ba72-793a-47d1-8871-1ca6faac0246", @@ -1051,7 +1118,7 @@ "#from astropy.coordinates import SkyCoord\n", "#import astropy.units as u\n", "\n", - "print(\"--- Calculating LBG Selection Metrics (Completeness & Purity) ---\")\n", + "print(\"--- Calculating DP1 LBG Selection Metrics (Completeness & Purity) ---\")\n", "\n", "# 1. Isolate ALL high-quality VANDELS spectra (not just z~4)\n", "is_vandels_hq = vandels_cdfs['q_zsp'] >= 3\n", @@ -1088,7 +1155,7 @@ "completeness = true_positives / (true_positives + false_negatives) if (true_positives + false_negatives) > 0 else 0\n", "purity = true_positives / (true_positives + false_positives) if (true_positives + false_positives) > 0 else 0\n", "\n", - "print(f\"Total VANDELS spectra evaluated: {len(matched_v_all)}\")\n", + "print(f\"Total VANDELS spectra evaluated (u-band lim included): {len(matched_v_all)}\")\n", "print(f\"True Positives (Recovered): {true_positives}\")\n", "print(f\"False Negatives (Missed): {false_negatives}\")\n", "print(f\"False Positives (Contaminants): {false_positives}\\n\")\n", diff --git a/DP1/300_Science_Demos/303_Galaxies/Color_selections_exploration.ipynb b/DP1/300_Science_Demos/303_Galaxies/Color_selections_exploration.ipynb deleted file mode 100644 index c5512fa9..00000000 --- a/DP1/300_Science_Demos/303_Galaxies/Color_selections_exploration.ipynb +++ /dev/null @@ -1,2242 +0,0 @@ -{ - "cells": [ - { - "attachments": { - "697dbfa5-0793-4e9d-8401-2f3b86b0243c.png": { - "image/png": "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GPJmu7BUJEACJEACJEACJEACJEACJEACJEACJFBwApyVrOCIeQASIAESIAESIAESIAESIAESIAESIAES8CYBCkPebBeWigRIgARIgARIgARIgARIgARIgARIgAQKToDCUMER8wAkQAIkQAIkQAIkQAIkQAIkQAIkQAIk4E0CFIa82S4sFQmQAAmQAAmQAAmQAAmQAAmQAAmQAAkUnACFoYIj5gFIgARIgARIgARIgARIgARIgARIgARIwJsEKAx5s11YKhIgARIgARIgARIgARIgARIgARIgARIoOAEKQwVHzAOQAAmQAAmQAAmQAAmQAAmQAAmQAAmQgDcJUBjyZruwVCRAAiRAAiRAAiRAAiRAAiRAAiRAAiRQcAIUhgqOmAcgARIgARIgARIgARIgARIgARIgARIgAW8SoDDkzXZhqUiABEiABEiABEiABEiABEiABEiABEig4AQoDBUcMQ9AAiRAAiRAAiRAAiRAAiRAAiRAAiRAAt4kQGHIm+3CUpEACZAACZAACZAACZAACZAACZAACZBAwQlQGCo4Yh6ABEiABEiABEiABEiABEiABEiABEiABLxJgMKQN9uFpSIBEiABEiABEiABEiABEiABEiABEiCBghOgMFRwxDwACZAACZAACZAACZAACZAACZAACZAACXiTAIUhb7YLS0UCJEACJEACJEACJEACJEACJEACJEACBSdQXfAj8AAkQAIkUAACk4uLgr/k1N3cLPhj8i6BVG2XWGK2YyINfiYBEih3Aqnue7zXlXvLsvwkQAIkUBkEKAxVRjuyFiRQ8QTQqf7tjZvy1o0bliC0GonIaiR8T73rq6ulvrpGupqb5FBPjxzq7bWWXhKLUI83b1y/p+yZruhuatoQv1Av1NNL9UushxkMXRqfSNt2ifsltqM1cNI6P9vfL4e1PYuRcm2jTMuItntO61XI9jPXzoXxsUyLtbGdl861dPV4dm+/PL+vf6PsuX5Id7xitJ1dHS6Nj8tb12/IxNK9wnji9l4vX2JZ8/053+eC2/K5ue+Ze91B63nVI1gW6z6XSb3SXQdOeXjl/pGuDihnPp4v6a5NXJNfOHhQmmprnbDxNxIgARIoCQEKQyXBzoOSAAlkQsB05iAGDc3NyfjCgkzoH0ShdKlOBaITt25LW329PLn7Pnlkxw7PdLgvjI3JP370cboqpPy9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CWxeAr41TZu3+qw5CZBAORGIuzqsWAMXxOWwiytkZsDCbFjoqMOVqtjBZNMxNfVIt1263zHIq6+p2ZgBLN32hf4dbgAQ8LBEQvsgmDhmHUtsK8wgh2ntjSDixTbLVxulY27O0XTb5fJ7crsk5oVzKNtrJB2jYtQtsS52n53qnrh9qcrqVL5c2iaxbsmfndqtUMdMLkPyd6cylaptksvo9rtpW1O3xHtgYl7m/teqM0hipk3rvq7XpVeSqQeWySmX88VwSc7TfPdCuzuV0QvlM6y4JAESIIF8EKAwlA+KzIMESIAESCBjAhhg4I2E1wS7jCvADUmABEiABEiABEiABEiggghQGKqgxmRVSIAESIAESIAESIAESIAESIAESIAESMANAU5X74YWtyUBEiABEiABEiABEiABEiABEiABEiCBCiJAYaiCGpNVIQESIAESIAESIAESIAESIAESIAESIAE3BCgMuaHFbUmABEiABEiABEiABEiABEiABEiABEiggghQGKqgxmRVSIAESIAESIAESIAESIAESIAESIAESMANAQpDbmhxWxIgARIgARIgARIgARIgARIgARIgARKoIAIUhiqoMVkVEiABEiABEiABEiABEiABEiABEiABEnBDgMKQG1rclgRIgARIgARIgARIgARIgARIgARIgAQqiACFoQpqTFaFBEiABEiABEiABEiABEiABEiABEiABNwQoDDkhha3JQESIAESIAESIAESIAESIAESIAESIIEKIkBhqIIak1UhARIgARIgARIgARIgARIgARIgARIgATcEKAy5ocVtSYAESIAESIAESIAESIAESIAESIAESKCCCFAYqqDGZFVIgARIgARIgARIgARIgARIgARIgARIwA0BCkNuaHFbEiABEiABEiABEiABEiABEiABEiABEqggAhSGKqgxWRUSIAESIAESIAESIAESIAESIAESIAEScEOAwpAbWtyWBEiABEiABEiABEiABEiABEiABEiABCqIAIWhCmpMVoUESIAESIAESIAESIAESIAESIAESIAE3BCgMOSGFrclARIgARIgARIgARIgARIgARIgARIggQoiQGGoghqTVSEBEiABEiABEiABEiABEiABEiABEiABNwQoDLmhxW1JgARIgARIgARIgARIgARIgARIgARIoIIIUBiqoMZkVUiABEiABEiABEiABEiABEiABEiABEjADQEKQ25ocVsSIAESIAESIAESIAESIAESIAESIAESqCACFIYqqDFZFRIgARIgARIgARIgARIgARIgARIgARJwQ4DCkBta3JYESIAESIAESIAESIAESIAESIAESIAEKogAhaEKakxWhQRIgARIgARIgARIgARIgARIgARIgATcEKAw5IYWtyUBEiABEiABEiABEiABEiABEiABEiCBCiJAYaiCGpNVIQESIAESIAESIAESIAESIAESIAESIAE3BCgMuaHFbUmABEiABEiABEiABEiABEiABEiABEiggghQGKqgxmRVSIAESIAESIAESIAESIAESIAESIAESMANAQpDbmhxWxIgARIgARIgARIgARIgARIgARIgARKoIAIUhiqoMVkVEiABEiABEiABEiABEiABEiABEiABEnBDgMKQG1rclgRIgARIgARIgARIgARIgARIgARIgAQqiACFoQpqTFaFBEiABEiABEiABEiABEiABEiABEiABNwQoDDkhha3JQESIAESIAESIAESIAESIAESIAESIIEKIkBhqIIak1UhARIgARIgARIgARIgARIgARIgARIgATcEKAy5ocVtSYAESIAESIAESIAESIAESIAESIAESKCCCFAYqqDGZFVIgARIgARIgARIgARIgARIgARIgARIwA0BCkNuaHFbEiABEiABEiABEiABEiABEiABEiABEqggAhSGKqgxWRUSIAESIAESIAESIAESIAESIAESIAEScEOAwpAbWtyWBEiABEiABEiABEiABEiABEiABEiABCqIAIWhCmpMVoUESIAESIAESIAESIAESIAESIAESIAE3BCgMOSGFrclARIgARIgARIgARIgARIgARIgARIggQoiQGGoghqTVSEBEiABEiABEiABEiABEiABEiABEiABNwQoDLmhxW1JgARIgARIgARIgARIgARIgARIgARIoIIIUBiqoMZkVUiABEiABEiABEiABEiABEiABEiABEjADQEKQ25ocVsSIAESIAESIAESIAESIAESIAESIAESqCACFIYqqDFZFRIgARIgARIgARIgARIgARIgARIgARJwQ4DCkBta3JYESIAESIAESIAESIAESIAESIAESIAEKogAhaEKakxWhQRIgARIgARIgARIgARIgARIgARIgATcEKAw5IYWtyUBEiABEiABEiABEiABEiABEiABEiCBCiJAYaiCGpNVIQESIAESIAESIAESIAESIAESIAESIAE3BCgMuaHFbUmABEiABEiABEiABEiABEiABEiABEiggghQGKqgxmRVSIAESIAESIAESIAESIAESIAESIAESMANAQpDbmhxWxIgARIgARIgARIgARIgARIgARIgARKoIAIUhiqoMVkVEiABEiABEiABEiABEiABEiABEiABEnBDgMKQG1rclgRIgARIgARIgARIgARIgARIgARIgAQqiACFoQpqTFaFBEiABEiABEiABEiABEiABEiABEiABNwQoDDkhha3JQESIAESIAESIAESIAESIAESIAESIIEKIkBhqIIak1UhARIgARIgARIgARIgARIgARIgARIgATcEKAy5ocVtSYAESIAESIAESIAESIAESIAESIAESKCCCFAYqqDGZFVIgARIgARIgARIgARIgARIgARIgARIwA0BCkNuaHFbEiABEiABEiABEiABEiABEiABEiABEqggAtUVVJeyq8pSYFCm73wsgckbsjQ3ItV1TbLr0Bdl664nyq4uLDAJkAAJkAAJkAAJkAAJkAAJkAAJkED5EaAwVMI2W12clLnxT2R+6rbMTw9IdU2j9Nz3eAlLxEOTAAmQAAmQAAmQAAmQAAmQAAmQAAlsJgIUhkrZ2mtR8cmaNLR0SDQalEgoVMrS8NgkQAIkQAIkQAIkQAIkQAIkQAIkQAKbjACFoRI2eCS0LJHwsvir66SuoVVFoqUSloaHJgESIAESIAESIAESIAESIAESIAES2GwEGHy6hC2+JjHx+Xziq/Jbf6HVgKwuzRS0ROHVeQnrcZhIgARIgARIgARIgARIgARIgARIgARIgBZDSedAJLSowaAvy9LsLWntPiDtPUeStsjP19WlCQkuTUmVv1ZUFbKshtRkSJYXxiS4PCN1jZ35OVBCLqHVOY1ndFUWpwZUkKqXzh3HpGXLroQt+JEESIAESIAESIAESIAESIAESIAESGAzEaAwtN7a4eC8zgw2KAsz12Vh+pqsLoxr3J+wNLbtlNr69ryfE7FISNbWIpalkGicoZq6RqmpbZQVPS7EoUIIQzGtTyS8JIs6G9rc6G0ZuPBr2bbvKdl1+Helrqkj73VkhiRAAiRAAiRAAiRAAiRAAiRAAiRAAt4m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" - } - }, - "cell_type": "markdown", - "id": "325aa8a5-92fd-4913-a471-ad1617343be6", - "metadata": {}, - "source": [ - "# 303.3. Color Selections\n", - "\n", - "
\n", - "\n", - "![logo.png](attachment:697dbfa5-0793-4e9d-8401-2f3b86b0243c.png)\n", - "\n", - "
\n", - "\n", - "For the Rubin Science Platform at data.lsst.cloud.
\n", - "Data Release: Data Preview 1
\n", - "Container Size: large
\n", - "LSST Science Pipelines version: r29.2.0
\n", - "Last verified to run: 2025-09-02
\n", - "Repository: github.com/lsst/tutorial-notebooks
" - ] - }, - { - "cell_type": "markdown", - "id": "9da1a210-d858-42fe-8591-570965b8be1a", - "metadata": {}, - "source": [ - "**Learning objective:** Explore the available measurements of galaxy photometry produced by the LSST pipelines and their applications.\n", - "\n", - "**LSST data products:** `Object` table\n", - "\n", - "**Packages:** `lsst.rsp.get_tap_service `\n", - "\n", - "**Credit:**\n", - "This notebook benefitted from an earlier exploration of simulated data and notebook development by Melissa Graham and Dan Taranu, helpful discussions with Jim Bosch, and ideas from Douglas Tucker. \n", - "\n", - "**Get Support:**\n", - "Everyone is encouraged to ask questions or raise issues in the \n", - "Support Category \n", - "of the Rubin Community Forum.\n", - "Rubin staff will respond to all questions posted there." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "cfc73be0", - "metadata": {}, - "source": [ - "## 1. Introduction \n", - "\n", - "Photometry is the measurement of how much light is apparent from astronomical sources. The amount of light arriving on the telescope from the object is typically referred to as the flux density, or apparent magnitude (depending on units). Flux density is defined as the amount of energy arriving on the telescope per unit area, per unit time, per unit frequency (or wavelength) of the light.\n", - "\n", - "The LSST Science Pipelines makes a variety of photometric measurements for point-like and extended sources. This notebook will teach the user about the automated photometry measurements for extended sources that are measured on the deepCoadd images and appear in the Object Catalog as part of the LSST pipelines data products.\n", - "\n", - "The photometry measurements in the catalogs are flux densities in units of nano-Jansky [nJy]. 1 Jy = 10^{-23} ergs/s/cm^2/Hz." - ] - }, - { - "cell_type": "markdown", - "id": "dc36f107", - "metadata": {}, - "source": [ - "### 1.1. Import packages\n", - "\n", - "Import `numpy`, a fundamental package for scientific computing with arrays in Python\n", - "(numpy.org), and\n", - "`matplotlib`, a comprehensive library for data visualization\n", - "(matplotlib.org; \n", - "matplotlib gallery).\n", - "\n", - "From the `lsst` package, import modules for accessing the Table Access Protocol (TAP) service,\n", - "the butler, and image display functions from the LSST Science Pipelines (pipelines.lsst.io)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cddc1458", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from lsst.rsp import get_tap_service\n", - "\n", - "from scipy.stats import binned_statistic" - ] - }, - { - "cell_type": "markdown", - "id": "c217adff-25ed-4fce-95e7-8aa04630f6cc", - "metadata": {}, - "source": [ - "### 1.2. Define parameters and functions" - ] - }, - { - "cell_type": "markdown", - "id": "d3383f6e-8c34-4cb7-aa2f-12e9b7f8efc0", - "metadata": {}, - "source": [ - "Get an instance of the TAP service, and assert that it exists." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e8184089-8a3e-4666-a194-5362a8faa541", - "metadata": {}, - "outputs": [], - "source": [ - "service = get_tap_service(\"tap\")\n", - "assert service is not None" - ] - }, - { - "cell_type": "markdown", - "id": "557bbb99-3a37-4b15-ad6d-e86c6282866c", - "metadata": {}, - "source": [ - "## 2. Types of photometry\n", - "\n", - "This section will explore photometry measurements produced by the LSST pipelines, and provide some guidance for which are optimal for various applications for science with galaxies. \n", - "### 2.1. Explore the schema\n", - "\n", - "Numerous photometry measurements are produced by the LSST Pipelines. Two types of photometry are in the object table. The first are total fluxes (see Section 3), which aim to approximate (or model) all of the light coming from object. The second class of fluxes are measured inside an on-sky aperture but not corrected for flux that may fall outside: thus they are apparent fluxes but do not recover the intrisic (total) flux (see Section 4 and 5). The apparent fluxes are optimized for other purposes, such as for measuring accurate light profiles or accurate colors. \n", - "\n", - "Schema for the object catalog for DP1 is available here. It lists the catalog header and brief explanation of the parameters.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "id": "1513ee4c-0a00-4868-8525-53aaccfff9b1", - "metadata": {}, - "source": [ - "First, see what is available in the object table by querying the `tap_schema` columns, and printing all the parameters available related to \"Flux\" measured in the i-band (as an example). For clarity, the return also omits errors and flags associated with the photometric measurements outlined in section 1.1. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3d532f5a-52ad-408d-bce6-a5a4d346477f", - "metadata": {}, - "outputs": [], - "source": [ - "query = \"SELECT column_name, datatype, description, unit \" \\\n", - " \"FROM tap_schema.columns \" \\\n", - " \"WHERE table_name = 'dp1.Object'\"\n", - "\n", - "results = service.search(query).to_table()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "84849d6b-527d-4ac7-9cbb-09df352f7b34", - "metadata": {}, - "outputs": [], - "source": [ - "search_string = 'Flux'\n", - "band = 'i_'\n", - "exclude1 = 'Err'\n", - "exclude2 = 'flag'\n", - "for cname in results['column_name']:\n", - " if cname.find(search_string) > -1 and cname.find(band) > -1 and \\\n", - " cname.find(exclude1) == -1 and cname.find(exclude2) == -1:\n", - "\n", - " print(cname)" - ] - }, - { - "cell_type": "markdown", - "id": "5dd9c7cb-8ab0-4f7c-9161-69fa29d46537", - "metadata": {}, - "source": [ - "The object catalog also has pre-computed AB magnitudes (`Mag` columns) for cModel and PSF. Query the `tap_schema` columns, and print all the parameters available related to `Mag` measured in the i-band. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6225c1c4-e324-4846-b49b-06471a4abe59", - "metadata": {}, - "outputs": [], - "source": [ - "search_string = 'Mag'\n", - "band = 'i_'\n", - "exclude1 = 'Err'\n", - "for cname in results['column_name']:\n", - " if cname.find(search_string) > -1 and cname.find(band) > -1 and \\\n", - " cname.find(exclude1) == -1:\n", - "\n", - " print(cname)" - ] - }, - { - "cell_type": "markdown", - "id": "ac0528ca-2ec6-405e-b4ea-e897ef96de67", - "metadata": {}, - "source": [ - "\n", - "### 2.2. Select a galaxy sample\n", - "\n", - "Below, query the DP1 `objectTable` for a selection of photometric measurements. \n", - "\n", - "Limit the search to contain galaxies using the `i_extendedness` flag (which will exclude point sources). Further, identify objects which have been detected at high signal to noise > 20 and whose photometric measurements have not been flagged as having an issue (`i_kronFlux_flag` or `i_cModel_flag` or `sersic_no_data_flag` = 0 means the photometry is ok). Also exclude very bright galaxies (i-band magnitude < 20).\n", - "\n", - "Search for the sample using the DP1 imaging obtained in the Extended Chandra Deep Field South (ECDFS; center ra, dec = 53.2, -28.1 in degrees) which was one of the deepest imaging obtained as part of DP1.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "73dd5a5f-b761-4d4f-96b6-5767cffbb310", - "metadata": {}, - "outputs": [], - "source": [ - "target_ra = 53.2\n", - "target_dec = -28.1" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "75150971-e118-48d5-9db7-74c0fe600762", - "metadata": {}, - "outputs": [], - "source": [ - "query = \"SELECT obj.objectId, obj.coord_ra, obj.coord_dec, \" + \\\n", - " \"obj.detect_fromBlend, obj.detect_isIsolated, \" + \\\n", - " \"obj.i_blendedness, obj.i_extendedness, \" + \\\n", - " \"obj.u_sersicFlux, obj.u_sersicFluxErr, obj.u_gaap1p0Flux, \" + \\\n", - " \"obj.g_sersicFlux, obj.g_sersicFluxErr, obj.g_gaap1p0Flux, \" + \\\n", - " \"obj.r_sersicFlux, obj.r_sersicFluxErr, obj.r_gaap1p0Flux, \" + \\\n", - " \"obj.i_sersicFlux, obj.i_sersicFluxErr, obj.i_gaap1p0Flux, \" + \\\n", - " \"obj.u_cModelMag, obj.u_cModelMagErr, \" + \\\n", - " \"obj.g_cModelMag, obj.g_cModelMagErr, \" + \\\n", - " \"obj.r_cModelMag, obj.r_cModelMagErr, \" + \\\n", - " \"obj.i_cModelMag, obj.i_cModelMagErr, \" + \\\n", - " \"obj.u_cModelFlux, obj.u_cModelFluxErr, \" + \\\n", - " \"obj.g_cModelFlux, obj.g_cModelFluxErr, \" + \\\n", - " \"obj.r_cModelFlux, obj.r_cModelFluxErr, \" + \\\n", - " \"obj.i_cModelFlux, obj.i_cModelFluxErr, \" + \\\n", - " \"obj.i_kronFlux_flag, obj.i_cModel_flag, obj.sersic_no_data_flag \" + \\\n", - " \"FROM dp1.Object AS obj \" + \\\n", - " \"WHERE (obj.i_sersicFlux/obj.i_sersicFluxErr > 10) AND \" + \\\n", - " \"(obj.i_extendedness = 1) AND (obj.sersic_no_data_flag = 0) AND \" + \\\n", - " \"(obj.i_cModel_flag = 0) AND \" + \\\n", - " \"(scisql_nanojanskyToAbMag(obj.i_sersicFlux) > 20) AND \" + \\\n", - " \"CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), \" + \\\n", - " \"CIRCLE('ICRS',\"+str(target_ra)+\",\"+str(target_dec)+\", 0.5)) = 1 \"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "867871f3-d378-4cc5-88df-d91cfb01e259", - "metadata": {}, - "outputs": [], - "source": [ - "job = service.submit_job(query)\n", - "job.run()\n", - "job.wait(phases=['COMPLETED', 'ERROR'])\n", - "print('Job phase is', job.phase)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5b6cd0ba-132a-4552-b389-32e54d8591dc", - "metadata": {}, - "outputs": [], - "source": [ - "if job.phase == 'ERROR':\n", - " job.raise_if_error()\n", - "assert job.phase == 'COMPLETED'" - ] - }, - { - "cell_type": "markdown", - "id": "f38080f1-9a2d-48af-834d-1b49de86944f", - "metadata": {}, - "source": [ - "Print the results of the search query." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7e4a20e0-101d-4644-90e1-b0bd1058aae1", - "metadata": {}, - "outputs": [], - "source": [ - "results = job.fetch_result()\n", - "tab = results.to_table()\n", - "tab" - ] - }, - { - "cell_type": "markdown", - "id": "c9c94c7d-8635-4bbd-83e6-3eb64aea2b24", - "metadata": {}, - "source": [ - "Below, convert the fluxes (units $nJy$) extracted from the `objectTable` into AB magnitudes using: $m_{AB} = -2.5log( f_{nJy}) + 31.4$ (see e.g. AB Magnitudes Wikipedia page for the conversion between flux in Jy and AB magnitudes).\n", - "\n", - "> **Warning:** The following cell will produce warnings for invalid value encountered in log10, which happens if the source flux is negative. This occasionally happens from aperture photometry if the included pixels inside the aperture have negative values and can be safely ignored for this example. The log10 will return a NaN which can be filtered out later." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d58eacea-4573-433b-b9b1-382a24087dd1", - "metadata": {}, - "outputs": [], - "source": [ - "# old, does not re-set the flux to the upper limit when necessary\n", - "#cmodel_mag = -2.50 * np.log10(tab['i_cModelFlux']) + 31.4\n", - "#sersic_mag = -2.50 * np.log10(tab['i_sersicFlux']) + 31.4\n", - "#gaap_mag = -2.50 * np.log10(tab['i_gaap1p0Flux']) + 31.4\n", - "\n", - "# List of the filters you queried\n", - "#filters = ['u', 'g', 'r', 'i']\n", - "\n", - "# Temporarily ignore warnings for taking the log of negative/zero fluxes\n", - "#with np.errstate(divide='ignore', invalid='ignore'):\n", - "# for f in filters:\n", - " # 1. Convert Sersic Fluxes to AB Magnitudes\n", - " #tab[f'{f}_sersic_mag'] = -2.50 * np.log10(tab[f'{f}_sersicFlux']) + 31.4\n", - " \n", - " # 2. Convert GAAP Fluxes to AB Magnitudes\n", - " #tab[f'{f}_gaap_mag'] = -2.50 * np.log10(tab[f'{f}_gaap1p0Flux']) + 31.4\n", - " \n", - " # 3. Convert Sersic Flux Errors to Magnitude Errors\n", - " # The standard propagation of error formula for magnitudes is: \n", - " # mag_err = (2.5 / ln(10)) * (flux_err / flux)\n", - " #tab[f'{f}_sersic_magErr'] = 1.0857 * (tab[f'{f}_sersicFluxErr'] / tab[f'{f}_sersicFlux'])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cdbbbc80-38e5-4ae9-bb84-6902828b13f5", - "metadata": {}, - "outputs": [], - "source": [ - "# this should be better\n", - "# List of the filters you queried\n", - "filters = ['u', 'g', 'r', 'i']\n", - "\n", - "# Use a zeropoint of 31.4 as per your specific dataset configuration\n", - "zp = 31.4\n", - "\n", - "# Temporarily ignore warnings for taking the log of negative/zero fluxes\n", - "with np.errstate(divide='ignore', invalid='ignore'):\n", - " for f in filters:\n", - " # 1. Apply Flux-Limit Logic: \n", - " # If flux is less than the error (S/N < 1), we replace it with the error \n", - " # value to calculate a 'Lower Limit' on the magnitude.\n", - " sersic_flux_robust = np.where(tab[f'{f}_sersicFlux'] < tab[f'{f}_sersicFluxErr'], \n", - " tab[f'{f}_sersicFluxErr'], \n", - " tab[f'{f}_sersicFlux'])\n", - " \n", - " #gaap_flux_robust = np.where(tab[f'{f}_gaap1p0Flux'] < tab[f'{f}_gaap1p0FluxErr'], \n", - " # tab[f'{f}_gaap1p0FluxErr'], \n", - " # tab[f'{f}_gaap1p0Flux'])\n", - "\n", - " # 2. Convert Robust Fluxes to AB Magnitudes\n", - " tab[f'{f}_sersic_mag'] = -2.50 * np.log10(sersic_flux_robust) + zp\n", - " #tab[f'{f}_gaap_mag'] = -2.50 * np.log10(gaap_flux_robust) + zp\n", - " \n", - " # 3. Convert Sersic Flux Errors to Magnitude Errors\n", - " # We use the original flux here to represent measurement uncertainty accurately\n", - " tab[f'{f}_sersic_magErr'] = 1.0857 * (tab[f'{f}_sersicFluxErr'] / tab[f'{f}_sersicFlux'])" - ] - }, - { - "cell_type": "markdown", - "id": "8d2de168-5282-4a26-8740-930ce13e362b", - "metadata": {}, - "source": [ - "### do Lyman break selection" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "09d09866-9c0d-434b-844b-076cf34f93df", - "metadata": {}, - "outputs": [], - "source": [ - "# 1. Calculate the colors using the Sersic magnitudes you generated\n", - "# We wrap this in a mask to drop NaNs so matplotlib doesn't complain\n", - "valid_mask = np.isfinite(tab['g_sersic_mag']) & \\\n", - " np.isfinite(tab['r_sersic_mag']) & \\\n", - " np.isfinite(tab['i_sersic_mag'])\n", - "\n", - "#u_mag = tab['u_sersic_mag'][valid_mask]\n", - "g_mag = tab['g_sersic_mag'][valid_mask]\n", - "r_mag = tab['r_sersic_mag'][valid_mask]\n", - "i_mag = tab['i_sersic_mag'][valid_mask]\n", - "\n", - "g_minus_r = g_mag - r_mag\n", - "r_minus_i = r_mag - i_mag\n", - "\n", - "# 2. Define the z~4 LBG (g-dropout) selection criteria\n", - "# These are standard photometric cuts to isolate z~4 galaxies and exclude red dwarf stars\n", - "#is_z4_lbg = (\n", - "# (g_minus_r > 1.0) & \n", - "# (r_minus_i < 1.0) & \n", - "# (g_minus_r > 1.5 * r_minus_i + 0.8)\n", - "#)\n", - "\n", - "# 2. Define the STRICT z~4 LBG selection criteria (Purity over Completeness)\n", - "is_z4_lbg = (\n", - " (g_minus_r > 1.5) & (tab['u_sersicFlux']/tab['u_sersicFluxErr'] < 3) & \n", - " (r_minus_i < 1.0) & #(r_minus_i > 0) & \n", - " (g_minus_r > 1.5 * r_minus_i + 0.8)\n", - ")\n", - "\n", - "# 3. Create the Color-Color Diagram\n", - "fig, ax = plt.subplots(figsize=(8, 6))\n", - "\n", - "# Plot the background distribution of all objects (gray)\n", - "ax.scatter(r_minus_i, g_minus_r, s=5, color='gray', alpha=0.3, label='All Objects')\n", - "\n", - "# Highlight the selected z~4 LBGs (blue)\n", - "ax.scatter(r_minus_i[is_z4_lbg], g_minus_r[is_z4_lbg], \n", - " s=20, color='blue', alpha=0.8, edgecolor='white', linewidth=0.5, label='z~4 LBGs')\n", - "\n", - "# 4. Draw the Selection Boundaries for visual reference\n", - "# Calculate the vertices of the selection region\n", - "x_diag = np.linspace(0.133, 1.0, 50)\n", - "y_diag = 1.5 * x_diag + 0.8\n", - "\n", - "# Plot the bounding lines\n", - "#ax.plot([-1.5, 0.133], [1.0, 1.0], color='red', linestyle='--', lw=2, label='Selection Boundary') # Bottom horizontal cut\n", - "#ax.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut to avoid M-stars\n", - "#ax.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2)\n", - "\n", - "# Plot the updated bounding lines\n", - "# 4. Draw the NEW Selection Boundaries\n", - "# Calculate the new intersection between the horizontal and diagonal lines\n", - "intersect_x = (1.5 - 0.8) / 1.5\n", - "ax.plot([-1.5, intersect_x], [1.5, 1.5], color='red', linestyle='--', lw=2, label='Selection Boundary') # Raised horizontal cut\n", - "ax.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut\n", - "ax.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2) # Right vertical cut\n", - "\n", - "# 5. Formatting\n", - "ax.set_xlim(-1.5, 2.0)\n", - "ax.set_ylim(-1.0, 4.0)\n", - "\n", - "ax.set_xlabel(r'(r−i) [AB Mag]', fontsize=14)\n", - "ax.set_ylabel(r'(g−r) [AB Mag]', fontsize=14)\n", - "ax.set_title(r'z∼4 Lyman-Break Galaxy Selection (g-dropouts)', fontsize=16, fontweight='bold')\n", - "\n", - "ax.grid(True, linestyle=':', alpha=0.6)\n", - "ax.legend(loc='upper left', fontsize=12)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# Print out the results\n", - "print(f\"Total objects plotted: {len(g_mag)}\")\n", - "print(f\"Identified z~4 candidates: {np.sum(is_z4_lbg)}\")" - ] - }, - { - "cell_type": "markdown", - "id": "29ae8710-01c3-44bb-8edc-64de3738857a", - "metadata": {}, - "source": [ - "## Sanity checks: plot cutouts and SEDs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "81ade6bd-3b62-472b-a0b6-48656837bd22", - "metadata": {}, - "outputs": [], - "source": [ - "import io\n", - "import numpy as np\n", - "import astropy.units as u\n", - "from astropy.io import fits\n", - "import matplotlib.pyplot as plt\n", - "\n", - "from pyvo.dal.adhoc import SodaQuery, DatalinkResults \n", - "from astropy.visualization import ZScaleInterval, LinearStretch, ImageNormalize\n", - "\n", - "from lsst.rsp import get_tap_service\n", - "from lsst.rsp.utils import get_pyvo_auth # <-- ADDED: The RSP auth utility\n", - "\n", - "# Initialize the TAP service AND the auth session\n", - "tap_service = get_tap_service(\"tap\")\n", - "session = get_pyvo_auth() # <-- ADDED: Define the session variable\n", - "\n", - "# Extract the coordinates of the high-purity candidates\n", - "cands_ra = tab['coord_ra'][valid_mask][is_z4_lbg]\n", - "cands_dec = tab['coord_dec'][valid_mask][is_z4_lbg]\n", - "\n", - "# Limit to the first 5 candidates so we don't spam the SODA service\n", - "n_plot = min(len(cands_ra), 5)\n", - "filters = ['u', 'g', 'r', 'i']\n", - "\n", - "# Set up the Matplotlib Grid & define Field of View\n", - "fig, axes = plt.subplots(n_plot, len(filters), figsize=(10, 2.5 * n_plot))\n", - "norm = ImageNormalize(stretch=LinearStretch(), interval=ZScaleInterval())\n", - "fov = 10.0 / 3600.0 # 10 arcseconds in degrees\n", - "\n", - "print(f\"Requesting DP1 SODA cutouts via TAP for {n_plot} candidates...\")\n", - "\n", - "for row_idx in range(n_plot):\n", - " ra = cands_ra[row_idx]\n", - " dec = cands_dec[row_idx]\n", - " \n", - " # Query the ivoa.ObsCore table using the image footprint (s_region)\n", - " query = f\"\"\"\n", - " SELECT lsst_band, access_url \n", - " FROM ivoa.ObsCore \n", - " WHERE dataproduct_subtype = 'lsst.deep_coadd' \n", - " AND obs_collection = 'LSST.DP1'\n", - " AND CONTAINS(POINT('ICRS', {ra}, {dec}), s_region) = 1\n", - " \"\"\"\n", - " \n", - " # Run the query synchronously\n", - " tap_job = tap_service.run_sync(query)\n", - " coadds = tap_job.to_table()\n", - " \n", - " for col_idx, f in enumerate(filters):\n", - " ax = axes[row_idx, col_idx] if n_plot > 1 else axes[col_idx]\n", - " \n", - " # Match the specific filter\n", - " band_match = coadds[coadds['lsst_band'] == f]\n", - " \n", - " if len(band_match) > 0:\n", - " try:\n", - " datalink_url = band_match['access_url'][0]\n", - " \n", - " # We now pass the active session to the Datalink & SODA tools\n", - " dl_result = DatalinkResults.from_result_url(datalink_url, session=session)\n", - " \n", - " # Execute the Synchronous SODA Cutout\n", - " sq = SodaQuery.from_resource(dl_result,\n", - " dl_result.get_adhocservice_by_id(\"cutout-sync\"),\n", - " session=session)\n", - " sq.circle = (ra * u.deg, dec * u.deg, fov * u.deg)\n", - " \n", - " cutout_bytes = sq.execute_stream().read()\n", - " sq.raise_if_error()\n", - " \n", - " # Open the byte stream into an Astropy FITS object\n", - " hdul = fits.open(io.BytesIO(cutout_bytes))\n", - " \n", - " # HDU 1 contains the actual science 'image' array\n", - " img_array = hdul[1].data\n", - " \n", - " # Plot the array\n", - " ax.imshow(img_array, origin='lower', cmap='gray', norm=norm)\n", - " \n", - " # SODA automatically centers the cutout on the requested RA/Dec\n", - " center_y, center_x = img_array.shape[0] // 2, img_array.shape[1] // 2\n", - " circle = plt.Circle((center_x, center_y), radius=5, color='red', fill=False, lw=1, alpha=0.5)\n", - " ax.add_patch(circle)\n", - "\n", - " except Exception as e:\n", - " print(f\"Error on Cand {row_idx+1} {f}-band: {e}\")\n", - " ax.text(0.5, 0.5, 'SODA Error', ha='center', va='center', transform=ax.transAxes, color='red')\n", - " else:\n", - " ax.text(0.5, 0.5, 'No Coverage', ha='center', va='center', transform=ax.transAxes, color='red')\n", - " \n", - " # Formatting\n", - " ax.set_xticks([])\n", - " ax.set_yticks([])\n", - " \n", - " if row_idx == 0:\n", - " ax.set_title(f\"{f}-band\", fontsize=16, fontweight='bold')\n", - " if col_idx == 0:\n", - " ax.set_ylabel(f\"Cand {row_idx+1}\\nRA: {ra:.3f}\", fontsize=12, rotation=0, labelpad=40, ha='center')\n", - "\n", - "plt.subplots_adjust(wspace=0.05, hspace=0.05)\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0e5fd667-471d-46e0-96d1-cba433de8ead", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "# 1. Identify the best candidate (the one with the reddest g-r color)\n", - "high_purity_ids = tab['objectId'][valid_mask][is_z4_lbg]\n", - "#best_candidate_id = high_purity_ids[np.argmax(g_minus_r[is_z4_lbg])]\n", - "best_candidate_id = high_purity_ids[0]#np.argmax(g_minus_r[is_z4_lbg])]\n", - "\n", - "# 2. Query all 6 bands using forced cModelFlux for accurate multi-band colors\n", - "sed_query = f\"\"\"\n", - "SELECT \n", - " u_cModelFlux, g_cModelFlux, r_cModelFlux, \n", - " i_cModelFlux, z_cModelFlux, y_cModelFlux,\n", - " u_cModelFluxErr, g_cModelFluxErr, r_cModelFluxErr, \n", - " i_cModelFluxErr, z_cModelFluxErr, y_cModelFluxErr\n", - "FROM dp1.Object \n", - "WHERE objectId = {best_candidate_id}\n", - "\"\"\"\n", - "\n", - "sed_job = tap_service.run_sync(sed_query)\n", - "sed_data = sed_job.to_table()[0] # Isolate the single row\n", - "\n", - "# 3. Define the filters and their effective wavelengths in Angstroms\n", - "filters = ['u', 'g', 'r', 'i', 'z', 'y']\n", - "wavelengths = [3671, 4826, 6223, 7545, 8691, 9710]\n", - "\n", - "mags = []\n", - "mag_errs = []\n", - "fluxes = []\n", - "flux_errs = []\n", - "\n", - "# Convert to AB Magnitudes\n", - "with np.errstate(divide='ignore', invalid='ignore'):\n", - " for f in filters:\n", - " flux = sed_data[f'{f}_cModelFlux']\n", - " flux_err = sed_data[f'{f}_cModelFluxErr']\n", - "\n", - " fluxes.append(flux)\n", - " flux_errs.append(flux_err)\n", - " \n", - " mag = -2.50 * np.log10(flux) + 31.4\n", - " mag_err = 1.0857 * (flux_err / flux)\n", - " \n", - " mags.append(mag)\n", - " mag_errs.append(mag_err)\n", - " \n", - "# 4. Plot the SED\n", - "fig, ax = plt.subplots(figsize=(8, 5))\n", - "\n", - "# Plot the data (invert y-axis because lower magnitude = brighter!)\n", - "ax.errorbar(wavelengths, fluxes, yerr=flux_errs, fmt='o-', color='black', \n", - " markersize=8, capsize=4, linewidth=2)\n", - "#ax.invert_yaxis() # for mags only\n", - "\n", - "# Highlight the region absorbed by the Lyman Break\n", - "ax.axvspan(3000, 4826, color='lightblue', alpha=0.3, label='Absorbed by Neutral Hydrogen')\n", - "\n", - "# Formatting\n", - "ax.set_xticks(wavelengths)\n", - "ax.set_xticklabels(filters, fontsize=12)\n", - "ax.set_xlabel('Filter Band', fontsize=14)\n", - "ax.set_ylabel('Flux [nJy]', fontsize=14)\n", - "ax.set_title(f'Spectral Energy Distribution (Candidate ID: {best_candidate_id})', fontsize=16, fontweight='bold')\n", - "\n", - "ax.grid(True, linestyle=':', alpha=0.6)\n", - "ax.legend(loc='upper right')\n", - "\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "4c51bd19-e47d-4808-b334-3349d94a0924", - "metadata": {}, - "source": [ - "## Sanity check matching to Rubin photo-z catalogs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1c015634-0235-4329-92de-dcaf17954e3a", - "metadata": {}, - "outputs": [], - "source": [ - "import lsdb\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "print(\"Loading DP1 Photo-z LSDB catalog...\")\n", - "\n", - "# 1. Open the LSDB photo-z catalog from the RSP shared file system\n", - "pz_cat = lsdb.open_catalog(\"/rubin/lsdb_data/object_photoz\")\n", - "\n", - "# 2. Filter the catalog for our specific candidate IDs\n", - "# LSDB uses Dask under the hood for distributed computing. We access the Dask \n", - "# DataFrame (._ddf) to filter for our candidate IDs, then compute the result into a Pandas DataFrame.\n", - "pz_dask = pz_cat._ddf\n", - "matched_df = pz_dask[pz_dask['objectId'].isin(high_purity_ids)].compute()\n", - "\n", - "# Extract the redshift column. \n", - "# Note: Depending on the specific algorithm used for this DP1 release, the column \n", - "# might be named 'z_phot', 'z_mode', or 'photoZ'. If 'z_phot' throws a KeyError, \n", - "# you can use print(matched_df.columns) to check the correct name!\n", - "valid_pz = matched_df['bpz_z_mean'].dropna().values\n", - "\n", - "# 3. Plot the Histogram\n", - "fig, ax = plt.subplots(figsize=(8, 5))\n", - "\n", - "if len(valid_pz) > 0:\n", - " ax.hist(valid_pz, bins=15, color='rebeccapurple', alpha=0.8, edgecolor='white')\n", - "\n", - "# Draw a vertical line exactly at z=4 to show the target redshift\n", - "ax.axvline(4.0, color='red', linestyle='--', linewidth=2, label='Target Redshift (z=4)')\n", - "\n", - "# Formatting\n", - "ax.set_xlabel(r'Photometric Redshift (zphot)', fontsize=14)\n", - "ax.set_ylabel('Number of Galaxies', fontsize=14)\n", - "ax.set_title('Photo-z Distribution of High-Purity g-dropouts', fontsize=16, fontweight='bold')\n", - "\n", - "ax.legend()\n", - "ax.grid(True, linestyle=':', alpha=0.6)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# Print the confirmation statistics\n", - "print(f\"Total candidates cross-matched: {len(valid_pz)}\")\n", - "if len(valid_pz) > 0:\n", - " print(f\"Median Photo-z of sample: {np.median(valid_pz):.2f}\")" - ] - }, - { - "cell_type": "markdown", - "id": "595f2e93-1577-4ba7-8023-877d25a24a51", - "metadata": {}, - "source": [ - "## some failed attempts to retrieve VANDELS catalogs and spec-z columns\n", - "to clean up" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "14646c0e-76fd-4d28-82cb-ffdbf3dc4f9a", - "metadata": {}, - "outputs": [], - "source": [ - "# dont delete, it displays the column names\n", - "\n", - "from astroquery.vizier import Vizier\n", - "import astropy.units as u\n", - "from astropy.coordinates import SkyCoord\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "# 1. Initialize Vizier - fetch EVERYTHING associated with the VANDELS ID\n", - "v = Vizier(columns=['**'], catalog=\"J/A+A/647/A150\")\n", - "v.ROW_LIMIT = -1\n", - "\n", - "print(\"Analyzing VANDELS Catalog Structure...\")\n", - "\n", - "try:\n", - " all_tables = v.get_catalogs(\"J/A+A/647/A150\")\n", - " \n", - " vandels_data = None\n", - " z_col_name = None\n", - " flag_col_name = None\n", - "\n", - " # 2. Iterate through all tables to find the spectroscopic data\n", - " for i, table in enumerate(all_tables):\n", - " cols = table.colnames\n", - " print(f\"\\nTable {i}: {table.meta.get('name', 'Unknown')}\")\n", - " print(f\"Columns: {cols[:10]}... ({len(cols)} total columns)\")\n", - " \n", - " # Look for the redshift column (case-insensitive)\n", - " # We look for 'z' followed by 'spec', 'mode', or just 'z'\n", - " for c in cols:\n", - " c_low = c.lower()\n", - " if c_low in ['zspec', 'z', 'z_spec', 'specz', 'z_mode']:\n", - " z_col_name = c\n", - " vandels_data = table\n", - " print(f\"--> Found Redshift Column: '{z_col_name}' in Table {i}\")\n", - " \n", - " # Now find the quality flag in the SAME table\n", - " for f in cols:\n", - " f_low = f.lower()\n", - " if f_low in ['zflg', 'f_zspec', 'q', 'qual', 'zflag']:\n", - " flag_col_name = f\n", - " print(f\"--> Found Quality Flag: '{flag_col_name}'\")\n", - " break\n", - " break\n", - " if vandels_data: break\n", - "\n", - " if vandels_data is None:\n", - " print(\"\\n[!] Error: No redshift column found. Printing all table summaries for debugging:\")\n", - " for i, t in enumerate(all_tables):\n", - " print(f\"Table {i} has columns: {t.colnames}\")\n", - " raise ValueError(\"Column discovery failed.\")\n", - "\n", - " # 3. Filter and Match (Standard workflow)\n", - " # We use a broad mask first to ensure we have data\n", - " mask = (vandels_data[z_col_name] >= 3.5) & (vandels_data[z_col_name] <= 4.5)\n", - " \n", - " # Only apply flag if we found one\n", - " if flag_col_name:\n", - " mask &= (vandels_data[flag_col_name] >= 3)\n", - " \n", - " vandels_z4 = vandels_data[mask]\n", - " print(f\"\\nFiltering complete. Found {len(vandels_z4)} high-quality z~4 candidates.\")\n", - "\n", - " # Cross-match using coordinates found in the same table\n", - " # VizieR usually uses RAJ2000/DEJ2000 or _RAJ2000/_DEJ2000\n", - " ra_col = 'RAJ2000' if 'RAJ2000' in vandels_z4.colnames else '_RAJ2000'\n", - " dec_col = 'DEJ2000' if 'DEJ2000' in vandels_z4.colnames else '_DEJ2000'\n", - "\n", - " v_coords = SkyCoord(ra=vandels_z4[ra_col], dec=vandels_z4[dec_col], unit='deg')\n", - " r_coords = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", - " #r_coords = SkyCoord(ra=cands_ra, dec=cands_dec, unit='deg')\n", - "\n", - " idx, d2d, _ = v_coords.match_to_catalog_sky(r_coords)\n", - " matches = d2d < 1.5 * u.arcsec # Slightly wider match for different astrometric systems\n", - " matched_idx = idx[matches]\n", - " \n", - " print(f\"Successfully matched {len(matched_idx)} galaxies to Rubin sample.\")\n", - "\n", - " # 4. Final Plot\n", - " ri_match = tab['r_sersic_mag'][matched_idx] - tab['i_sersic_mag'][matched_idx]\n", - " gr_match = tab['g_sersic_mag'][matched_idx] - tab['r_sersic_mag'][matched_idx]\n", - "\n", - " plt.figure(figsize=(8, 6))\n", - " plt.scatter(tab['r_sersic_mag'] - tab['i_sersic_mag'], \n", - " tab['g_sersic_mag'] - tab['r_sersic_mag'], \n", - " s=1, color='gray', alpha=0.2, label='Parent Sample')\n", - " plt.scatter(ri_match, gr_match, color='gold', marker='*', s=150, edgecolor='k', label='VANDELS Confirmed')\n", - " plt.axhline(1.5, color='blue', ls='--', label='Your Strict Cut')\n", - " plt.xlabel('r - i')\n", - " plt.ylabel('g - r')\n", - " plt.legend()\n", - " plt.show()\n", - "\n", - "except Exception as e:\n", - " print(f\"\\nDiscovery Failed: {e}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6b46074c-d680-4a2c-8324-5b6fbcbbaa23", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "from astropy.coordinates import SkyCoord\n", - "import astropy.units as u\n", - "\n", - "# 1. Select Table 0 (CDFS) and extract the confirmed high-z sample\n", - "vandels_data = all_tables[0]\n", - "\n", - "# Filter for spectroscopic redshift between 3.5 and 4.5\n", - "# We use q_zsp >= 3 (standard for high-confidence VANDELS spectra)\n", - "mask = (vandels_data['zsp'] >= 3.5) & (vandels_data['zsp'] <= 4.5) & (vandels_data['q_zsp'] >= 3)\n", - "vandels_z4 = vandels_data[mask]\n", - "\n", - "print(f\"Found {len(vandels_z4)} high-confidence VANDELS spectra in CDFS at z~4.\")\n", - "\n", - "# 2. Perform the spatial cross-match\n", - "v_coords = SkyCoord(ra=vandels_z4['RAJ2000'], dec=vandels_z4['DEJ2000'], unit='deg')\n", - "r_coords = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", - "\n", - "idx, d2d, _ = v_coords.match_to_catalog_sky(r_coords)\n", - "\n", - "# 1.0 arcsecond is usually safe for Rubin vs VLT astrometry\n", - "matches = d2d < 1.0 * u.arcsec\n", - "matched_idx = idx[matches]\n", - "\n", - "print(f\"Successfully matched {len(matched_idx)} of those to your Rubin Object table.\")\n", - "\n", - "# 3. Calculate colors for the matched objects\n", - "# Assuming 'tab' has the sersic_mags we defined earlier\n", - "ri_match = tab['r_sersic_mag'][matched_idx] - tab['i_sersic_mag'][matched_idx]\n", - "gr_match = tab['g_sersic_mag'][matched_idx] - tab['r_sersic_mag'][matched_idx]\n", - "s2n_match = tab['i_sersicFlux'][matched_idx] / tab['i_sersicFluxErr'][matched_idx]\n", - "\n", - "# 4. Plotting\n", - "plt.figure(figsize=(9, 7))\n", - "\n", - "# Background: All Rubin objects in your field\n", - "plt.scatter(tab['r_sersic_mag'] - tab['i_sersic_mag'], \n", - " tab['g_sersic_mag'] - tab['r_sersic_mag'], \n", - " s=2, color='gray', alpha=0.15, label='Rubin Parent Sample')\n", - "\n", - "# Foreground: The spectroscopic \"Truth\"\n", - "plt.scatter(ri_match, gr_match, color='gold', marker='*', s=150, \n", - " edgecolor='black', linewidth=0.8, zorder=5, label='Confirmed VANDELS z~4')\n", - "\n", - "# Draw your selection boundaries\n", - "plt.axhline(1.5, color='blue', linestyle='--', lw=2, label='Strict Selection (g-r > 1.5)')\n", - "plt.axhline(1.0, color='red', linestyle=':', lw=1.5, label='Standard Selection (g-r > 1.0)')\n", - "\n", - "# Box boundaries (approximating the dropout region)\n", - "plt.vlines(1.0, 1.0, 4.0, color='black', alpha=0.3) \n", - "\n", - "plt.xlim(-0.5, 1.5)\n", - "plt.ylim(-0.5, 3.5)\n", - "plt.xlabel('$(r - i)$ color', fontsize=12)\n", - "plt.ylabel('$(g - r)$ color', fontsize=12)\n", - "plt.title('VANDELS Spectroscopic Validation of Rubin Color Selection', fontsize=14)\n", - "plt.legend(loc='upper left', frameon=True, shadow=True)\n", - "plt.grid(True, linestyle=':', alpha=0.5)\n", - "\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4efa3820-8dda-4d79-9b40-abcbe76fba4e", - "metadata": {}, - "outputs": [], - "source": [ - "# 1. List of RA/Dec for z~4 VANDELS confirmations\n", - "vandels_ra = vandels_z4['RAJ2000']\n", - "vandels_dec = vandels_z4['DEJ2000']\n", - "print(f\"VANDELS Truth List size: {len(vandels_ra)}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e23b3a3b-bb85-4d0b-8cfb-f99132fcab3a", - "metadata": {}, - "outputs": [], - "source": [ - "# 2. Get all Rubin objects with i-band S/N > 10\n", - "# We use a 0.2 degree radius around the VANDELS center\n", - "rubin_query = \"\"\"\n", - "SELECT \n", - " objectId, coord_ra, coord_dec,\n", - " g_cModelMag, r_cModelMag, i_cModelMag,\n", - " g_cModelFlux, g_cModelFluxErr,\n", - " i_cModelFlux, i_cModelFluxErr\n", - "FROM dp1.Object\n", - "WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec), \n", - " CIRCLE('ICRS', 53.125, -27.8, 0.2)) = 1\n", - " AND (i_cModelFlux / i_cModelFluxErr) > 10\n", - "\"\"\"\n", - "\n", - "print(\"Querying Rubin for all solid i-band detections...\")\n", - "rubin_job = tap_service.run_sync(rubin_query)\n", - "rubin_all = rubin_job.to_table()\n", - "print(f\"Rubin Detected List size: {len(rubin_all)}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1e00286f-7d96-4da5-a5dc-e0d527975a8e", - "metadata": {}, - "outputs": [], - "source": [ - "from astropy.coordinates import SkyCoord\n", - "import astropy.units as u\n", - "\n", - "# 1. Setup coordinates\n", - "c_vandels = SkyCoord(ra=vandels_ra, dec=vandels_dec, unit='deg')\n", - "c_rubin = SkyCoord(ra=rubin_all['coord_ra'], dec=rubin_all['coord_dec'], unit='deg')\n", - "\n", - "# 2. Match\n", - "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin)\n", - "match_mask = d2d < 1.0 * u.arcsec \n", - "matched_rubin = rubin_all[idx[match_mask]]\n", - "\n", - "print(f\"Found {len(matched_rubin)} matches!\")\n", - "\n", - "# 3. Handle 'NaN' in g-band (The Dropouts)\n", - "# If g is NaN, it means the flux was too low to measure a magnitude. \n", - "# We'll assign it a faint magnitude (e.g., 28) to visualize the dropout.\n", - "g_mags = matched_rubin['g_cModelMag']\n", - "r_mags = matched_rubin['r_cModelMag']\n", - "i_mags = matched_rubin['i_cModelMag']\n", - "\n", - "# Replace NaNs with 28.0 for visualization\n", - "g_plot = np.where(np.isnan(g_mags), 28.0, g_mags)\n", - "\n", - "g_r = g_plot - r_mags\n", - "r_i = r_mags - i_mags\n", - "\n", - "whblue = np.where(g_r < 1.5)[0]\n", - "\n", - "# 4. Plot\n", - "plt.figure(figsize=(8, 6))\n", - "\n", - "# Background (All objects from this new Rubin query)\n", - "plt.scatter(rubin_all['r_cModelMag'] - rubin_all['i_cModelMag'], \n", - " rubin_all['g_cModelMag'] - rubin_all['r_cModelMag'], \n", - " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", - "\n", - "# Matches\n", - "plt.scatter(r_i, g_r, color='gold', marker='*', s=100, edgecolor='k', label='VANDELS matches')\n", - "\n", - "# Highlight the selected z~4 LBGs (blue)\n", - "#plt.scatter(r_minus_i[is_z4_lbg], g_minus_r[is_z4_lbg], \n", - "# s=20, color='blue', alpha=0.8, edgecolor='white', linewidth=0.5, label='z~4 LBGs')\n", - "\n", - "\n", - "# 4. Draw the Selection Boundaries for visual reference\n", - "# Calculate the vertices of the selection region\n", - "x_diag = np.linspace(0.133, 1.0, 50)\n", - "y_diag = 1.5 * x_diag + 0.8\n", - "\n", - "# Plot the bounding lines\n", - "plt.plot([-1.5, 0.133], [1.0, 1.0], color='red', linestyle='--', lw=2, label='Selection Boundary') # Bottom horizontal cut\n", - "#ax.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut to avoid M-stars\n", - "#ax.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2)\n", - "\n", - "# Plot the updated bounding lines\n", - "# 4. Draw the NEW Selection Boundaries\n", - "# Calculate the new intersection between the horizontal and diagonal lines\n", - "intersect_x = (1.5 - 0.8) / 1.5\n", - "plt.plot([-1.5, intersect_x], [1.5, 1.5], color='red', linestyle='--', lw=2, label='Selection Boundary') # Raised horizontal cut\n", - "plt.plot(x_diag, y_diag, color='red', linestyle='--', lw=2) # Diagonal cut\n", - "plt.plot([1.0, 1.0], [2.3, 4.0], color='red', linestyle='--', lw=2) # Right vertical cut\n", - "\n", - "\n", - "plt.axhline(1.5, color='blue', linestyle='--', label='Strict Cut')\n", - "plt.axhline(1., color='green', linestyle='--', label='Standard Cut')\n", - "plt.xlabel('r - i')\n", - "plt.ylabel('g - r')\n", - "plt.xlim(-0.5, 1.5)\n", - "plt.ylim(-0.5, 3.5)\n", - "plt.title('VANDELS Confirmations in Rubin (Unfiltered)')\n", - "plt.legend()\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1b4a125d-0bd3-4bbb-8376-85ac410855e1", - "metadata": {}, - "outputs": [], - "source": [ - "# something might be wrong with the matching process, CHECK\n", - "\n", - "from astropy.coordinates import SkyCoord\n", - "import astropy.units as u\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "# 1. Setup coordinates\n", - "c_vandels = SkyCoord(ra=vandels_ra, dec=vandels_dec, unit='deg')\n", - "c_rubin = SkyCoord(ra=rubin_all['coord_ra'], dec=rubin_all['coord_dec'], unit='deg')\n", - "c_rubin_lbg = SkyCoord(ra=cands_ra, dec=cands_dec, unit='deg')\n", - "\n", - "# 2. Match\n", - "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin_lbg)\n", - "match_mask = d2d < 1.0 * u.arcsec \n", - "matched_rubin = rubin_all[idx[match_mask]]\n", - "#matched_rubin = tab[idx[match_mask]]\n", - "\n", - "# Extract the redshift for the matched objects!\n", - "# match_mask aligns with the VANDELS catalog\n", - "matched_z = vandels_z4['zsp'][match_mask] \n", - "\n", - "print(f\"Found {len(matched_rubin)} matches!\")\n", - "\n", - "# 3. Handle 'NaN' in g-band (The Dropouts)\n", - "g_mags = matched_rubin['g_cModelMag']\n", - "r_mags = matched_rubin['r_cModelMag']\n", - "i_mags = matched_rubin['i_cModelMag']\n", - "s2n = matched_rubin['i_cModelFlux']/matched_rubin['i_cModelFluxErr']\n", - "\n", - "# Replace NaNs with 28.0 for visualization\n", - "g_plot = np.where(np.isnan(g_mags), 28.0, g_mags)\n", - "\n", - "g_r = g_plot - r_mags\n", - "r_i = r_mags - i_mags\n", - "\n", - "whblue = np.where(g_r > 1.5)[0]\n", - "\n", - "# 4. Plot\n", - "# Slightly wider figure to accommodate the colorbar\n", - "plt.figure(figsize=(9, 6))\n", - "\n", - "# Background (All objects from this new Rubin query)\n", - "plt.scatter(rubin_all['r_cModelMag'] - rubin_all['i_cModelMag'], \n", - " rubin_all['g_cModelMag'] - rubin_all['r_cModelMag'], \n", - " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", - "\n", - "# Matches: Color-coded by spectroscopic redshift\n", - "# Note: Keeping your [whblue] index, but you can remove it to see all stars!\n", - "sc = plt.scatter(r_i, g_r, \n", - " c=matched_z, cmap='plasma', \n", - " marker='*', s=150, edgecolor='k', zorder=10, \n", - " label='VANDELS matches')\n", - "\n", - "# Add the colorbar\n", - "cbar = plt.colorbar(sc)\n", - "cbar.set_label('VANDELS z_spec', fontsize=12, fontweight='bold')\n", - "\n", - "plt.axhline(1.5, color='blue', linestyle='--', label='Your Strict Cut')\n", - "plt.xlabel('r - i', fontsize=12)\n", - "plt.ylabel('g - r', fontsize=12)\n", - "plt.xlim(-0.5, 1.5)\n", - "plt.ylim(-0.5, 3.5)\n", - "plt.title('VANDELS Confirmations in Rubin (Color-Coded by z)', fontsize=14)\n", - "plt.legend(loc='lower right')\n", - "\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2ce194c9-55ac-44c7-bf29-702f2e7032bd", - "metadata": {}, - "outputs": [], - "source": [ - "from astropy.coordinates import SkyCoord\n", - "import astropy.units as u\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "\n", - "# 1. Setup coordinates\n", - "c_vandels = SkyCoord(ra=vandels_ra, dec=vandels_dec, unit='deg')\n", - "c_rubin = SkyCoord(ra=rubin_all['coord_ra'], dec=rubin_all['coord_dec'], unit='deg')\n", - "\n", - "# 2. Match\n", - "idx, d2d, _ = c_vandels.match_to_catalog_sky(c_rubin)\n", - "match_mask = d2d < 1.0 * u.arcsec \n", - "matched_rubin = rubin_all[idx[match_mask]]\n", - "\n", - "print(f\"Found {len(matched_rubin)} matches!\")\n", - "\n", - "# 3. Handle 'NaN' in g-band (The Dropouts)\n", - "g_mags = matched_rubin['g_cModelMag']\n", - "r_mags = matched_rubin['r_cModelMag']\n", - "i_mags = matched_rubin['i_cModelMag']\n", - "\n", - "# Replace NaNs with 28.0 for visualization\n", - "g_plot = np.where(np.isnan(g_mags), 28.0, g_mags)\n", - "\n", - "g_r = g_plot - r_mags\n", - "r_i = r_mags - i_mags\n", - "\n", - "# Keep only the stars below your 1.5 cut\n", - "whblue = np.where(g_r > 1.5)[0]\n", - "\n", - "# 4. Plot\n", - "plt.figure(figsize=(9, 6))\n", - "\n", - "# Background (All objects from this new Rubin query)\n", - "plt.scatter(rubin_all['r_cModelMag'] - rubin_all['i_cModelMag'], \n", - " rubin_all['g_cModelMag'] - rubin_all['r_cModelMag'], \n", - " s=2, color='gray', alpha=0.1, label='All Rubin i-band Detections')\n", - "\n", - "# Matches: Color-coded by r-band magnitude\n", - "sc = plt.scatter(r_i, g_r, \n", - " c=r_mags, cmap='viridis', \n", - " marker='*', s=150, edgecolor='k', zorder=10, \n", - " label='VANDELS matches')\n", - "\n", - "# Add the colorbar\n", - "cbar = plt.colorbar(sc)\n", - "cbar.set_label('r-band Magnitude', fontsize=12, fontweight='bold')\n", - "cbar.ax.invert_yaxis() # Invert so brighter (smaller number) is at the top\n", - "\n", - "plt.axhline(1.5, color='blue', linestyle='--', label='Your Strict Cut')\n", - "plt.xlabel('r - i', fontsize=12)\n", - "plt.ylabel('g - r', fontsize=12)\n", - "plt.xlim(-0.5, 1.5)\n", - "plt.ylim(-0.5, 3.5)\n", - "plt.title('VANDELS Confirmations in Rubin (Color-Coded by r-mag)', fontsize=14)\n", - "plt.legend(loc='lower right')\n", - "\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "e4fc8f40-cee2-465c-b7b4-c1a696e156d3", - "metadata": {}, - "source": [ - "Some points to consider here: the redshift window is 3.5 1 else axes[col_idx]\n", - " \n", - " band_match = coadds[coadds['lsst_band'] == f]\n", - " \n", - " if len(band_match) > 0:\n", - " try:\n", - " datalink_url = band_match['access_url'][0]\n", - " dl_result = DatalinkResults.from_result_url(datalink_url, session=session)\n", - " \n", - " sq = SodaQuery.from_resource(dl_result,\n", - " dl_result.get_adhocservice_by_id(\"cutout-sync\"),\n", - " session=session)\n", - " sq.circle = (ra * u.deg, dec * u.deg, fov * u.deg)\n", - " \n", - " cutout_bytes = sq.execute_stream().read()\n", - " hdul = fits.open(io.BytesIO(cutout_bytes))\n", - " img_array = hdul[1].data\n", - " \n", - " # ZScale is best for seeing the noise level in dropout bands\n", - " norm = ImageNormalize(img_array, interval=ZScaleInterval(), stretch=LinearStretch())\n", - " ax.imshow(img_array, origin='lower', cmap='gray', norm=norm)\n", - " \n", - " # Marker to help identify the target in noisy u/g bands\n", - " cy, cx = img_array.shape[0]//2, img_array.shape[1]//2\n", - " ax.add_patch(plt.Circle((cx, cy), radius=4, color='cyan', fill=False, lw=1.5, alpha=0.7))\n", - "\n", - " except Exception as e:\n", - " ax.text(0.5, 0.5, 'SODA Error', ha='center', va='center', transform=ax.transAxes, color='red')\n", - " else:\n", - " ax.text(0.5, 0.5, 'No Coverage', ha='center', va='center', transform=ax.transAxes, color='red')\n", - " \n", - " ax.set_xticks([]); ax.set_yticks([])\n", - " if row_idx == 0:\n", - " ax.set_title(f\"{f}-band\", fontsize=15, fontweight='bold')\n", - " if col_idx == 0:\n", - " ax.set_ylabel(f\"z={z_spec:.2f}\\n{obj_id}\\n{gr}\\n{s2n}\", rotation=0, labelpad=70, ha='center', fontweight='bold')\n", - "\n", - "\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "b2f95d66-b972-4d69-ab4a-cd2314e263cb", - "metadata": {}, - "source": [ - "## Comparison between VANDELS spec-z and Rubin photo-z sanity check" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "24942ae5-e69b-46a4-902e-d93e73f298ab", - "metadata": {}, - "outputs": [], - "source": [ - "import astropy.units as u\n", - "from astropy.coordinates import SkyCoord\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "print(\"Preparing VANDELS and LSDB catalogs for cross-matching...\")\n", - "\n", - "# 1. Extract the full VANDELS coordinates and spec-z\n", - "# (Assuming your unfiltered VANDELS table from VizieR is stored as 'vandels_data')\n", - "v_ra = vandels_data['RAJ2000']\n", - "v_dec = vandels_data['DEJ2000']\n", - "v_zspec = vandels_data['zsp']\n", - "v_coords = SkyCoord(ra=v_ra, dec=v_dec, unit='deg')\n", - "\n", - "# 2. Filter the massive LSDB catalog down to the CDFS region\n", - "# lsdb updated its API to require 'radius_arcsec' to avoid unit confusion.\n", - "# We want a 0.5 degree radius, which is 1800 arcseconds.\n", - "print(\"Running LSDB cone search on the VANDELS footprint...\")\n", - "pz_regional = pz_cat.cone_search(ra=53.125, dec=-27.8, radius_arcsec=1800).compute()\n", - "\n", - "# 3. Setup the Rubin coordinates from the regional Photo-z catalog\n", - "# Note: LSDB uses 'coord_ra' and 'coord_dec' by default\n", - "rubin_coords = SkyCoord(ra=pz_regional['coord_ra'].values, \n", - " dec=pz_regional['coord_dec'].values, \n", - " unit='deg')\n", - "\n", - "# 4. Perform the spatial cross-match\n", - "print(\"Performing spatial cross-match...\")\n", - "idx, d2d, _ = v_coords.match_to_catalog_sky(rubin_coords)\n", - "\n", - "# Keep only confident matches within 1 arcsecond\n", - "match_mask = d2d < 1.0 * u.arcsec\n", - "\n", - "# Extract the matched data\n", - "matched_rubin_pz = pz_regional.iloc[idx[match_mask]]\n", - "matched_v_zspec = v_zspec[match_mask]\n", - "matched_v_zphot = matched_rubin_pz['bpz_z_mean'].values\n", - "\n", - "# Clean out any rows where the photo-z pipeline failed (returned NaN)\n", - "valid = ~np.isnan(matched_v_zphot) & ~np.isnan(matched_v_zspec)\n", - "z_spec_clean = matched_v_zspec[valid]\n", - "z_phot_clean = matched_v_zphot[valid]\n", - "\n", - "print(f\"Successfully matched {len(z_spec_clean)} galaxies with both Spec-z and Photo-z!\")\n", - "\n", - "# 5. Plot Photo-z vs Spec-z\n", - "fig, ax = plt.subplots(figsize=(8, 7))\n", - "\n", - "# Scatter plot of the matches\n", - "ax.scatter(z_spec_clean, z_phot_clean, s=20, color='teal', alpha=0.5, \n", - " edgecolor='k', linewidth=0.5, label='Matched Galaxies')\n", - "\n", - "# Perfect agreement line (1:1)\n", - "z_line = np.linspace(0, 6, 100)\n", - "ax.plot(z_line, z_line, color='black', linestyle='--', linewidth=2, label='1:1 line')\n", - "\n", - "# Catastrophic outlier boundaries\n", - "# The standard definition in astronomy is |dz| / (1+z) > 0.15\n", - "ax.plot(z_line, z_line + 0.15*(1+z_line), color='red', linestyle=':', label='Outliers ($|\\Delta z| > 0.15(1+z)$)')\n", - "ax.plot(z_line, z_line - 0.15*(1+z_line), color='red', linestyle=':')\n", - "\n", - "# Formatting\n", - "ax.set_xlim(0, 5.5)\n", - "ax.set_ylim(0, 5.5)\n", - "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", - "ax.set_ylabel('Photometric Redshift (Rubin bpz_z_mean)', fontsize=14)\n", - "ax.set_title('Validation: Photo-z vs. Spec-z', fontsize=16, fontweight='bold')\n", - "ax.legend(loc='upper left', frameon=True)\n", - "ax.grid(True, linestyle=':', alpha=0.6)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# 6. Calculate Standard Photo-z Quality Metrics\n", - "# dz = (z_phot - z_spec) / (1 + z_spec)\n", - "dz = (z_phot_clean - z_spec_clean) / (1 + z_spec_clean)\n", - "\n", - "# NMAD: Normalized Median Absolute Deviation (A robust measure of scatter)\n", - "nmad = 1.48 * np.median(np.abs(dz - np.median(dz)))\n", - "\n", - "# Outlier Fraction: Percentage of objects outside the red dotted lines\n", - "outlier_fraction = np.sum(np.abs(dz) > 0.15) / len(dz)\n", - "\n", - "print(f\"--- Photo-z Performance Metrics ---\")\n", - "print(f\"Robust Scatter ($\\sigma_{{NMAD}}$): {nmad:.3f}\")\n", - "print(f\"Catastrophic Outlier Fraction: {outlier_fraction:.1%}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "57b52d6b-2441-4b38-ae0f-cff23504b472", - "metadata": {}, - "outputs": [], - "source": [ - "import astropy.units as u\n", - "from astropy.coordinates import SkyCoord\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "print(\"Preparing VANDELS and LSDB catalogs for cross-matching...\")\n", - "\n", - "# 1. Extract the full VANDELS coordinates and spec-z\n", - "v_ra = vandels_data['RAJ2000']\n", - "v_dec = vandels_data['DEJ2000']\n", - "v_zspec = vandels_data['zsp']\n", - "v_coords = SkyCoord(ra=v_ra, dec=v_dec, unit='deg')\n", - "\n", - "# 2. Filter the massive LSDB catalog down to the CDFS region\n", - "print(\"Running LSDB cone search on the VANDELS footprint...\")\n", - "pz_regional = pz_cat.cone_search(ra=53.125, dec=-27.8, radius_arcsec=1800).compute()\n", - "\n", - "# 3. Setup the Rubin coordinates\n", - "rubin_coords = SkyCoord(ra=pz_regional['coord_ra'].values, \n", - " dec=pz_regional['coord_dec'].values, \n", - " unit='deg')\n", - "\n", - "# 4. Perform the spatial cross-match\n", - "print(\"Performing spatial cross-match...\")\n", - "idx, d2d, _ = v_coords.match_to_catalog_sky(rubin_coords)\n", - "match_mask = d2d < 1.0 * u.arcsec\n", - "\n", - "# Extract the matched data\n", - "matched_rubin_pz = pz_regional.iloc[idx[match_mask]]\n", - "matched_v_zspec = v_zspec[match_mask]\n", - "matched_v_zphot = matched_rubin_pz['bpz_z_mean'].values\n", - "\n", - "# Check the column name for i-band magnitude in the photo-z catalog\n", - "if 'i_cModelMag' in matched_rubin_pz.columns:\n", - " matched_i_mag = matched_rubin_pz['i_cModelMag'].values\n", - "elif 'mag_i' in matched_rubin_pz.columns:\n", - " matched_i_mag = matched_rubin_pz['mag_i'].values\n", - "else:\n", - " # If it throws an error here, print matched_rubin_pz.columns to find the exact name!\n", - " print(\"Warning: Could not find i-band magnitude column. Using placeholder.\")\n", - " matched_i_mag = np.zeros(len(matched_v_zphot))\n", - "\n", - "# Clean out any rows with NaNs in z_phot, z_spec, OR i_mag to keep arrays aligned\n", - "valid = ~np.isnan(matched_v_zphot) & ~np.isnan(matched_v_zspec) & ~np.isnan(matched_i_mag)\n", - "z_spec_clean = matched_v_zspec[valid]\n", - "z_phot_clean = matched_v_zphot[valid]\n", - "i_mag_clean = matched_i_mag[valid]\n", - "\n", - "print(f\"Successfully matched {len(z_spec_clean)} galaxies with Spec-z, Photo-z, and i-mag!\")\n", - "\n", - "# 5. Plot Photo-z vs Spec-z\n", - "fig, ax = plt.subplots(figsize=(9, 7)) # Slightly wider for the colorbar\n", - "\n", - "# Scatter plot: Color-coded by i-band magnitude\n", - "sc = ax.scatter(z_spec_clean, z_phot_clean, c=i_mag_clean, cmap='viridis', \n", - " s=35, alpha=0.8, edgecolor='k', linewidth=0.5, zorder=5)\n", - "\n", - "# Add the colorbar\n", - "cbar = plt.colorbar(sc, ax=ax)\n", - "cbar.set_label('i-band Magnitude', fontsize=12, fontweight='bold')\n", - "cbar.ax.invert_yaxis() # Invert so brighter (smaller number) is at the top\n", - "\n", - "# Perfect agreement line (1:1)\n", - "z_line = np.linspace(0, 6, 100)\n", - "ax.plot(z_line, z_line, color='black', linestyle='--', linewidth=2, label='1:1 Agreement')\n", - "\n", - "# Catastrophic outlier boundaries\n", - "ax.plot(z_line, z_line + 0.15*(1+z_line), color='red', linestyle=':', label='Outlier Boundary ($|\\Delta z| > 0.15(1+z)$)')\n", - "ax.plot(z_line, z_line - 0.15*(1+z_line), color='red', linestyle=':')\n", - "\n", - "# Formatting\n", - "ax.set_xlim(0, 5.5)\n", - "ax.set_ylim(0, 5.5)\n", - "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", - "ax.set_ylabel('Photometric Redshift (Rubin bpz_z_mean)', fontsize=14)\n", - "ax.set_title('Validation: Photo-z vs. Spec-z (Colored by i-mag)', fontsize=16, fontweight='bold')\n", - "\n", - "# Combine legends\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "ax.legend(handles, labels, loc='upper left', frameon=True)\n", - "ax.grid(True, linestyle=':', alpha=0.6)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# 6. Calculate Standard Photo-z Quality Metrics\n", - "dz = (z_phot_clean - z_spec_clean) / (1 + z_spec_clean)\n", - "nmad = 1.48 * np.median(np.abs(dz - np.median(dz)))\n", - "outlier_fraction = np.sum(np.abs(dz) > 0.15) / len(dz)\n", - "\n", - "print(f\"--- Photo-z Performance Metrics ---\")\n", - "print(f\"Robust Scatter ($\\sigma_{{NMAD}}$): {nmad:.3f}\")\n", - "print(f\"Catastrophic Outlier Fraction: {outlier_fraction:.1%}\")" - ] - }, - { - "cell_type": "markdown", - "id": "354dbbd9-f5df-47ee-962c-1384b7e21b29", - "metadata": {}, - "source": [ - "## 3. Total fluxes\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0cec2ebe-6134-4f86-b9de-67aa16dea0d5", - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "sys.exit()" - ] - }, - { - "cell_type": "markdown", - "id": "7d75b896-770c-4d7e-94d9-7202af571209", - "metadata": {}, - "source": [ - "### 3.1. Comparing total fluxes\n", - "\n", - "This section will make several plots that shows how the different photometric measurements compare.\n", - "\n", - "First, compare `cModelFlux` (two component bulge+disk sersic model flux) to `sersicFlux` (single sersic model flux with shape parameters free), `bdFluxB` (sersic with n=4) and `bdFluxD` (sersic with n=1). " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9443b34f-9afe-4c12-b345-860896176cac", - "metadata": {}, - "outputs": [], - "source": [ - "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", - " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", - "\n", - "bins = np.arange(16, 27, 1)\n", - "\n", - "ylims = [-1.2, 1.2]\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-bdFluxD_mag), 's', alpha=.3,\n", - " label='cModel-bdFluxD', color='blue')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-bdFluxD_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='blue', lw=2, label='bin median', zorder=11)\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-bdFluxB_mag), '^', alpha=.3,\n", - " label='cModel-bdFluxB', color='r')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-bdFluxB_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='r', lw=2, label='bin median', zorder=11)\n", - "\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag - sersic_mag), 'o', alpha=.3,\n", - " label='cModel - sersic', color='g')\n", - "\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-sersic_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='g', lw=2, label='bin median', zorder=11)\n", - "\n", - "ax.axhline(0, linestyle='--')\n", - "ax.set_xlabel('cModel Magnitude')\n", - "ax.set_ylabel('cModel mag - other mag')\n", - "ax.set_ylim([-1, 1])\n", - "ax.legend()\n", - "\n", - "ax2.hist((cmodel_mag-bdFluxD_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='blue', stacked=True, fill=False, label='bdFluxD')\n", - "ax2.hist((cmodel_mag-bdFluxB_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='r', stacked=True, fill=False, label='bdFluxB')\n", - "ax2.hist((cmodel_mag-sersic_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='g', stacked=True, fill=False, label='Sersic')\n", - "\n", - "ax2.set_ylim(ylims)\n", - "ax2.axhline(0, linestyle='--', color='k')\n", - "ax.axhline(0, linestyle='--', color='k')\n", - "ax.set_xlabel('i-band AB magnitude [cModel]')\n", - "ax.set_ylabel('cModel mag - Other mag')\n", - "ax.set_ylim(ylims)\n", - "\n", - "ax.legend()\n", - "ax2.legend()" - ] - }, - { - "cell_type": "markdown", - "id": "f290d993-8645-406a-9e95-fabd852383c8", - "metadata": {}, - "source": [ - "> Figure 1: Left panel: a plot comparing the magnitude difference between cModel and dbFluxD (blue), bdFluxB (red) and sersic (green) vs i-band magnitude as measured by cModel. Right panel: a histogram showing the difference in color between cModel and the three other photometric measurements, across all magnitudes. The sersic fluxes are in best agreement with cModel (smallest scatter in right panel) with the bdFluxB returning systematically fainter magnitudes, and bdFluxD returning systematically brighter magnitudes.\n", - "\n", - "Below, explore how the BD fluxes compare to sersic fluxes as a function of the shape of the light profile, sersic index n." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c1fea6a9-fc32-43ce-bb7a-f7e23677f548", - "metadata": {}, - "outputs": [], - "source": [ - "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", - " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", - "\n", - "bins = np.arange(0, 7, 0.25)\n", - "\n", - "ylims = [-1.2, 1.2]\n", - "\n", - "ax.plot(sersic_index, (sersic_mag-bdFluxD_mag), 's', alpha=.3,\n", - " label='cModel-bdFluxD', color='blue')\n", - "x = sersic_index\n", - "y = (sersic_mag-bdFluxD_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='blue', lw=2, label='bin median', zorder=11)\n", - "\n", - "ax.plot(sersic_index, (sersic_mag-bdFluxB_mag), '^', alpha=.3,\n", - " label='cModel-bdFluxB', color='r')\n", - "x = sersic_index\n", - "y = (sersic_mag-bdFluxB_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='r', lw=2, label='bin median', zorder=11)\n", - "\n", - "ax.axhline(0, linestyle='--')\n", - "\n", - "ax.set_ylabel('sersic mag - BD mag')\n", - "ax.set_ylim([-1, 1])\n", - "ax.legend()\n", - "\n", - "\n", - "ax2.hist((cmodel_mag-bdFluxD_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='blue', stacked=True, fill=False, label='bdFluxD')\n", - "ax2.hist((cmodel_mag-bdFluxB_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='r', stacked=True, fill=False, label='bdFluxB')\n", - "\n", - "ax2.set_ylim(ylims)\n", - "ax2.axhline(0, linestyle='--', color='k')\n", - "ax.axhline(0, linestyle='--', color='k')\n", - "ax.set_xlabel('Sersic Index n')\n", - "ax.set_ylabel('Sersic mag - Other mag')\n", - "ax.set_ylim(ylims)\n", - "ax.set_xlim([0, 8])\n", - "ax.legend()\n", - "ax2.legend()" - ] - }, - { - "cell_type": "markdown", - "id": "3c44cfa4-7e2d-4c77-960d-f540683744b2", - "metadata": {}, - "source": [ - "> Fig 2: Comparison of the sersic mag (flux measured with sersic parameters left free) with the bdFlux that is measured with sersic index fixed to either n=1 (D) or n=4 (B) as a function of sersic index n. Fixing the sersic index can inject scatter in the flux relative to leaving it free, but the sersic flux converges on bdFluxD(B) for n=1 and n=4." - ] - }, - { - "cell_type": "markdown", - "id": "b7c9fdd5-3bb1-4d8c-abac-5cdafa8df188", - "metadata": {}, - "source": [ - "## 4. Apparent fluxes\n", - "\n", - "This section explores three types of apparent fluxes: Kron (elliptical apertures that typically includes more than 90% of intrinsic light), and aperture photometry (flux measured inside circles of varying size).\n", - "\n", - "Here, apparent fluxes refers to photometry that are not corrected for flux outside of the measurement aperture (i.e. not corrected to be a total flux). These measurements have their own applications but should not be used to measure mass or luminosity.\n", - " \n", - "##### Kron fluxes\n", - "\n", - "A decent summary of Kron fluxes in the NED documentation. The aperture used for the fluxes is 2.5 x R1 where R1 is the luminosity weighted radius (also called \"first moment\"; Kron et al. 1980).\n", - "\n", - "```\n", - "_kronFlux : Flux from Kron Flux algorithm. Measured on -band.\n", - "_kronFluxErr : Uncertainty of _kronFlux.\n", - "_kronFlux_flag : Failure flag for _kronFlux.\n", - "```\n", - "\n", - "The Kron radius, `_kronRad`, is also available. In this case of LSST pipeline output, the Kron flux is not corrected for light that is emitted outside of the Kron aperture. While in many cases it will collect the majority of light, it will not be as accurate as the cModel for science cases requiring total flux.\n", - "\n", - "\n", - "##### Aperture fluxes\n", - "This contains the enclosed flux inside a given aperture (and not corrected to total fluxes using an aperture correction that accounts for the flux falling outside the aperture). Fixed aperture size refers to the aperture radius in pixels.\n", - "\n", - "```\n", - "_apFlux : Flux within -pixel aperture. Forced on -band.\n", - "_apFluxErr : Uncertainty of _apFlux.\n", - "_apFluxFlag : Failure flag for _apFlux.\n", - "```\n", - "\n", - "The apertures are 3, 6, 9, 12, 17, 25, 35, 50, and 70 pixels. In the column name, apertures are `03`, `06`, `09`, `12`, and so on. While aperture fluxes are not corrected for the loss outside the aperture, if the aperture size is much larger than the galaxy size then it will approximate the total flux of the galaxy. The general application of these measurements are for measuring radial profiles (see Section 4 below).\n" - ] - }, - { - "cell_type": "markdown", - "id": "d0869336-562f-4909-8109-9a737f57877b", - "metadata": {}, - "source": [ - "### 4.1. Comparing total to apparent fluxes\n", - "\n", - "This section will make several plots that compare the `cModel` flux (which we take as the fiducial total flux, as commonly used for SDSS) to some of the apparent flux measurements. Kron, and aperture photometry are all measures of light within a fixed aperture. \n", - "\n", - "\n", - "Generally, magnitudes measured using aperture photometry in the LSST pipeline are fainter than those measured from cModel, because the fixed circular aperture systematically underestimates the flux in the galaxy wings (and the lost flux increases as the intrinsic size of the galaxy increases, e.g. as traced by the Kron radius).\n", - "\n", - "First, compare `cModel` to `Kron` which should typically enclose 90% of the light." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "96dc3077-e086-430a-bace-47383bb60c97", - "metadata": {}, - "outputs": [], - "source": [ - "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", - " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", - "\n", - "bins = np.arange(16, 27, 1)\n", - "\n", - "ylims = [-1.2, 1.2]\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag - kron_mag), 's', alpha=.3,\n", - " label='cModel-Kron', color='blue')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-kron_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1]) / 2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='blue', lw=2, label='bin median', zorder=11)\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-sersic_mag), 'o', alpha=.3,\n", - " label='cModel - sersic', color='r')\n", - "\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-sersic_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='k', lw=3, label=None, zorder=10)\n", - "ax.plot(binctr, bin_mean, color='r', lw=2, label='bin median', zorder=11)\n", - "\n", - "ax.axhline(0, linestyle='--')\n", - "ax.set_xlabel('cModel Magnitude')\n", - "ax.set_ylabel('cModel mag - sersic mag')\n", - "ax.set_ylim([-1, 1])\n", - "ax.legend()\n", - "\n", - "\n", - "ax2.hist((cmodel_mag-sersic_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 50), align='mid',\n", - " histtype=\"step\", color='red', stacked=True, fill=False, label='Sersic')\n", - "ax2.hist((cmodel_mag-kron_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 50), align='mid',\n", - " histtype=\"step\", color='blue', stacked=True, fill=False, label='Kron')\n", - "\n", - "ax2.set_ylim(ylims)\n", - "ax2.axhline(0, linestyle='--', color='k')\n", - "ax.axhline(0, linestyle='--', color='k')\n", - "ax.set_xlabel('Kron Radius [i-band; pixels]')\n", - "ax.set_ylabel('cModel mag - Other mag')\n", - "ax.set_ylim(ylims)\n", - "\n", - "ax.legend()\n", - "ax2.legend()\n" - ] - }, - { - "cell_type": "markdown", - "id": "68e45fe0-9d1d-4d13-af74-9302c3f3c118", - "metadata": {}, - "source": [ - "> Figure 3: A figure comparing the difference between cModel and Kron magnitudes, compared to the difference between cModel and sersic magnitudes (left panel). Generally, both Kron and sersic the measurements are in comparable agreement with cModel. The right panel shows the histogram of magnitude differences, demonstrating that there are not systematic offsets but slightly higher scatter from Kron with respect to cModel.\n", - "\n", - "Below, explore how circular aperture photometry compares to cModel. Generally, magnitudes measured using aperture photometry in the LSST pipeline are fainter than those measured from cModel, because the fixed circular aperture systematically underestimates the flux in the galaxy wings (and the lost flux increases as the intrinsic size of the galaxy increases, e.g. as traced by the Kron radius)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f867380a-dac7-4a0b-a249-b8ee199cfdf3", - "metadata": {}, - "outputs": [], - "source": [ - "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", - " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", - "\n", - "bins = np.arange(2, 15, 1)\n", - "ylims = [-1.5, 1.5]\n", - "\n", - "ax.plot(i_kronRad, (cmodel_mag-ap06_mag), '^', alpha=.3,\n", - " label='6-pixel aperture', color='red')\n", - "ax.plot(i_kronRad, (cmodel_mag-ap09_mag), 's', alpha=.3,\n", - " label='9-pixel aperture', color='orange')\n", - "ax.plot(i_kronRad, (cmodel_mag-ap12_mag), 'o', alpha=.3,\n", - " label='12-pixel aperture', color='green')\n", - "ax.plot(i_kronRad, (cmodel_mag-ap17_mag), '.', alpha=.3,\n", - " label='17-pixel aperture', color='blue')\n", - "\n", - "ax2.hist((cmodel_mag-ap17_mag), edgecolor='blue', orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", stacked=True, fill=False)\n", - "ax2.hist((cmodel_mag-ap12_mag), edgecolor='green', orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", stacked=True, fill=False)\n", - "ax2.hist((cmodel_mag-ap09_mag), edgecolor='orange', orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", stacked=True, fill=False)\n", - "ax2.hist((cmodel_mag-ap06_mag), edgecolor='red', orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", stacked=True, fill=False)\n", - "\n", - "ax2.set_ylim(ylims)\n", - "ax.axhline(0, linestyle='--', color='k')\n", - "ax2.axhline(0, linestyle='--', color='k')\n", - "ax.set_xlabel('Kron Radius [i-band; pixels]')\n", - "ax.set_ylabel('cModel mag - Aperture mag')\n", - "ax.set_ylim(ylims)\n", - "ax.set_xlim([2, 12])\n", - "ax.legend()" - ] - }, - { - "cell_type": "markdown", - "id": "01de6505-06f2-4c80-a674-7a421613fd8c", - "metadata": {}, - "source": [ - "> Figure 4: A comparison of the difference between cModel photometry and aperture photometry measured by the LSST pipelines for four different aperture sizes as a function of galaxy size (as measured using the Kron radius). The left panel shows the scatter plot of difference in photometry vs Kron radius, and the right panel shows a histogram of these values that demonstrate that larger aperture sizes have photometry that is closer to the cModel. The right panel shows histograms of the data in the left panel, where the colors indicate for the same data in each panel." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "40604f56-60f7-43d3-afe7-981950402813", - "metadata": {}, - "outputs": [], - "source": [ - "fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(7, 6))\n", - "ylims = [-1.2, 1.2]\n", - "bins = np.arange(16, 27, 1)\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-ap06_mag), '^', alpha=.1,\n", - " label='cModel 6-pix aperture', color='red')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-ap06_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='red', lw=2, label='bin median', zorder=10)\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-ap09_mag), 's', alpha=.1,\n", - " label='cModel 9-pix aperture', color='orange')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-ap09_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='orange', lw=2,\n", - " label='bin median', zorder=10)\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-ap12_mag), 'o', alpha=.1,\n", - " label='cModel 12-pix aperture', color='green')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-ap12_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='green', lw=2,\n", - " label='bin median', zorder=10)\n", - "\n", - "ax.plot(cmodel_mag, (cmodel_mag-ap17_mag), '.', alpha=.1,\n", - " label='cModel 17-pix aperture', color='blue')\n", - "x = cmodel_mag\n", - "y = (cmodel_mag-ap17_mag)\n", - "bin_mean, bin_edge, binnum = binned_statistic(x, y,\n", - " statistic='median', bins=bins)\n", - "binctr = bin_edge[:-1] + (bin_edge[1:]-bin_edge[:-1])/2\n", - "ax.plot(binctr, bin_mean, color='blue', lw=2,\n", - " label='bin median', zorder=10)\n", - "\n", - "ax.axhline(0, linestyle='--')\n", - "ax.set_xlabel('cModel Magnitude')\n", - "ax.set_ylabel('cModel mag - Aperture mag')\n", - "ax.set_ylim([-1, 1])\n", - "ax.set_xlim([20, 25])\n", - "ax.legend()" - ] - }, - { - "cell_type": "markdown", - "id": "84519e9a-0810-49b2-bcd6-1c7dd8e63124", - "metadata": {}, - "source": [ - "> Figure 5: A similar comparison of the difference between cModel photometry and aperture photometry measured by the LSST pipelines for four different aperture sizes, this time as a function of cModel magnitude. Running median is included." - ] - }, - { - "cell_type": "markdown", - "id": "d4e2093d-9d9a-41d4-9217-209519b0a6d9", - "metadata": {}, - "source": [ - "These two figures show that the aperture photometry typically under-estimates the flux relative to the total flux estimated using cModel. As expected, there is a general trend for larger apertures to get closer to the total flux from cModel for large galaxies (i.e. whose Kron Radius is larger). There is also a general trend for the aperture photometry to be less discrepant at fainter magnitudes, since faint galaxies tend to be small.\n" - ] - }, - { - "cell_type": "markdown", - "id": "3d3dd22a-80aa-4282-8c14-1f20c8525088", - "metadata": {}, - "source": [ - "### 4.2. Application of aperture photometry: radial profile\n", - "\n", - "A science application for the aperture photometry is easy visualization of the radial profile of galaxies. In the cell below, make this plot for both a large galaxy (first) and a smaller galaxy of similar brightness (second). The query looks for bright galaxies whose `cModel` magnitude ~ 20 ABmag. Dividing the aperture flux by the surface area of the aperture yields the surface brightness, which can be plotted as a function of radius from the center of the galaxy to compare radial light profiles." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "83fdc23c-6234-4156-ac4a-d340240f2762", - "metadata": {}, - "outputs": [], - "source": [ - "wh = np.where((tab['i_kronRad'] > 20) & (cmodel_mag > 20)\n", - " & (cmodel_mag < 20.5))[0]\n", - "\n", - "indx = 0\n", - "arcsec_per_pix = 0.2\n", - "\n", - "rad = np.array([3, 6, 9, 12, 17, 25, 35, 50]) * arcsec_per_pix\n", - "area = np.pi * rad**2\n", - "profile = np.array([tab['i_ap03Flux'][wh][indx], tab['i_ap06Flux'][wh][indx],\n", - " tab['i_ap09Flux'][wh][indx], tab['i_ap12Flux'][wh][indx],\n", - " tab['i_ap17Flux'][wh][indx], tab['i_ap25Flux'][wh][indx],\n", - " tab['i_ap35Flux'][wh][indx],\n", - " tab['i_ap50Flux'][wh][indx]]) / area\n", - "\n", - "plt.plot(rad, profile, linestyle=':',\n", - " label='Large Radius R='\n", - " + str(np.round(i_kronRad[wh][indx]*arcsec_per_pix, 2)))\n", - "plt.xlabel('Aperture Radius [arcsec]')\n", - "plt.ylabel(r'Surface Brightness [nJy arcsec−2]')\n", - "\n", - "wh2 = np.where((tab['i_kronRad'] < 8) & (tab['i_kronRad'] > 5)\n", - " & (cmodel_mag > 20) & (cmodel_mag < 20.5))[0]\n", - "\n", - "indx = 0\n", - "\n", - "profile = np.array([tab['i_ap03Flux'][wh2][indx], tab['i_ap06Flux'][wh2][indx],\n", - " tab['i_ap09Flux'][wh2][indx], tab['i_ap12Flux'][wh2][indx],\n", - " tab['i_ap17Flux'][wh2][indx], tab['i_ap25Flux'][wh2][indx],\n", - " tab['i_ap35Flux'][wh2][indx],\n", - " tab['i_ap50Flux'][wh2][indx]])/area\n", - "\n", - "plt.plot(rad, profile,\n", - " label='Small Radius R='\n", - " + str(round(i_kronRad[wh2][indx]*arcsec_per_pix, 2)))\n", - "plt.legend()\n", - "plt.yscale('log')" - ] - }, - { - "cell_type": "markdown", - "id": "f2fae258-ded9-4d7b-be5a-c77b1e5fbf9a", - "metadata": {}, - "source": [ - "> Figure 6: Plot demonstrating the use of aperture photometry to plot the surface brightness profile (as a function of aperture radius) for a galaxy with large Kron radius (green solid) and small Kron radius (blue dotted). " - ] - }, - { - "cell_type": "markdown", - "id": "fdc9dd4c-95fc-4ba8-96f7-3d85ea32b9f7", - "metadata": {}, - "source": [ - "## 5. Photometry for color\n", - "\n", - "This section will explore GaaP fluxes (which are optimized for measuring accurate colors between bands).\n", - "\n", - "##### GaaP fluxes\n", - "\n", - "These are the Gaussian-aperture-and-PSF flux that is defined in Kuijken et al. 2008. The main goal of this method is to measure accurate colors while accounting for the different spatial resolution between filters. This is sometimes achieved in other datasets by convolving all images to the largest PSF, but this process of PSF-matching is computationally very time consuming for large images, thus motivating GaaP as a faster alternative. It is not a measure of total flux in a filter. Several measurement apertures are available. \n", - "\n", - "**Aperture**\n", - "\n", - "```\n", - "_gaapFlux : GaaP flux with aperture after multiplying the seeing aperture. Forced on -band.\n", - "_gaapFluxErr : Uncertainty of _gaapFlux.\n", - "```\n", - "\n", - "Where the measurement apertures are 0.5, 0.7, 1.0, 1.5, 2.5, and 3.0 arcseconds. In the column name `` appears as `0p5`, `0p7`, etc. Multiplying by the \"seeing aperture\" refers to convolving the PSF with a kernel so that the PSF is as if the seeing were 1.15 arcseconds. This has the effect of smearing the images of all filters consistently so that the colors are accurate.\n", - "\n", - "For photometric redshifts, and other analysis where accurate colors are important, it is recommended to start with the GaaP fluxes with 1.0 aperture (optimal aperture was found to not perform as well, and should not be used). The largest aperture `gaap3p0` might work better for larger galaxies, but `gaap1p0` has better overall performance. Experiment yourself to see how it works for your science case.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "id": "2468484d-3f81-4be4-b962-3a43a299f41d", - "metadata": {}, - "source": [ - "\n", - "#### 5.1. Kron and GaaP comparison\n", - "\n", - "In the next cell, compare the cModel instead to the Kron and GaaP measures. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08d1c010-a802-4d03-a035-25a07cb51c19", - "metadata": {}, - "outputs": [], - "source": [ - "fig, (ax, ax2) = plt.subplots(ncols=2, nrows=1,\n", - " width_ratios=[0.8, 0.2], figsize=(10, 6))\n", - "ylims = [-2, 2]\n", - "\n", - "ax.plot(i_kronRad, (cmodel_mag-gaap_mag), 's', alpha=.3,\n", - " label='gaap1p0', color='orange')\n", - "\n", - "ax.plot(i_kronRad, (cmodel_mag-kron_mag), 'o', alpha=.3,\n", - " label='Kron', color='blue')\n", - "\n", - "ax2.hist((cmodel_mag-gaap_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='orange', stacked=True, fill=False, label='gaap1p0')\n", - "ax2.hist((cmodel_mag-kron_mag), orientation=\"horizontal\",\n", - " bins=np.linspace(ylims[0], ylims[1], 40), align='mid',\n", - " histtype=\"step\", color='blue', stacked=True, fill=False, label='Kron')\n", - "\n", - "ax2.set_ylim(ylims)\n", - "ax.axhline(0, linestyle='--', color='k')\n", - "ax2.axhline(0, linestyle='--', color='k')\n", - "ax.set_xlabel('Kron Radius [i-band; pixels]')\n", - "ax.set_ylabel('cModel mag - Other mag')\n", - "ax.set_ylim(ylims)\n", - "ax.set_xlim([2, 15])\n", - "ax.legend()\n", - "ax2.legend()\n" - ] - }, - { - "cell_type": "markdown", - "id": "892f08f9-b64e-485b-8d24-97e9104778d8", - "metadata": {}, - "source": [ - "> Figure 7: The left panel figure shows the i-band magnitude difference between cModel and Kron (orange circles) and between cModel and gaap1p0 (blue squares) vs the Kron radius (a proxy for galaxy size) for the galaxies in the query. The dashed line indicates where the two magnitudes would have the same value. The gaap1p0 magnitude always underestimates the flux, but the offset becomes worse for larger galaxies (relative to the fixed aperture). The right panel shows the histogram of the magnitude differences in the left panel, illustrating that while cModel - Kron magnitudes are similar on average (blue histogram) the gaap1p0 systematically underestimates the flux relative to cModel (orange histogram). \n" - ] - }, - { - "cell_type": "markdown", - "id": "f17ac68e-312c-4d90-9191-0efe4154d8b6", - "metadata": {}, - "source": [ - "#### 5.2. CMD with GaaP\n", - "\n", - "This section demonstrates using GaaP photometry to calculate accurate galaxy colors to identify different types of galaxies. First, define magnitudes from g, r, and i band photometry. The second cell will then compare the colors of galaxies that overlap the galaxy cluster with that in the field. In clusters, galaxies tend to be old, red elliptical galaxies and thus exhibit a well defined red sequence in color space. \n", - "\n", - "The earlier query in Section 2 returned galaxies from a blank, \"field\" location (the ECDFS). These will be dominated by bluer star forming galaxies which are most common in field environments.\n", - "\n", - "Below, add a new query near a known galaxy cluster at redshift z=0.3. This is Abell 360 and sits in the DP1 data from the low ecliptic latitude field.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "07de357a-44ff-448f-966b-b5c508b9dfa7", - "metadata": {}, - "outputs": [], - "source": [ - "cluster_ra = 37.83\n", - "cluster_dec = 6.98\n", - "\n", - "query = \"SELECT obj.objectId, obj.coord_ra, obj.coord_dec, \" + \\\n", - " \"obj.detect_fromBlend, obj.detect_isIsolated, \" + \\\n", - " \"obj.i_blendedness, obj.i_extendedness, \" + \\\n", - " \"obj.i_kronFlux, obj.i_kronFluxErr, obj.i_kronRad, \" + \\\n", - " \"obj.i_cModelFlux, obj.i_cModelFluxErr, obj.i_gaap1p0Flux, obj.i_gaap3p0Flux, \" + \\\n", - " \"obj.g_gaap1p0Flux, obj.g_gaap3p0Flux, \" + \\\n", - " \"obj.i_kronFlux_flag, obj.i_cModel_flag \" + \\\n", - " \"FROM dp1.Object AS obj \" + \\\n", - " \"WHERE (obj.i_cModelFlux/obj.i_cModelFluxErr > 20) AND \" + \\\n", - " \"(obj.i_extendedness = 1) AND \" + \\\n", - " \"(obj.i_kronFlux_flag = 0) AND (obj.i_cModel_flag = 0) AND \" + \\\n", - " \"CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), \" + \\\n", - " \"CIRCLE('ICRS',\"+str(cluster_ra)+\",\"+str(cluster_dec)+\", 0.2)) = 1 \"\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5973da2a-2a02-4ad0-8415-deccc55bb89c", - "metadata": {}, - "outputs": [], - "source": [ - "job = service.submit_job(query)\n", - "job.run()\n", - "job.wait(phases=['COMPLETED', 'ERROR'])\n", - "print('Job phase is', job.phase)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "18bc593d-bf80-44c1-9a33-158606fa2c8c", - "metadata": {}, - "outputs": [], - "source": [ - "if job.phase == 'ERROR':\n", - " job.raise_if_error()\n", - "assert job.phase == 'COMPLETED'" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "32400242-e8f6-4461-941a-8617f75960de", - "metadata": {}, - "outputs": [], - "source": [ - "results = job.fetch_result()\n", - "tab2 = results.to_table()" - ] - }, - { - "cell_type": "markdown", - "id": "364f5aca-a4f7-4964-94cf-8c157b75f296", - "metadata": {}, - "source": [ - "First, calculate the magnitudes of galaxies in the 'field' location. Then, calculate the magnitudes for the other filters near the galaxy cluster from the query performed in the cell above. This will enable plotting their colors.\n", - "\n", - "> **Warning:** Like in Section 2, the following cell will produce warnings for invalid value encountered in log10, which happens if the source flux is negative. This happens for a small number of objects and since the goal of the plot is to see the distribution of the majority of sources, the warning can be safely ignored. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4fe037fb-3da7-4f82-bdc9-f62c2f701f7f", - "metadata": {}, - "outputs": [], - "source": [ - "g_field_gaap_mag = -2.50 * np.log10(tab['g_gaap1p0Flux']) + 31.4\n", - "i_field_gaap_mag = -2.50 * np.log10(tab['i_gaap1p0Flux']) + 31.4\n", - "i_field_cmodel_mag = -2.50 * np.log10(tab['i_cModelFlux']) + 31.4\n", - "i_cluster_gaap_mag = -2.50 * np.log10(tab2['i_gaap1p0Flux']) + 31.4\n", - "g_cluster_gaap_mag = -2.50 * np.log10(tab2['g_gaap1p0Flux']) + 31.4\n", - "i_cluster_cmodel_mag = -2.50 * np.log10(tab2['i_cModelFlux']) + 31.4" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "450d40b8-3e1d-4e84-81ca-8d882eef7c69", - "metadata": {}, - "outputs": [], - "source": [ - "fig, (ax, ax1) = plt.subplots(ncols=1, nrows=2, figsize=(10, 6))\n", - "\n", - "ax.plot(i_field_cmodel_mag, (g_field_gaap_mag-i_field_gaap_mag),\n", - " '.', alpha=.1, color='blue', label='Field Galaxies (ECDFS)')\n", - "ax.set_xlabel('i-band Magnitude [cModel]')\n", - "ax.set_ylabel('g-i color')\n", - "ax.set_ylim([-1, 4])\n", - "ax.legend()\n", - "\n", - "ax1.plot(i_cluster_cmodel_mag, (g_cluster_gaap_mag-i_cluster_gaap_mag),\n", - " '.', alpha=.1, color='r', label='Cluster Galaxies (Abell 360)')\n", - "ax1.set_xlabel('i-band Magnitude [cModel]')\n", - "ax1.set_ylabel('g-i color')\n", - "ax1.set_ylim([-1, 4])\n", - "ax1.legend()" - ] - }, - { - "cell_type": "markdown", - "id": "b4e3745a-8e04-4243-898c-10c8d25aae4b", - "metadata": {}, - "source": [ - "> Figure 8: The g − i vs. i color-magnitude diagram for galaxies selected in the queries. Top panel shows the galaxies selected from in a random field that does not contain a galaxy cluster (ECDFS). The bottom panel shows galaxies from a field with a galaxy cluster (A360). The cluster galaxies appear as a \"red sequence\" with red i-g colors, because the Balmer / 4000 Angstrom break spectral feature that traces older stars sits between the bands." - ] - }, - { - "cell_type": "markdown", - "id": "f4800e26-7f1f-4b50-bdf5-b3e7bba174c4", - "metadata": {}, - "source": [ - "A very nice red sequence appears from the red, old galaxies in the cluster! " - ] - }, - { - "cell_type": "markdown", - "id": "927a6cd3-5db6-4308-a7a6-2f13ccdb4568", - "metadata": {}, - "source": [ - "## 6. Exercise for the learner\n", - "\n", - "Compare the `_free_cModelFlux` measurements to `_cModelFlux` in the filters that are not the reference band where the `_cModelFlux` was measured (i.e. `refBand`). Investigate how leaving the cModel measurements free differs from the one measured with parameters fixed to the `refBand`, as a function of decreasing signal to noise. As an additional exercise, check how the signal to noise in colors measured using `_gaap1p0Flux` values compare to those measured with the larger 3.0\" aperture, `_gaap3p0Flux`, where the larger aperture may increase the noise. " - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "LSST", - "language": "python", - "name": "lsst" - }, - "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.12.11" - }, - "toc-autonumbering": false - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 554a811400dfd08e295546e49eedcf877392edb8 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Wed, 3 Jun 2026 00:17:05 +0000 Subject: [PATCH 09/27] updating --- .../303_Galaxies/303_3_Color_selections.ipynb | 430 +++--------------- 1 file changed, 75 insertions(+), 355 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index a3e2a029..26c0a070 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -83,9 +83,7 @@ "\n", "Import `pyvo` packages for working with the virtual observatory cutout service.\n", "\n", - "Import `astroquery` to allow access to publicly available external science products (spectroscopic redshift catalogs).\n", - "\n", - "Import the [LSDB package](https://github.com/astronomy-commons/lsdb/) to work with LSDB-formatted files, along with standard astronomy packages and LSST software for data access." + "Import `astroquery` to allow access to publicly available external science products (spectroscopic redshift catalogs).\n" ] }, { @@ -107,9 +105,7 @@ "from lsst.rsp.utils import get_pyvo_auth\n", "\n", "from pyvo.dal.adhoc import SodaQuery, DatalinkResults\n", - "from astroquery.vizier import Vizier\n", - "\n", - "import lsdb" + "from astroquery.vizier import Vizier" ] }, { @@ -229,7 +225,7 @@ "outputs": [], "source": [ "tab = job.fetch_result().to_table()\n", - "print(f\" -> Retrieved {len(tab)} Rubin sources.\")" + "print(f\"Retrieved {len(tab)} galaxies from Rubin imaging.\")" ] }, { @@ -298,12 +294,12 @@ "source": [ "is_z4_lbg = (\n", " (tab['g_minus_r'] > 1.0) & \n", - " (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3) & # should this go before re-assigning upper lims to colors?\n", + " (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3) &\n", " (tab['r_minus_i'] < 1.0) & \n", " (tab['g_minus_r'] > 1.5 * tab['r_minus_i'] + 0.8)\n", ")\n", "\n", - "print(f\" -> Identified {np.sum(is_z4_lbg)} photometric LBG candidates.\")\n" + "print(f\"Identified {np.sum(is_z4_lbg)} photometric LBG candidates.\")\n" ] }, { @@ -364,15 +360,15 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"\\n2. Fetching regional Rubin Photo-z catalog via LSDB...\")\n", - "pz_cat = lsdb.open_catalog(\"/rubin/lsdb_data/object_photoz\")\n", - "# 1800 arcseconds = 0.5 degrees\n", - "pz_regional = pz_cat.cone_search(ra=target_ra, dec=target_dec, radius_arcsec=1800).compute()\n", - "print(f\" -> Found photo-z data for {len(pz_regional)} objects in this region.\")\n", - "\n", - "# Map the photo-z values directly into our main Astropy 'tab'\n", - "pz_series = pz_regional.set_index('objectId')['cmnn_z_mean'] # bpz seems to suck ['bpz_z_mean']\n", - "tab['z_phot'] = pz_series.reindex(tab['objectId']).values" + "# print(\"\\n2. Fetching regional Rubin Photo-z catalog via LSDB...\")\n", + "# pz_cat = lsdb.open_catalog(\"/rubin/lsdb_data/object_photoz\")\n", + "# # 1800 arcseconds = 0.5 degrees\n", + "# pz_regional = pz_cat.cone_search(ra=target_ra, dec=target_dec, radius_arcsec=1800).compute()\n", + "# print(f\" -> Found photo-z data for {len(pz_regional)} objects in this region.\")\n", + "\n", + "# # Map the photo-z values directly into our main Astropy 'tab'\n", + "# pz_series = pz_regional.set_index('objectId')['cmnn_z_mean'] # bpz seems to suck ['bpz_z_mean']\n", + "# tab['z_phot'] = pz_series.reindex(tab['objectId']).values" ] }, { @@ -424,8 +420,6 @@ "source": [ "## 2.3 plot color-color selection\n", "\n", - "Cell 5: Validation Color-Color Plot\n", - "\n", "This visually summarizes everything: your parent Rubin sample, your LBG candidates, and the VANDELS ground-truth objects (color-coded by magnitude).\n", "\n", "First, store some shorthand variables for the color (TBD if you can consolidate this more with above)" @@ -442,7 +436,11 @@ "v_r_minus_i = vandels_in_rubin['r_minus_i']\n", "v_g_minus_r = vandels_in_rubin['g_minus_r']\n", "v_i_mag = vandels_in_rubin['i_mag_robust']\n", - "vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n" + "vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", + "\n", + "# Extract parameters for plotting\n", + "#v_r_minus_i = vandels_in_rubin['r_minus_i']\n", + "#v_g_minus_r = vandels_in_rubin['g_minus_r']\n" ] }, { @@ -474,17 +472,9 @@ "\n", "# --- Colorbar ---\n", "cbar = plt.colorbar(sc2, ax=ax)\n", - "cbar.set_label('i-band [Robust Sersic Mag]', fontsize=12, fontweight='bold')\n", + "cbar.set_label('i-band [Sersic Mag]', fontsize=12, fontweight='bold')\n", "cbar.ax.invert_yaxis()\n", "\n", - "# --- Selection Boundaries (Strict Cut: g-r > 1.5) ---\n", - "#x_diag = np.linspace(0.133, 1.0, 50)\n", - "#y_diag = 1.5 * x_diag + 0.8\n", - "#intersect_x = (1.5 - 0.8) / 1.5\n", - "#ax.plot([-1.5, intersect_x], [1.5, 1.5], color='black', linestyle='--', lw=1.5) \n", - "#ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", - "#ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", - "\n", "\n", "# --- Selection Boundaries (Ono et al. 2018 Cut: g-r > 1.0) ---\n", "# Ono et al. 2018 criteria for z~4 LBGs:\n", @@ -503,14 +493,11 @@ "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", "\n", "\n", - "\n", - "\n", - "# --- Formatting ---\n", "ax.set_xlim(-1.0, 2.0)\n", "ax.set_ylim(-1.0, 4.0)\n", "ax.set_xlabel('$(r - i)$ [AB Mag]', fontsize=14)\n", "ax.set_ylabel('$(g - r)$ [AB Mag]', fontsize=14)\n", - "ax.set_title('Validation of Lyman Break Selection (g-r > 1.5)', fontsize=16, fontweight='bold')\n", + "ax.set_title('Lyman Break Selection (g-r > 1)', fontsize=16, fontweight='bold')\n", "\n", "handles, labels = ax.get_legend_handles_labels()\n", "ax.legend(handles, labels, loc='upper left', framealpha=1)\n", @@ -527,70 +514,13 @@ { "cell_type": "code", "execution_count": null, - "id": "65e165d0-e1da-4ce5-9225-8f47e024bf6d", + "id": "f555b639-0d0c-4826-a7b5-d7e3c2b11c0c", "metadata": {}, "outputs": [], "source": [ "# Extract parameters for plotting\n", "#v_r_minus_i = vandels_in_rubin['r_minus_i']\n", "#v_g_minus_r = vandels_in_rubin['g_minus_r']\n", - "v_z_phot = vandels_in_rubin['z_phot'] # Changed to use photo-z\n", - "vmin, vmax = np.nanmin(v_z_phot), np.nanmax(v_z_phot)\n", - "\n", - "fig, ax = plt.subplots(figsize=(11, 8))\n", - "\n", - "# 1. Background (All Rubin Data)\n", - "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Parent Sample (Rubin)')\n", - "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", - " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates (g-r > 1.5)')\n", - "\n", - "# 2. VANDELS Truth - Missed Sources ('+')\n", - "sc1 = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", - " s=120, c=v_z_phot[failed_lbg], cmap='plasma', vmin=vmin, vmax=vmax, \n", - " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", - " label='VANDELS Truth (Missed)')\n", - "\n", - "# 3. VANDELS Truth - Confirmed Sources ('*')\n", - "sc2 = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", - " s=250, c=v_z_phot[lbg_success_mask], cmap='plasma', vmin=vmin, vmax=vmax, \n", - " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", - " label='Confirmed LBG Candidates')\n", - "\n", - "# --- Colorbar ---\n", - "cbar = plt.colorbar(sc2, ax=ax)\n", - "cbar.set_label('Photometric Redshift (Rubin z_phot)', fontsize=12, fontweight='bold')\n", - "# Inverted Y-axis removed so higher redshift is at the top\n", - "\n", - "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5) \n", - "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", - "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", - "\n", - "\n", - "# --- Formatting ---\n", - "ax.set_xlim(-1.0, 2.0)\n", - "ax.set_ylim(-1.0, 4.0)\n", - "ax.set_xlabel('$(r - i)$ [Sersic Mag]', fontsize=14)\n", - "ax.set_ylabel('$(g - r)$ [Sersic Mag]', fontsize=14)\n", - "ax.set_title('Validation of Lyman Break Selection (Color-Coded by Photo-z)', fontsize=16, fontweight='bold')\n", - "\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "ax.legend(handles, labels, loc='upper left', framealpha=1)\n", - "ax.grid(True, linestyle=':', alpha=0.6)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f555b639-0d0c-4826-a7b5-d7e3c2b11c0c", - "metadata": {}, - "outputs": [], - "source": [ - "# Extract parameters for plotting\n", - "v_r_minus_i = vandels_in_rubin['r_minus_i']\n", - "v_g_minus_r = vandels_in_rubin['g_minus_r']\n", "\n", "# --- CHANGED: Use spectroscopic redshift from the matched VANDELS truth catalog ---\n", "v_z_spec = v_matched_truth['zsp'] \n", @@ -615,29 +545,25 @@ " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", " label='Confirmed LBG Candidates')\n", "\n", - "# --- Colorbar ---\n", + "\n", "cbar = plt.colorbar(sc2, ax=ax)\n", - "# --- CHANGED: Updated label to Spec-z ---\n", "cbar.set_label('Spectroscopic Redshift (VANDELS z_spec)', fontsize=12, fontweight='bold')\n", - "# Inverted Y-axis removed so higher redshift is at the top\n", "\n", - "# --- Selection Boundaries ---\n", - "x_diag = np.linspace(0.133, 1.0, 50)\n", + "# Calculate the new intersection between the horizontal line (g-r = 1.0) and the diagonal\n", + "intersect_x = (1.0 - 0.8) / 1.5 # This equals ~0.133\n", + "x_diag = np.linspace(intersect_x, 1.0, 50)\n", "y_diag = 1.5 * x_diag + 0.8\n", - "intersect_x = (1.5 - 0.8) / 1.5\n", "\n", + "# Draw the boundaries\n", "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5) \n", "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", "\n", - "\n", - "# --- Formatting ---\n", "ax.set_xlim(-1.0, 2.0)\n", "ax.set_ylim(-1.0, 4.0)\n", "ax.set_xlabel('$(r - i)$ [Robust Sersic Mag]', fontsize=14)\n", "ax.set_ylabel('$(g - r)$ [Robust Sersic Mag]', fontsize=14)\n", - "# --- CHANGED: Updated title to Spec-z ---\n", - "ax.set_title('Validation of Strict Lyman Break Selection (Color-Coded by Spec-z)', fontsize=16, fontweight='bold')\n", + "ax.set_title('Validation of Lyman Break Selection', fontsize=16, fontweight='bold')\n", "\n", "handles, labels = ax.get_legend_handles_labels()\n", "ax.legend(handles, labels, loc='upper left', framealpha=1)\n", @@ -701,10 +627,8 @@ " \n", " # Pull data from our aligned tables\n", " z_spec = v_data['zsp'][row_idx]\n", - " z_phot = r_data['z_phot'][row_idx]\n", " g_r = r_data['g_minus_r'][row_idx] \n", " r_i = r_data['r_minus_i'][row_idx]\n", - " z_phot_str = f\"{z_phot:.2f}\" if np.isfinite(z_phot) else \"NaN\"\n", "\n", " query = f\"\"\"\n", " SELECT lsst_band, access_url\n", @@ -745,7 +669,7 @@ " ax.set_xticks([]); ax.set_yticks([])\n", " if row_idx == 0: ax.set_title(f\"{f}-band\", fontsize=15, fontweight='bold')\n", " if col_idx == 0:\n", - " label_str = f\"z_sp: {z_spec:.2f}\\nz_ph: {z_phot_str}\\nID:{obj_id}\\ng-r: {g_r:.2f}\\nr-i={r_i:.2f}\"\n", + " label_str = f\"z_sp: {z_spec:.2f}\\nID:{obj_id}\\ng-r: {g_r:.2f}\\nr-i={r_i:.2f}\"\n", " ax.set_ylabel(label_str, rotation=0, labelpad=70, ha='center', fontweight='bold')\n", "\n", " plt.tight_layout()\n", @@ -761,61 +685,6 @@ "Spec-z histogram of color selected?" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "28a47c0b-ac22-40bc-93d3-f46471382f0f", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "\n", - "print(\"Isolating VANDELS galaxies that passed the Rubin LBG color cut...\")\n", - "\n", - "# Re-apply the Ono et al. 2018 LBG selection mask to the cross-matched catalog\n", - "is_selected_lbg = (\n", - " (matched_rubin_all['g_minus_r'] > 1.0) & \n", - " (matched_rubin_all['u_sersicFlux'] / matched_rubin_all['u_sersicFluxErr'] < 3) & \n", - " (matched_rubin_all['r_minus_i'] < 1.0) & \n", - " (matched_rubin_all['g_minus_r'] > 1.5 * matched_rubin_all['r_minus_i'] + 0.8)\n", - ")\n", - "\n", - "# Extract the true spectroscopic redshifts of ONLY the galaxies inside our color box\n", - "selected_spec_z = matched_v_all['zsp'][is_selected_lbg]\n", - "\n", - "print(f\" -> Found {len(selected_spec_z)} VANDELS sources inside the color selection box.\")\n", - "\n", - "fig, ax = plt.subplots(figsize=(10, 6))\n", - "\n", - "# Define the redshift bins (e.g., from z=0 to z=6.5 in steps of z=0.2)\n", - "z_bins = np.arange(0, 6.6, 0.2)\n", - "\n", - "# Plot the histogram\n", - "ax.hist(selected_spec_z, bins=z_bins, color='dodgerblue', edgecolor='black', alpha=0.8, zorder=3)\n", - "\n", - "# Highlight our target ground-truth window (3.2 <= z <= 4.5)\n", - "ax.axvspan(3.2, 4.5, color='mediumseagreen', alpha=0.2, label='Target Window ($3.5 < z < 4.5$)')\n", - "ax.axvline(3.2, color='darkgreen', linestyle='--', linewidth=1.5, zorder=4)\n", - "ax.axvline(4.5, color='darkgreen', linestyle='--', linewidth=1.5, zorder=4)\n", - "\n", - "# Formatting\n", - "ax.set_xlim(0, 6.5)\n", - "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", - "ax.set_ylabel('Number of Selected Candidates', fontsize=14)\n", - "ax.set_title('True Redshift Distribution of LBG Candidates (g-dropout)', fontsize=16, fontweight='bold')\n", - "\n", - "ax.legend(loc='upper right', fontsize=12, framealpha=1)\n", - "ax.grid(axis='y', linestyle=':', alpha=0.7, zorder=0)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# andres added some things about the g-band leak to the documentation. can cite that dp1. then change it for dp2 updated nb\n", - "# rthat is def not expected to be a problem for dp2\n", - "# it was something related to camera temperature. \n" - ] - }, { "cell_type": "markdown", "id": "e855ba72-793a-47d1-8871-1ca6faac0246", @@ -832,7 +701,7 @@ "outputs": [], "source": [ "# Execute the plots\n", - "plot_soda_cutouts_with_pz(missed_r_data, missed_v_truth, n_max=10, title_label=\"Missed VANDELS Truth\")\n" + "plot_soda_cutouts_with_pz(missed_r_data, missed_v_truth, n_max=20, title_label=\"Missed VANDELS Truth\")\n" ] }, { @@ -855,32 +724,18 @@ "plot_soda_cutouts_with_pz(\n", " confirmed_r_data, \n", " confirmed_v_truth, \n", - " n_max=10, \n", + " n_max=20, \n", " title_label=\"Confirmed LBG Selection (True Positives)\"\n", ")" ] }, - { - "cell_type": "markdown", - "id": "8b7702fb-ec6d-4776-8559-6d0b663f015d", - "metadata": {}, - "source": [ - "## 4. Photo-z validation\n", - "\n", - "Do some photo-z validation " - ] - }, { "cell_type": "code", "execution_count": null, - "id": "11096ef6-e3a3-41ad-857a-7372844cf606", + "id": "dcfaa77a-2731-433b-9f74-537272881fb2", "metadata": {}, "outputs": [], "source": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "from astropy.coordinates import SkyCoord\n", - "import astropy.units as u\n", "\n", "print(\"1. Isolating all high-quality VANDELS spectra...\")\n", "# Keep all redshifts with quality flag >= 3 (standard for secure spec-z)\n", @@ -898,203 +753,71 @@ "matched_rubin_all = tab[idx_rubin_all[match_mask_all]]\n", "matched_v_all = vandels_all_hq[match_mask_all]\n", "\n", - "# Extract redshifts and i-band magnitude\n", "z_spec_all = matched_v_all['zsp']\n", - "z_phot_all = matched_rubin_all['z_phot']\n", "i_mag_all = matched_rubin_all['i_mag_robust']\n", - "\n", - "# Clean out any rows where the photo-z pipeline failed (returned NaN)\n", - "valid_pz = ~np.isnan(z_phot_all) & ~np.isnan(z_spec_all) & ~np.isnan(i_mag_all)\n", - "z_spec_clean = z_spec_all[valid_pz]\n", - "z_phot_clean = z_phot_all[valid_pz]\n", - "i_mag_clean = i_mag_all[valid_pz]\n", - "\n", - "print(f\" -> Found {len(z_spec_clean)} global matches with valid Photo-z and Spec-z.\")\n", - "\n", - "# --- 3. Build the Plot ---\n", - "fig, ax = plt.subplots(figsize=(10, 8))\n", - "\n", - "# Scatter plot: Color-coded by i-band magnitude\n", - "sc = ax.scatter(z_spec_clean, z_phot_clean, c=i_mag_clean, cmap='viridis', \n", - " s=25, alpha=0.8, edgecolor='k', linewidth=0.5, zorder=5)\n", - "\n", - "# Add the colorbar\n", - "cbar = plt.colorbar(sc, ax=ax)\n", - "cbar.set_label('i-band [Robust Sersic Mag]', fontsize=12, fontweight='bold')\n", - "cbar.ax.invert_yaxis() # Invert so brighter (smaller number) is at the top\n", - "\n", - "# Perfect agreement line (1:1)\n", - "z_line = np.linspace(0, 7, 100)\n", - "ax.plot(z_line, z_line, color='black', linestyle='--', linewidth=2, label='1:1 Agreement')\n", - "\n", - "# Catastrophic outlier boundaries\n", - "# The standard definition in astronomy is |dz| / (1+z) > 0.15\n", - "ax.plot(z_line, z_line + 0.15*(1+z_line), color='red', linestyle=':', label='Outlier Boundary ($|\\Delta z| > 0.15(1+z)$)')\n", - "ax.plot(z_line, z_line - 0.15*(1+z_line), color='red', linestyle=':')\n", - "\n", - "# Formatting\n", - "ax.set_xlim(0, 6.5)\n", - "ax.set_ylim(0, 6.5)\n", - "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", - "ax.set_ylabel('Photometric Redshift (Rubin bpz_z_mean)', fontsize=14)\n", - "ax.set_title('Global Validation: Rubin Photo-z vs. VANDELS Spec-z', fontsize=16, fontweight='bold')\n", - "\n", - "handles, labels = ax.get_legend_handles_labels()\n", - "ax.legend(handles, labels, loc='upper left', frameon=True)\n", - "ax.grid(True, linestyle=':', alpha=0.6)\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# --- 4. Calculate Standard Photo-z Quality Metrics ---\n", - "if len(z_spec_clean) > 0:\n", - " dz = (z_phot_clean - z_spec_clean) / (1 + z_spec_clean)\n", - " \n", - " # NMAD: Normalized Median Absolute Deviation (A robust measure of scatter)\n", - " nmad = 1.48 * np.median(np.abs(dz - np.median(dz)))\n", - " \n", - " # Outlier Fraction: Percentage of objects outside the red dotted lines\n", - " outlier_fraction = np.sum(np.abs(dz) > 0.15) / len(dz)\n", - " \n", - " print(f\"--- Global Photo-z Performance Metrics ---\")\n", - " print(f\"Robust Scatter (\\u03c3_NMAD): {nmad:.3f}\")\n", - " print(f\"Catastrophic Outlier Fraction: {outlier_fraction:.1%}\")" + "obj_ids_all = matched_rubin_all['objectId']" ] }, { "cell_type": "markdown", - "id": "f84560ee-c33a-45b6-b8b9-137cac8adc21", + "id": "773d1887-6234-45e3-949e-c1055e65ff60", "metadata": {}, "source": [ - "A quick test to decide which photo-z measurement performs best at z>3" + "make spec-z histogram?" ] }, { "cell_type": "code", "execution_count": null, - "id": "05d839a7-d226-4334-81d3-97fae5246d92", + "id": "28a47c0b-ac22-40bc-93d3-f46471382f0f", "metadata": {}, "outputs": [], "source": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import math\n", - "from astropy.coordinates import SkyCoord\n", - "import astropy.units as u\n", "\n", - "print(\"1. Isolating all high-quality VANDELS spectra...\")\n", - "# Keep all redshifts with quality flag >= 3 (standard for secure spec-z)\n", - "is_vandels_hq = vandels_cdfs['q_zsp'] >= 3\n", - "vandels_all_hq = vandels_cdfs[is_vandels_hq]\n", "\n", - "print(\"2. Cross-matching to the Rubin Object Table...\")\n", - "coord_v_all = SkyCoord(ra=vandels_all_hq['RAJ2000'], dec=vandels_all_hq['DEJ2000'], unit='deg')\n", - "coord_r = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", + "print(\"Isolating VANDELS galaxies that passed the Rubin LBG color cut...\")\n", "\n", - "idx_rubin_all, d2d_all, _ = coord_v_all.match_to_catalog_sky(coord_r)\n", - "match_mask_all = d2d_all < 1.0 * u.arcsec\n", + "# Re-apply the Ono et al. 2018 LBG selection mask to the cross-matched catalog\n", + "is_selected_lbg = (\n", + " (matched_rubin_all['g_minus_r'] > 1.0) & \n", + " (matched_rubin_all['u_sersicFlux'] / matched_rubin_all['u_sersicFluxErr'] < 3) & \n", + " (matched_rubin_all['r_minus_i'] < 1.0) & \n", + " (matched_rubin_all['g_minus_r'] > 1.5 * matched_rubin_all['r_minus_i'] + 0.8)\n", + ")\n", "\n", - "# Extract the matched data\n", - "matched_rubin_all = tab[idx_rubin_all[match_mask_all]]\n", - "matched_v_all = vandels_all_hq[match_mask_all]\n", + "# Extract the true spectroscopic redshifts of ONLY the galaxies inside our color box\n", + "selected_spec_z = matched_v_all['zsp'][is_selected_lbg]\n", "\n", - "z_spec_all = matched_v_all['zsp']\n", - "i_mag_all = matched_rubin_all['i_mag_robust']\n", - "obj_ids_all = matched_rubin_all['objectId']\n", - "\n", - "# --- 3. Identify Available Photo-z Algorithms in LSDB ---\n", - "print(\"3. Scanning LSDB for available Photo-z columns...\")\n", - "\n", - "# Dynamically find ANY column that is a photo-z mean or mode estimate\n", - "available_pz_cols = [col for col in pz_regional.columns if ('z_mean' in col.lower() or 'z_median' in col.lower())]\n", - "\n", - "# Fallback just in case nothing matches\n", - "#if not available_pz_cols:\n", - "# available_pz_cols = ['bpz_z_mean']\n", - "\n", - "print(f\" -> Comparing {len(available_pz_cols)} measurements: {available_pz_cols}\")\n", - "\n", - "# Set up index lookup for fast mapping from the LSDB dataframe\n", - "pz_regional_indexed = pz_regional.set_index('objectId')\n", - "\n", - "# --- 4. Build the 3-Row Multi-Panel Plot ---\n", - "# Calculate columns and rows for the layout (Targeting 3 rows)\n", - "n_plots = len(available_pz_cols)\n", - "n_rows = min(3, n_plots) # Use up to 3 rows\n", - "n_cols = math.ceil(n_plots / n_rows)\n", - "\n", - "# Size the figure dynamically based on the grid shape\n", - "fig, axes = plt.subplots(n_rows, n_cols, figsize=(6 * n_cols, 5 * n_rows))\n", - "\n", - "# Flatten the axes array for easy 1D iteration\n", - "if isinstance(axes, np.ndarray):\n", - " axes_flat = axes.flatten()\n", - "else:\n", - " axes_flat = [axes]\n", - "\n", - "for i, pz_col in enumerate(available_pz_cols):\n", - " ax = axes_flat[i]\n", - " \n", - " # Extract photo-z for the specific algorithm\n", - " z_phot_all = pz_regional_indexed.reindex(obj_ids_all)[pz_col].values\n", - " \n", - " # Clean out any rows where this specific pipeline failed (returned NaN)\n", - " valid_pz = ~np.isnan(z_phot_all) & ~np.isnan(z_spec_all) & ~np.isnan(i_mag_all)\n", - " z_s = z_spec_all[valid_pz]\n", - " z_p = z_phot_all[valid_pz]\n", - " i_m = i_mag_all[valid_pz]\n", - " \n", - " # Scatter plot: Color-coded by i-band magnitude\n", - " sc = ax.scatter(z_s, z_p, c=i_m, cmap='viridis', \n", - " s=25, alpha=0.8, edgecolor='k', linewidth=0.5, zorder=5)\n", - " \n", - " # Perfect agreement line (1:1)\n", - " z_line = np.linspace(0, 7, 100)\n", - " ax.plot(z_line, z_line, color='black', linestyle='--', linewidth=2, label='1:1 Agreement')\n", - " \n", - " # Catastrophic outlier boundaries\n", - " ax.plot(z_line, z_line + 0.15*(1+z_line), color='red', linestyle=':')\n", - " ax.plot(z_line, z_line - 0.15*(1+z_line), color='red', linestyle=':')\n", - " \n", - " # Formatting\n", - " ax.set_xlim(0, 6.5)\n", - " ax.set_ylim(0, 6.5)\n", - " ax.set_xlabel('VANDELS z_spec', fontsize=13)\n", - " \n", - " # Add Y-labels only to the leftmost plot of each row\n", - " if i % n_cols == 0:\n", - " ax.set_ylabel('Rubin z_phot', fontsize=13)\n", - " \n", - " ax.set_title(f'{pz_col}', fontsize=14, fontweight='bold')\n", - " \n", - " # Calculate & display Standard Photo-z Quality Metrics on the plot\n", - " if len(z_s) > 0:\n", - " dz = (z_p - z_s) / (1 + z_s)\n", - " nmad = 1.48 * np.median(np.abs(dz - np.median(dz)))\n", - " outlier_fraction = np.sum(np.abs(dz) > 0.15) / len(dz)\n", - " \n", - " # Add a text box with the statistics\n", - " textstr = f\"Matches: {len(z_s)}\\n$\\sigma_{{NMAD}}$: {nmad:.3f}\\nOutliers: {outlier_fraction:.1%}\"\n", - " props = dict(boxstyle='round', facecolor='white', alpha=0.9, edgecolor='gray')\n", - " ax.text(0.05, 0.95, textstr, transform=ax.transAxes, fontsize=11,\n", - " verticalalignment='top', bbox=props)\n", - "\n", - "# Hide any empty subplots if there are blank spaces in the grid\n", - "for j in range(n_plots, len(axes_flat)):\n", - " axes_flat[j].set_visible(False)\n", - "\n", - "# --- 5. Custom Colorbar Placement ---\n", - "# Adjust the subplots to leave exactly 15% of the figure width empty on the right side\n", - "plt.subplots_adjust(top=0.90, right=0.85, wspace=0.2, hspace=0.35)\n", - "\n", - "# Add a dedicated axis for the colorbar [left, bottom, width, height]\n", - "cbar_ax = fig.add_axes([0.88, 0.15, 0.02, 0.7])\n", - "cbar = fig.colorbar(sc, cax=cbar_ax)\n", - "cbar.set_label('i-band [Sersic Mag]', fontsize=12, fontweight='bold')\n", - "cbar.ax.invert_yaxis() \n", + "print(f\" -> Found {len(selected_spec_z)} VANDELS sources inside the color selection box.\")\n", "\n", - "plt.suptitle('Multi-Code Validation: Rubin Photo-z vs. VANDELS Spec-z', fontsize=18, fontweight='bold')\n", - "plt.show()" + "fig, ax = plt.subplots(figsize=(10, 6))\n", + "\n", + "# Define the redshift bins (e.g., from z=0 to z=6.5 in steps of z=0.2)\n", + "z_bins = np.arange(0, 6.6, 0.2)\n", + "\n", + "# Plot the histogram\n", + "ax.hist(selected_spec_z, bins=z_bins, color='dodgerblue', edgecolor='black', alpha=0.8, zorder=3)\n", + "\n", + "# Highlight our target ground-truth window (3.2 <= z <= 4.5)\n", + "ax.axvspan(3.2, 4.5, color='mediumseagreen', alpha=0.2, label='Selection Window ($3.2 < z < 4.5$)')\n", + "ax.axvline(3.2, color='darkgreen', linestyle='--', linewidth=1.5, zorder=4)\n", + "ax.axvline(4.5, color='darkgreen', linestyle='--', linewidth=1.5, zorder=4)\n", + "\n", + "# Formatting\n", + "ax.set_xlim(0, 6.5)\n", + "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", + "ax.set_ylabel('Number of Selected Candidates', fontsize=14)\n", + "ax.set_title('True Redshift Distribution of LBG Candidates (g-dropout)', fontsize=16, fontweight='bold')\n", + "\n", + "ax.legend(loc='upper right', fontsize=12, framealpha=1)\n", + "ax.grid(axis='y', linestyle=':', alpha=0.7, zorder=0)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "# andres added some things about the g-band leak to the documentation. can cite that dp1. then change it for dp2 updated nb\n", + "# rthat is def not expected to be a problem for dp2\n", + "# it was something related to camera temperature. \n" ] }, { @@ -1114,9 +837,6 @@ "metadata": {}, "outputs": [], "source": [ - "#import numpy as np\n", - "#from astropy.coordinates import SkyCoord\n", - "#import astropy.units as u\n", "\n", "print(\"--- Calculating DP1 LBG Selection Metrics (Completeness & Purity) ---\")\n", "\n", From 7a5670f1148e3499738301444d6154858b61616f Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Wed, 3 Jun 2026 17:48:23 +0000 Subject: [PATCH 10/27] updating colors nb --- .../303_Galaxies/303_3_Color_selections.ipynb | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 26c0a070..05a4b5a7 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -31,14 +31,14 @@ "id": "63df5e4e-1960-4622-8aab-ec4ad076c33b", "metadata": {}, "source": [ - "**Learning objective:** Explore high redshift galaxy selections with DP1.\n", + "**Learning objective:** Explore high redshift galaxy color selection with DP1.\n", "\n", "**LSST data products:** `Object` table, `deep_coadd` images\n", "\n", "**Packages:** `lsst.rsp.get_tap_service `\n", "\n", "**Credit:**\n", - "This notebook benefitted from ... \n", + "This notebook benefited from discussions with Dan Taranu, John Franklin Crenshaw, and the Rubin LSST photometric redshift commissioning team. \n", "\n", "**Get Support:**\n", "Everyone is encouraged to ask questions or raise issues in the \n", @@ -573,6 +573,14 @@ "plt.show()" ] }, + { + "cell_type": "markdown", + "id": "2f0b8d97-06de-4226-b21b-782f7cbe56c5", + "metadata": {}, + "source": [ + "The color selection identifies a large number of true high-redshift galaxies. A number of confirmed galaxies fall outside the selection window. While the color selection is not designed to be 100% inclusive of high redshift galaxies, it should select a relatively pure sample with few interlopers. Galaxies my reside outside the selection box due to photometric scatter, dust attenuation in the galaxy reddening the restframe UV probed by the r-i color and similarly decreasing the brightness of the observed r band flux (thus making the g-r color less robustly constrained). A possible effect from DP1 could also be the known issue of a small fraction of red-wavelength photon leak in the g-band which might contaminate the dropout filter with redder-wavelength light from the galaxy. This effect is exacerbated by the higher operating temperature of LSSTComCam during commissioning and is expected to be resolved in DP2 LSSTCam data.\n" + ] + }, { "cell_type": "markdown", "id": "fbff5f57-9f6e-4847-84c3-582083035bf2", @@ -580,8 +588,6 @@ "source": [ "# 3. Visual inspection\n", "\n", - "Cell 6: Visual Inspection with SODA\n", - "\n", "Finally, we pull the image cutouts directly from the Rubin archives for the missed and confirmed subsets to inspect the pixels." ] }, @@ -600,6 +606,14 @@ "confirmed_r_data = vandels_in_rubin[lbg_success_mask]\n" ] }, + { + "cell_type": "markdown", + "id": "85a038df-d0e7-49ef-81f8-97a5bbb9bd76", + "metadata": {}, + "source": [ + "Define a function to generate 4-filter cutouts for visual inspection." + ] + }, { "cell_type": "code", "execution_count": null, @@ -607,8 +621,7 @@ "metadata": {}, "outputs": [], "source": [ - "# --- SODA Plotting Function ---\n", - "def plot_soda_cutouts_with_pz(r_data, v_data, n_max=10, title_label=\"Candidate\"):\n", + "def plot_cutouts(r_data, v_data, n_max=10, title_label=\"Candidate\"):\n", " n_plot = min(len(r_data), n_max)\n", " if n_plot == 0:\n", " print(f\"No sources to plot for {title_label}.\")\n", @@ -701,7 +714,7 @@ "outputs": [], "source": [ "# Execute the plots\n", - "plot_soda_cutouts_with_pz(missed_r_data, missed_v_truth, n_max=20, title_label=\"Missed VANDELS Truth\")\n" + "plot_cutouts(missed_r_data, missed_v_truth, n_max=20, title_label=\"Missed VANDELS Truth\")\n" ] }, { @@ -721,7 +734,7 @@ "print(f\"Total confirmed VANDELS LBGs available to plot: {len(confirmed_r_data)}\")\n", "\n", "# Execute the plotter specifically for the confirmed overlap\n", - "plot_soda_cutouts_with_pz(\n", + "plot_cutouts(\n", " confirmed_r_data, \n", " confirmed_v_truth, \n", " n_max=20, \n", From d0d21a6238f2e2f634a0d30de26b0fa7bbd3cc61 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Wed, 3 Jun 2026 17:51:02 +0000 Subject: [PATCH 11/27] updating colors nb --- .../303_Galaxies/303_3_Color_selections.ipynb | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 05a4b5a7..512cd1ef 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -518,11 +518,6 @@ "metadata": {}, "outputs": [], "source": [ - "# Extract parameters for plotting\n", - "#v_r_minus_i = vandels_in_rubin['r_minus_i']\n", - "#v_g_minus_r = vandels_in_rubin['g_minus_r']\n", - "\n", - "# --- CHANGED: Use spectroscopic redshift from the matched VANDELS truth catalog ---\n", "v_z_spec = v_matched_truth['zsp'] \n", "vmin, vmax = np.nanmin(v_z_spec), np.nanmax(v_z_spec)\n", "\n", @@ -690,14 +685,6 @@ "\n" ] }, - { - "cell_type": "markdown", - "id": "965fe3c3-5d32-42a6-b2cf-260a8275af44", - "metadata": {}, - "source": [ - "Spec-z histogram of color selected?" - ] - }, { "cell_type": "markdown", "id": "e855ba72-793a-47d1-8871-1ca6faac0246", @@ -826,11 +813,7 @@ "ax.grid(axis='y', linestyle=':', alpha=0.7, zorder=0)\n", "\n", "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "# andres added some things about the g-band leak to the documentation. can cite that dp1. then change it for dp2 updated nb\n", - "# rthat is def not expected to be a problem for dp2\n", - "# it was something related to camera temperature. \n" + "plt.show()\n" ] }, { From 683d37364d3f9936e9318d38d9e522e28b0c1556 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Wed, 3 Jun 2026 21:09:48 +0000 Subject: [PATCH 12/27] updating colors nb --- .../303_Galaxies/303_3_Color_selections.ipynb | 70 ++++++++----------- 1 file changed, 29 insertions(+), 41 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 512cd1ef..8759aee6 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -56,10 +56,9 @@ "\n", "Color selections have served as a key method of identifying galaxies of different populations over decades. Especially at redshift z > 2.5, the Lyman-break is a strong spectral feature that is exploited to identify galaxies at high redshift. Lyman-break selections make use of the fact that intergalactic hydrogen in the foreground absorbs all the light of background galaxies that is emitted blueward of the Lyman limit (912A) or at very high redshifts, Lyman-alpha (1216A). More details about why this works can be found at this blog-post. \n", "\n", - "Such galaxies can be identified by their very red colors between filters that bridge the Lyman break feature. Since intergalactic hydrogen absorbs all the light blueward of the Lyman break, true z > 3 galaxies should be undetected in the LSST u-band, and at z > 4 undetected in the LSST g-band.\n", + "Such galaxies can be identified by their very red colors between filters that bridge the Lyman break feature. Since intergalactic hydrogen absorbs the light blueward of the Lyman break, true z > 3 galaxies should be undetected in the LSST u-band, and at z > 4 undetected in the LSST g-band.\n", "\n", - "This notebook demonstrates this color selection on DP1 data for galaxies at 3.5 < z < 4.5 as an example, and provides some validation metrics for its performance. It makes use of color selections defined and used in the literature with data from facilities with similar filtersets (bandpass shapes and effective wavelengths). These are using the Canada-France-Hawaii Telescope Legacy Survey (CFHTLS) as presented in Hildebrandt et al., 2009 and van der Burg et al., 2010. A similar selection was performed using Subaru Hyper-Suprime Cam data in the GOLDRUSH survey Ono et al. 2018\n", - "\n" + "This notebook demonstrates this color selection on DP1 data for galaxies at 3 < z < 4.5 as an example, and provides some validation metrics for its performance. It makes use of color selections defined and used in the literature with data from facilities with similar filter sets (band pass shapes and effective wavelengths). These are using the Canada-France-Hawaii Telescope Legacy Survey (CFHTLS) as presented in Hildebrandt et al., 2009 and van der Burg et al., 2010. A similar selection was performed using Subaru Hyper-Suprime Cam data in the GOLDRUSH survey Ono et al. 2018\n" ] }, { @@ -143,7 +142,9 @@ "id": "5a454c77-f8b1-41ca-ac25-290df2c557a7", "metadata": {}, "source": [ - "Set the target field to be the ECDFS, where many spectroscopic redshift data exist." + "Set the target field to be the ECDFS, where many spectroscopic redshift data exist.\n", + "\n", + "IS THIS THE CENTER?:" ] }, { @@ -154,7 +155,7 @@ "outputs": [], "source": [ "target_ra = 53.125\n", - "target_dec = -27.8" + "target_dec = -28.1" ] }, { @@ -162,7 +163,12 @@ "id": "e9c07b17-bc81-42e2-991c-0ab3a7d30eb8", "metadata": {}, "source": [ - "Define a query to retrieve galaxies in this field using an 0.2 degree radius from the object table using the `extendedness`=1 flag. To ensure good detections, include the $S/N > 10$ cut on the $i$-band." + "Define a query to retrieve galaxies from the object table using the `extendedness`=1 flag. Search around the center of the field using an 0.2 degree search radius to ensure the candidates are identified within the deepest area of g-band imaging. To further ensure good detections, include the $S/N > 10$ cut on the $i$-band.\n", + "\n", + "NOTES:\n", + "note: could these below horizontal line be in a shallow are of g? Could be a data thing\n", + "use the survey depth map to cut out the edges. or use a smaller search radius from the center. survey property maps will show\n", + "depth at given location and use that instead of the \n" ] }, { @@ -183,7 +189,7 @@ " AND (obj.i_extendedness = 1) \n", " AND (obj.sersic_no_data_flag = 0) \n", " AND (obj.i_cModel_flag = 0) \n", - " AND CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), CIRCLE('ICRS', {target_ra}, {target_dec}, 0.2)) = 1\n", + " AND CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), CIRCLE('ICRS', {target_ra}, {target_dec}, 0.5)) = 1\n", "\"\"\"" ] }, @@ -270,7 +276,8 @@ "outputs": [], "source": [ "tab['g_minus_r'] = tab['g_mag_robust'] - tab['r_mag_robust']\n", - "tab['r_minus_i'] = tab['r_mag_robust'] - tab['i_mag_robust']" + "tab['r_minus_i'] = tab['r_mag_robust'] - tab['i_mag_robust']\n", + "\n" ] }, { @@ -343,34 +350,6 @@ "print(f\" -> Found {len(vandels_truth)} high-confidence VANDELS sources at z~4\")\n" ] }, - { - "cell_type": "markdown", - "id": "a528f722-9ff5-4fbc-903c-fe91da18cdbc", - "metadata": {}, - "source": [ - "#### 2.2.2 Photo-z catalog\n", - "\n", - "Now fetch the photo-z catalog that was measured by commissioning team for DP1. See notebook 310.1. Take my word for it that the cmnn measurements perform best at z>3." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "69903bab-db67-4728-8647-f81f62c1ba6e", - "metadata": {}, - "outputs": [], - "source": [ - "# print(\"\\n2. Fetching regional Rubin Photo-z catalog via LSDB...\")\n", - "# pz_cat = lsdb.open_catalog(\"/rubin/lsdb_data/object_photoz\")\n", - "# # 1800 arcseconds = 0.5 degrees\n", - "# pz_regional = pz_cat.cone_search(ra=target_ra, dec=target_dec, radius_arcsec=1800).compute()\n", - "# print(f\" -> Found photo-z data for {len(pz_regional)} objects in this region.\")\n", - "\n", - "# # Map the photo-z values directly into our main Astropy 'tab'\n", - "# pz_series = pz_regional.set_index('objectId')['cmnn_z_mean'] # bpz seems to suck ['bpz_z_mean']\n", - "# tab['z_phot'] = pz_series.reindex(tab['objectId']).values" - ] - }, { "cell_type": "markdown", "id": "fe011d0d-4077-402c-be5d-176d23c33439", @@ -399,6 +378,10 @@ "idx_rubin, d2d, _ = coord_v.match_to_catalog_sky(coord_r)\n", "match_mask = d2d < 1.0 * u.arcsec\n", "\n", + "print(np.min(tab['coord_ra'][idx_rubin]), np.max(tab['coord_ra'][idx_rubin]))\n", + "print(np.min(tab['coord_dec'][idx_rubin]), np.max(tab['coord_dec'][idx_rubin]))\n", + " \n", + "\n", "# Isolate the matched sources\n", "matched_rubin_indices = idx_rubin[match_mask]\n", "vandels_in_rubin = tab[matched_rubin_indices]\n", @@ -505,10 +488,7 @@ "\n", "plt.tight_layout()\n", "plt.show()\n", - "\n", - "# note: could these below horizontal line be in a shallow are of g? Could be a data thing\n", - "# use the survey depth map to cut out the edges. or use a smaller search radius from the center. survey property maps will show\n", - "# depth at given location and use that instead of the \n" + "\n" ] }, { @@ -729,6 +709,14 @@ ")" ] }, + { + "cell_type": "markdown", + "id": "1b5c1515-47a2-4cfa-b9f2-60acadb4daa9", + "metadata": {}, + "source": [ + "Below, use only the spectra which have a high quality flag (3 or 4) corresponding to a secure spectroscopic redshift measurement (see PAPER). ALSO I THINK YOU WANT TO DO THIS ABOVE, NOT HERE..." + ] + }, { "cell_type": "code", "execution_count": null, @@ -883,7 +871,7 @@ { "cell_type": "code", "execution_count": null, - "id": "39d7a901-d2a4-4e92-96e1-acbe8d263d0f", + "id": "1cf7f40e-4f13-4217-bd71-5b6342dac78e", "metadata": {}, "outputs": [], "source": [] From 6a534d7b52d521511aad227844809473ea2b6ef7 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Wed, 3 Jun 2026 23:34:15 +0000 Subject: [PATCH 13/27] updating color nb --- .../303_Galaxies/303_3_Color_selections.ipynb | 164 ++++++++++-------- 1 file changed, 96 insertions(+), 68 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 8759aee6..1398ce53 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -142,9 +142,7 @@ "id": "5a454c77-f8b1-41ca-ac25-290df2c557a7", "metadata": {}, "source": [ - "Set the target field to be the ECDFS, where many spectroscopic redshift data exist.\n", - "\n", - "IS THIS THE CENTER?:" + "Set the target field to be the ECDFS, where many spectroscopic redshift data exist." ] }, { @@ -239,7 +237,7 @@ "id": "34047a4c-0412-4944-9c19-8dd14d6edf03", "metadata": {}, "source": [ - "Galaxy colors may be inaccurate for galaxies whose S/N is very low in one or more filters. To ensure that (in particular) the dropout color is robust, if the S/N is less than 1 then set the flux to the flux error (this will use the 1-sigma lower limit to the color, replacing flux with the error floor if S/N < 1). " + "Galaxy colors may be inaccurate for galaxies whose S/N is very low in one or more filters. To ensure that (in particular) the dropout color is robust, if the S/N is less than 1 then set the flux to the flux error (this will use the 1-sigma lower limit to the color, replacing flux with the error floor if S/N < 1). Convert the nJy flux to ABmag, using definition of -2.5 * log10(nJy) + 31.4." ] }, { @@ -250,14 +248,13 @@ "outputs": [], "source": [ "filters = ['u', 'g', 'r', 'i']\n", - "zp = 31.4\n", "\n", "with np.errstate(divide='ignore', invalid='ignore'):\n", " for f in filters:\n", " flux_robust = np.where(tab[f'{f}_sersicFlux'] < tab[f'{f}_sersicFluxErr'], \n", " tab[f'{f}_sersicFluxErr'], \n", " tab[f'{f}_sersicFlux'])\n", - " tab[f'{f}_mag_robust'] = -2.50 * np.log10(flux_robust) + zp\n" + " tab[f'{f}_mag_robust'] = -2.50 * np.log10(flux_robust) + 31.4\n" ] }, { @@ -276,8 +273,7 @@ "outputs": [], "source": [ "tab['g_minus_r'] = tab['g_mag_robust'] - tab['r_mag_robust']\n", - "tab['r_minus_i'] = tab['r_mag_robust'] - tab['i_mag_robust']\n", - "\n" + "tab['r_minus_i'] = tab['r_mag_robust'] - tab['i_mag_robust']" ] }, { @@ -285,7 +281,7 @@ "id": "8baf7434-aee5-459b-8282-4926978dc4ce", "metadata": {}, "source": [ - "### 2.1 perform the LBG color selection\n", + "### 2.1 LBG color selection\n", "\n", "Now, perform the color selection to identify the high-redshift galaxy candidates. Use a typical Lyman Break Selection for a camera with similar filter properties to the LSST (e.g. Ono et al. 2018) which require very red g-r colors (to identify galaxies with strong lyman breaks), and relatively blue r-i colors (which excludes stars). \n", "\n", @@ -314,9 +310,9 @@ "id": "e3e6685e-98a1-4612-9869-082ecdab43af", "metadata": {}, "source": [ - "### 2.2 Fetch validation data \n", + "### 2.2 Validation data \n", "\n", - "#### 2.2.1 First fetch a spec-z catalog\n", + "#### 2.2.1 Fetch spec-z catalog\n", "\n", "This will serve as validation" ] @@ -357,9 +353,7 @@ "source": [ "#### 2.2.3 Cross-match\n", "\n", - "Cell 4: Lyman Break Selection & Cross-Matching\n", - "\n", - "Here we perform the strict LBG selection on the Rubin data, then match it against the VANDELS truth catalog to see what passed and what failed" + "Here we perform the LBG selection on the Rubin data, then match it against the VANDELS truth catalog to see what passed and what failed" ] }, { @@ -405,7 +399,7 @@ "\n", "This visually summarizes everything: your parent Rubin sample, your LBG candidates, and the VANDELS ground-truth objects (color-coded by magnitude).\n", "\n", - "First, store some shorthand variables for the color (TBD if you can consolidate this more with above)" + "First, store some shorthand parameters for the color (TBD if you can consolidate this more with above)" ] }, { @@ -415,15 +409,42 @@ "metadata": {}, "outputs": [], "source": [ - "# Extract parameters for plotting\n", "v_r_minus_i = vandels_in_rubin['r_minus_i']\n", "v_g_minus_r = vandels_in_rubin['g_minus_r']\n", "v_i_mag = vandels_in_rubin['i_mag_robust']\n", - "vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", - "\n", - "# Extract parameters for plotting\n", - "#v_r_minus_i = vandels_in_rubin['r_minus_i']\n", - "#v_g_minus_r = vandels_in_rubin['g_minus_r']\n" + "v_z_spec = v_matched_truth['zsp'] \n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "b381133b-22e6-46e1-957e-75a62d1b6c6e", + "metadata": {}, + "source": [ + "Also, use the selection criteria for z~4 LBGs defined in Ono et al. 2018 :\n", + "1. g - r > 1.0\n", + "2. r - i < 1.0\n", + "3. g - r > 1.5 * (r - i) + 0.8" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea040183-435e-4029-9dac-6b214fe9b9f7", + "metadata": {}, + "outputs": [], + "source": [ + "intersect_x = (1.0 - 0.8) / 1.5\n", + "x_diag = np.linspace(intersect_x, 1.0, 50)\n", + "y_diag = 1.5 * x_diag + 0.8" + ] + }, + { + "cell_type": "markdown", + "id": "ef3b6dac-ec19-4f3c-9d61-ff9002385247", + "metadata": {}, + "source": [ + "Define a figure and plot all the Rubin galaxies from the query (gray), all Rubin galaxies that satisfy the LBG color selection (blue), and the true spectroscopically confirmed high-redshift galaxies as bold colored symbols. Stars indicate the true high-redshift galaxies that meet the color selection and plus signs are the true high-redshift galaxies that do not. " ] }, { @@ -433,49 +454,32 @@ "metadata": {}, "outputs": [], "source": [ - "\n", "fig, ax = plt.subplots(figsize=(11, 8))\n", "\n", - "# 1. Background (All Rubin Data)\n", - "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Parent Sample (Rubin)')\n", + "vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", + "\n", + "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Rubin Parent Sample')\n", "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", - " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates (g-r > 1.5)')\n", + " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates')\n", "\n", - "# 2. VANDELS Truth - Missed Sources ('+')\n", - "sc1 = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", + "sc = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", " s=120, c=v_i_mag[failed_lbg], cmap='viridis', vmin=vmin, vmax=vmax, \n", " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", " label='VANDELS Truth (Missed)')\n", "\n", - "# 3. VANDELS Truth - Confirmed Sources ('*')\n", - "sc2 = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", + "sc = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", " s=250, c=v_i_mag[lbg_success_mask], cmap='viridis', vmin=vmin, vmax=vmax, \n", " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", " label='Confirmed LBG Candidates')\n", "\n", - "# --- Colorbar ---\n", - "cbar = plt.colorbar(sc2, ax=ax)\n", + "cbar = plt.colorbar(sc, ax=ax)\n", "cbar.set_label('i-band [Sersic Mag]', fontsize=12, fontweight='bold')\n", "cbar.ax.invert_yaxis()\n", "\n", - "\n", - "# --- Selection Boundaries (Ono et al. 2018 Cut: g-r > 1.0) ---\n", - "# Ono et al. 2018 criteria for z~4 LBGs:\n", - "# 1. g - r > 1.0\n", - "# 2. r - i < 1.0\n", - "# 3. g - r > 1.5 * (r - i) + 0.8\n", - "\n", - "# Calculate the new intersection between the horizontal line (g-r = 1.0) and the diagonal\n", - "intersect_x = (1.0 - 0.8) / 1.5 # This equals ~0.133\n", - "x_diag = np.linspace(intersect_x, 1.0, 50)\n", - "y_diag = 1.5 * x_diag + 0.8\n", - "\n", - "# Draw the boundaries\n", "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5) \n", "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", "\n", - "\n", "ax.set_xlim(-1.0, 2.0)\n", "ax.set_ylim(-1.0, 4.0)\n", "ax.set_xlabel('$(r - i)$ [AB Mag]', fontsize=14)\n", @@ -487,8 +491,15 @@ "ax.grid(True, linestyle=':', alpha=0.6)\n", "\n", "plt.tight_layout()\n", - "plt.show()\n", - "\n" + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "b2849d83-8780-4a28-8b31-2f52e5365aa0", + "metadata": {}, + "source": [ + "> Figure X: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by i-band magnitude and their successful selection does not show any trend with magnitude." ] }, { @@ -498,7 +509,6 @@ "metadata": {}, "outputs": [], "source": [ - "v_z_spec = v_matched_truth['zsp'] \n", "vmin, vmax = np.nanmin(v_z_spec), np.nanmax(v_z_spec)\n", "\n", "fig, ax = plt.subplots(figsize=(11, 8))\n", @@ -548,6 +558,14 @@ "plt.show()" ] }, + { + "cell_type": "markdown", + "id": "4e702cae-4406-424f-abec-ec2375cfe0b6", + "metadata": {}, + "source": [ + "> Figure X:" + ] + }, { "cell_type": "markdown", "id": "2f0b8d97-06de-4226-b21b-782f7cbe56c5", @@ -586,7 +604,7 @@ "id": "85a038df-d0e7-49ef-81f8-97a5bbb9bd76", "metadata": {}, "source": [ - "Define a function to generate 4-filter cutouts for visual inspection." + "Define a function to generate image cutouts in 4 filters for visual inspection." ] }, { @@ -680,8 +698,17 @@ "metadata": {}, "outputs": [], "source": [ - "# Execute the plots\n", - "plot_cutouts(missed_r_data, missed_v_truth, n_max=20, title_label=\"Missed VANDELS Truth\")\n" + "#plot_cutouts(missed_r_data, missed_v_truth, n_max=20, title_label=\"Missed VANDELS Truth\")" + ] + }, + { + "cell_type": "markdown", + "id": "cfb13a25-127d-4594-9e61-685f93e76e73", + "metadata": {}, + "source": [ + "> Figure X:\n", + "\n", + "Now do others" ] }, { @@ -691,22 +718,9 @@ "metadata": {}, "outputs": [], "source": [ - "# --- Visual Inspection: True Positives (Confirmed VANDELS LBGs) ---\n", - "# These are the galaxies that have a VANDELS spec-z ~ 4 AND successfully passed your Rubin g-r > 1.5 cut.\n", - "\n", - "# Re-authenticate the RSP session just in case it timed out\n", - "#from lsst.rsp.utils import get_pyvo_auth\n", - "#session = get_pyvo_auth()\n", - "\n", "print(f\"Total confirmed VANDELS LBGs available to plot: {len(confirmed_r_data)}\")\n", "\n", - "# Execute the plotter specifically for the confirmed overlap\n", - "plot_cutouts(\n", - " confirmed_r_data, \n", - " confirmed_v_truth, \n", - " n_max=20, \n", - " title_label=\"Confirmed LBG Selection (True Positives)\"\n", - ")" + "#plot_cutouts(confirmed_r_data, confirmed_v_truth, n_max=20, title_label=\"Confirmed LBG Selection (True Positives)\")" ] }, { @@ -751,7 +765,7 @@ "id": "773d1887-6234-45e3-949e-c1055e65ff60", "metadata": {}, "source": [ - "make spec-z histogram?" + "Now make spec-z histogram to investigate the interloper fraction among confirmed galaxies." ] }, { @@ -775,8 +789,11 @@ "\n", "# Extract the true spectroscopic redshifts of ONLY the galaxies inside our color box\n", "selected_spec_z = matched_v_all['zsp'][is_selected_lbg]\n", + "# Invert the mask with ~ to find where it is False\n", + "failed_lbg_indices = np.where(~is_selected_lbg)[0] # this is wrong, you want to find which spec-z are < 3 among hte selected ones\n", "\n", - "print(f\" -> Found {len(selected_spec_z)} VANDELS sources inside the color selection box.\")\n", + "print(f\"Found {len(selected_spec_z)} out of {len(matched_v_all['zsp'])} VANDELS sources inside the color selection box.\")\n", + "#print(f\"indicating a {len(failed_spec_z)/len(matched_v_all['zsp'])*100}% interloper fraction\")\n", "\n", "fig, ax = plt.subplots(figsize=(10, 6))\n", "\n", @@ -801,7 +818,18 @@ "ax.grid(axis='y', linestyle=':', alpha=0.7, zorder=0)\n", "\n", "plt.tight_layout()\n", - "plt.show()\n" + "plt.show()\n", + "\n", + "\n", + "# maybe we should make the selection window empirically? or at least reference it from somewhere" + ] + }, + { + "cell_type": "markdown", + "id": "82d9acbc-e0c4-4049-90c6-1b8f13af5326", + "metadata": {}, + "source": [ + "> Figure X: Histogram of the redshifts of all spectroscopically confirmed galaxies that enter the lyman-break color selection, indicating a very low interloper fraction" ] }, { From 48d06696605082f32b1fd237f39a8fb8d56e58c5 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Thu, 4 Jun 2026 17:41:17 +0000 Subject: [PATCH 14/27] updating --- .../303_Galaxies/303_3_Color_selections.ipynb | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 1398ce53..59f99de4 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -312,19 +312,11 @@ "source": [ "### 2.2 Validation data \n", "\n", - "#### 2.2.1 Fetch spec-z catalog\n", + "This section will fetch an archival spectroscopic catalog to use as a validation dataset. Use data from the VANDELS spectroscopic redshift catalog (a deep VLT/VIMOS spectroscopic survey of the Cosmic Assembly Near-infrared Deep Extragalactic Survey or CANDELS). This survey was very deep and targeted a large number of high redshift galaxies making it a good single-catalog choice for validation.\n", "\n", - "This will serve as validation" - ] - }, - { - "cell_type": "markdown", - "id": "34cc9127-8e63-4af0-abc0-9d926b91addd", - "metadata": {}, - "source": [ - "Cell 3: Fetch VANDELS Truth & Rubin Photo-z\n", + "#### 2.2.1 Fetch spec-z catalog\n", "\n", - "This fetches your two validation datasets: the spectroscopic ground truth from VizieR, and the photometric redshifts from LSDB. It then maps the photo-z directly into your Rubin table." + "Use the `astroquery` package's `VizieR` service to retrieve the public More information on the catalog and its contents can be found in Garilli et al. 2021." ] }, { @@ -339,9 +331,26 @@ "v.ROW_LIMIT = -1\n", "all_tables = v.get_catalogs(\"J/A+A/647/A150\")\n", "vandels_cdfs = all_tables[0] \n", - "\n", - "# Isolate high-confidence z~4 spectra (3.5 <= z <= 4.5)\n", - "is_vandels_z4 = (vandels_cdfs['zsp'] >= 3.5) & (vandels_cdfs['zsp'] <= 4.5) & (vandels_cdfs['q_zsp'] >= 3)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "3d692c3e-aa56-409f-87ff-4f2e6ab010b8", + "metadata": {}, + "source": [ + "Select galaxies at high redshift using a loose window with z > 3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68a624ba-0ccd-403b-a3b1-eb9a1cdc8577", + "metadata": {}, + "outputs": [], + "source": [ + "is_vandels_z4 = (vandels_cdfs['zsp'] >= 3.2) & (vandels_cdfs['zsp'] <= 4.5) & (vandels_cdfs['q_zsp'] >= 3)\n", + "#is_vandels_z4 = (vandels_cdfs['zsp'] >= 3) & (vandels_cdfs['q_zsp'] >= 3)\n", "vandels_truth = vandels_cdfs[is_vandels_z4]\n", "print(f\" -> Found {len(vandels_truth)} high-confidence VANDELS sources at z~4\")\n" ] @@ -867,7 +876,7 @@ "matched_v_all = vandels_all_hq[match_mask_all]\n", "\n", "# 3. Define the \"Ground Truth\" (3.5 <= spec-z <= 4.5)\n", - "is_true_z4 = (matched_v_all['zsp'] >= 3.5) & (matched_v_all['zsp'] <= 4.5)\n", + "is_true_z4 = (matched_v_all['zsp'] >= 3.2) & (matched_v_all['zsp'] <= 4.5)\n", "\n", "# 4. Define the \"Photometric Selection\" (Ono et al. 2018 Criteria)\n", "# Applying the exact same mask to the matched Rubin data\n", From 29abc5f586242d7c5e6152007135c19dfdc1403d Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Fri, 5 Jun 2026 01:00:42 +0000 Subject: [PATCH 15/27] updating color sel nb --- .../303_Galaxies/303_3_Color_selections.ipynb | 68 +++++++++++-------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 59f99de4..c5079c0d 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -58,7 +58,7 @@ "\n", "Such galaxies can be identified by their very red colors between filters that bridge the Lyman break feature. Since intergalactic hydrogen absorbs the light blueward of the Lyman break, true z > 3 galaxies should be undetected in the LSST u-band, and at z > 4 undetected in the LSST g-band.\n", "\n", - "This notebook demonstrates this color selection on DP1 data for galaxies at 3 < z < 4.5 as an example, and provides some validation metrics for its performance. It makes use of color selections defined and used in the literature with data from facilities with similar filter sets (band pass shapes and effective wavelengths). These are using the Canada-France-Hawaii Telescope Legacy Survey (CFHTLS) as presented in Hildebrandt et al., 2009 and van der Burg et al., 2010. A similar selection was performed using Subaru Hyper-Suprime Cam data in the GOLDRUSH survey Ono et al. 2018\n" + "This notebook demonstrates this color selection on DP1 data for galaxies at 3 < z < 4.5 as an example, and provides some validation metrics for its performance. It makes use of color selections defined and used in the literature with data from facilities with similar filter sets (band pass shapes and effective wavelengths). These are using the Canada-France-Hawaii Telescope Legacy Survey (CFHTLS) as presented in Hildebrandt et al., 2009 and van der Burg et al., 2010. A similar selection was performed using Subaru Hyper-Suprime Cam data in the GOLDRUSH survey Ono et al. 2018\n" ] }, { @@ -312,11 +312,11 @@ "source": [ "### 2.2 Validation data \n", "\n", - "This section will fetch an archival spectroscopic catalog to use as a validation dataset. Use data from the VANDELS spectroscopic redshift catalog (a deep VLT/VIMOS spectroscopic survey of the Cosmic Assembly Near-infrared Deep Extragalactic Survey or CANDELS). This survey was very deep and targeted a large number of high redshift galaxies making it a good single-catalog choice for validation.\n", + "This section will fetch an archival spectroscopic redshift catalog to use as a validation dataset. Use data from the VANDELS spectroscopic redshift catalog (a deep VLT/VIMOS spectroscopic survey of the Cosmic Assembly Near-infrared Deep Extragalactic Survey or CANDELS). This survey was very deep and targeted a large number of high redshift galaxies making it a good single-catalog choice for validation.\n", "\n", "#### 2.2.1 Fetch spec-z catalog\n", "\n", - "Use the `astroquery` package's `VizieR` service to retrieve the public More information on the catalog and its contents can be found in Garilli et al. 2021." + "Use the `astroquery` package's `VizieR` service to retrieve the public catalog, w More information on the catalog and its contents can be found in Garilli et al. 2021. The catalog ID to search in `VizieR` can be found on adsabs.harvard.edu in connection to the data release paper." ] }, { @@ -326,12 +326,10 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"1. Fetching VANDELS Spectroscopic Catalog from VizieR...\")\n", "v = Vizier(columns=['**'], catalog=\"J/A+A/647/A150\")\n", "v.ROW_LIMIT = -1\n", "all_tables = v.get_catalogs(\"J/A+A/647/A150\")\n", - "vandels_cdfs = all_tables[0] \n", - "\n" + "vandels_cdfs = all_tables[0] " ] }, { @@ -372,9 +370,6 @@ "metadata": {}, "outputs": [], "source": [ - "\n", - "\n", - "print(\"\\n2. Cross-matching VANDELS Truth to Rubin Object Table...\")\n", "coord_v = SkyCoord(ra=vandels_truth['RAJ2000'], dec=vandels_truth['DEJ2000'], unit='deg')\n", "coord_r = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", "\n", @@ -383,14 +378,28 @@ "\n", "print(np.min(tab['coord_ra'][idx_rubin]), np.max(tab['coord_ra'][idx_rubin]))\n", "print(np.min(tab['coord_dec'][idx_rubin]), np.max(tab['coord_dec'][idx_rubin]))\n", - " \n", - "\n", - "# Isolate the matched sources\n", + " \n" + ] + }, + { + "cell_type": "markdown", + "id": "97deb2fb-44aa-43fa-b6c1-e22bba242f50", + "metadata": {}, + "source": [ + "Below, isolate the matched sources in the two datasets. Then define success and failure masks based on whether the matched objects passed the LBG color selection. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4c218a0b-7c0c-4a41-b237-29eeaa6cae83", + "metadata": {}, + "outputs": [], + "source": [ "matched_rubin_indices = idx_rubin[match_mask]\n", "vandels_in_rubin = tab[matched_rubin_indices]\n", "v_matched_truth = vandels_truth[match_mask]\n", "\n", - "# Define success/fail masks based on whether the matched objects passed the LBG cut\n", "lbg_success_mask = is_z4_lbg[matched_rubin_indices]\n", "failed_lbg = ~lbg_success_mask\n", "\n", @@ -421,8 +430,7 @@ "v_r_minus_i = vandels_in_rubin['r_minus_i']\n", "v_g_minus_r = vandels_in_rubin['g_minus_r']\n", "v_i_mag = vandels_in_rubin['i_mag_robust']\n", - "v_z_spec = v_matched_truth['zsp'] \n", - "\n" + "v_z_spec = v_matched_truth['zsp'] " ] }, { @@ -472,14 +480,14 @@ " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates')\n", "\n", "sc = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", - " s=120, c=v_i_mag[failed_lbg], cmap='viridis', vmin=vmin, vmax=vmax, \n", - " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", - " label='VANDELS Truth (Missed)')\n", + " s=120, c=v_i_mag[failed_lbg], cmap='viridis', vmin=vmin, vmax=vmax, \n", + " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", + " label='VANDELS Truth (Missed)')\n", "\n", "sc = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", - " s=250, c=v_i_mag[lbg_success_mask], cmap='viridis', vmin=vmin, vmax=vmax, \n", - " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", - " label='Confirmed LBG Candidates')\n", + " s=250, c=v_i_mag[lbg_success_mask], cmap='viridis', vmin=vmin, vmax=vmax, \n", + " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", + " label='Confirmed LBG Candidates')\n", "\n", "cbar = plt.colorbar(sc, ax=ax)\n", "cbar.set_label('i-band [Sersic Mag]', fontsize=12, fontweight='bold')\n", @@ -528,19 +536,19 @@ " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates (g-r > 1.5)')\n", "\n", "# 2. VANDELS Truth - Missed Sources ('+')\n", - "sc1 = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", - " s=120, c=v_z_spec[failed_lbg], cmap='plasma', vmin=vmin, vmax=vmax, \n", - " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", - " label='VANDELS Truth (Missed)')\n", + "sc = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", + " s=120, c=v_z_spec[failed_lbg], cmap='plasma', vmin=vmin, vmax=vmax, \n", + " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", + " label='VANDELS Truth (Missed)')\n", "\n", "# 3. VANDELS Truth - Confirmed Sources ('*')\n", - "sc2 = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", - " s=250, c=v_z_spec[lbg_success_mask], cmap='plasma', vmin=vmin, vmax=vmax, \n", - " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", - " label='Confirmed LBG Candidates')\n", + "sc = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", + " s=250, c=v_z_spec[lbg_success_mask], cmap='plasma', vmin=vmin, vmax=vmax, \n", + " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", + " label='Confirmed LBG Candidates')\n", "\n", "\n", - "cbar = plt.colorbar(sc2, ax=ax)\n", + "cbar = plt.colorbar(sc, ax=ax)\n", "cbar.set_label('Spectroscopic Redshift (VANDELS z_spec)', fontsize=12, fontweight='bold')\n", "\n", "# Calculate the new intersection between the horizontal line (g-r = 1.0) and the diagonal\n", From 3d3b9cd7c65baad0f55df95f4a7fd4900aa1f99b Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Fri, 5 Jun 2026 23:08:53 +0000 Subject: [PATCH 16/27] updating color sel nb --- .../303_Galaxies/303_3_Color_selections.ipynb | 68 +++++++++---------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index c5079c0d..2003926c 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -54,11 +54,11 @@ "source": [ "# 1. Introduction\n", "\n", - "Color selections have served as a key method of identifying galaxies of different populations over decades. Especially at redshift z > 2.5, the Lyman-break is a strong spectral feature that is exploited to identify galaxies at high redshift. Lyman-break selections make use of the fact that intergalactic hydrogen in the foreground absorbs all the light of background galaxies that is emitted blueward of the Lyman limit (912A) or at very high redshifts, Lyman-alpha (1216A). More details about why this works can be found at this blog-post. \n", + "Color selections have served as a key method of identifying different populations of galaxies for decades. Especially at redshift z > 2.5, the Lyman-break is a strong spectral feature that is exploited to identify galaxies at high redshift in ground-based imaging. Lyman-break selections make use of the fact that intergalactic hydrogen in the foreground absorbs all the light of background galaxies that is emitted blueward of the Lyman limit (912A) or at very high redshifts, Lyman-alpha (1216A). More details about why this works can be found at this blog-post. \n", "\n", - "Such galaxies can be identified by their very red colors between filters that bridge the Lyman break feature. Since intergalactic hydrogen absorbs the light blueward of the Lyman break, true z > 3 galaxies should be undetected in the LSST u-band, and at z > 4 undetected in the LSST g-band.\n", + "Thus, galaxies at high redshifts can be identified by their very red colors between filters that bridge the Lyman break feature (and are named after their selection method as Lyman break galaxies or LBGs). Since intergalactic hydrogen absorbs the light blueward of the Lyman break, the flux of true z ~ 3 galaxies drops as the Lyman-break redshifts into the LSST u-band, and at z ~ 4 in the LSST g-band.\n", "\n", - "This notebook demonstrates this color selection on DP1 data for galaxies at 3 < z < 4.5 as an example, and provides some validation metrics for its performance. It makes use of color selections defined and used in the literature with data from facilities with similar filter sets (band pass shapes and effective wavelengths). These are using the Canada-France-Hawaii Telescope Legacy Survey (CFHTLS) as presented in Hildebrandt et al., 2009 and van der Burg et al., 2010. A similar selection was performed using Subaru Hyper-Suprime Cam data in the GOLDRUSH survey Ono et al. 2018\n" + "This notebook demonstrates the Lyman break color selection on DP1 data for galaxies at z ~ 4 as an example (referred to as g-band dropouts), and provides some validation metrics for its performance. It makes use of color selections defined and used in the literature with data from facilities with similar filter sets (band pass shapes and effective wavelengths). These are using the Canada-France-Hawaii Telescope Legacy Survey (CFHTLS) as presented in Hildebrandt et al., 2009 and van der Burg et al., 2010. A similar selection was performed using Subaru Hyper-Suprime Cam data in the GOLDRUSH survey Ono et al. 2018\n" ] }, { @@ -161,12 +161,7 @@ "id": "e9c07b17-bc81-42e2-991c-0ab3a7d30eb8", "metadata": {}, "source": [ - "Define a query to retrieve galaxies from the object table using the `extendedness`=1 flag. Search around the center of the field using an 0.2 degree search radius to ensure the candidates are identified within the deepest area of g-band imaging. To further ensure good detections, include the $S/N > 10$ cut on the $i$-band.\n", - "\n", - "NOTES:\n", - "note: could these below horizontal line be in a shallow are of g? Could be a data thing\n", - "use the survey depth map to cut out the edges. or use a smaller search radius from the center. survey property maps will show\n", - "depth at given location and use that instead of the \n" + "Define a query to retrieve galaxies from the object table using the `extendedness`=1 flag. Search around the center of the field using a 0.2 degree search radius to ensure the candidates are identified within the deepest area of g-band imaging. To further ensure good detections, include the $S/N > 10$ cut on the $i$-band." ] }, { @@ -262,7 +257,7 @@ "id": "6ed23adb-f5ff-409c-b8b9-e63251d1d77a", "metadata": {}, "source": [ - "Store these colors as new columns in the table." + "Store these robust colors as new columns in the table." ] }, { @@ -281,11 +276,11 @@ "id": "8baf7434-aee5-459b-8282-4926978dc4ce", "metadata": {}, "source": [ - "### 2.1 LBG color selection\n", + "### 2.1 LBG selection\n", "\n", - "Now, perform the color selection to identify the high-redshift galaxy candidates. Use a typical Lyman Break Selection for a camera with similar filter properties to the LSST (e.g. Ono et al. 2018) which require very red g-r colors (to identify galaxies with strong lyman breaks), and relatively blue r-i colors (which excludes stars). \n", + "Now, perform the color selection to identify the high-redshift galaxy candidates. Use a typical Lyman break selection for a camera with similar filter properties to the LSST (e.g. Ono et al. 2018). The selection requires very red g-r colors (to identify galaxies with strong Lyman breaks), and relatively blue r-i colors (typical of star-forming galaxies with little dust, and which excludes stars). \n", "\n", - "Also add another criteria requiring that the u-band flux be undetected (S/N < 3), since all u-band flux should also be absorbed by the intergalactic medium since it is blueward of the Lyman limit at z > 3." + "Also, add another criteria requiring that the u-band flux be undetected (S/N < 3), since all u-band flux should also be absorbed by the intergalactic medium since it is blueward of the Lyman limit at z > 3." ] }, { @@ -302,7 +297,7 @@ " (tab['g_minus_r'] > 1.5 * tab['r_minus_i'] + 0.8)\n", ")\n", "\n", - "print(f\"Identified {np.sum(is_z4_lbg)} photometric LBG candidates.\")\n" + "print(f\"Identified {np.sum(is_z4_lbg)} photometric LBG candidates.\")" ] }, { @@ -316,7 +311,7 @@ "\n", "#### 2.2.1 Fetch spec-z catalog\n", "\n", - "Use the `astroquery` package's `VizieR` service to retrieve the public catalog, w More information on the catalog and its contents can be found in Garilli et al. 2021. The catalog ID to search in `VizieR` can be found on adsabs.harvard.edu in connection to the data release paper." + "Use the `astroquery` package's `VizieR` service to retrieve the public catalog. Information on the catalog and its contents can be found in Garilli et al. 2021. The catalog ID to search in `VizieR` can be found on adsabs.harvard.edu in connection to the data release paper." ] }, { @@ -337,7 +332,7 @@ "id": "3d692c3e-aa56-409f-87ff-4f2e6ab010b8", "metadata": {}, "source": [ - "Select galaxies at high redshift using a loose window with z > 3" + "Select LBGs at high redshift using a loose window with 3.2 < z < 4.5 (this is the typical selection window for this same g-band dropout selection, as characterized by Ono et al. 2018). Ensure that only high quality measurements are used by requiring the good and excellent spectroscopic redshift flag `q_zsp` of 3 and 4." ] }, { @@ -350,7 +345,7 @@ "is_vandels_z4 = (vandels_cdfs['zsp'] >= 3.2) & (vandels_cdfs['zsp'] <= 4.5) & (vandels_cdfs['q_zsp'] >= 3)\n", "#is_vandels_z4 = (vandels_cdfs['zsp'] >= 3) & (vandels_cdfs['q_zsp'] >= 3)\n", "vandels_truth = vandels_cdfs[is_vandels_z4]\n", - "print(f\" -> Found {len(vandels_truth)} high-confidence VANDELS sources at z~4\")\n" + "print(f\"Found {len(vandels_truth)} high-confidence VANDELS sources at z~4\")" ] }, { @@ -360,7 +355,7 @@ "source": [ "#### 2.2.3 Cross-match\n", "\n", - "Here we perform the LBG selection on the Rubin data, then match it against the VANDELS truth catalog to see what passed and what failed" + "Perform the LBG selection on the Rubin data, then match to objects with the same coordinates in the VANDELS catalog to see what true high redshift galaxies passed the LBG selection and which failed." ] }, { @@ -374,11 +369,7 @@ "coord_r = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", "\n", "idx_rubin, d2d, _ = coord_v.match_to_catalog_sky(coord_r)\n", - "match_mask = d2d < 1.0 * u.arcsec\n", - "\n", - "print(np.min(tab['coord_ra'][idx_rubin]), np.max(tab['coord_ra'][idx_rubin]))\n", - "print(np.min(tab['coord_dec'][idx_rubin]), np.max(tab['coord_dec'][idx_rubin]))\n", - " \n" + "match_mask = d2d < 1.0 * u.arcsec" ] }, { @@ -403,9 +394,9 @@ "lbg_success_mask = is_z4_lbg[matched_rubin_indices]\n", "failed_lbg = ~lbg_success_mask\n", "\n", - "print(f\" -> VANDELS z~4 sources detected in Rubin catalog: {len(matched_rubin_indices)}\")\n", - "print(f\" -> VANDELS sources successfully recovered by LBG selection: {np.sum(lbg_success_mask)}\")\n", - "print(f\" -> VANDELS sources missed by LBG selection: {np.sum(failed_lbg)}\")" + "print(f\"VANDELS z~4 sources detected in Rubin catalog: {len(matched_rubin_indices)}\")\n", + "print(f\"VANDELS sources successfully recovered by LBG selection: {np.sum(lbg_success_mask)}\")\n", + "print(f\"VANDELS sources missed by LBG selection: {np.sum(failed_lbg)}\")" ] }, { @@ -413,11 +404,9 @@ "id": "d0e7c80f-0587-4c17-93d8-a52096d4c99e", "metadata": {}, "source": [ - "## 2.3 plot color-color selection\n", - "\n", - "This visually summarizes everything: your parent Rubin sample, your LBG candidates, and the VANDELS ground-truth objects (color-coded by magnitude).\n", + "## 2.3 Plot color color diagrams\n", "\n", - "First, store some shorthand parameters for the color (TBD if you can consolidate this more with above)" + "First, store some shorthand parameters for the colors of interest, and for parameters to color-code the galaxies by." ] }, { @@ -438,7 +427,7 @@ "id": "b381133b-22e6-46e1-957e-75a62d1b6c6e", "metadata": {}, "source": [ - "Also, use the selection criteria for z~4 LBGs defined in Ono et al. 2018 :\n", + "Use the selection criteria for z~4 LBGs defined in Ono et al. 2018, which are :\n", "1. g - r > 1.0\n", "2. r - i < 1.0\n", "3. g - r > 1.5 * (r - i) + 0.8" @@ -461,7 +450,7 @@ "id": "ef3b6dac-ec19-4f3c-9d61-ff9002385247", "metadata": {}, "source": [ - "Define a figure and plot all the Rubin galaxies from the query (gray), all Rubin galaxies that satisfy the LBG color selection (blue), and the true spectroscopically confirmed high-redshift galaxies as bold colored symbols. Stars indicate the true high-redshift galaxies that meet the color selection and plus signs are the true high-redshift galaxies that do not. " + "Define a figure for the color color diagram. Plot all the Rubin galaxies from the query in Section 2.1 (gray), all Rubin galaxies that satisfy the LBG color selection (blue), and the true spectroscopically confirmed high-redshift galaxies as bold colored symbols. Stars indicate the true high-redshift galaxies that meet the color selection and plus signs are the true high-redshift galaxies that do not. " ] }, { @@ -516,7 +505,15 @@ "id": "b2849d83-8780-4a28-8b31-2f52e5365aa0", "metadata": {}, "source": [ - "> Figure X: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by i-band magnitude and their successful selection does not show any trend with magnitude." + "> Figure 1: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by i-band magnitude and their successful selection does not show any trend with magnitude." + ] + }, + { + "cell_type": "markdown", + "id": "8062a269-a6c8-43b2-ae46-88ebc8790912", + "metadata": {}, + "source": [ + "Since there is no obvious trend with i-band magnitude, color code the spectroscopically confirmed high-redshift galaxies by their redshift instead." ] }, { @@ -530,18 +527,15 @@ "\n", "fig, ax = plt.subplots(figsize=(11, 8))\n", "\n", - "# 1. Background (All Rubin Data)\n", "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Parent Sample (Rubin)')\n", "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates (g-r > 1.5)')\n", "\n", - "# 2. VANDELS Truth - Missed Sources ('+')\n", "sc = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", " s=120, c=v_z_spec[failed_lbg], cmap='plasma', vmin=vmin, vmax=vmax, \n", " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", " label='VANDELS Truth (Missed)')\n", "\n", - "# 3. VANDELS Truth - Confirmed Sources ('*')\n", "sc = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", " s=250, c=v_z_spec[lbg_success_mask], cmap='plasma', vmin=vmin, vmax=vmax, \n", " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", @@ -580,7 +574,7 @@ "id": "4e702cae-4406-424f-abec-ec2375cfe0b6", "metadata": {}, "source": [ - "> Figure X:" + "> Figure 2: UPDATE: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by i-band magnitude and their successful selection does not show any trend with magnitude." ] }, { From d67e8bc858da50ce9815e1d70ad68cf7babaeda1 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Mon, 8 Jun 2026 01:10:58 +0000 Subject: [PATCH 17/27] updating color sel nb --- .../303_Galaxies/303_3_Color_selections.ipynb | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 2003926c..ab2a2409 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -58,7 +58,7 @@ "\n", "Thus, galaxies at high redshifts can be identified by their very red colors between filters that bridge the Lyman break feature (and are named after their selection method as Lyman break galaxies or LBGs). Since intergalactic hydrogen absorbs the light blueward of the Lyman break, the flux of true z ~ 3 galaxies drops as the Lyman-break redshifts into the LSST u-band, and at z ~ 4 in the LSST g-band.\n", "\n", - "This notebook demonstrates the Lyman break color selection on DP1 data for galaxies at z ~ 4 as an example (referred to as g-band dropouts), and provides some validation metrics for its performance. It makes use of color selections defined and used in the literature with data from facilities with similar filter sets (band pass shapes and effective wavelengths). These are using the Canada-France-Hawaii Telescope Legacy Survey (CFHTLS) as presented in Hildebrandt et al., 2009 and van der Burg et al., 2010. A similar selection was performed using Subaru Hyper-Suprime Cam data in the GOLDRUSH survey Ono et al. 2018\n" + "This notebook demonstrates the Lyman break color selection on DP1 data for galaxies at z ~ 4 as an example (referred to as g-band dropouts), and provides some validation metrics for its performance. It makes use of color selections defined and used in the literature with data from facilities with similar filter sets (band pass shapes and effective wavelengths). These are using the Canada-France-Hawaii Telescope Legacy Survey (CFHTLS) as presented in Hildebrandt et al., 2009 and van der Burg et al., 2010. A similar selection was performed using Subaru Hyper-Suprime Cam data in Ono et al. 2018\n" ] }, { @@ -176,7 +176,8 @@ " obj.u_sersicFlux, obj.u_sersicFluxErr,\n", " obj.g_sersicFlux, obj.g_sersicFluxErr,\n", " obj.r_sersicFlux, obj.r_sersicFluxErr,\n", - " obj.i_sersicFlux, obj.i_sersicFluxErr\n", + " obj.i_sersicFlux, obj.i_sersicFluxErr,\n", + " obj.z_sersicFlux, obj.z_sersicFluxErr\n", "FROM dp1.Object AS obj\n", "WHERE (obj.i_sersicFlux/obj.i_sersicFluxErr > 10) \n", " AND (obj.i_extendedness = 1) \n", @@ -242,7 +243,7 @@ "metadata": {}, "outputs": [], "source": [ - "filters = ['u', 'g', 'r', 'i']\n", + "filters = ['u', 'g', 'r', 'i', 'z']\n", "\n", "with np.errstate(divide='ignore', invalid='ignore'):\n", " for f in filters:\n", @@ -268,7 +269,8 @@ "outputs": [], "source": [ "tab['g_minus_r'] = tab['g_mag_robust'] - tab['r_mag_robust']\n", - "tab['r_minus_i'] = tab['r_mag_robust'] - tab['i_mag_robust']" + "tab['r_minus_i'] = tab['r_mag_robust'] - tab['i_mag_robust']\n", + "tab['i_minus_z'] = tab['i_mag_robust'] - tab['z_mag_robust']" ] }, { @@ -311,7 +313,7 @@ "\n", "#### 2.2.1 Fetch spec-z catalog\n", "\n", - "Use the `astroquery` package's `VizieR` service to retrieve the public catalog. Information on the catalog and its contents can be found in Garilli et al. 2021. The catalog ID to search in `VizieR` can be found on adsabs.harvard.edu in connection to the data release paper." + "Use the `astroquery` package's `VizieR` service to retrieve the public catalog. Information on the catalog and its contents can be found in Garilli et al. 2021. The catalog ID to search in `VizieR` can be found on adsabs.harvard.edu in connection to the data release paper. Pull the table of data obtained in the ECDFS as `vandels_cdfs`" ] }, { @@ -332,7 +334,7 @@ "id": "3d692c3e-aa56-409f-87ff-4f2e6ab010b8", "metadata": {}, "source": [ - "Select LBGs at high redshift using a loose window with 3.2 < z < 4.5 (this is the typical selection window for this same g-band dropout selection, as characterized by Ono et al. 2018). Ensure that only high quality measurements are used by requiring the good and excellent spectroscopic redshift flag `q_zsp` of 3 and 4." + "##### Select LBGs at high redshift using a loose window with 3.5 < z < 4.5 (this is the typical selection window for this same g-band dropout selection, as characterized by Ono et al. 2018). Ensure that only high quality measurements are used by requiring the good and excellent spectroscopic redshift flag `q_zsp` of 3 and 4." ] }, { @@ -342,7 +344,7 @@ "metadata": {}, "outputs": [], "source": [ - "is_vandels_z4 = (vandels_cdfs['zsp'] >= 3.2) & (vandels_cdfs['zsp'] <= 4.5) & (vandels_cdfs['q_zsp'] >= 3)\n", + "is_vandels_z4 = (vandels_cdfs['zsp'] >= 3.5) & (vandels_cdfs['zsp'] <= 4.5) & (vandels_cdfs['q_zsp'] >= 3)\n", "#is_vandels_z4 = (vandels_cdfs['zsp'] >= 3) & (vandels_cdfs['q_zsp'] >= 3)\n", "vandels_truth = vandels_cdfs[is_vandels_z4]\n", "print(f\"Found {len(vandels_truth)} high-confidence VANDELS sources at z~4\")" @@ -416,10 +418,12 @@ "metadata": {}, "outputs": [], "source": [ - "v_r_minus_i = vandels_in_rubin['r_minus_i']\n", "v_g_minus_r = vandels_in_rubin['g_minus_r']\n", + "v_r_minus_i = vandels_in_rubin['r_minus_i']\n", + "v_i_minus_z = vandels_in_rubin['i_minus_z']\n", "v_i_mag = vandels_in_rubin['i_mag_robust']\n", - "v_z_spec = v_matched_truth['zsp'] " + "v_z_spec = v_matched_truth['zsp']\n", + "v_g_err = vandels_in_rubin['g" ] }, { @@ -462,19 +466,21 @@ "source": [ "fig, ax = plt.subplots(figsize=(11, 8))\n", "\n", - "vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", + "#vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", + "vmin, vmax = np.nanmin(v_i_minus_z), np.nanmax(v_i_minus_z)\n", + "vmin, vmax = 0, np.nanmax(v_i_minus_z)\n", "\n", "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Rubin Parent Sample')\n", "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates')\n", "\n", "sc = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", - " s=120, c=v_i_mag[failed_lbg], cmap='viridis', vmin=vmin, vmax=vmax, \n", + " s=120, c=v_i_minus_z[failed_lbg], cmap='viridis', vmin=vmin, vmax=vmax, \n", " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", " label='VANDELS Truth (Missed)')\n", "\n", "sc = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", - " s=250, c=v_i_mag[lbg_success_mask], cmap='viridis', vmin=vmin, vmax=vmax, \n", + " s=250, c=v_i_minus_z[lbg_success_mask], cmap='viridis', vmin=vmin, vmax=vmax, \n", " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", " label='Confirmed LBG Candidates')\n", "\n", @@ -500,12 +506,22 @@ "plt.show()" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "562b810d-58cc-4ed8-a5e9-9818c0dc09ce", + "metadata": {}, + "outputs": [], + "source": [ + "g_sersicFluxErr" + ] + }, { "cell_type": "markdown", "id": "b2849d83-8780-4a28-8b31-2f52e5365aa0", "metadata": {}, "source": [ - "> Figure 1: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by i-band magnitude and their successful selection does not show any trend with magnitude." + "> Figure 1: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by i-band magnitude and their successful selection does not show any trend with magnitude (which might be expected if photometric scatter ." ] }, { From 5c0aa1f020b84b7cd090d7b1eb5521231eb7e07d Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Mon, 8 Jun 2026 20:31:21 +0000 Subject: [PATCH 18/27] updating color sel nb --- .../303_Galaxies/303_3_Color_selections.ipynb | 143 +++++++++++++----- 1 file changed, 106 insertions(+), 37 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index ab2a2409..10fc8bed 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -344,7 +344,7 @@ "metadata": {}, "outputs": [], "source": [ - "is_vandels_z4 = (vandels_cdfs['zsp'] >= 3.5) & (vandels_cdfs['zsp'] <= 4.5) & (vandels_cdfs['q_zsp'] >= 3)\n", + "is_vandels_z4 = (vandels_cdfs['zsp'] >= 3.7) & (vandels_cdfs['zsp'] <= 4.5) & (vandels_cdfs['q_zsp'] >= 3)\n", "#is_vandels_z4 = (vandels_cdfs['zsp'] >= 3) & (vandels_cdfs['q_zsp'] >= 3)\n", "vandels_truth = vandels_cdfs[is_vandels_z4]\n", "print(f\"Found {len(vandels_truth)} high-confidence VANDELS sources at z~4\")" @@ -389,7 +389,9 @@ "metadata": {}, "outputs": [], "source": [ - "matched_rubin_indices = idx_rubin[match_mask]\n", + "# sort out which masks apply to which parent array, color coding in the following plots could be wrong\n", + "\n", + "matched_rubin_indices = idx_rubin[match_mask] \n", "vandels_in_rubin = tab[matched_rubin_indices]\n", "v_matched_truth = vandels_truth[match_mask]\n", "\n", @@ -423,7 +425,8 @@ "v_i_minus_z = vandels_in_rubin['i_minus_z']\n", "v_i_mag = vandels_in_rubin['i_mag_robust']\n", "v_z_spec = v_matched_truth['zsp']\n", - "v_g_err = vandels_in_rubin['g" + "#v_g_err = vandels_in_rubin['g\n", + "v_gerr = vandels_in_rubin['g_sersicFluxErr']\n" ] }, { @@ -466,21 +469,21 @@ "source": [ "fig, ax = plt.subplots(figsize=(11, 8))\n", "\n", - "#vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", - "vmin, vmax = np.nanmin(v_i_minus_z), np.nanmax(v_i_minus_z)\n", - "vmin, vmax = 0, np.nanmax(v_i_minus_z)\n", + "vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", + "\n", + "#vmin, vmax = 24, np.nanmax(v_i_mag)\n", "\n", "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Rubin Parent Sample')\n", "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates')\n", "\n", "sc = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", - " s=120, c=v_i_minus_z[failed_lbg], cmap='viridis', vmin=vmin, vmax=vmax, \n", + " s=120, c=v_i_mag[failed_lbg], cmap='viridis', vmin=vmin, vmax=vmax, \n", " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", " label='VANDELS Truth (Missed)')\n", "\n", "sc = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", - " s=250, c=v_i_minus_z[lbg_success_mask], cmap='viridis', vmin=vmin, vmax=vmax, \n", + " s=250, c=v_i_mag[lbg_success_mask], cmap='viridis', vmin=vmin, vmax=vmax, \n", " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", " label='Confirmed LBG Candidates')\n", "\n", @@ -513,7 +516,49 @@ "metadata": {}, "outputs": [], "source": [ - "g_sersicFluxErr" + "v_gerr = vandels_in_rubin['g_sersicFluxErr']\n", + "\n", + "\n", + "fig, ax = plt.subplots(figsize=(11, 8))\n", + "\n", + "#vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", + "vmin, vmax = np.nanmin(v_gerr), 20 #np.nanmax(v_gerr)\n", + "#vmin, vmax = 0, np.nanmax(v_i_minus_z)\n", + "\n", + "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Rubin Parent Sample')\n", + "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", + " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates')\n", + "\n", + "sc = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", + " s=120, c=v_gerr[failed_lbg], cmap='viridis', vmin=vmin, vmax=vmax, \n", + " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", + " label='VANDELS Truth (Missed)')\n", + "\n", + "sc = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", + " s=250, c=v_gerr[lbg_success_mask], cmap='viridis', vmin=vmin, vmax=vmax, \n", + " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", + " label='Confirmed LBG Candidates')\n", + "\n", + "cbar = plt.colorbar(sc, ax=ax)\n", + "cbar.set_label('g-band flux err (njy)', fontsize=12, fontweight='bold')\n", + "#cbar.ax.invert_yaxis()\n", + "\n", + "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5) \n", + "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", + "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", + "\n", + "ax.set_xlim(-1.0, 2.0)\n", + "ax.set_ylim(-1.0, 4.0)\n", + "ax.set_xlabel('$(r - i)$ [AB Mag]', fontsize=14)\n", + "ax.set_ylabel('$(g - r)$ [AB Mag]', fontsize=14)\n", + "ax.set_title('Lyman Break Selection (g-r > 1)', fontsize=16, fontweight='bold')\n", + "\n", + "handles, labels = ax.get_legend_handles_labels()\n", + "ax.legend(handles, labels, loc='upper left', framealpha=1)\n", + "ax.grid(True, linestyle=':', alpha=0.6)\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" ] }, { @@ -608,7 +653,7 @@ "source": [ "# 3. Visual inspection\n", "\n", - "Finally, we pull the image cutouts directly from the Rubin archives for the missed and confirmed subsets to inspect the pixels." + "Finally, generate image cutouts to visually inspect both the missed and confirmed subsets of spectroscopically confirmed galaxies." ] }, { @@ -618,12 +663,11 @@ "metadata": {}, "outputs": [], "source": [ - "# Isolate the missed and confirmed subsets\n", "missed_v_truth = v_matched_truth[failed_lbg]\n", "missed_r_data = vandels_in_rubin[failed_lbg]\n", "\n", "confirmed_v_truth = v_matched_truth[lbg_success_mask]\n", - "confirmed_r_data = vandels_in_rubin[lbg_success_mask]\n" + "confirmed_r_data = vandels_in_rubin[lbg_success_mask]" ] }, { @@ -725,7 +769,8 @@ "metadata": {}, "outputs": [], "source": [ - "#plot_cutouts(missed_r_data, missed_v_truth, n_max=20, title_label=\"Missed VANDELS Truth\")" + "plot_cutouts(missed_r_data, missed_v_truth, n_max=30,\n", + " title_label=\"VANDELS high-z confirmations missed by Rubin color selection\")" ] }, { @@ -735,7 +780,7 @@ "source": [ "> Figure X:\n", "\n", - "Now do others" + "Optionally, also generate cutouts of the true high-redshift galaxies that were successfully identified by the color selection." ] }, { @@ -755,7 +800,11 @@ "id": "1b5c1515-47a2-4cfa-b9f2-60acadb4daa9", "metadata": {}, "source": [ - "Below, use only the spectra which have a high quality flag (3 or 4) corresponding to a secure spectroscopic redshift measurement (see PAPER). ALSO I THINK YOU WANT TO DO THIS ABOVE, NOT HERE..." + "# 4. Interloper fraction\n", + "\n", + "Below, select all Rubin objects at any redshift with a secure VANDELS ectroscopic redshift measurement (high quality only, `q_zsp` of 3 or 4; See Garilla et al.). Use that full sample across all redshifts to investigate the interloper fraction of the Rubin color selection (this exercise is only informative above the magnitude limit of the VANDELS sample, and does not apply to fainter galaxies). \n", + "\n", + "First, cross-match all galaxies for which VANDELS secured a robust redshift measurement with the Rubin objects from hte query in Section 2." ] }, { @@ -765,20 +814,31 @@ "metadata": {}, "outputs": [], "source": [ - "\n", - "print(\"1. Isolating all high-quality VANDELS spectra...\")\n", - "# Keep all redshifts with quality flag >= 3 (standard for secure spec-z)\n", "is_vandels_hq = vandels_cdfs['q_zsp'] >= 3\n", "vandels_all_hq = vandels_cdfs[is_vandels_hq]\n", "\n", - "print(\"2. Cross-matching to the Rubin Object Table...\")\n", "coord_v_all = SkyCoord(ra=vandels_all_hq['RAJ2000'], dec=vandels_all_hq['DEJ2000'], unit='deg')\n", "coord_r = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", "\n", "idx_rubin_all, d2d_all, _ = coord_v_all.match_to_catalog_sky(coord_r)\n", - "match_mask_all = d2d_all < 1.0 * u.arcsec\n", - "\n", - "# Extract the matched data\n", + "match_mask_all = d2d_all < 1.0 * u.arcsec" + ] + }, + { + "cell_type": "markdown", + "id": "4bbb4f8e-eb80-4cdd-847d-89671817c018", + "metadata": {}, + "source": [ + "For simplicity, make new arrays to hold the matched datasets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63794bbc-5fbb-4a88-a365-765f24c5bc5b", + "metadata": {}, + "outputs": [], + "source": [ "matched_rubin_all = tab[idx_rubin_all[match_mask_all]]\n", "matched_v_all = vandels_all_hq[match_mask_all]\n", "\n", @@ -792,7 +852,9 @@ "id": "773d1887-6234-45e3-949e-c1055e65ff60", "metadata": {}, "source": [ - "Now make spec-z histogram to investigate the interloper fraction among confirmed galaxies." + "Now make a histogram of VANDELS galaxies with spectroscopic redshifts that met the Rubin LBG color selection, and investigate the interloper fraction among confirmed galaxies.\n", + "\n", + "First, perform the color selection again on the parent sample of all VANDELS high-quality confirmations." ] }, { @@ -802,11 +864,6 @@ "metadata": {}, "outputs": [], "source": [ - "\n", - "\n", - "print(\"Isolating VANDELS galaxies that passed the Rubin LBG color cut...\")\n", - "\n", - "# Re-apply the Ono et al. 2018 LBG selection mask to the cross-matched catalog\n", "is_selected_lbg = (\n", " (matched_rubin_all['g_minus_r'] > 1.0) & \n", " (matched_rubin_all['u_sersicFlux'] / matched_rubin_all['u_sersicFluxErr'] < 3) & \n", @@ -822,20 +879,35 @@ "print(f\"Found {len(selected_spec_z)} out of {len(matched_v_all['zsp'])} VANDELS sources inside the color selection box.\")\n", "#print(f\"indicating a {len(failed_spec_z)/len(matched_v_all['zsp'])*100}% interloper fraction\")\n", "\n", + "\n", + "# maybe we should make the selection window empirically? or at least reference it from somewhere" + ] + }, + { + "cell_type": "markdown", + "id": "7bc2c568-34a1-4cd6-9481-110865b80cdf", + "metadata": {}, + "source": [ + "Next, plot the histogram along with the redshift selection window that was characterized by Ono et al. 2018. That study found that the HSC filterset and their color selection criteria (both very similar to Rubin's filters and the color selection used in this notebook) produces a selection window at 3.2 < z < 4.5." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d5df4ce-88e3-4bd5-bebf-1c3d29006f28", + "metadata": {}, + "outputs": [], + "source": [ "fig, ax = plt.subplots(figsize=(10, 6))\n", "\n", - "# Define the redshift bins (e.g., from z=0 to z=6.5 in steps of z=0.2)\n", "z_bins = np.arange(0, 6.6, 0.2)\n", "\n", - "# Plot the histogram\n", "ax.hist(selected_spec_z, bins=z_bins, color='dodgerblue', edgecolor='black', alpha=0.8, zorder=3)\n", "\n", - "# Highlight our target ground-truth window (3.2 <= z <= 4.5)\n", "ax.axvspan(3.2, 4.5, color='mediumseagreen', alpha=0.2, label='Selection Window ($3.2 < z < 4.5$)')\n", "ax.axvline(3.2, color='darkgreen', linestyle='--', linewidth=1.5, zorder=4)\n", "ax.axvline(4.5, color='darkgreen', linestyle='--', linewidth=1.5, zorder=4)\n", "\n", - "# Formatting\n", "ax.set_xlim(0, 6.5)\n", "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", "ax.set_ylabel('Number of Selected Candidates', fontsize=14)\n", @@ -845,10 +917,7 @@ "ax.grid(axis='y', linestyle=':', alpha=0.7, zorder=0)\n", "\n", "plt.tight_layout()\n", - "plt.show()\n", - "\n", - "\n", - "# maybe we should make the selection window empirically? or at least reference it from somewhere" + "plt.show()" ] }, { @@ -926,7 +995,7 @@ { "cell_type": "code", "execution_count": null, - "id": "1cf7f40e-4f13-4217-bd71-5b6342dac78e", + "id": "ffc3d379-eee2-4536-af6e-6ff48814f833", "metadata": {}, "outputs": [], "source": [] From a9ab6497dccf1eb18e68a02e5f3e79c472ccbc3f Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Mon, 8 Jun 2026 21:57:06 +0000 Subject: [PATCH 19/27] updating color sel nb --- .../303_Galaxies/303_3_Color_selections.ipynb | 146 +++++------------- 1 file changed, 41 insertions(+), 105 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 10fc8bed..bdbc2f6a 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -345,7 +345,6 @@ "outputs": [], "source": [ "is_vandels_z4 = (vandels_cdfs['zsp'] >= 3.7) & (vandels_cdfs['zsp'] <= 4.5) & (vandels_cdfs['q_zsp'] >= 3)\n", - "#is_vandels_z4 = (vandels_cdfs['zsp'] >= 3) & (vandels_cdfs['q_zsp'] >= 3)\n", "vandels_truth = vandels_cdfs[is_vandels_z4]\n", "print(f\"Found {len(vandels_truth)} high-confidence VANDELS sources at z~4\")" ] @@ -410,7 +409,7 @@ "source": [ "## 2.3 Plot color color diagrams\n", "\n", - "First, store some shorthand parameters for the colors of interest, and for parameters to color-code the galaxies by." + "First, store some shorthand parameters for the colors in the selection, and for parameters to color-code the galaxies by." ] }, { @@ -457,7 +456,11 @@ "id": "ef3b6dac-ec19-4f3c-9d61-ff9002385247", "metadata": {}, "source": [ - "Define a figure for the color color diagram. Plot all the Rubin galaxies from the query in Section 2.1 (gray), all Rubin galaxies that satisfy the LBG color selection (blue), and the true spectroscopically confirmed high-redshift galaxies as bold colored symbols. Stars indicate the true high-redshift galaxies that meet the color selection and plus signs are the true high-redshift galaxies that do not. " + "Define a figure for the color color diagram. Plot all the Rubin galaxies from the query in Section 2.1 (gray), all Rubin galaxies that satisfy the LBG color selection (blue), and the true spectroscopically confirmed high-redshift galaxies as bold colored symbols. Stars indicate the true high-redshift galaxies that meet the color selection and plus signs are the true high-redshift galaxies that do not. \n", + "\n", + "### 2.3.1 Magnitude dependence\n", + "\n", + "Color-code the galaxies by their i-band magnitude, to see if spectroscopically confirmed galaxies that are missed by the LBG selection might be faint, suggesting photometric scatter could contribute to missed galaxies." ] }, { @@ -509,6 +512,16 @@ "plt.show()" ] }, + { + "cell_type": "markdown", + "id": "ef30522a-274c-4ac2-99f2-4a391646d729", + "metadata": {}, + "source": [ + "### 2.3.2 Imaging depth dependence\n", + "\n", + "Color-code the galaxies by their g-band flux error, a proxy for the depth of the g-band imaging, to see if spectroscopically confirmed galaxies that are missed by the LBG selection might because the g-band imaging was not deep enough to provide a robust lower limit on the dropout color." + ] + }, { "cell_type": "code", "execution_count": null, @@ -574,7 +587,9 @@ "id": "8062a269-a6c8-43b2-ae46-88ebc8790912", "metadata": {}, "source": [ - "Since there is no obvious trend with i-band magnitude, color code the spectroscopically confirmed high-redshift galaxies by their redshift instead." + "### 2.3.3 Redshift dependence\n", + "\n", + "Since there is no obvious trend with magnitude or imaging depth, color code the spectroscopically confirmed high-redshift galaxies by their spectroscopic redshift. At the higher redshift end of the selection window, the g-band flux is completely undetected when the filter probes blueward of the Lyman limit (912A). But at lower end of the redshift selection window the g-band will probe blueward of Lyman alpha (1216A) and redward of the Lyman limit (912A) but will only be partially absorbed because of the Lyman-alpha forest. The amount of flux can vary. In the plot below, color-code by spectroscopic redshift to see if the bluer galaxies are at lower redshifts." ] }, { @@ -586,7 +601,7 @@ "source": [ "vmin, vmax = np.nanmin(v_z_spec), np.nanmax(v_z_spec)\n", "\n", - "fig, ax = plt.subplots(figsize=(11, 8))\n", + "fig, ax = plt.subplots(figsize=(10, 7))\n", "\n", "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Parent Sample (Rubin)')\n", "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", @@ -602,24 +617,17 @@ " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", " label='Confirmed LBG Candidates')\n", "\n", - "\n", "cbar = plt.colorbar(sc, ax=ax)\n", "cbar.set_label('Spectroscopic Redshift (VANDELS z_spec)', fontsize=12, fontweight='bold')\n", "\n", - "# Calculate the new intersection between the horizontal line (g-r = 1.0) and the diagonal\n", - "intersect_x = (1.0 - 0.8) / 1.5 # This equals ~0.133\n", - "x_diag = np.linspace(intersect_x, 1.0, 50)\n", - "y_diag = 1.5 * x_diag + 0.8\n", - "\n", - "# Draw the boundaries\n", "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5) \n", "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", "\n", "ax.set_xlim(-1.0, 2.0)\n", "ax.set_ylim(-1.0, 4.0)\n", - "ax.set_xlabel('$(r - i)$ [Robust Sersic Mag]', fontsize=14)\n", - "ax.set_ylabel('$(g - r)$ [Robust Sersic Mag]', fontsize=14)\n", + "ax.set_xlabel('$(r - i)$ [AB Mag]', fontsize=14)\n", + "ax.set_ylabel('$(g - r)$ [AB Mag]', fontsize=14)\n", "ax.set_title('Validation of Lyman Break Selection', fontsize=16, fontweight='bold')\n", "\n", "handles, labels = ax.get_legend_handles_labels()\n", @@ -635,7 +643,7 @@ "id": "4e702cae-4406-424f-abec-ec2375cfe0b6", "metadata": {}, "source": [ - "> Figure 2: UPDATE: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by i-band magnitude and their successful selection does not show any trend with magnitude." + "> Figure 2: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by spectroscopic redshift, and their successful selection does not show any trend with redshift." ] }, { @@ -643,7 +651,9 @@ "id": "2f0b8d97-06de-4226-b21b-782f7cbe56c5", "metadata": {}, "source": [ - "The color selection identifies a large number of true high-redshift galaxies. A number of confirmed galaxies fall outside the selection window. While the color selection is not designed to be 100% inclusive of high redshift galaxies, it should select a relatively pure sample with few interlopers. Galaxies my reside outside the selection box due to photometric scatter, dust attenuation in the galaxy reddening the restframe UV probed by the r-i color and similarly decreasing the brightness of the observed r band flux (thus making the g-r color less robustly constrained). A possible effect from DP1 could also be the known issue of a small fraction of red-wavelength photon leak in the g-band which might contaminate the dropout filter with redder-wavelength light from the galaxy. This effect is exacerbated by the higher operating temperature of LSSTComCam during commissioning and is expected to be resolved in DP2 LSSTCam data.\n" + "### 2.3.4 Interpretation\n", + "\n", + "The color selection identifies a large number of true high-redshift galaxies. A number of confirmed galaxies fall outside the selection window. While the color selection is not designed to be 100% inclusive of high redshift galaxies, it should select a relatively pure sample with few interlopers. Galaxies my reside outside the selection box do not seem to trend with any single property tested in Section 2.3.1-2.3.3, but may be caused by a combination of photometric scatter, dust attenuation in the galaxy reddening the restframe UV probed by the r-i color and similarly decreasing the brightness of the observed r band flux (thus making the g-r color less robustly constrained). A possible effect from DP1 could also be the known issue of a small fraction of red-wavelength photon leak in the g-band which might contaminate the dropout filter with redder-wavelength light from the galaxy. This effect is exacerbated by the higher operating temperature of LSSTComCam during commissioning and is expected to be resolved in DP2 LSSTCam data.\n" ] }, { @@ -693,16 +703,14 @@ "\n", " filters = ['u', 'g', 'r', 'i']\n", " fig, axes = plt.subplots(n_plot, len(filters), figsize=(12, 3.5 * n_plot))\n", - " if n_plot == 1: axes = [axes] # Ensure 2D array structure\n", + " if n_plot == 1: axes = [axes]\n", "\n", - " print(f\"Requesting SODA cutouts for {n_plot} sources: {title_label}...\")\n", + " print(f\"Requesting cutouts for {n_plot} sources: {title_label}...\")\n", "\n", " for row_idx in range(n_plot):\n", " ra = r_data['coord_ra'][row_idx]\n", " dec = r_data['coord_dec'][row_idx]\n", " obj_id = r_data['objectId'][row_idx]\n", - " \n", - " # Pull data from our aligned tables\n", " z_spec = v_data['zsp'][row_idx]\n", " g_r = r_data['g_minus_r'][row_idx] \n", " r_i = r_data['r_minus_i'][row_idx]\n", @@ -750,8 +758,7 @@ " ax.set_ylabel(label_str, rotation=0, labelpad=70, ha='center', fontweight='bold')\n", "\n", " plt.tight_layout()\n", - " plt.show()\n", - "\n" + " plt.show()" ] }, { @@ -759,18 +766,20 @@ "id": "e855ba72-793a-47d1-8871-1ca6faac0246", "metadata": {}, "source": [ - "Now plot the 4-filter cutouts for the real high redshift galaxies confirmed by VANDELS but that the Rubin color selection missed. They are a mix of galaxies with too-blue g-r colors and too-red r-i colors." + "Now plot the 4-filter cutouts for the real high redshift galaxies confirmed by VANDELS that were identified correctly in the Rubin color selection. " ] }, { "cell_type": "code", "execution_count": null, - "id": "7d34a329-15fc-433f-942e-6b6e7e396ff3", + "id": "25b4985a-9006-4cf8-a7dd-f217562ee164", "metadata": {}, "outputs": [], "source": [ - "plot_cutouts(missed_r_data, missed_v_truth, n_max=30,\n", - " title_label=\"VANDELS high-z confirmations missed by Rubin color selection\")" + "print(f\"Total confirmed VANDELS LBGs available to plot: {len(confirmed_r_data)}\")\n", + "\n", + "plot_cutouts(confirmed_r_data, confirmed_v_truth, n_max=5,\n", + " title_label=\"VANDELS high-z confirmations identified by Rubin color selection\")" ] }, { @@ -778,21 +787,20 @@ "id": "cfb13a25-127d-4594-9e61-685f93e76e73", "metadata": {}, "source": [ - "> Figure X:\n", + "> Figure X: Deep coadd image cutouts of a few confirmed high-redshift galaxies that are selected as LBGs from the Rubin imaging. As expected for galaxies at z > 3.5, the galaxies are not detected in the u-band, their flux is significantly decreased in the g-band, and are detected in r and i-bands.\n", "\n", - "Optionally, also generate cutouts of the true high-redshift galaxies that were successfully identified by the color selection." + "Optionally, also generate cutouts of the true high-redshift galaxies that were missed the color selection. Now plot the 4-filter cutouts for the real high redshift galaxies confirmed by VANDELS but that the Rubin color selection missed. They are a mix of galaxies with too-blue g-r colors and too-red r-i colors." ] }, { "cell_type": "code", "execution_count": null, - "id": "25b4985a-9006-4cf8-a7dd-f217562ee164", + "id": "7d34a329-15fc-433f-942e-6b6e7e396ff3", "metadata": {}, "outputs": [], "source": [ - "print(f\"Total confirmed VANDELS LBGs available to plot: {len(confirmed_r_data)}\")\n", - "\n", - "#plot_cutouts(confirmed_r_data, confirmed_v_truth, n_max=20, title_label=\"Confirmed LBG Selection (True Positives)\")" + "#plot_cutouts(missed_r_data, missed_v_truth, n_max=5,\n", + "# title_label=\"VANDELS high-z confirmations missed by Rubin color selection\")" ] }, { @@ -925,80 +933,8 @@ "id": "82d9acbc-e0c4-4049-90c6-1b8f13af5326", "metadata": {}, "source": [ - "> Figure X: Histogram of the redshifts of all spectroscopically confirmed galaxies that enter the lyman-break color selection, indicating a very low interloper fraction" - ] - }, - { - "cell_type": "markdown", - "id": "6f76f775-b947-44ec-acb2-e5b590e029fd", - "metadata": {}, - "source": [ - "### purity and completeness and other stuff\n", - "\n", - "I think this is not insulated from any biases in the VANDELS slit assignment... TBD" + "> Figure X: Histogram of the redshifts of all spectroscopically confirmed galaxies that enter the Lyman-break color selection, indicating a very low interloper fraction. The selection window with Rubin data matches the one characterized by Ono et al. 2018 (green) using HSC data and the same color criteria (3.2 < z < 4.5)." ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "73ec3135-52b0-4cfb-9125-3d7d4ed0ffc0", - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "print(\"--- Calculating DP1 LBG Selection Metrics (Completeness & Purity) ---\")\n", - "\n", - "# 1. Isolate ALL high-quality VANDELS spectra (not just z~4)\n", - "is_vandels_hq = vandels_cdfs['q_zsp'] >= 3\n", - "vandels_all_hq = vandels_cdfs[is_vandels_hq]\n", - "\n", - "# 2. Cross-match to the Rubin Object Table\n", - "coord_v_all = SkyCoord(ra=vandels_all_hq['RAJ2000'], dec=vandels_all_hq['DEJ2000'], unit='deg')\n", - "coord_r = SkyCoord(ra=tab['coord_ra'], dec=tab['coord_dec'], unit='deg')\n", - "\n", - "idx_rubin_all, d2d_all, _ = coord_v_all.match_to_catalog_sky(coord_r)\n", - "match_mask_all = d2d_all < 1.0 * u.arcsec\n", - "\n", - "matched_rubin_all = tab[idx_rubin_all[match_mask_all]]\n", - "matched_v_all = vandels_all_hq[match_mask_all]\n", - "\n", - "# 3. Define the \"Ground Truth\" (3.5 <= spec-z <= 4.5)\n", - "is_true_z4 = (matched_v_all['zsp'] >= 3.2) & (matched_v_all['zsp'] <= 4.5)\n", - "\n", - "# 4. Define the \"Photometric Selection\" (Ono et al. 2018 Criteria)\n", - "# Applying the exact same mask to the matched Rubin data\n", - "is_selected_lbg = (\n", - " (matched_rubin_all['g_minus_r'] > 1.0) & \n", - " (matched_rubin_all['u_sersicFlux'] / matched_rubin_all['u_sersicFluxErr'] < 3) & \n", - " (matched_rubin_all['r_minus_i'] < 1.0) & \n", - " (matched_rubin_all['g_minus_r'] > 1.5 * matched_rubin_all['r_minus_i'] + 0.8)\n", - ")\n", - "\n", - "# 5. Calculate Confusion Matrix Elements\n", - "true_positives = np.sum(is_true_z4 & is_selected_lbg) # Real z~4 and Selected\n", - "false_positives = np.sum(~is_true_z4 & is_selected_lbg) # Not z~4 but Selected (Interlopers)\n", - "false_negatives = np.sum(is_true_z4 & ~is_selected_lbg) # Real z~4 but Missed\n", - "\n", - "# 6. Calculate Metrics\n", - "completeness = true_positives / (true_positives + false_negatives) if (true_positives + false_negatives) > 0 else 0\n", - "purity = true_positives / (true_positives + false_positives) if (true_positives + false_positives) > 0 else 0\n", - "\n", - "print(f\"Total VANDELS spectra evaluated (u-band lim included): {len(matched_v_all)}\")\n", - "print(f\"True Positives (Recovered): {true_positives}\")\n", - "print(f\"False Negatives (Missed): {false_negatives}\")\n", - "print(f\"False Positives (Contaminants): {false_positives}\\n\")\n", - "\n", - "print(f\"COMPLETENESS: {completeness:.1%} <-- (Fraction of real z~4 galaxies we successfully found)\")\n", - "print(f\"PURITY: {purity:.1%} <-- (Fraction of our photometric candidates that are truly at z~4)\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ffc3d379-eee2-4536-af6e-6ff48814f833", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { From c508805f58fe56116dfa647e3de57944530aee90 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Mon, 8 Jun 2026 22:10:14 +0000 Subject: [PATCH 20/27] updating color sel nb --- .../303_Galaxies/303_3_Color_selections.ipynb | 62 +++++++++++-------- 1 file changed, 36 insertions(+), 26 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index bdbc2f6a..451f9e90 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -22,7 +22,7 @@ "Data Release: Data Preview 1
\n", "Container Size: large
\n", "LSST Science Pipelines version: r29.2.0
\n", - "Last verified to run: 2025-09-02
\n", + "Last verified to run: 2026-06-08
\n", "Repository: github.com/lsst/tutorial-notebooks
" ] }, @@ -282,6 +282,11 @@ "\n", "Now, perform the color selection to identify the high-redshift galaxy candidates. Use a typical Lyman break selection for a camera with similar filter properties to the LSST (e.g. Ono et al. 2018). The selection requires very red g-r colors (to identify galaxies with strong Lyman breaks), and relatively blue r-i colors (typical of star-forming galaxies with little dust, and which excludes stars). \n", "\n", + "Use the selection criteria for z~4 LBGs defined in Ono et al. 2018, which are:\n", + "1. g - r > 1.0\n", + "2. r - i < 1.0\n", + "3. g - r > 1.5 * (r - i) + 0.8\n", + "\n", "Also, add another criteria requiring that the u-band flux be undetected (S/N < 3), since all u-band flux should also be absorbed by the intergalactic medium since it is blueward of the Lyman limit at z > 3." ] }, @@ -388,8 +393,6 @@ "metadata": {}, "outputs": [], "source": [ - "# sort out which masks apply to which parent array, color coding in the following plots could be wrong\n", - "\n", "matched_rubin_indices = idx_rubin[match_mask] \n", "vandels_in_rubin = tab[matched_rubin_indices]\n", "v_matched_truth = vandels_truth[match_mask]\n", @@ -433,10 +436,7 @@ "id": "b381133b-22e6-46e1-957e-75a62d1b6c6e", "metadata": {}, "source": [ - "Use the selection criteria for z~4 LBGs defined in Ono et al. 2018, which are :\n", - "1. g - r > 1.0\n", - "2. r - i < 1.0\n", - "3. g - r > 1.5 * (r - i) + 0.8" + "Define the selection window from Ono et al. 2018 to plot in the color color diagram. " ] }, { @@ -470,12 +470,10 @@ "metadata": {}, "outputs": [], "source": [ - "fig, ax = plt.subplots(figsize=(11, 8))\n", + "fig, ax = plt.subplots(figsize=(9, 6))\n", "\n", "vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", "\n", - "#vmin, vmax = 24, np.nanmax(v_i_mag)\n", - "\n", "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Rubin Parent Sample')\n", "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates')\n", @@ -531,12 +529,9 @@ "source": [ "v_gerr = vandels_in_rubin['g_sersicFluxErr']\n", "\n", + "fig, ax = plt.subplots(figsize=(9, 6))\n", "\n", - "fig, ax = plt.subplots(figsize=(11, 8))\n", - "\n", - "#vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", "vmin, vmax = np.nanmin(v_gerr), 20 #np.nanmax(v_gerr)\n", - "#vmin, vmax = 0, np.nanmax(v_i_minus_z)\n", "\n", "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Rubin Parent Sample')\n", "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", @@ -554,7 +549,6 @@ "\n", "cbar = plt.colorbar(sc, ax=ax)\n", "cbar.set_label('g-band flux err (njy)', fontsize=12, fontweight='bold')\n", - "#cbar.ax.invert_yaxis()\n", "\n", "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5) \n", "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", @@ -601,7 +595,7 @@ "source": [ "vmin, vmax = np.nanmin(v_z_spec), np.nanmax(v_z_spec)\n", "\n", - "fig, ax = plt.subplots(figsize=(10, 7))\n", + "fig, ax = plt.subplots(figsize=(9, 6))\n", "\n", "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Parent Sample (Rubin)')\n", "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", @@ -653,7 +647,9 @@ "source": [ "### 2.3.4 Interpretation\n", "\n", - "The color selection identifies a large number of true high-redshift galaxies. A number of confirmed galaxies fall outside the selection window. While the color selection is not designed to be 100% inclusive of high redshift galaxies, it should select a relatively pure sample with few interlopers. Galaxies my reside outside the selection box do not seem to trend with any single property tested in Section 2.3.1-2.3.3, but may be caused by a combination of photometric scatter, dust attenuation in the galaxy reddening the restframe UV probed by the r-i color and similarly decreasing the brightness of the observed r band flux (thus making the g-r color less robustly constrained). A possible effect from DP1 could also be the known issue of a small fraction of red-wavelength photon leak in the g-band which might contaminate the dropout filter with redder-wavelength light from the galaxy. This effect is exacerbated by the higher operating temperature of LSSTComCam during commissioning and is expected to be resolved in DP2 LSSTCam data.\n" + "The color selection identifies a large number of true high-redshift galaxies. A number of confirmed galaxies fall outside the selection window. While the color selection is not designed to be 100% inclusive of high redshift galaxies, it should select a relatively pure sample with few interlopers. Galaxies my reside outside the selection box do not seem to trend with any single property tested in Section 2.3.1-2.3.3, but may be caused by a combination of photometric scatter, variation in depth of the g-band imaging, and that the strength of the g-r color will vary across the redshift selection window. Other effects also contribute: dust attenuation in the galaxy will redden the restframe UV probed by the r-i color and similarly decreasing the brightness of the observed r band flux (thus making the g-r color less robustly constrained). A possible effect from DP1 could also be the known issue of a small fraction of red-wavelength photon leak in the g-band which might contaminate the dropout filter with redder-wavelength light from the galaxy. This effect is exacerbated by the higher operating temperature of LSSTComCam during commissioning and is expected to be resolved in DP2 LSSTCam data.\n", + "\n", + "This exemplifies how photometric selection is statistical in nature. While the physics of the Lyman break creates the strong spectral feature that can be exploited for a simple selection, the photometric noise and intrinsic galaxy variations will scatter the galaxy colors in and out of the selection box.\n" ] }, { @@ -663,7 +659,7 @@ "source": [ "# 3. Visual inspection\n", "\n", - "Finally, generate image cutouts to visually inspect both the missed and confirmed subsets of spectroscopically confirmed galaxies." + "Finally, generate image cutouts to visually inspect both the missed and confirmed subsets of spectroscopically confirmed galaxies. This validation is necessary to confirm the fidelity of the sample." ] }, { @@ -879,16 +875,30 @@ " (matched_rubin_all['g_minus_r'] > 1.5 * matched_rubin_all['r_minus_i'] + 0.8)\n", ")\n", "\n", - "# Extract the true spectroscopic redshifts of ONLY the galaxies inside our color box\n", - "selected_spec_z = matched_v_all['zsp'][is_selected_lbg]\n", - "# Invert the mask with ~ to find where it is False\n", - "failed_lbg_indices = np.where(~is_selected_lbg)[0] # this is wrong, you want to find which spec-z are < 3 among hte selected ones\n", + "selected_spec_z = matched_v_all['zsp'][is_selected_lbg]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7c8fcb4-a880-43a3-9caf-b276bef802cd", + "metadata": {}, + "outputs": [], + "source": [ + "Next, identify low-redshift interlopers that met the color selection criteria." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dcf83ef8-c385-42b2-bf84-85ffceeb0ba1", + "metadata": {}, + "outputs": [], + "source": [ + "failed_lbg_indices = np.where(matched_v_all['zsp'][is_selected_lbg] < 3)[0] \n", "\n", "print(f\"Found {len(selected_spec_z)} out of {len(matched_v_all['zsp'])} VANDELS sources inside the color selection box.\")\n", - "#print(f\"indicating a {len(failed_spec_z)/len(matched_v_all['zsp'])*100}% interloper fraction\")\n", - "\n", - "\n", - "# maybe we should make the selection window empirically? or at least reference it from somewhere" + "#print(f\"indicating a {len(failed_spec_z)/len(matched_v_all['zsp'])*100}% interloper fraction\")\n" ] }, { From b0ba332d6d3669eb833c9e89a74cdf019ff6beb4 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Mon, 8 Jun 2026 22:12:48 +0000 Subject: [PATCH 21/27] updating color sel nb --- .../303_Galaxies/303_3_Color_selections.ipynb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 451f9e90..3e59d4f1 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -875,17 +875,15 @@ " (matched_rubin_all['g_minus_r'] > 1.5 * matched_rubin_all['r_minus_i'] + 0.8)\n", ")\n", "\n", - "selected_spec_z = matched_v_all['zsp'][is_selected_lbg]" + "selected_spec_z = matched_v_all['zsp'][is_selected_lbg]\n" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "id": "e7c8fcb4-a880-43a3-9caf-b276bef802cd", "metadata": {}, - "outputs": [], "source": [ - "Next, identify low-redshift interlopers that met the color selection criteria." + "Next, identify low-redshift interlopers that met the color selection criteria, and compare." ] }, { @@ -898,7 +896,8 @@ "failed_lbg_indices = np.where(matched_v_all['zsp'][is_selected_lbg] < 3)[0] \n", "\n", "print(f\"Found {len(selected_spec_z)} out of {len(matched_v_all['zsp'])} VANDELS sources inside the color selection box.\")\n", - "#print(f\"indicating a {len(failed_spec_z)/len(matched_v_all['zsp'])*100}% interloper fraction\")\n" + "print(f\"Found {len(failed_spec_z)} LBG candidates that are confirmed low redshift interlopers,\")\n", + "print(f\"indicating a {len(failed_spec_z)/len(matched_v_all['zsp'])*100}% interloper fraction\")\n" ] }, { From d18052290cfcbb4175f0078b31300c39f22077b6 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Mon, 8 Jun 2026 22:58:54 +0000 Subject: [PATCH 22/27] finished color color nb --- .../303_Galaxies/303_3_Color_selections.ipynb | 186 ++++++++++-------- 1 file changed, 100 insertions(+), 86 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 3e59d4f1..8144950b 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -167,24 +167,25 @@ { "cell_type": "code", "execution_count": null, - "id": "a22963fc-ef6b-40b7-8e95-1a07d7e264d3", + "id": "e5ba0d7b-861f-4874-bd05-819a7ebcc4b4", "metadata": {}, "outputs": [], "source": [ - "query = f\"\"\"\n", - "SELECT obj.objectId, obj.coord_ra, obj.coord_dec,\n", - " obj.u_sersicFlux, obj.u_sersicFluxErr,\n", - " obj.g_sersicFlux, obj.g_sersicFluxErr,\n", - " obj.r_sersicFlux, obj.r_sersicFluxErr,\n", - " obj.i_sersicFlux, obj.i_sersicFluxErr,\n", - " obj.z_sersicFlux, obj.z_sersicFluxErr\n", - "FROM dp1.Object AS obj\n", - "WHERE (obj.i_sersicFlux/obj.i_sersicFluxErr > 10) \n", - " AND (obj.i_extendedness = 1) \n", - " AND (obj.sersic_no_data_flag = 0) \n", - " AND (obj.i_cModel_flag = 0) \n", - " AND CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), CIRCLE('ICRS', {target_ra}, {target_dec}, 0.5)) = 1\n", - "\"\"\"" + "query = (\n", + " \"SELECT obj.objectId, obj.coord_ra, obj.coord_dec, \"\n", + " \"obj.u_sersicFlux, obj.u_sersicFluxErr, \"\n", + " \"obj.g_sersicFlux, obj.g_sersicFluxErr, \"\n", + " \"obj.r_sersicFlux, obj.r_sersicFluxErr, \"\n", + " \"obj.i_sersicFlux, obj.i_sersicFluxErr, \"\n", + " \"obj.z_sersicFlux, obj.z_sersicFluxErr \"\n", + " \"FROM dp1.Object AS obj \"\n", + " \"WHERE (obj.i_sersicFlux / obj.i_sersicFluxErr > 10) \"\n", + " \"AND (obj.i_extendedness = 1) \"\n", + " \"AND (obj.sersic_no_data_flag = 0) \"\n", + " \"AND (obj.i_cModel_flag = 0) \"\n", + " \"AND CONTAINS(POINT('ICRS', obj.coord_ra, obj.coord_dec), \"\n", + " f\"CIRCLE('ICRS', {target_ra}, {target_dec}, 0.5)) = 1\"\n", + ")" ] }, { @@ -243,14 +244,14 @@ "metadata": {}, "outputs": [], "source": [ - "filters = ['u', 'g', 'r', 'i', 'z']\n", + "filters = ['u', 'g', 'r', 'i']\n", "\n", "with np.errstate(divide='ignore', invalid='ignore'):\n", " for f in filters:\n", - " flux_robust = np.where(tab[f'{f}_sersicFlux'] < tab[f'{f}_sersicFluxErr'], \n", - " tab[f'{f}_sersicFluxErr'], \n", + " flux_robust = np.where(tab[f'{f}_sersicFlux'] < tab[f'{f}_sersicFluxErr'],\n", + " tab[f'{f}_sersicFluxErr'],\n", " tab[f'{f}_sersicFlux'])\n", - " tab[f'{f}_mag_robust'] = -2.50 * np.log10(flux_robust) + 31.4\n" + " tab[f'{f}_mag_robust'] = -2.50 * np.log10(flux_robust) + 31.4" ] }, { @@ -269,8 +270,7 @@ "outputs": [], "source": [ "tab['g_minus_r'] = tab['g_mag_robust'] - tab['r_mag_robust']\n", - "tab['r_minus_i'] = tab['r_mag_robust'] - tab['i_mag_robust']\n", - "tab['i_minus_z'] = tab['i_mag_robust'] - tab['z_mag_robust']" + "tab['r_minus_i'] = tab['r_mag_robust'] - tab['i_mag_robust']" ] }, { @@ -297,12 +297,10 @@ "metadata": {}, "outputs": [], "source": [ - "is_z4_lbg = (\n", - " (tab['g_minus_r'] > 1.0) & \n", - " (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3) &\n", - " (tab['r_minus_i'] < 1.0) & \n", - " (tab['g_minus_r'] > 1.5 * tab['r_minus_i'] + 0.8)\n", - ")\n", + "is_z4_lbg = ((tab['g_minus_r'] > 1.0)\n", + " & (tab['u_sersicFlux'] / tab['u_sersicFluxErr'] < 3)\n", + " & (tab['r_minus_i'] < 1.0)\n", + " & (tab['g_minus_r'] > 1.5 * tab['r_minus_i'] + 0.8))\n", "\n", "print(f\"Identified {np.sum(is_z4_lbg)} photometric LBG candidates.\")" ] @@ -331,7 +329,7 @@ "v = Vizier(columns=['**'], catalog=\"J/A+A/647/A150\")\n", "v.ROW_LIMIT = -1\n", "all_tables = v.get_catalogs(\"J/A+A/647/A150\")\n", - "vandels_cdfs = all_tables[0] " + "vandels_cdfs = all_tables[0]" ] }, { @@ -349,7 +347,9 @@ "metadata": {}, "outputs": [], "source": [ - "is_vandels_z4 = (vandels_cdfs['zsp'] >= 3.7) & (vandels_cdfs['zsp'] <= 4.5) & (vandels_cdfs['q_zsp'] >= 3)\n", + "is_vandels_z4 = ((vandels_cdfs['zsp'] >= 3.7)\n", + " & (vandels_cdfs['zsp'] <= 4.5)\n", + " & (vandels_cdfs['q_zsp'] >= 3))\n", "vandels_truth = vandels_cdfs[is_vandels_z4]\n", "print(f\"Found {len(vandels_truth)} high-confidence VANDELS sources at z~4\")" ] @@ -393,7 +393,7 @@ "metadata": {}, "outputs": [], "source": [ - "matched_rubin_indices = idx_rubin[match_mask] \n", + "matched_rubin_indices = idx_rubin[match_mask]\n", "vandels_in_rubin = tab[matched_rubin_indices]\n", "v_matched_truth = vandels_truth[match_mask]\n", "\n", @@ -424,11 +424,9 @@ "source": [ "v_g_minus_r = vandels_in_rubin['g_minus_r']\n", "v_r_minus_i = vandels_in_rubin['r_minus_i']\n", - "v_i_minus_z = vandels_in_rubin['i_minus_z']\n", "v_i_mag = vandels_in_rubin['i_mag_robust']\n", "v_z_spec = v_matched_truth['zsp']\n", - "#v_g_err = vandels_in_rubin['g\n", - "v_gerr = vandels_in_rubin['g_sersicFluxErr']\n" + "v_gerr = vandels_in_rubin['g_sersicFluxErr']" ] }, { @@ -472,19 +470,20 @@ "source": [ "fig, ax = plt.subplots(figsize=(9, 6))\n", "\n", - "vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", + "vmin, vmax = np.nanmin(v_i_mag), np.nanmax(v_i_mag)\n", "\n", - "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Rubin Parent Sample')\n", - "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", + "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray',\n", + " alpha=0.3, label='Rubin Parent Sample')\n", + "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg],\n", " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates')\n", "\n", - "sc = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", - " s=120, c=v_i_mag[failed_lbg], cmap='viridis', vmin=vmin, vmax=vmax, \n", + "sc = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg],\n", + " s=120, c=v_i_mag[failed_lbg], cmap='viridis', vmin=vmin, vmax=vmax,\n", " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", " label='VANDELS Truth (Missed)')\n", "\n", - "sc = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", - " s=250, c=v_i_mag[lbg_success_mask], cmap='viridis', vmin=vmin, vmax=vmax, \n", + "sc = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask],\n", + " s=250, c=v_i_mag[lbg_success_mask], cmap='viridis', vmin=vmin, vmax=vmax,\n", " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", " label='Confirmed LBG Candidates')\n", "\n", @@ -492,7 +491,7 @@ "cbar.set_label('i-band [Sersic Mag]', fontsize=12, fontweight='bold')\n", "cbar.ax.invert_yaxis()\n", "\n", - "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5) \n", + "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5)\n", "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", "\n", @@ -515,6 +514,8 @@ "id": "ef30522a-274c-4ac2-99f2-4a391646d729", "metadata": {}, "source": [ + "> Figure 1: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by i-band magnitude and their successful selection does not show any trend with magnitude (which might be expected if photometric scatter.\n", + "\n", "### 2.3.2 Imaging depth dependence\n", "\n", "Color-code the galaxies by their g-band flux error, a proxy for the depth of the g-band imaging, to see if spectroscopically confirmed galaxies that are missed by the LBG selection might because the g-band imaging was not deep enough to provide a robust lower limit on the dropout color." @@ -531,26 +532,27 @@ "\n", "fig, ax = plt.subplots(figsize=(9, 6))\n", "\n", - "vmin, vmax = np.nanmin(v_gerr), 20 #np.nanmax(v_gerr)\n", + "vmin, vmax = np.nanmin(v_gerr), 20\n", "\n", - "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Rubin Parent Sample')\n", - "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", + "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray',\n", + " alpha=0.3, label='Rubin Parent Sample')\n", + "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg],\n", " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates')\n", "\n", - "sc = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", - " s=120, c=v_gerr[failed_lbg], cmap='viridis', vmin=vmin, vmax=vmax, \n", + "sc = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg],\n", + " s=120, c=v_gerr[failed_lbg], cmap='viridis', vmin=vmin, vmax=vmax,\n", " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", " label='VANDELS Truth (Missed)')\n", "\n", - "sc = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", - " s=250, c=v_gerr[lbg_success_mask], cmap='viridis', vmin=vmin, vmax=vmax, \n", + "sc = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask],\n", + " s=250, c=v_gerr[lbg_success_mask], cmap='viridis', vmin=vmin, vmax=vmax,\n", " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", " label='Confirmed LBG Candidates')\n", "\n", "cbar = plt.colorbar(sc, ax=ax)\n", "cbar.set_label('g-band flux err (njy)', fontsize=12, fontweight='bold')\n", "\n", - "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5) \n", + "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5)\n", "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", "\n", @@ -573,7 +575,7 @@ "id": "b2849d83-8780-4a28-8b31-2f52e5365aa0", "metadata": {}, "source": [ - "> Figure 1: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by i-band magnitude and their successful selection does not show any trend with magnitude (which might be expected if photometric scatter ." + "> Figure 2: Like Figure 2, except that confirmed galaxies are color coded by g-band flux uncertainty as a proxy for variations in the depth or integration time in the g-band filter imaging. Their unsuccessful selection does not show any trend with image depth (which might be expected if galaxies in shallower imaging have smaller lower limits to the g-r color)." ] }, { @@ -597,24 +599,25 @@ "\n", "fig, ax = plt.subplots(figsize=(9, 6))\n", "\n", - "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3, label='Parent Sample (Rubin)')\n", - "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg], \n", + "ax.scatter(tab['r_minus_i'], tab['g_minus_r'], s=2, color='lightgray', alpha=0.3,\n", + " label='Parent Sample (Rubin)')\n", + "ax.scatter(tab['r_minus_i'][is_z4_lbg], tab['g_minus_r'][is_z4_lbg],\n", " s=15, color='dodgerblue', alpha=0.1, label='Rubin LBG Candidates (g-r > 1.5)')\n", "\n", - "sc = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg], \n", - " s=120, c=v_z_spec[failed_lbg], cmap='plasma', vmin=vmin, vmax=vmax, \n", + "sc = ax.scatter(v_r_minus_i[failed_lbg], v_g_minus_r[failed_lbg],\n", + " s=120, c=v_z_spec[failed_lbg], cmap='plasma', vmin=vmin, vmax=vmax,\n", " marker='P', edgecolor='k', linewidth=0.5, zorder=4,\n", " label='VANDELS Truth (Missed)')\n", "\n", - "sc = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask], \n", - " s=250, c=v_z_spec[lbg_success_mask], cmap='plasma', vmin=vmin, vmax=vmax, \n", + "sc = ax.scatter(v_r_minus_i[lbg_success_mask], v_g_minus_r[lbg_success_mask],\n", + " s=250, c=v_z_spec[lbg_success_mask], cmap='plasma', vmin=vmin, vmax=vmax,\n", " marker='*', edgecolor='k', linewidth=0.8, zorder=5,\n", " label='Confirmed LBG Candidates')\n", "\n", "cbar = plt.colorbar(sc, ax=ax)\n", "cbar.set_label('Spectroscopic Redshift (VANDELS z_spec)', fontsize=12, fontweight='bold')\n", "\n", - "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5) \n", + "ax.plot([-1.5, intersect_x], [1.0, 1.0], color='black', linestyle='--', lw=1.5)\n", "ax.plot(x_diag, y_diag, color='black', linestyle='--', lw=1.5)\n", "ax.plot([1.0, 1.0], [2.3, 4.0], color='black', linestyle='--', lw=1.5)\n", "\n", @@ -637,7 +640,7 @@ "id": "4e702cae-4406-424f-abec-ec2375cfe0b6", "metadata": {}, "source": [ - "> Figure 2: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by spectroscopic redshift, and their successful selection does not show any trend with redshift." + "> Figure 3: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by spectroscopic redshift, and their successful selection does not show any trend with redshift." ] }, { @@ -699,7 +702,8 @@ "\n", " filters = ['u', 'g', 'r', 'i']\n", " fig, axes = plt.subplots(n_plot, len(filters), figsize=(12, 3.5 * n_plot))\n", - " if n_plot == 1: axes = [axes]\n", + " if n_plot == 1:\n", + " axes = [axes]\n", "\n", " print(f\"Requesting cutouts for {n_plot} sources: {title_label}...\")\n", "\n", @@ -708,7 +712,7 @@ " dec = r_data['coord_dec'][row_idx]\n", " obj_id = r_data['objectId'][row_idx]\n", " z_spec = v_data['zsp'][row_idx]\n", - " g_r = r_data['g_minus_r'][row_idx] \n", + " g_r = r_data['g_minus_r'][row_idx]\n", " r_i = r_data['r_minus_i'][row_idx]\n", "\n", " query = f\"\"\"\n", @@ -732,25 +736,31 @@ " dl_result.get_adhocservice_by_id(\"cutout-sync\"),\n", " session=session)\n", " sq.circle = (ra * u.deg, dec * u.deg, 10.0 / 3600.0 * u.deg)\n", - " \n", + "\n", " cutout_bytes = sq.execute_stream().read()\n", " hdul = fits.open(io.BytesIO(cutout_bytes))\n", " img_array = hdul[1].data\n", "\n", - " norm = ImageNormalize(img_array, interval=ZScaleInterval(), stretch=LinearStretch())\n", + " norm = ImageNormalize(img_array, interval=ZScaleInterval(),\n", + " stretch=LinearStretch())\n", " ax.imshow(img_array, origin='lower', cmap='gray', norm=norm)\n", " cy, cx = img_array.shape[0]//2, img_array.shape[1]//2\n", - " ax.add_patch(plt.Circle((cx, cy), radius=6, color='cyan', fill=False, lw=1.5, alpha=0.7))\n", + " ax.add_patch(plt.Circle((cx, cy), radius=6, color='cyan',\n", + " fill=False, lw=1.5, alpha=0.7))\n", "\n", " except Exception:\n", - " ax.text(0.5, 0.5, 'SODA Error', ha='center', va='center', transform=ax.transAxes, color='red')\n", + " ax.text(0.5, 0.5, 'SODA Error', ha='center', va='center',\n", + " transform=ax.transAxes, color='red')\n", " else:\n", - " ax.text(0.5, 0.5, 'No Coverage', ha='center', va='center', transform=ax.transAxes, color='red')\n", + " ax.text(0.5, 0.5, 'No Coverage', ha='center', va='center',\n", + " transform=ax.transAxes, color='red')\n", "\n", - " ax.set_xticks([]); ax.set_yticks([])\n", - " if row_idx == 0: ax.set_title(f\"{f}-band\", fontsize=15, fontweight='bold')\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + " if row_idx == 0:\n", + " ax.set_title(f\"{f}-band\", fontsize=15, fontweight='bold')\n", " if col_idx == 0:\n", - " label_str = f\"z_sp: {z_spec:.2f}\\nID:{obj_id}\\ng-r: {g_r:.2f}\\nr-i={r_i:.2f}\"\n", + " label_str = f\"z_sp: {z_spec: .2f}\\nID: {obj_id}\\ng-r: {g_r: .2f}\\nr-i={r_i: .2f}\"\n", " ax.set_ylabel(label_str, rotation=0, labelpad=70, ha='center', fontweight='bold')\n", "\n", " plt.tight_layout()\n", @@ -783,7 +793,7 @@ "id": "cfb13a25-127d-4594-9e61-685f93e76e73", "metadata": {}, "source": [ - "> Figure X: Deep coadd image cutouts of a few confirmed high-redshift galaxies that are selected as LBGs from the Rubin imaging. As expected for galaxies at z > 3.5, the galaxies are not detected in the u-band, their flux is significantly decreased in the g-band, and are detected in r and i-bands.\n", + "> Figure 4: Deep coadd image cutouts of a few confirmed high-redshift galaxies that are selected as LBGs from the Rubin imaging. As expected for galaxies at z > 3.5, the galaxies are not detected in the u-band, their flux is significantly decreased in the g-band, and are detected in r and i-bands.\n", "\n", "Optionally, also generate cutouts of the true high-redshift galaxies that were missed the color selection. Now plot the 4-filter cutouts for the real high redshift galaxies confirmed by VANDELS but that the Rubin color selection missed. They are a mix of galaxies with too-blue g-r colors and too-red r-i colors." ] @@ -795,8 +805,8 @@ "metadata": {}, "outputs": [], "source": [ - "#plot_cutouts(missed_r_data, missed_v_truth, n_max=5,\n", - "# title_label=\"VANDELS high-z confirmations missed by Rubin color selection\")" + "# plot_cutouts(missed_r_data, missed_v_truth, n_max=5,\n", + "# title_label=\"VANDELS high-z confirmations missed by Rubin color selection\")" ] }, { @@ -869,13 +879,12 @@ "outputs": [], "source": [ "is_selected_lbg = (\n", - " (matched_rubin_all['g_minus_r'] > 1.0) & \n", - " (matched_rubin_all['u_sersicFlux'] / matched_rubin_all['u_sersicFluxErr'] < 3) & \n", - " (matched_rubin_all['r_minus_i'] < 1.0) & \n", - " (matched_rubin_all['g_minus_r'] > 1.5 * matched_rubin_all['r_minus_i'] + 0.8)\n", - ")\n", + " (matched_rubin_all['g_minus_r'] > 1.0)\n", + " & (matched_rubin_all['u_sersicFlux'] / matched_rubin_all['u_sersicFluxErr'] < 3)\n", + " & (matched_rubin_all['r_minus_i'] < 1.0)\n", + " & (matched_rubin_all['g_minus_r'] > 1.5 * matched_rubin_all['r_minus_i'] + 0.8))\n", "\n", - "selected_spec_z = matched_v_all['zsp'][is_selected_lbg]\n" + "selected_spec_z = matched_v_all['zsp'][is_selected_lbg]" ] }, { @@ -883,7 +892,7 @@ "id": "e7c8fcb4-a880-43a3-9caf-b276bef802cd", "metadata": {}, "source": [ - "Next, identify low-redshift interlopers that met the color selection criteria, and compare." + "Next, identify low-redshift interlopers that met the color selection criteria, and compare. Define the redshift window according to Ono et al. 2018 selection window of 3.2 < z < 4.5." ] }, { @@ -893,11 +902,13 @@ "metadata": {}, "outputs": [], "source": [ - "failed_lbg_indices = np.where(matched_v_all['zsp'][is_selected_lbg] < 3)[0] \n", + "failed_lbg_indices = np.where(matched_v_all['zsp'][is_selected_lbg] < 3.2)[0]\n", + "failed_spec_z = matched_v_all['zsp'][failed_lbg_indices]\n", "\n", - "print(f\"Found {len(selected_spec_z)} out of {len(matched_v_all['zsp'])} VANDELS sources inside the color selection box.\")\n", - "print(f\"Found {len(failed_spec_z)} LBG candidates that are confirmed low redshift interlopers,\")\n", - "print(f\"indicating a {len(failed_spec_z)/len(matched_v_all['zsp'])*100}% interloper fraction\")\n" + "print(\"Among the VANDELS spectroscopic sample:\")\n", + "print(f\"{len(selected_spec_z)} out of {len(matched_v_all['zsp'])} are color selected\")\n", + "print(f\"{len(failed_spec_z)} LBG candidates are confirmed low redshift interlopers, \")\n", + "print(f\"indicating a {len(failed_spec_z)/len(matched_v_all['zsp'])*100: .2f}% interloper fraction\")" ] }, { @@ -919,16 +930,19 @@ "\n", "z_bins = np.arange(0, 6.6, 0.2)\n", "\n", - "ax.hist(selected_spec_z, bins=z_bins, color='dodgerblue', edgecolor='black', alpha=0.8, zorder=3)\n", + "ax.hist(selected_spec_z, bins=z_bins, color='dodgerblue', edgecolor='black',\n", + " alpha=0.8, zorder=3)\n", "\n", - "ax.axvspan(3.2, 4.5, color='mediumseagreen', alpha=0.2, label='Selection Window ($3.2 < z < 4.5$)')\n", + "ax.axvspan(3.2, 4.5, color='mediumseagreen', alpha=0.2,\n", + " label='Selection Window ($3.2 < z < 4.5$)')\n", "ax.axvline(3.2, color='darkgreen', linestyle='--', linewidth=1.5, zorder=4)\n", "ax.axvline(4.5, color='darkgreen', linestyle='--', linewidth=1.5, zorder=4)\n", "\n", "ax.set_xlim(0, 6.5)\n", "ax.set_xlabel('Spectroscopic Redshift (VANDELS z_spec)', fontsize=14)\n", "ax.set_ylabel('Number of Selected Candidates', fontsize=14)\n", - "ax.set_title('True Redshift Distribution of LBG Candidates (g-dropout)', fontsize=16, fontweight='bold')\n", + "ax.set_title('True Redshift Distribution of LBG Candidates (g-dropout)',\n", + " fontsize=16, fontweight='bold')\n", "\n", "ax.legend(loc='upper right', fontsize=12, framealpha=1)\n", "ax.grid(axis='y', linestyle=':', alpha=0.7, zorder=0)\n", @@ -942,7 +956,7 @@ "id": "82d9acbc-e0c4-4049-90c6-1b8f13af5326", "metadata": {}, "source": [ - "> Figure X: Histogram of the redshifts of all spectroscopically confirmed galaxies that enter the Lyman-break color selection, indicating a very low interloper fraction. The selection window with Rubin data matches the one characterized by Ono et al. 2018 (green) using HSC data and the same color criteria (3.2 < z < 4.5)." + "> Figure 5: Histogram of the redshifts of all spectroscopically confirmed galaxies that enter the Lyman-break color selection, indicating a very low interloper fraction. The selection window with Rubin data matches the one characterized by Ono et al. 2018 (green) using HSC data and the same color criteria (3.2 < z < 4.5)." ] } ], From 9fe6cb731555b4511dbe11bafb87e6d17f85d2a0 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Mon, 8 Jun 2026 23:11:54 +0000 Subject: [PATCH 23/27] finished color color nb --- .../303_Galaxies/303_3_Color_selections.ipynb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 8144950b..96768c8d 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -722,8 +722,9 @@ " AND obs_collection = 'LSST.DP1'\n", " AND CONTAINS(POINT('ICRS', {ra}, {dec}), s_region) = 1\n", " \"\"\"\n", - " coadds = tap_service.run_sync(query).to_table()\n", - "\n", + " \n", + " coadds = tap_service.search(query).to_table()\n", + " \n", " for col_idx, f in enumerate(filters):\n", " ax = axes[row_idx][col_idx]\n", " band_match = coadds[coadds['lsst_band'] == f]\n", From 45a857ca30599f6279177b13cdd6ca5f7ee6c849 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Fri, 12 Jun 2026 16:49:38 +0000 Subject: [PATCH 24/27] addressing comments --- .../303_Galaxies/303_3_Color_selections.ipynb | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 96768c8d..b6f888db 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -35,7 +35,7 @@ "\n", "**LSST data products:** `Object` table, `deep_coadd` images\n", "\n", - "**Packages:** `lsst.rsp.get_tap_service `\n", + "**Packages:** `lsst.rsp.get_tap_service`, `pyvo`, `astroquery`\n", "\n", "**Credit:**\n", "This notebook benefited from discussions with Dan Taranu, John Franklin Crenshaw, and the Rubin LSST photometric redshift commissioning team. \n", @@ -52,7 +52,7 @@ "id": "938cb660-8449-4014-9610-b36a877aea6c", "metadata": {}, "source": [ - "# 1. Introduction\n", + "## 1. Introduction\n", "\n", "Color selections have served as a key method of identifying different populations of galaxies for decades. Especially at redshift z > 2.5, the Lyman-break is a strong spectral feature that is exploited to identify galaxies at high redshift in ground-based imaging. Lyman-break selections make use of the fact that intergalactic hydrogen in the foreground absorbs all the light of background galaxies that is emitted blueward of the Lyman limit (912A) or at very high redshifts, Lyman-alpha (1216A). More details about why this works can be found at this blog-post. \n", "\n", @@ -74,7 +74,7 @@ "id": "b4ce8a67-a3c9-4609-aaeb-6b62f865943e", "metadata": {}, "source": [ - "## 1.1 Import packages\n", + "### 1.1. Import packages\n", "\n", "Import common scientific analysis packages `numpy`, `matplotlib`, and `astropy`.\n", "\n", @@ -133,7 +133,7 @@ "id": "30d04fb9-a3a3-4c34-b6f8-496e7c648435", "metadata": {}, "source": [ - "# 2. Query and photometric validation \n", + "## 2. Query and photometric validation \n", "\n" ] }, @@ -278,7 +278,7 @@ "id": "8baf7434-aee5-459b-8282-4926978dc4ce", "metadata": {}, "source": [ - "### 2.1 LBG selection\n", + "### 2.1. LBG selection\n", "\n", "Now, perform the color selection to identify the high-redshift galaxy candidates. Use a typical Lyman break selection for a camera with similar filter properties to the LSST (e.g. Ono et al. 2018). The selection requires very red g-r colors (to identify galaxies with strong Lyman breaks), and relatively blue r-i colors (typical of star-forming galaxies with little dust, and which excludes stars). \n", "\n", @@ -310,11 +310,11 @@ "id": "e3e6685e-98a1-4612-9869-082ecdab43af", "metadata": {}, "source": [ - "### 2.2 Validation data \n", + "### 2.2. Validation data \n", "\n", "This section will fetch an archival spectroscopic redshift catalog to use as a validation dataset. Use data from the VANDELS spectroscopic redshift catalog (a deep VLT/VIMOS spectroscopic survey of the Cosmic Assembly Near-infrared Deep Extragalactic Survey or CANDELS). This survey was very deep and targeted a large number of high redshift galaxies making it a good single-catalog choice for validation.\n", "\n", - "#### 2.2.1 Fetch spec-z catalog\n", + "#### 2.2.1. Fetch spec-z catalog\n", "\n", "Use the `astroquery` package's `VizieR` service to retrieve the public catalog. Information on the catalog and its contents can be found in Garilli et al. 2021. The catalog ID to search in `VizieR` can be found on adsabs.harvard.edu in connection to the data release paper. Pull the table of data obtained in the ECDFS as `vandels_cdfs`" ] @@ -359,7 +359,7 @@ "id": "fe011d0d-4077-402c-be5d-176d23c33439", "metadata": {}, "source": [ - "#### 2.2.3 Cross-match\n", + "#### 2.2.3. Cross-match\n", "\n", "Perform the LBG selection on the Rubin data, then match to objects with the same coordinates in the VANDELS catalog to see what true high redshift galaxies passed the LBG selection and which failed." ] @@ -410,7 +410,7 @@ "id": "d0e7c80f-0587-4c17-93d8-a52096d4c99e", "metadata": {}, "source": [ - "## 2.3 Plot color color diagrams\n", + "### 2.3 Plot color color diagrams\n", "\n", "First, store some shorthand parameters for the colors in the selection, and for parameters to color-code the galaxies by." ] @@ -456,7 +456,7 @@ "source": [ "Define a figure for the color color diagram. Plot all the Rubin galaxies from the query in Section 2.1 (gray), all Rubin galaxies that satisfy the LBG color selection (blue), and the true spectroscopically confirmed high-redshift galaxies as bold colored symbols. Stars indicate the true high-redshift galaxies that meet the color selection and plus signs are the true high-redshift galaxies that do not. \n", "\n", - "### 2.3.1 Magnitude dependence\n", + "#### 2.3.1 Magnitude dependence\n", "\n", "Color-code the galaxies by their i-band magnitude, to see if spectroscopically confirmed galaxies that are missed by the LBG selection might be faint, suggesting photometric scatter could contribute to missed galaxies." ] @@ -516,7 +516,7 @@ "source": [ "> Figure 1: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by i-band magnitude and their successful selection does not show any trend with magnitude (which might be expected if photometric scatter.\n", "\n", - "### 2.3.2 Imaging depth dependence\n", + "#### 2.3.2 Imaging depth dependence\n", "\n", "Color-code the galaxies by their g-band flux error, a proxy for the depth of the g-band imaging, to see if spectroscopically confirmed galaxies that are missed by the LBG selection might because the g-band imaging was not deep enough to provide a robust lower limit on the dropout color." ] @@ -583,7 +583,7 @@ "id": "8062a269-a6c8-43b2-ae46-88ebc8790912", "metadata": {}, "source": [ - "### 2.3.3 Redshift dependence\n", + "#### 2.3.3 Redshift dependence\n", "\n", "Since there is no obvious trend with magnitude or imaging depth, color code the spectroscopically confirmed high-redshift galaxies by their spectroscopic redshift. At the higher redshift end of the selection window, the g-band flux is completely undetected when the filter probes blueward of the Lyman limit (912A). But at lower end of the redshift selection window the g-band will probe blueward of Lyman alpha (1216A) and redward of the Lyman limit (912A) but will only be partially absorbed because of the Lyman-alpha forest. The amount of flux can vary. In the plot below, color-code by spectroscopic redshift to see if the bluer galaxies are at lower redshifts." ] @@ -648,7 +648,7 @@ "id": "2f0b8d97-06de-4226-b21b-782f7cbe56c5", "metadata": {}, "source": [ - "### 2.3.4 Interpretation\n", + "#### 2.3.4 Interpretation\n", "\n", "The color selection identifies a large number of true high-redshift galaxies. A number of confirmed galaxies fall outside the selection window. While the color selection is not designed to be 100% inclusive of high redshift galaxies, it should select a relatively pure sample with few interlopers. Galaxies my reside outside the selection box do not seem to trend with any single property tested in Section 2.3.1-2.3.3, but may be caused by a combination of photometric scatter, variation in depth of the g-band imaging, and that the strength of the g-r color will vary across the redshift selection window. Other effects also contribute: dust attenuation in the galaxy will redden the restframe UV probed by the r-i color and similarly decreasing the brightness of the observed r band flux (thus making the g-r color less robustly constrained). A possible effect from DP1 could also be the known issue of a small fraction of red-wavelength photon leak in the g-band which might contaminate the dropout filter with redder-wavelength light from the galaxy. This effect is exacerbated by the higher operating temperature of LSSTComCam during commissioning and is expected to be resolved in DP2 LSSTCam data.\n", "\n", @@ -660,7 +660,7 @@ "id": "fbff5f57-9f6e-4847-84c3-582083035bf2", "metadata": {}, "source": [ - "# 3. Visual inspection\n", + "## 3. Visual inspection\n", "\n", "Finally, generate image cutouts to visually inspect both the missed and confirmed subsets of spectroscopically confirmed galaxies. This validation is necessary to confirm the fidelity of the sample." ] @@ -815,7 +815,7 @@ "id": "1b5c1515-47a2-4cfa-b9f2-60acadb4daa9", "metadata": {}, "source": [ - "# 4. Interloper fraction\n", + "## 4. Interloper fraction\n", "\n", "Below, select all Rubin objects at any redshift with a secure VANDELS ectroscopic redshift measurement (high quality only, `q_zsp` of 3 or 4; See Garilla et al.). Use that full sample across all redshifts to investigate the interloper fraction of the Rubin color selection (this exercise is only informative above the magnitude limit of the VANDELS sample, and does not apply to fainter galaxies). \n", "\n", From 5ea06548e563a5ba9a7cad21f6351fd44416c109 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Fri, 12 Jun 2026 19:15:11 +0000 Subject: [PATCH 25/27] addressing comments --- .../303_Galaxies/303_3_Color_selections.ipynb | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index b6f888db..2008cc79 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -54,11 +54,11 @@ "source": [ "## 1. Introduction\n", "\n", - "Color selections have served as a key method of identifying different populations of galaxies for decades. Especially at redshift z > 2.5, the Lyman-break is a strong spectral feature that is exploited to identify galaxies at high redshift in ground-based imaging. Lyman-break selections make use of the fact that intergalactic hydrogen in the foreground absorbs all the light of background galaxies that is emitted blueward of the Lyman limit (912A) or at very high redshifts, Lyman-alpha (1216A). More details about why this works can be found at this blog-post. \n", + "Color selections have served as a key method of identifying different populations of galaxies for decades. Especially at redshift z > 2.5, the Lyman-break is a strong spectral feature that is exploited to identify galaxies at high redshift in ground-based imaging. Lyman-break selections make use of the fact that intergalactic hydrogen in the foreground absorbs all the light of background galaxies that is emitted blueward of the Lyman limit (912A) or at very high redshifts, Lyman-alpha (1216A). [More details about why this works can be found at this blog-post.](http://candels-collaboration.blogspot.com/2012/08/how-to-find-distant-galaxies.html) \n", "\n", "Thus, galaxies at high redshifts can be identified by their very red colors between filters that bridge the Lyman break feature (and are named after their selection method as Lyman break galaxies or LBGs). Since intergalactic hydrogen absorbs the light blueward of the Lyman break, the flux of true z ~ 3 galaxies drops as the Lyman-break redshifts into the LSST u-band, and at z ~ 4 in the LSST g-band.\n", "\n", - "This notebook demonstrates the Lyman break color selection on DP1 data for galaxies at z ~ 4 as an example (referred to as g-band dropouts), and provides some validation metrics for its performance. It makes use of color selections defined and used in the literature with data from facilities with similar filter sets (band pass shapes and effective wavelengths). These are using the Canada-France-Hawaii Telescope Legacy Survey (CFHTLS) as presented in Hildebrandt et al., 2009 and van der Burg et al., 2010. A similar selection was performed using Subaru Hyper-Suprime Cam data in Ono et al. 2018\n" + "This notebook demonstrates the Lyman break color selection on DP1 data for galaxies at z ~ 4 as an example (referred to as g-band dropouts), and provides some validation metrics for its performance. It makes use of color selections defined and used in the literature with data from facilities with similar filter sets (band pass shapes and effective wavelengths). These are using the Canada-France-Hawaii Telescope Legacy Survey (CFHTLS) as presented in [Hildebrandt et al., 2009](https://ui.adsabs.harvard.edu/abs/2009A%26A...498..725H/abstract) and [van der Burg et al., 2010](https://ui.adsabs.harvard.edu/abs/2010A%26A...523A..74V/abstract). A similar selection was performed using Subaru Hyper-Suprime Cam data in [Ono et al. 2018](https://ui.adsabs.harvard.edu/abs/2018PASJ...70S..10O/abstract).\n" ] }, { @@ -247,11 +247,12 @@ "filters = ['u', 'g', 'r', 'i']\n", "\n", "with np.errstate(divide='ignore', invalid='ignore'):\n", - " for f in filters:\n", - " flux_robust = np.where(tab[f'{f}_sersicFlux'] < tab[f'{f}_sersicFluxErr'],\n", - " tab[f'{f}_sersicFluxErr'],\n", - " tab[f'{f}_sersicFlux'])\n", - " tab[f'{f}_mag_robust'] = -2.50 * np.log10(flux_robust) + 31.4" + " for filt in filters:\n", + " flux_robust = np.where(tab[f'{filt}_sersicFlux']\n", + " < tab[f'{filt}_sersicFluxErr'],\n", + " tab[f'{filt}_sersicFluxErr'],\n", + " tab[f'{filt}_sersicFlux'])\n", + " tab[f'{filt}_mag_robust'] = -2.50 * np.log10(flux_robust) + 31.4" ] }, { @@ -316,7 +317,7 @@ "\n", "#### 2.2.1. Fetch spec-z catalog\n", "\n", - "Use the `astroquery` package's `VizieR` service to retrieve the public catalog. Information on the catalog and its contents can be found in Garilli et al. 2021. The catalog ID to search in `VizieR` can be found on adsabs.harvard.edu in connection to the data release paper. Pull the table of data obtained in the ECDFS as `vandels_cdfs`" + "Use the `astroquery` package's `VizieR` service to retrieve the public catalog. Information on the catalog and its contents can be found in [Garilli et al. 2021](https://ui.adsabs.harvard.edu/abs/2021A%26A...647A.150G/abstract). The [catalog ID to search in `VizieR`](https://ui.adsabs.harvard.edu/abs/2022yCat..36470150G/abstract) can be found on adsabs.harvard.edu in connection to the data release paper. Pull the table of data obtained in the ECDFS as `vandels_cdfs`" ] }, { @@ -337,7 +338,7 @@ "id": "3d692c3e-aa56-409f-87ff-4f2e6ab010b8", "metadata": {}, "source": [ - "##### Select LBGs at high redshift using a loose window with 3.5 < z < 4.5 (this is the typical selection window for this same g-band dropout selection, as characterized by Ono et al. 2018). Ensure that only high quality measurements are used by requiring the good and excellent spectroscopic redshift flag `q_zsp` of 3 and 4." + "Select LBGs at high redshift using a loose window with 3.5 < z < 4.5 (this is the typical selection window for this same g-band dropout selection, as characterized by Ono et al. 2018). Ensure that only high quality measurements are used by requiring the good and excellent spectroscopic redshift flag `q_zsp` of 3 and 4." ] }, { @@ -650,7 +651,7 @@ "source": [ "#### 2.3.4 Interpretation\n", "\n", - "The color selection identifies a large number of true high-redshift galaxies. A number of confirmed galaxies fall outside the selection window. While the color selection is not designed to be 100% inclusive of high redshift galaxies, it should select a relatively pure sample with few interlopers. Galaxies my reside outside the selection box do not seem to trend with any single property tested in Section 2.3.1-2.3.3, but may be caused by a combination of photometric scatter, variation in depth of the g-band imaging, and that the strength of the g-r color will vary across the redshift selection window. Other effects also contribute: dust attenuation in the galaxy will redden the restframe UV probed by the r-i color and similarly decreasing the brightness of the observed r band flux (thus making the g-r color less robustly constrained). A possible effect from DP1 could also be the known issue of a small fraction of red-wavelength photon leak in the g-band which might contaminate the dropout filter with redder-wavelength light from the galaxy. This effect is exacerbated by the higher operating temperature of LSSTComCam during commissioning and is expected to be resolved in DP2 LSSTCam data.\n", + "The color selection identifies a large number of true high-redshift galaxies. A number of confirmed galaxies fall outside the selection window. While the color selection is not designed to be 100% inclusive of high redshift galaxies, it should select a relatively pure sample with few interlopers. Galaxies my reside outside the selection box do not seem to trend with any single property tested in Section 2.3.1-2.3.3, but may be caused by a combination of photometric scatter, variation in depth of the g-band imaging, and that the strength of the g-r color will vary across the redshift selection window. Other effects also contribute: dust attenuation in the galaxy will redden the restframe UV probed by the r-i color and similarly decreasing the brightness of the observed r band flux (thus making the g-r color less robustly constrained). A possible effect from DP1 could also be the known issue of a small fraction of [red-wavelength photon leak in the g-band](https://dp1.lsst.io/products/known_issues_and_subtleties.html#g-band-red-leak-excess-long-wavelength-transmission) which might contaminate the dropout filter with redder-wavelength light from the galaxy. This effect is exacerbated by the higher operating temperature of LSSTComCam during commissioning and is expected to be resolved in DP2 LSSTCam data.\n", "\n", "This exemplifies how photometric selection is statistical in nature. While the physics of the Lyman break creates the strong spectral feature that can be exploited for a simple selection, the photometric noise and intrinsic galaxy variations will scatter the galaxy colors in and out of the selection box.\n" ] @@ -817,7 +818,7 @@ "source": [ "## 4. Interloper fraction\n", "\n", - "Below, select all Rubin objects at any redshift with a secure VANDELS ectroscopic redshift measurement (high quality only, `q_zsp` of 3 or 4; See Garilla et al.). Use that full sample across all redshifts to investigate the interloper fraction of the Rubin color selection (this exercise is only informative above the magnitude limit of the VANDELS sample, and does not apply to fainter galaxies). \n", + "Below, select all Rubin objects at any redshift with a secure VANDELS ectroscopic redshift measurement (high quality only, `q_zsp` of 3 or 4; See Garilli et al. 2021). Use that full sample across all redshifts to investigate the interloper fraction of the Rubin color selection (this exercise is only informative above the magnitude limit of the VANDELS sample, and does not apply to fainter galaxies). \n", "\n", "First, cross-match all galaxies for which VANDELS secured a robust redshift measurement with the Rubin objects from hte query in Section 2." ] From e9e9f7f5cbf1de11a6cbd052046108431ef6c009 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Fri, 12 Jun 2026 19:16:55 +0000 Subject: [PATCH 26/27] addressing comments --- DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index 2008cc79..fec3cf71 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -313,7 +313,7 @@ "source": [ "### 2.2. Validation data \n", "\n", - "This section will fetch an archival spectroscopic redshift catalog to use as a validation dataset. Use data from the VANDELS spectroscopic redshift catalog (a deep VLT/VIMOS spectroscopic survey of the Cosmic Assembly Near-infrared Deep Extragalactic Survey or CANDELS). This survey was very deep and targeted a large number of high redshift galaxies making it a good single-catalog choice for validation.\n", + "This section will fetch an archival spectroscopic redshift catalog to use as a validation dataset. Use data from the [VANDELS](http://vandels.inaf.it/) spectroscopic redshift catalog (a deep VLT/VIMOS spectroscopic survey of the Cosmic Assembly Near-infrared Deep Extragalactic Survey or CANDELS). This survey was very deep and targeted a large number of high redshift galaxies making it a good single-catalog choice for validation.\n", "\n", "#### 2.2.1. Fetch spec-z catalog\n", "\n", From 16938f18cff63d83c7dc341200d7e14d683f7697 Mon Sep 17 00:00:00 2001 From: christinawilliams Date: Fri, 12 Jun 2026 23:52:07 +0000 Subject: [PATCH 27/27] last updates --- .../303_Galaxies/303_3_Color_selections.ipynb | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb index fec3cf71..e74b4562 100644 --- a/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb +++ b/DP1/300_Science_Demos/303_Galaxies/303_3_Color_selections.ipynb @@ -10,7 +10,7 @@ "id": "ab80c8e2-f477-40df-ba82-d1cbbe2b5892", "metadata": {}, "source": [ - "# 303.3. Color Selections\n", + "# 303.3. Color selections\n", "\n", "
\n", "\n", @@ -22,7 +22,7 @@ "Data Release: Data Preview 1
\n", "Container Size: large
\n", "LSST Science Pipelines version: r29.2.0
\n", - "Last verified to run: 2026-06-08
\n", + "Last verified to run: 2026-06-12
\n", "Repository: github.com/lsst/tutorial-notebooks
" ] }, @@ -161,7 +161,7 @@ "id": "e9c07b17-bc81-42e2-991c-0ab3a7d30eb8", "metadata": {}, "source": [ - "Define a query to retrieve galaxies from the object table using the `extendedness`=1 flag. Search around the center of the field using a 0.2 degree search radius to ensure the candidates are identified within the deepest area of g-band imaging. To further ensure good detections, include the $S/N > 10$ cut on the $i$-band." + "Define a query to retrieve galaxies from the object table using the `extendedness`=1 flag. Search around the center of the field using a 0.5 degree search radius to cover the full field. To ensure good detections, include the $S/N > 10$ cut on the $i$-band." ] }, { @@ -317,7 +317,7 @@ "\n", "#### 2.2.1. Fetch spec-z catalog\n", "\n", - "Use the `astroquery` package's `VizieR` service to retrieve the public catalog. Information on the catalog and its contents can be found in [Garilli et al. 2021](https://ui.adsabs.harvard.edu/abs/2021A%26A...647A.150G/abstract). The [catalog ID to search in `VizieR`](https://ui.adsabs.harvard.edu/abs/2022yCat..36470150G/abstract) can be found on adsabs.harvard.edu in connection to the data release paper. Pull the table of data obtained in the ECDFS as `vandels_cdfs`" + "Use the `astroquery` package's `VizieR` service to retrieve the public catalog. Information on the catalog and its contents can be found in [Garilli et al. 2021](https://ui.adsabs.harvard.edu/abs/2021A%26A...647A.150G/abstract). The [catalog ID to search in `VizieR`](https://ui.adsabs.harvard.edu/abs/2022yCat..36470150G/abstract) can be found on adsabs.harvard.edu in connection to the data release paper. VANDELS took data in two extragalactic deep fields. Pull the table of data obtained in the ECDFS as `vandels_cdfs`, which is the first table in the return (index 0)." ] }, { @@ -327,9 +327,9 @@ "metadata": {}, "outputs": [], "source": [ - "v = Vizier(columns=['**'], catalog=\"J/A+A/647/A150\")\n", - "v.ROW_LIMIT = -1\n", - "all_tables = v.get_catalogs(\"J/A+A/647/A150\")\n", + "vandels_survey = Vizier(columns=['**'], catalog=\"J/A+A/647/A150\")\n", + "vandels_survey.ROW_LIMIT = -1\n", + "all_tables = vandels_survey.get_catalogs(\"J/A+A/647/A150\")\n", "vandels_cdfs = all_tables[0]" ] }, @@ -360,7 +360,7 @@ "id": "fe011d0d-4077-402c-be5d-176d23c33439", "metadata": {}, "source": [ - "#### 2.2.3. Cross-match\n", + "#### 2.2.2. Cross-match\n", "\n", "Perform the LBG selection on the Rubin data, then match to objects with the same coordinates in the VANDELS catalog to see what true high redshift galaxies passed the LBG selection and which failed." ] @@ -576,7 +576,7 @@ "id": "b2849d83-8780-4a28-8b31-2f52e5365aa0", "metadata": {}, "source": [ - "> Figure 2: Like Figure 2, except that confirmed galaxies are color coded by g-band flux uncertainty as a proxy for variations in the depth or integration time in the g-band filter imaging. Their unsuccessful selection does not show any trend with image depth (which might be expected if galaxies in shallower imaging have smaller lower limits to the g-r color)." + "> Figure 2: Like Figure 1, except that confirmed galaxies are color coded by g-band flux uncertainty as a proxy for variations in the depth or integration time in the g-band filter imaging. Their unsuccessful selection does not show any trend with image depth (which might be expected if galaxies in shallower imaging have smaller lower limits to the g-r color)." ] }, { @@ -641,7 +641,7 @@ "id": "4e702cae-4406-424f-abec-ec2375cfe0b6", "metadata": {}, "source": [ - "> Figure 3: A color-color diagram showing g - r vs r - i colors for all Rubin galaxies (gray). The Lyman-break color selection window is shown in black dashed lines. Blue points indicate Rubin galaxies that meet the color criteria for being at high-redshift. Stars and pluses indicate Rubin galaxies that are spectroscopically confirmed by VANDELS to lie at z > 3.5 but do and do not meet the color selection (respectively). Confirmed galaxies are color coded by spectroscopic redshift, and their successful selection does not show any trend with redshift." + "> Figure 3: Like Figure 1, except that confirmed galaxies are color coded by spectroscopic redshift, and their successful selection does not show any trend with redshift." ] }, { @@ -651,7 +651,7 @@ "source": [ "#### 2.3.4 Interpretation\n", "\n", - "The color selection identifies a large number of true high-redshift galaxies. A number of confirmed galaxies fall outside the selection window. While the color selection is not designed to be 100% inclusive of high redshift galaxies, it should select a relatively pure sample with few interlopers. Galaxies my reside outside the selection box do not seem to trend with any single property tested in Section 2.3.1-2.3.3, but may be caused by a combination of photometric scatter, variation in depth of the g-band imaging, and that the strength of the g-r color will vary across the redshift selection window. Other effects also contribute: dust attenuation in the galaxy will redden the restframe UV probed by the r-i color and similarly decreasing the brightness of the observed r band flux (thus making the g-r color less robustly constrained). A possible effect from DP1 could also be the known issue of a small fraction of [red-wavelength photon leak in the g-band](https://dp1.lsst.io/products/known_issues_and_subtleties.html#g-band-red-leak-excess-long-wavelength-transmission) which might contaminate the dropout filter with redder-wavelength light from the galaxy. This effect is exacerbated by the higher operating temperature of LSSTComCam during commissioning and is expected to be resolved in DP2 LSSTCam data.\n", + "The color selection identifies a large number of true high-redshift galaxies. A number of confirmed galaxies fall outside the selection window. While the color selection is not designed to be 100% inclusive of high redshift galaxies, it should select a relatively pure sample with few interlopers. Galaxies may reside outside the selection box do not seem to trend with any single property tested in Section 2.3.1-2.3.3, but may be caused by a combination of photometric scatter, variation in depth of the g-band imaging, and that the strength of the g-r color will vary across the redshift selection window. Other effects also contribute: dust attenuation in the galaxy will redden the restframe UV probed by the r-i color and similarly decreasing the brightness of the observed r band flux (thus making the g-r color less robustly constrained). A possible effect from DP1 could also be the known issue of a small fraction of [red-wavelength photon leak in the g-band](https://dp1.lsst.io/products/known_issues_and_subtleties.html#g-band-red-leak-excess-long-wavelength-transmission) which might contaminate the dropout filter with redder-wavelength light from the galaxy. This effect is exacerbated by the higher operating temperature of LSSTComCam during commissioning and is expected to be resolved in DP2 LSSTCam data.\n", "\n", "This exemplifies how photometric selection is statistical in nature. While the physics of the Lyman break creates the strong spectral feature that can be exploited for a simple selection, the photometric noise and intrinsic galaxy variations will scatter the galaxy colors in and out of the selection box.\n" ] @@ -716,16 +716,19 @@ " g_r = r_data['g_minus_r'][row_idx]\n", " r_i = r_data['r_minus_i'][row_idx]\n", "\n", - " query = f\"\"\"\n", + " cutout_query = f\"\"\"\n", " SELECT lsst_band, access_url\n", " FROM ivoa.ObsCore\n", " WHERE dataproduct_subtype = 'lsst.deep_coadd'\n", " AND obs_collection = 'LSST.DP1'\n", " AND CONTAINS(POINT('ICRS', {ra}, {dec}), s_region) = 1\n", " \"\"\"\n", - " \n", - " coadds = tap_service.search(query).to_table()\n", - " \n", + "\n", + " job = tap_service.submit_job(cutout_query)\n", + " job.run()\n", + " job.wait()\n", + " coadds = job.fetch_result().to_table()\n", + "\n", " for col_idx, f in enumerate(filters):\n", " ax = axes[row_idx][col_idx]\n", " band_match = coadds[coadds['lsst_band'] == f]\n", @@ -774,7 +777,7 @@ "id": "e855ba72-793a-47d1-8871-1ca6faac0246", "metadata": {}, "source": [ - "Now plot the 4-filter cutouts for the real high redshift galaxies confirmed by VANDELS that were identified correctly in the Rubin color selection. " + "Now plot the 4-filter cutouts for a few (5) real high redshift galaxies confirmed by VANDELS that were identified correctly in the Rubin color selection. " ] }, { @@ -904,8 +907,7 @@ "metadata": {}, "outputs": [], "source": [ - "failed_lbg_indices = np.where(matched_v_all['zsp'][is_selected_lbg] < 3.2)[0]\n", - "failed_spec_z = matched_v_all['zsp'][failed_lbg_indices]\n", + "failed_spec_z = selected_spec_z[selected_spec_z < 3.2]\n", "\n", "print(\"Among the VANDELS spectroscopic sample:\")\n", "print(f\"{len(selected_spec_z)} out of {len(matched_v_all['zsp'])} are color selected\")\n",