diff --git a/docs/source/tutorials/BasicIntroduction.ipynb b/docs/source/tutorials/BasicIntroduction.ipynb index 1f90ff07..43bf44a6 100644 --- a/docs/source/tutorials/BasicIntroduction.ipynb +++ b/docs/source/tutorials/BasicIntroduction.ipynb @@ -13,9 +13,23 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Simulating an SIE lens\n", + "## Simulating an SIE lens\n", "\n", - "Here we will demo the very basics of lensing with a classic `SIE` lens model. We will see what it takes to make an `SIE` model, lens a background `Sersic` source, and sample the resulting image using a `Simulator`. Caustics simulators can generalize to very complex scenarios, here we will use a built-in simulator which handles a common use case (lensing a background source). To start, we of course need to import some modules. For the minimal example, this is just `matplotlib` a common package used for plotting, `torch` which is a numerical package for GPU/autodiff (much like `numpy`), and `caustics` the reason you are here." + "Here we will demo the very basics of lensing with a classic `SIE` lens model. We will see what it takes to make an `SIE` model, lens a background `Sersic` source, and sample the resulting image using a `Simulator`. Caustics simulators can generalize to very complex scenarios, here we will use a built-in simulator which handles a common use case (lensing a background source). To start, we of course need to import some modules. For the minimal example, this is just `matplotlib` a common package used for plotting, `torch` which is a numerical package for GPU/autodiff (much like `numpy`), and `caustics` the reason you are here.\n", + "\n", + "In this tutorial, we will guide you through the process of simulating an SIE lens using both the object-oriented method and the YAML file method. Each step in the object-oriented method will be mirrored and explained in the YAML file method. This will help you understand how the two methods correspond to each other.\n", + "\n", + "We will break the YAML file into individual sections to facilitate the comparison. The object-oriented method will be denoted by the title \"Using the Object-oriented Method\" while the YAML file method will be denoted by the title \"Using the YAML Method\".\n", + "\n", + "First, let's import the necessary packages:" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Import the Necessary Packages\n", + "> **Note:** These packages need to be imported for both methods" ] }, { @@ -33,11 +47,44 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Define a Cosmology\n", + "### Using the YAML File Method" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The YAML File Method for building a simulator greatly simplifies the process by providing a clear, human-readable, and structured format to define all the components of the simulator. It allows for easy reuse of defined components, such as cosmology or lenses, and makes the configuration of the simulator easily adjustable without touching the actual code. This method enhances maintainability, readability, and scalability of the simulator building process. All sections of the yaml configuration will be explained in the subsequent sections." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Build the simulator\n", + "sim = caustics.build_simulator(\"example.yml\")\n", + "\n", + "!cat example.yml" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define a Cosmology\n", "\n", "Before we can begin gravitational lensing, we need to know what kind of universe we are in. This is used for calculating various distances and timescales (depending on the problem) since gravitational lensing typically occurs over cosmologically significant distances in the universe. Here we define a standard flat Lambda Cold Dark Matter cosmology. Nothing fancy here, but it's still needed." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using the Object-oriented Method" + ] + }, { "cell_type": "code", "execution_count": null, @@ -51,9 +98,42 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Lens Mass Distribution\n", + "### Using the YAML File Method\n", + "\n", + "In the YAML file, the cosmology is defined under the `cosmology` key. This section is used to specify the cosmological model that will be used in the simulator. \n", + "\n", + "Here's the corresponding section from the YAML file:\n", + "\n", + "```yaml\n", + "cosmology: &cosmo\n", + " name: cosmo\n", + " kind: FlatLambdaCDM\n", + "```\n", + "\n", + "In this section:\n", + "\n", + "- `cosmology:` is the key that starts the definition of the cosmology.\n", + "- `&cosmo` is a YAML anchor that allows us to give a name to this section for later reference.\n", + "- `name: cosmo` sets the name of the cosmology to `cosmo`.\n", + "- `kind: FlatLambdaCDM` sets the kind of the cosmology to `FlatLambdaCDM`, which is a cosmological model assuming a flat Universe dominated by a cosmological constant (Lambda) and cold dark matter (CDM).\n", + "\n", + "This cosmology definition can be referenced elsewhere in the YAML file using the `*cosmo` alias. This allows us to reuse the same cosmology definition for multiple lenses or other components without having to redefine it each time. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Lens Mass Distribution\n", "\n", - "In order for gravitational lensing to occur, we need some mass to bend the light. Here we define a basic Singular Isothermal Ellipsoid (SIE), which is a versatile profile used in many strong gravitational lensing simulations. As the first argument, we pass the cosmology so that the `SIE` can compute various quantities which make use of redshift information (seen later). Each model must have a unique name so we call this one `lens` though you can also let Caustics automatically pick a unique name." + "In order for gravitational lensing to occur, we need some mass to bend the light. Here we define a basic Singular Isothermal Ellipsoid (SIE), which is a versatile profile used in many strong gravitational lensing simulations. As the first argument, we pass the cosmology so that the `SIE` can compute various quantities which make use of redshift information (seen later). Each model must have a unique name so we call this one `lens` though you can also let caustics automatically pick a unique name." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using the Object-oriented Method" ] }, { @@ -69,11 +149,45 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Sersic Source Light Distribution\n", + "### Using the YAML File Method\n", + "\n", + "In the YAML file, the lens mass distribution is defined under the `lens` key. This section is used to specify the properties of the lens that will be used in the simulator. \n", + "\n", + "Here's the corresponding section from the YAML file for `lens`:\n", + "\n", + "```yaml\n", + "lens: &lens\n", + " name: lense\n", + " kind: SIE\n", + " init_kwargs:\n", + " cosmology: *cosmo\n", + "```\n", + "In this section:\n", + "\n", + "- `lens:` is the key that starts the definition of the first lens.\n", + "- `&lens` is a YAML anchor that allows us to give a name to this section for later reference.\n", + "- `name: lense` sets the name of the lens to 'lense'.\n", + "- `kind: SIE` sets the kind of the lens to 'SIE', which stands for Singular Isothermal Ellipsoid, a common model for the mass distribution of a lens in gravitational lensing.\n", + "- `init_kwargs:` is a key for additional parameters required for the lens.\n", + "- `cosmology: *cosmo` sets the cosmology for the lens to the cosmology defined earlier in the YAML file.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sersic Source Light Distribution\n", "\n", "If we wish to see anything in our lensing configuration then we need a bright object in the background to produce some light that will pass through (and be bent by) our lens mass distribution. Here we create a `Sersic` light model which is a common versatile profile for representing galaxies. Note that we don't need to pass a light model any `Cosmology` information, since light models essentially just define a function on `(x,y)` coordinates that gives a brightness, the lens models handle all cosmology related calculations. For the name we very creatively choose `source`." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using the Object-oriented Method" + ] + }, { "cell_type": "code", "execution_count": null, @@ -87,11 +201,44 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Sersic Lens Light Distribution\n", + "### Using YAML File Method\n", + "\n", + "In the YAML file, the source light distribution is defined under the `src` key. This section is used to specify the properties of the source that will be used in the simulator. \n", + "\n", + "Here's the corresponding section from the YAML file:\n", + "\n", + "```yaml\n", + "src: &src\n", + " name: source\n", + " kind: Sersic\n", + "```\n", + "\n", + "In this section:\n", + "\n", + "- `src:` is the key that starts the definition of the source.\n", + "- `&src` is a YAML anchor that allows us to give a name to this section for later reference.\n", + "- `name: source` sets the name of the source to 'source'.\n", + "- `kind: Sersic` sets the kind of the source to 'Sersic', which is a common model for the light distribution of a source in astronomical imaging.\n", + "\n", + "This source definition can be referenced elsewhere in the YAML file using the `*src` alias. This allows us to reuse the same source definition for multiple components without having to redefine it each time.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sersic Lens Light Distribution\n", "\n", "The source isn't the only bright thing in the sky! The lensing galaxy itself will also have bright stars and can be seen as well. Let's add another Sersic model with the name `lenslight`." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using the Object-oriented Method" + ] + }, { "cell_type": "code", "execution_count": null, @@ -105,11 +252,43 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Lens Source Simulator\n", + "### Using YAML File Method\n", + "\n", + "In the YAML file, the lens light distribution is defined under the `lnslt` key. This section is used to specify the properties of the lens light that will be used in the simulator. \n", + "\n", + "Here's the corresponding section from the YAML file:\n", + "\n", + "```yaml\n", + "lnslt: &lnslt\n", + " name: lenslight\n", + " kind: Sersic\n", + "```\n", + "\n", + "In this section:\n", + "- `lnslt:` is the key that starts the definition of the lens light.\n", + "- `&lnslt` is a YAML anchor that allows us to give a name to this section for later reference.\n", + "- `name: lenslight` sets the name of the lens light to 'lenslight'.\n", + "- `kind: Sersic` sets the kind of the lens light to 'Sersic', which is a common model for the light distribution of a lens in astronomical imaging.\n", + "\n", + "This lens light definition can be referenced elsewhere in the YAML file using the `*lnslt` alias. This allows us to reuse the same lens light definition for multiple components without having to redefine it each time." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Lens Source Simulator\n", "\n", "Next we pass our configuration to a `Simulator` in caustics, simulators perform the work of forward modelling various configurations and producing the desired outputs. Here we are interested in a common scenario of producing an image of a background source through a lens distribution. It is possible to make your own simulator to represent all sorts of situations. First, we pass the `lens` model and the `source` model defined above. Next we use `pixelscale` and `pixels_x` to define the grid of pixels that will be sampled. Finally, we pass the `z_s` redshift at which the source (`Sersic`) model should be placed; recall that light models don't use the cosmology model and so aren't aware of their placement in space." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using the Object-oriented Method" + ] + }, { "cell_type": "code", "execution_count": null, @@ -125,13 +304,56 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Model Parameters\n", + "### Using YAML File Method\n", + "\n", + "In the YAML file, the simulator is defined under the `simulator` key. This section is used to specify the properties of the simulator that will be used to perform the simulation.\n", + "\n", + "Here's the corresponding section from the YAML file:\n", + "\n", + "```yaml\n", + "simulator:\n", + " name: minisim\n", + " kind: Lens_Source\n", + " init_kwargs:\n", + " lens: *lens\n", + " source: *src\n", + " lens_light: *lnslt\n", + " pixelscale: 0.05\n", + " pixels_x: 100\n", + "```\n", + "\n", + "In this section:\n", + "- `simulator:` is the key that starts the definition of the simulator.\n", + "- `name: minisim` sets the name of the simulator to 'minisim'.\n", + "- `kind: Lens_Source` sets the kind of the simulator to 'Lens_Source', which indicates that this simulator will simulate a lens and a source.\n", + "- `init_kwargs:` is a key for additional parameters required for the simulator.\n", + "- `lens: *lens` sets the lens for the simulator to the lens defined earlier in the YAML file.\n", + "- `source: *src` sets the source for the simulator to the source defined earlier in the YAML file.\n", + "- `lens_light: *lnslt` sets the lens light for the simulator to the lens light defined earlier in the YAML file.\n", + "- `pixelscale: 0.05` sets the pixel scale for the simulator to 0.05.\n", + "- `pixels_x: 100` sets the number of pixels in the x-direction for the simulator to 100.\n", + "\n", + "This section defines the `simulator` that will be used to perform the simulation. It references the lens, source, and lens light definitions from earlier in the YAML file and sets additional parameters for the simulator." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Model Parameters\n", "\n", "Each of the `lens`, `source`, and `lenslight` models have their own parameters that are needed to sample a given lensing configuration. There are a number of ways to pass these parameters to a Caustics simulator, but the most straightforward for most purposes is as a Pytorch `Tensor`. In this cell, we build the tensor manually for our configuration. In general one would have a script generate the configuration, or an optimizer/sampler would randomly choose parameter values.\n", "\n", "In order, here is an explanation of the parameters. `z_s` is the redshift of the source. `z_l` is the lens redshift which tells the lens how far away it is from the observer (us). The next two parameters `x0` and `y0` indicate where the lens is relative to the main optical axis, which is the coordinates `(0, 0)`. The `q` parameter gives the axis ratio for the `SIE`, so it knows how elongated it is. Then `phi` indicates the position angle (where the ellipse is pointing). `b` gives the Einstein radius (in arcsec) of the lens. The next `x0` and `y0` provide the position relative to the main optical axis of the Sersic source, here we offset the source slightly to make for an interesting figure. The `q` parameter defines the axis ratio of the Sersic ellipse. `phi` defines the position angle of the ellipse. `n` is the Sersic index which determines how concentrated the light is; `n=0.5` is a Gaussian distribution, `n=1` is an exponential, `n=4` is a De Vaucouleurs profile. `Re` is the radius (in arcsec) within which half the total light of the profile is enclosed. `Ie` is the brightness at `Re`. The next set of parameters are also Sersic parameters, but this time they are for the lens light model." ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using the Object-oriented Method" + ] + }, { "cell_type": "code", "execution_count": null, @@ -146,6 +368,40 @@ "]) # fmt: skip" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Using YAML File Method\n", + "\n", + "Model parameters in the YAML file method can be categorized into two types: static and dynamic. \n", + "\n", + "- Static parameters are those that remain constant throughout the simulation. These include parameters like the cosmology, lens, source, and lens light definitions that we have defined earlier in the YAML file. \n", + "\n", + "- Dynamic parameters, on the other hand, are those that can change during the simulation. These could include parameters like the position of the source, the mass of the lens, or the brightness of the lens light.\n", + "\n", + "The order of the model parameters is very important. The simulator expects the parameters to be input in a specific order, which can be displayed using the `sim.params` command. If the parameters are not input in the correct order, the simulation may not run correctly or may produce incorrect results.\n", + "\n", + "At this step, the \"Using YAML File Method\" converges with the \"Using Object-oriented Method\". Regardless of whether you're using the YAML file method or the object-oriented method, the model parameters need to be input in the correct order for the simulation to run correctly. The main difference is that with the YAML file method, the parameters are defined in the YAML file, while with the object-oriented method, the parameters are defined in the code." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Print out the order of model parameters\n", + "sim.params" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "> **Note:** The `sim.params` step is not required, but we highly recommend that yaml-users utilize this step in the process." + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -161,6 +417,7 @@ "metadata": {}, "outputs": [], "source": [ + "# Substitute minisim with sim for yaml method\n", "image = minisim(x, quad_level=3).detach().cpu().numpy()\n", "\n", "plt.imshow(image, origin=\"lower\")\n", @@ -183,6 +440,7 @@ "metadata": {}, "outputs": [], "source": [ + "# Substitute minisim with sim for the yaml method\n", "minisim.get_graph(True, True)" ] }, @@ -204,7 +462,7 @@ "newx = x.repeat(20, 1)\n", "newx += torch.normal(mean=0, std=0.1 * torch.ones_like(newx))\n", "\n", - "images = torch.vmap(minisim)(newx)\n", + "images = torch.vmap(minisim)(newx) # Substitute minisim with sim for the yaml method\n", "\n", "fig, axarr = plt.subplots(4, 5, figsize=(20, 16))\n", "for ax, im in zip(axarr.flatten(), images):\n", @@ -229,7 +487,7 @@ "metadata": {}, "outputs": [], "source": [ - "J = torch.func.jacfwd(minisim)(x)\n", + "J = torch.func.jacfwd(minisim)(x) # Substitute minisim with sim for the yaml method\n", "\n", "fig, axarr = plt.subplots(3, 7, figsize=(20, 9))\n", "for i, ax in enumerate(axarr.flatten()):\n", @@ -247,9 +505,9 @@ "\n", "The caustic tutorials are generally short and to the point, that way you can identify what you want and jump right to some useful code that demo's the particular problem you face. Below is a list of caustic tutorials and a quick description of what you will learn in each one::\n", "\n", - "- `LensZoo`: here you can see all the built-in lens mass distributions in `caustic` and how they distort the same background Seric source.\n", + "- `LensZoo`: here you can see all the built-in lens mass distributions in `caustics` and how they distort the same background Seric source.\n", "- `Playground`: here we demo the main visualizations of a lensing system (deflection angles, convergence, potential, time delay, magnification) in an interactive display so you can change the parameters by hand and see how the visuals change!\n", - "- `VisualizeCaustics`: here you can see how to find and display caustics, a must when using `caustic`!\n", + "- `VisualizeCaustics`: here you can see how to find and display caustics, a must when using `caustics`!\n", "- `Simulators`: here we describe the powerful simulator framework and how it can be used to quickly swap models, parameters, and other features and turn a complex forward model into a simple function.\n", "- `InvertLensEquation`: here we demo forward ray tracing in `caustic` the process of mapping from the source plane to the image plane." ] diff --git a/docs/source/tutorials/example.yml b/docs/source/tutorials/example.yml new file mode 100644 index 00000000..8d83cdeb --- /dev/null +++ b/docs/source/tutorials/example.yml @@ -0,0 +1,28 @@ +cosmology: &cosmo + name: cosmo + kind: FlatLambdaCDM + +lens: &lens + name: lens + kind: SIE + init_kwargs: + cosmology: *cosmo + +src: &src + name: source + kind: Sersic + +lnslt: &lnslt + name: lenslight + kind: Sersic + +simulator: + name: minisim + kind: Lens_Source + init_kwargs: + # Single lense + lens: *lens + source: *src + lens_light: *lnslt + pixelscale: 0.05 + pixels_x: 100