{ "cells": [ { "cell_type": "markdown", "id": "7b3aae73", "metadata": { "editable": true, "slideshow": { "slide_type": "" }, "tags": [] }, "source": [ "[](https://colab.research.google.com/github/nrao/astrohack/blob/v1.0.1/docs/cassegrain_ray_tracing_tutorial.ipynb)" ] }, { "cell_type": "markdown", "id": "9151b55a", "metadata": {}, "source": [ "" ] }, { "cell_type": "markdown", "id": "4c6db5ff", "metadata": {}, "source": [ "# Cassegrain Ray Tracing tutorial\n", "This tutorial was created to clarify the usage of the Cassegrain ray tracing tools.\n", "These tools were created as a proof of concept of using ray tracing to simulate phase effects caused by small optical misalignments in holography apertures.\n", "On previous holography experiments, e.g. VLA holographies, these phase effects were fitted out of apertures by using a phase model derived by Ruze (1969), this model assumes that the path length perturbations are small and hence only the first-degree terms are used.\n", "This type of \"phase fitting\" is very powerful, however it relies on the misalignments being small and on the fact of the VLA using a modified version of the Cassegrain optical design.\n", "For the case of the ngVLA this is no longer the case and both reflectors used shaped optics, and thus it is very hard to estimate phase effects on the aperture analytically.\n", "Hence the need for a Ray tracing model of the ngVLA.\n", "\n", "The toy model presented here is a proofย of concept, that can be checked against the phase fitting algorithm already present in astrohack." ] }, { "cell_type": "code", "execution_count": 1, "id": "4beb8248-5a07-4673-82fd-4a74b8f31c38", "metadata": { "ExecuteTime": { "end_time": "2026-02-10T16:54:25.542818377Z", "start_time": "2026-02-10T16:54:22.941822569Z" }, "execution": { "iopub.execute_input": "2026-03-19T21:39:16.654597Z", "iopub.status.busy": "2026-03-19T21:39:16.654450Z", "iopub.status.idle": "2026-03-19T21:39:18.807393Z", "shell.execute_reply": "2026-03-19T21:39:18.806808Z" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AstroHACK version 1.0.1 already installed.\n" ] } ], "source": [ "import os\n", "\n", "try:\n", " import astrohack\n", "\n", " print(\"AstroHACK version\", astrohack.__version__, \"already installed.\")\n", "except ImportError as e:\n", " print(e)\n", " print(\"Installing AstroHACK\")\n", "\n", " os.system(\"pip install astrohack\")\n", "\n", " import astrohack\n", "\n", " print(\"astrohack version\", astrohack.__version__, \" installed.\")" ] }, { "cell_type": "markdown", "id": "2a404254-1e8c-4c22-8ce4-fa278d677601", "metadata": {}, "source": [ "## Setting up\n", "In this step we create the variables containing the names of the files to be created, as well as the folder to contain the plots and ray tracing file." ] }, { "cell_type": "code", "execution_count": 2, "id": "e3502b07-492f-40e8-b1e2-e2b3013b7c62", "metadata": { "ExecuteTime": { "end_time": "2026-02-10T16:54:25.608481378Z", "start_time": "2026-02-10T16:54:25.577739941Z" }, "execution": { "iopub.execute_input": "2026-03-19T21:39:18.808736Z", "iopub.status.busy": "2026-03-19T21:39:18.808509Z", "iopub.status.idle": "2026-03-19T21:39:18.810780Z", "shell.execute_reply": "2026-03-19T21:39:18.810363Z" } }, "outputs": [], "source": [ "# Setting up file names and a folder to contain data\n", "datafolder = \"vla-rt-data\"\n", "os.makedirs(datafolder, exist_ok=True)\n", "vla_rt_filename = datafolder + \"/VLA-rt.zarr\"\n", "plot_base_names = datafolder + \"/vla-rt\"" ] }, { "cell_type": "markdown", "id": "2e6a51bb-ce33-42cb-abc1-760a0dadc8a8", "metadata": {}, "source": [ "## Initiate Telescope parameters\n", "To run the ray tracing pipeline, we need a set of parameters to describe the optics of the telescope to be simulated.\n", "The expected format for these parameters is a dictionary, the function below creates such a dictionary.\n", "Below we fill the parameters of this function with the appropriate values for the VLA, according to EVLA memo 211.\n" ] }, { "cell_type": "code", "execution_count": 3, "id": "0d42b0f6", "metadata": { "ExecuteTime": { "end_time": "2026-02-10T16:54:25.683639866Z", "start_time": "2026-02-10T16:54:25.610566120Z" }, "execution": { "iopub.execute_input": "2026-03-19T21:39:18.812111Z", "iopub.status.busy": "2026-03-19T21:39:18.811977Z", "iopub.status.idle": "2026-03-19T21:39:18.819973Z", "shell.execute_reply": "2026-03-19T21:39:18.819543Z" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[\u001b[38;2;128;05;128m2026-03-19 15:39:18,813\u001b[0m] \u001b[38;2;50;50;205m INFO\u001b[0m\u001b[38;2;112;128;144m astrohack: \u001b[0m Module path: \u001b[38;2;50;50;205m/export/home/arya/work/Holography-1022/astrohack/src/astrohack\u001b[0m \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "primary_diameter = 25.0\n", "secondary_diameter = 2.5146\n", "focal_length = 9.0\n", "z_intercept = 3.14\n", "foci_half_distance = 3.662\n", "inner_radius = 2.0\n", "horn_diameter = 0.2\n", "horn_position = [0, 0, 1.6760000000000002]\n", "horn_orientation = [0, 0, 1]\n", "\n" ] } ], "source": [ "from astrohack import create_ray_tracing_telescope_parameter_dict\n", "\n", "vla_pars = create_ray_tracing_telescope_parameter_dict(\n", " primary_diameter=25, # 25 meters for the VLA\n", " secondary_diameter=2.5146, # VLA's Secondary diameter\n", " focal_length=9.0, # VLA's focal length\n", " z_intercept=3.140, # Distance between the z intercept of the secondary and the point between the 2 foci\n", " foci_half_distance=3.662, # Half distance between the 2 foci\n", " inner_radius=2.0, # Inner blockage\n", " horn_diameter=0.2, # Horn diameter\n", " length_unit=\"m\", # Unit for the dimensions given\n", ")\n", "\n", "print()\n", "for key, item in vla_pars.items():\n", " print(f\"{key:20s} = {item}\")\n", "print()" ] }, { "cell_type": "markdown", "id": "a55c89ea-d681-4fc5-b76b-db462ac8f449", "metadata": {}, "source": [ "## Run Ray tracing pipeline\n", "In the step below we ran the actual ray tracing pipeline.\n", "By default, no perturbations are introduced, the user is encouraged to play with the parameters to see the effects they create on the phase image plotted on the next step.\n", "Note that to first order a X Y displacement of the secondary reflector is equivalent to a pointing offset, a pointing offset is usually used to compensate for such displacements of the secondary, such as the ones caused by gravitational torques. Such is the case in reference pointing." ] }, { "cell_type": "code", "execution_count": 4, "id": "ba508eff", "metadata": { "ExecuteTime": { "end_time": "2026-02-23T21:40:38.399717546Z", "start_time": "2026-02-23T21:40:36.131098519Z" }, "execution": { "iopub.execute_input": "2026-03-19T21:39:18.821103Z", "iopub.status.busy": "2026-03-19T21:39:18.820952Z", "iopub.status.idle": "2026-03-19T21:39:21.744561Z", "shell.execute_reply": "2026-03-19T21:39:21.744089Z" }, "tags": [] }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[\u001b[38;2;128;05;128m2026-03-19 15:39:18,822\u001b[0m] \u001b[38;2;50;50;205m INFO\u001b[0m\u001b[38;2;112;128;144m astrohack: \u001b[0m Module path: \u001b[38;2;50;50;205m/export/home/arya/work/Holography-1022/astrohack/src/astrohack\u001b[0m \n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 2.9 s, sys: 90.4 ms, total: 2.99 s\n", "Wall time: 2.92 s\n" ] } ], "source": [ "%%time\n", "from astrohack import cassegrain_ray_tracing_pipeline\n", "\n", "rt_xds = cassegrain_ray_tracing_pipeline(\n", " output_xds_filename=vla_rt_filename, # Name of the output XDS file\n", " telescope_parameters=vla_pars, # Using previously defined dictionary with VLA parameters\n", " grid_size=28, # Big enough to fit the primary of the VLA with some spare\n", " grid_resolution=0.1, # Fine-grained enough for most holographies\n", " grid_unit=\"m\", # Unit for grid parameters\n", " x_pointing_offset=0, # Pointing offset in the X direction\n", " y_pointing_offset=0, # Pointing offset in the Y direction\n", " pointing_offset_unit=\"asec\", # Unit for pointing offset\n", " x_focus_offset=0, # Secondary displacement in the X direction\n", " y_focus_offset=0, # Secondary displacement in the Y direction\n", " z_focus_offset=0, # Secondary displacement in the Z direction (regular focus offset)\n", " focus_offset_unit=\"mm\", # Unit for secondary displacements\n", " phase_offset=0, # Simple additive offset for phases\n", " phase_unit=\"deg\", # Unit for phase offset\n", " observing_wavelength=1, # Wavelength for the simulations\n", " wavelength_unit=\"cm\", # Unit for the wavelength\n", " overwrite=True, # Overwrite RT file on disk\n", ")" ] }, { "cell_type": "markdown", "id": "b1155bc1-9d4f-46fd-8e5e-2735c6b1ee72", "metadata": {}, "source": [ "The ray tracing pipeline produces at the end a Xarray dataset that is saved to disk on a Zarr format, this data product shall be called the `rt_xds` from now on.\n", "The `rt_xds` is also returned as an Xarray dataset object that can be inspected.\n", "Below we can that the data variables inside the `rt_xds` are not shaped as an image they are arrays of tridimensional points, arrays of tridimensional vectors or 1D arrays.\n", "The data is arranged this way to minimize the overhead of checking for nans in images, and can be easily rebuilt onto a 2D image grid with the data variable `image_indexes`." ] }, { "cell_type": "code", "execution_count": 5, "id": "6d824ef0-d7b2-4119-ab09-2951e7ebe0ea", "metadata": { "ExecuteTime": { "end_time": "2026-02-10T16:54:31.986920588Z", "start_time": "2026-02-10T16:54:31.925123661Z" }, "execution": { "iopub.execute_input": "2026-03-19T21:39:21.746201Z", "iopub.status.busy": "2026-03-19T21:39:21.746044Z", "iopub.status.idle": "2026-03-19T21:39:21.767145Z", "shell.execute_reply": "2026-03-19T21:39:21.766656Z" } }, "outputs": [ { "data": { "text/html": [ "
<xarray.Dataset> Size: 11MB\n",
"Dimensions: (points: 47816, xyz: 3, vxyz: 3, idx: 2,\n",
" x: 283, y: 283)\n",
"Dimensions without coordinates: points, xyz, vxyz, idx, x, y\n",
"Data variables: (12/15)\n",
" primary_points (points, xyz) float64 1MB -1.05 ... 4.336\n",
" primary_normals (points, vxyz) float64 1MB 0.04792 ... 0.8215\n",
" image_indexes (points, idx) int64 765kB 16 130 ... 265 151\n",
" x_axis (x) float64 2kB -14.05 -13.95 ... 14.05 14.15\n",
" y_axis (y) float64 2kB -14.05 -13.95 ... 14.05 14.15\n",
" primary_reflections (points, vxyz) float64 1MB 0.07873 ... 0.3497\n",
" ... ...\n",
" secondary_normals (points, vxyz) float64 1MB 0.04418 ... 0.8507\n",
" secondary_reflections (points, vxyz) float64 1MB 0.008928 ... -0...\n",
" distance_secondary_to_horn (points) float64 383kB 7.083 7.083 ... 7.083\n",
" horn_intercept (points, xyz) float64 1MB -1.818e-15 ... 1...\n",
" total_path (points) float64 383kB 19.62 19.62 ... 19.62\n",
" phase (points) float64 383kB 0.08727 ... 0.08727\n",
"Attributes:\n",
" image_size: 283\n",
" npnt_1d: 47816\n",
" telescope_parameters: {'primary_diameter': 25.0, 'secondary_diameter': 2...\n",
" input_parameters: {'output_xds_filename': 'vla-rt-data/VLA-rt.zarr',...