diff --git a/llms-full.txt b/llms-full.txt index f81b32b2..91700df3 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -50,7 +50,7 @@ AUTO-GENERATED by PyAutoBuild — do not edit by hand; regenerate with generate. - [__Log Likelihood Function: Multi Gaussian Expansion__](scripts/imaging/features/multi_gaussian_expansion/likelihood_function.py): This script provides a step-by-step guide of the `log_likelihood_function` which is used to fit `Imaging` data with a multi-Gaussian expansion (MGE), which is a superposition of multiple 2D Gaussian linear light profiles. - Contents: Dataset, Dataset Auto-Simulation, Masked Image Grid, Multiple Gaussians & Linear Light Profiles, Basis, Comparison To Linear Light Profiles Example, LightProfileLinearObjFuncList, Mapping Matrix, Blurred Mapping Matrix ($f$), Data Vector (D), Curvature Matrix (F), Reconstruction (Positive-Negative), Reconstruction (Positive Only), Image Reconstruction, Likelihood Function, Chi Squared, Noise Normalization Term, Calculate The Log Likelihood, Fit, Galaxy Modeling, Wrap Up - [Modeling Features: Multi Gaussian Expansion](scripts/imaging/features/multi_gaussian_expansion/modeling.py): A multi Gaussian expansion (MGE) decomposes the galaxy light into ~15-100 Gaussians, where the `intensity` of every Gaussian is solved for via a linear algebra using a process called an "inversion" (see the `linear_light_profiles.py` feature for a full description of this). - - Contents: Advantages & Disadvantages, Positive Only Solver, MGE Source Galaxy, Dataset & Mask, Model, Search & Analysis, Run Time, Model-Fit, Result, MGE Source, Regularization + - Contents: Advantages & Disadvantages, Positive Only Solver, MGE Source Galaxy, Dataset & Mask, Model, Search & Analysis, Run Time, Model-Fit, Result, Point Source, MGE Source, Regularization - [Simulator: Light MGE](scripts/imaging/features/multi_gaussian_expansion/simulator.py): This script simulates `Imaging` of a galaxy using light profiles where: - Contents: Dataset Paths, Grid, Galaxies, Output, Visualize, Plane Output - [Modeling: Light Parametric Operated](scripts/imaging/features/operated_light_profile/modeling.py): (no summary in script docstring) diff --git a/notebooks/imaging/features/multi_gaussian_expansion/modeling.ipynb b/notebooks/imaging/features/multi_gaussian_expansion/modeling.ipynb index 655a3643..2150c4d2 100644 --- a/notebooks/imaging/features/multi_gaussian_expansion/modeling.ipynb +++ b/notebooks/imaging/features/multi_gaussian_expansion/modeling.ipynb @@ -26,6 +26,7 @@ "- **Run Time:** Profiling of MGE run times and discussion of how they compare to standard light profiles.\n", "- **Model-Fit:** Performs the model fit using standard API.\n", "- **Result:** MGE results, including accessing light profiles with solved for intensity values.\n", + "- **Point Source:** Using a compact MGE to model an unresolved point-like component (e.g. an AGN) in the galaxy.\n", "- **MGE Source:** Detailed illustration of using MGE source.\n", "- **Regularization:** API for applying regularization to MGE, which is not recommend but included for illustration.\n", "\n", @@ -473,6 +474,117 @@ "outputs": [], "execution_count": null }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "__Point Source__\n", + "\n", + "The MGE is not only suited to a galaxy's extended stellar light -- it is also an effective way to model a compact,\n", + "unresolved point-like component at the centre of the galaxy, for example a nuclear starburst, an active galactic\n", + "nucleus (AGN) or an unresolved bulge.\n", + "\n", + "Such a component is modeled as a `Basis` of a small number of linear Gaussians (here 10) which all share the same\n", + "`centre` and elliptical components. Their `sigma` values are fixed to a set of logarithmically spaced values between\n", + "0.01\" and twice the pixel scale of the data. This keeps the basis compact relative to the resolution of the image, so\n", + "that it represents a realistic PSF-convolved point source. Fixing the sigmas and linking the centre and ellipticity\n", + "across all Gaussians keeps the parameter count low: the only free parameters are the shared (y, x) `centre` (given a\n", + "+/- 0.1\" uniform prior) and the two shared elliptical components, for N=4 in total.\n", + "\n", + "The point-source MGE is added to the galaxy as an additional light component alongside the extended `bulge` MGE\n", + "composed above, so the galaxy's light becomes the sum of its diffuse stellar emission and its compact nuclear source.\n", + "We recreate the Gaussians line-by-line below so you can copy and paste the code into your own scripts." + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "# The pixel scale of the data, which sets the maximum Gaussian sigma (and therefore how compact the source is).\n", + "\n", + "pixel_scales = 0.1\n", + "\n", + "total_point_gaussians = 10\n", + "\n", + "# Sigma values span 0.01\" (10**-2) up to twice the pixel scale, keeping the basis compact and point-like.\n", + "\n", + "log10_sigma_list = np.linspace(-2, np.log10(2.0 * pixel_scales), total_point_gaussians)\n", + "\n", + "# The centre is the only free parameter, shared by every Gaussian and given a +/- 0.1\" uniform prior.\n", + "\n", + "centre_0 = af.UniformPrior(lower_limit=-0.1, upper_limit=0.1)\n", + "centre_1 = af.UniformPrior(lower_limit=-0.1, upper_limit=0.1)\n", + "\n", + "point_gaussian_list = af.Collection(\n", + " af.Model(ag.lp_linear.Gaussian) for _ in range(total_point_gaussians)\n", + ")\n", + "\n", + "for i, gaussian in enumerate(point_gaussian_list):\n", + " gaussian.centre.centre_0 = centre_0 # All Gaussians share the same y centre.\n", + " gaussian.centre.centre_1 = centre_1 # All Gaussians share the same x centre.\n", + " gaussian.ell_comps = point_gaussian_list[\n", + " 0\n", + " ].ell_comps # All Gaussians share the same elliptical components.\n", + " gaussian.sigma = 10 ** log10_sigma_list[i] # Fixed, log-spaced sigma values.\n", + "\n", + "# The Basis groups the Gaussians into a single compact point-source light component.\n", + "\n", + "point = af.Model(ag.lp_basis.Basis, profile_list=point_gaussian_list)\n", + "\n", + "# The point-source MGE is added to the galaxy alongside its extended `bulge` MGE.\n", + "\n", + "galaxy = af.Model(ag.Galaxy, redshift=0.5, bulge=bulge, point=point)\n", + "\n", + "model = af.Collection(galaxies=af.Collection(galaxy=galaxy))" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Printing the model info confirms the galaxy now has both an extended `bulge` MGE and a compact `point` MGE." + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "print(model.info)" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Recreating the Gaussians line-by-line is useful for understanding how the point-source basis is composed, but in\n", + "practice it is more convenient to use the `mge_point_model_from` helper, which builds exactly the same compact basis\n", + "in a single line. It takes the data's `pixel_scales` (which sets the maximum Gaussian `sigma` and therefore how\n", + "compact the source is), the number of Gaussians and the source `centre`:" + ] + }, + { + "cell_type": "code", + "metadata": {}, + "source": [ + "point = ag.model_util.mge_point_model_from(\n", + " pixel_scales=0.1,\n", + " total_gaussians=10,\n", + " centre=(0.0, 0.0),\n", + ")\n", + "\n", + "galaxy = af.Model(ag.Galaxy, redshift=0.5, bulge=bulge, point=point)\n", + "\n", + "model = af.Collection(galaxies=af.Collection(galaxy=galaxy))\n", + "\n", + "print(model.info)" + ], + "outputs": [], + "execution_count": null + }, { "cell_type": "markdown", "metadata": {}, diff --git a/scripts/imaging/features/multi_gaussian_expansion/modeling.py b/scripts/imaging/features/multi_gaussian_expansion/modeling.py index 49769f70..2f66d9e5 100644 --- a/scripts/imaging/features/multi_gaussian_expansion/modeling.py +++ b/scripts/imaging/features/multi_gaussian_expansion/modeling.py @@ -21,6 +21,7 @@ - **Run Time:** Profiling of MGE run times and discussion of how they compare to standard light profiles. - **Model-Fit:** Performs the model fit using standard API. - **Result:** MGE results, including accessing light profiles with solved for intensity values. +- **Point Source:** Using a compact MGE to model an unresolved point-like component (e.g. an AGN) in the galaxy. - **MGE Source:** Detailed illustration of using MGE source. - **Regularization:** API for applying regularization to MGE, which is not recommend but included for illustration. @@ -304,6 +305,84 @@ aplt.subplot_fit_imaging(fit=result.max_log_likelihood_fit) +""" +__Point Source__ + +The MGE is not only suited to a galaxy's extended stellar light -- it is also an effective way to model a compact, +unresolved point-like component at the centre of the galaxy, for example a nuclear starburst, an active galactic +nucleus (AGN) or an unresolved bulge. + +Such a component is modeled as a `Basis` of a small number of linear Gaussians (here 10) which all share the same +`centre` and elliptical components. Their `sigma` values are fixed to a set of logarithmically spaced values between +0.01" and twice the pixel scale of the data. This keeps the basis compact relative to the resolution of the image, so +that it represents a realistic PSF-convolved point source. Fixing the sigmas and linking the centre and ellipticity +across all Gaussians keeps the parameter count low: the only free parameters are the shared (y, x) `centre` (given a ++/- 0.1" uniform prior) and the two shared elliptical components, for N=4 in total. + +The point-source MGE is added to the galaxy as an additional light component alongside the extended `bulge` MGE +composed above, so the galaxy's light becomes the sum of its diffuse stellar emission and its compact nuclear source. +We recreate the Gaussians line-by-line below so you can copy and paste the code into your own scripts. +""" +# The pixel scale of the data, which sets the maximum Gaussian sigma (and therefore how compact the source is). + +pixel_scales = 0.1 + +total_point_gaussians = 10 + +# Sigma values span 0.01" (10**-2) up to twice the pixel scale, keeping the basis compact and point-like. + +log10_sigma_list = np.linspace(-2, np.log10(2.0 * pixel_scales), total_point_gaussians) + +# The centre is the only free parameter, shared by every Gaussian and given a +/- 0.1" uniform prior. + +centre_0 = af.UniformPrior(lower_limit=-0.1, upper_limit=0.1) +centre_1 = af.UniformPrior(lower_limit=-0.1, upper_limit=0.1) + +point_gaussian_list = af.Collection( + af.Model(ag.lp_linear.Gaussian) for _ in range(total_point_gaussians) +) + +for i, gaussian in enumerate(point_gaussian_list): + gaussian.centre.centre_0 = centre_0 # All Gaussians share the same y centre. + gaussian.centre.centre_1 = centre_1 # All Gaussians share the same x centre. + gaussian.ell_comps = point_gaussian_list[ + 0 + ].ell_comps # All Gaussians share the same elliptical components. + gaussian.sigma = 10 ** log10_sigma_list[i] # Fixed, log-spaced sigma values. + +# The Basis groups the Gaussians into a single compact point-source light component. + +point = af.Model(ag.lp_basis.Basis, profile_list=point_gaussian_list) + +# The point-source MGE is added to the galaxy alongside its extended `bulge` MGE. + +galaxy = af.Model(ag.Galaxy, redshift=0.5, bulge=bulge, point=point) + +model = af.Collection(galaxies=af.Collection(galaxy=galaxy)) + +""" +Printing the model info confirms the galaxy now has both an extended `bulge` MGE and a compact `point` MGE. +""" +print(model.info) + +""" +Recreating the Gaussians line-by-line is useful for understanding how the point-source basis is composed, but in +practice it is more convenient to use the `mge_point_model_from` helper, which builds exactly the same compact basis +in a single line. It takes the data's `pixel_scales` (which sets the maximum Gaussian `sigma` and therefore how +compact the source is), the number of Gaussians and the source `centre`: +""" +point = ag.model_util.mge_point_model_from( + pixel_scales=0.1, + total_gaussians=10, + centre=(0.0, 0.0), +) + +galaxy = af.Model(ag.Galaxy, redshift=0.5, bulge=bulge, point=point) + +model = af.Collection(galaxies=af.Collection(galaxy=galaxy)) + +print(model.info) + """ __Wrap Up__ diff --git a/workspace_index.json b/workspace_index.json index 7e0bea33..ba622d79 100644 --- a/workspace_index.json +++ b/workspace_index.json @@ -1297,6 +1297,7 @@ "Run Time", "Model-Fit", "Result", + "Point Source", "MGE Source", "Regularization" ],