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
@@ -21,7 +21,7 @@ homologous_expansion_models = ['exponential_powerlaw_bolometric', 'arnett_bolome
21
21
  'type_1c_bolometric','type_1a_bolometric']
22
22
 
23
23
  @citation_wrapper('https://zenodo.org/record/6363879#.YkQn3y8RoeY')
24
- def sncosmo_models(time, redshift, model_kwargs, **kwargs):
24
+ def sncosmo_models(time, redshift, model_kwargs=None, **kwargs):
25
25
  """
26
26
  A wrapper to SNCosmo models
27
27
 
@@ -33,28 +33,36 @@ def sncosmo_models(time, redshift, model_kwargs, **kwargs):
33
33
  :param sncosmo_model: String of the SNcosmo model to use.
34
34
  :param peak_time: SNe peak time in days
35
35
  :param cosmology: astropy cosmology object by default set to Planck18
36
- :param peak_abs_mag: SNe peak absolute magnitude default set to -19
37
- :param peak_abs_mag_band: Band corresponding to the peak abs mag limit, default to standard::b. Must be in SNCosmo
38
36
  :param mw_extinction: Boolean for whether there is MW extinction or not. Default True
39
- :param magnitude_system: Mag system; default ab
40
37
  :param host_extinction: Boolean for whether there is host extinction or not. Default True
41
38
  if used adds an extra parameter ebv which must also be in kwargs; host galaxy E(B-V). Set to 0.1 by default
39
+ :param use_set_peak_magnitude: Boolean for whether to set the peak magnitude or not. Default False,
40
+ if True the following keyword arguments also apply. Else the brightness is set by the model_kwargs.
41
+ :param peak_abs_mag: SNe peak absolute magnitude default set to -19
42
+ :param peak_abs_mag_band: Band corresponding to the peak abs mag limit, default to standard::b. Must be in SNCosmo
43
+ :param magnitude_system: Mag system; default ab
42
44
  :return: set by output format - 'flux_density', 'magnitude', 'flux', 'sncosmo_source'
43
45
  """
44
46
  import sncosmo
45
- cosmology = kwargs.get('cosmology', cosmo)
46
47
  peak_time = kwargs.get('peak_time', 0)
47
- peak_abs_mag = kwargs.get('peak_abs_mag', -19)
48
- peak_abs_mag_band = kwargs.get('peak_abs_mag_band', 'standard::b')
48
+ cosmology = kwargs.get('cosmology', cosmo)
49
49
  model_name = kwargs.get('sncosmo_model', 'salt2')
50
50
  host_extinction = kwargs.get('host_extinction', True)
51
51
  mw_extinction = kwargs.get('mw_extinction', True)
52
- magsystem = kwargs.get('magnitude_system', 'ab')
52
+ use_set_peak_magnitude = kwargs.get('use_set_peak_magnitude', False)
53
53
 
54
54
  model = sncosmo.Model(source=model_name)
55
55
  model.set(z=redshift)
56
56
  model.set(t0=peak_time)
57
- model.update(model_kwargs)
57
+
58
+ if model_kwargs == None:
59
+ _model_kwargs = {}
60
+ for x in kwargs['model_kwarg_names']:
61
+ _model_kwargs[x] = kwargs[x]
62
+ else:
63
+ _model_kwargs = model_kwargs
64
+
65
+ model.update(_model_kwargs)
58
66
 
59
67
  if host_extinction:
60
68
  ebv = kwargs.get('ebv', 0.1)
@@ -63,13 +71,21 @@ def sncosmo_models(time, redshift, model_kwargs, **kwargs):
63
71
  if mw_extinction:
64
72
  model.add_effect(sncosmo.F99Dust(), 'mw', 'obs')
65
73
 
66
- model.set_source_peakabsmag(peak_abs_mag, band=peak_abs_mag_band, magsys=magsystem, cosmo=cosmology)
74
+ if use_set_peak_magnitude:
75
+ peak_abs_mag = kwargs.get('peak_abs_mag', -19)
76
+ peak_abs_mag_band = kwargs.get('peak_abs_mag_band', 'standard::b')
77
+ magsystem = kwargs.get('magnitude_system', 'ab')
78
+ model.set_source_peakabsmag(peak_abs_mag, band=peak_abs_mag_band, magsys=magsystem, cosmo=cosmology)
67
79
 
68
80
  if kwargs['output_format'] == 'flux_density':
69
81
  frequency = kwargs['frequency']
70
82
 
83
+ if isinstance(frequency, float):
84
+ frequency = np.array([frequency])
85
+
71
86
  if (len(frequency) != 1 or len(frequency) == len(time)):
72
87
  raise ValueError('frequency array must be of length 1 or same size as time array')
88
+
73
89
  unique_frequency = np.sort(np.unique(frequency))
74
90
  angstroms = nu_to_lambda(unique_frequency)
75
91
 
@@ -90,11 +106,11 @@ def sncosmo_models(time, redshift, model_kwargs, **kwargs):
90
106
 
91
107
  if kwargs['output_format'] == 'flux':
92
108
  bands = kwargs['bands']
93
- magnitude = model.bandmag(phase=time, band=bands, magsys='ab')
109
+ magnitude = model.bandmag(time=time, band=bands, magsys='ab')
94
110
  return sed.bandpass_magnitude_to_flux(magnitude=magnitude, bands=bands)
95
111
  elif kwargs['output_format'] == 'magnitude':
96
112
  bands = kwargs['bands']
97
- magnitude = model.bandmag(phase=time, band=bands, magsys='ab')
113
+ magnitude = model.bandmag(time=time, band=bands, magsys='ab')
98
114
  return magnitude
99
115
  elif kwargs['output_format'] == 'sncosmo_source':
100
116
  return model
@@ -874,11 +890,9 @@ def _csm_engine(time, mej, csm_mass, vej, eta, rho, kappa, r0, **kwargs):
874
890
  # scaling constant for CSM density profile
875
891
  qq = rho * r0 ** eta
876
892
  # outer CSM shell radius
877
- radius_csm = ((3.0 - eta) / (4.0 * np.pi * qq) * csm_mass + r0 ** (3.0 - eta)) ** (
878
- 1.0 / (3.0 - eta))
893
+ radius_csm = ((3.0 - eta) / (4.0 * np.pi * qq) * csm_mass + r0 ** (3.0 - eta)) ** (1.0 / (3.0 - eta))
879
894
  # photosphere radius
880
- r_photosphere = abs((-2.0 * (1.0 - eta) / (3.0 * kappa * qq) +
881
- radius_csm ** (1.0 - eta)) ** (1.0 / (1.0 - eta)))
895
+ r_photosphere = abs((-2.0 * (1.0 - eta) / (3.0 * kappa * qq) + radius_csm ** (1.0 - eta)) ** (1.0 / (1.0 - eta)))
882
896
 
883
897
  # mass of the optically thick CSM (tau > 2/3).
884
898
  mass_csm_threshold = np.abs(4.0 * np.pi * qq / (3.0 - eta) * (
@@ -904,20 +918,19 @@ def _csm_engine(time, mej, csm_mass, vej, eta, rho, kappa, r0, **kwargs):
904
918
  (3.0 - nn) * g_n)) ** (1.0 / (3.0 - nn))) ** (
905
919
  (nn - eta) / (eta - 3.0))
906
920
 
907
- mask_1 = t_FS - time * day_to_s > 0
908
- mask_2 = t_RS - time * day_to_s > 0
921
+ mask_RS = t_RS - time * day_to_s > 0
922
+ mask_FS = t_FS - time * day_to_s > 0
909
923
 
910
- lbol = efficiency * (2.0 * np.pi / (nn - eta) ** 3 * g_n ** ((5.0 - eta) / (nn - eta)) * qq **
911
- ((nn - 5.0) / (nn - eta)) * (nn - 3.0) ** 2 * (nn - 5.0) * Bf ** (5.0 - eta) * AA **
912
- ((5.0 - eta) / (nn - eta)) * (time * day_to_s + ti) **
913
- ((2.0 * nn + 6.0 * eta - nn * eta - 15.) /
914
- (nn - eta)) + 2.0 * np.pi * (AA * g_n / qq) **
915
- ((5.0 - nn) / (nn - eta)) * Br ** (5.0 - nn) * g_n * ((3.0 - eta) / (nn - eta)) ** 3 * (
916
- time * day_to_s + ti) **
917
- ((2.0 * nn + 6.0 * eta - nn * eta - 15.0) / (nn - eta)))
924
+ lbol_FS = 2.0 * np.pi / (nn - eta) ** 3 * g_n ** ((5.0 - eta) / (nn - eta)) * qq ** ((nn - 5.0) / (nn - eta)) \
925
+ * (nn - 3.0) ** 2 * (nn - 5.0) * Bf ** (5.0 - eta) * AA ** ((5.0 - eta) / (nn - eta)) * (time * day_to_s + ti) \
926
+ ** ((2.0 * nn + 6.0 * eta - nn * eta - 15.) / (nn - eta))
918
927
 
919
- lbol[~mask_1] = 0
920
- lbol[~mask_2] = 0
928
+ lbol_RS = 2.0 * np.pi * (AA * g_n / qq) ** ((5.0 - nn) / (nn - eta)) * Br ** (5.0 - nn) * g_n * ((3.0 - eta) / (nn - eta)) \
929
+ ** 3 * (time * day_to_s + ti) ** ((2.0 * nn + 6.0 * eta - nn * eta - 15.0) / (nn - eta))
930
+ lbol_FS[~mask_FS] = 0
931
+ lbol_RS[~mask_RS] = 0
932
+
933
+ lbol = efficiency * (lbol_FS + lbol_RS)
921
934
 
922
935
  csm_output = namedtuple('csm_output', ['lbol', 'r_photosphere', 'mass_csm_threshold'])
923
936
  csm_output.lbol = lbol
@@ -926,7 +939,7 @@ def _csm_engine(time, mej, csm_mass, vej, eta, rho, kappa, r0, **kwargs):
926
939
  return csm_output
927
940
 
928
941
 
929
- @citation_wrapper('redback')
942
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2013ApJ...773...76C/abstract, https://ui.adsabs.harvard.edu/abs/2017ApJ...849...70V/abstract, https://ui.adsabs.harvard.edu/abs/2020RNAAS...4...16J/abstract')
930
943
  def csm_interaction_bolometric(time, mej, csm_mass, vej, eta, rho, kappa, r0, **kwargs):
931
944
  """
932
945
  :param time: time in days in source frame
@@ -951,14 +964,15 @@ def csm_interaction_bolometric(time, mej, csm_mass, vej, eta, rho, kappa, r0, **
951
964
  csm_output = _csm_engine(time=time, mej=mej, csm_mass=csm_mass, vej=vej,
952
965
  eta=eta, rho=rho, kappa=kappa, r0=r0, **kwargs)
953
966
  lbol = csm_output.lbol
954
- r_photosphere = csm_output.r_photosphere
955
- mass_csm_threshold = csm_output.mass_csm_threshold
956
967
 
957
968
  if _interaction_process is not None:
958
969
  dense_resolution = kwargs.get("dense_resolution", 1000)
959
- dense_times = np.linspace(0, time[-1]+100, dense_resolution)
960
- dense_lbols = _csm_engine(time=dense_times, mej=mej, csm_mass=csm_mass, vej=vej,
961
- eta=eta, rho=rho, kappa=kappa, r0=r0, **kwargs).lbol
970
+ dense_times = np.geomspace(0.1, time[-1]+100, dense_resolution)
971
+ csm_output = _csm_engine(time=dense_times, mej=mej, csm_mass=csm_mass, vej=vej,
972
+ eta=eta, rho=rho, kappa=kappa, r0=r0, **kwargs)
973
+ dense_lbols = csm_output.lbol
974
+ r_photosphere = csm_output.r_photosphere
975
+ mass_csm_threshold = csm_output.mass_csm_threshold
962
976
  interaction_class = _interaction_process(time=time, dense_times=dense_times, luminosity=dense_lbols,
963
977
  kappa=kappa, r_photosphere=r_photosphere,
964
978
  mass_csm_threshold=mass_csm_threshold, csm_mass=csm_mass, **kwargs)
@@ -966,7 +980,7 @@ def csm_interaction_bolometric(time, mej, csm_mass, vej, eta, rho, kappa, r0, **
966
980
  return lbol
967
981
 
968
982
 
969
- @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2013ApJ...773...76C/abstract')
983
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2013ApJ...773...76C/abstract, https://ui.adsabs.harvard.edu/abs/2017ApJ...849...70V/abstract, https://ui.adsabs.harvard.edu/abs/2020RNAAS...4...16J/abstract')
970
984
  def csm_interaction(time, redshift, mej, csm_mass, vej, eta, rho, kappa, r0, **kwargs):
971
985
  """
972
986
  :param time: time in days in observer frame
@@ -1017,7 +1031,7 @@ def csm_interaction(time, redshift, mej, csm_mass, vej, eta, rho, kappa, r0, **k
1017
1031
  else:
1018
1032
  time_obs = time
1019
1033
  lambda_observer_frame = kwargs.get('lambda_array', np.geomspace(100, 60000, 100))
1020
- time_temp = np.geomspace(0.1, 3000, 300) # in days
1034
+ time_temp = np.linspace(0.1, 500, 300) # in days
1021
1035
  time_observer_frame = time_temp * (1. + redshift)
1022
1036
  frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
1023
1037
  redshift=redshift, time=time_observer_frame)
@@ -262,6 +262,8 @@ def gaussianrise_cooling_envelope_bolometric(time, peak_time, sigma_t, mbh_6, st
262
262
  bolometric version for fitting the bolometric lightcurve
263
263
 
264
264
  :param time: time in source frame in days
265
+ :param peak_time: peak time in days
266
+ :param sigma_t: the sharpness of the Gaussian in days
265
267
  :param mbh_6: mass of supermassive black hole in units of 10^6 solar mass
266
268
  :param stellar_mass: stellar mass in units of solar masses
267
269
  :param eta: SMBH feedback efficiency (typical range: etamin - 0.1)
@@ -299,6 +301,8 @@ def gaussianrise_cooling_envelope(time, redshift, peak_time, sigma_t, mbh_6, ste
299
301
 
300
302
  :param time: time in observer frame in days
301
303
  :param redshift: redshift
304
+ :param peak_time: peak time in days
305
+ :param sigma_t: the sharpness of the Gaussian in days
302
306
  :param mbh_6: mass of supermassive black hole in units of 10^6 solar mass
303
307
  :param stellar_mass: stellar mass in units of solar masses
304
308
  :param eta: SMBH feedback efficiency (typical range: etamin - 0.1)
@@ -408,6 +412,127 @@ def gaussianrise_cooling_envelope(time, redshift, peak_time, sigma_t, mbh_6, ste
408
412
  output.append(flux_den_interp_func[freq](tt * cc.day_to_s))
409
413
  return np.array(output)
410
414
 
415
+ @citation_wrapper('https://arxiv.org/abs/2307.15121,https://ui.adsabs.harvard.edu/abs/2022arXiv220707136M/abstract')
416
+ def bpl_cooling_envelope(time, redshift, peak_time, alpha_1, alpha_2, mbh_6, stellar_mass, eta, alpha, beta, **kwargs):
417
+ """
418
+ Full lightcurve, with gaussian rise till fallback time and then the metzger tde model,
419
+ photometric version where each band is fit/joint separately
420
+
421
+ :param time: time in observer frame in days
422
+ :param redshift: redshift
423
+ :param peak_time: peak time in days
424
+ :param alpha_1: power law index for first power law
425
+ :param alpha_2: power law index for second power law (should be positive)
426
+ :param mbh_6: mass of supermassive black hole in units of 10^6 solar mass
427
+ :param stellar_mass: stellar mass in units of solar masses
428
+ :param eta: SMBH feedback efficiency (typical range: etamin - 0.1)
429
+ :param alpha: disk viscosity
430
+ :param beta: TDE penetration factor (typical range: 1 - beta_max)
431
+ :param kwargs: Additional parameters
432
+ :param xi: Optional argument (default set to one) to change the point where lightcurve switches from Gaussian rise to cooling envelope.
433
+ stitching_point = xi * tfb (where tfb is fallback time). So a xi=1 means the stitching point is at fallback time.
434
+ :param frequency: Required if output_format is 'flux_density'.
435
+ frequency to calculate - Must be same length as time array or a single number).
436
+ :param bands: Required if output_format is 'magnitude' or 'flux'.
437
+ :param output_format: 'flux_density', 'magnitude', 'flux'
438
+ :param lambda_array: Optional argument to set your desired wavelength array (in Angstroms) to evaluate the SED on.
439
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
440
+ :return: set by output format - 'flux_density', 'magnitude', 'flux'
441
+ """
442
+ binding_energy_const = kwargs.get('binding_energy_const', 0.8)
443
+ tfb_sf = calc_tfb(binding_energy_const, mbh_6, stellar_mass) # source frame
444
+ tfb_obf = tfb_sf * (1. + redshift) # observer frame
445
+ xi = kwargs.get('xi', 1.)
446
+ output = _cooling_envelope(mbh_6, stellar_mass, eta, alpha, beta, **kwargs)
447
+ cosmology = kwargs.get('cosmology', cosmo)
448
+ dl = cosmology.luminosity_distance(redshift).cgs.value
449
+ stitching_point = xi * tfb_obf
450
+
451
+ # normalisation term in observer frame
452
+ f1 = pm.exponential_powerlaw(time=stitching_point, a_1=1., tpeak=peak_time * cc.day_to_s,
453
+ alpha_1=alpha_1, alpha_2=alpha_2)
454
+
455
+ if kwargs['output_format'] == 'flux_density':
456
+ frequency = kwargs['frequency']
457
+ if isinstance(frequency, float):
458
+ frequency = np.ones(len(time)) * frequency
459
+
460
+ # convert to source frame time and frequency
461
+ frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
462
+ unique_frequency = np.sort(np.unique(frequency))
463
+
464
+ # source frame
465
+ f2 = sed.blackbody_to_flux_density(temperature=output.photosphere_temperature[0],
466
+ r_photosphere=output.photosphere_radius[0],
467
+ dl=dl, frequency=unique_frequency).to(uu.mJy)
468
+ norms = f2.value / f1
469
+ norm_dict = dict(zip(unique_frequency, norms))
470
+
471
+ # build flux density function for each frequency
472
+ flux_den_interp_func = {}
473
+ for freq in unique_frequency:
474
+ tt_pre_fb = np.linspace(0, stitching_point / cc.day_to_s, 200) * cc.day_to_s
475
+ tt_post_fb = xi * (output.time_temp * (1 + redshift))
476
+ total_time = np.concatenate([tt_pre_fb, tt_post_fb])
477
+ f1 = pm.exponential_powerlaw(time=tt_pre_fb, a_1=norm_dict[freq],
478
+ tpeak=peak_time * cc.day_to_s, alpha_1=alpha_1, alpha_2=alpha_2)
479
+ f2 = sed.blackbody_to_flux_density(temperature=output.photosphere_temperature,
480
+ r_photosphere=output.photosphere_radius,
481
+ dl=dl, frequency=freq).to(uu.mJy)
482
+ flux_den = np.concatenate([f1, f2.value])
483
+ flux_den_interp_func[freq] = interp1d(total_time, flux_den, fill_value='extrapolate')
484
+
485
+ # interpolate onto actual observed frequency and time values
486
+ flux_density = []
487
+ for freq, tt in zip(frequency, time):
488
+ flux_density.append(flux_den_interp_func[freq](tt * cc.day_to_s))
489
+ flux_density = flux_density * uu.mJy
490
+ return flux_density.to(uu.mJy).value
491
+ else:
492
+ bands = kwargs['bands']
493
+ if isinstance(bands, str):
494
+ bands = [str(bands) for x in range(len(time))]
495
+
496
+ unique_bands = np.unique(bands)
497
+ temp_kwargs = kwargs.copy()
498
+ temp_kwargs['bands'] = unique_bands
499
+ f2 = cooling_envelope(time=0., redshift=redshift,
500
+ mbh_6=mbh_6, stellar_mass=stellar_mass, eta=eta, alpha=alpha, beta=beta,
501
+ **temp_kwargs)
502
+ if kwargs['output_format'] == 'magnitude':
503
+ # make the normalisation in fmjy to avoid magnitude normalisation problems
504
+ _f2mjy = calc_flux_density_from_ABmag(f2).value
505
+ norms = _f2mjy / f1
506
+ else:
507
+ norms = f2 / f1
508
+
509
+ if isinstance(norms, float):
510
+ norms = np.ones(len(time)) * norms
511
+ norm_dict = dict(zip(unique_bands, norms))
512
+
513
+ flux_den_interp_func = {}
514
+ for band in unique_bands:
515
+ tt_pre_fb = np.linspace(0, stitching_point / cc.day_to_s, 100) * cc.day_to_s
516
+ tt_post_fb = output.time_temp * (1 + redshift)
517
+ total_time = np.concatenate([tt_pre_fb, tt_post_fb])
518
+ f1 = pm.exponential_powerlaw(time=tt_pre_fb, a_1=norm_dict[band],
519
+ tpeak=peak_time * cc.day_to_s, alpha_1=alpha_1, alpha_2=alpha_2)
520
+ if kwargs['output_format'] == 'magnitude':
521
+ f1 = calc_ABmag_from_flux_density(f1).value
522
+ temp_kwargs = kwargs.copy()
523
+ temp_kwargs['bands'] = band
524
+ f2 = cooling_envelope(time=output.time_since_fb / cc.day_to_s, redshift=redshift,
525
+ mbh_6=mbh_6, stellar_mass=stellar_mass, eta=eta, alpha=alpha, beta=beta,
526
+ **temp_kwargs)
527
+ flux_den = np.concatenate([f1, f2])
528
+ flux_den_interp_func[band] = interp1d(total_time, flux_den, fill_value='extrapolate')
529
+
530
+ # interpolate onto actual observed band and time values
531
+ output = []
532
+ for freq, tt in zip(bands, time):
533
+ output.append(flux_den_interp_func[freq](tt * cc.day_to_s))
534
+ return np.array(output)
535
+
411
536
  @citation_wrapper('redback')
412
537
  def tde_analytical_bolometric(time, l0, t_0_turn, **kwargs):
413
538
  """
@@ -471,7 +596,7 @@ def tde_analytical(time, redshift, l0, t_0_turn, **kwargs):
471
596
  else:
472
597
  time_obs = time
473
598
  lambda_observer_frame = kwargs.get('lambda_array', np.geomspace(100, 60000, 100))
474
- time_temp = np.geomspace(0.1, 300, 200) # in days
599
+ time_temp = np.geomspace(0.1, 1000, 300) # in days
475
600
  time_observer_frame = time_temp * (1. + redshift)
476
601
  frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
477
602
  redshift=redshift, time=time_observer_frame)
redback/utils.py CHANGED
@@ -44,7 +44,7 @@ def download_pointing_tables():
44
44
  """
45
45
  return logger.info("Pointing tables downloaded and stored in redback/tables")
46
46
 
47
- def sncosmo_bandname_from_band(bands, warning_style='soft'):
47
+ def sncosmo_bandname_from_band(bands, warning_style='softest'):
48
48
  """
49
49
  Convert redback data band names to sncosmo compatible band names
50
50
 
@@ -65,12 +65,14 @@ def sncosmo_bandname_from_band(bands, warning_style='soft'):
65
65
  try:
66
66
  res.append(bands_to_flux[band])
67
67
  except KeyError as e:
68
- logger.info(e)
69
68
  if warning_style == 'hard':
70
69
  raise KeyError(f"Band {band} is not defined in filters.csv!")
71
- else:
70
+ elif warning_style == 'soft':
71
+ logger.info(e)
72
72
  logger.info(f"Band {band} is not defined in filters.csv!")
73
73
  res.append('r')
74
+ else:
75
+ res.append('r')
74
76
  return np.array(res)
75
77
 
76
78
  def check_kwargs_validity(kwargs):
@@ -374,7 +376,7 @@ def check_element(driver, id_number):
374
376
  checks that an element exists on a website, and provides an exception
375
377
  """
376
378
  try:
377
- driver.find_element_by_id(id_number)
379
+ driver.find_element('id', id_number)
378
380
  except NoSuchElementException as e:
379
381
  print(e)
380
382
  return False
@@ -549,7 +551,10 @@ def frequency_to_bandname(frequency):
549
551
 
550
552
  def fetch_driver():
551
553
  # open the webdriver
552
- return webdriver.PhantomJS()
554
+ options = webdriver.ChromeOptions()
555
+ options.add_argument("--headless=new")
556
+ driver = webdriver.Chrome(options=options)
557
+ return driver
553
558
 
554
559
 
555
560
  def calc_credible_intervals(samples, interval=0.9):
@@ -785,6 +790,265 @@ def interpolated_barnes_and_kasen_thermalisation_efficiency(mej, vej):
785
790
  return av, bv, dv
786
791
 
787
792
 
793
+ def heatinggrids():
794
+ # Grid of velocity and Ye
795
+ YE_GRID = np.array([0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5], dtype=np.float64)
796
+ V_GRID = np.array([0.05, 0.1, 0.2, 0.3, 0.4, 0.5], dtype=np.float64)
797
+
798
+ # Approximant coefficients on the grid
799
+ E0_GRID = np.array([
800
+ 1.000, 1.000, 1.000, 1.000, 1.000, 1.000,
801
+ 1.000, 1.000, 1.041, 1.041, 1.041, 1.041,
802
+ 1.146, 1.000, 1.041, 1.041, 1.041, 1.041,
803
+ 1.146, 1.000, 1.000, 1.000, 1.041, 1.041,
804
+ 1.301, 1.398, 1.602, 1.580, 1.763, 1.845,
805
+ 0.785, 1.255, 1.673, 1.673, 1.874, 1.874,
806
+ 0.863, 0.845, 1.212, 1.365, 1.635, 2.176,
807
+ -2.495, -2.495, -2.097, -2.155, -2.046, -1.824,
808
+ -0.699, -0.699, -0.222, 0.176, 0.176, 0.176,
809
+ -0.398, 0.000, 0.301, 0.477, 0.477, 0.477], dtype=np.float64)
810
+
811
+ # Reshape GRIDs to a 2D array
812
+ E0_GRID = E0_GRID.reshape((len(V_GRID), len(YE_GRID)), order='F')
813
+
814
+ # ALP_GRID
815
+ ALP_GRID = np.array([
816
+ 1.37, 1.38, 1.41, 1.41, 1.41, 1.41,
817
+ 1.41, 1.38, 1.37, 1.37, 1.37, 1.37,
818
+ 1.41, 1.38, 1.37, 1.37, 1.37, 1.37,
819
+ 1.36, 1.25, 1.32, 1.32, 1.34, 1.34,
820
+ 1.44, 1.40, 1.46, 1.66, 1.60, 1.60,
821
+ 1.36, 1.33, 1.33, 1.33, 1.374, 1.374,
822
+ 1.40, 1.358, 1.384, 1.384, 1.384, 1.344,
823
+ 1.80, 1.80, 2.10, 2.10, 1.90, 1.90,
824
+ 8.00, 8.00, 7.00, 7.00, 7.00, 7.00,
825
+ 1.40, 1.40, 1.40, 1.60, 1.60, 1.60
826
+ ], dtype=np.float64)
827
+
828
+ ALP_GRID = ALP_GRID.reshape((len(V_GRID), len(YE_GRID)), order='F')
829
+
830
+ # T0_GRID
831
+ T0_GRID = np.array([
832
+ 1.80, 1.40, 1.20, 1.20, 1.20, 1.20,
833
+ 1.40, 1.00, 0.85, 0.85, 0.85, 0.85,
834
+ 1.00, 0.80, 0.65, 0.65, 0.61, 0.61,
835
+ 0.85, 0.60, 0.45, 0.45, 0.45, 0.45,
836
+ 0.65, 0.38, 0.22, 0.18, 0.12, 0.095,
837
+ 0.540, 0.31, 0.18, 0.13, 0.095, 0.081,
838
+ 0.385, 0.235, 0.1, 0.06, 0.035, 0.025,
839
+ 26.0, 26.0, 0.4, 0.4, 0.12, -20.0,
840
+ 0.20, 0.12, 0.05, 0.03, 0.025, 0.021,
841
+ 0.16, 0.08, 0.04, 0.02, 0.018, 0.016
842
+ ], dtype=np.float64)
843
+
844
+ T0_GRID = T0_GRID.reshape((len(V_GRID), len(YE_GRID)), order='F')
845
+
846
+ # SIG_GRID
847
+ SIG_GRID = np.array([
848
+ 0.08, 0.08, 0.095, 0.095, 0.095, 0.095,
849
+ 0.10, 0.08, 0.070, 0.070, 0.070, 0.070,
850
+ 0.07, 0.08, 0.070, 0.065, 0.070, 0.070,
851
+ 0.040, 0.030, 0.05, 0.05, 0.05, 0.050,
852
+ 0.05, 0.030, 0.025, 0.045, 0.05, 0.05,
853
+ 0.11, 0.04, 0.021, 0.021, 0.017, 0.017,
854
+ 0.10, 0.094, 0.068, 0.05, 0.03, 0.01,
855
+ 45.0, 45.0, 45.0, 45.0, 25.0, 40.0,
856
+ 0.20, 0.12, 0.05, 0.03, 0.025, 0.021,
857
+ 0.03, 0.015, 0.007, 0.01, 0.009, 0.007
858
+ ], dtype=np.float64)
859
+
860
+ SIG_GRID = SIG_GRID.reshape((len(V_GRID), len(YE_GRID)), order='F')
861
+
862
+ # ALP1_GRID
863
+ ALP1_GRID = np.array([
864
+ 7.50, 7.50, 7.50, 7.50, 7.50, 7.50,
865
+ 9.00, 9.00, 7.50, 7.50, 7.00, 7.00,
866
+ 8.00, 8.00, 7.50, 7.50, 7.00, 7.00,
867
+ 8.00, 8.00, 7.50, 7.50, 7.00, 7.00,
868
+ 8.00, 8.00, 5.00, 7.50, 7.00, 6.50,
869
+ 4.5, 3.8, 4.0, 4.0, 4.0, 4.0,
870
+ 2.4, 3.8, 3.8, 3.21, 2.91, 3.61,
871
+ -1.55, -1.55, -0.75, -0.75, -2.50, -5.00,
872
+ -1.55, -1.55, -1.55, -1.55, -1.55, -1.55,
873
+ 3.00, 3.00, 3.00, 3.00, 3.00, 3.00
874
+ ], dtype=np.float64)
875
+
876
+ ALP1_GRID = ALP1_GRID.reshape((len(V_GRID), len(YE_GRID)), order='F')
877
+
878
+ # T1_GRID
879
+ T1_GRID = np.array([
880
+ 0.040, 0.025, 0.014, 0.010, 0.008, 0.006,
881
+ 0.040, 0.035, 0.020, 0.012, 0.010, 0.008,
882
+ 0.080, 0.040, 0.020, 0.012, 0.012, 0.009,
883
+ 0.080, 0.040, 0.030, 0.018, 0.012, 0.009,
884
+ 0.080, 0.060, 0.065, 0.028, 0.020, 0.015,
885
+ 0.14, 0.123, 0.089, 0.060, 0.045, 0.031,
886
+ 0.264, 0.1, 0.07, 0.055, 0.042, 0.033,
887
+ 1.0, 1.0, 1.0, 1.0, 0.02, 0.01,
888
+ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
889
+ 0.04, 0.02, 0.01, 0.002, 0.002, 0.002
890
+ ], dtype=np.float64)
891
+
892
+ T1_GRID = T1_GRID.reshape((len(V_GRID), len(YE_GRID)), order='F')
893
+
894
+ SIG1_GRID = np.array([0.250, 0.120, 0.045, 0.028, 0.020, 0.015,
895
+ 0.250, 0.060, 0.035, 0.020, 0.016, 0.012,
896
+ 0.170, 0.090, 0.035, 0.020, 0.012, 0.009,
897
+ 0.170, 0.070, 0.035, 0.015, 0.012, 0.009,
898
+ 0.170, 0.070, 0.050, 0.025, 0.020, 0.020,
899
+ 0.065, 0.067, 0.053, 0.032, 0.032, 0.024,
900
+ 0.075, 0.044, 0.03, 0.02, 0.02, 0.014,
901
+ 10.0, 10.0, 10.0, 10.0, 0.02, 0.01,
902
+ 10.0, 10.0, 10.0, 10.0, 10.0, 10.0,
903
+ 0.01, 0.005, 0.002, 1e-4, 1e-4, 1e-4])
904
+
905
+ SIG1_GRID = SIG1_GRID.reshape((len(V_GRID), len(YE_GRID)), order='F')
906
+
907
+ C1_GRID = np.array([27.2, 27.8, 28.2, 28.2, 28.2, 28.2,
908
+ 28.0, 27.8, 27.8, 27.8, 27.8, 27.8,
909
+ 27.5, 27.0, 27.8, 27.8, 27.8, 27.8,
910
+ 28.8, 28.1, 27.8, 27.8, 27.5, 27.5,
911
+ 28.5, 28.0, 27.5, 28.5, 29.2, 29.0,
912
+ 25.0, 27.5, 25.8, 20.9, 29.3, 1.0,
913
+ 28.7, 27.0, 28.0, 28.0, 27.4, 25.3,
914
+ 28.5, 29.1, 29.5, 30.1, 30.4, 29.9,
915
+ 20.4, 20.6, 20.8, 20.9, 20.9, 21.0,
916
+ 29.9, 30.1, 30.1, 30.2, 30.3, 30.3])
917
+
918
+ C1_GRID = C1_GRID.reshape((len(V_GRID), len(YE_GRID)), order='F')
919
+
920
+ TAU1_GRID = np.array([4.07, 4.07, 4.07, 4.07, 4.07, 4.07,
921
+ 4.07, 4.07, 4.07, 4.07, 4.07, 4.07,
922
+ 4.07, 4.07, 4.07, 4.07, 4.07, 4.07,
923
+ 4.07, 4.07, 4.07, 4.07, 4.07, 4.07,
924
+ 4.77, 4.77, 4.77, 4.77, 4.07, 4.07,
925
+ 4.77, 4.77, 28.2, 1.03, 0.613, 1.0,
926
+ 3.4, 14.5, 11.4, 14.3, 13.3, 13.3,
927
+ 2.52, 2.52, 2.52, 2.52, 2.52, 2.52,
928
+ 1.02, 1.02, 1.02, 1.02, 1.02, 1.02,
929
+ 0.22, 0.22, 0.22, 0.22, 0.22, 0.22])
930
+
931
+ TAU1_GRID = TAU1_GRID.reshape((len(V_GRID), len(YE_GRID)), order='F')
932
+
933
+ C2_GRID = np.array([21.5, 21.5, 22.1, 22.1, 22.1, 22.1,
934
+ 22.3, 21.5, 21.5, 21.8, 21.8, 21.8,
935
+ 22.0, 21.5, 21.5, 22.0, 21.8, 21.8,
936
+ 23.5, 22.5, 22.1, 22.0, 22.2, 22.2,
937
+ 22.0, 22.8, 23.0, 23.0, 23.5, 23.5,
938
+ 10.0, 0.0, 0.0, 19.8, 22.0, 21.0,
939
+ 26.2, 14.1, 18.8, 19.1, 23.8, 19.2,
940
+ 25.4, 25.4, 25.8, 26.0, 26.0, 25.8,
941
+ 18.4, 18.4, 18.6, 18.6, 18.6, 18.6,
942
+ 27.8, 28.0, 28.2, 28.2, 28.3, 28.3])
943
+
944
+ C2_GRID = C2_GRID.reshape((len(V_GRID), len(YE_GRID)), order='F')
945
+
946
+ TAU2_GRID = np.array([4.62, 4.62, 4.62, 4.62, 4.62, 4.62,
947
+ 4.62, 4.62, 4.62, 4.62, 4.62, 4.62,
948
+ 4.62, 4.62, 4.62, 4.62, 4.62, 4.62,
949
+ 4.62, 4.62, 4.62, 4.62, 4.62, 4.62,
950
+ 5.62, 5.62, 5.62, 5.62, 4.62, 4.62,
951
+ 5.62, 5.18, 5.18, 34.7, 8.38, 22.6,
952
+ 0.15, 4.49, 95.0, 95.0, 0.95, 146.,
953
+ 0.12, 0.12, 0.12, 0.12, 0.12, 0.14,
954
+ 0.32, 0.32, 0.32, 0.32, 0.32, 0.32,
955
+ 0.02, 0.02, 0.02, 0.02, 0.02, 0.02])
956
+
957
+ TAU2_GRID = TAU2_GRID.reshape((len(V_GRID), len(YE_GRID)), order='F')
958
+
959
+ C3_GRID = np.array([19.4, 19.8, 20.1, 20.1, 20.1, 20.1,
960
+ 20.0, 19.8, 19.8, 19.8, 19.8, 19.8,
961
+ 19.9, 19.8, 19.8, 19.8, 19.8, 19.8,
962
+ 5.9, 9.8, 23.5, 23.5, 23.5, 23.5,
963
+ 27.3, 26.9, 26.6, 27.4, 25.8, 25.8,
964
+ 27.8, 26.9, 18.9, 25.4, 24.8, 25.8,
965
+ 22.8, 17.9, 18.9, 25.4, 24.8, 25.5,
966
+ 20.6, 20.2, 19.8, 19.2, 19.5, 18.4,
967
+ 12.6, 13.1, 14.1, 14.5, 14.5, 14.5,
968
+ 24.3, 24.2, 24.0, 24.0, 24.0, 23.9])
969
+
970
+ C3_GRID = C3_GRID.reshape((len(V_GRID), len(YE_GRID)), order='F')
971
+
972
+ TAU3_GRID = np.array([18.2, 18.2, 18.2, 18.2, 18.2, 18.2,
973
+ 18.2, 18.2, 18.2, 18.2, 18.2, 18.2,
974
+ 18.2, 18.2, 18.2, 18.2, 18.2, 18.2,
975
+ 18.2, 18.2, 0.62, 0.62, 0.62, 0.62,
976
+ 0.18, 0.18, 0.18, 0.18, 0.32, 0.32,
977
+ 0.12, 0.18, 50.8, 0.18, 0.32, 0.32,
978
+ 2.4, 51.8, 50.8, 0.18, 0.32, 0.32,
979
+ 3.0, 2.5, 2.4, 2.4, 2.4, 60.4,
980
+ 200., 200., 200., 200., 200., 200.,
981
+ 8.76, 8.76, 8.76, 8.76, 8.76, 8.76])
982
+
983
+ TAU3_GRID = TAU3_GRID.reshape((len(V_GRID), len(YE_GRID)), order='F')
984
+
985
+ # make interpolants
986
+ E0_interp = RegularGridInterpolator((V_GRID, YE_GRID), E0_GRID, bounds_error=False, fill_value=None)
987
+ ALP_interp = RegularGridInterpolator((V_GRID, YE_GRID), ALP_GRID, bounds_error=False, fill_value=None)
988
+ T0_interp = RegularGridInterpolator((V_GRID, YE_GRID), T0_GRID, bounds_error=False, fill_value=None)
989
+ SIG_interp = RegularGridInterpolator((V_GRID, YE_GRID), SIG_GRID, bounds_error=False, fill_value=None)
990
+ ALP1_interp = RegularGridInterpolator((V_GRID, YE_GRID), ALP1_GRID, bounds_error=False, fill_value=None)
991
+ T1_interp = RegularGridInterpolator((V_GRID, YE_GRID), T1_GRID, bounds_error=False, fill_value=None)
992
+ SIG1_interp = RegularGridInterpolator((V_GRID, YE_GRID), SIG1_GRID, bounds_error=False, fill_value=None)
993
+ C1_interp = RegularGridInterpolator((V_GRID, YE_GRID), C1_GRID, bounds_error=False, fill_value=None)
994
+ TAU1_interp = RegularGridInterpolator((V_GRID, YE_GRID), TAU1_GRID, bounds_error=False, fill_value=None)
995
+ C2_interp = RegularGridInterpolator((V_GRID, YE_GRID), C2_GRID, bounds_error=False, fill_value=None)
996
+ TAU2_interp = RegularGridInterpolator((V_GRID, YE_GRID), TAU2_GRID, bounds_error=False, fill_value=None)
997
+ C3_interp = RegularGridInterpolator((V_GRID, YE_GRID), C3_GRID, bounds_error=False, fill_value=None)
998
+ TAU3_interp = RegularGridInterpolator((V_GRID, YE_GRID), TAU3_GRID, bounds_error=False, fill_value=None)
999
+
1000
+
1001
+ interpolators = namedtuple('interpolators', ['E0', 'ALP', 'T0', 'SIG', 'ALP1', 'T1', 'SIG1',
1002
+ 'C1', 'TAU1', 'C2', 'TAU2', 'C3', 'TAU3'])
1003
+ interpolators.E0 = E0_interp
1004
+ interpolators.ALP = ALP_interp
1005
+ interpolators.T0 = T0_interp
1006
+ interpolators.SIG = SIG_interp
1007
+ interpolators.ALP1 = ALP1_interp
1008
+ interpolators.T1 = T1_interp
1009
+ interpolators.SIG1 = SIG1_interp
1010
+ interpolators.C1 = C1_interp
1011
+ interpolators.TAU1 = TAU1_interp
1012
+ interpolators.C2 = C2_interp
1013
+ interpolators.TAU2 = TAU2_interp
1014
+ interpolators.C3 = C3_interp
1015
+ interpolators.TAU3 = TAU3_interp
1016
+ return interpolators
1017
+
1018
+ def get_heating_terms(ye, vel, **kwargs):
1019
+ ints = heatinggrids()
1020
+ e0 = ints.E0([vel, ye])[0]
1021
+ alp = ints.ALP([vel, ye])[0]
1022
+ t0 = ints.T0([vel, ye])[0]
1023
+ sig = ints.SIG([vel, ye])[0]
1024
+ alp1 = ints.ALP1([vel, ye])[0]
1025
+ t1 = ints.T1([vel, ye])[0]
1026
+ sig1 = ints.SIG1([vel, ye])[0]
1027
+ c1 = ints.C1([vel, ye])[0]
1028
+ tau1 = ints.TAU1([vel, ye])[0]
1029
+ c2 = ints.C2([vel, ye])[0]
1030
+ tau2 = ints.TAU2([vel, ye])[0]
1031
+ c3 = ints.C3([vel, ye])[0]
1032
+ tau3 = ints.TAU3([vel, ye])[0]
1033
+ heating_terms = namedtuple('heating_terms', ['e0', 'alp', 't0', 'sig', 'alp1', 't1', 'sig1', 'c1',
1034
+ 'tau1', 'c2', 'tau2', 'c3', 'tau3'])
1035
+
1036
+ heating_rate_fudge = kwargs.get('heating_rate_fudge', 1.0)
1037
+ heating_terms.e0 = e0 * heating_rate_fudge
1038
+ heating_terms.alp = alp * heating_rate_fudge
1039
+ heating_terms.t0 = t0 * heating_rate_fudge
1040
+ heating_terms.sig = sig * heating_rate_fudge
1041
+ heating_terms.alp1 = alp1 * heating_rate_fudge
1042
+ heating_terms.t1 = t1 * heating_rate_fudge
1043
+ heating_terms.sig1 = sig1 * heating_rate_fudge
1044
+ heating_terms.c1 = c1 * heating_rate_fudge
1045
+ heating_terms.tau1 = tau1 * heating_rate_fudge
1046
+ heating_terms.c2 = c2 * heating_rate_fudge
1047
+ heating_terms.tau2 = tau2 * heating_rate_fudge
1048
+ heating_terms.c3 = c3 * heating_rate_fudge
1049
+ heating_terms.tau3 = tau3 * heating_rate_fudge
1050
+ return heating_terms
1051
+
788
1052
  def electron_fraction_from_kappa(kappa):
789
1053
  """
790
1054
  Uses interpolation from Tanaka+19 to calculate
@@ -795,9 +1059,22 @@ def electron_fraction_from_kappa(kappa):
795
1059
 
796
1060
  kappa_array = np.array([1, 3, 5, 20, 30])
797
1061
  ye_array = np.array([0.4,0.35,0.25,0.2, 0.1])
798
- kappa_func = interp1d(kappa_array, y=ye_array)
1062
+ kappa_func = interp1d(kappa_array, y=ye_array, fill_value='extrapolate')
799
1063
  electron_fraction = kappa_func(kappa)
800
1064
  return electron_fraction
1065
+
1066
+ def kappa_from_electron_fraction(ye):
1067
+ """
1068
+ Uses interpolation from Tanaka+19 to calculate
1069
+ the opacity based on the electron fraction
1070
+ :param ye: electron fraction
1071
+ :return: electron_fraction
1072
+ """
1073
+ kappa_array = np.array([1, 3, 5, 20, 30])
1074
+ ye_array = np.array([0.4,0.35,0.25,0.2, 0.1])
1075
+ func = interp1d(ye_array, y=kappa_array, fill_value='extrapolate')
1076
+ kappa = func(ye)
1077
+ return kappa
801
1078
 
802
1079
  def lorentz_factor_from_velocity(velocity):
803
1080
  """