uvex_transients.simulation.event.Event.simulate_photometry#
- Event.simulate_photometry(mission: Mission, bands: list | None = None, n_sigma: float | None = None) QTable[source]#
Evaluate this event’s detectability at every observation in observations.
Builds one ~synphot.SourceSpectrum for this whole event – batched over every candidate observation’s own time since explosion, via ~uvex_transients.models.core.base.SpectralModel.as_source_spectrum (dust folded in through its
log_attenuation, from this event’s own cached ebv) – and reuses it, unmodified, for every requested band: a ~synphot.SourceSpectrum is purely a function of wavelength/time, so “band” only enters once it’s integrated against a bandpass, via ~m4opt.synphot.Detector.get_snr. That turns what used to be a Python loop over every (observation, band) pair, each doing its own scalar SpectralModel.flux/astropy.stats.signal_to_noise_oir_ccd call, into one vectorized get_snr call per band, regardless of how many observations there are.The reported flux/magnitude at each (observation, band) is then a Gaussian realization of the true (noiseless) flux – evaluated from that same SourceSpectrum at the band’s pivot wavelength – at that SNR’s implied uncertainty; a synthetic measurement, not the ground truth. Physical SED parameters are sampled once, from seed; every band’s noise draws are one vectorized call over all observations at once, in bands order, on the same stream that draw consumed – so the whole event still replays identically given the same seed, but not row-for-row identically to an older, unbatched implementation, since the draws are now grouped per band across every observation rather than interleaved observation-by-observation.
mag_erris the usual linearized (first-order) propagation offlux_errthrough the magnitude log transform – a good description of the uncertainty only while it’s small relative toflux, i.e. at high SNR. It is not a substitute for a real confidence interval: because magnitude is a nonlinear (logarithmic) function of flux, a symmetric interval in flux is an asymmetric one in magnitude, and that asymmetry grows as SNR drops – comparing againstab_mag/mag_erras if they were a plain Gaussian pull systematically reads as biased at low SNR even when the underlying flux draw has no bias at all.flux_upper/flux_lowerandmag_upper/mag_lowerare the actualn_sigmainterval, built the correct way around: bound flux symmetrically first (where the noise is actually Gaussian), then transform each bound to magnitude separately, rather than propagating one linearized width through the transform.- Parameters:
mission (
m4opt.missions.Mission) – Supplies the ~m4opt.synphot.Detector (bandpasses, background, …) evaluated against.bands (
listofstr, optional) – Which of mission.detector’s bandpasses to evaluate. Defaults to every bandpass the detector has.n_sigma (
float, optional) – Width, in multiples offlux_err, of theflux_upper/flux_lower/mag_upper/mag_lowerinterval. If None (the default), usesconfig["simulation.detection_n_sigma"](5 out of the box).
- Returns:
One row per (observation, band), sorted by
obs_timethenband, with columnsevent_id,obs_time,exptime,band,snr,flux/flux_err(Jy),flux_upper/flux_lower(Jy,flux ± n_sigma*flux_err),ab_mag/mag_err, andmag_upper/mag_lower– then_sigmainterval transformed to magnitude, brighter bound first:mag_lower(fromflux_upper) is always finite whenflux_upper>0;mag_upper(fromflux_lower) isnanwheneverflux_lower<=0, i.e. whenever the source isn’t securely distinguished from zero flux atn_sigma– the correct behavior is a one-sided (no faint bound) result there, not a spuriously finite one.flux/flux_err/ab_mag/mag_errarenanwhereversnris non-positive or non-finite (ab_mag/mag_errare alsonanwherever the noisyfluxrealization itself came out non-positive). Empty (but correctly typed) if observations is empty.- Return type: