Synthetic Image

A “synthetic image” is the result of ray-shooting and possibly also convolving with a PSF. Importantly, there is no detector noise. The units of the pixels are in counts/sec.

Generating a synthetic image from a strong lens is the first step in simulating the observed image (the “exposure”).

from mejiro.galaxy_galaxy import SampleGG
from mejiro.instruments.roman import Roman
from mejiro.synthetic_image import SyntheticImage

strong_lens = SampleGG()

synthetic_image = SyntheticImage(strong_lens=strong_lens,
                                instrument=Roman(),
                                band='F129',
                                fov_arcsec=5)
synthetic_image.plot()

This produces the following figure:

Example synthetic image

synthetic_image

class mejiro.synthetic_image.LightweightStrongLens(meta)[source]

Bases: object

Minimal StrongLens stand-in loaded from a lightweight .npz.

Exposes only the attributes and accessor methods the romanisim-path pipeline reads from synthetic_image.strong_lens — redshifts, substructure flag, and the scalar get_* accessors. Each lightweight file is per-band, so the per-band magnitude accessors assert the requested band matches the stored band.

get_einstein_radius()[source]
get_lens_magnitude(band)[source]
get_lensed_source_magnitude(band)[source]
get_magnification()[source]
get_main_halo_mass()[source]
get_source_magnitude(band)[source]
get_velocity_dispersion()[source]
class mejiro.synthetic_image.LightweightSyntheticImage(data, meta)[source]

Bases: object

In-memory shim returned when loading a lightweight .npz.

Quacks like SyntheticImage for the attributes and methods consumed by the romanisim path. Not suitable for the galsim path (no lens model, PSF, or pixel-grid plumbing).

get_flux()[source]

Total flux in counts/sec (sum over all pixels).

get_maggies()[source]

Total flux in maggies. Replicates SyntheticImage.get_maggies.

Implemented in plain floats so it does not require the stored magnitude_zeropoint to be an astropy Quantity.

classmethod load(path)[source]
class mejiro.synthetic_image.SyntheticImage(strong_lens, instrument, band, fov_arcsec=5, instrument_params={}, kwargs_numerics={}, kwargs_psf={}, pieces=False)[source]

Bases: object

DEFAULT_KWARGS_NUMERICS = {'compute_indexes': None, 'compute_mode': 'regular', 'flux_evaluate_indexes': None, 'point_source_supersampling_factor': 5, 'supersampled_indexes': None, 'supersampling_convolution': True, 'supersampling_factor': 5, 'supersampling_kernel_size': None}
DEFAULT_KWARGS_PSF = {'psf_type': 'NONE'}
build_adaptive_grid(pad)[source]

Builds an adaptive grid mask based on the distance of image positions from the center of the scene. To ensure that the mask includes the image positions, the pad value should be at least two pixels but ideally much larger in order to capture the vast majority of the lensed source’s flux.

Parameters:

pad (int) – Padding value to extend the minimum and maximum radii of the grid mask. Must be non-negative.

Returns:

A boolean mask array where True indicates grid points within the adaptive grid range and False indicates points outside the range.

Return type:

numpy.ndarray

Raises:

ValueError – If the image positions cannot be calculated or are empty.

Notes

  • The grid is centered around the scene, and the distances are calculated relative to the lens center adjusted by the pixel scale.

  • The adaptive grid range is determined by the minimum and maximum radii of the image positions, adjusted by the padding value.

  • The range is clamped to ensure it does not exceed the bounds of the scene dimensions.

get_flux()[source]

Calculate the total flux in counts/sec of the synthetic image by summing over all pixel values.

Returns:

The total flux of the synthetic image in counts/sec.

Return type:

float

get_image_positions(ignore_substructure=True, pixel=True)[source]

Calculate the image positions from the source position and lensing mass model. Wraps GalaxyGalaxy.get_image_positions(), with the added functionality of returning the positions in pixel coordinates based on the pixel grid defined for this synthetic image.

Parameters:
  • ignore_substructure (bool, optional) – If True (default), ignores substructure in the lens model when computing image positions. If False, includes substructure in the calculation.

  • pixel (bool, optional) – If True, the image positions are returned in pixel coordinates. If False, the image positions are returned in lenstronomy’s default angular coordinates. Default is True.

Returns:

([x coordinates], [y coordinates]) of the image positions. When pixel=True (default), coordinates are in pixels; when pixel=False, coordinates are in lenstronomy’s angular units (often arcseconds).

Return type:

Tuple of arrays

get_maggies()[source]

Calculate the total flux of the synthetic image in maggies. This is done by summing over all pixel values to get the total flux in counts/sec, and then converting that flux to maggies using the instrument’s zero-point magnitude for the specified band.

Returns:

The total flux of the synthetic image in maggies.

Return type:

float

overplot_subhalos(alpha=0.5, savepath=None)[source]
plot(savepath=None)[source]

Quickly visualize the synthetic image.

Parameters:

savepath (str, optional) – The file path where the plot will be saved. If None, the plot will not be saved. Default is None.

Notes

The image is displayed using a logarithmic scale (base 10).

save_lightweight(path)[source]

Write the lightweight .npz representation used by the romanisim path.

Stores the image as float32 plus a JSON metadata blob carrying only the scalars that downstream consumers (romanisim_pipeline, _06_h5_export_romanisim, calculate_snrs, projects/.../rung_1.py) actually read. The full StrongLens and lenstronomy plumbing are not persisted; loaders should use mejiro.utils.util.load_synthetic_image(), which returns a LightweightSyntheticImage for .npz paths.

Parameters:

path (str) – Destination path. Should end in .npz.

Notes

Not compatible with the galsim path (_05_create_exposures.py); that step requires the full SyntheticImage and will raise if it sees lightweight outputs. self.pieces is ignored — per-piece arrays are not serialized.