redback 1.0.3__py3-none-any.whl → 1.1__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.
- redback/__init__.py +3 -2
- redback/analysis.py +321 -4
- redback/filters.py +57 -23
- redback/get_data/directory.py +18 -0
- redback/likelihoods.py +260 -0
- redback/model_library.py +12 -2
- redback/plotting.py +335 -4
- redback/priors/blackbody_spectrum_with_absorption_and_emission_lines.prior +9 -0
- redback/priors/csm_shock_and_arnett_two_rphots.prior +11 -0
- redback/priors/exp_rise_powerlaw_decline.prior +6 -0
- redback/priors/powerlaw_spectrum_with_absorption_and_emission_lines.prior +8 -0
- redback/priors/shockcooling_morag.prior +6 -0
- redback/priors/shockcooling_morag_and_arnett.prior +10 -0
- redback/priors/shockcooling_morag_and_arnett_bolometric.prior +9 -0
- redback/priors/shockcooling_morag_bolometric.prior +5 -0
- redback/priors/shockcooling_sapirandwaxman.prior +6 -0
- redback/priors/shockcooling_sapirandwaxman_bolometric.prior +5 -0
- redback/priors/shockcooling_sapirwaxman_and_arnett.prior +10 -0
- redback/priors/shockcooling_sapirwaxman_and_arnett_bolometric.prior +9 -0
- redback/priors/shocked_cocoon_and_arnett.prior +13 -0
- redback/priors/synchrotron_ism.prior +6 -0
- redback/priors/synchrotron_massloss.prior +6 -0
- redback/priors/synchrotron_pldensity.prior +7 -0
- redback/priors/thermal_synchrotron_v2_fluxdensity.prior +8 -0
- redback/priors/thermal_synchrotron_v2_lnu.prior +7 -0
- redback/priors.py +10 -3
- redback/result.py +9 -1
- redback/sampler.py +46 -4
- redback/sed.py +48 -1
- redback/simulate_transients.py +5 -1
- redback/tables/filters.csv +265 -254
- redback/transient/__init__.py +2 -3
- redback/transient/transient.py +648 -10
- redback/transient_models/__init__.py +3 -2
- redback/transient_models/extinction_models.py +3 -2
- redback/transient_models/gaussianprocess_models.py +45 -0
- redback/transient_models/general_synchrotron_models.py +296 -6
- redback/transient_models/phenomenological_models.py +154 -7
- redback/transient_models/shock_powered_models.py +503 -40
- redback/transient_models/spectral_models.py +82 -0
- redback/transient_models/supernova_models.py +333 -7
- redback/transient_models/tde_models.py +57 -41
- redback/utils.py +302 -51
- {redback-1.0.3.dist-info → redback-1.1.dist-info}/METADATA +8 -6
- {redback-1.0.3.dist-info → redback-1.1.dist-info}/RECORD +48 -29
- {redback-1.0.3.dist-info → redback-1.1.dist-info}/WHEEL +1 -1
- {redback-1.0.3.dist-info → redback-1.1.dist-info/licenses}/LICENCE.md +0 -0
- {redback-1.0.3.dist-info → redback-1.1.dist-info}/top_level.txt +0 -0
redback/utils.py
CHANGED
|
@@ -14,11 +14,11 @@ from scipy.interpolate import RegularGridInterpolator, interp1d
|
|
|
14
14
|
from scipy.stats import gaussian_kde
|
|
15
15
|
from selenium import webdriver
|
|
16
16
|
from selenium.common.exceptions import NoSuchElementException
|
|
17
|
+
from astropy.cosmology import FlatLambdaCDM
|
|
17
18
|
|
|
18
19
|
import redback
|
|
19
20
|
from redback.constants import *
|
|
20
21
|
|
|
21
|
-
|
|
22
22
|
dirname = os.path.dirname(__file__)
|
|
23
23
|
filename = os.path.join(dirname, 'plot_styles/paper.mplstyle')
|
|
24
24
|
plt.style.use(filename)
|
|
@@ -26,6 +26,7 @@ plt.style.use(filename)
|
|
|
26
26
|
logger = logging.getLogger('redback')
|
|
27
27
|
_bilby_logger = logging.getLogger('bilby')
|
|
28
28
|
|
|
29
|
+
|
|
29
30
|
def find_nearest(array, value):
|
|
30
31
|
"""
|
|
31
32
|
Find the nearest value in an array to a given value.
|
|
@@ -38,12 +39,14 @@ def find_nearest(array, value):
|
|
|
38
39
|
idx = (np.abs(array - value)).argmin()
|
|
39
40
|
return array[idx], idx
|
|
40
41
|
|
|
42
|
+
|
|
41
43
|
def download_pointing_tables():
|
|
42
44
|
"""
|
|
43
45
|
Download the pointing tables from zenodo.
|
|
44
46
|
"""
|
|
45
47
|
return logger.info("Pointing tables downloaded and stored in redback/tables")
|
|
46
48
|
|
|
49
|
+
|
|
47
50
|
def sncosmo_bandname_from_band(bands, warning_style='softest'):
|
|
48
51
|
"""
|
|
49
52
|
Convert redback data band names to sncosmo compatible band names
|
|
@@ -75,7 +78,14 @@ def sncosmo_bandname_from_band(bands, warning_style='softest'):
|
|
|
75
78
|
res.append('r')
|
|
76
79
|
return np.array(res)
|
|
77
80
|
|
|
81
|
+
|
|
78
82
|
def check_kwargs_validity(kwargs):
|
|
83
|
+
"""
|
|
84
|
+
Check the validity of the kwargs passed to a model
|
|
85
|
+
|
|
86
|
+
:param kwargs:
|
|
87
|
+
:return:
|
|
88
|
+
"""
|
|
79
89
|
if kwargs == None:
|
|
80
90
|
logger.info("No kwargs passed to function")
|
|
81
91
|
return kwargs
|
|
@@ -101,17 +111,21 @@ def check_kwargs_validity(kwargs):
|
|
|
101
111
|
kwargs['frequency_array'] = kwargs.get('frequency_array', np.linspace(100, 20000, 100))
|
|
102
112
|
return kwargs
|
|
103
113
|
|
|
114
|
+
|
|
104
115
|
def citation_wrapper(r):
|
|
105
116
|
"""
|
|
106
117
|
Wrapper for citation function to allow functions to have a citation attribute
|
|
107
118
|
:param r: proxy argument
|
|
108
119
|
:return: wrapped function
|
|
109
120
|
"""
|
|
121
|
+
|
|
110
122
|
def wrapper(f):
|
|
111
123
|
f.citation = r
|
|
112
124
|
return f
|
|
125
|
+
|
|
113
126
|
return wrapper
|
|
114
127
|
|
|
128
|
+
|
|
115
129
|
def calc_tfb(binding_energy_const, mbh_6, stellar_mass):
|
|
116
130
|
"""
|
|
117
131
|
Calculate the fall back timescale for a SMBH disrupting a stellar mass object
|
|
@@ -123,6 +137,7 @@ def calc_tfb(binding_energy_const, mbh_6, stellar_mass):
|
|
|
123
137
|
tfb = 58. * (3600. * 24.) * (mbh_6 ** (0.5)) * (stellar_mass ** (0.2)) * ((binding_energy_const / 0.8) ** (-1.5))
|
|
124
138
|
return tfb
|
|
125
139
|
|
|
140
|
+
|
|
126
141
|
def calculate_normalisation(unique_frequency, model_1, model_2, tref, model_1_dict, model_2_dict):
|
|
127
142
|
"""
|
|
128
143
|
Calculate the normalisation for smoothly joining two models together at a reference time.
|
|
@@ -138,18 +153,19 @@ def calculate_normalisation(unique_frequency, model_1, model_2, tref, model_1_di
|
|
|
138
153
|
"""
|
|
139
154
|
from redback.model_library import all_models_dict
|
|
140
155
|
f1 = all_models_dict[model_1](time=tref, a_1=1, **model_1_dict)
|
|
141
|
-
if unique_frequency
|
|
156
|
+
if unique_frequency is None:
|
|
142
157
|
f2 = all_models_dict[model_2](time=tref, **model_2_dict)
|
|
143
|
-
norm = f2/f1
|
|
158
|
+
norm = f2 / f1
|
|
144
159
|
normalisation = namedtuple('normalisation', ['bolometric_luminosity'])(norm)
|
|
145
160
|
else:
|
|
146
161
|
model_2_dict['frequency'] = unique_frequency
|
|
147
162
|
f2 = all_models_dict[model_2](time=tref, **model_2_dict)
|
|
148
|
-
unique_norms = f2/f1
|
|
163
|
+
unique_norms = f2 / f1
|
|
149
164
|
dd = dict(zip(unique_frequency, unique_norms))
|
|
150
165
|
normalisation = namedtuple('normalisation', dd.keys())(*dd.values())
|
|
151
166
|
return normalisation
|
|
152
167
|
|
|
168
|
+
|
|
153
169
|
def get_csm_properties(nn, eta):
|
|
154
170
|
"""
|
|
155
171
|
Calculate CSM properties for CSM interacting models
|
|
@@ -179,6 +195,46 @@ def get_csm_properties(nn, eta):
|
|
|
179
195
|
csm_properties.Br = Br
|
|
180
196
|
return csm_properties
|
|
181
197
|
|
|
198
|
+
|
|
199
|
+
def abmag_to_flambda(mag, lam_eff):
|
|
200
|
+
"""
|
|
201
|
+
Converts an AB magnitude to flux density in erg/s/cm^2/Å
|
|
202
|
+
using the effective wavelength for the band.
|
|
203
|
+
|
|
204
|
+
In the AB system, the flux density per unit frequency is:
|
|
205
|
+
f_nu = 10**(-0.4*(mag+48.6)) [erg/s/cm^2/Hz]
|
|
206
|
+
To obtain f_lambda [erg/s/cm^2/Å]:
|
|
207
|
+
|
|
208
|
+
f_lambda = f_nu * (c / λ^2) / 1e8,
|
|
209
|
+
|
|
210
|
+
where λ is the effective wavelength (in cm) and 1e8 converts from per cm to per Å.
|
|
211
|
+
"""
|
|
212
|
+
# effective wavelength from Å to cm:
|
|
213
|
+
lam_eff_cm = lam_eff * 1e-8
|
|
214
|
+
f_nu = 10 ** (-0.4 * (mag + 48.6))
|
|
215
|
+
f_lambda = f_nu * (redback.constants.speed_of_light / lam_eff_cm ** 2) / 1e8
|
|
216
|
+
return f_lambda
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def flambda_err_from_mag_err(flux, mag_err):
|
|
220
|
+
"""
|
|
221
|
+
Compute the error on the flux given an error on the magnitude.
|
|
222
|
+
Using error propagation for f = A*10^(-0.4*mag):
|
|
223
|
+
df/dmag = -0.4 ln(10)* f => σ_f = 0.4 ln(10)* f * σ_mag.
|
|
224
|
+
"""
|
|
225
|
+
return 0.4 * np.log(10) * flux * mag_err
|
|
226
|
+
|
|
227
|
+
def fnu_to_flambda(f_nu, wavelength_A):
|
|
228
|
+
"""
|
|
229
|
+
Convert flux density from erg/s/cm^2/Hz to erg/s/cm^2/Angstrom.
|
|
230
|
+
|
|
231
|
+
:param f_nu: flux density in erg/s/cm^2/Hz
|
|
232
|
+
:param wavelength_A: wavelength in Angstrom
|
|
233
|
+
:return: flux density in erg/s/cm^2/Angstrom
|
|
234
|
+
"""
|
|
235
|
+
return f_nu * speed_of_light * 1e8 / wavelength_A ** 2
|
|
236
|
+
|
|
237
|
+
|
|
182
238
|
def lambda_to_nu(wavelength):
|
|
183
239
|
"""
|
|
184
240
|
:param wavelength: wavelength in Angstrom
|
|
@@ -194,6 +250,7 @@ def nu_to_lambda(frequency):
|
|
|
194
250
|
"""
|
|
195
251
|
return 1.e10 * (speed_of_light_si / frequency)
|
|
196
252
|
|
|
253
|
+
|
|
197
254
|
def calc_kcorrected_properties(frequency, redshift, time):
|
|
198
255
|
"""
|
|
199
256
|
Perform k-correction
|
|
@@ -273,6 +330,7 @@ def date_to_mjd(year, month, day):
|
|
|
273
330
|
"""
|
|
274
331
|
return Time(dict(year=year, month=month, day=day), format="ymdhms").mjd
|
|
275
332
|
|
|
333
|
+
|
|
276
334
|
def deceleration_timescale(e0, g0, n0):
|
|
277
335
|
"""
|
|
278
336
|
Calculate the deceleration timescale for an afterglow
|
|
@@ -290,6 +348,7 @@ def deceleration_timescale(e0, g0, n0):
|
|
|
290
348
|
t_peak = (num / denom) ** (1. / 3.)
|
|
291
349
|
return t_peak
|
|
292
350
|
|
|
351
|
+
|
|
293
352
|
def calc_flux_density_from_ABmag(magnitudes):
|
|
294
353
|
"""
|
|
295
354
|
Calculate flux density from AB magnitude assuming monochromatic AB filter
|
|
@@ -299,6 +358,7 @@ def calc_flux_density_from_ABmag(magnitudes):
|
|
|
299
358
|
"""
|
|
300
359
|
return (magnitudes * uu.ABmag).to(uu.mJy)
|
|
301
360
|
|
|
361
|
+
|
|
302
362
|
def calc_ABmag_from_flux_density(fluxdensity):
|
|
303
363
|
"""
|
|
304
364
|
Calculate AB magnitude from flux density assuming monochromatic AB filter
|
|
@@ -308,6 +368,7 @@ def calc_ABmag_from_flux_density(fluxdensity):
|
|
|
308
368
|
"""
|
|
309
369
|
return (fluxdensity * uu.mJy).to(uu.ABmag)
|
|
310
370
|
|
|
371
|
+
|
|
311
372
|
def calc_flux_density_from_vegamag(magnitudes, zeropoint):
|
|
312
373
|
"""
|
|
313
374
|
Calculate flux density from Vega magnitude assuming Vega filter
|
|
@@ -317,9 +378,10 @@ def calc_flux_density_from_vegamag(magnitudes, zeropoint):
|
|
|
317
378
|
:return: flux density in mJy
|
|
318
379
|
"""
|
|
319
380
|
zeropoint = zeropoint * 1000
|
|
320
|
-
flux_density = zeropoint * 10 ** (magnitudes
|
|
381
|
+
flux_density = zeropoint * 10 ** (magnitudes / -2.5)
|
|
321
382
|
return flux_density
|
|
322
383
|
|
|
384
|
+
|
|
323
385
|
def calc_vegamag_from_flux_density(fluxdensity, zeropoint):
|
|
324
386
|
"""
|
|
325
387
|
Calculate Vega magnitude from flux density assuming Vega filter
|
|
@@ -360,6 +422,29 @@ def bandflux_error_from_limiting_mag(fiveSigmaDepth, bandflux_ref):
|
|
|
360
422
|
return bandflux_error
|
|
361
423
|
|
|
362
424
|
|
|
425
|
+
def convert_apparent_mag_to_absolute(app_magnitude, redshift, **kwargs):
|
|
426
|
+
"""
|
|
427
|
+
Convert apparent magnitude to absolute magnitude assuming planck18 cosmology.
|
|
428
|
+
|
|
429
|
+
:param app_magnitude: AB/Vega apparent magnitude
|
|
430
|
+
:param redshift: redshift
|
|
431
|
+
:param kwargs: Additional kwargs
|
|
432
|
+
:param cosmology: Cosmology object if not using default
|
|
433
|
+
:return: absolute magnitude
|
|
434
|
+
"""
|
|
435
|
+
from astropy.cosmology import Planck18
|
|
436
|
+
import astropy.units as uu
|
|
437
|
+
|
|
438
|
+
# Create a cosmology object
|
|
439
|
+
cosmo = kwargs.get('cosmology', Planck18)
|
|
440
|
+
# Calculate the luminosity distance in megaparsecs (pc)
|
|
441
|
+
luminosity_distance = cosmo.luminosity_distance(redshift).to(uu.pc).value
|
|
442
|
+
|
|
443
|
+
# Convert to absolute magnitude using the formula
|
|
444
|
+
absolute_magnitude = app_magnitude - 5 * np.log10(luminosity_distance) + 5
|
|
445
|
+
return absolute_magnitude
|
|
446
|
+
|
|
447
|
+
|
|
363
448
|
def convert_absolute_mag_to_apparent(magnitude, distance):
|
|
364
449
|
"""
|
|
365
450
|
Convert absolute magnitude to apparent
|
|
@@ -382,7 +467,92 @@ def check_element(driver, id_number):
|
|
|
382
467
|
return False
|
|
383
468
|
return True
|
|
384
469
|
|
|
385
|
-
def
|
|
470
|
+
def bandpass_flux_to_flux_density(flux, flux_err, delta_nu):
|
|
471
|
+
"""
|
|
472
|
+
Convert an integrated flux (and its error) measured over a bandpass
|
|
473
|
+
in erg/s/cm² into a flux density (in erg/s/cm²/Hz) and then into millijanskys (mJy).
|
|
474
|
+
|
|
475
|
+
Parameters
|
|
476
|
+
----------
|
|
477
|
+
flux : float or numpy.ndarray
|
|
478
|
+
Integrated flux in erg/s/cm².
|
|
479
|
+
flux_err : float or numpy.ndarray
|
|
480
|
+
Error in the integrated flux in erg/s/cm².
|
|
481
|
+
delta_nu : float
|
|
482
|
+
Effective bandwidth of the filter in Hz.
|
|
483
|
+
|
|
484
|
+
Returns
|
|
485
|
+
-------
|
|
486
|
+
f_nu_mJy : float or numpy.ndarray
|
|
487
|
+
Flux density converted to millijanskys (mJy).
|
|
488
|
+
f_nu_err_mJy : float or numpy.ndarray
|
|
489
|
+
Error in the flux density in mJy.
|
|
490
|
+
|
|
491
|
+
Notes
|
|
492
|
+
-----
|
|
493
|
+
The conversion from integrated flux F (erg/s/cm²) to flux density f_nu (erg/s/cm²/Hz)
|
|
494
|
+
assumes a known effective bandwidth Δν in Hz:
|
|
495
|
+
|
|
496
|
+
f_nu = F / Δν
|
|
497
|
+
|
|
498
|
+
Then, converting to mJy is done using the relation
|
|
499
|
+
1 mJy = 1e-3 Jy = 1e-3 * 1e-23 erg/s/cm²/Hz = 1e-26 erg/s/cm²/Hz.
|
|
500
|
+
Therefore, to convert erg/s/cm²/Hz into mJy, divide by 1e-26.
|
|
501
|
+
"""
|
|
502
|
+
# Calculate flux density in erg/s/cm²/Hz
|
|
503
|
+
f_nu = flux / delta_nu
|
|
504
|
+
f_nu_err = flux_err / delta_nu
|
|
505
|
+
|
|
506
|
+
# Convert to mJy: 1 mJy = 1e-26 erg/s/cm²/Hz
|
|
507
|
+
conversion_factor = 1e-26 # erg/s/cm²/Hz per mJy
|
|
508
|
+
f_nu_mJy = f_nu / conversion_factor
|
|
509
|
+
f_nu_err_mJy = f_nu_err / conversion_factor
|
|
510
|
+
|
|
511
|
+
return f_nu_mJy, f_nu_err_mJy
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def abmag_to_flux_density_and_error_inmjy(m_AB, sigma_m):
|
|
515
|
+
"""
|
|
516
|
+
Convert an AB magnitude and its uncertainty to a flux density in millijanskys (mJy)
|
|
517
|
+
along with the associated error. In the AB system, the flux density (in erg/s/cm²/Hz) is:
|
|
518
|
+
|
|
519
|
+
f_nu = 10^(-0.4*(m_AB + 48.60))
|
|
520
|
+
|
|
521
|
+
Since 1 Jansky = 1e-23 erg/s/cm²/Hz and 1 mJy = 1e-3 Jansky,
|
|
522
|
+
1 mJy = 1e-26 erg/s/cm²/Hz. Therefore, to convert f_nu to mJy, we do:
|
|
523
|
+
|
|
524
|
+
f_nu(mJy) = f_nu / 1e-26
|
|
525
|
+
|
|
526
|
+
The uncertainty in the flux density is propagated as:
|
|
527
|
+
|
|
528
|
+
sigma_f(mJy) = 0.9210 * f_nu(mJy) * sigma_m
|
|
529
|
+
|
|
530
|
+
Parameters
|
|
531
|
+
----------
|
|
532
|
+
m_AB : float or array_like
|
|
533
|
+
The AB magnitude value(s).
|
|
534
|
+
sigma_m : float or array_like
|
|
535
|
+
The uncertainty in the AB magnitude.
|
|
536
|
+
|
|
537
|
+
Returns
|
|
538
|
+
-------
|
|
539
|
+
f_nu_mjy : float or ndarray
|
|
540
|
+
Flux density in millijanskys (mJy).
|
|
541
|
+
sigma_f_mjy : float or ndarray
|
|
542
|
+
Uncertainty in the flux density (mJy).
|
|
543
|
+
"""
|
|
544
|
+
# Compute flux density in erg/s/cm^2/Hz
|
|
545
|
+
f_nu = 10 ** (-0.4 * (m_AB + 48.60))
|
|
546
|
+
# Convert flux density to mJy (1 mJy = 1e-26 erg/s/cm^2/Hz)
|
|
547
|
+
f_nu_mjy = f_nu / 1e-26
|
|
548
|
+
# Propagate the uncertainty (σ_f = 0.9210 * f_nu * σ_m, applied after conversion)
|
|
549
|
+
sigma_f_mjy = 0.9210 * f_nu_mjy * sigma_m
|
|
550
|
+
return f_nu_mjy, sigma_f_mjy
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
def calc_flux_density_error_from_monochromatic_magnitude(magnitude, magnitude_error, reference_flux,
|
|
555
|
+
magnitude_system='AB'):
|
|
386
556
|
"""
|
|
387
557
|
Calculate flux density error from magnitude error
|
|
388
558
|
|
|
@@ -399,6 +569,7 @@ def calc_flux_density_error_from_monochromatic_magnitude(magnitude, magnitude_er
|
|
|
399
569
|
flux_err = ((dfdm * magnitude_error) ** 2) ** 0.5
|
|
400
570
|
return flux_err
|
|
401
571
|
|
|
572
|
+
|
|
402
573
|
def calc_flux_error_from_magnitude(magnitude, magnitude_error, reference_flux):
|
|
403
574
|
"""
|
|
404
575
|
Calculate flux error from magnitude error
|
|
@@ -422,7 +593,7 @@ def bands_to_zeropoint(bands):
|
|
|
422
593
|
:return: zeropoint for magnitude to flux density calculation
|
|
423
594
|
"""
|
|
424
595
|
reference_flux = bands_to_reference_flux(bands)
|
|
425
|
-
zeropoint = 10**(reference_flux
|
|
596
|
+
zeropoint = 10 ** (reference_flux / -2.5)
|
|
426
597
|
return zeropoint
|
|
427
598
|
|
|
428
599
|
|
|
@@ -435,7 +606,7 @@ def bandpass_magnitude_to_flux(magnitude, bands):
|
|
|
435
606
|
:return: flux
|
|
436
607
|
"""
|
|
437
608
|
reference_flux = bands_to_reference_flux(bands)
|
|
438
|
-
maggi = 10.0**(magnitude / (-2.5))
|
|
609
|
+
maggi = 10.0 ** (magnitude / (-2.5))
|
|
439
610
|
flux = maggi * reference_flux
|
|
440
611
|
return flux
|
|
441
612
|
|
|
@@ -527,6 +698,29 @@ def bands_to_frequency(bands):
|
|
|
527
698
|
raise KeyError(f"Band {band} is not defined in filters.csv!")
|
|
528
699
|
return np.array(res)
|
|
529
700
|
|
|
701
|
+
def bands_to_effective_width(bands):
|
|
702
|
+
"""
|
|
703
|
+
Converts a list of bands into an array of effective width in Hz
|
|
704
|
+
|
|
705
|
+
:param bands: List of bands.
|
|
706
|
+
:type bands: list[str]
|
|
707
|
+
:return: An array of effective width associated with the given bands.
|
|
708
|
+
:rtype: np.ndarray
|
|
709
|
+
"""
|
|
710
|
+
if bands is None:
|
|
711
|
+
bands = []
|
|
712
|
+
df = pd.read_csv(f"{dirname}/tables/filters.csv")
|
|
713
|
+
bands_to_freqs = {band: wavelength for band, wavelength in zip(df['bands'], df['effective_width [Hz]'])}
|
|
714
|
+
res = []
|
|
715
|
+
for band in bands:
|
|
716
|
+
try:
|
|
717
|
+
res.append(bands_to_freqs[band])
|
|
718
|
+
except KeyError as e:
|
|
719
|
+
logger.info(e)
|
|
720
|
+
raise KeyError(f"Band {band} is not defined in filters.csv!")
|
|
721
|
+
return np.array(res)
|
|
722
|
+
|
|
723
|
+
|
|
530
724
|
def frequency_to_bandname(frequency):
|
|
531
725
|
"""
|
|
532
726
|
Converts a list of frequencies into an array corresponding band names
|
|
@@ -549,6 +743,7 @@ def frequency_to_bandname(frequency):
|
|
|
549
743
|
raise KeyError(f"Wavelength {freq} is not defined in filters.csv!")
|
|
550
744
|
return np.array(res)
|
|
551
745
|
|
|
746
|
+
|
|
552
747
|
def fetch_driver():
|
|
553
748
|
# open the webdriver
|
|
554
749
|
options = webdriver.ChromeOptions()
|
|
@@ -567,37 +762,49 @@ def calc_credible_intervals(samples, interval=0.9):
|
|
|
567
762
|
"""
|
|
568
763
|
if not 0 <= interval <= 1:
|
|
569
764
|
raise ValueError
|
|
570
|
-
lower_bound = np.quantile(samples, 0.5 - interval/2, axis=0)
|
|
571
|
-
upper_bound = np.quantile(samples, 0.5 + interval/2, axis=0)
|
|
765
|
+
lower_bound = np.quantile(samples, 0.5 - interval / 2, axis=0)
|
|
766
|
+
upper_bound = np.quantile(samples, 0.5 + interval / 2, axis=0)
|
|
572
767
|
median = np.quantile(samples, 0.5, axis=0)
|
|
573
768
|
return lower_bound, upper_bound, median
|
|
574
769
|
|
|
575
|
-
|
|
576
770
|
def calc_one_dimensional_median_and_error_bar(samples, quantiles=(0.16, 0.84), fmt='.2f'):
|
|
577
771
|
"""
|
|
578
|
-
|
|
772
|
+
Calculates the median and error bars for a one-dimensional sample array.
|
|
579
773
|
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
774
|
+
This function computes the median, lower, and upper error bars based on the
|
|
775
|
+
specified quantiles. It returns these values along with a formatted string
|
|
776
|
+
representation.
|
|
777
|
+
|
|
778
|
+
:param samples: An array of numerical values representing the sample data. The
|
|
779
|
+
input must not be empty.
|
|
780
|
+
:type samples: list or numpy.ndarray
|
|
781
|
+
:param quantiles: A tuple specifying the lower and upper quantile values. For
|
|
782
|
+
example, (0.16, 0.84) represents the 16th percentile as the lower quantile
|
|
783
|
+
and the 84th percentile as the upper quantile. Default is (0.16, 0.84).
|
|
784
|
+
:type quantiles: tuple
|
|
785
|
+
:param fmt: A format string for rounding the results in the formatted output.
|
|
786
|
+
Default is '.2f'.
|
|
787
|
+
:type fmt: str
|
|
788
|
+
:return: A namedtuple containing the median, lower error bar, upper error bar,
|
|
789
|
+
and a formatted string representation.
|
|
790
|
+
:rtype: MedianErrorBarResult
|
|
791
|
+
:raises ValueError: If the input `samples` array is empty.
|
|
584
792
|
"""
|
|
585
|
-
|
|
793
|
+
MedianErrorBarResult = namedtuple('MedianErrorBarResult', ['median', 'lower', 'upper', 'string'])
|
|
586
794
|
|
|
587
|
-
if len(
|
|
588
|
-
raise ValueError("
|
|
795
|
+
if len(samples) == 0:
|
|
796
|
+
raise ValueError("Samples array cannot be empty.")
|
|
589
797
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
798
|
+
median = np.median(samples)
|
|
799
|
+
lower_quantile, upper_quantile = np.quantile(samples, quantiles)
|
|
800
|
+
|
|
801
|
+
lower = median - lower_quantile
|
|
802
|
+
upper = upper_quantile - median
|
|
803
|
+
|
|
804
|
+
formatted_string = rf"${median:{fmt}}_{{-{lower:{fmt}}}}^{{+{upper:{fmt}}}}$"
|
|
805
|
+
|
|
806
|
+
return MedianErrorBarResult(median=median, lower=lower, upper=upper, string=formatted_string)
|
|
595
807
|
|
|
596
|
-
fmt = "{{0:{0}}}".format(fmt).format
|
|
597
|
-
string_template = r"${{{0}}}_{{-{1}}}^{{+{2}}}$"
|
|
598
|
-
summary.string = string_template.format(
|
|
599
|
-
fmt(summary.median), fmt(summary.minus), fmt(summary.plus))
|
|
600
|
-
return summary
|
|
601
808
|
|
|
602
809
|
|
|
603
810
|
def kde_scipy(x, bandwidth=0.05, **kwargs):
|
|
@@ -700,7 +907,6 @@ def setup_logger(outdir='.', label=None, log_level='INFO'):
|
|
|
700
907
|
|
|
701
908
|
logger.info(f'Running redback version: {redback.__version__}')
|
|
702
909
|
|
|
703
|
-
|
|
704
910
|
class MetaDataAccessor(object):
|
|
705
911
|
"""
|
|
706
912
|
Generic descriptor class that allows handy access of properties without long
|
|
@@ -722,6 +928,7 @@ class MetaDataAccessor(object):
|
|
|
722
928
|
getattr(instance, self.container_instance_name)[self.property_name] = value
|
|
723
929
|
|
|
724
930
|
|
|
931
|
+
|
|
725
932
|
class DataModeSwitch(object):
|
|
726
933
|
"""
|
|
727
934
|
Descriptor class to access boolean data_mode switches.
|
|
@@ -775,14 +982,14 @@ def interpolated_barnes_and_kasen_thermalisation_efficiency(mej, vej):
|
|
|
775
982
|
v_array = np.asarray([0.1, 0.2, 0.3, 0.4])
|
|
776
983
|
mass_array = np.asarray([1.e-3, 5.e-3, 1.e-2, 5.e-2, 1.e-1])
|
|
777
984
|
a_array = np.asarray([[2.01, 4.52, 8.16, 16.3], [0.81, 1.9, 3.2, 5.0],
|
|
778
|
-
|
|
779
|
-
|
|
985
|
+
[0.56, 1.31, 2.19, 3.0], [.27, .55, .95, 2.0],
|
|
986
|
+
[0.20, 0.39, 0.65, 0.9]])
|
|
780
987
|
b_array = np.asarray([[0.28, 0.62, 1.19, 2.4], [0.19, 0.28, 0.45, 0.65],
|
|
781
|
-
|
|
782
|
-
|
|
988
|
+
[0.17, 0.21, 0.31, 0.45], [0.10, 0.13, 0.15, 0.17],
|
|
989
|
+
[0.06, 0.11, 0.12, 0.12]])
|
|
783
990
|
d_array = np.asarray([[1.12, 1.39, 1.52, 1.65], [0.86, 1.21, 1.39, 1.5],
|
|
784
|
-
|
|
785
|
-
|
|
991
|
+
[0.74, 1.13, 1.32, 1.4], [0.6, 0.9, 1.13, 1.25],
|
|
992
|
+
[0.63, 0.79, 1.04, 1.5]])
|
|
786
993
|
a_func = RegularGridInterpolator((mass_array, v_array), a_array, bounds_error=False, fill_value=None)
|
|
787
994
|
b_func = RegularGridInterpolator((mass_array, v_array), b_array, bounds_error=False, fill_value=None)
|
|
788
995
|
d_func = RegularGridInterpolator((mass_array, v_array), d_array, bounds_error=False, fill_value=None)
|
|
@@ -1000,7 +1207,6 @@ def heatinggrids():
|
|
|
1000
1207
|
C3_interp = RegularGridInterpolator((V_GRID, YE_GRID), C3_GRID, bounds_error=False, fill_value=None)
|
|
1001
1208
|
TAU3_interp = RegularGridInterpolator((V_GRID, YE_GRID), TAU3_GRID, bounds_error=False, fill_value=None)
|
|
1002
1209
|
|
|
1003
|
-
|
|
1004
1210
|
interpolators = namedtuple('interpolators', ['E0', 'ALP', 'T0', 'SIG', 'ALP1', 'T1', 'SIG1',
|
|
1005
1211
|
'C1', 'TAU1', 'C2', 'TAU2', 'C3', 'TAU3'])
|
|
1006
1212
|
interpolators.E0 = E0_interp
|
|
@@ -1018,6 +1224,7 @@ def heatinggrids():
|
|
|
1018
1224
|
interpolators.TAU3 = TAU3_interp
|
|
1019
1225
|
return interpolators
|
|
1020
1226
|
|
|
1227
|
+
|
|
1021
1228
|
def get_heating_terms(ye, vel, **kwargs):
|
|
1022
1229
|
ints = heatinggrids()
|
|
1023
1230
|
e0 = ints.E0([vel, ye])[0]
|
|
@@ -1052,6 +1259,7 @@ def get_heating_terms(ye, vel, **kwargs):
|
|
|
1052
1259
|
heating_terms.tau3 = tau3 * heating_rate_fudge
|
|
1053
1260
|
return heating_terms
|
|
1054
1261
|
|
|
1262
|
+
|
|
1055
1263
|
def _calculate_rosswogkorobkin24_qdot(time_array, ejecta_velocity, electron_fraction):
|
|
1056
1264
|
import pickle
|
|
1057
1265
|
import os
|
|
@@ -1065,6 +1273,7 @@ def _calculate_rosswogkorobkin24_qdot(time_array, ejecta_velocity, electron_frac
|
|
|
1065
1273
|
lum_in = qdot_object(full_array)
|
|
1066
1274
|
return lum_in
|
|
1067
1275
|
|
|
1276
|
+
|
|
1068
1277
|
def electron_fraction_from_kappa(kappa):
|
|
1069
1278
|
"""
|
|
1070
1279
|
Uses interpolation from Tanaka+19 to calculate
|
|
@@ -1079,6 +1288,7 @@ def electron_fraction_from_kappa(kappa):
|
|
|
1079
1288
|
electron_fraction = kappa_func(kappa)
|
|
1080
1289
|
return electron_fraction
|
|
1081
1290
|
|
|
1291
|
+
|
|
1082
1292
|
def kappa_from_electron_fraction(ye):
|
|
1083
1293
|
"""
|
|
1084
1294
|
Uses interpolation from Tanaka+19 to calculate
|
|
@@ -1091,37 +1301,78 @@ def kappa_from_electron_fraction(ye):
|
|
|
1091
1301
|
func = interp1d(ye_array, y=kappa_array, fill_value='extrapolate')
|
|
1092
1302
|
kappa = func(ye)
|
|
1093
1303
|
return kappa
|
|
1094
|
-
|
|
1304
|
+
|
|
1305
|
+
|
|
1095
1306
|
def lorentz_factor_from_velocity(velocity):
|
|
1096
1307
|
"""
|
|
1097
1308
|
Calculates the Lorentz factor for a given velocity
|
|
1098
1309
|
:param velocity: velocity in cm/s
|
|
1099
1310
|
:return: Lorentz factor
|
|
1100
1311
|
"""
|
|
1101
|
-
return 1 / np.sqrt(1 - (velocity / speed_of_light)**2
|
|
1102
|
-
|
|
1312
|
+
return 1 / np.sqrt(1 - (velocity / speed_of_light) ** 2)
|
|
1313
|
+
|
|
1314
|
+
|
|
1103
1315
|
def velocity_from_lorentz_factor(lorentz_factor):
|
|
1104
1316
|
"""
|
|
1105
|
-
Calculates the velocity for a given Lorentz factor
|
|
1317
|
+
Calculates the velocity for a given Lorentz factor
|
|
1106
1318
|
:param Lorentz_factor: relativistic Lorentz factor
|
|
1107
1319
|
:return: velocity in cm/s
|
|
1108
1320
|
"""
|
|
1109
1321
|
|
|
1110
1322
|
return speed_of_light * np.sqrt(1 - 1 / lorentz_factor ** 2)
|
|
1111
1323
|
|
|
1112
|
-
|
|
1324
|
+
|
|
1325
|
+
class UserCosmology(FlatLambdaCDM):
|
|
1113
1326
|
"""
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1327
|
+
Dummy cosmology class that behaves like an Astropy cosmology,
|
|
1328
|
+
except that the luminosity distance is fixed to the user‐specified value.
|
|
1329
|
+
|
|
1330
|
+
Parameters
|
|
1331
|
+
----------
|
|
1332
|
+
dl : astropy.units.Quantity
|
|
1333
|
+
The luminosity distance to return (e.g., 100 * u.Mpc).
|
|
1334
|
+
**kwargs
|
|
1335
|
+
Additional keyword arguments for FlatLambdaCDM (e.g. H0, Om0) if needed.
|
|
1118
1336
|
"""
|
|
1337
|
+
def __init__(self, **kwargs):
|
|
1338
|
+
self.dl = kwargs.pop("dl", None)
|
|
1339
|
+
|
|
1340
|
+
if 'H0' not in kwargs:
|
|
1341
|
+
kwargs['H0'] = 70 * uu.km / uu.s / uu.Mpc
|
|
1342
|
+
if 'Om0' not in kwargs:
|
|
1343
|
+
kwargs['Om0'] = 0.3
|
|
1344
|
+
|
|
1345
|
+
# Initialize the parent FlatLambdaCDM class.
|
|
1346
|
+
super().__init__(**kwargs)
|
|
1347
|
+
|
|
1348
|
+
def __repr__(self):
|
|
1349
|
+
# Optionally, override __repr__ so that when printed the class appears as FlatLambdaCDM.
|
|
1350
|
+
base_repr = super().__repr__()
|
|
1351
|
+
return base_repr.replace(self.__class__.__name__, "FlatLambdaCDM", 1)
|
|
1352
|
+
|
|
1353
|
+
def set_luminosity_distance(self, dl):
|
|
1354
|
+
"""
|
|
1355
|
+
Set (or update) the user-specified luminosity distance.
|
|
1119
1356
|
|
|
1120
|
-
|
|
1121
|
-
|
|
1357
|
+
Parameters
|
|
1358
|
+
----------
|
|
1359
|
+
dl : astropy.units.Quantity
|
|
1360
|
+
The new luminosity distance.
|
|
1361
|
+
"""
|
|
1362
|
+
self.dl = dl
|
|
1122
1363
|
|
|
1123
|
-
def set_luminosity_distance(cls, dl):
|
|
1124
|
-
cls.dl = dl
|
|
1125
|
-
|
|
1126
1364
|
def luminosity_distance(self, redshift):
|
|
1365
|
+
"""
|
|
1366
|
+
Return the user-specified luminosity distance, ignoring the redshift.
|
|
1367
|
+
|
|
1368
|
+
Parameters
|
|
1369
|
+
----------
|
|
1370
|
+
redshift : float or array-like
|
|
1371
|
+
Redshift (ignored).
|
|
1372
|
+
|
|
1373
|
+
Returns
|
|
1374
|
+
-------
|
|
1375
|
+
astropy.units.Quantity
|
|
1376
|
+
The user-specified luminosity distance.
|
|
1377
|
+
"""
|
|
1127
1378
|
return self.dl
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: redback
|
|
3
|
-
Version: 1.
|
|
4
|
-
Summary: A Bayesian inference pipeline for electromagnetic transients
|
|
3
|
+
Version: 1.1
|
|
4
|
+
Summary: A Bayesian inference and modelling pipeline for electromagnetic transients
|
|
5
5
|
Home-page: https://github.com/nikhil-sarin/redback
|
|
6
6
|
Author: Nikhil Sarin, Moritz Huebner
|
|
7
7
|
Author-email: nsarin.astro@gmail.com
|
|
@@ -31,6 +31,7 @@ Requires-Dist: afterglowpy
|
|
|
31
31
|
Provides-Extra: all
|
|
32
32
|
Requires-Dist: nestle; extra == "all"
|
|
33
33
|
Requires-Dist: sherpa; extra == "all"
|
|
34
|
+
Requires-Dist: george; extra == "all"
|
|
34
35
|
Requires-Dist: scikit-learn; extra == "all"
|
|
35
36
|
Requires-Dist: PyQt5; extra == "all"
|
|
36
37
|
Requires-Dist: lalsuite; extra == "all"
|
|
@@ -45,6 +46,7 @@ Dynamic: description
|
|
|
45
46
|
Dynamic: description-content-type
|
|
46
47
|
Dynamic: home-page
|
|
47
48
|
Dynamic: license
|
|
49
|
+
Dynamic: license-file
|
|
48
50
|
Dynamic: provides-extra
|
|
49
51
|
Dynamic: requires-dist
|
|
50
52
|
Dynamic: requires-python
|
|
@@ -56,7 +58,7 @@ Dynamic: summary
|
|
|
56
58
|

|
|
57
59
|
[](https://arxiv.org/abs/2308.12806)
|
|
58
60
|
# Redback
|
|
59
|
-
Introducing REDBACK,
|
|
61
|
+
Introducing REDBACK, A software package for end-to-end modelling, fitting, and interpretation of electromagnetic transients via Bayesian Inference
|
|
60
62
|
|
|
61
63
|
### Online documentation
|
|
62
64
|
|
|
@@ -67,12 +69,12 @@ Introducing REDBACK, a bayesian inference software package for fitting electroma
|
|
|
67
69
|
|
|
68
70
|
### Motivation and why redback might be useful to you.
|
|
69
71
|
The launch of new telescopes/surveys is leading to an explosion of transient observations.
|
|
70
|
-
Redback is a software package for end-to-end interpretation and parameter estimation of these transients.
|
|
72
|
+
Redback is a software package for modelling, end-to-end interpretation and parameter estimation of these transients.
|
|
71
73
|
|
|
72
74
|
- Download data for supernovae, tidal disruption events, gamma-ray burst afterglows, kilonovae, prompt emission from
|
|
73
75
|
different catalogs/telescopes; Swift, BATSE, Open access catalogs, FINK and LASAIR brokers.
|
|
74
76
|
Users can also provide their own data or use simulated data
|
|
75
|
-
- Redback processes the data into a homogeneous transient object. Making it easy to plot lightcurves and do any other processing.
|
|
77
|
+
- Redback processes the data into a homogeneous transient object. Making it easy to plot lightcurves and do any other processing e.g., estimating bolometric luminosities or blackbody properties.
|
|
76
78
|
- The user can then fit one of the models implemented in redback. Or fit their own model. Models for several different types of electromagnetic transients are implemented and range from simple analytical models to numerical surrogates.
|
|
77
79
|
- All models are implemented as functions and can be used to simulate populations, without needing to provide data. This way redback can be used simply as a tool to simulate realistic populations, no need to actually fit anything.
|
|
78
80
|
- Simulate realistic transient lightcurves for Rubin LSST Survey using the latest cadence tables and for ZTF. Or make your own survey.
|