This file is a navigation guide for the nullsim package. It points to the
load-bearing modules, the data flow between them, and the tests that pin each
area.
nullsim is a Python package and CLI for simulating photonic nulling
instruments from a single TOML config. The package is organized around an
ordered pipeline:
TOML config
-> config load / preset merge / sweep expansion
-> ordered stage validation and execution
-> typed SimulationState budgets
-> registered plots and tables
-> results/<run>/<YYYYMMDD-HHMMSS>/
The public command surface is:
nullsim run <config>: execute a config, expand sweeps, write outputs.nullsim run --dry-run <config>: validate the expanded run plan, output names, and dependency graph without creating outputs.nullsim validate <config>: schema, output registry, sweep, and stage dependency check, no execution.nullsim inspect <config>: non-executing run plan with hashes, output dir, stage consumes/produces, and physics/trust notes.nullsim list-stages [--family ...]: inspect registered stage types.nullsim list-outputs [--kind ...]: inspect registered plot/table outputs.python -m nullsim: same CLI entry point.
nullsim/
__init__.py import side effects: stage and output autoload
__main__.py python -m nullsim entry point
cli.py argparse CLI, sweep execution, manifests, outputs
config/ TOML schema, loader, hashing, sweep expansion
pipeline/ stage protocol, registry, state, runner, cache
stages/ built-in stage implementations
physics/ pure math / scientific primitives
outputs/ registered plot and table writers
catalogs/ versioned external catalog loaders
data/ packaged reference data and catalog snapshots
examples/ canonical user-facing TOML configs
tests/ unit, stage, output, and example tests
scripts/ maintenance, reference-generation, benchmarks
changelog.d/ fragment changelog entries
README.md user quick start and CLI overview
nullsim.md design document and roadmap
CONTRIBUTING.md development workflow
pyproject.toml package metadata, deps, pytest/ruff config
-
nullsim/__init__.py- Sets
__version__. - Imports
nullsim.stages._autoloadso stage registration decorators run. - Imports
nullsim.outputsforRunCollection/RunRecorddataclasses. Plot/table registration is deferred:nullsim.outputs._autoload_outputs()is called by output-writing/listing paths and by validation/inspection only when requested output names need to be checked.
- Sets
-
nullsim/cli.py- Builds the
run,validate,inspect,list-stages, andlist-outputssubcommands. - Loads configs through
config.load_config. - Expands sweep cells with
config.expand_sweeps. - Validates requested plot/table names before expensive stage execution.
run --dry-runandinspectprint a non-executing plan with run hashes, output location, stage consumes/produces, and trust notes.- Runs each cell through
pipeline.run. - Uses a spawn-based
ProcessPoolExecutorfor parallel sweep cells. - Writes
config.toml,config.resolved.toml,manifest.json,sweep_results.*, registered outputs, and the opt-in paper bundle when[output].paper = true.
- Builds the
-
nullsim/config/loader.py- Parses TOML with
tomllib. - Merges supported presets from
config/presets/. - Materializes top-level config fields into stage params through
stage_materialize.py. - Validates with Pydantic models from
schema.py. - Computes
config_hash, initialrun_hash, and a timestamp.
- Parses TOML with
-
nullsim/config/sweeps.py- Expands
[[sweep]]axes into independentSweepCellobjects. - Supports explicit
values, numericrange,linspace,logspace. - Supports grid axes and zip axes.
- Re-materializes stage params after each sweep coordinate is applied.
- Expands
-
nullsim/pipeline/runner.py- Builds stage instances from
pipeline.stagesin the declared TOML order. - Validates that every stage's required
consumeskeys were produced by an earlier stage. - Runs stages in order. There is no topological reordering.
- Wraps each stage in content-addressed cache lookup/store.
- Returns
RunResult(state, diagnostics, timings, cache_hit_count, config_hash).
- Builds stage instances from
-
nullsim/outputs/- Receives a
RunCollectionof one or moreRunRecords. - Writes selected plots/tables by looking up names in the shared registry.
- Receives a
Key files:
-
nullsim/config/schema.py- Pydantic models for the TOML surface.
- Top-level sections:
run,grid,site,telescope,scene,observation,instrument,pipeline,sweep,output,cache,catalog. [instrument]is the shared port-topology section. It validatesn_modes = n_bright_ports + n_dark_ports + n_spectro_portswhen all are set and carriesn_input_modesfor physical guided-mode counts before any duplicated-input chip fanout.StageSpecallows extra keys because each stage owns its own parameter model.PipelineConfigrejects duplicate stage IDs.
-
nullsim/config/loader.py- Public
load_config(path)entry point. - Applies presets and stage materialization before producing
ResolvedConfig.
- Public
-
nullsim/config/stage_materialize.py- Bridges user-facing sections into stage params.
- Stages pull shared physical defaults from top-level sections:
scene.point_sourcefrom[scene.*], telescope / atmosphere / AO / injection / background / fringe-tracking stages from merged[site]and[telescope]presets, and port-bearing stages from[instrument]. Instrument values materialize into chip, chip-optimization, detector, sensitivity, characterization,injection.ideal, andfringe_tracking.closed_loopparams while preserving explicit stage-level overrides.
-
nullsim/config/sweeps.py- Turns one
ResolvedConfiginto executable sweep cells. - Sweep params can target
scene.*,observation.*, orpipeline.stages.<id>.<field>.
- Turns one
-
nullsim/config/hashes.py- Deterministic TOML serialization.
- Computes
config_hashfrom resolved config text. - Computes
run_hashfrom config identity, package/runtime identity, dependency versions, and external dependency hashes.
-
nullsim/config/catalog.py- Validates the
[catalog.exoplanets]TOML block and resolves relative snapshot paths.
- Validates the
-
nullsim/config/factories.py- Band-sweep dict helpers for cross-band study configs. (Site sky
brightness tables live in
stages/background/sky_surface_brightness.py, not here.)
- Band-sweep dict helpers for cross-band study configs. (Site sky
brightness tables live in
Tests:
tests/config/test_loader.pytests/config/test_sweeps.pytests/config/test_hashes.py
Key files:
-
nullsim/pipeline/stage.py- Defines the
Stageprotocol,BaseStage,ExternalDependency, andconsumed_state_keys(). - Stage classes declare
type_name,family,consumes,produces, and optionalcache_key_extras. - If a stage defines an inner
ParamsPydantic model,BaseStagevalidates params once at construction time.
- Defines the
-
nullsim/pipeline/state.py- Defines the immutable
SimulationState. - Defines the eight state budgets:
scene,geometry,field,opd_budget,throughput,wavefront,photon_rates,results. - Each sub-budget supports named
componentsand deterministic content hashing.
- Defines the immutable
-
nullsim/pipeline/registry.py- Shared singleton registry for stages, plots, and tables.
@register_stage,@register_plot, and@register_tableare the extension mechanism used by built-ins.- Validates stage-specific params via
stage_cls.Paramswhen present.
-
nullsim/pipeline/runner.py- Instantiates stages with deterministic per-instance RNG contexts.
- Validates dotted-path
consumes/producescontracts. - Executes the declared stage order.
- Tracks timings, diagnostics, and cache hit count.
-
nullsim/pipeline/cache.py- Content-addressed stage cache.
- Cache keys fold in validated stage params, consumed state digest, a per-stage-family source digest (shared core + the stage family's import closure; output and CLI code excluded), class and instance identity, RNG identity, package version, external dependencies, and cache version.
- Cache entries are pickle files under
.nullsim_cacheby default.
-
nullsim/pipeline/rng.py- Deterministic RNG derivation from root seed, the stage's own spec digest, sweep coordinate, and stage instance ID. Stage-local by design: config edits that do not touch a stage's spec cannot change its draws (review 2026-06-10 Issue 7).
-
nullsim/pipeline/manifest.py- Writes
manifest.jsonwith config/run hashes, dependency versions, host info, RNG seed, timings, cache stats, and external dependencies.
- Writes
Tests:
tests/pipeline/test_cache.pytests/pipeline/test_registry.pytests/pipeline/test_rng.pytests/pipeline/test_runner_validation.pytests/pipeline/test_state.py
Built-ins are imported by nullsim/stages/_autoload.py. Stage type names are
the strings used in TOML under [[pipeline.stages]].
| Type | File | Consumes | Produces | Purpose |
|---|---|---|---|---|
scene.point_source |
stages/scene/point_source.py |
none | scene |
Populate source properties and pointing. |
telescope.fixed_aperture |
stages/telescope/fixed_aperture.py |
scene |
geometry, throughput |
Aperture area, ENU positions, baselines, telescope throughput. |
telescope.pupil_modes |
stages/telescope/pupil_modes.py |
geometry |
geometry |
Place photonic input modes across a single circular pupil; geometry bridge for single-primary configs (HWO) that skip AO but need per-mode positions for planet throughput. |
atmosphere.kolmogorov |
stages/atmosphere/kolmogorov_screens.py |
geometry |
opd_budget, wavefront, throughput |
Seeing, atmospheric transmission, OPD/wavefront budgets. |
ao.pyramid_wfs |
stages/ao/pyramid_wfs.py |
geometry, opd_budget, wavefront, scene |
opd_budget, wavefront, geometry |
KILO-style pyramid WFS residuals and sub-aperture geometry. |
wavefront.space_residual |
stages/wavefront/space_residual.py |
none | wavefront, opd_budget |
Scalar space-telescope WFE/Strehl, amplitude-jitter, and pointing-jitter residual budget. |
injection.ideal |
stages/injection/ideal.py |
scene, geometry |
field, throughput, wavefront |
Seed ideal field amplitudes, optionally using upstream Strehl. |
injection.mode_splitter |
stages/injection/mode_splitter.py |
field, geometry |
field, geometry |
Area-normalized guided-mode fanout for duplicated-input Clements mesh architecture studies; preserves physical pupil positions while expanding the chip input mode count. |
injection.single_mode_fiber |
stages/injection/single_mode_fiber.py |
field, throughput, wavefront, geometry |
field, throughput |
Ruilier-Cassaing SMF coupling. |
delay_lines.geometric |
stages/delay_lines/geometric.py |
geometry, throughput, scene, field |
throughput, field |
Geometric delay-line path equalization loss, with opt-in fiber-medium chromatic phase diagnostics. |
transport.smf28 |
stages/transport/smf28.py |
field, throughput, opd_budget |
field, throughput, opd_budget |
SMF-28 loss, phase, and dispersion. |
transport.pm980 |
stages/transport/smf28.py |
field, throughput, opd_budget |
field, throughput, opd_budget |
PM980-XP polarization-maintaining fiber; subclass of SMF28Transport with PM980-XP attenuation defaults. |
transport.pm780 |
stages/transport/smf28.py |
field, throughput, opd_budget |
field, throughput, opd_budget |
PM780-HP polarization-maintaining fiber for ~800 nm bands; subclass of SMF28Transport with PM780-HP attenuation defaults. |
transport.photometric_pickoff |
stages/transport/photometric_pickoff.py |
field, throughput |
field, throughput |
Fixed scalar photometric tap before the science mesh: routes tap_fraction of each guided mode to a photometric monitor for amplitude sensing and scales the surviving field/throughput. |
background.nayra_sky |
stages/background/nayra_sky.py |
geometry, throughput, field |
results |
Per-port sky-background photon rates for single-pupil ELT (NAYRA) pipelines. |
background.sky_surface_brightness |
stages/background/sky_surface_brightness.py |
geometry, throughput, field |
results |
Generic sky surface brightness background; uses site sky spectrum from config factories. |
background.space_zodi |
stages/background/space_zodi.py |
geometry, throughput, field, scene, results |
results |
Space local-zodiacal and exozodiacal background rates per physical dark/spectro port. |
polarization.hwp |
stages/polarization/optics.py |
field, throughput |
field, throughput |
Half-wave plate Jones rotation applied per-port. |
polarization.pbs_split |
stages/polarization/optics.py |
field, throughput |
field, throughput |
Polarizing beam splitter: splits into two orthogonal linear polarization arms. |
polarization.pm_fiber |
stages/polarization/optics.py |
field, throughput |
field, throughput, results |
PM fiber Jones propagation with birefringence and leakage; records polarization diagnostics. |
instrument.nayra_six_chip |
stages/instrument/nayra_six_chip.py |
none | results |
Records NAYRA Y/J/H × dual-pol six-chip channel manifest into results. |
chip.identity |
stages/chip/identity.py |
field, throughput |
field, throughput |
Pass-through chip for smoke tests. |
chip.kernel_mzi_mesh |
stages/chip/kernel_mzi_mesh.py |
field, throughput (+ results when optimization_source is set) |
field, throughput, results |
Kernel-nulling Clements MZI mesh; supports deployment_mode="per_pol_arm" for NAYRA dual-PBS-arm front end (independent chip per arm with diagonal phase correction). |
chip.quadrature_reference_mesh |
stages/chip/quadrature_reference_mesh.py |
field, throughput |
field, throughput, results |
Ideal 2N-output quadrature-reference architecture test: N tracker rows plus N science rows, published as a rectangular effective chip.kernel_mzi_mesh stack for downstream diagnostics. |
chip_optimization.scipy |
stages/chip_optimization/scipy.py |
field, throughput, geometry (+ scene when disk samples enabled) |
results |
Scipy broadband chip optimization; supports disk_n_rings/disk_n_azimuths/disk_weight for finite stellar-disk null constraints. |
chip_optimization.torch |
stages/chip_optimization/torch.py |
field, throughput, geometry (+ scene when disk samples enabled) |
results |
Torch/autograd chip optimization backend; batches wavelength solves across the MZI mesh for speed; supports finite-disk rows, bright-port piston tracker regularization through singular-value floor/count-free CRLB/tracker-rank-priority restart selection, passive amplitude-mismatch suppression, selected-port amplitude-observability regularization, and a joint phase+amplitude Fisher proxy for mixed piston/scintillation estimability. |
chip_optimization.ideal_kernel |
stages/chip_optimization/ideal_kernel.py |
field, throughput, geometry |
results |
Ideal achromatic kernel-null projector; builds the Guyon et al. (2013) PCA/SVD stellar-mode upper bound and publishes the chip unitary without iterative optimization. Warm-start source for physical Clements refinements. |
detector.ideal_counter |
stages/detector/ideal_counter.py |
field, throughput, scene, geometry |
photon_rates, results |
Simple ideal detector for vertical slice. |
detector.mkid |
stages/detector/mkid.py |
field, throughput, scene, geometry |
photon_rates, results, throughput |
MKID QE, saturation, count rates, and opt-in finite energy-resolution redistribution. |
detector.snspd |
stages/detector/snspd.py |
field, throughput, scene, geometry |
photon_rates, results, throughput |
SNSPD QE, saturation, dark counts; folds detector QE into throughput budget. |
fringe_tracking.closed_loop |
stages/fringe_tracking/closed_loop.py |
photon_rates, opd_budget, wavefront, geometry |
opd_budget, results |
Closed-loop piston residuals with classical or control_model="photon_kalman" operation. The stage supersedes replaced AO piston components, separates detector sample rate f_sample_hz from equivalent closed-loop f_3db_hz, can add inter-telescope von Karman piston and vibration disturbances, and publishes IID/common residual splits for realized-null covariance propagation. |
calibration.floor_lookup |
stages/calibration/floor_lookup.py |
results, scene |
results |
Calibration systematic floor lookup/subtraction. |
sensitivity.detection_curve |
stages/sensitivity/detection_curve.py |
results, geometry, wavefront, scene, field, throughput |
results |
Planet throughput curve, finite stellar-disk floor, realized null, optional closed-loop/open-loop scintillation injection, setpoint-trim and dither leakage, and optional fringe-observability piston covariance propagation through either scalar predictive gain or the temporal-Kalman model. opd_budget is a cache-key extra for optional OPD-budget piston reads, not a dependency-validation consume. Publishes effective_null_by_separation, leakage_rate_hz_effective, leakage_rate_hz_static_chip, and effective_to_static_leakage_ratio; raises if the separation grid does not cover the configured stellar radius. |
performance.standard |
stages/performance/standard.py |
results, scene |
results |
SNR, integration time, and contrast curve. Recomputes leakage from the sensitivity-published effective null (the published leakage-rate keys are debug-report inputs), reads the FT-published servo_bandwidth_hz equivalent to f_3db_hz, keeps opd_budget as a cache-key extra for the legacy residual audit, and applies nsc_systematic_reduction only to the null-instability systematic term, not mean-leakage photon noise. |
performance.pdi |
stages/performance/pdi.py |
results |
results |
Polarimetric differential imaging SNR. |
characterization.spectro |
stages/characterization/spectro.py |
results, geometry, scene, throughput, field |
results |
Known-position spectro-port retuning and SNR; supports AWG or MKID-native spectrograph accounting plus optional bright-port piston-observability regularization for characterization units that must also fringe-track. Params include compile_objective (also honored via NULLSIM_TORCH_COMPILE; forces serial restarts when on), residual_speckle_stability_factor, nsc_systematic_reduction, and null_floor. The stage emits eps_systematic, nsc_systematic_reduction, and null_floor; the old hand-tuned calibration-epsilon knob is gone. |
characterization.detection_curve |
stages/characterization/detection_curve.py |
results, geometry, scene, throughput, field |
results |
Characterization-mode contrast curve anchors using the same optional bright-port piston-observability regularization as characterization.spectro. Shares compile_objective, residual_speckle_stability_factor, nsc_systematic_reduction, and null_floor Params, and emits null_floor, eps_systematic, and nsc_systematic_reduction; the old hand-tuned calibration-epsilon knob is gone. |
diagnostics.fringe_observability |
stages/diagnostics/fringe_observability.py |
field, photon_rates, results, geometry |
results |
Fringe-tracker piston and amplitude observability audit: bright-port piston intensity response, selectable bright/bright+dark/all-port amplitude response, SVD/Fisher observability spectrum, differential fractional-intensity CRLB, scintillation-assumption and amplitude post-processing checks, spectral-diversity sweep, linear/Gauss-Newton residuals, active coordinate-scan acquisition, and dedicated cophasing-unitary handoff Monte Carlo diagnostics. |
Stage-family tests live under tests/stages/, with additional integration
coverage in tests/examples/.
nullsim/physics/ should remain independent of TOML, SimulationState, and
stage execution except where explicitly documented.
| File | Responsibility |
|---|---|
kolmogorov.py |
Kolmogorov turbulence constants, r0 scaling, phase variance, and effective_wind_speed_m_s from Greenwood/Fried tau0 = 0.314 r0 / v_eff. |
ruilier_cassaing.py |
Single-mode fiber coupling and angular coupling factors. |
clements.py |
Clements unitary decomposition and reconstruction. |
jones.py |
Jones matrices, waveplates, Stokes conversions; PM fiber birefringence and leakage (jones_pm_fiber, pm_fiber_leakage_power); polarizing beam splitter arm matrices (polarizing_beam_splitter_arm); DualPolField container. |
photometry.py |
Vega zero points and photon-rate conversions. |
pupil_geometry.py |
Keck/KILO/E-ELT sub-aperture packing and pupil constraints; keck_pupil(), eelt_pupil(), concentric-ring and wedge-hex seed strategies. |
fresnel.py |
Angular-spectrum scalar propagation. |
uv_coverage.py |
Baseline enumeration, ENU-to-UV projection, and project_positions_to_sky_plane_m for off-zenith aperture-coordinate projection before sky-angle phase rows. |
stellar_disk.py |
Uniform-disk null-floor integration: area-weighted incoherent intensity integral over a finite stellar disk. |
planet_throughput.py |
Off-axis coherent input fields, chip throughput vs separation, and 2-D summed dark-port transmission maps. |
realized_null.py |
Monte Carlo AO-realized null-depth statistics, including piston_covariance_with_common_mode_m2 for an IID per-mode piston term plus a rank-1 inter-telescope common differential mode. |
quadrature_fringe_tracker.py |
Ideal duplicated-input quadrature-reference mesh primitives and analytic observability/CRLB estimates. |
scintillation.py |
Scintillation and amplitude-servo residual model. |
fringe_tracking.py |
Piston-servo bandwidth primitives; disturbance terms von_karman_differential_piston_rms_m, piston_psd_knee_hz, servo_residual_variance_flat_knee, and vibration_residual_rms_nm; accelerometer-fusion and structure-function helpers; photon_kalman_residual_budget / PhotonKalmanResidual for the frame-free photon-counting control model; and the AR(1) temporal-Kalman covariance surrogate used to turn bright-port CRLB measurements into mode-dependent residual piston covariance. |
systematic_bandwidth.py |
Effective bandwidth for null-instability noise. |
spectroscopy.py |
Characterization spectro-port SNR and max resolving power; AWG spectrograph model (AWGSpectrum, awg_spectrum, awg_wavelength_grid, per_bin_snr). |
mkid.py |
MKID constant-delta-E resolving power and true-to-measured energy-response matrix primitives. |
pdi.py |
Polarimetric differential imaging SNR primitives. |
characterization.py |
Known-position chip optimization for spectro mode. |
characterization_torch.py |
Torch autograd-Jacobian helper for characterization optimization. |
imaging.py |
Aperture-synthesis image reconstruction: dark-port beam patterns, simulated photon-count observations, matched-filter SNR maps, and wavelength-resolved NNLS reconstruction. |
fringe_observability.py |
Fringe-tracker piston and amplitude observability primitives: intensity response matrices at zero and nonzero piston, selectable-port fractional-intensity response matrices for scintillation sensing, SVD-based observability rank and singular values, CRLB estimates, linear Monte Carlo piston-estimation RMSE, amplitude post-processing Monte Carlo comparisons against ideal photometric taps, damped Gauss-Newton reconstruction/capture-range diagnostics, active acquisition scans, and pairwise ABCD cophasing-handoff simulations. |
reflected_light.py |
Reflected-light planet/star contrast: Lambertian phase function and reflected_light_contrast (geometric albedo × phase × (R_p/a)²). |
ideal_coronagraph.py |
Guyon et al. (2006) theoretically optimal coronagraph bound: order-2/4 removed-stellar-subspace planet throughput, uniform-disk leakage, and the photon-limited 5σ contrast curve drawn by the opt-in detection_space overlay ([output.detection_space].ideal_coronagraph_orders). |
Tests:
tests/physics/test_*.pytests/physics/notes/*.mdfor derivation notes and pinning rationale.
The output layer is registry-driven. Configs name plots/tables in [output],
and the CLI resolves names against the shared registry.
Core containers:
-
nullsim/outputs/__init__.pyRunRecord: one sweep cell or single run.RunCollection: all records plus output directory.
-
nullsim/outputs/sweep_results.py- Writes long-format
sweep_results.parquet. - Includes scalar results, photon-rate spectra, contrast curves, sensitivity scalars, and characterization scalars.
- Writes long-format
-
nullsim/outputs/paper.py- Opt-in
[output].paper = truebundle writer. - Creates a
paper/directory besideplots/andtables/. - Reuses registered plot/table writers for KILO-paper-equivalent artifacts
and adds paper-only products: schematic PDFs (
signal_chain.pdf,array_layout.pdf,baseline_histogram.pdf,cophasing_scheme.pdf,dirty_beams.pdf, plus dual-pol layout and signal-chain variants) and LaTeX result tables (exoplanet_table.tex,characterization_table.tex,pdi_exoplanet_table.tex). The full emitted set, including intentionally out-of-scope products, is recorded inpaper_manifest.json.
- Opt-in
Registered plots:
| Name | File | Purpose |
|---|---|---|
contrast_curve |
outputs/plots/__init__.py |
Basic contrast curve plot. |
detection_space |
outputs/plots/detection_space.py |
Exoplanet population overlay with contrast curves. |
subaperture_layout |
outputs/plots/subaperture_layout.py |
Pupil/sub-aperture layout panels. |
uv_coverage_grid |
outputs/plots/uv_coverage_grid.py |
KILO-style UV coverage grid. |
chip_diagnostics |
outputs/plots/chip_diagnostics.py |
Detection-chip power, matrix, DAC, and spectrum diagnostics. |
chip_diagnostics_characterization |
outputs/plots/chip_diagnostics.py |
Characterization retune power, matrix, DAC, and spectro-port broadband-null diagnostics. |
cophasing_unitary |
outputs/plots/cophasing_unitary.py |
Dedicated cophasing-mode ABCD analysis matrix, pair graph, OPD-incidence, and handoff summary diagnostics. |
loss_budget |
outputs/plots/loss_budget.py |
Throughput/loss breakdown. |
contrast_curves_multiband |
outputs/plots/contrast_curves_multiband.py |
Multi-band/multi-time contrast curves. |
calibration_time |
outputs/plots/calibration_time.py |
Optimizer convergence / calibration-time style plot. |
debug_report |
outputs/plots/debug_report.py |
Multi-page pipeline audit report. |
imaging_reconstruction |
outputs/plots/imaging_reconstruction.py |
Truth/SNR/beam imaging artifacts for HWO-class space nuller image reconstruction. |
null_transmission_map |
outputs/plots/null_transmission_map.py |
Optional design-wavelength and band-averaged summed dark-port transmission map over sky coordinates; shares chip-field retrieval via outputs/plots/_chip_field_inputs.py. |
fringe_observability |
outputs/plots/fringe_observability.py |
Fringe-tracker piston/amplitude observability diagnostic panels: singular-value spectrum, amplitude rank/CRLB summary, scintillation and amplitude-post-processing summary, spectral-diversity rank/CRLB sweep, weakest-mode shape, science-unitary reconstruction residuals, active/cophasing acquisition and handoff residuals, capture sweep, and compact health summary. |
Registered tables:
| Name | File | Purpose |
|---|---|---|
performance_summary |
outputs/tables/__init__.py |
One row per run with headline scalar metrics. |
characterization_summary |
outputs/tables/__init__.py |
One row per characterization.spectro result component. |
Tests:
tests/outputs/test_outputs.pytests/outputs/test_end_to_end.pytests/outputs/test_paper.pytests/outputs/plots/test_*.py
Key files:
-
nullsim/catalogs/exoplanets.py- Validates NASA Exoplanet Archive-style CSV snapshots.
- Computes or verifies snapshot hashes.
- Classifies planets with versioned rules.
- Derives separation in mas from semi-major axis and distance when needed.
-
nullsim/data/exoplanet_catalogs/nasa_exoplanet_archive_paperv3.csv- Packaged exoplanet snapshot used by detection-space outputs.
-
nullsim/data/kilo_reference/*.json- KILO reference data used for optional plot overlays and calibration floors.
-
nullsim/data/nayra_reference/*.json- NAYRA E-ELT reference data;
calibration_time_J_M18.json(N=18 sub-aperture baseline) andcalibration_time_J_M36.json(N=36 sub-aperture baseline).
- NAYRA E-ELT reference data;
Tests:
tests/catalogs/test_exoplanets.pytests/catalogs/fixtures/sample_catalog.csv
Reference/instrument configs in the root of examples/:
examples/kilo_keck.toml- KILO Keck-only paper-baseline pipeline; enables
[output].paper = trueso runs also produce the paper artifact bundle.
- KILO Keck-only paper-baseline pipeline; enables
examples/kilo_keck_6.toml- Default KILO Keck config: reduced 6-subaperture-per-pupil quadrature mesh
(24 Clements inputs -> 12 tracker + 11 dark + 1 spectro) extending
kilo_keck.toml. Run namekilo_keck_6; source of the phasing-paper bundle.
- Default KILO Keck config: reduced 6-subaperture-per-pupil quadrature mesh
(24 Clements inputs -> 12 tracker + 11 dark + 1 spectro) extending
examples/nayra_eelt.toml- Single-pupil E-ELT NAYRA at Cerro Armazones; N=48 sub-aperture J-primary baseline with PM980 fiber transport, generic sky background, sensitivity, characterization, and diagnostic plot outputs.
examples/hwo_space.toml- HWO-class space nuller with no atmosphere/AO stages.
Auxiliary regression and smoke-test configs under examples/test/:
examples/test/vertical_slice.toml- Fast architecture smoke test with simple stages and a J-mag sweep.
examples/test/kilo_maunakea.toml- Compact four-telescope Maunakea KILO-style demonstrator.
examples/test/nayra_eelt_baseline.toml- Fixed-point NAYRA E-ELT baseline config (no sweeps); used as a stable regression reference.
examples/test/detection_space_example.toml- Minimal standalone detection-space output exercise.
examples/test/mkid_native_spectro.toml- MKID-native spectroscopy smoke config.
examples/test/kilo_vs_hwo_study.toml- Cross-config comparison study.
examples/test/kilo_keck_quadrature_mesh.toml- KILO Keck with a 48-mode duplicated-input Clements mesh (mode splitter + quadrature reference stage + fringe observability, active acquisition, and cophasing handoff diagnostics).
Example tests live under tests/examples/ and exercise config loading,
structural invariants, and runnable end-to-end slices:
conda run -n py313 pytest- Create a module under the appropriate
nullsim/stages/<family>/directory. - Subclass
BaseStage. - Add class variables:
type_name = "<family>.<name>"family = "<family>"consumes = frozenset({...})produces = frozenset({...})
- Add an inner
Params(BaseModel)if the stage has parameters. - Implement
apply(self, state: SimulationState) -> SimulationState. - Return diagnostics from
diagnostics()if the stage has audit values. - Return
ExternalDependencyobjects fromexternal_dependencies()for data files or snapshots that affect results. - Decorate the class with
@register_stage. - Add the module path to
_STAGE_MODULESinnullsim/stages/_autoload.py. - Add focused tests under
tests/stages/<family>/and, if relevant, an example-level smoke test.
Important contracts:
- Do not mutate existing state budgets in place; return replaced budgets.
- Preserve existing components when adding a component to a budget.
- Declare every required state read in
consumes. - Use
cache_key_extrasonly for opportunistic reads that should affect cache identity but should not be enforced by dependency validation.
- Add a function that accepts
(collection, output_dir, formats). - Decorate it with
@register_plotor@register_table. - Import the module from
outputs/plots/__init__.pyoroutputs/tables/__init__.pyso registration runs. - Add the output name to an example config if it is user-facing.
- Add a focused test under
tests/outputs/.
tests/config/ config loading, hashing, sweeps
tests/pipeline/ registry, runner validation, cache, RNG, state
tests/physics/ pure mathematical primitives
tests/stages/ stage behavior and stage integration
tests/outputs/ output writers and plot modules
tests/catalogs/ exoplanet catalog loader
tests/examples/ end-to-end config checks
Default test command:
conda run -n py313 pytestTargeted examples:
conda run -n py313 pytest tests/pipeline
conda run -n py313 pytest tests/stages
conda run -n py313 pytest tests/examples/test_vertical_slice.py- To understand a config field: start in
config/schema.py, then inspect the stageParamsmodel that consumes it. - To understand why a pipeline fails validation: inspect the failing stage's
consumes, the earlier stages'produces, andpipeline/runner.py. - To understand stale or surprising results: inspect
pipeline/cache.py,external_dependencies(), and the run'smanifest.json. - To understand a plotted quantity: inspect the output module first, then trace
the
state.results.componentsor budget field it reads. - To add a physics formula: put it in
physics/, test it intests/physics/, then wrap it with a stage only after the primitive is pinned. - To debug an end-to-end config: start with the relevant
examples/*.toml, then inspect the corresponding structure or smoke test undertests/examples/.