redback 1.0.31__py3-none-any.whl → 1.12.0__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 (50) hide show
  1. redback/__init__.py +3 -2
  2. redback/analysis.py +321 -4
  3. redback/filters.py +57 -23
  4. redback/get_data/directory.py +18 -0
  5. redback/likelihoods.py +260 -0
  6. redback/model_library.py +12 -2
  7. redback/plotting.py +335 -4
  8. redback/priors/blackbody_spectrum_with_absorption_and_emission_lines.prior +9 -0
  9. redback/priors/csm_shock_and_arnett_two_rphots.prior +11 -0
  10. redback/priors/exp_rise_powerlaw_decline.prior +6 -0
  11. redback/priors/powerlaw_spectrum_with_absorption_and_emission_lines.prior +8 -0
  12. redback/priors/salt2.prior +6 -0
  13. redback/priors/shock_cooling_and_arnett_bolometric.prior +11 -0
  14. redback/priors/shockcooling_morag.prior +6 -0
  15. redback/priors/shockcooling_morag_and_arnett.prior +10 -0
  16. redback/priors/shockcooling_morag_and_arnett_bolometric.prior +9 -0
  17. redback/priors/shockcooling_morag_bolometric.prior +5 -0
  18. redback/priors/shockcooling_sapirandwaxman.prior +6 -0
  19. redback/priors/shockcooling_sapirandwaxman_bolometric.prior +5 -0
  20. redback/priors/shockcooling_sapirwaxman_and_arnett.prior +10 -0
  21. redback/priors/shockcooling_sapirwaxman_and_arnett_bolometric.prior +9 -0
  22. redback/priors/shocked_cocoon_and_arnett.prior +13 -0
  23. redback/priors/synchrotron_ism.prior +6 -0
  24. redback/priors/synchrotron_massloss.prior +6 -0
  25. redback/priors/synchrotron_pldensity.prior +7 -0
  26. redback/priors/thermal_synchrotron_v2_fluxdensity.prior +8 -0
  27. redback/priors/thermal_synchrotron_v2_lnu.prior +7 -0
  28. redback/priors.py +10 -3
  29. redback/result.py +9 -1
  30. redback/sampler.py +46 -4
  31. redback/sed.py +48 -1
  32. redback/simulate_transients.py +5 -1
  33. redback/tables/filters.csv +265 -254
  34. redback/transient/__init__.py +2 -3
  35. redback/transient/transient.py +648 -10
  36. redback/transient_models/__init__.py +3 -2
  37. redback/transient_models/extinction_models.py +3 -2
  38. redback/transient_models/gaussianprocess_models.py +45 -0
  39. redback/transient_models/general_synchrotron_models.py +296 -6
  40. redback/transient_models/phenomenological_models.py +154 -7
  41. redback/transient_models/shock_powered_models.py +503 -40
  42. redback/transient_models/spectral_models.py +82 -0
  43. redback/transient_models/supernova_models.py +405 -31
  44. redback/transient_models/tde_models.py +57 -41
  45. redback/utils.py +302 -51
  46. {redback-1.0.31.dist-info → redback-1.12.0.dist-info}/METADATA +8 -6
  47. {redback-1.0.31.dist-info → redback-1.12.0.dist-info}/RECORD +50 -29
  48. {redback-1.0.31.dist-info → redback-1.12.0.dist-info}/WHEEL +1 -1
  49. {redback-1.0.31.dist-info → redback-1.12.0.dist-info/licenses}/LICENCE.md +0 -0
  50. {redback-1.0.31.dist-info → redback-1.12.0.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 == None:
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/-2.5)
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 calc_flux_density_error_from_monochromatic_magnitude(magnitude, magnitude_error, reference_flux, magnitude_system='AB'):
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/-2.5)
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
- Calculate the median and error bar of a one dimensional array of samples
772
+ Calculates the median and error bars for a one-dimensional sample array.
579
773
 
580
- :param samples: samples array
581
- :param quantiles: quantiles to calculate
582
- :param fmt: latex fmt
583
- :return: summary named tuple
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
- summary = namedtuple('summary', ['median', 'lower', 'upper', 'string'])
793
+ MedianErrorBarResult = namedtuple('MedianErrorBarResult', ['median', 'lower', 'upper', 'string'])
586
794
 
587
- if len(quantiles) != 2:
588
- raise ValueError("quantiles must be of length 2")
795
+ if len(samples) == 0:
796
+ raise ValueError("Samples array cannot be empty.")
589
797
 
590
- quants_to_compute = np.array([quantiles[0], 0.5, quantiles[1]])
591
- quants = np.percentile(samples, quants_to_compute * 100)
592
- summary.median = quants[1]
593
- summary.plus = quants[2] - summary.median
594
- summary.minus = summary.median - quants[0]
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
- [0.56, 1.31, 2.19, 3.0], [.27, .55, .95, 2.0],
779
- [0.20, 0.39, 0.65, 0.9]])
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
- [0.17, 0.21, 0.31, 0.45], [0.10, 0.13, 0.15, 0.17],
782
- [0.06, 0.11, 0.12, 0.12]])
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
- [0.74, 1.13, 1.32, 1.4], [0.6, 0.9, 1.13, 1.25],
785
- [0.63, 0.79, 1.04, 1.5]])
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
- class user_cosmology():
1324
+
1325
+ class UserCosmology(FlatLambdaCDM):
1113
1326
  """
1114
- Cosmology class similar to the Astropy cosmology class.
1115
- Needed if the user wants to provide a distance instead
1116
- of using the luminosity distance inferred from a particular
1117
- cosmology model.
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
- def __init__(self, dl=0):
1121
- self.dl = 0
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.2
1
+ Metadata-Version: 2.4
2
2
  Name: redback
3
- Version: 1.0.31
4
- Summary: A Bayesian inference pipeline for electromagnetic transients
3
+ Version: 1.12.0
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
  ![PyPI](https://img.shields.io/pypi/v/redback)
57
59
  [![arXiv](https://img.shields.io/badge/arXiv-2308.12806-00ff00.svg)](https://arxiv.org/abs/2308.12806)
58
60
  # Redback
59
- Introducing REDBACK, a bayesian inference software package for fitting electromagnetic transients
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.