### Install from source with Git LFS Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/install.rst Clones the repository, pulls large files with Git LFS, and installs in editable mode. Recommended for using examples with pre-computed data. Requires several gigabytes of disk space. ```bash git clone https://github.com/xiaziyna/PyStarshade.git PyStarshade cd PyStarshade git lfs pull pip install -e . ``` -------------------------------- ### Install pystarshade with pip Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/install.rst Installs the package from PyPI for a barebones installation without pre-computed data. ```bash pip install pystarshade ``` -------------------------------- ### Install with GPU support Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/install.rst Installs the package with GPU support, adding PyTorch as a dependency. Requires an NVIDIA GPU with CUDA; if available, gen_pupil_field() will automatically use the GPU. ```bash pip install -e ".[gpu]" ``` -------------------------------- ### Install PyStarshade from source with Git LFS Source: https://github.com/xiaziyna/pystarshade/blob/main/README.md Clones the repository, pulls large files with Git LFS, and installs the package in editable mode. Requires several GB of disk space and is intended for using pre-generated data. ```bash $ git clone https://github.com/xiaziyna/PyStarshade.git PyStarshade $ cd PyStarshade $ git lfs pull pip install -e . ``` -------------------------------- ### Example drm configuration dictionary Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/usage.rst Example drm dictionary defining starshade parameters: focal length, telescope diameter, starshade radius, distance, petal count, wavelength bands, pixel samplings, and inner working angle. The 'grey_mask_dx' values describe pixel sampling in physical units (e.g., '01m' means Δs = 0.01 m). ```python 'hwo': { 'focal_length_lens': 10, 'diameter_telescope_m': 6, 'radius_lens': 3, 'ss_radius': 30, 'dist_ss_t': [9.52e+07], 'num_pet': 24, 'wl_bands': [[500, 600]], 'dx_': [0.04, 0.001], 'grey_mask_dx': ['04m', '001m'], 'iwa': [30 / 9.52e+07 / mas_to_rad] # R_ss / dist_ss_t in MAS } ``` -------------------------------- ### grey_mask_dx parameter example Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/solar_system.ipynb Shows the mapping of the grey_mask_dx parameter value "01m" to a physical pixel sampling of 0.01 meters. ```text "01m" → Δs = 0.01 m ``` -------------------------------- ### StarshadeProp example: hwo mission workflow Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/test.rst Shows the typical workflow for the StarshadeProp class: instantiate with the 'hwo' design reference mission, generate the pupil field, generate the PSF basis for a hexagonal pupil, and generate the scene intensity at 500 nm. The source_field argument is a placeholder for an existing array. ```pycon >>> hwo_starshade = StarshadeProp(drm='hwo') >>> hwo_starshade.gen_pupil_field() >>> hwo_starshade.gen_psf_basis(pupil_type='hex') >>> hwo_starshade.gen_scene(pupil_type='hex', source_field, 500e-9) ``` -------------------------------- ### Commit message example for PyStarshade Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/contribute.rst Use this as a commit message format when contributing code. It follows the conventional commit style and clearly describes the change. ```python feat: add widget-alignment option ``` -------------------------------- ### Run tests with pytest Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/install.rst Runs all unit tests in the tests/ directory from the repository root. Passing tests confirm the installation works. ```bash pytest tests/ ``` -------------------------------- ### Generate and use a PSF basis with StarshadeProp Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/usage.rst Complete workflow to generate a PSF basis and simulate a scene. Initialize with a DRM, generate the pupil field (computationally intensive), generate the PSF basis for a specific pupil type, then create a source field and call gen_scene to get the focal intensity. Note that gen_pupil_field may take hours and gen_psf_basis may take minutes to an hour. ```python from pystarshade.propagator import StarshadeProp import numpy as np # 1. Initialize with a DRM drm = 'hwo' starshade = StarshadeProp(drm=drm) # 2. Generate the pupil field (this is computationally intensive) # Optional parameters: wl_override, N_x_override, dx_override, chunk=1 starshade.gen_pupil_field() # 3. Generate PSF basis for a specific telescope pupil pupil_type = 'hex' # Can be 'hex', 'circular', or a custom pupil starshade.gen_psf_basis(pupil_type=pupil_type) # 4. Use the generated PSF basis to simulate a scene # Load or create a toy model of a source field source_field = np.zeros((251, 251), dtype=np.float32) source_field[126, 126] = 1 #star source_field[70, 126] = 1e-10 #toy planet wavelength = 500e-9 # 500 nm focal_intensity = starshade.gen_scene(pupil_type, source_field, wavelength) ``` -------------------------------- ### Generate HWO PSF basis with StarshadeProp Source: https://github.com/xiaziyna/pystarshade/blob/main/examples/solar_system.ipynb Generates a full PSF basis for the HWO starshade and saves it to disk. Requires the StarshadeProp class and the pre-computed diffracted fields from the git-LFS install. The pupil_type 'hwopupil_onaxis' is used for the on-axis HWO pupil. ```python hwo_starshade = StarshadeProp(drm='hwo') hwo_starshade.gen_pupil_field() hwo_starshade.gen_psf_basis(pupil_type='hwopupil_onaxis') ``` -------------------------------- ### Load and print WFIRST telescope parameters Source: https://github.com/xiaziyna/pystarshade/blob/main/examples/solar_system.ipynb Loads the WFIRST telescope parameters from the DRM file and prints them. The output shows the focal length, telescope diameter, inner working angle, and other mission parameters. ```python from pystarshade.data.drm import telescope_params # Load the 'wfirst' parameters wfirst_params = telescope_params['wfirst'] # Print the WFIRST parameters print("WFIRST Telescope Parameters:") for key, value in wfirst_params.items(): print(f"{key}: {value}") ``` -------------------------------- ### Force GPU or CPU for chunked FFT Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/usage.rst Controls GPU usage for the chunked FFT when a CUDA-capable GPU and PyTorch are available (install with `pip install pystarshade[gpu]`). Setting use_gpu=True forces GPU execution; use_gpu=False forces CPU execution. ```python hwo_starshade.gen_pupil_field(use_gpu=True) # force GPU hwo_starshade.gen_pupil_field(use_gpu=False) # force CPU ``` -------------------------------- ### Import libraries and download ExoVista scene Source: https://github.com/xiaziyna/pystarshade/blob/main/examples/solar_system.ipynb Imports the required libraries and pystarshade modules, downloads the ExoVista scene file, and sets the local zodiacal light magnitude to 22.5 mag/arcsec^2. ```python from astropy.io import fits import numpy as np import download_exovista download_exovista.exovista_scenes_file() from pystarshade.data.scenes.Scene import * from pystarshade.diffraction.util import mas_to_rad, au_to_meter, pc_to_meter, data_file_path #, flux_to_mag, from pystarshade.propagator import StarshadeProp import matplotlib.pyplot as plt from matplotlib.colors import LogNorm from matplotlib import rc local_zodi_mag_v_arcsec2 = 22.5 #local zodi ``` -------------------------------- ### Fresnel Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/test.rst Class representing a Fresnel diffraction computation setup. Stores spatial sampling, input size, propagation distance, and wavelength. ```APIDOC ## Fresnel ### Description Represents a Fresnel diffraction computation setup. ### Constructor Parameters - **d_x** (float) - Required - Spatial sampling interval of the input field [m]. - **N_in** (int) - Required - Number of non-zero input samples. - **z** (float) - Required - Propagation distance [m]. - **wavelength** (float) - Required - Wavelength of the light [m]. ### Attributes - **wl_z** (float) - Product of the wavelength and propagation distance. - **k** (float) - Wave number. - **max_freq** (float) - Maximum frequency of the input field. ``` -------------------------------- ### Output: WFIRST telescope parameters Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/solar_system.ipynb Output from the previous cell showing the WFIRST telescope parameters as printed by the loop. ```text Output: WFIRST Telescope Parameters: focal_length_lens: 30 diameter_telescope_m: 2.36 radius_lens: 1.18 dist_ss_t: [37242256.68350351 26120376.72633376 21191429.69119565] iwa_mas: 72 num_pet: 16 ss_radius: 13 grey_mask_dx: ['01m', '005m', '002m', '001m', '0005m'] dx_: [0.01, 0.005, 0.002, 0.001, 0.0005] wl_bands: [[425, 552], [606, 787], [747, 970]] iwa: [ 72. 102.65711361 126.53428864] ``` -------------------------------- ### Add parent directory to sys.path Source: https://github.com/xiaziyna/pystarshade/blob/main/examples/solar_system.ipynb Adds the parent directory to the Python path so that the notebook can import the pystarshade package when run from the examples folder. ```python import os import gc import sys notebook_dir = os.getcwd() parent_dir = os.path.abspath(os.path.join(notebook_dir, "..")) if parent_dir not in sys.path: sys.path.insert(0, parent_dir) ``` -------------------------------- ### Load ExoVista scene and print scene properties Source: https://github.com/xiaziyna/pystarshade/blob/main/examples/solar_system.ipynb Loads an ExoVista scene, builds a source field at 500 nm, and prints scene properties (star/planet brightness, semi-major axes, distance, etc.) before displaying the input scene. Requires prior definitions of `file_path`, `dist_xo_ss`, `hdul`, `n_planet`, and unit conversion constants. The printed output shows the scene's magnitude, inclination, number of Zodis, and physical extent. ```python t = 0 # timestep scene = Scene(file_path) wl_range = scene.lambdas * 1e-6 # Define the wavelength (lam_ref), make sure this matches up with the PSF basis lam_ref = np.float64(5*1e-7) wl_str = int(lam_ref*1e9) w_i = np.where(wl_range >= lam_ref)[0][0] wl = wl_range[w_i] bg_scene = scene.getDiskImage()[w_i] star_xy = scene.getXYstar() star_spectra = scene.getStarSpec(time = t)[w_i] bg_scene[int(star_xy[0]), int(star_xy[1])] += star_spectra planet_xy = scene.getXYplanets(time = t).astype(int) planet_spectra = scene.getPlanetSpec(time = t)[:, w_i] ds_mas = scene.getPixScale() stel_ang_diam = scene.getAngDiam() ds = dist_xo_ss * ds_mas * mas_to_rad ds_au = ds / au_to_meter N_wl = len(wl_range) N_dust = np.shape(bg_scene)[1] N_dust_half = N_dust//2 N_s = 1001 source_field = np.zeros((N_s, N_s), dtype=np.complex128) half_N = N_s // 2 half_in_N = N_dust // 2 bit_arr = N_dust % 2 source_field[half_N - half_in_N : half_N + half_in_N + bit_arr, half_N - half_in_N : half_N + half_in_N + bit_arr] = bg_scene n_planet = 0 for i in range(scene.nplanets): if np.all(planet_xy[i] - N_dust_half + half_N <= N_s-1) and np.all(planet_xy[i] - N_dust_half + half_N >= 0): source_field[planet_xy[i, 1]- N_dust_half + half_N , planet_xy[i, 0]- N_dust_half + half_N] += planet_spectra[i] n_planet +=1 print ('Magnitude of star: ', -2.5*np.log10((500**2)*source_field[int(star_xy[0]), int(star_xy[1])])+8.9) print ('Magnitude at ~ 1 AU: ', - 2.5*np.log10((500**2)*source_field[int(star_xy[0]) - 50, int(star_xy[1])]) + 8.9) print ('inclination: ', hdul[2].header['I-0']) print ('number of Zodis: ', hdul[2].header['NZODIS-0']) print ('Distance from exo-scene to starshade [pc]: ', dist_xo_ss/pc_to_meter) print ('Number of planets included in scene: ', n_planet) print ('Star brightness: ', star_spectra) print ('Planet brightness: ', planet_spectra) print ('Plan/Star brightness: ', (planet_spectra/(star_spectra))) print ('Semi major axis[au]: ', np.sqrt(2)*ds_au*np.hypot(planet_xy[:, 0] - N_dust_half, planet_xy[:, 1] - N_dust_half)) print ('wavelength [m]', wl) print ('ZODIs: ', hdul[2].header['NZODIS-0']) print ('Physical extent (AU)', N_s * ds * (1/au_to_meter)) print ( '1 source pixel is (AU): ', ds/au_to_meter) print ('Distance of system (pc): ', dist_xo_ss/pc_to_meter) plt.figure() plt.title('ExoVista input scene', fontsize=14) plt.text(-940, 900, r'$\lambda = $%s nm' % (wl_str), color='white', fontsize=12) plt.imshow(np.abs(source_field), norm=LogNorm(), cmap='jet', extent=(-N_s, N_s, -N_s, N_s)) plt.xlabel('x [mas]', fontsize=14) plt.ylabel('y [mas]', fontsize=14) cbar = plt.colorbar() cbar.set_label('Contrast', fontsize=14) plt.tight_layout() plt.show() del scene del star_xy del star_spectra del planet_xy del planet_spectra del bg_scene _ = __ = ___ = None gc.collect() ``` -------------------------------- ### Select starshade drm configuration Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/usage.rst Selects the 'hwo' design reference mission (drm) configuration for PyStarshade. Other provided options are 'wfirst' and 'habex'. ```python drm = 'hwo' ``` -------------------------------- ### StarshadeProp Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/test.rst Class for pre-computing files and propagating light past a starshade. Constructor initializes with mission parameters and resolution settings. ```APIDOC ## StarshadeProp ### Description Class for pre-computing files and propagating light past a starshade. ### Constructor Parameters - **drm** (str) - Required - Design reference mission (e.g., 'wfirst' or 'hwo'). - **d_s_mas** (float, optional) - Source angular resolution in milliarcseconds, defaults to 2. - **d_t_mas** (float, optional) - Pixel shift in the pupil plane corresponding to the angular field, defaults to 0.05. - **d_p_mas** (float, optional) - Pixel size in the focal plane in milliarcseconds, defaults to 2. - **d_wl** (float, optional) - Wavelength step size in nanometers, defaults to 50. ### Example ```pycon >>> hwo_starshade = StarshadeProp(drm='hwo') >>> hwo_starshade.gen_pupil_field() >>> hwo_starshade.gen_psf_basis(pupil_type='hex') >>> hwo_starshade.gen_scene(pupil_type='hex', source_field, 500e-9) ``` ``` -------------------------------- ### Clone and branch PyStarshade repository Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/contribute.rst Use this to set up a local development branch for contributing to PyStarshade. It clones the repository, changes into the project directory, and creates a new branch named feature/short-name from the current main branch. ```python git clone git@github.com:xiaziyna/PyStarshade.git cd PyStarshade git checkout -b feature/short-name ``` -------------------------------- ### Load ExoVista scene from FITS file Source: https://github.com/xiaziyna/pystarshade/blob/main/examples/solar_system.ipynb Loads a solar system scene from a FITS file, extracting the distance and inclination from the headers. Requires the 'fname_faceon' variable defined earlier and the 'pc_to_meter' conversion factor. The scene is used for imaging simulations with PyStarshade. ```python # Handle directories and load solar system scene data_dir = os.path.abspath(os.path.join(notebook_dir, '..', 'pystarshade', 'data')) file_path = os.path.join(data_dir, 'scenes', fname_faceon) hdul = fits.open(file_path) dist_xo_ss = hdul[4].header['dist'] * pc_to_meter inclination = hdul[2].header['I-0'] ``` -------------------------------- ### Initialize StarshadeProp and generate pupil field Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/usage.rst Initializes the StarshadeProp class for the 'hwo' drm and generates the pupil field, storing it on disk. Optional parameters can change pupil or wavelength sampling; the 'chunk' setting enables a chunked FFT using a memory-mapped starshade mask to avoid RAM bottlenecks. ```python from pystarshade.propagator import StarshadeProp drm = 'hwo' hwo_starshade = StarshadeProp(drm = drm) hwo_starshade.gen_pupil_field() ``` -------------------------------- ### Output: Scene.py already exists Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/solar_system.ipynb Output from the previous cell indicating that the Scene.py file already exists in the specified path. ```text Output: Scene.py already exists in /home/ielo/sandbox/test_/PyStarshade/pystarshade/data/scenes. ``` -------------------------------- ### Simulate with GMT aperture Source: https://github.com/xiaziyna/pystarshade/blob/main/examples/solar_system.ipynb Runs the simulation with a different aperture (GMT) by setting drm='hwo' and pupil_type='GMT'. It generates the PSF basis, scene, and pupil mask, then plots the aperture. The output shows a ComplexWarning and a figure with 1 Axes. ```python drm = 'hwo' pupil_type = 'GMT' hwo_starshade = StarshadeProp(drm = drm) hwo_starshade.N_wl = 1 # edit an internal variable so that only a single wavelength PSF basis is calculated hwo_starshade.gen_psf_basis(pupil_type = pupil_type) focal_intensity = hwo_starshade.gen_scene(pupil_type, source_field.astype(np.float32), lam_ref, pupil_symmetry = False) hwo_starshade.gen_pupil(pupil_type = pupil_type) aperture = hwo_starshade.pupil_mask plt.figure() # Plot the first image plt.imshow(aperture,extent=(-3, 3, -3, 3)) plt.xlabel('x [m]',fontsize=14) plt.ylabel('y [m]',fontsize=14) plt.show() ``` ```text Output: /tmp/ipykernel_426246/4103030377.py:7: ComplexWarning: Casting complex values to real discards the imaginary part focal_intensity = hwo_starshade.gen_scene(pupil_type, source_field.astype(np.float32), lam_ref, pupil_symmetry = False) ``` ```text Result:
``` -------------------------------- ### Define ExoVista solar system scene filenames Source: https://github.com/xiaziyna/pystarshade/blob/main/examples/solar_system.ipynb Defines filenames for pre-simulated solar system scenes at 60 degrees inclination and face-on, located in the 'data/scenes' directory. These are used with the Scene.py script to load the scenes. ```python fname_60 = '999-HIP_-TYC_SUN-mv_4.83-L_1.00-d_10.00-Teff_5778.60.fits' #solar system at 60 deg inclination fname_faceon = '999-HIP_-TYC_SUN-mv_4.83-L_1.00-d_10.00-Teff_5778.00.fits' #solar system face-on ``` -------------------------------- ### Load and plot WFIRST and HWO starshade masks Source: https://github.com/xiaziyna/pystarshade/blob/main/examples/solar_system.ipynb Loads the WFIRST and HWO starshade masks from the provided data files, converts them to full masks, and plots them side by side with the appropriate extents. The plot shows the starshade masks for the Roman (WFIRST) and HWO missions. ```python import matplotlib.pyplot as plt from pystarshade.apodization.apodize import qu_mask_to_full drm = 'wfirst' wfirst_starshade = StarshadeProp(drm = drm) wfirst_starshade.set_mission_params(drm, mask_choice=0, band_i=0) d_x_w = wfirst_starshade.d_x ss_mask_fname = wfirst_starshade.ss_mask_fname_partial + '_qu.npz' starshade_qu = np.load(ss_mask_fname) wfirst_starshade = qu_mask_to_full(starshade_qu['grey_mask']) drm = 'hwo' hwo_starshade = StarshadeProp(drm = drm) hwo_starshade.set_mission_params(drm, mask_choice=0) d_x_h = hwo_starshade.d_x ss_mask_fname = hwo_starshade.ss_mask_fname_partial + '_qu.npz' starshade_qu = np.load(ss_mask_fname) hwo_starshade = qu_mask_to_full(starshade_qu['grey_mask']) N1 = wfirst_starshade.shape[0] N2 = hwo_starshade.shape[0] extent1 = (-N1*d_x_w/2, N1*d_x_w/2, -N1*d_x_w/2, N1*d_x_w/2) extent2 = (-N2*d_x_h/2, N2*d_x_h/2, -N2*d_x_h/2, N2*d_x_h/2) fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 5)) im1 = ax1.imshow(wfirst_starshade, extent=extent1, origin='lower', aspect='equal') ax1.set(title='Roman rendezvous (WFIRST)', xlabel='x [m]', ylabel='y [m]') im2 = ax2.imshow(hwo_starshade, extent=extent2, origin='lower', aspect='equal') ax2.set(title='HWO', xlabel='x [m]', ylabel='y [m]') ``` -------------------------------- ### Simulate starshade imaging with StarshadeProp Source: https://github.com/xiaziyna/pystarshade/blob/main/README.md Simulates imaging for a source field with a default 2 mas sampling using the StarshadeProp class. Initializes with the HWO design reference mission, generates the pupil field and PSF basis for a hexagonal pupil, creates a point source, and produces a focal intensity image with a log-normalized colorbar. ```python import numpy as np from pystarshade.propagator import StarshadeProp import matplotlib.pyplot as plt # 1. Initialize the Starshade Propagator with HWO (Habitable Worlds Observatory) configuration starshade = StarshadeProp(drm='hwo') # drm = design reference mission # 2. Generate the pupil field (this handles the Fresnel diffraction from starshade to telescope) starshade.gen_pupil_field() # 3. Generate PSF basis for a hexagonal pupil (this handles the Fraunhofer diffraction to focal plane) pupil_type = 'hex' starshade.gen_psf_basis(pupil_type=pupil_type) # 4. Create a simple point source (representing a star) # Using 2 mas (milliarcsecond) sampling as default nx = ny = 100 # image size source_field = np.zeros((nx, ny), dtype=np.float32) source_field[nx//2, ny//2] = 1.0 # place a point source in the center # 5. Generate the final image wavelength = 500e-9 # 500 nm focal_intensity = starshade.gen_scene(pupil_type, source_field, wavelength) # 6. Visualize the result plt.figure(figsize=(8, 8)) plt.imshow(focal_intensity, norm=plt.LogNorm()) plt.colorbar() plt.title('Simulated Starshade Image') plt.xlabel('Pixels') plt.ylabel('Pixels') plt.show() ``` -------------------------------- ### FresnelSingle.nchunk_zoom_fresnel_single_fft(x_file, N_out, N_chunk=None) Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/test.rst Performs single FFT Fresnel diffraction using an N_chunk*N_chunk-way chunked Bluestein FFT to cap peak memory usage. If use_gpu was set at construction, uses GPU-accelerated Bluestein FFT. ```APIDOC ## FresnelSingle.nchunk_zoom_fresnel_single_fft(x_file, N_out, N_chunk=None) ### Description Performs single FFT Fresnel diffraction using an N_chunk*N_chunk-way chunked Bluestein FFT to cap peak memory usage. If use_gpu was set at construction, uses GPU-accelerated Bluestein FFT. ### Method nchunk_zoom_fresnel_single_fft ### Endpoint FresnelSingle.nchunk_zoom_fresnel_single_fft(x_file, N_out, N_chunk=None) ### Parameters #### Path Parameters - **x_file** (np.memmap) - Required - Input mask filename as a memory-mapped object. - **N_out** (int) - Required - Number of output samples. - **N_chunk** (int, optional) - Optional - Number of chunks along each axis. Default is 8. ### Returns - **np.ndarray** - Propagated output field. - **float** - Output grid sampling. ``` -------------------------------- ### FresnelSingle.calc_zero_padding() Source: https://github.com/xiaziyna/pystarshade/blob/main/docs/content/test.rst Calculates the zero-padding factor (ZP * N_in) to achieve a specified frequency spacing (d_f) for a given spatial sampling (d_x) using the Fresnel single FT method. ```APIDOC ## FresnelSingle.calc_zero_padding() ### Description Calculates the zero-padding factor (ZP * N_in) to achieve a specified frequency spacing (d_f) for a given spatial sampling (d_x) using the Fresnel single FT method. ### Method calc_zero_padding ### Endpoint FresnelSingle.calc_zero_padding() ### Parameters None ### Returns - **Zero-padding factor** (float) - ZP * N_in to achieve the desired frequency spacing. ```