.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/simulating/plot_too_followup.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_simulating_plot_too_followup.py: Target-of-Opportunity Follow-up of a TDE =========================================== :ref:`sphx_glr_auto_examples_simulating_plot_tde_end_to_end.py` starts from a whole population, Monte Carlo sampled and screened against a real :class:`~uvex_transients.surveys.base.SurveySchedule`. A target-of-opportunity (ToO) follow-up is the opposite problem: one *specific* TDE, at a position and redshift already known (from an alert, say), that gets pointed at directly on whatever cadence is chosen -- no schedule, no windowed sampling, no :class:`~uvex_transients.simulation.event.Event`. :meth:`~uvex_transients.models.core.base.SpectralModel.simulate_photometry` is built for exactly this: given a sky position and whatever time grid and exposure time the caller wants evaluated, it runs the same noise model a real survey simulation uses (a batched :class:`~synphot.SourceSpectrum` plus :meth:`~m4opt.synphot.Detector.get_snr`), with no schedule in the loop. This example follows one TDE weekly across its whole ~200-day duration and builds its UV light curves. .. GENERATED FROM PYTHON SOURCE LINES 23-35 Choosing the target ---------------------- A target of opportunity is a specific object, not a population draw. :class:`~uvex_transients.transients.TDEs.TidalDisruptionEvent` still supplies the right SED model (:class:`~uvex_transients.models.tdes.van_velzen.VanVelzenTDESED`) and a conservative duration window; only its *parameters* are fixed here, to one concrete realization (via a seed, for reproducibility), rather than left to be sampled for a whole population. Milky Way foreground dust is resolved the same way a real survey simulation resolves it -- :func:`~uvex_transients.dust.resolve_ebv` against the real sky map -- since it depends only on sky position, not on when the TDE happens to be observed. .. GENERATED FROM PYTHON SOURCE LINES 35-60 .. code-block:: Python import numpy as np from astropy import units as u from astropy.coordinates import SkyCoord from astropy.time import Time from m4opt.missions import uvex from m4opt.synphot.background import GalacticBackground from uvex_transients.dust import dust_map, log_attenuation, resolve_ebv from uvex_transients.transients.TDEs import TidalDisruptionEvent from uvex_transients.utils.plotting import get_band_color, plot_band_light_curve, resolve_fig_axes, set_plot_style set_plot_style() tde = TidalDisruptionEvent() coord = SkyCoord(ra=195.3 * u.deg, dec=27.8 * u.deg) redshift = 0.03 luminosity_distance = tde.cosmology.luminosity_distance(redshift) ebv = float(resolve_ebv(dust_map(), coord)) params = {name: value[0] for name, value in tde.sed.sample_parameters(1, rng=12345).items()} print(f"E(B-V) at target: {ebv:.3f}") print("SED parameters:", {name: f"{value:.3g}" for name, value in params.items()}) .. rst-class:: sphx-glr-script-out .. code-block:: none E(B-V) at target: 0.007 SED parameters: {'amplitude': '2.36e+43 erg / s', 'sigma_rise': '3.58 d', 'tau_decline': '26 d', 'temperature': '1.44e+04 K'} .. GENERATED FROM PYTHON SOURCE LINES 61-68 A weekly cadence ------------------- No schedule to query -- just pick the times to observe. :attr:`tde.duration_limit ` is a conservative upper bound on how long this class of event stays relevant; weekly visits across that whole window is a plausible real follow-up cadence for something this slow. .. GENERATED FROM PYTHON SOURCE LINES 68-75 .. code-block:: Python CADENCE = 7 * u.day EXPTIME = 900 * u.s t = np.arange(0, tde.duration_limit.to_value(u.day), CADENCE.to_value(u.day)) * u.day print(f"{len(t)} visits, one every {CADENCE}.") .. rst-class:: sphx-glr-script-out .. code-block:: none 29 visits, one every 7.0 d. .. GENERATED FROM PYTHON SOURCE LINES 76-88 Simulating photometry, with no zodiacal light -------------------------------------------------- A real ToO trigger time isn't known in advance, so there's no meaningful ``obstime`` to feed a season-dependent background term like zodiacal light. Passing ``background=GalacticBackground()`` explicitly simulates against dust (already folded into the source flux itself, via ``ebv``) plus the Milky Way's diffuse UV glow only, and leaves ``observer_location``/``obstime`` at their placeholder defaults -- both irrelevant to :class:`~m4opt.synphot.background.GalacticBackground`, so there is nothing else to supply. See :meth:`~uvex_transients.models.core.base.SpectralModel.simulate_photometry`'s own docstring for exactly when that placeholder default is (and isn't) safe. .. GENERATED FROM PYTHON SOURCE LINES 88-103 .. code-block:: Python phot = tde.sed.simulate_photometry( t, EXPTIME, uvex.detector, coord, background=GalacticBackground(), redshift=redshift, luminosity_distance=luminosity_distance, ebv=ebv, rng=0, **params, ) print(phot["t", "band", "snr", "ab_mag"][:6]) .. rst-class:: sphx-glr-script-out .. code-block:: none t band snr ab_mag d ---- ---- -------------------- ------------------ 0.0 FUV 0.011435447604935759 28.88966586939173 0.0 NUV 0.042660466209702985 28.658262785939527 7.0 FUV 12.75841223741749 23.251605560381677 7.0 NUV 28.266290110411916 22.325140164532897 14.0 FUV 114.19899302776052 18.797226845120594 14.0 NUV 228.6763329164951 17.849637520582068 .. GENERATED FROM PYTHON SOURCE LINES 104-112 The light curves ------------------- The noiseless theory curve (:meth:`~uvex_transients.models.core.base.SpectralModel.mag`, evaluated at each band's pivot wavelength) alongside the simulated weekly visits: detections above SNR=5 as points with error bars, fainter visits as downward-pointing upper limits -- the same plotting convention used at the end of :ref:`sphx_glr_auto_examples_simulating_plot_tde_end_to_end.py`. .. GENERATED FROM PYTHON SOURCE LINES 112-147 .. code-block:: Python SNR_THRESHOLD = 5.0 t_theory = np.linspace(0, tde.duration_limit.to_value(u.day), 300) * u.day fig, ax = resolve_fig_axes(fig_size=(7, 4)) for band in ("FUV", "NUV"): nu = uvex.detector.bandpasses[band].pivot().to(u.Hz, equivalencies=u.spectral()) theory_mag = tde.sed.mag( nu, t_theory, redshift=redshift, luminosity_distance=luminosity_distance, log_attenuation=log_attenuation(nu, ebv), **params, ) plot_band_light_curve( ax, band, phot["t"], phot, t_theory=t_theory, theory_mag=theory_mag, snr_threshold=SNR_THRESHOLD, color=get_band_color(band), err_scale=5.0, label=band, ) ax.invert_yaxis() ax.set_xlabel("Days since explosion") ax.set_ylabel("AB magnitude") ax.set_title(f"Weekly ToO follow-up (z={redshift}, {len(t)} visits)") ax.legend() fig.tight_layout() .. image-sg:: /auto_examples/simulating/images/sphx_glr_plot_too_followup_001.png :alt: Weekly ToO follow-up (z=0.03, 29 visits) :srcset: /auto_examples/simulating/images/sphx_glr_plot_too_followup_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 148-159 Bonus: what zodiacal light would have cost ----------------------------------------------- Suppose the trigger date *had* been known -- say, this TDE actually went off on a specific night. Comparing that against the Galactic-only run above shows what assuming ``background=GalacticBackground()`` glossed over: passing ``background=None`` (the default) uses :data:`~m4opt.missions.uvex`'s own detector background, Galactic *and* zodiacal light together, and now real ``observer_location``/``obstime`` values (from :meth:`~m4opt.missions.uvex.observer_location`) are needed too, since zodiacal light actually depends on both. .. GENERATED FROM PYTHON SOURCE LINES 159-182 .. code-block:: Python hypothetical_trigger = Time("2031-03-01T00:00:00", scale="utc") obstime = hypothetical_trigger + t observer_location = uvex.observer_location(obstime) phot_with_zodi = tde.sed.simulate_photometry( t, EXPTIME, uvex.detector, coord, observer_location=observer_location, obstime=obstime, redshift=redshift, luminosity_distance=luminosity_distance, ebv=ebv, rng=0, **params, ) for band in uvex.detector.bandpasses: galactic_only = np.nanmedian(phot["snr"][phot["band"] == band]) with_zodi = np.nanmedian(phot_with_zodi["snr"][phot_with_zodi["band"] == band]) print(f"{band}: median SNR {galactic_only:.1f} (Galactic only) vs {with_zodi:.1f} (+ zodiacal)") .. rst-class:: sphx-glr-script-out .. code-block:: none FUV: median SNR 27.5 (Galactic only) vs 27.5 (+ zodiacal) NUV: median SNR 56.7 (Galactic only) vs 56.2 (+ zodiacal) .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 9.406 seconds) .. _sphx_glr_download_auto_examples_simulating_plot_too_followup.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_too_followup.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_too_followup.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_too_followup.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_