stdpipe.simulation module

Image simulation module for generating realistic stellar fields with contaminants.

This module provides functions for creating simulated astronomical images with: - Stars with Gaussian and Moffat PSF (pixel-integrated) - Extended sources (galaxies with Sersic profiles) - Imaging artifacts (cosmic rays, hot pixels, bad columns, satellite trails) - Diffraction spikes and optical ghosts for bright sources

Designed for real-bogus classifier development and photometry testing.

stdpipe.simulation.create_psf_model(fwhm=3.0, psf_type='gaussian', beta=2.5, size=None, oversampling=2, defocus=0.0, astigmatism_x=0.0, astigmatism_y=0.0, coma_x=0.0, coma_y=0.0, wavelength=5.5e-07, pupil_diameter=1.0)[source]

Create an oversampled PSF model compatible with PSFEx format.

This creates a PSF model that can be used with psf.place_psf_stamp() and other STDPipe routines. Uses oversampling for accurate flux conservation and fast evaluation with sub-pixel positioning.

Optical aberrations can be added via Zernike polynomial coefficients (Noll ordering). When any aberration coefficient is non-zero, a diffraction PSF is computed via Fourier optics and convolved with the atmospheric seeing PSF (Gaussian or Moffat). When all coefficients are zero, the existing analytical path is used unchanged.

Parameters:
fwhmfloat, optional

Full width at half maximum in pixels.

psf_typestr, optional

Type of PSF model (‘gaussian’ or ‘moffat’).

betafloat, optional

Moffat beta parameter (default 2.5, only used for psf_type=’moffat’).

sizeint, optional

Output stamp size in pixels (after downsampling). If None, automatically sized to capture ~99% of PSF flux (>=8*FWHM).

oversamplingint, optional

Oversampling factor (default 2).

defocusfloat, optional

Zernike Z4 defocus coefficient in waves (default 0.0).

astigmatism_xfloat, optional

Zernike Z5 oblique astigmatism coefficient in waves (default 0.0).

astigmatism_yfloat, optional

Zernike Z6 vertical astigmatism coefficient in waves (default 0.0).

coma_xfloat, optional

Zernike Z7 vertical coma coefficient in waves (default 0.0).

coma_yfloat, optional

Zernike Z8 horizontal coma coefficient in waves (default 0.0).

wavelengthfloat, optional

Observation wavelength in meters (default 550e-9, affects diffraction scale).

pupil_diameterfloat, optional

Pupil diameter in meters (default 1.0, affects diffraction scale).

Returns:
dict

Dictionary with PSFEx-compatible structure containing the PSF model.

stdpipe.simulation.create_sersic_profile(size, x0, y0, amplitude=1.0, r_eff=5.0, n=1.0, ellipticity=0.0, position_angle=0.0)[source]

Create a Sersic profile for galaxy simulation.

The Sersic profile is: I(r) = amplitude * exp(-b_n * ((r/r_eff)^(1/n) - 1)) where b_n ≈ 2n - 0.324 for n >= 0.5 (more accurate formula used internally)

Common cases: - n=0.5: Gaussian-like profile - n=1.0: Exponential disk (typical spiral galaxy disk) - n=4.0: de Vaucouleurs profile (typical elliptical galaxy)

Parameters:
sizeint

Size of the profile stamp (must be odd).

x0float

X center position within the stamp.

y0float

Y center position within the stamp.

amplitudefloat, optional

Central surface brightness amplitude.

r_efffloat, optional

Effective radius in pixels (half-light radius).

nfloat, optional

Sersic index (shape parameter).

ellipticityfloat, optional

Ellipticity (0 = circular, 0.5 = moderate, 0.9 = very elongated).

position_anglefloat, optional

Position angle in degrees (0 = vertical, increases CCW).

Returns:
numpy.ndarray

2D array of shape (size, size) with Sersic profile.

stdpipe.simulation.place_galaxy(image, x0, y0, flux, r_eff=5.0, n=1.0, ellipticity=0.0, position_angle=0.0)[source]

Place a galaxy with Sersic profile into an image.

The galaxy stamp is created, scaled to the requested flux, and added to the image. Similar to psf.place_psf_stamp() but for extended sources.

The image is modified in-place.

Parameters:
imagenumpy.ndarray

Target image (2D array), modified in-place.

x0float

X coordinate where to place the galaxy center.

y0float

Y coordinate where to place the galaxy center.

fluxfloat

Total integrated flux in ADU units.

r_efffloat, optional

Effective radius in pixels.

nfloat, optional

Sersic index.

ellipticityfloat, optional

Ellipticity (0 = circular, 1 = line).

position_anglefloat, optional

Position angle in degrees.

stdpipe.simulation.create_cosmic_ray(length, width, angle, max_intensity, profile='sharp')[source]

Create a cosmic ray track.

Cosmic rays appear as elongated tracks with sharp edges, oriented randomly.

Parameters:
lengthfloat

Length of the track in pixels.

widthfloat

Width of the track in pixels.

anglefloat

Angle in degrees (0 = horizontal, increases CCW).

max_intensityfloat

Peak intensity in ADU.

profilestr, optional

Intensity profile (‘sharp’, ‘tapered’, ‘worm’).

Returns:
dict

Dictionary with ‘stamp’ (2D array), ‘size’ (stamp dimensions).

stdpipe.simulation.add_cosmic_rays(image, n_rays=5, length_range=(5, 50), width_range=(1, 3), intensity_range=(1000, 10000), profile='sharp')[source]

Add cosmic ray tracks to an image.

Cosmic rays are placed at random positions with random orientations.

Parameters:
imagenumpy.ndarray

Target image (modified in-place).

n_raysint, optional

Number of cosmic rays to add.

length_rangetuple, optional

(min, max) length in pixels.

width_rangetuple, optional

(min, max) width in pixels.

intensity_rangetuple, optional

(min, max) peak intensity in ADU.

profilestr, optional

Intensity profile (‘sharp’, ‘tapered’, ‘worm’).

Returns:
astropy.table.Table

Catalog of added cosmic rays with columns: x, y, length, width, angle, intensity, type.

stdpipe.simulation.add_hot_pixels(image, n_pixels=10, intensity_range=(500, 5000), clustering=False, cluster_size=3)[source]

Add hot pixels to an image.

Hot pixels are single bright pixels at random locations, optionally clustered to simulate physical detector defects.

Parameters:
imagenumpy.ndarray

Target image (modified in-place).

n_pixelsint, optional

Number of hot pixels to add.

intensity_rangetuple, optional

(min, max) intensity in ADU.

clusteringbool, optional

If True, create clusters of hot pixels.

cluster_sizeint, optional

Number of pixels per cluster (if clustering=True).

Returns:
astropy.table.Table

Catalog of added hot pixels with columns: x, y, intensity, type.

stdpipe.simulation.add_bad_columns(image, n_columns=2, intensity_range=None, bad_type='dead', orientation='vertical')[source]

Add bad columns or rows to an image.

Bad columns can be dead (low/zero values), hot (high values), or noisy (high variance).

Parameters:
imagenumpy.ndarray

Target image (modified in-place).

n_columnsint, optional

Number of bad columns/rows to add.

intensity_rangetuple, optional

(min, max) intensity for ‘hot’ type. Ignored for ‘dead’ and ‘noisy’.

bad_typestr, optional

Type of bad column (‘dead’, ‘hot’, ‘noisy’).

orientationstr, optional

‘vertical’ for columns, ‘horizontal’ for rows.

Returns:
astropy.table.Table

Catalog of bad columns with columns: position, bad_type, orientation, type.

stdpipe.simulation.create_satellite_trail(length, width, intensity, angle=None, profile='linear', tumbling=False)[source]

Create a satellite trail.

Satellite trails are long, thin, bright streaks caused by satellites passing through the field.

Parameters:
lengthfloat

Length of the trail in pixels.

widthfloat

Width of the trail in pixels.

intensityfloat

Peak intensity in ADU.

anglefloat, optional

Angle in degrees (0 = horizontal). If None, random.

profilestr, optional

Transverse profile (‘linear’, ‘gaussian’).

tumblingbool, optional

If True, add intensity variations along the trail (tumbling satellite).

Returns:
dict

Dictionary with ‘stamp’ (2D array), ‘angle’ (actual angle used).

stdpipe.simulation.add_satellite_trails(image, n_trails=1, length_range=(100, 400), width_range=(2, 8), intensity_range=(5000, 20000), profile='linear', tumbling_prob=0.2)[source]

Add satellite trails to an image.

Parameters:
imagenumpy.ndarray

Target image (modified in-place).

n_trailsint, optional

Number of satellite trails to add.

length_rangetuple, optional

(min, max) length in pixels.

width_rangetuple, optional

(min, max) width in pixels.

intensity_rangetuple, optional

(min, max) peak intensity in ADU.

profilestr, optional

Transverse profile (‘linear’, ‘gaussian’).

tumbling_probfloat, optional

Probability of tumbling satellite (intensity variations).

Returns:
astropy.table.Table

Catalog of added trails.

stdpipe.simulation.create_diffraction_spikes(size, x0, y0, star_flux, n_spikes=4, spike_length=50, spike_width=2)[source]

Create diffraction spikes for a bright star.

Diffraction spikes are caused by the support structure of telescopes (refractors, SCTs). Typically 4 spikes at 45-degree intervals.

Parameters:
sizeint

Size of the stamp.

x0float

X center (star position).

y0float

Y center (star position).

star_fluxfloat

Flux of the source star (determines spike intensity).

n_spikesint, optional

Number of spikes (typically 4).

spike_lengthfloat, optional

Length of each spike in pixels.

spike_widthfloat, optional

Width of each spike in pixels.

Returns:
numpy.ndarray

2D array with diffraction spikes.

stdpipe.simulation.create_optical_ghost(size, x0, y0, source_flux, ghost_fraction=0.05, offset=(50, 50), blur_sigma=5.0)[source]

Create an optical ghost (reflection artifact).

Optical ghosts are faint, blurred copies of bright sources caused by reflections in the optical system.

Parameters:
sizeint

Minimum size of the stamp (will be expanded if needed to fit ghost).

x0float

X center of original source within stamp.

y0float

Y center of original source within stamp.

source_fluxfloat

Flux of the original source.

ghost_fractionfloat, optional

Fraction of source flux appearing in ghost (typically 0.01-0.1).

offsettuple, optional

(dx, dy) offset of ghost from source in pixels.

blur_sigmafloat, optional

Gaussian blur sigma for the ghost.

Returns:
dict

Dictionary with ‘stamp’ (2D array) and ‘source_pos’ (x, y) giving the source position within the stamp (needed to align stamp onto the image).

stdpipe.simulation.add_close_companions_to_catalog(catalog, fwhm, fraction=0.2, min_separation_fwhm=1.0, max_separation_fwhm=3.0, flux_variation=(0.5, 1.5), image_shape=None, edge=10)[source]

Add close companions to stars in a catalog (before image placement).

This function creates a new catalog with additional companion stars placed near existing stars to simulate crowded fields. Companions are only added to sources with type=’star’.

Parameters:
catalogastropy.table.Table

Input catalog with ‘x’, ‘y’, ‘flux’, ‘type’ columns.

fwhmfloat

FWHM of the PSF in pixels (used to calculate separations).

fractionfloat, optional

Fraction of stars (0-1) that will have companions.

min_separation_fwhmfloat, optional

Minimum separation in FWHM units.

max_separation_fwhmfloat, optional

Maximum separation in FWHM units.

flux_variationtuple, optional

(min, max) flux ratio for companion relative to primary.

image_shapetuple, optional

(height, width) tuple for bounds checking, or None to skip.

edgeint, optional

Minimum distance from edges when bounds checking.

Returns:
astropy.table.Table

New catalog with companions added (original catalog unchanged).

stdpipe.simulation.add_stars(image, n=100, flux_range=(100, 10000), fwhm=3.0, psf='gaussian', beta=2.5, edge=0, saturation=None, diffraction_spikes=False, spike_threshold=50000, optical_ghosts=False, ghost_threshold=100000, wcs=None)[source]

Add stars to an image with realistic PSF.

Parameters:
imagenumpy.ndarray

Target image (modified in-place).

nint, optional

Number of stars to add.

flux_rangetuple, optional

(min, max) flux range in ADU.

fwhmfloat, optional

FWHM of the PSF in pixels (used if psf is a string).

psfstr or dict, optional

PSF specification — either a string (‘gaussian’, ‘moffat’) or a PSF model dictionary (PSFEx format).

betafloat, optional

Moffat beta parameter (only used if psf=’moffat’).

edgeint, optional

Minimum distance from image edges.

saturationfloat, optional

Saturation level in ADU.

diffraction_spikesbool, optional

If True, add diffraction spikes to bright stars.

spike_thresholdfloat, optional

Flux threshold for adding diffraction spikes.

optical_ghostsbool, optional

If True, add optical ghosts to very bright stars.

ghost_thresholdfloat, optional

Flux threshold for adding optical ghosts.

wcsastropy.wcs.WCS, optional

WCS object for computing RA/Dec.

Returns:
astropy.table.Table

Catalog of added stars.

stdpipe.simulation.add_galaxies(image, n=20, flux_range=(500, 5000), r_eff_range=(3, 15), n_range=(0.5, 4.0), ellipticity_range=(0.0, 0.7), edge=0, wcs=None)[source]

Add galaxies with Sersic profiles to an image.

Parameters:
imagenumpy.ndarray

Target image (modified in-place).

nint, optional

Number of galaxies to add.

flux_rangetuple, optional

(min, max) total flux in ADU.

r_eff_rangetuple, optional

(min, max) effective radius in pixels.

n_rangetuple, optional

(min, max) Sersic index.

ellipticity_rangetuple, optional

(min, max) ellipticity.

edgeint, optional

Minimum distance from image edges.

wcsastropy.wcs.WCS, optional

WCS object for computing RA/Dec.

Returns:
astropy.table.Table

Catalog of added galaxies.

stdpipe.simulation.simulate_image(width, height, n_stars=100, star_flux_range=(100, 10000), star_fwhm=3.0, star_psf='gaussian', star_beta=2.5, n_galaxies=20, galaxy_flux_range=(500, 5000), galaxy_r_eff_range=(3, 15), galaxy_n_range=(0.5, 4.0), galaxy_ellipticity_range=(0.0, 0.7), n_cosmic_rays=5, cosmic_ray_length_range=(5, 50), cosmic_ray_width_range=(1, 3), cosmic_ray_intensity_range=(1000, 10000), cosmic_ray_profile='worm', n_hot_pixels=10, hot_pixel_intensity_range=(500, 5000), n_bad_columns=0, bad_column_type='dead', n_satellites=0, satellite_length_range=(100, 400), satellite_width_range=(2, 8), satellite_intensity_range=(5000, 20000), diffraction_spikes=False, spike_threshold=50000, optical_ghosts=False, ghost_threshold=100000, add_companions=False, companion_fraction=0.2, companion_separation_fwhm=(1.0, 3.0), companion_flux_ratio=(0.5, 1.5), background=1000.0, readnoise=10.0, gain=1.0, edge=10, wcs=None, return_catalog=True, return_masks=False, seed=None, verbose=False)[source]

Simulate a realistic astronomical image with stars, galaxies, and contaminants.

This is the high-level API that creates a complete simulated image in one call.

Parameters:
widthint, optional

Image width in pixels.

heightint, optional

Image height in pixels.

n_starsint, optional

Number of stars to add.

star_flux_rangetuple, optional

(min, max) star flux in ADU.

star_fwhmfloat, optional

FWHM of stellar PSF in pixels.

star_psfstr or dict, optional

PSF type — either a string (‘gaussian’, ‘moffat’) or a PSF model dict (from create_psf_model). Use dict to specify aberrated PSFs.

star_betafloat, optional

Moffat beta parameter (if star_psf=’moffat’).

n_galaxiesint, optional

Number of galaxies to add.

galaxy_flux_rangetuple, optional

(min, max) galaxy flux in ADU.

galaxy_r_eff_rangetuple, optional

(min, max) effective radius in pixels.

galaxy_n_rangetuple, optional

(min, max) Sersic index.

galaxy_ellipticity_rangetuple, optional

(min, max) ellipticity.

n_cosmic_raysint, optional

Number of cosmic ray tracks.

cosmic_ray_length_rangetuple, optional

(min, max) cosmic ray length in pixels.

cosmic_ray_width_rangetuple, optional

(min, max) cosmic ray width in pixels.

cosmic_ray_intensity_rangetuple, optional

(min, max) cosmic ray peak intensity.

cosmic_ray_profilestr, optional

Cosmic ray profile (‘sharp’, ‘tapered’, ‘worm’).

n_hot_pixelsint, optional

Number of hot pixels.

hot_pixel_intensity_rangetuple, optional

(min, max) hot pixel intensity.

n_bad_columnsint, optional

Number of bad columns.

bad_column_typestr, optional

Type of bad columns (‘dead’, ‘hot’, ‘noisy’).

n_satellitesint, optional

Number of satellite trails.

satellite_length_rangetuple, optional

(min, max) satellite trail length in pixels.

satellite_width_rangetuple, optional

(min, max) satellite trail width in pixels.

satellite_intensity_rangetuple, optional

(min, max) satellite trail intensity.

diffraction_spikesbool, optional

Add diffraction spikes to bright stars.

spike_thresholdfloat, optional

Flux threshold for diffraction spikes.

optical_ghostsbool, optional

Add optical ghosts to very bright stars.

ghost_thresholdfloat, optional

Flux threshold for optical ghosts.

add_companionsbool, optional

If True, add close stellar companions to simulate crowded fields.

companion_fractionfloat, optional

Fraction of stars (0-1) that will have companions.

companion_separation_fwhmtuple, optional

(min, max) companion separation in FWHM units.

companion_flux_ratiotuple, optional

(min, max) companion flux relative to primary star.

backgroundfloat, optional

Background level in ADU.

readnoisefloat, optional

Read noise in ADU.

gainfloat, optional

Detector gain in e-/ADU.

edgeint, optional

Minimum distance from image edges for sources.

wcsastropy.wcs.WCS, optional

WCS object for computing sky coordinates.

return_catalogbool, optional

If True, return catalog of all injected sources.

return_masksbool, optional

If True, return separate masks for each artifact type.

seedint, optional

Random seed for reproducibility. If set, calls np.random.seed(seed).

verbosebool, optional

Enable verbose output.

Returns:
dict

Dictionary with ‘image’, ‘catalog’ (if requested), ‘masks’ (if requested), ‘background’, ‘noise’.

stdpipe.simulation.generate_realbogus_training_data(n_images=100, image_size=(2048, 2048), n_stars_range=(50, 200), n_galaxies_range=(10, 50), fwhm_range=(1.5, 8.0), background_range=(100, 10000), n_cosmic_rays_range=(5, 20), n_hot_pixels_range=(5, 30), n_satellites_range=(0, 2), detection_threshold=3.0, match_radius=3.0, cutout_radius=15, augment=True, real_source_types=['star'], close_pair_fraction=0.2, min_separation_fwhm=1.0, max_separation_fwhm=3.0, aberration_fraction=0.0, defocus_range=(0.0, 2.0), astigmatism_range=(0.0, 1.5), coma_range=(0.0, 1.0), readnoise_range=(5.0, 20.0), gain_range=(0.5, 2.0), asinh_softening=None, seed=None, verbose=False)[source]

Generate labeled training data for real-bogus classifier.

This function creates a dataset of labeled cutouts by: 1. Simulating images with known source positions 2. Running object detection 3. Matching detections to truth catalog 4. Labeling matched detections as ‘real’, others as ‘bogus’ 5. Extracting and preprocessing cutouts 6. Optionally applying data augmentation

Flux ranges are automatically calculated for each image based on the background noise level to ensure sources are detectable: - Minimum flux = detection_threshold × noise (e.g., 3σ for detectability) - Maximum flux = 1000 × noise (bright sources) This prevents generating sources that are too faint to detect or unrealistically bright.

Close pairs are automatically added to ensure the classifier learns to accept crowded sources. A fraction of stars will have stellar companions added at controlled separations (e.g., 1-3 FWHM). Companions are only added to stars, not galaxies.

PSF diversity can be included in training data by setting aberration_fraction > 0. A fraction of images will use aberrated PSFs with randomized Zernike coefficients (defocus, astigmatism, coma) computed via Fourier optics, helping the classifier handle realistic PSF variations from optical aberrations.

Parameters:
n_imagesint, optional

Number of simulated images to generate.

image_sizetuple, optional

(width, height) of simulated images.

n_stars_rangetuple, optional

(min, max) number of stars per image.

n_galaxies_rangetuple, optional

(min, max) number of galaxies per image.

fwhm_rangetuple, optional

(min, max) FWHM in pixels (varied per image).

background_rangetuple, optional

(min, max) background level in ADU.

n_cosmic_rays_rangetuple, optional

(min, max) cosmic rays per image.

n_hot_pixels_rangetuple, optional

(min, max) hot pixels per image.

n_satellites_rangetuple, optional

(min, max) satellite trails per image.

detection_thresholdfloat, optional

Detection threshold in sigma (also used for min flux calculation).

match_radiusfloat, optional

Matching radius in pixels for truth matching.

cutout_radiusint, optional

Cutout radius in pixels.

augmentbool, optional

Apply data augmentation (rotations, flips).

real_source_typeslist, optional

List of source types to consider ‘real’. Default: [‘star’] treats only stars as real and galaxies as bogus. Use [‘star’, ‘galaxy’] to treat both as real.

close_pair_fractionfloat, optional

Fraction of sources (0-1) that will have close companions added. Default: 0.2 (20% of sources get companions).

min_separation_fwhmfloat, optional

Minimum separation for companions in FWHM units. Default: 1.0 (1x FWHM).

max_separation_fwhmfloat, optional

Maximum separation for companions in FWHM units. Default: 3.0 (3x FWHM).

aberration_fractionfloat, optional

Fraction of images (0-1) with aberrated PSFs. Default: 0.0 (all Gaussian). When > 0 and aberration ranges have non-zero max values, uses Fourier optics with Zernike polynomials. Otherwise falls back to Moffat PSFs as a simpler proxy.

defocus_rangetuple, optional

(min, max) defocus aberration in waves (default: (0.0, 2.0)).

astigmatism_rangetuple, optional

(min, max) astigmatism aberration in waves (default: (0.0, 1.5)).

coma_rangetuple, optional

(min, max) coma aberration in waves (default: (0.0, 1.0)).

readnoise_rangetuple, optional

(min, max) read noise in ADU (randomized per image).

gain_rangetuple, optional

(min, max) detector gain in e-/ADU (randomized per image).

asinh_softeningfloat, optional

Asinh softening in units of background sigma for realbogus preprocessing. If None, uses DEFAULT_ASINH_SOFTENING_SIGMA.

seedint, optional

Random seed for reproducibility. If set, calls np.random.seed(seed).

verbosebool, optional

Print progress.

Returns:
dict

Dictionary with ‘X’ (cutouts), ‘y’ (labels), ‘fwhm’ (FWHM values), ‘metadata’.