redback 1.0.1__py3-none-any.whl → 1.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. redback/__init__.py +4 -0
  2. redback/constraints.py +31 -25
  3. redback/get_data/lasair.py +3 -4
  4. redback/get_data/swift.py +7 -7
  5. redback/interaction_processes.py +1 -4
  6. redback/likelihoods.py +207 -21
  7. redback/plotting.py +10 -10
  8. redback/priors/csm_interaction.prior +6 -7
  9. redback/priors/csm_nickel.prior +3 -3
  10. redback/priors/one_comp_kne_rosswog_heatingrate.prior +5 -0
  11. redback/priors/tde_analytical.prior +5 -5
  12. redback/priors/tde_analytical_bolometric.prior +6 -4
  13. redback/priors/tophat_from_emulator.prior +9 -0
  14. redback/priors/two_comp_kne_rosswog_heatingrate.prior +9 -0
  15. redback/priors/two_layer_stratified_kilonova.prior +1 -1
  16. redback/priors.py +11 -0
  17. redback/sed.py +194 -2
  18. redback/simulate_transients.py +61 -32
  19. redback/tables/filters.csv +14 -0
  20. redback/tables/ztf.tar.gz +0 -0
  21. redback/transient/afterglow.py +3 -2
  22. redback/transient/kilonova.py +1 -1
  23. redback/transient/supernova.py +1 -1
  24. redback/transient/tde.py +1 -1
  25. redback/transient/transient.py +2 -2
  26. redback/transient_models/afterglow_models.py +42 -0
  27. redback/transient_models/combined_models.py +47 -32
  28. redback/transient_models/extinction_models.py +5 -4
  29. redback/transient_models/kilonova_models.py +241 -8
  30. redback/transient_models/magnetar_driven_ejecta_models.py +2 -2
  31. redback/transient_models/phenomenological_models.py +13 -0
  32. redback/transient_models/supernova_models.py +50 -36
  33. redback/transient_models/tde_models.py +126 -1
  34. redback/utils.py +283 -6
  35. {redback-1.0.1.dist-info → redback-1.0.2.dist-info}/METADATA +6 -3
  36. {redback-1.0.1.dist-info → redback-1.0.2.dist-info}/RECORD +39 -37
  37. {redback-1.0.1.dist-info → redback-1.0.2.dist-info}/WHEEL +1 -1
  38. redback/tables/ztf_obslog.csv +0 -106649
  39. {redback-1.0.1.dist-info → redback-1.0.2.dist-info}/LICENCE.md +0 -0
  40. {redback-1.0.1.dist-info → redback-1.0.2.dist-info}/top_level.txt +0 -0
redback/plotting.py CHANGED
@@ -346,7 +346,7 @@ class IntegratedFluxPlotter(Plotter):
346
346
  axes.plot(times, ys, color=self.random_sample_color, alpha=self.random_sample_alpha, lw=self.linewidth,
347
347
  zorder=self.zorder)
348
348
  elif self.uncertainty_mode == "credible_intervals":
349
- lower_bound, upper_bound, _ = redback.utils.calc_credible_intervals(samples=random_ys_list)
349
+ lower_bound, upper_bound, _ = redback.utils.calc_credible_intervals(samples=random_ys_list, interval=self.credible_interval_level)
350
350
  axes.fill_between(
351
351
  times, lower_bound, upper_bound, alpha=self.uncertainty_band_alpha, color=self.max_likelihood_color)
352
352
 
@@ -391,11 +391,11 @@ class LuminosityPlotter(IntegratedFluxPlotter):
391
391
 
392
392
  class MagnitudePlotter(Plotter):
393
393
 
394
- xlim_low_phase_model_multiplier = 0.9
395
- xlim_high_phase_model_multiplier = 1.1
396
- xlim_high_multiplier = 1.2
397
- ylim_low_magnitude_multiplier = 0.8
398
- ylim_high_magnitude_multiplier = 1.2
394
+ xlim_low_phase_model_multiplier = KwargsAccessorWithDefault("xlim_low_multiplier", 0.9)
395
+ xlim_high_phase_model_multiplier = KwargsAccessorWithDefault("xlim_high_multiplier", 1.1)
396
+ xlim_high_multiplier = KwargsAccessorWithDefault("xlim_high_multiplier", 1.2)
397
+ ylim_low_magnitude_multiplier = KwargsAccessorWithDefault("ylim_low_multiplier", 0.8)
398
+ ylim_high_magnitude_multiplier = KwargsAccessorWithDefault("ylim_high_multiplier", 1.2)
399
399
  ncols = KwargsAccessorWithDefault("ncols", 2)
400
400
 
401
401
  @property
@@ -635,11 +635,11 @@ class MagnitudePlotter(Plotter):
635
635
  elif self.uncertainty_mode == "credible_intervals":
636
636
  if band in self.band_scaling:
637
637
  if self.band_scaling.get("type") == 'x':
638
- lower_bound, upper_bound, _ = redback.utils.calc_credible_intervals(samples=np.array(random_ys_list) * self.band_scaling.get(band))
638
+ lower_bound, upper_bound, _ = redback.utils.calc_credible_intervals(samples=np.array(random_ys_list) * self.band_scaling.get(band), interval=self.credible_interval_level)
639
639
  elif self.band_scaling.get("type") == '+':
640
- lower_bound, upper_bound, _ = redback.utils.calc_credible_intervals(samples=np.array(random_ys_list) + self.band_scaling.get(band))
640
+ lower_bound, upper_bound, _ = redback.utils.calc_credible_intervals(samples=np.array(random_ys_list) + self.band_scaling.get(band), interval=self.credible_interval_level)
641
641
  else:
642
- lower_bound, upper_bound, _ = redback.utils.calc_credible_intervals(samples=np.array(random_ys_list))
642
+ lower_bound, upper_bound, _ = redback.utils.calc_credible_intervals(samples=np.array(random_ys_list), interval=self.credible_interval_level)
643
643
  axes.fill_between(
644
644
  times - self._reference_mjd_date, lower_bound, upper_bound,
645
645
  alpha=self.uncertainty_band_alpha, color=color_sample)
@@ -789,7 +789,7 @@ class MagnitudePlotter(Plotter):
789
789
  axes[ii].plot(times - self._reference_mjd_date, random_ys, color=color_sample,
790
790
  alpha=self.random_sample_alpha, lw=self.linewidth, zorder=self.zorder)
791
791
  elif self.uncertainty_mode == "credible_intervals":
792
- lower_bound, upper_bound, _ = redback.utils.calc_credible_intervals(samples=random_ys_list)
792
+ lower_bound, upper_bound, _ = redback.utils.calc_credible_intervals(samples=random_ys_list, interval=self.credible_interval_level)
793
793
  axes[ii].fill_between(
794
794
  times - self._reference_mjd_date, lower_bound, upper_bound,
795
795
  alpha=self.uncertainty_band_alpha, color=color_sample)
@@ -1,10 +1,9 @@
1
1
  redshift = Uniform(1e-3,3,name='redshift', latex_label = r'$z$')
2
- mej = LogUniform(1e-4, 100, 'mej', latex_label = r'$M_{\mathrm{ej} }~(M_\odot)$')
3
- csm_mass = LogUniform(1e-4, 100, 'csm_mass', latex_label = r'$M_{\mathrm{csm}}~(M_\odot)$')
2
+ mej = LogUniform(1, 100, 'mej', latex_label = r'$M_{\mathrm{ej} }~(M_\odot)$')
3
+ csm_mass = LogUniform(1, 100, 'csm_mass', latex_label = r'$M_{\mathrm{csm}}~(M_\odot)$')
4
4
  vej = LogUniform(1e3, 1e5, 'vej', latex_label = r'$v_{\mathrm{ej}}~(\mathrm{km}/\mathrm{s})$')
5
- eta = Uniform(0, 1, '\\eta', latex_label = r'$\\eta$')
6
- rho = Uniform(8, 12, 'rho', latex_label = r'$\\rho$')
7
- r0 = Uniform(4, 8, 'r0', latex_label=r'$r_0~({\mathrm{AU}})$')
5
+ eta = Uniform(0, 2, '\\eta', latex_label = r'$\\eta$')
6
+ rho = LogUniform(1e-14, 1e-12, 'rho', latex_label = r'$\\rho$')
7
+ r0 = Uniform(50, 700, 'r0', latex_label=r'$r_0~({\mathrm{AU}})$')
8
8
  kappa = Uniform(0.05, 2, 'kappa', latex_label = r'$\\kappa~(\mathrm{cm}^{2}/\mathrm{g})$')
9
- kappa_gamma = LogUniform(1e-4, 1e4, 'kappa_gamma', latex_label = r'$\\kappa_{\\gamma}~(\mathrm{cm}^{2}/\mathrm{g})$')
10
- temperature_floor = LogUniform(1e3,1e5,name = 'temperature_floor', latex_label = r'$T_{\mathrm{floor}}~(\mathrm{K})$')
9
+ temperature_floor = LogUniform(100,1e4,name = 'temperature_floor', latex_label = r'$T_{\mathrm{floor}}~(\mathrm{K})$')
@@ -3,9 +3,9 @@ mej = LogUniform(1e-4, 100, 'mej', latex_label = r'$M_{\mathrm{ej} }~(M_\odot)$'
3
3
  f_nickel = LogUniform(1e-3,1,name='f_nickel', latex_label = r'$f_{\mathrm{Ni}}$')
4
4
  csm_mass = LogUniform(1e-4, 100, 'csm_mass', latex_label = r'$M_{\mathrm{csm}}~(M_\odot)$')
5
5
  ek = LogUniform(1e48, 1e52, 'ek', latex_label = r'$E_{\mathrm{kin}}~(\mathrm{ erg})$')
6
- eta = Uniform(0, 1, '\\eta', latex_label = r'$\\eta$')
7
- rho = Uniform(8, 12, 'rho', latex_label = r'$\\rho$')
6
+ eta = Uniform(0, 2, '\\eta', latex_label = r'$\\eta$')
7
+ rho = LogUniform(1e-15, 1e-12, 'rho', latex_label = r'$\\rho$')
8
8
  r0 = Uniform(4, 8, 'r0', latex_label=r'$r_0~({\mathrm{AU}})$')
9
9
  kappa = Uniform(0.05, 2, 'kappa', latex_label = r'$\\kappa~(\mathrm{cm}^{2}/\mathrm{g})$')
10
10
  kappa_gamma = LogUniform(1e-4, 1e4, 'kappa_gamma', latex_label = r'$\\kappa_{\\gamma}~(\mathrm{cm}^{2}/\mathrm{g})$')
11
- temperature_floor = LogUniform(1e3,1e5,name = 'temperature_floor', latex_label = r'$T_{\mathrm{floor}}~(\mathrm{K})$')
11
+ temperature_floor = LogUniform(100,1e4,name = 'temperature_floor', latex_label = r'$T_{\mathrm{floor}}~(\mathrm{K})$')
@@ -0,0 +1,5 @@
1
+ redshift = Uniform(1e-6, 0.1, 'redshift', latex_label = r'$z$')
2
+ mej = Uniform(1e-2, 0.05, 'mej', latex_label = r'$M_{\mathrm{ej} }~(M_\odot)$')
3
+ vej = Uniform(0.05, 0.3, 'vej', latex_label = r'$v_{\mathrm{ej}}~(c)$')
4
+ ye = Uniform(0.05, 0.4, 'ye', latex_label = r'$Y_{e}$')
5
+ temperature_floor = LogUniform(100, 6000, 'temperature_floor', latex_label = r'$T_{\mathrm{floor}}~(\mathrm{K})$')
@@ -1,8 +1,8 @@
1
1
  redshift = Uniform(0.01, 3, 'redshift', latex_label=r'$z$')
2
- mej = LogUniform(1e-4, 100, 'mej', latex_label = r'$M_{\mathrm{ej} }~(M_\odot)$')
2
+ mej = LogUniform(0.1, 100, 'mej', latex_label = r'$M_{\mathrm{ej} }~(M_\odot)$')
3
3
  vej = LogUniform(1e3, 1e5, 'vej', latex_label = r'$v_{\mathrm{ej}}~(\mathrm{km}/\mathrm{s})$')
4
- kappa = Uniform(0.05, 2, 'kappa', latex_label = r'$\\kappa~(\mathrm{cm}^{2}/\mathrm{g})$')
4
+ kappa = Uniform(0.05, 1e2, 'kappa', latex_label = r'$\\kappa~(\mathrm{cm}^{2}/\mathrm{g})$')
5
5
  kappa_gamma = LogUniform(1e-4, 1e4, 'kappa_gamma', latex_label = r'$\\kappa_{\\gamma}~(\mathrm{cm}^{2}/\mathrm{g})$')
6
- temperature_floor = LogUniform(1e3,1e5,name = 'temperature_floor', latex_label = r'$T_{\mathrm{floor}}~(\mathrm{K})$')
7
- l0 = LogUniform(1e51, 1e58, "l0", latex_label="$l_0$")
8
- t_0_turn = LogUniform(1e-4, 1e2, "t_0_turn", latex_label="$t_{0 t}$")
6
+ temperature_floor = LogUniform(1e3,1e4,name = 'temperature_floor', latex_label = r'$T_{\mathrm{floor}}~(\mathrm{K})$')
7
+ l0 = LogUniform(1e51, 1e60, "l0", latex_label="$l_0$")
8
+ t_0_turn = LogUniform(1e-4, 5e2, "t_0_turn", latex_label="$t_{0 t}$")
@@ -1,6 +1,8 @@
1
- mej = LogUniform(1e-4, 100, 'mej', latex_label = r'$M_{\mathrm{ej} }~(M_\odot)$')
1
+ redshift = Uniform(0.01, 3, 'redshift', latex_label=r'$z$')
2
+ mej = LogUniform(0.1, 100, 'mej', latex_label = r'$M_{\mathrm{ej} }~(M_\odot)$')
2
3
  vej = LogUniform(1e3, 1e5, 'vej', latex_label = r'$v_{\mathrm{ej}}~(\mathrm{km}/\mathrm{s})$')
3
- kappa = Uniform(0.05, 2, 'kappa', latex_label = r'$\\kappa~(\mathrm{cm}^{2}/\mathrm{g})$')
4
+ kappa = Uniform(0.05, 1e2, 'kappa', latex_label = r'$\\kappa~(\mathrm{cm}^{2}/\mathrm{g})$')
4
5
  kappa_gamma = LogUniform(1e-4, 1e4, 'kappa_gamma', latex_label = r'$\\kappa_{\\gamma}~(\mathrm{cm}^{2}/\mathrm{g})$')
5
- l0 = LogUniform(1e51, 1e58, "l0", latex_label="$l_0$")
6
- t_0_turn = LogUniform(1e-4, 1e2, "t_0_turn", latex_label="$t_{0 t}$")
6
+ temperature_floor = LogUniform(1e3,1e4,name = 'temperature_floor', latex_label = r'$T_{\mathrm{floor}}~(\mathrm{K})$')
7
+ l0 = LogUniform(1e51, 1e60, "l0", latex_label="$l_0$")
8
+ t_0_turn = LogUniform(1e-4, 5e2, "t_0_turn", latex_label="$t_{0 t}$")
@@ -0,0 +1,9 @@
1
+ redshift = Uniform(0.01, 3, 'redshift', latex_label=r'$z$')
2
+ thv = Sine(name='thv', maximum=np.pi/2, latex_label=r'$\\theta_{\mathrm{observer}}~(\mathrm{rad})$')
3
+ loge0 = Uniform(44, 54, 'loge0', latex_label=r'$\log_{10}~E_{0} / {\mathrm{erg}}$')
4
+ thc = Uniform(0.01, 0.1, 'thc', latex_label=r'$\\theta_{\mathrm{core}}~({\mathrm{rad}})$')
5
+ logn0 = Uniform(-5, 2, 'logn0', latex_label=r'$\log_{10}~n_{\mathrm{ism}} / {\mathrm{cm}}^{-3}$')
6
+ p = Uniform(2, 3, 'p', latex_label=r'$p$')
7
+ logepse = Uniform(-5, 0, 'logepse', latex_label=r'$\log_{10}~\\epsilon_{e}$')
8
+ logepsb = Uniform(-5, 0, 'logepsb', latex_label=r'$\log_{10}~\\epsilon_{B}$')
9
+ g0 = Uniform(100,2000, 'g0', latex_label=r'$\\Gamma_{0}$')
@@ -0,0 +1,9 @@
1
+ redshift = Uniform(1e-6, 0.1, 'redshift', latex_label = r'$z$')
2
+ mej_1 = Uniform(1e-2, 0.05, 'mej', latex_label = r'$M_{\mathrm{ej}~1}~(M_\odot)$')
3
+ vej_1 = Uniform(0.05, 0.3, 'vej', latex_label = r'$v_{\mathrm{ej}~1}~(c)$')
4
+ ye_1 = Uniform(0.05, 0.4, 'ye', latex_label = r'$Y_{e}~1$')
5
+ temperature_floor_1 = LogUniform(100, 6000, 'temperature_floor', latex_label = r'$T_{\mathrm{floor}~1}~(\mathrm{K})$')
6
+ mej_2 = Uniform(1e-2, 0.05, 'mej', latex_label = r'$M_{\mathrm{ej}~2}~(M_\odot)$')
7
+ vej_2 = Uniform(0.05, 0.3, 'vej', latex_label = r'$v_{\mathrm{ej}~2}~(c)$')
8
+ ye_2 = Uniform(0.05, 0.4, 'ye', latex_label = r'$Y_{e}~2$')
9
+ temperature_floor_2 = LogUniform(100, 6000, 'temperature_floor', latex_label = r'$T_{\mathrm{floor}~2}~(\mathrm{K})$')
@@ -3,4 +3,4 @@ mej = Uniform(1e-2, 0.05, 'mej', latex_label = r'$M_{\mathrm{ej}}~(M_\odot)$')
3
3
  vej_1 = Uniform(0.05, 0.2, 'vej_1', latex_label = r'$v_{\mathrm{ej}~1}~(c)$')
4
4
  vej_2 = Uniform(0.3, 0.5, 'vej_2', latex_label = r'$v_{\mathrm{ej}~2}~(c)$')
5
5
  kappa = Uniform(1, 30, 'kappa', latex_label = r'$\\kappa~(\mathrm{cm}^{2}/\mathrm{g})$')
6
- beta = Uniform(1.5, 8, 'beta', latex_label = r'$\\beta$')
6
+ beta = Uniform(3.1, 8, 'beta', latex_label = r'$\\beta$')
redback/priors.py CHANGED
@@ -9,6 +9,17 @@ from redback.utils import logger
9
9
 
10
10
 
11
11
  def get_priors(model, times=None, y=None, yerr=None, dt=None, **kwargs):
12
+ """
13
+ Get the prior for the given model. If the model is a prompt model, the times, y, and yerr must be provided.
14
+
15
+ :param model: String referring to a name of a model implemented in Redback.
16
+ :param times: Time array
17
+ :param y: Y values, arbitrary units
18
+ :param yerr: Error on y values, arbitrary units
19
+ :param dt: time interval
20
+ :param kwargs: Extra arguments to be passed to the prior function
21
+ :return: priors: PriorDict object
22
+ """
12
23
  prompt_prior_functions = dict(gaussian=get_gaussian_priors, skew_gaussian=get_skew_gaussian_priors,
13
24
  skew_exponential=get_skew_exponential_priors, fred=get_fred_priors,
14
25
  fred_extended=get_fred_extended_priors)
redback/sed.py CHANGED
@@ -6,6 +6,193 @@ from sncosmo import TimeSeriesSource
6
6
  from redback.constants import *
7
7
  from redback.utils import nu_to_lambda, bandpass_magnitude_to_flux
8
8
 
9
+ def _bandflux_single_redback(model, band, time_or_phase):
10
+ """
11
+
12
+ Synthetic photometry of a model through a single bandpass
13
+
14
+ :param model: Source object
15
+ :param band: Bandpass
16
+ :param time_or_phase: Time or phase numpy array
17
+ :return: bandflux through the bandpass
18
+ """
19
+ from sncosmo.utils import integration_grid
20
+ HC_ERG_AA = 1.9864458571489284e-08 # planck * speed_of_light in AA/s
21
+ MODEL_BANDFLUX_SPACING = 5.0 # Angstroms
22
+
23
+ if (band.minwave() < model.minwave() or band.maxwave() > model.maxwave()):
24
+ raise ValueError('bandpass {0!r:s} [{1:.6g}, .., {2:.6g}] '
25
+ 'outside spectral range [{3:.6g}, .., {4:.6g}]'
26
+ .format(band.name, band.minwave(), band.maxwave(),
27
+ model.minwave(), model.maxwave()))
28
+
29
+ # Set up wavelength grid. Spacing (dwave) evenly divides the bandpass,
30
+ # closest to 5 angstroms without going over.
31
+ wave, dwave = integration_grid(band.minwave(), band.maxwave(),
32
+ MODEL_BANDFLUX_SPACING)
33
+ trans = band(wave)
34
+ f = model._flux(time_or_phase, wave)
35
+ f = np.abs(f)
36
+ return np.sum(wave * trans * f, axis=1) * dwave / HC_ERG_AA
37
+
38
+
39
+ def _bandflux_redback(model, band, time_or_phase, zp, zpsys):
40
+ """
41
+ Support function for bandflux in Source and Model. Follows SNCOSMO
42
+
43
+ This is necessary to have outside because ``phase`` is used in Source
44
+ and ``time`` is used in Model, and we want the method signatures to
45
+ have the right variable name.
46
+ """
47
+ from sncosmo.magsystems import get_magsystem
48
+ from sncosmo.bandpasses import get_bandpass
49
+
50
+ if zp is not None and zpsys is None:
51
+ raise ValueError('zpsys must be given if zp is not None')
52
+
53
+ # broadcast arrays
54
+ if zp is None:
55
+ time_or_phase, band = np.broadcast_arrays(time_or_phase, band)
56
+ else:
57
+ time_or_phase, band, zp, zpsys = \
58
+ np.broadcast_arrays(time_or_phase, band, zp, zpsys)
59
+
60
+ # Convert all to 1-d arrays.
61
+ ndim = time_or_phase.ndim # Save input ndim for return val.
62
+ time_or_phase = np.atleast_1d(time_or_phase)
63
+ band = np.atleast_1d(band)
64
+ if zp is not None:
65
+ zp = np.atleast_1d(zp)
66
+ zpsys = np.atleast_1d(zpsys)
67
+
68
+ # initialize output arrays
69
+ bandflux = np.zeros(time_or_phase.shape, dtype=float)
70
+
71
+ # Loop over unique bands.
72
+ for b in set(band):
73
+ mask = band == b
74
+ b = get_bandpass(b)
75
+
76
+ fsum = _bandflux_single_redback(model, b, time_or_phase[mask])
77
+
78
+ if zp is not None:
79
+ zpnorm = 10. ** (0.4 * zp[mask])
80
+ bandzpsys = zpsys[mask]
81
+ for ms in set(bandzpsys):
82
+ mask2 = bandzpsys == ms
83
+ ms = get_magsystem(ms)
84
+ zpnorm[mask2] = zpnorm[mask2] / ms.zpbandflux(b)
85
+ fsum *= zpnorm
86
+
87
+ bandflux[mask] = fsum
88
+
89
+ if ndim == 0:
90
+ return bandflux[0]
91
+ return bandflux
92
+
93
+ def _bandmag_redback(model, band, magsys, time_or_phase):
94
+ """
95
+ Support function for bandflux in Source and Model.
96
+ This is necessary to have outside the models because ``phase`` is used in
97
+ Source and ``time`` is used in Model.
98
+ """
99
+ from sncosmo.magsystems import get_magsystem
100
+
101
+ bandflux = _bandflux_redback(model, band, time_or_phase, None, None)
102
+ band, magsys, bandflux = np.broadcast_arrays(band, magsys, bandflux)
103
+ return_scalar = (band.ndim == 0)
104
+ band = band.ravel()
105
+ magsys = magsys.ravel()
106
+ bandflux = bandflux.ravel()
107
+
108
+ result = np.empty(bandflux.shape, dtype=float)
109
+ for i, (b, ms, f) in enumerate(zip(band, magsys, bandflux)):
110
+ ms = get_magsystem(ms)
111
+ zpf = ms.zpbandflux(b)
112
+ result[i] = -2.5 * np.log10(f / zpf)
113
+
114
+ if return_scalar:
115
+ return result[0]
116
+ return result
117
+
118
+ class RedbackTimeSeriesSource(TimeSeriesSource):
119
+ def __init__(self, phase, wave, flux, **kwargs):
120
+ """
121
+ RedbackTimeSeriesSource is a subclass of sncosmo.TimeSeriesSource that adds the ability to return the
122
+ flux density at a given time and wavelength, and changes
123
+ the behaviour of the _flux method to better handle models with very low flux values.
124
+
125
+ :param phase: phase/time array
126
+ :param wave: wavelength array in Angstrom
127
+ :param spectra: spectra in erg/cm^2/s/A evaluated at all times and frequencies; shape (len(times), len(frequency_array))
128
+ :param kwargs: additional arguments
129
+ """
130
+ super(RedbackTimeSeriesSource, self).__init__(phase=phase, wave=wave, flux=flux, **kwargs)
131
+
132
+ def get_flux_density(self, time, wavelength):
133
+ """
134
+ Get the flux density at a given time and wavelength.
135
+
136
+ :param time: time in days
137
+ :param wavelength: wavelength in Angstrom
138
+ :return: flux density in erg/cm^2/s/A
139
+ """
140
+ return self._flux(time, wavelength)
141
+
142
+ def bandflux(self, band, phase, zp=None, zpsys=None):
143
+ """
144
+ Flux through the given bandpass(es) at the given phase(s).
145
+
146
+ Default return value is flux in photons / s / cm^2. If zp and zpsys
147
+ are given, flux(es) are scaled to the requested zeropoints.
148
+
149
+ Parameters
150
+ ----------
151
+ band : str or list_like
152
+ Name(s) of bandpass(es) in registry.
153
+ phase : float or list_like, optional
154
+ Phase(s) in days. Default is `None`, which corresponds to the full
155
+ native phase sampling of the model.
156
+ zp : float or list_like, optional
157
+ If given, zeropoint to scale flux to (must also supply ``zpsys``).
158
+ If not given, flux is not scaled.
159
+ zpsys : str or list_like, optional
160
+ Name of a magnitude system in the registry, specifying the system
161
+ that ``zp`` is in.
162
+
163
+ Returns
164
+ -------
165
+ bandflux : float or `~numpy.ndarray`
166
+ Flux in photons / s /cm^2, unless `zp` and `zpsys` are
167
+ given, in which case flux is scaled so that it corresponds
168
+ to the requested zeropoint. Return value is `float` if all
169
+ input parameters are scalars, `~numpy.ndarray` otherwise.
170
+ """
171
+ return _bandflux_redback(self, band, phase, zp, zpsys)
172
+
173
+ def bandmag(self, band, magsys, phase):
174
+ """Magnitude at the given phase(s) through the given
175
+ bandpass(es), and for the given magnitude system(s).
176
+
177
+ Parameters
178
+ ----------
179
+ band : str or list_like
180
+ Name(s) of bandpass in registry.
181
+ magsys : str or list_like
182
+ Name(s) of `~sncosmo.MagSystem` in registry.
183
+ phase : float or list_like
184
+ Phase(s) in days.
185
+
186
+ Returns
187
+ -------
188
+ mag : float or `~numpy.ndarray`
189
+ Magnitude for each item in band, magsys, phase.
190
+ The return value is a float if all parameters are not iterables.
191
+ The return value is an `~numpy.ndarray` if any are iterable.
192
+ """
193
+ return _bandmag_redback(self, band, magsys, phase)
194
+
195
+
9
196
 
10
197
  def blackbody_to_flux_density(temperature, r_photosphere, dl, frequency):
11
198
  """
@@ -298,13 +485,18 @@ def get_correct_output_format_from_spectra(time, time_eval, spectra, lambda_arra
298
485
  :param time: times in observer frame in days to evaluate the model on
299
486
  :param time_eval: times in observer frame where spectra are evaluated. A densely sampled array for accuracy
300
487
  :param bands: band array - must be same length as time array or a single band
301
- :param spectra: spectra in mJy evaluated at all times and frequencies; shape (len(times), len(frequency_array))
488
+ :param spectra: spectra in erg/cm^2/s/A evaluated at all times and frequencies; shape (len(times), len(frequency_array))
302
489
  :param lambda_array: wavelenth array in Angstrom in observer frame
303
490
  :param kwargs: Additional parameters
304
491
  :param output_format: 'flux', 'magnitude', 'sncosmo_source', 'flux_density'
305
492
  :return: flux, magnitude or SNcosmo TimeSeries Source depending on output format kwarg
306
493
  """
307
- source = TimeSeriesSource(phase=time_eval, wave=lambda_array, flux=spectra)
494
+ # clean up spectrum to remove nonsensical values before creating sncosmo source
495
+ spectra = np.nan_to_num(spectra)
496
+ spectra[spectra.value == np.nan_to_num(np.inf)] = 1e-30 * np.mean(spectra[5])
497
+ spectra[spectra.value == 0.] = 1e-30 * np.mean(spectra[5])
498
+
499
+ source = RedbackTimeSeriesSource(phase=time_eval, wave=lambda_array, flux=spectra)
308
500
  if kwargs['output_format'] == 'flux':
309
501
  bands = kwargs['bands']
310
502
  magnitude = source.bandmag(phase=time, band=bands, magsys='ab')
@@ -14,7 +14,7 @@ datadir = os.path.join(os.path.dirname(redback.__file__), 'tables')
14
14
 
15
15
  class SimulateGenericTransient(object):
16
16
  def __init__(self, model, parameters, times, model_kwargs, data_points,
17
- seed=1234, multiwavelength_transient=False, noise_term=0.2):
17
+ seed=1234, multiwavelength_transient=False, noise_term=0.2, noise_type='gaussianmodel', extra_scatter=0.0):
18
18
  """
19
19
  A generic interface to simulating transients
20
20
 
@@ -31,7 +31,12 @@ class SimulateGenericTransient(object):
31
31
  and the data points are sampled in bands/frequency as well,
32
32
  rather than just corresponding to one wavelength/filter.
33
33
  This also allows the same time value to be sampled multiple times.
34
- :param noise_term: Float. Factor which is multiplied by the model flux/magnitude to give the sigma.
34
+ :param noise_type: String. Type of noise to add to the model.
35
+ Default is 'gaussianmodel' where sigma is noise_term * model.
36
+ Another option is 'gaussian' i.e., a simple Gaussian noise with sigma = noise_term.
37
+ :param noise_term: Float. Factor which is multiplied by the model flux/magnitude to give the sigma
38
+ or is sigma itself for 'gaussian' noise.
39
+ :param extra_scatter: Float. Sigma of normal added to output for additional scatter.
35
40
  """
36
41
  self.model = redback.model_library.all_models_dict[model]
37
42
  self.parameters = parameters
@@ -44,20 +49,25 @@ class SimulateGenericTransient(object):
44
49
  self.noise_term = noise_term
45
50
  random.seed(self.seed)
46
51
 
47
- if multiwavelength_transient:
48
- self.all_bands = self.model_kwargs.get('bands', None)
49
- self.all_frequency = self.model_kwargs.get('frequency', None)
50
- if self.all_bands is None and self.all_frequency is None:
51
- raise ValueError('Must supply either bands or frequency to sample data points for an optical transient')
52
- if self.all_bands is not None and self.all_frequency is None:
53
- self.subset_bands = np.array(random.choices(self.all_bands, k=self.data_points))
54
- if self.all_bands is None and self.all_frequency is not None:
55
- self.subset_frequency = np.array(random.choices(self.all_frequency, k=self.data_points))
56
- self.replacement = True
57
- # allow times to be chosen repeatedly
52
+ self.all_bands = self.model_kwargs.get('bands', None)
53
+ self.all_frequency = self.model_kwargs.get('frequency', None)
54
+ if self.all_bands is None and self.all_frequency is None:
55
+ raise ValueError('Must supply either bands or frequency to sample data points for an optical transient')
58
56
  else:
59
- # allow times to be chosen only once.
60
- self.replacement = False
57
+ if multiwavelength_transient:
58
+ if self.all_bands is not None and self.all_frequency is None:
59
+ self.subset_bands = np.array(random.choices(self.all_bands, k=self.data_points))
60
+ if self.all_bands is None and self.all_frequency is not None:
61
+ self.subset_frequency = np.array(random.choices(self.all_frequency, k=self.data_points))
62
+ self.replacement = True
63
+ # allow times to be chosen repeatedly
64
+ else:
65
+ if self.all_bands is not None and self.all_frequency is None:
66
+ self.subset_bands = self.data_points * [self.all_bands]
67
+ if self.all_bands is None and self.all_frequency is not None:
68
+ self.subset_frequency = np.ones(self.data_points) * self.all_frequency
69
+ # allow times to be chosen only once.
70
+ self.replacement = False
61
71
  self.subset_times = np.sort(np.random.choice(self.all_times, size=self.data_points, replace=self.replacement))
62
72
 
63
73
  injection_kwargs = self.parameters.copy()
@@ -76,24 +86,43 @@ class SimulateGenericTransient(object):
76
86
  if 'frequency' in model_kwargs.keys():
77
87
  data['frequency'] = self.subset_frequency
78
88
  data['true_output'] = true_output
79
- data['output'] = np.random.normal(true_output, self.noise_term * true_output)
80
- data['output_error'] = self.noise_term * true_output
89
+
90
+ if noise_type == 'gaussianmodel':
91
+ noise = np.random.normal(0, self.noise_term * true_output, len(true_output))
92
+ output = true_output + noise
93
+ output_error = self.noise_term * true_output
94
+ elif noise_type == 'gaussian':
95
+ noise = np.random.normal(0, self.noise_term, len(true_output))
96
+ output = true_output + noise
97
+ output_error = self.noise_term
98
+ else:
99
+ logger.warning(f"noise_type {noise_type} not implemented.")
100
+ raise ValueError('noise_type must be either gaussianmodel or gaussian')
101
+
102
+ if extra_scatter > 0:
103
+ extra_noise = np.random.normal(0, extra_scatter, len(true_output))
104
+ output = output + extra_noise
105
+ output_error = np.sqrt(output_error**2 + extra_noise**2)
106
+
107
+ data['output'] = output
108
+ data['output_error'] = output_error
81
109
  self.data = data
82
110
 
83
- def save_transient(self, name):
84
- """
85
- Save the transient observations to a csv file.
86
- This will save the full observational dataframe including non-detections etc.
87
- This will save the data to a folder called 'simulated'
88
- with the name of the transient and a csv file of the injection parameters
89
-
90
- :param name: name to save transient.
91
- """
92
- bilby.utils.check_directory_exists_and_if_not_mkdir('simulated')
93
- path = 'simulated/' + name + '.csv'
94
- injection_path = 'simulated/' + name + '_injection_parameters.csv'
95
- self.observations.to_csv(path, index=False)
96
- self.parameters.to_csv(injection_path, index=False)
111
+ def save_transient(self, name):
112
+ """
113
+ Save the transient observations to a csv file.
114
+ This will save the full observational dataframe including non-detections etc.
115
+ This will save the data to a folder called 'simulated'
116
+ with the name of the transient and a csv file of the injection parameters
117
+
118
+ :param name: name to save transient.
119
+ """
120
+ bilby.utils.check_directory_exists_and_if_not_mkdir('simulated')
121
+ path = 'simulated/' + name + '.csv'
122
+ injection_path = 'simulated/' + name + '_injection_parameters.csv'
123
+ self.data.to_csv(path, index=False)
124
+ self.parameters=pd.DataFrame.from_dict([self.parameters])
125
+ self.parameters.to_csv(injection_path, index=False)
97
126
 
98
127
  class SimulateOpticalTransient(object):
99
128
  def __init__(self, model, parameters, pointings_database=None,
@@ -415,7 +444,7 @@ class SimulateOpticalTransient(object):
415
444
  Convert the circular field of view to a radius in radians.
416
445
  :return: survey_radius in radians
417
446
  """
418
- survey_fov_sqrad = self.survey_fov_sqdeg*(np.pi/180.0)
447
+ survey_fov_sqrad = self.survey_fov_sqdeg*(np.pi/180.0)**2
419
448
  survey_radius = np.sqrt(survey_fov_sqrad/np.pi)
420
449
  # survey_radius = np.sqrt(self.survey_fov_sqdeg*((np.pi/180.0)**2.0)/np.pi)
421
450
  return survey_radius
@@ -238,3 +238,17 @@ euclid::VIS,4.223e+14,7103.37,black,7.577e-06,euclid::VIS,EUCLID/VIS
238
238
  efosc2::g,5.866e+14,5114.66,black,3.302e-06,efosc2::g,EFOSC2/g
239
239
  efosc2::r,4.493e+14,6677.40,black,2.342e-06,efosc2::r,EFOSC2/r
240
240
  efosc2::i,3.758e+14,7983.20,black,2.435e-06,efosc2::i,EFOSC2/i
241
+ desg,6.2390e+14,4808.49,black,4.781e-06,desg,DES/g
242
+ desr,4.6746e+14,6417.65,black,3.409e-06,desr,DES/r
243
+ desi,3.8390e+14,7814.58,black,2.300e-06,desi,DES/i
244
+ desz,3.2719e+14,9168.85,black,1.679e-06,desz,DES/z
245
+ desy,3.0315e+14,9896.11,black,7.511e-07,desy,DES/y
246
+ tess,3.8973e+14,7697.6,black,7.658e-06,tess,TESS
247
+ gaia::gbp,5.8712e+14,5109.71,black,9.421e-06,gaia::gbp,GAIA/Gbp
248
+ gaia::g,4.799e+14,6217.59,black,1.278e-05,gaia::g,GAIA/G
249
+ gaia::grp,3.8615e+14,7769.02,black,5.472e-06,gaia::grp,GAIA/Grp
250
+ gaia::grvs,3.4970e+14,8578.76,black,3.481e-07,gaia::grvs,GAIA/Grvs
251
+ gotob,6.4895e+14,4622.88,black,3.771e-06,gotob,GOTO/B
252
+ gotog,5.5819e+14,5374.54,black,3.255e-06,gotog,GOTO/G
253
+ gotol,5.4311e+14,5523.78,black,8.027e-06,gotol,GOTO/L
254
+ gotor,4.6679e+14,6426.84,black,2.510e-06,gotor,GOTO/R
redback/tables/ztf.tar.gz CHANGED
Binary file
@@ -57,7 +57,7 @@ class Afterglow(Transient):
57
57
  :type flux: np.ndarray, optional
58
58
  :type flux_err: np.ndarray, optional
59
59
  :param flux_err: Flux error values.
60
- :param flux_density:Flux density values.
60
+ :param flux_density: Flux density values.
61
61
  :type flux_density: np.ndarray, optional
62
62
  :param flux_density_err: Flux density error values.
63
63
  :type flux_density_err: np.ndarray, optional
@@ -244,7 +244,8 @@ class Afterglow(Transient):
244
244
  'BAT Photon Index (15-150 keV) (PL = simple power-law, CPL = cutoff power-law)'].fillna(0)
245
245
  self.meta_data = meta_data
246
246
  except FileNotFoundError:
247
- logger.warning("Meta data does not exist for this event.")
247
+ logger.info("Metadata does not exist for this event.")
248
+ logger.info("Setting metadata to None. This is not an error, but a warning that no metadata could be found online.")
248
249
  self.meta_data = None
249
250
 
250
251
  def _set_photon_index(self) -> None:
@@ -50,7 +50,7 @@ class Kilonova(OpticalTransient):
50
50
  :type flux: np.ndarray, optional
51
51
  :type flux_err: np.ndarray, optional
52
52
  :param flux_err: Flux error values.
53
- :param flux_density:Flux density values.
53
+ :param flux_density: Flux density values.
54
54
  :type flux_density: np.ndarray, optional
55
55
  :param flux_density_err: Flux density error values.
56
56
  :type flux_density_err: np.ndarray, optional
@@ -45,7 +45,7 @@ class Supernova(OpticalTransient):
45
45
  :type flux: np.ndarray, optional
46
46
  :type flux_err: np.ndarray, optional
47
47
  :param flux_err: Flux error values.
48
- :param flux_density:Flux density values.
48
+ :param flux_density: Flux density values.
49
49
  :type flux_density: np.ndarray, optional
50
50
  :param flux_density_err: Flux density error values.
51
51
  :type flux_density_err: np.ndarray, optional
redback/transient/tde.py CHANGED
@@ -42,7 +42,7 @@ class TDE(OpticalTransient):
42
42
  :type flux: np.ndarray, optional
43
43
  :type flux_err: np.ndarray, optional
44
44
  :param flux_err: Flux error values.
45
- :param flux_density:Flux density values.
45
+ :param flux_density: Flux density values.
46
46
  :type flux_density: np.ndarray, optional
47
47
  :param flux_density_err: Flux density error values.
48
48
  :type flux_density_err: np.ndarray, optional
@@ -137,7 +137,7 @@ class Transient(object):
137
137
  self.system = system
138
138
  self.data_mode = data_mode
139
139
  self.active_bands = active_bands
140
- self.sncosmo_bands = redback.utils.sncosmo_bandname_from_band(self.bands, warning_style='soft')
140
+ self.sncosmo_bands = redback.utils.sncosmo_bandname_from_band(self.bands)
141
141
  self.redshift = redshift
142
142
  self.name = name
143
143
  self.use_phase_model = use_phase_model
@@ -906,7 +906,7 @@ class OpticalTransient(Transient):
906
906
  meta_data = pd.read_csv(self.event_table, on_bad_lines='skip', delimiter=',', dtype='str')
907
907
  except FileNotFoundError as e:
908
908
  redback.utils.logger.warning(e)
909
- redback.utils.logger.warning("Setting metadata to None")
909
+ redback.utils.logger.warning("Setting metadata to None. This is not an error, but a warning that no metadata could be found online.")
910
910
  meta_data = None
911
911
  self.meta_data = meta_data
912
912