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
@@ -2092,6 +2092,48 @@ def tophat(time, redshift, thv, loge0, thc, logn0, p, logepse, logepsb, ksin, g0
2092
2092
  elif kwargs['output_format'] == 'magnitude':
2093
2093
  return calc_ABmag_from_flux_density(flux_density).value
2094
2094
 
2095
+
2096
+ def tophat_from_emulator(time, redshift, thv, loge0, thc, logn0, p, logepse, logepsb, g0, **kwargs):
2097
+ """
2098
+ Evaluate a tophat afterglow model using an mpl regressor. Note that this model predicts for a fixed redshift = 0.01 and fixed ksin = 1.
2099
+ This tophat model does not include all of the ususal kwargs
2100
+
2101
+ :param time: time in days in observer frame, should be in range 0.1 to 300
2102
+ :param redshift: source redshift
2103
+ :param thv: viewing angle in radians
2104
+ :param loge0: log10 on axis isotropic equivalent energy
2105
+ :param thc: half width of jet core/jet opening angle in radians
2106
+ :param logn0: log10 number density of ISM in cm^-3
2107
+ :param p: electron distribution power law index. Must be greater than 2.
2108
+ :param logepse: log10 fraction of thermal energy in electrons
2109
+ :param logepsb: log10 fraction of thermal energy in magnetic field
2110
+ :param g0: initial lorentz factor
2111
+ :param kwargs: Additional keyword arguments
2112
+ :param frequency: frequency of the band to view in- single number or same length as time array
2113
+ :param output_format: Whether to output flux density or AB mag, specified by 'flux_density' or 'magnitude'
2114
+ :return: flux density or AB mag predicted by emulator. Note this is going to give the monochromatic magnitude at the effective frequency for the band.
2115
+ For a proper calculation of the magntitude use the sed variant models
2116
+ """
2117
+
2118
+ from redback_surrogates.afterglowmodels import tophat_emulator
2119
+
2120
+ z1=0.01
2121
+ z2= redshift
2122
+ frequency= np.log10(kwargs['frequency'])
2123
+ flux_density = tophat_emulator(new_time=time/(1+z2), thv=thv, loge0=loge0, thc=thc, logn0=logn0, p=p,
2124
+ logepse=logepse, logepsb=logepsb, g0=g0,frequency=frequency)
2125
+
2126
+ #scaling flux density with redshift
2127
+ dl1 = cosmo.luminosity_distance(z1)
2128
+ dl2 = cosmo.luminosity_distance(z2)
2129
+ scale_factor = ((dl1**2)*(1+z1)) / (dl2**2)
2130
+ flux_density=flux_density*scale_factor
2131
+
2132
+ if kwargs['output_format'] == 'flux_density':
2133
+ return flux_density
2134
+ elif kwargs['output_format'] == 'magnitude':
2135
+ return calc_ABmag_from_flux_density(flux_density).value
2136
+
2095
2137
  @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2020ApJ...896..166R/abstract')
2096
2138
  def afterglow_models_with_energy_injection(time, **kwargs):
2097
2139
  """
@@ -1,5 +1,9 @@
1
- import redback.transient_models.extinction_models
2
- def tophat_and_twolayerstratified(time, redshift, av, thv, loge0, thc, logn0, p, logepse, logepsb, ksin, g0, mej, vej_1, vej_2, kappa, beta, **kwargs):
1
+ import redback.transient_models.extinction_models as em
2
+ from redback.utils import citation_wrapper
3
+
4
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2020ApJ...896..166R/abstract, https://ui.adsabs.harvard.edu/abs/2020ApJ...891..152H/abstract')
5
+ def tophat_and_twolayerstratified(time, redshift, av, thv, loge0, thc, logn0, p, logepse,
6
+ logepsb, ksin, g0, mej, vej_1, vej_2, kappa, beta, **kwargs):
3
7
 
4
8
  """
5
9
  function to combine the flux density signals of a tophat afterglow and a two layer stratified kilonova with extinction
@@ -36,18 +40,20 @@ def tophat_and_twolayerstratified(time, redshift, av, thv, loge0, thc, logn0, p,
36
40
  """
37
41
  kwargs['output_format']='flux_density'
38
42
  kwargs['base_model']='tophat'
39
- afterglow = redback.transient_models.extinction_models.extinction_with_afterglow_base_model(time=time, redshift=redshift, av=av,
43
+ afterglow = em.extinction_with_afterglow_base_model(time=time, redshift=redshift, av=av,
40
44
  thv=thv, loge0=loge0 , thc= thc, logn0=logn0, p=p, logepse=logepse, logepsb=logepsb, ksin=ksin, g0=g0,
41
45
  **kwargs)
42
46
  kwargs['base_model']='two_layer_stratified_kilonova'
43
- kilonova = redback.transient_models.extinction_models.extinction_with_kilonova_base_model(time=time, redshift=redshift, av=av,
47
+ kilonova = em.extinction_with_kilonova_base_model(time=time, redshift=redshift, av=av,
44
48
  mej=mej, vej_1=vej_1, vej_2=vej_2, kappa=kappa, beta=beta, **kwargs)
45
49
 
46
50
  combined = afterglow+kilonova
47
51
  return combined
48
52
 
49
-
50
- def tophat_and_twocomponent(time, redshift, av, thv, loge0, thc, logn0, p, logepse, logepsb, ksin, g0, mej_1, vej_1, temperature_floor_1, kappa_1, mej_2, vej_2, temperature_floor_2, kappa_2, **kwargs):
53
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2020ApJ...896..166R/abstract, redback')
54
+ def tophat_and_twocomponent(time, redshift, av, thv, loge0, thc, logn0,
55
+ p, logepse, logepsb, ksin, g0, mej_1, vej_1,
56
+ temperature_floor_1, kappa_1, mej_2, vej_2, temperature_floor_2, kappa_2, **kwargs):
51
57
 
52
58
  """
53
59
  function to combine the flux density signals of a tophat afterglow and a two component kilonova with extinction added
@@ -85,19 +91,21 @@ def tophat_and_twocomponent(time, redshift, av, thv, loge0, thc, logn0, p, logep
85
91
  :return: flux density signal with extinction added
86
92
  """
87
93
 
88
- kwargs['output_format']='flux_density'
89
- kwargs['base_model']='tophat'
90
- afterglow = redback.transient_models.extinction_models.extinction_with_afterglow_base_model(time=time, redshift=redshift, av=av,
91
- thv=thv, loge0=loge0 , thc= thc, logn0=logn0, p=p, logepse=logepse, logepsb=logepsb, ksin=ksin, g0=g0,
92
- **kwargs)
93
- kwargs['base_model']='two_component_kilonova_model'
94
- kilonova = redback.transient_models.extinction_models.extinction_with_kilonova_base_model(time=time, redshift=redshift, av=av,
95
- mej_1=mej_1, vej_1=vej_2, temperature_floor_1=temperature_floor_1, kappa_1=kappa_1, mej_2=mej_2, vej_2=vej_2, temperature_floor_2=temperature_floor_2, kappa_2=kappa_2, **kwargs)
94
+ kwargs['output_format'] = 'flux_density'
95
+ kwargs['base_model'] = 'tophat'
96
+ afterglow = em.extinction_with_afterglow_base_model(time=time, redshift=redshift, av=av,
97
+ thv=thv, loge0=loge0, thc=thc, logn0=logn0, p=p, logepse=logepse, logepsb=logepsb, ksin=ksin, g0=g0,**kwargs)
98
+
99
+ kwargs['base_model'] = 'two_component_kilonova_model'
100
+ kilonova = em.extinction_with_kilonova_base_model(time=time, redshift=redshift, av=av,
101
+ mej_1=mej_1, vej_1=vej_1, temperature_floor_1=temperature_floor_1,
102
+ kappa_1=kappa_1, mej_2=mej_2, vej_2=vej_2,
103
+ temperature_floor_2=temperature_floor_2, kappa_2=kappa_2, **kwargs)
96
104
 
97
105
  combined = afterglow + kilonova
98
106
  return combined
99
107
 
100
-
108
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2020ApJ...896..166R/abstract, https://ui.adsabs.harvard.edu/abs/1982ApJ...253..785A/abstract')
101
109
  def tophat_and_arnett(time, av, redshift, thv, loge0, thc, logn0, p, logepse, logepsb, ksin, g0, f_nickel, mej, **kwargs):
102
110
 
103
111
  """
@@ -137,19 +145,20 @@ def tophat_and_arnett(time, av, redshift, thv, loge0, thc, logn0, p, logepse, lo
137
145
  :return: flux density with extinction added
138
146
  """
139
147
 
140
- kwargs['output_format']='flux_density'
141
- kwargs['base_model']='tophat'
142
- afterglow = redback.transient_models.extinction_models.extinction_with_afterglow_base_model(time=time, redshift=redshift, av=av,
143
- thv=thv, loge0=loge0 , thc= thc, logn0=logn0, p=p, logepse=logepse, logepsb=logepsb, ksin=ksin, g0=g0,
148
+ kwargs['output_format'] = 'flux_density'
149
+ kwargs['base_model'] = 'tophat'
150
+ afterglow = em.extinction_with_afterglow_base_model(time=time, redshift=redshift, av=av,
151
+ thv=thv, loge0=loge0, thc=thc, logn0=logn0, p=p, logepse=logepse, logepsb=logepsb, ksin=ksin, g0=g0,
144
152
  **kwargs)
145
- kwargs['base_model']='arnett'
146
- supernova = redback.transient_models.extinction_models.extinction_with_supernova_base_model(time=time, redshift=redshift, av=av,
153
+ kwargs['base_model'] = 'arnett'
154
+ supernova = em.extinction_with_supernova_base_model(time=time, redshift=redshift, av=av,
147
155
  f_nickel=f_nickel, mej=mej, **kwargs)
148
156
 
149
157
  combined = afterglow + supernova
150
158
  return combined
151
159
 
152
- def afterglow_and_optical(time, redshift, av, model_type, afterglow_kwargs, optical_kwargs, **shared_kwargs):
160
+ @citation_wrapper('redback, and any citations for the specific model you use')
161
+ def afterglow_and_optical(time, redshift, av, **model_kwargs):
153
162
 
154
163
  """
155
164
  function to combine the signals of any afterglow and any other optical transient with extinction added
@@ -157,26 +166,32 @@ def afterglow_and_optical(time, redshift, av, model_type, afterglow_kwargs, opti
157
166
  :param time: time in days in observer frame
158
167
  :param redshift: source redshift
159
168
  :param av: absolute mag extinction
169
+ :param model_kwargs: kwargs shared by models e.g. output_format, frequency, bands, r_v (extinction paramater defaults to 3.1)
160
170
  :param model_type: specify type of optical transient model- 'supernova', 'tde', 'kilonova', 'magnetar_driven', 'shock_powered'
161
171
  :param afterglow_kwargs: dictionary of parameters required by the afterglow transient model specified by 'base_model'
162
172
  and any additional keyword arguments. Refer to model documentation for details.
163
173
  :param optical_kwargs: dictionary of parameters required by the optical transient model specifed by 'base_model'
164
174
  and any additional keyword arguments. Note the base model must correspond to the given model type. Refer to model documentation
165
175
  for details.
166
- :param shared_kwargs: kwargs shared by models e.g. output_format, frequency, bands, r_v (extinction paramater defaults to 3.1)
167
176
  :return: set by shared_kwargs output format - 'flux_density' or 'magnitude' with extinction added
168
177
  note that only afterglow_models_sed allow for magnitude outputs
169
178
  """
179
+
180
+ optical_kwargs = model_kwargs['optical_kwargs']
181
+ afterglow_kwargs = model_kwargs['afterglow_kwargs']
182
+
183
+ _afterglow_kwargs = afterglow_kwargs.copy()
184
+ _afterglow_kwargs.update(model_kwargs)
185
+ _afterglow_kwargs.pop('model_type')
186
+
187
+ _optical_kwargs = optical_kwargs.copy()
188
+ _optical_kwargs.update(model_kwargs)
189
+
190
+ afterglow = em._evaluate_extinction_model(time=time, redshift=redshift, av=av,model_type='afterglow',
191
+ **_afterglow_kwargs)
170
192
 
171
- afterglow_kwargs.update(shared_kwargs)
172
- optical_kwargs.update(shared_kwargs)
173
-
174
- afterglow = redback.transient_models.extinction_models._evaluate_extinction_model(time=time, redshift=redshift, av=av,
175
- model_type='afterglow', **afterglow_kwargs)
176
-
177
- optical= redback.transient_models.extinction_models._evaluate_extinction_model(time=time, redshift=redshift, av=av,
178
- model_type=model_type, **optical_kwargs)
179
-
193
+ optical = em._evaluate_extinction_model(time=time, redshift=redshift, av=av, **_optical_kwargs)
194
+
180
195
  combined= afterglow + optical
181
196
  return combined
182
197
 
@@ -1,6 +1,5 @@
1
1
  from inspect import isfunction
2
2
  import numpy as np
3
-
4
3
  import redback.utils
5
4
  from redback.transient_models.fireball_models import predeceleration
6
5
  from redback.utils import logger, calc_ABmag_from_flux_density, citation_wrapper, lambda_to_nu
@@ -12,12 +11,14 @@ extinction_afterglow_base_models = ['tophat', 'cocoon', 'gaussian',
12
11
  'kn_afterglow', 'cone_afterglow',
13
12
  'gaussiancore', 'gaussian',
14
13
  'smoothpowerlaw', 'powerlawcore',
14
+ 'tophat','tophat_from_emulator',
15
15
  'kilonova_afterglow_redback', 'kilonova_afterglow_nakarpiran',
16
16
  'tophat_redback', 'gaussian_redback', 'twocomponent_redback',
17
17
  'powerlaw_redback', 'alternativepowerlaw_redback', 'doublegaussian_redback',
18
18
  'tophat_redback_refreshed', 'gaussian_redback_refreshed',
19
19
  'twocomponent_redback_refreshed','powerlaw_redback_refreshed',
20
20
  'alternativepowerlaw_redback_refreshed', 'doublegaussian_redback_refreshed']
21
+
21
22
  extinction_integrated_flux_afterglow_models = extinction_afterglow_base_models
22
23
  extinction_supernova_base_models = ['sn_exponential_powerlaw', 'arnett', 'shock_cooling_and_arnett',
23
24
  'basic_magnetar_powered', 'slsn', 'magnetar_nickel',
@@ -25,17 +26,17 @@ extinction_supernova_base_models = ['sn_exponential_powerlaw', 'arnett', 'shock_
25
26
  'general_magnetar_slsn','general_magnetar_driven_supernova']
26
27
  extinction_kilonova_base_models = ['nicholl_bns', 'mosfit_rprocess', 'mosfit_kilonova',
27
28
  'power_law_stratified_kilonova','bulla_bns_kilonova',
28
- 'bulla_nsbh_kilonova', 'kasen_nsbh_kilonova','two_layer_stratified_kilonova',
29
+ 'bulla_nsbh_kilonova', 'kasen_bns_kilonova','two_layer_stratified_kilonova',
29
30
  'three_component_kilonova_model', 'two_component_kilonova_model',
30
31
  'one_component_kilonova_model', 'one_component_ejecta_relation',
31
32
  'one_component_ejecta_relation_projection', 'two_component_bns_ejecta_relation',
32
33
  'polytrope_eos_two_component_bns', 'one_component_nsbh_ejecta_relation',
33
34
  'two_component_nsbh_ejecta_relation','metzger_kilonova_model']
34
35
  extinction_tde_base_models = ['tde_analytical', 'tde_semianalytical', 'gaussianrise_cooling_envelope',
35
- 'cooling_envelope']
36
+ 'cooling_envelope', 'bpl_cooling_envelope']
36
37
  extinction_magnetar_driven_base_models = ['basic_mergernova', 'general_mergernova', 'general_mergernova_thermalisation',
37
38
  'general_mergernova_evolution', 'metzger_magnetar_driven_kilonova_model',
38
- 'general_metzger_magnetar_driven', 'general_magnetar_driven_thermalisation',
39
+ 'general_metzger_magnetar_driven', 'general_metzger_magnetar_driven_thermalisation',
39
40
  'general_metzger_magnetar_driven_evolution']
40
41
  extinction_shock_powered_base_models = ['shocked_cocoon', 'shock_cooling']
41
42
 
@@ -10,7 +10,7 @@ from redback.photosphere import TemperatureFloor, CocoonPhotosphere
10
10
  from redback.interaction_processes import Diffusion, AsphericalDiffusion
11
11
 
12
12
  from redback.utils import calc_kcorrected_properties, interpolated_barnes_and_kasen_thermalisation_efficiency, \
13
- electron_fraction_from_kappa, citation_wrapper, lambda_to_nu
13
+ electron_fraction_from_kappa, citation_wrapper, lambda_to_nu, get_heating_terms, kappa_from_electron_fraction
14
14
  from redback.eos import PiecewisePolytrope
15
15
  from redback.sed import blackbody_to_flux_density, get_correct_output_format_from_spectra, Blackbody
16
16
  from redback.constants import *
@@ -476,7 +476,7 @@ def mosfit_rprocess(time, redshift, mej, vej, kappa, kappa_gamma, temperature_fl
476
476
  cosmology = kwargs.get('cosmology', cosmo)
477
477
  dl = cosmology.luminosity_distance(redshift).cgs.value
478
478
  dense_resolution = kwargs.get('dense_resolution', 300)
479
- time_temp = np.geomspace(1e-2, 5e6, dense_resolution) # in source frame
479
+ time_temp = np.geomspace(1e-2, 7e6, dense_resolution) # in source frame
480
480
  time_obs = time
481
481
  lbols = _mosfit_kilonova_one_component_lbol(time=time_temp,
482
482
  mej=mej, vej=vej)
@@ -555,7 +555,7 @@ def mosfit_kilonova(time, redshift, mej_1, vej_1, temperature_floor_1, kappa_1,
555
555
  cosmology = kwargs.get('cosmology', cosmo)
556
556
  dl = cosmology.luminosity_distance(redshift).cgs.value
557
557
  dense_resolution = kwargs.get('dense_resolution', 300)
558
- time_temp = np.geomspace(1e-2, 5e6, dense_resolution) # in source frame
558
+ time_temp = np.geomspace(1e-2, 7e6, dense_resolution) # in source frame
559
559
  time_obs = time
560
560
  mej = [mej_1, mej_2, mej_3]
561
561
  vej = [vej_1, vej_2, vej_3]
@@ -817,7 +817,7 @@ def kasen_bns_kilonova(time, redshift, mej, vej, chi, **kwargs):
817
817
  fmjy = spectra.to(uu.mJy, equivalencies=uu.spectral_density(wav=output.lambdas * uu.Angstrom)).value
818
818
  nu_array = lambda_to_nu(output.lambdas)
819
819
  fmjy_func = RegularGridInterpolator((np.unique(time), nu_array), fmjy, bounds_error=False)
820
- if type(frequency) == float:
820
+ if type(frequency) == float or type(frequency) == np.float64:
821
821
  frequency = np.ones(len(time)) * frequency
822
822
  points = np.array([time, frequency]).T
823
823
  return fmjy_func(points)
@@ -890,6 +890,11 @@ def _kilonova_hr(time, redshift, mej, velocity_array, kappa_array, beta, **kwarg
890
890
  time = time * day_to_s
891
891
  # convert to source frame time and frequency
892
892
  frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
893
+ if (isinstance(frequency, (float, int)) == False):
894
+ radio_mask = frequency < 10e10
895
+ frequency[radio_mask]=10e50
896
+ elif frequency < 10e10:
897
+ frequency =10e50
893
898
 
894
899
  _, temperature, r_photosphere = _kilonova_hr_sourceframe(time, mej, velocity_array, kappa_array, beta)
895
900
 
@@ -974,7 +979,7 @@ def three_component_kilonova_model(time, redshift, mej_1, vej_1, temperature_flo
974
979
  """
975
980
  cosmology = kwargs.get('cosmology', cosmo)
976
981
  dl = cosmology.luminosity_distance(redshift).cgs.value
977
- time_temp = np.geomspace(1e-2, 5e6, 300) # in source frame
982
+ time_temp = np.geomspace(1e-2, 7e6, 300) # in source frame
978
983
  time_obs = time
979
984
 
980
985
  mej = [mej_1, mej_2, mej_3]
@@ -1063,7 +1068,7 @@ def two_component_kilonova_model(time, redshift, mej_1, vej_1, temperature_floor
1063
1068
  """
1064
1069
  cosmology = kwargs.get('cosmology', cosmo)
1065
1070
  dl = cosmology.luminosity_distance(redshift).cgs.value
1066
- time_temp = np.geomspace(1e-2, 5e6, 300) # in source frame
1071
+ time_temp = np.geomspace(1e-2, 7e6, 300) # in source frame
1067
1072
  time_obs = time
1068
1073
 
1069
1074
  mej = [mej_1, mej_2]
@@ -1376,7 +1381,7 @@ def one_component_kilonova_model(time, redshift, mej, vej, kappa, **kwargs):
1376
1381
  """
1377
1382
  cosmology = kwargs.get('cosmology', cosmo)
1378
1383
  dl = cosmology.luminosity_distance(redshift).cgs.value
1379
- time_temp = np.geomspace(1e-3, 5e6, 300) # in source frame
1384
+ time_temp = np.geomspace(1e-3, 7e6, 300) # in source frame
1380
1385
  time_obs = time
1381
1386
  _, temperature, r_photosphere = _one_component_kilonova_model(time_temp, mej, vej, kappa, **kwargs)
1382
1387
 
@@ -1416,6 +1421,234 @@ def one_component_kilonova_model(time, redshift, mej, vej, kappa, **kwargs):
1416
1421
  spectra=spectra, lambda_array=lambda_observer_frame,
1417
1422
  **kwargs)
1418
1423
 
1424
+
1425
+ def _calc_new_heating_rate(time, mej, electron_fraction, ejecta_velocity, **kwargs):
1426
+ """
1427
+ Heating rate prescription following Rosswog and Korobkin 2022
1428
+
1429
+ :param time: time in seconds
1430
+ :param mej: ejecta mass in solar masses
1431
+ :param electron_fraction: electron fraction
1432
+ :param ejecta_velocity: ejecta velocity in c
1433
+ :param kwargs: Additional keyword arguments
1434
+ :param heating_rate_perturbation: A fudge factor for heating rate to account for uncertainties in the heating rate. Default is 1.0 i.e., no perturbation.
1435
+ :param heating_rate_fudge: A fudge factor for each of the terms in the heating rate. Default to 1. i.e., no uncertainty
1436
+ Default is 1.0 i.e., no perturbation.
1437
+ :return: heating rate in erg/s
1438
+ """
1439
+ heating_terms = get_heating_terms(electron_fraction, ejecta_velocity, **kwargs)
1440
+ heating_rate_perturbation = kwargs.get('heating_rate_perturbation', 1.0)
1441
+ # rescale
1442
+ m0 = mej * solar_mass
1443
+ c1 = np.exp(heating_terms.c1)
1444
+ c2 = np.exp(heating_terms.c2)
1445
+ c3 = np.exp(heating_terms.c3)
1446
+ tau1 = 1e3*heating_terms.tau1
1447
+ tau2 = 1e5*heating_terms.tau2
1448
+ tau3 = 1e5*heating_terms.tau3
1449
+ term1 = 10.**(heating_terms.e0+18) * (0.5 - np.arctan((time - heating_terms.t0) / heating_terms.sig) / np.pi)**heating_terms.alp
1450
+ term2 = (0.5 + np.arctan((time - heating_terms.t1)/heating_terms.sig1) / np.pi )**heating_terms.alp1
1451
+ term3 = c1 * np.exp(-time/tau1)
1452
+ term4 = c2 * np.exp(-time/tau2)
1453
+ term5 = c3 * np.exp(-time/tau3)
1454
+ lum_in = term1*term2 + term3 + term4 + term5
1455
+ return lum_in*m0 * heating_rate_perturbation
1456
+
1457
+ def _one_component_kilonova_rosswog_heatingrate(time, mej, vej, electron_fraction, **kwargs):
1458
+ tdays = time/day_to_s
1459
+ # set up kilonova physics
1460
+ av, bv, dv = interpolated_barnes_and_kasen_thermalisation_efficiency(mej, vej)
1461
+ # thermalisation from Barnes+16
1462
+ e_th = 0.36 * (np.exp(-av * tdays) + np.log1p(2.0 * bv * tdays ** dv) / (2.0 * bv * tdays ** dv))
1463
+ temperature_floor = kwargs.get('temperature_floor', 4000) # kelvin
1464
+ beta = 13.7
1465
+
1466
+ v0 = vej * speed_of_light
1467
+ m0 = mej * solar_mass
1468
+ kappa = kappa_from_electron_fraction(electron_fraction)
1469
+ tdiff = np.sqrt(2.0 * kappa * (m0) / (beta * v0 * speed_of_light))
1470
+
1471
+ lum_in = _calc_new_heating_rate(time, mej, electron_fraction, vej, **kwargs)
1472
+ integrand = lum_in * e_th * (time / tdiff) * np.exp(time ** 2 / tdiff ** 2)
1473
+
1474
+ bolometric_luminosity = np.zeros(len(time))
1475
+ bolometric_luminosity[1:] = cumtrapz(integrand, time)
1476
+ bolometric_luminosity[0] = bolometric_luminosity[1]
1477
+ bolometric_luminosity = bolometric_luminosity * np.exp(-time ** 2 / tdiff ** 2) / tdiff
1478
+
1479
+ temperature = (bolometric_luminosity / (4.0 * np.pi * sigma_sb * v0 ** 2 * time ** 2)) ** 0.25
1480
+ r_photosphere = (bolometric_luminosity / (4.0 * np.pi * sigma_sb * temperature_floor ** 4)) ** 0.5
1481
+
1482
+ # check temperature floor conditions
1483
+ mask = temperature <= temperature_floor
1484
+ temperature[mask] = temperature_floor
1485
+ mask = np.logical_not(mask)
1486
+ r_photosphere[mask] = v0 * time[mask]
1487
+ return bolometric_luminosity, temperature, r_photosphere
1488
+
1489
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2024arXiv240407271S/abstract, https://ui.adsabs.harvard.edu/abs/2024AnP...53600306R/abstract')
1490
+ def one_comp_kne_rosswog_heatingrate(time, redshift, mej, vej, ye, **kwargs):
1491
+ """
1492
+ :param time: observer frame time in days
1493
+ :param redshift: redshift
1494
+ :param mej: ejecta mass in solar masses
1495
+ :param vej: minimum initial velocity
1496
+ :param kappa: gray opacity
1497
+ :param kwargs: Additional keyword arguments
1498
+ :param temperature_floor: Temperature floor in K (default 4000)
1499
+ :param heating_rate_perturbation: A fudge factor for heating rate to account for uncertainties in the heating rate.
1500
+ Default is 1.0 i.e., no perturbation.
1501
+ :param heating_rate_fudge: A fudge factor for each of the terms in the heating rate. Default to 1. i.e., no uncertainty
1502
+ :param frequency: Required if output_format is 'flux_density'.
1503
+ frequency to calculate - Must be same length as time array or a single number).
1504
+ :param bands: Required if output_format is 'magnitude' or 'flux'.
1505
+ :param output_format: 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
1506
+ :param lambda_array: Optional argument to set your desired wavelength array (in Angstroms) to evaluate the SED on.
1507
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
1508
+ :return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
1509
+ """
1510
+ cosmology = kwargs.get('cosmology', cosmo)
1511
+ dl = cosmology.luminosity_distance(redshift).cgs.value
1512
+ time_temp = np.geomspace(1e-3, 7e6, 300) # in source frame
1513
+ time_obs = time
1514
+ _, temperature, r_photosphere = _one_component_kilonova_rosswog_heatingrate(time_temp, mej, vej, ye, **kwargs)
1515
+
1516
+ if kwargs['output_format'] == 'flux_density':
1517
+ time = time_obs * day_to_s
1518
+ frequency = kwargs['frequency']
1519
+ # interpolate properties onto observation times
1520
+ temp_func = interp1d(time_temp, y=temperature)
1521
+ rad_func = interp1d(time_temp, y=r_photosphere)
1522
+ # convert to source frame time and frequency
1523
+ frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
1524
+
1525
+ temp = temp_func(time)
1526
+ photosphere = rad_func(time)
1527
+
1528
+ flux_density = blackbody_to_flux_density(temperature=temp, r_photosphere=photosphere,
1529
+ dl=dl, frequency=frequency)
1530
+
1531
+ return flux_density.to(uu.mJy).value
1532
+
1533
+ else:
1534
+ lambda_observer_frame = kwargs.get('lambda_array', np.geomspace(100, 60000, 200))
1535
+ time_observer_frame = time_temp * (1. + redshift)
1536
+ frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
1537
+ redshift=redshift, time=time_observer_frame)
1538
+ fmjy = blackbody_to_flux_density(temperature=temperature,
1539
+ r_photosphere=r_photosphere, frequency=frequency[:, None], dl=dl)
1540
+ fmjy = fmjy.T
1541
+ spectra = fmjy.to(uu.mJy).to(uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom,
1542
+ equivalencies=uu.spectral_density(wav=lambda_observer_frame * uu.Angstrom))
1543
+ if kwargs['output_format'] == 'spectra':
1544
+ return namedtuple('output', ['time', 'lambdas', 'spectra'])(time=time_observer_frame,
1545
+ lambdas=lambda_observer_frame,
1546
+ spectra=spectra)
1547
+ else:
1548
+ return get_correct_output_format_from_spectra(time=time_obs, time_eval=time_observer_frame/day_to_s,
1549
+ spectra=spectra, lambda_array=lambda_observer_frame,
1550
+ **kwargs)
1551
+
1552
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2024arXiv240407271S/abstract, https://ui.adsabs.harvard.edu/abs/2024AnP...53600306R/abstract')
1553
+ def two_comp_kne_rosswog_heatingrate(time, redshift, mej_1, vej_1, temperature_floor_1, ye_1,
1554
+ mej_2, vej_2, temperature_floor_2, ye_2, **kwargs):
1555
+ """
1556
+ :param time: observer frame time in days
1557
+ :param redshift: redshift
1558
+ :param mej_1: ejecta mass in solar masses of first component
1559
+ :param vej_1: minimum initial velocity of first component
1560
+ :param kappa_1: gray opacity of first component
1561
+ :param temperature_floor_1: floor temperature of first component
1562
+ :param mej_2: ejecta mass in solar masses of second component
1563
+ :param vej_2: minimum initial velocity of second component
1564
+ :param temperature_floor_2: floor temperature of second component
1565
+ :param kappa_2: gray opacity of second component
1566
+ :param kwargs: Additional keyword arguments
1567
+ :param heating_rate_perturbation: A fudge factor for heating rate to account for uncertainties in the heating rate.
1568
+ Default is 1.0 i.e., no perturbation.
1569
+ :param heating_rate_fudge: A fudge factor for each of the terms in the heating rate. Default to 1. i.e., no uncertainty
1570
+ :param frequency: Required if output_format is 'flux_density'.
1571
+ frequency to calculate - Must be same length as time array or a single number).
1572
+ :param bands: Required if output_format is 'magnitude' or 'flux'.
1573
+ :param output_format: 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
1574
+ :param lambda_array: Optional argument to set your desired wavelength array (in Angstroms) to evaluate the SED on.
1575
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
1576
+ :return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
1577
+ """
1578
+ cosmology = kwargs.get('cosmology', cosmo)
1579
+ dl = cosmology.luminosity_distance(redshift).cgs.value
1580
+ time_temp = np.geomspace(1e-2, 7e6, 300) # in source frame
1581
+ time_obs = time
1582
+
1583
+ mej = [mej_1, mej_2]
1584
+ vej = [vej_1, vej_2]
1585
+ temperature_floor = [temperature_floor_1, temperature_floor_2]
1586
+ ye = [ye_1, ye_2]
1587
+
1588
+ if kwargs['output_format'] == 'flux_density':
1589
+ time = time * day_to_s
1590
+ frequency = kwargs['frequency']
1591
+
1592
+ # convert to source frame time and frequency
1593
+ frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
1594
+
1595
+ ff = np.zeros(len(time))
1596
+ for x in range(2):
1597
+ temp_kwargs = {}
1598
+ if 'heating_rate_fudge' in kwargs:
1599
+ temp_kwargs['heating_rate_fudge'] = kwargs['heating_rate_fudge']
1600
+ if 'heating_rate_perturbation' in kwargs:
1601
+ temp_kwargs['heating_rate_perturbation'] = kwargs['heating_rate_perturbation']
1602
+ temp_kwargs['temperature_floor'] = temperature_floor[x]
1603
+ _, temperature, r_photosphere = _one_component_kilonova_rosswog_heatingrate(time_temp, mej[x], vej[x], ye[x],
1604
+ **temp_kwargs)
1605
+ # interpolate properties onto observation times
1606
+ temp_func = interp1d(time_temp, y=temperature)
1607
+ rad_func = interp1d(time_temp, y=r_photosphere)
1608
+ temp = temp_func(time)
1609
+ photosphere = rad_func(time)
1610
+ flux_density = blackbody_to_flux_density(temperature=temp, r_photosphere=photosphere,
1611
+ dl=dl, frequency=frequency)
1612
+ units = flux_density.unit
1613
+ ff += flux_density.value
1614
+
1615
+ ff = ff * units
1616
+ return ff.to(uu.mJy).value
1617
+
1618
+ else:
1619
+ lambda_observer_frame = kwargs.get('lambda_array', np.geomspace(100, 60000, 200))
1620
+ time_observer_frame = time_temp * (1. + redshift)
1621
+ frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
1622
+ redshift=redshift, time=time_observer_frame)
1623
+ full_spec = np.zeros((len(time), len(frequency)))
1624
+
1625
+ for x in range(2):
1626
+ temp_kwargs = {}
1627
+ if 'heating_rate_fudge' in kwargs:
1628
+ temp_kwargs['heating_rate_fudge'] = kwargs['heating_rate_fudge']
1629
+ if 'heating_rate_perturbation' in kwargs:
1630
+ temp_kwargs['heating_rate_perturbation'] = kwargs['heating_rate_perturbation']
1631
+ temp_kwargs['temperature_floor'] = temperature_floor[x]
1632
+ _, temperature, r_photosphere = _one_component_kilonova_rosswog_heatingrate(time_temp, mej[x], vej[x], ye[x],
1633
+ **temp_kwargs)
1634
+ fmjy = blackbody_to_flux_density(temperature=temperature,
1635
+ r_photosphere=r_photosphere, frequency=frequency[:, None], dl=dl)
1636
+ fmjy = fmjy.T
1637
+ spectra = fmjy.to(uu.mJy).to(uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom,
1638
+ equivalencies=uu.spectral_density(wav=lambda_observer_frame * uu.Angstrom))
1639
+ units = spectra.unit
1640
+ full_spec += spectra.value
1641
+
1642
+ full_spec = full_spec * units
1643
+ if kwargs['output_format'] == 'spectra':
1644
+ return namedtuple('output', ['time', 'lambdas', 'spectra'])(time=time_observer_frame,
1645
+ lambdas=lambda_observer_frame,
1646
+ spectra=full_spec)
1647
+ else:
1648
+ return get_correct_output_format_from_spectra(time=time_obs, time_eval=time_observer_frame/day_to_s,
1649
+ spectra=full_spec, lambda_array=lambda_observer_frame,
1650
+ **kwargs)
1651
+
1419
1652
  def _one_component_kilonova_model(time, mej, vej, kappa, **kwargs):
1420
1653
  """
1421
1654
  :param time: source frame time in seconds
@@ -1479,7 +1712,7 @@ def metzger_kilonova_model(time, redshift, mej, vej, beta, kappa, **kwargs):
1479
1712
  """
1480
1713
  cosmology = kwargs.get('cosmology', cosmo)
1481
1714
  dl = cosmology.luminosity_distance(redshift).cgs.value
1482
- time_temp = np.geomspace(1e-4, 1e7, 300) # in source frame
1715
+ time_temp = np.geomspace(1e-4, 7e6, 300) # in source frame
1483
1716
  time_obs = time
1484
1717
  bolometric_luminosity, temperature, r_photosphere = _metzger_kilonova_model(time_temp, mej, vej, beta,
1485
1718
  kappa, **kwargs)
@@ -58,8 +58,8 @@ def _ejecta_dynamics_and_interaction(time, mej, beta, ejecta_radius, kappa, n_is
58
58
 
59
59
  ni56_lum = 6.45e43
60
60
  co56_lum = 1.45e43
61
- ni56_life = 8.8 # days
62
- co56_life = 111.3 # days
61
+ ni56_life = 8.8*86400 # days
62
+ co56_life = 111.3*86400 # days
63
63
 
64
64
  for i in range(len(time)):
65
65
  beta = np.sqrt(1 - 1 / gamma ** 2)
@@ -1,5 +1,18 @@
1
1
  import numpy as np
2
2
 
3
+ def line_spectrum(wavelength, line_amp, cont_amp, x0):
4
+ """
5
+ A gaussian to add or subtract from a continuum spectrum to mimic absorption or emission lines
6
+
7
+ :param wavelength: wavelength array in whatever units
8
+ :param line_amp: line amplitude scale
9
+ :param cont_amp: Continuum amplitude scale
10
+ :param x0: Position of emission line
11
+ :return: spectrum in whatever units set by line_amp
12
+ """
13
+ spectrum = line_amp / cont_amp * np.exp(-(wavelength - x0) ** 2. / (2 * cont_amp ** 2) )
14
+ return spectrum
15
+
3
16
  def gaussian_rise(time, a_1, peak_time, sigma_t):
4
17
  """
5
18
  :param time: time array in whatver time units