Configuration reference
Pipelines are described in YAML and validated by pydantic v2. The top-level shape is:
pupil:
resolution: <int>
extent: <float>
aperture: { type: <name>, ... }
correctors:
<name>:
type: <name>
wavefront_role: actuate | impose | fit
target_strategy: none | actuators | actuators_plus_residual_fit | residual_fit_only
fit_source: <corrector_name> | <wavefront_name> | null
target: <bool>
# ... type-specific kwargs
corrector_chain: [<name>, <name>, ...]
coronagraph: { type: <name>, ... } # optional
focal_planes:
<name>: { type: <name>, ... }
outputs:
<name>:
tap: { type: <name>, ... }
post_processing:
- <name> # bare string = no-arg post-processor
- { type: <name>, ... } # mapping form for parameterized ones
strehl_method: peak | matched_filter | null
strehl_core_rad: <float | null>
Strehl
strehl_methodSelects the Strehl estimator.
"peak"reads the current PSF at the reference PSF’s argmax — so a tip-tilt that moves the peak off-center correctly drops Strehl below 1."matched_filter"is a normalized matched-filter projection over a circular core mask of radiusstrehl_core_radcentered on the focal-grid origin; pixels are weighted by the reference intensity. If unset, defaults to"matched_filter"whenstrehl_core_radis given (legacy behavior), else"peak".strehl_core_radRequired when
strehl_method == "matched_filter"; ignored for"peak".
Per-sample state
sample() accepts a few non-actuator inputs per call:
actuations— per-corrector actuator state, keyed by corrector name.atmos— external atmosphere (any wf→wf callable), see Architecture & concepts for the contract.output_overrides— per-output, per-tap-config overrides. Shape{output_name: {key: value, ...}}. The pipeline puts the inner mapping on each post-processor’sPipelineContextascontext.overrides; processors that consume per-sample state (e.g.noisy_detectorreadsint_phot_flux,convolve_imagereadsconvolve_image) check the override and fall back to their YAML default. Processors with no per-sample state ignore the field.meas_strehl— if true, returnout["strehls"].meas_pupil_opd— if true, returnout["pupil_opd"]as anhcipy.Fieldof cumulative pupil-plane OPD in meters (atmosphere seed whenphase_foris available, plus every DM-backed corrector’s surface × 2). Pair withsim.aperture.fieldfor masked display viahcipy.imshow_field(out["pupil_opd"], mask=sim.aperture.field); the bundledtelescope_sim.helpers.diagnostics.plot_opd_and_psfs()uses this contract.
Stages
Apertures
segmented_circularFields:
segment_diameter,layout("elf"or"custom"),n_segments,ring_radius,positions,supersample,spider(optional{width, angle}).external_pupilFields:
module(dotted name or path to a.pyfile),function,mode("field"or"callable"),kwargs,area,supersample(only whenmode == "callable").
Correctors
segmented_pttFields:
piston_scale,tip_tilt_scale. Actuator shape(n_segments, 3).zernikeFields:
n_modes,zernike_diameter,starting_mode,actuate_scale.actuator_gridFields:
num_actuators(per side),actuator_pitch(pupil-plane projected),influence(gaussian|xinetics),crosstalk(gaussian only),rotation_deg,flip_x,flip_y,actuate_scale. Actuator shape: flat(N²,)or shaped(N, N)(axis 0 = y ascending, axis 1 = x ascending). Positiverotation_degrotates the DM counterclockwise relative to the pupil; flips mirror the command indexing before the rotation is applied (flip-then-rotate).
Coronagraphs
identityPassthrough (no-op).
vortex/vector_vortexFields:
charge,lyot(an aperture sub-config; built into a transmission field).
Focal planes
angularFields:
central_lam,focal_extent(arcsec),focal_res,fractional_bandwidth,num_samples.physicalFields: same as
angularplusfocal_length(meters),focal_extentin meters, optionalwavefront_total_power.
Output taps
intensityStack PSF intensities from one or more focal planes channels-last. Fields:
focal_planes(list of names).fiber_dualStack focal intensity + multi-mode-fiber-coupled intensity along axis 0. Fields:
focal_plane_name,fiber({type: step_index, core_radius, NA, fiber_length, max_in_cache}).
Post-processors
max_intensity_normDivide each channel by the reference PSF peak.
max_image_normDivide each channel by its own peak.
per_sample_normMin-max normalize each channel to [0, 1].
channels_firstTranspose
(H, W, C) → (C, H, W).noisy_detectorApply
hcipy.NoisyDetector(read noise, dark current, flat-field, photon shot noise) to a single-channel intensity image.Fields:
int_phot_flux(float | null) — photon flux in photons/m². When set, rescales the input image so total accumulated charge =int_phot_flux * aperture_area(legacy_addNoiseToObservationcontract).Noneintegrates at the natural input scale (useful when an upstreamconvolve_imagehas imposed absolute brightness).detector(mapping) — forwarded tohcipy.NoisyDetector:read_noise,dark_current_rate,flat_field,include_photon_noise,subsampling.clamp_nonnegative(bool, defaultTrue) — applynp.absto read-out (legacy workaround for Gaussian read noise pulling pixels negative). Disable for science-faithful analyses.
Single-focal-plane only: the processor needs one focal grid. For multi-filter noisy outputs, declare one output (with its own
noisy_detector) per filter.Per-sample override:
output_overrides={"<output_name>": {"int_phot_flux": <flux>}}.convolve_imageConvolve the focal-plane PSF (as a kernel, normalized by the at-rest reference PSF sum) with a caller-supplied scene. Equivalent to legacy
fftconvolve(scene, psf / reference_psf_sum, mode='same').Fields:
image(array-like | null) — default 2D scene to convolve with.Nonemeans no default; the caller must supplyconvolve_imageviaoutput_overridesper sample.
Single-focal-plane only (kernel normalization needs a single
reference_psf_sum). For multi-filter convolution, split into one output (with its ownconvolve_image) per filter.Per-sample override:
output_overrides={"<output_name>": {"convolve_image": <2D array>}}.Composes cleanly with
noisy_detectorfor extended-source noisy imaging — the recommended order isintensity → convolve_image → noisy_detector.
Examples
See fixtures/configs/ in the repo for working configs that reproduce
each of the legacy fixtures.