Command-Line Interface#
Everything covered in Simulation (sampling an
EventCatalog, screening it down with one or
more cuts, and running synthetic photometry) is also available without writing any Python, via
the uvex-transients console script (uvex_transients.cli). One YAML run-config file
describes what to simulate (which transients, what schedule, what screening); the CLI’s four
subcommands (generate, cut, photometry, and run) describe when to do each step,
reading and writing plain EventCatalog files
between stages.
This page is a hands-on tour of the run-config format and the commands themselves. See Simulation for what each stage actually does under the hood; this page is about driving that same pipeline from a config file and a terminal instead of a Python script.
Quick Look#
The repository ships a ready-to-run example, quickstart_tde.yaml, at
the top of the source tree. Once the package is installed (pip install -e . from a source
checkout registers the uvex-transients command), running the whole pipeline is one line:
uvex-transients run quickstart_tde.yaml --out-dir quickstart_results/
That samples tidal disruption events against the default UVEX schedule, tabulates the survey’s
effective exposure to them, screens them by magnitude and then by SNR, summarizes the resulting
yield, and runs synthetic photometry on whatever survives – leaving every intermediate catalog in
quickstart_results/: 00_generated.ecsv, exposure.ecsv, one numbered file per cut,
yield_summary.ecsv/yield_summary.txt, and a final photometry.ecsv. The rest of this
page explains the config file that made that happen and the commands it works with, so you can
build your own.
The Run-Config File#
A run-config is a single YAML file with up to seven top-level sections. Every CLI command reads the
same file (there’s no separate config per command), but each command only needs the section(s)
it actually touches, resolved lazily by RunConfig: a config
with no photometry: block is perfectly valid as long as you never run
uvex-transients photometry against it.
Section |
Required by |
Purpose |
|---|---|---|
|
all commands |
Which |
|
all commands |
Which |
|
all commands |
At least one |
|
|
|
|
|
Named screening passes, run in the order they’re declared. |
|
|
|
|
|
|
|
|
|
|
|
Whether |
Important
schedule:, mission:, and transients: are the shared “setup” every command needs to
build a SurveySimulator
(simulator); they’re listed as required by “all
commands” above even though, individually, schedule:/mission: each have a fallback
default.
The Schedule#
schedule:
name: uvex_initial_main # one of the names in `schedules.schedule_urls`
# ...or, to fetch a URL directly instead of a name registered in the package config:
#
# schedule:
# url: https://example.com/plan.ecsv
#
# ...or to read a schedule already saved to disk (as written by
# `SurveySchedule.to_disk(path, fov_path=...)`):
#
# schedule:
# path: my_schedule.ecsv
# fov_path: my_schedule.reg
name:, url:, and path:/fov_path: are mutually exclusive: giving more than one
raises. See Surveys for what a schedule actually is and
list_schedules() for the full set of registered names.
Key |
Type |
Description |
|---|---|---|
|
str |
A name registered in |
|
str |
A direct URL to fetch a schedule table from. Mutually exclusive with |
|
str |
A local schedule table path, as written by |
|
str |
The companion instrument-FOV region file for |
The Mission#
mission: uvex
A bare name, resolved against every Mission instance in
m4opt.missions (rubin, ultrasat, uvex, ztf as of this writing); an
unrecognized name raises, listing the real ones.
Key |
Type |
Description |
|---|---|---|
(bare value) |
str |
A name from |
The Transients#
Each entry under transients: is a label of your choosing (used as the catalog’s
transient_type value; see Simulation) mapping to a class: plus whatever
overrides you want on top of its defaults:
transients:
tde:
class: TidalDisruptionEvent
z_limit: 2.0 # overrides ExtragalacticTransient.redshift_limit
duration_limit: 200 day # overrides TransientBase.duration_limit
cosmology: !astropy_cosmology {name: Planck18}
parameters:
amplitude: !prior {type: normal, mean: 43.8, sigma: 0.3}
sigma_rise: 1.0 day # a bare value fixes the parameter instead
class: must name a registered TransientBase
subclass: every built-in type (TidalDisruptionEvent, Kilonova,
LuminousFastBlueOpticalTransient, TypeIIPSNe, TypeIIPExcessSNe, TypeIIbSNe,
ShockCoolingIIb, TypeIbSNe, TypeIcSNe) is available by class name; an unrecognized one
raises, listing what is registered.
Everything under parameters: is applied the same way
Event.simulate_photometry
expects to find it later: a plain value fixes that parameter
(fix()), while a !prior node replaces
its prior entirely (set_prior()). A value
with units (like sigma_rise above) needs a unit string ("1.0 day"); a bare, unitless
number only works for a genuinely dimensionless parameter. See Models for what a
model’s parameters actually are.
Tip
!prior takes a type: naming one of Prior’s
built-in subclasses, plus that class’s own fields:
|
Fields |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
An unrecognized type:, a missing type:, or an unknown field for the chosen type all
raise at load time, naming the line the problem is on.
Key |
Type |
Description |
|---|---|---|
|
str |
A registered |
|
float |
Overrides |
|
str or number |
Overrides |
|
|
Overrides the transient’s cosmology. Optional; defaults to the package’s own default cosmology. |
|
mapping |
Per-SED-parameter overrides, keyed by parameter name; each value is either a fixed value
or a |
Generating Events#
generate:
time_bins: 20
nside: 64
downsample: 20
seed: 42
A direct pass-through to
generate_events(); see
Simulation for what each field means.
downsample: can also give a different factor per transient type instead of one number for
every type – keys are the transients: section’s own keys, and a type left out isn’t
downsampled at all:
generate:
time_bins: 20
downsample:
tde: 20
kilonova: 5
seed: 42
uvex-transients generate quickstart_tde.yaml --out catalog.ecsv
Key |
Type |
Description |
|---|---|---|
|
int |
Number of evenly-spaced time bins to divide the schedule’s span into. Required. |
|
int |
HEALPix resolution. Optional; falls back to the package’s |
|
str |
HEALPix pixel ordering ( |
|
int or mapping of str to int |
Draw a random |
|
int |
Root seed for |
Screening With Cuts#
cuts:
mag_screen:
type: limiting_magnitude
mag_limit: 25.0
snr_screen:
type: snr
snr_threshold: 5.0
Every entry needs a type: naming one of
SurveySimulator.available_cuts():
the two screening methods from Simulation, limiting_magnitude
(filter_by_limiting_magnitude()) and
snr (filter_by_snr()), registered via
the cut() decorator. Everything else under a cut is
forwarded straight through as keyword arguments to that method.
# Run every cut declared above, in order, chained into one output catalog:
uvex-transients cut quickstart_tde.yaml --in catalog.ecsv --out screened.ecsv
# Or run just one, useful for debugging a single stage:
uvex-transients cut quickstart_tde.yaml mag_screen --in catalog.ecsv --out mag_only.ecsv
Hint
Cuts are ordinary SurveySimulator methods, not a
separate plugin class: decorating a new method on a
SurveySimulator subclass with @cut("my_cut")
registers it automatically, immediately usable from a type: in any run-config.
|
Required params |
Optional params |
|---|---|---|
|
|
|
|
|
|
Synthetic Photometry#
photometry:
bands: [FUV, NUV]
n_sigma: 5.0
Both fields are optional; omit the section entirely to evaluate every band the mission’s detector
has, at the package’s default detection significance (simulation.detection_n_sigma in the
package config; see Simulation).
uvex-transients photometry quickstart_tde.yaml --in screened.ecsv --out photometry.ecsv
The output is one row per (event, observation, band): exactly
Event.simulate_photometry’s
own column schema, stacked across every event in the input catalog via
simulate_photometry().
Key |
Type |
Description |
|---|---|---|
|
list of str |
Which of the mission detector’s bandpasses to evaluate. Optional; defaults to every band. |
|
float |
Width, in multiples of the flux error, of the reported detection interval. Optional;
defaults to the package’s |
Yield and Exposure#
yield:
confidence: 0.9
Optional; the one field defaults to a 0.9 Clopper-Pearson confidence level if the whole
section is omitted. Unlike the other sections, there’s no standalone yield subcommand – a
yield summary needs a raw (pre-cut) catalog, a detected (post-cut) catalog, and an exposure
tabulation all at once (see Exposure and Yield), so it’s only ever produced as
part of run, which already has all three in hand.
Key |
Type |
Description |
|---|---|---|
|
float |
Confidence level for the Clopper-Pearson binomial bounds. Optional; defaults to |
run (see below) always computes an
ExposureCatalog and a
YieldTable alongside the event catalog and
photometry, writing exposure.ecsv, yield_summary.ecsv, and a human-readable
yield_summary.txt into --out-dir.
Estimating Detection Counts#
detection_counts:
snr_threshold: 5.0
confidence: 0.9
Estimates, per transient type, how many events would show \(N_{\rm det}\geq k\) detected
epochs, for every \(k\) at once – see
compute_detection_count_table()
and Exposure and Yield. Unlike yield:, this section is entirely optional even
for run: leaving it out of the config skips this stage everywhere, including run.
uvex-transients detection-counts quickstart_tde.yaml \
--catalog catalog.ecsv --photometry photometry.ecsv --exposure exposure.ecsv \
--out detection_counts.ecsv
Key |
Type |
Description |
|---|---|---|
|
float |
An observation epoch counts as detected if at least one band’s SNR exceeds this value. Required. |
|
float |
Confidence level for the Clopper-Pearson binomial bounds. Optional; defaults to |
--catalog is the event catalog --photometry was computed over (typically the same catalog
photometry ran against, i.e. whatever survived every declared cut) – it’s needed alongside
the photometry table itself so that events with zero qualifying epochs (including ones the
schedule never observed at all) are still counted at \(N_{\rm det}=0\). --exposure is an
exposure catalog as written by run (or
compute_effective_exposure() directly).
If detection_counts: is declared, run runs this stage automatically too, writing
detection_counts.ecsv into --out-dir.
Running the Whole Pipeline#
uvex-transients run quickstart_tde.yaml --out-dir results/
Chains generate, an ExposureCatalog
tabulation, every declared cut (in order), a
YieldTable summary, photometry, and (if
detection_counts: is declared) a detection-count table, all in one process, writing each
stage’s output to results/ as it goes: 00_generated.ecsv, exposure.ecsv, then one
NN_<cut key>.ecsv per cut, then yield_summary.ecsv/yield_summary.txt,
photometry.ecsv, and (if declared) detection_counts.ecsv. A config with no cuts:
section at all is fine here too; run goes straight from generate to the yield summary and
photometry.
Every stage’s catalog stays in memory and feeds the next stage regardless, so writing the
intermediate event catalogs (everything up to, but not including, the catalog that photometry
actually runs against – exposure.ecsv/yield_summary.*/photometry.ecsv/
detection_counts.ecsv are always written regardless) is purely for inspection/debugging – set
the config’s top-level keep_intermediate: false (or pass --no-keep-intermediate, which
overrides the config either way) to have run skip those and write only final_catalog.ecsv
(the catalog photometry ran against) instead of 00_generated.ecsv/NN_<cut key>.ecsv:
uvex-transients run quickstart_tde.yaml --out-dir results/ --no-keep-intermediate
Every command accepts --overwrite to replace an existing output file/directory contents
instead of raising.
Every command also accepts --dry-run, which validates the config and prints what the real
command would do without sampling, computing photometry, or writing anything:
uvex-transients run configs/full_run.yaml --out-dir results/ --dry-run
It resolves every section the command needs, so an unknown transient class:, a bad
parameters: override, an unknown cut type or cut name, an unknown mission, or an unreadable
schedule fails here exactly as it would in the real run (as a short dry run failed: ...
message). On success it reports the mission, the size of the schedule, each transient population
(class, SED, redshift limit, duration window), the generate:, cuts:, photometry:,
yield: (for run), and detection_counts: (if declared) settings, and each output file it
would write. If a real run would refuse to overwrite one that already exists, the dry run flags it
as WOULD FAIL and exits non-zero unless --overwrite is also given. The schedule is loaded
(and downloaded on first use), but the command never reads the --in/--catalog/
--photometry/--exposure inputs of cut/photometry/detection-counts, only checks
that they exist.
Using It From Python#
Every command is a thin wrapper: uvex_transients.cli.pipeline’s
run_generate(),
run_exposure(),
run_cuts(),
run_yield_summary(),
run_photometry(), and
run_detection_counts() take a parsed
RunConfig and do the real work, with no click
dependency, useful if you want the same config-driven setup inside a notebook or a larger script
instead of a fresh subprocess per stage:
from uvex_transients.cli.config import RunConfig
from uvex_transients.cli.pipeline import (
run_cuts, run_detection_counts, run_exposure, run_generate, run_photometry, run_yield_summary,
)
config = RunConfig.from_yaml("quickstart_tde.yaml")
catalog = run_generate(config)
exposure = run_exposure(config)
screened = run_cuts(config, catalog) # every declared cut, in order
yields = run_yield_summary(config, catalog, screened, exposure)
phot = run_photometry(config, screened)
counts = run_detection_counts(config, screened, exposure, phot) # only if config has 'detection_counts:'
config.simulator, config.schedule, config.mission, and config.transients are each
resolved once and cached, so building a RunConfig and calling every function above costs one
schedule fetch and one round of transient construction, no matter how many stages you run.
See uvex_transients.cli in the API reference for exhaustive, method-by-method
detail, and Simulation for the pipeline these commands are driving.