redback 1.0.1__py3-none-any.whl → 1.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- redback/__init__.py +4 -0
- redback/constraints.py +46 -25
- redback/eos.py +1 -0
- redback/get_data/fink.py +1 -1
- redback/get_data/lasair.py +3 -4
- redback/get_data/swift.py +7 -7
- redback/interaction_processes.py +1 -4
- redback/likelihoods.py +207 -21
- redback/model_library.py +2 -2
- redback/plotting.py +10 -10
- redback/priors/bazin_sne.prior +5 -0
- redback/priors/csm_interaction.prior +6 -7
- redback/priors/csm_nickel.prior +3 -3
- redback/priors/csm_shock_and_arnett.prior +11 -0
- redback/priors/csm_shock_and_arnett_bolometric.prior +10 -0
- redback/priors/csm_shock_breakout.prior +7 -0
- redback/priors/nicholl_bns.prior +2 -1
- redback/priors/one_comp_kne_rosswog_heatingrate.prior +5 -0
- redback/priors/pwn.prior +7 -0
- redback/priors/shocked_cocoon.prior +6 -6
- redback/priors/sn_fallback.prior +8 -0
- redback/priors/stream_stream_tde.prior +10 -0
- redback/priors/stream_stream_tde_bolometric.prior +9 -0
- redback/priors/tde_analytical.prior +5 -5
- redback/priors/tde_analytical_bolometric.prior +6 -4
- redback/priors/tde_fallback.prior +9 -0
- redback/priors/tde_fallback_bolometric.prior +6 -0
- redback/priors/tde_synchrotron.prior +6 -0
- redback/priors/tophat_from_emulator.prior +9 -0
- redback/priors/two_comp_kne_rosswog_heatingrate.prior +9 -0
- redback/priors/two_layer_stratified_kilonova.prior +1 -1
- redback/priors/villar_sne.prior +7 -0
- redback/priors.py +12 -1
- redback/sed.py +194 -2
- redback/simulate_transients.py +71 -35
- redback/tables/GRBs_w_redshift.txt +430 -413
- redback/tables/LGRB_table.txt +70 -6
- redback/tables/SGRB_table.txt +139 -135
- redback/tables/filters.csv +14 -0
- redback/tables/qdot_rosswogkorobkin24.pck +0 -0
- redback/tables/ztf.tar.gz +0 -0
- redback/transient/afterglow.py +17 -7
- redback/transient/kilonova.py +6 -3
- redback/transient/prompt.py +14 -4
- redback/transient/supernova.py +7 -3
- redback/transient/tde.py +6 -3
- redback/transient/transient.py +29 -12
- redback/transient_models/afterglow_models.py +152 -146
- redback/transient_models/combined_models.py +69 -48
- redback/transient_models/extinction_models.py +6 -6
- redback/transient_models/general_synchrotron_models.py +518 -0
- redback/transient_models/integrated_flux_afterglow_models.py +2 -2
- redback/transient_models/kilonova_models.py +310 -61
- redback/transient_models/magnetar_driven_ejecta_models.py +2 -2
- redback/transient_models/magnetar_models.py +1 -1
- redback/transient_models/phenomenological_models.py +69 -1
- redback/transient_models/shock_powered_models.py +159 -110
- redback/transient_models/supernova_models.py +211 -43
- redback/transient_models/tde_models.py +975 -5
- redback/utils.py +309 -16
- {redback-1.0.1.dist-info → redback-1.0.3.dist-info}/METADATA +46 -6
- {redback-1.0.1.dist-info → redback-1.0.3.dist-info}/RECORD +65 -49
- {redback-1.0.1.dist-info → redback-1.0.3.dist-info}/WHEEL +1 -1
- redback/tables/ztf_obslog.csv +0 -106649
- {redback-1.0.1.dist-info → redback-1.0.3.dist-info}/LICENCE.md +0 -0
- {redback-1.0.1.dist-info → redback-1.0.3.dist-info}/top_level.txt +0 -0
|
@@ -4,13 +4,14 @@ import pandas as pd
|
|
|
4
4
|
from astropy.table import Table, Column
|
|
5
5
|
from scipy.interpolate import interp1d, RegularGridInterpolator
|
|
6
6
|
from astropy.cosmology import Planck18 as cosmo # noqa
|
|
7
|
-
from scipy.integrate import
|
|
7
|
+
from scipy.integrate import cumulative_trapezoid
|
|
8
8
|
from collections import namedtuple
|
|
9
9
|
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, _calculate_rosswogkorobkin24_qdot, \
|
|
14
|
+
kappa_from_electron_fraction
|
|
14
15
|
from redback.eos import PiecewisePolytrope
|
|
15
16
|
from redback.sed import blackbody_to_flux_density, get_correct_output_format_from_spectra, Blackbody
|
|
16
17
|
from redback.constants import *
|
|
@@ -18,7 +19,7 @@ import redback.ejecta_relations as ejr
|
|
|
18
19
|
|
|
19
20
|
@citation_wrapper('https://ui.adsabs.harvard.edu/abs/2021MNRAS.505.3016N/abstract')
|
|
20
21
|
def _nicholl_bns_get_quantities(mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
21
|
-
mtov, epsilon, alpha,
|
|
22
|
+
mtov, epsilon, alpha, cos_theta_open, cos_theta, **kwargs):
|
|
22
23
|
"""
|
|
23
24
|
Calculates quantities for the Nicholl et al. 2021 BNS model
|
|
24
25
|
|
|
@@ -31,7 +32,7 @@ def _nicholl_bns_get_quantities(mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
|
31
32
|
:param epsilon: fraction of disk that gets unbound/ejected
|
|
32
33
|
:param alpha: Enhancement of blue ejecta by NS surface winds if mtotal < prompt collapse,
|
|
33
34
|
can turn off by setting alpha=1
|
|
34
|
-
:param
|
|
35
|
+
:param cos_theta_open: Lanthanide opening angle
|
|
35
36
|
:param cos_theta: Viewing angle of observer
|
|
36
37
|
:param kwargs: Additional keyword arguments
|
|
37
38
|
:param dynamical_ejecta_error: Error in dynamical ejecta mass, default is 1 i.e., no error in fitting formula
|
|
@@ -50,7 +51,7 @@ def _nicholl_bns_get_quantities(mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
|
50
51
|
n_ave = 0.743
|
|
51
52
|
dynamical_ejecta_error = kwargs.get('dynamical_ejecta_error', 1.0)
|
|
52
53
|
disk_ejecta_error = kwargs.get('disk_ejecta_error', 1.0)
|
|
53
|
-
theta_open = np.arccos(
|
|
54
|
+
theta_open = np.arccos(cos_theta_open)
|
|
54
55
|
|
|
55
56
|
fq = (1 - (mass_2 / mass_1) ** (10. / (3 - n_ave))) / (1 + (mass_2 / mass_1) ** (10. / (3 - n_ave)))
|
|
56
57
|
|
|
@@ -210,14 +211,14 @@ def _nicholl_bns_get_quantities(mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
|
210
211
|
kappa_blue * mejecta_blue) / (mejecta_purple + mejecta_red + mejecta_blue)
|
|
211
212
|
|
|
212
213
|
# Viewing angle and lanthanide-poor opening angle correction from Darbha and Kasen 2020
|
|
213
|
-
ct = (1 -
|
|
214
|
+
ct = (1 - cos_theta_open ** 2) ** 0.5
|
|
214
215
|
|
|
215
|
-
if
|
|
216
|
+
if cos_theta > ct:
|
|
216
217
|
area_projected_top = np.pi * ct * cos_theta
|
|
217
218
|
else:
|
|
218
|
-
theta_p = np.arccos(
|
|
219
|
+
theta_p = np.arccos(cos_theta_open /
|
|
219
220
|
(1 - cos_theta ** 2) ** 0.5)
|
|
220
|
-
theta_d = np.arctan(np.sin(theta_p) /
|
|
221
|
+
theta_d = np.arctan(np.sin(theta_p) / cos_theta_open *
|
|
221
222
|
(1 - cos_theta ** 2) ** 0.5 / np.abs(cos_theta))
|
|
222
223
|
area_projected_top = (theta_p - np.sin(theta_p) * np.cos(theta_p)) - (ct *
|
|
223
224
|
cos_theta * (theta_d - np.sin(theta_d) * np.cos(
|
|
@@ -228,9 +229,9 @@ def _nicholl_bns_get_quantities(mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
|
228
229
|
if minus_cos_theta < -1 * ct:
|
|
229
230
|
area_projected_bottom = 0
|
|
230
231
|
else:
|
|
231
|
-
theta_p2 = np.arccos(
|
|
232
|
+
theta_p2 = np.arccos(cos_theta_open /
|
|
232
233
|
(1 - minus_cos_theta ** 2) ** 0.5)
|
|
233
|
-
theta_d2 = np.arctan(np.sin(theta_p2) /
|
|
234
|
+
theta_d2 = np.arctan(np.sin(theta_p2) / cos_theta_open *
|
|
234
235
|
(1 - minus_cos_theta ** 2) ** 0.5 / np.abs(minus_cos_theta))
|
|
235
236
|
|
|
236
237
|
Aproj_bot1 = (theta_p2 - np.sin(theta_p2) * np.cos(theta_p2)) + (ct *
|
|
@@ -247,9 +248,9 @@ def _nicholl_bns_get_quantities(mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
|
247
248
|
if cos_theta_ref > ct:
|
|
248
249
|
area_ref_top = np.pi * ct * cos_theta_ref
|
|
249
250
|
else:
|
|
250
|
-
theta_p_ref = np.arccos(
|
|
251
|
+
theta_p_ref = np.arccos(cos_theta_open /
|
|
251
252
|
(1 - cos_theta_ref ** 2) ** 0.5)
|
|
252
|
-
theta_d_ref = np.arctan(np.sin(theta_p_ref) /
|
|
253
|
+
theta_d_ref = np.arctan(np.sin(theta_p_ref) / cos_theta_open *
|
|
253
254
|
(1 - cos_theta_ref ** 2) ** 0.5 / np.abs(cos_theta_ref))
|
|
254
255
|
area_ref_top = (theta_p_ref - np.sin(theta_p_ref) *
|
|
255
256
|
np.cos(theta_p_ref)) - (ct * cos_theta_ref *
|
|
@@ -261,10 +262,10 @@ def _nicholl_bns_get_quantities(mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
|
261
262
|
if minus_cos_theta_ref < -1 * ct:
|
|
262
263
|
area_ref_bottom = 0
|
|
263
264
|
else:
|
|
264
|
-
theta_p2_ref = np.arccos(
|
|
265
|
+
theta_p2_ref = np.arccos(cos_theta_open /
|
|
265
266
|
(1 - minus_cos_theta_ref ** 2) ** 0.5)
|
|
266
267
|
theta_d2_ref = np.arctan(np.sin(theta_p2_ref) /
|
|
267
|
-
|
|
268
|
+
cos_theta_open * (1 - minus_cos_theta_ref ** 2) ** 0.5 /
|
|
268
269
|
np.abs(minus_cos_theta_ref))
|
|
269
270
|
|
|
270
271
|
area_ref_bottom = (theta_p2_ref - np.sin(theta_p2_ref) *
|
|
@@ -309,7 +310,7 @@ def _nicholl_bns_get_quantities(mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
|
309
310
|
|
|
310
311
|
@citation_wrapper('https://ui.adsabs.harvard.edu/abs/2021MNRAS.505.3016N/abstract')
|
|
311
312
|
def nicholl_bns(time, redshift, mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
312
|
-
mtov, epsilon, alpha, cos_theta, cos_theta_cocoon, temperature_floor_1,
|
|
313
|
+
mtov, epsilon, alpha, cos_theta, cos_theta_open, cos_theta_cocoon, temperature_floor_1,
|
|
313
314
|
temperature_floor_2, temperature_floor_3, **kwargs):
|
|
314
315
|
"""
|
|
315
316
|
Kilonova model from Nicholl et al. 2021, inclides three kilonova components
|
|
@@ -327,6 +328,7 @@ def nicholl_bns(time, redshift, mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
|
327
328
|
:param alpha: Enhancement of blue ejecta by NS surface winds if mtotal < prompt collapse,
|
|
328
329
|
can turn off by setting alpha=1
|
|
329
330
|
:param cos_theta: Viewing angle of observer
|
|
331
|
+
:param cos_theta_open: Lanthanide opening angle
|
|
330
332
|
:param cos_theta_cocoon: Opening angle of shocked cocoon
|
|
331
333
|
:param temperature_floor_1: Temperature floor of first (blue) component
|
|
332
334
|
:param temperature_floor_2: Temperature floor of second (purple) component
|
|
@@ -351,11 +353,12 @@ def nicholl_bns(time, redshift, mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
|
351
353
|
cosmology = kwargs.get('cosmology', cosmo)
|
|
352
354
|
dl = cosmology.luminosity_distance(redshift).cgs.value
|
|
353
355
|
dense_resolution = kwargs.get('dense_resolution', 100)
|
|
354
|
-
time_temp = np.geomspace(0.
|
|
356
|
+
time_temp = np.geomspace(0.01, 30, dense_resolution) # in source frame and days
|
|
355
357
|
kappa_gamma = kwargs.get('kappa_gamma', 10)
|
|
358
|
+
ckm = 3e10/1e5
|
|
356
359
|
|
|
357
360
|
if np.max(time) > 20: # in source frame and days
|
|
358
|
-
time_temp = np.geomspace(0.
|
|
361
|
+
time_temp = np.geomspace(0.01, np.max(time) + 5, dense_resolution)
|
|
359
362
|
|
|
360
363
|
time_obs = time
|
|
361
364
|
shocked_fraction = kwargs.get('shocked_fraction', 0.2)
|
|
@@ -364,14 +367,14 @@ def nicholl_bns(time, redshift, mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
|
364
367
|
|
|
365
368
|
output = _nicholl_bns_get_quantities(mass_1=mass_1, mass_2=mass_2, lambda_s=lambda_s,
|
|
366
369
|
kappa_red=kappa_red, kappa_blue=kappa_blue, mtov=mtov,
|
|
367
|
-
epsilon=epsilon, alpha=alpha,
|
|
370
|
+
epsilon=epsilon, alpha=alpha, cos_theta_open=cos_theta_open,
|
|
368
371
|
cos_theta=cos_theta, **kwargs)
|
|
369
372
|
cocoon_output = _shocked_cocoon_nicholl(time=time_temp, kappa=kappa_blue, mejecta=output.mejecta_blue,
|
|
370
373
|
vejecta=output.vejecta_blue, cos_theta_cocoon=cos_theta_cocoon,
|
|
371
374
|
shocked_fraction=shocked_fraction, nn=nn, tshock=tshock)
|
|
372
375
|
cocoon_photo = CocoonPhotosphere(time=time_temp, luminosity=cocoon_output.lbol,
|
|
373
376
|
tau_diff=cocoon_output.taudiff, t_thin=cocoon_output.tthin,
|
|
374
|
-
vej=output.vejecta_blue, nn=nn)
|
|
377
|
+
vej=output.vejecta_blue*ckm, nn=nn)
|
|
375
378
|
mejs = [output.mejecta_blue, output.mejecta_purple, output.mejecta_red]
|
|
376
379
|
vejs = [output.vejecta_blue, output.vejecta_purple, output.vejecta_red]
|
|
377
380
|
area_projs = [output.area_blue, output.area_blue, output.area_red]
|
|
@@ -386,26 +389,29 @@ def nicholl_bns(time, redshift, mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
|
386
389
|
rad_func = interp1d(time_temp, y=cocoon_photo.r_photosphere)
|
|
387
390
|
# convert to source frame time and frequency
|
|
388
391
|
frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
|
|
389
|
-
temp = temp_func(
|
|
390
|
-
photosphere = rad_func(
|
|
392
|
+
temp = temp_func(time)
|
|
393
|
+
photosphere = rad_func(time)
|
|
391
394
|
flux_density = blackbody_to_flux_density(temperature=temp, r_photosphere=photosphere,
|
|
392
395
|
dl=dl, frequency=frequency)
|
|
393
396
|
ff = flux_density.value
|
|
397
|
+
ff = np.nan_to_num(ff)
|
|
394
398
|
for x in range(3):
|
|
395
399
|
lbols = _mosfit_kilonova_one_component_lbol(time=time_temp*day_to_s, mej=mejs[x], vej=vejs[x])
|
|
396
|
-
interaction_class = AsphericalDiffusion(time=time_temp
|
|
400
|
+
interaction_class = AsphericalDiffusion(time=time_temp, dense_times=time_temp,
|
|
397
401
|
luminosity=lbols, kappa=kappas[x], kappa_gamma=kappa_gamma,
|
|
398
|
-
mej=mejs[x], vej=vejs[x], area_projection=area_projs[x],
|
|
402
|
+
mej=mejs[x], vej=vejs[x]*ckm, area_projection=area_projs[x],
|
|
399
403
|
area_reference=area_refs[x])
|
|
400
404
|
lbols = interaction_class.new_luminosity
|
|
401
|
-
|
|
402
|
-
|
|
405
|
+
lbols = np.nan_to_num(lbols)
|
|
406
|
+
photo = TemperatureFloor(time=time_temp, luminosity=lbols,
|
|
407
|
+
temperature_floor=temperature_floors[x], vej=vejs[x]*ckm)
|
|
403
408
|
temp_func = interp1d(time_temp, y=photo.photosphere_temperature)
|
|
404
409
|
rad_func = interp1d(time_temp, y=photo.r_photosphere)
|
|
405
410
|
temp = temp_func(time)
|
|
406
411
|
photosphere = rad_func(time)
|
|
407
412
|
flux_density = blackbody_to_flux_density(temperature=temp, r_photosphere=photosphere,
|
|
408
413
|
dl=dl, frequency=frequency)
|
|
414
|
+
flux_density = np.nan_to_num(flux_density)
|
|
409
415
|
units = flux_density.unit
|
|
410
416
|
ff += flux_density.value
|
|
411
417
|
ff = ff * units
|
|
@@ -420,22 +426,24 @@ def nicholl_bns(time, redshift, mass_1, mass_2, lambda_s, kappa_red, kappa_blue,
|
|
|
420
426
|
frequency=frequency[:,None]).T
|
|
421
427
|
cocoon_spectra = fmjy.to(uu.mJy).to(uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom,
|
|
422
428
|
equivalencies=uu.spectral_density(wav=lambda_observer_frame * uu.Angstrom))
|
|
429
|
+
cocoon_spectra = np.nan_to_num(cocoon_spectra)
|
|
423
430
|
full_spec = cocoon_spectra.value
|
|
424
431
|
for x in range(3):
|
|
425
432
|
lbols = _mosfit_kilonova_one_component_lbol(time=time_temp*day_to_s, mej=mejs[x], vej=vejs[x])
|
|
426
|
-
interaction_class = AsphericalDiffusion(time=time_temp
|
|
433
|
+
interaction_class = AsphericalDiffusion(time=time_temp, dense_times=time_temp,
|
|
427
434
|
luminosity=lbols, kappa=kappas[x], kappa_gamma=kappa_gamma,
|
|
428
|
-
mej=mejs[x], vej=vejs[x], area_projection=area_projs[x],
|
|
435
|
+
mej=mejs[x], vej=vejs[x]*ckm, area_projection=area_projs[x],
|
|
429
436
|
area_reference=area_refs[x])
|
|
430
437
|
lbols = interaction_class.new_luminosity
|
|
431
|
-
photo = TemperatureFloor(time=time_temp
|
|
432
|
-
temperature_floor=temperature_floors[x], vej=vejs[x])
|
|
438
|
+
photo = TemperatureFloor(time=time_temp, luminosity=lbols,
|
|
439
|
+
temperature_floor=temperature_floors[x], vej=vejs[x]*ckm)
|
|
433
440
|
fmjy = blackbody_to_flux_density(temperature=photo.photosphere_temperature,
|
|
434
441
|
r_photosphere=photo.r_photosphere, dl=dl,
|
|
435
442
|
frequency=frequency[:, None])
|
|
436
443
|
fmjy = fmjy.T
|
|
437
444
|
spectra = fmjy.to(uu.mJy).to(uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom,
|
|
438
445
|
equivalencies=uu.spectral_density(wav=lambda_observer_frame * uu.Angstrom))
|
|
446
|
+
spectra = np.nan_to_num(spectra)
|
|
439
447
|
units = spectra.unit
|
|
440
448
|
full_spec += spectra.value
|
|
441
449
|
|
|
@@ -459,7 +467,7 @@ def mosfit_rprocess(time, redshift, mej, vej, kappa, kappa_gamma, temperature_fl
|
|
|
459
467
|
:param time: observer frame time in days
|
|
460
468
|
:param redshift: redshift
|
|
461
469
|
:param mej: ejecta mass in solar masses of first component
|
|
462
|
-
:param vej: minimum initial velocity of first component
|
|
470
|
+
:param vej: minimum initial velocity of first component in units of c
|
|
463
471
|
:param kappa: gray opacity of first component
|
|
464
472
|
:param temperature_floor: floor temperature of first component
|
|
465
473
|
:param kappa_gamma: gamma-ray opacity
|
|
@@ -473,25 +481,26 @@ def mosfit_rprocess(time, redshift, mej, vej, kappa, kappa_gamma, temperature_fl
|
|
|
473
481
|
:param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
|
|
474
482
|
:return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
|
|
475
483
|
"""
|
|
484
|
+
ckm = 3e10/1e5
|
|
476
485
|
cosmology = kwargs.get('cosmology', cosmo)
|
|
477
486
|
dl = cosmology.luminosity_distance(redshift).cgs.value
|
|
478
487
|
dense_resolution = kwargs.get('dense_resolution', 300)
|
|
479
|
-
time_temp = np.geomspace(1e-2,
|
|
488
|
+
time_temp = np.geomspace(1e-2, 7e6, dense_resolution) # in source frame in seconds
|
|
480
489
|
time_obs = time
|
|
481
490
|
lbols = _mosfit_kilonova_one_component_lbol(time=time_temp,
|
|
482
491
|
mej=mej, vej=vej)
|
|
483
|
-
interaction_class = Diffusion(time=time_temp, dense_times=time_temp, luminosity=lbols,
|
|
484
|
-
kappa=kappa, kappa_gamma=kappa_gamma, mej=mej, vej=vej)
|
|
492
|
+
interaction_class = Diffusion(time=time_temp / day_to_s, dense_times=time_temp / day_to_s, luminosity=lbols,
|
|
493
|
+
kappa=kappa, kappa_gamma=kappa_gamma, mej=mej, vej=vej*ckm)
|
|
485
494
|
lbols = interaction_class.new_luminosity
|
|
486
|
-
photo = TemperatureFloor(time=time_temp, luminosity=lbols, vej=vej,
|
|
495
|
+
photo = TemperatureFloor(time=time_temp / day_to_s, luminosity=lbols, vej=vej*ckm,
|
|
487
496
|
temperature_floor=temperature_floor)
|
|
488
497
|
|
|
489
498
|
if kwargs['output_format'] == 'flux_density':
|
|
490
|
-
time = time_obs * day_to_s
|
|
499
|
+
#time = time_obs * day_to_s
|
|
491
500
|
frequency = kwargs['frequency']
|
|
492
501
|
# interpolate properties onto observation times
|
|
493
|
-
temp_func = interp1d(time_temp, y=photo.photosphere_temperature)
|
|
494
|
-
rad_func = interp1d(time_temp, y=photo.r_photosphere)
|
|
502
|
+
temp_func = interp1d(time_temp / day_to_s, y=photo.photosphere_temperature)
|
|
503
|
+
rad_func = interp1d(time_temp / day_to_s, y=photo.r_photosphere)
|
|
495
504
|
# convert to source frame time and frequency
|
|
496
505
|
frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
|
|
497
506
|
temp = temp_func(time)
|
|
@@ -501,7 +510,7 @@ def mosfit_rprocess(time, redshift, mej, vej, kappa, kappa_gamma, temperature_fl
|
|
|
501
510
|
return flux_density.to(uu.mJy).value
|
|
502
511
|
else:
|
|
503
512
|
lambda_observer_frame = kwargs.get('lambda_array', np.geomspace(100, 60000, 200))
|
|
504
|
-
time_observer_frame = time_temp * (1. + redshift)
|
|
513
|
+
time_observer_frame = time_temp / day_to_s * (1. + redshift) # in days
|
|
505
514
|
frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
|
|
506
515
|
redshift=redshift, time=time_observer_frame)
|
|
507
516
|
fmjy = blackbody_to_flux_density(temperature=photo.photosphere_temperature,
|
|
@@ -514,7 +523,7 @@ def mosfit_rprocess(time, redshift, mej, vej, kappa, kappa_gamma, temperature_fl
|
|
|
514
523
|
lambdas=lambda_observer_frame,
|
|
515
524
|
spectra=spectra)
|
|
516
525
|
else:
|
|
517
|
-
return get_correct_output_format_from_spectra(time=time_obs, time_eval=time_observer_frame
|
|
526
|
+
return get_correct_output_format_from_spectra(time=time_obs, time_eval=time_observer_frame,
|
|
518
527
|
spectra=spectra, lambda_array=lambda_observer_frame,
|
|
519
528
|
**kwargs)
|
|
520
529
|
|
|
@@ -530,15 +539,15 @@ def mosfit_kilonova(time, redshift, mej_1, vej_1, temperature_floor_1, kappa_1,
|
|
|
530
539
|
:param time: observer frame time in days
|
|
531
540
|
:param redshift: redshift
|
|
532
541
|
:param mej_1: ejecta mass in solar masses of first component
|
|
533
|
-
:param vej_1: minimum initial velocity of first component
|
|
542
|
+
:param vej_1: minimum initial velocity of first component in units of c
|
|
534
543
|
:param kappa_1: gray opacity of first component
|
|
535
544
|
:param temperature_floor_1: floor temperature of first component
|
|
536
545
|
:param mej_2: ejecta mass in solar masses of second component
|
|
537
|
-
:param vej_2: minimum initial velocity of second component
|
|
546
|
+
:param vej_2: minimum initial velocity of second component in units of c
|
|
538
547
|
:param temperature_floor_2: floor temperature of second component
|
|
539
548
|
:param kappa_2: gray opacity of second component
|
|
540
549
|
:param mej_3: ejecta mass in solar masses of third component
|
|
541
|
-
:param vej_3: minimum initial velocity of third component
|
|
550
|
+
:param vej_3: minimum initial velocity of third component in units of c
|
|
542
551
|
:param temperature_floor_3: floor temperature of third component
|
|
543
552
|
:param kappa_3: gray opacity of third component
|
|
544
553
|
:param kappa_gamma: gamma-ray opacity
|
|
@@ -552,17 +561,18 @@ def mosfit_kilonova(time, redshift, mej_1, vej_1, temperature_floor_1, kappa_1,
|
|
|
552
561
|
:param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
|
|
553
562
|
:return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
|
|
554
563
|
"""
|
|
564
|
+
ckm = 3e10/1e5
|
|
555
565
|
cosmology = kwargs.get('cosmology', cosmo)
|
|
556
566
|
dl = cosmology.luminosity_distance(redshift).cgs.value
|
|
557
567
|
dense_resolution = kwargs.get('dense_resolution', 300)
|
|
558
|
-
time_temp = np.geomspace(1e-2,
|
|
568
|
+
time_temp = np.geomspace(1e-2, 7e6, dense_resolution) # in source frame in s
|
|
559
569
|
time_obs = time
|
|
560
570
|
mej = [mej_1, mej_2, mej_3]
|
|
561
571
|
vej = [vej_1, vej_2, vej_3]
|
|
562
572
|
temperature_floor = [temperature_floor_1, temperature_floor_2, temperature_floor_3]
|
|
563
573
|
kappa = [kappa_1, kappa_2, kappa_3]
|
|
564
574
|
if kwargs['output_format'] == 'flux_density':
|
|
565
|
-
time = time_obs * day_to_s
|
|
575
|
+
#time = time_obs * day_to_s
|
|
566
576
|
frequency = kwargs['frequency']
|
|
567
577
|
frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
|
|
568
578
|
|
|
@@ -570,13 +580,13 @@ def mosfit_kilonova(time, redshift, mej_1, vej_1, temperature_floor_1, kappa_1,
|
|
|
570
580
|
for x in range(3):
|
|
571
581
|
lbols = _mosfit_kilonova_one_component_lbol(time=time_temp,
|
|
572
582
|
mej=mej[x], vej=vej[x])
|
|
573
|
-
interaction_class = Diffusion(time=time_temp, dense_times=time_temp, luminosity=lbols,
|
|
574
|
-
kappa=kappa[x], kappa_gamma=kappa_gamma, mej=mej[x], vej=vej[x])
|
|
583
|
+
interaction_class = Diffusion(time=time_temp / day_to_s, dense_times=time_temp / day_to_s, luminosity=lbols,
|
|
584
|
+
kappa=kappa[x], kappa_gamma=kappa_gamma, mej=mej[x], vej=vej[x]*ckm)
|
|
575
585
|
lbols = interaction_class.new_luminosity
|
|
576
|
-
photo = TemperatureFloor(time=time_temp, luminosity=lbols, vej=vej[x],
|
|
586
|
+
photo = TemperatureFloor(time=time_temp / day_to_s, luminosity=lbols, vej=vej[x]*ckm,
|
|
577
587
|
temperature_floor=temperature_floor[x])
|
|
578
|
-
temp_func = interp1d(time_temp, y=photo.photosphere_temperature)
|
|
579
|
-
rad_func = interp1d(time_temp, y=photo.r_photosphere)
|
|
588
|
+
temp_func = interp1d(time_temp / day_to_s, y=photo.photosphere_temperature)
|
|
589
|
+
rad_func = interp1d(time_temp / day_to_s, y=photo.r_photosphere)
|
|
580
590
|
# convert to source frame time and frequency
|
|
581
591
|
temp = temp_func(time)
|
|
582
592
|
photosphere = rad_func(time)
|
|
@@ -588,17 +598,17 @@ def mosfit_kilonova(time, redshift, mej_1, vej_1, temperature_floor_1, kappa_1,
|
|
|
588
598
|
return ff.to(uu.mJy).value
|
|
589
599
|
else:
|
|
590
600
|
lambda_observer_frame = kwargs.get('lambda_array', np.geomspace(100, 60000, 200))
|
|
591
|
-
time_observer_frame = time_temp * (1. + redshift)
|
|
601
|
+
time_observer_frame = time_temp / day_to_s * (1. + redshift) # in days
|
|
592
602
|
frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
|
|
593
603
|
redshift=redshift, time=time_observer_frame)
|
|
594
604
|
full_spec = np.zeros((len(time), len(frequency)))
|
|
595
605
|
for x in range(3):
|
|
596
606
|
lbols = _mosfit_kilonova_one_component_lbol(time=time_temp,
|
|
597
607
|
mej=mej[x], vej=vej[x])
|
|
598
|
-
interaction_class = Diffusion(time=time_temp, dense_times=time_temp, luminosity=lbols,
|
|
599
|
-
kappa=kappa[x], kappa_gamma=kappa_gamma, mej=mej[x], vej=vej[x])
|
|
608
|
+
interaction_class = Diffusion(time=time_temp / day_to_s, dense_times=time_temp / day_to_s, luminosity=lbols,
|
|
609
|
+
kappa=kappa[x], kappa_gamma=kappa_gamma, mej=mej[x], vej=vej[x]*ckm)
|
|
600
610
|
lbols = interaction_class.new_luminosity
|
|
601
|
-
photo = TemperatureFloor(time=time_temp, luminosity=lbols, vej=vej[x],
|
|
611
|
+
photo = TemperatureFloor(time=time_temp / day_to_s, luminosity=lbols, vej=vej[x]*ckm,
|
|
602
612
|
temperature_floor=temperature_floor[x])
|
|
603
613
|
fmjy = blackbody_to_flux_density(temperature=photo.photosphere_temperature,
|
|
604
614
|
r_photosphere=photo.r_photosphere, frequency=frequency[:, None], dl=dl).T
|
|
@@ -613,7 +623,7 @@ def mosfit_kilonova(time, redshift, mej_1, vej_1, temperature_floor_1, kappa_1,
|
|
|
613
623
|
lambdas=lambda_observer_frame,
|
|
614
624
|
spectra=full_spec)
|
|
615
625
|
else:
|
|
616
|
-
return get_correct_output_format_from_spectra(time=time_obs, time_eval=time_observer_frame
|
|
626
|
+
return get_correct_output_format_from_spectra(time=time_obs, time_eval=time_observer_frame,
|
|
617
627
|
spectra=full_spec, lambda_array=lambda_observer_frame,
|
|
618
628
|
**kwargs)
|
|
619
629
|
|
|
@@ -817,7 +827,7 @@ def kasen_bns_kilonova(time, redshift, mej, vej, chi, **kwargs):
|
|
|
817
827
|
fmjy = spectra.to(uu.mJy, equivalencies=uu.spectral_density(wav=output.lambdas * uu.Angstrom)).value
|
|
818
828
|
nu_array = lambda_to_nu(output.lambdas)
|
|
819
829
|
fmjy_func = RegularGridInterpolator((np.unique(time), nu_array), fmjy, bounds_error=False)
|
|
820
|
-
if type(frequency) == float:
|
|
830
|
+
if type(frequency) == float or type(frequency) == np.float64:
|
|
821
831
|
frequency = np.ones(len(time)) * frequency
|
|
822
832
|
points = np.array([time, frequency]).T
|
|
823
833
|
return fmjy_func(points)
|
|
@@ -890,6 +900,11 @@ def _kilonova_hr(time, redshift, mej, velocity_array, kappa_array, beta, **kwarg
|
|
|
890
900
|
time = time * day_to_s
|
|
891
901
|
# convert to source frame time and frequency
|
|
892
902
|
frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
|
|
903
|
+
if (isinstance(frequency, (float, int)) == False):
|
|
904
|
+
radio_mask = frequency < 10e10
|
|
905
|
+
frequency[radio_mask]=10e50
|
|
906
|
+
elif frequency < 10e10:
|
|
907
|
+
frequency =10e50
|
|
893
908
|
|
|
894
909
|
_, temperature, r_photosphere = _kilonova_hr_sourceframe(time, mej, velocity_array, kappa_array, beta)
|
|
895
910
|
|
|
@@ -974,7 +989,7 @@ def three_component_kilonova_model(time, redshift, mej_1, vej_1, temperature_flo
|
|
|
974
989
|
"""
|
|
975
990
|
cosmology = kwargs.get('cosmology', cosmo)
|
|
976
991
|
dl = cosmology.luminosity_distance(redshift).cgs.value
|
|
977
|
-
time_temp = np.geomspace(1e-2,
|
|
992
|
+
time_temp = np.geomspace(1e-2, 7e6, 300) # in source frame
|
|
978
993
|
time_obs = time
|
|
979
994
|
|
|
980
995
|
mej = [mej_1, mej_2, mej_3]
|
|
@@ -1063,7 +1078,7 @@ def two_component_kilonova_model(time, redshift, mej_1, vej_1, temperature_floor
|
|
|
1063
1078
|
"""
|
|
1064
1079
|
cosmology = kwargs.get('cosmology', cosmo)
|
|
1065
1080
|
dl = cosmology.luminosity_distance(redshift).cgs.value
|
|
1066
|
-
time_temp = np.geomspace(1e-2,
|
|
1081
|
+
time_temp = np.geomspace(1e-2, 7e6, 300) # in source frame
|
|
1067
1082
|
time_obs = time
|
|
1068
1083
|
|
|
1069
1084
|
mej = [mej_1, mej_2]
|
|
@@ -1376,7 +1391,7 @@ def one_component_kilonova_model(time, redshift, mej, vej, kappa, **kwargs):
|
|
|
1376
1391
|
"""
|
|
1377
1392
|
cosmology = kwargs.get('cosmology', cosmo)
|
|
1378
1393
|
dl = cosmology.luminosity_distance(redshift).cgs.value
|
|
1379
|
-
time_temp = np.geomspace(1e-3,
|
|
1394
|
+
time_temp = np.geomspace(1e-3, 7e6, 300) # in source frame
|
|
1380
1395
|
time_obs = time
|
|
1381
1396
|
_, temperature, r_photosphere = _one_component_kilonova_model(time_temp, mej, vej, kappa, **kwargs)
|
|
1382
1397
|
|
|
@@ -1416,6 +1431,240 @@ def one_component_kilonova_model(time, redshift, mej, vej, kappa, **kwargs):
|
|
|
1416
1431
|
spectra=spectra, lambda_array=lambda_observer_frame,
|
|
1417
1432
|
**kwargs)
|
|
1418
1433
|
|
|
1434
|
+
|
|
1435
|
+
def _calc_new_heating_rate(time, mej, electron_fraction, ejecta_velocity, **kwargs):
|
|
1436
|
+
"""
|
|
1437
|
+
Heating rate prescription following Rosswog and Korobkin 2024
|
|
1438
|
+
|
|
1439
|
+
:param time: time in seconds
|
|
1440
|
+
:param mej: ejecta mass in solar masses
|
|
1441
|
+
:param electron_fraction: electron fraction
|
|
1442
|
+
:param ejecta_velocity: ejecta velocity in c
|
|
1443
|
+
:param kwargs: Additional keyword arguments
|
|
1444
|
+
: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.
|
|
1445
|
+
:param heating_rate_fudge: A fudge factor for each of the terms in the heating rate. Default to 1. i.e., no uncertainty
|
|
1446
|
+
Default is 1.0 i.e., no perturbation.
|
|
1447
|
+
:return: heating rate in erg/s
|
|
1448
|
+
"""
|
|
1449
|
+
heating_rate_perturbation = kwargs.get('heating_rate_perturbation', 1.0)
|
|
1450
|
+
# rescale
|
|
1451
|
+
m0 = mej * solar_mass
|
|
1452
|
+
qdot_in = _calculate_rosswogkorobkin24_qdot(time, ejecta_velocity, electron_fraction)
|
|
1453
|
+
lum_in = qdot_in * m0
|
|
1454
|
+
return lum_in * heating_rate_perturbation
|
|
1455
|
+
|
|
1456
|
+
def _calculate_rosswogkorobkin24_qdot_formula(time_array, e0, alp, t0, sig, alp1,
|
|
1457
|
+
t1, sig1, c1, tau1, c2, tau2, c3, tau3):
|
|
1458
|
+
time = time_array
|
|
1459
|
+
c1 = np.exp(c1)
|
|
1460
|
+
c2 = np.exp(c2)
|
|
1461
|
+
c3 = np.exp(c3)
|
|
1462
|
+
tau1 = 1e3 * tau1
|
|
1463
|
+
tau2 = 1e5 * tau2
|
|
1464
|
+
tau3 = 1e5 * tau3
|
|
1465
|
+
term1 = 10. ** (e0 + 18) * (0.5 - np.arctan((time - t0) / sig) / np.pi) ** alp
|
|
1466
|
+
term2 = (0.5 + np.arctan((time - t1) / sig1) / np.pi) ** alp1
|
|
1467
|
+
term3 = c1 * np.exp(-time / tau1)
|
|
1468
|
+
term4 = c2 * np.exp(-time / tau2)
|
|
1469
|
+
term5 = c3 * np.exp(-time / tau3)
|
|
1470
|
+
lum_in = term1 * term2 + term3 + term4 + term5
|
|
1471
|
+
return lum_in
|
|
1472
|
+
|
|
1473
|
+
def _one_component_kilonova_rosswog_heatingrate(time, mej, vej, electron_fraction, **kwargs):
|
|
1474
|
+
tdays = time/day_to_s
|
|
1475
|
+
# set up kilonova physics
|
|
1476
|
+
av, bv, dv = interpolated_barnes_and_kasen_thermalisation_efficiency(mej, vej)
|
|
1477
|
+
# thermalisation from Barnes+16
|
|
1478
|
+
e_th = 0.36 * (np.exp(-av * tdays) + np.log1p(2.0 * bv * tdays ** dv) / (2.0 * bv * tdays ** dv))
|
|
1479
|
+
temperature_floor = kwargs.get('temperature_floor', 4000) # kelvin
|
|
1480
|
+
beta = 13.7
|
|
1481
|
+
|
|
1482
|
+
v0 = vej * speed_of_light
|
|
1483
|
+
m0 = mej * solar_mass
|
|
1484
|
+
kappa = kappa_from_electron_fraction(electron_fraction)
|
|
1485
|
+
tdiff = np.sqrt(2.0 * kappa * (m0) / (beta * v0 * speed_of_light))
|
|
1486
|
+
|
|
1487
|
+
lum_in = _calc_new_heating_rate(time, mej, electron_fraction, vej, **kwargs)
|
|
1488
|
+
integrand = lum_in * e_th * (time / tdiff) * np.exp(time ** 2 / tdiff ** 2)
|
|
1489
|
+
|
|
1490
|
+
bolometric_luminosity = np.zeros(len(time))
|
|
1491
|
+
bolometric_luminosity[1:] = cumulative_trapezoid(integrand, time)
|
|
1492
|
+
bolometric_luminosity[0] = bolometric_luminosity[1]
|
|
1493
|
+
bolometric_luminosity = bolometric_luminosity * np.exp(-time ** 2 / tdiff ** 2) / tdiff
|
|
1494
|
+
|
|
1495
|
+
temperature = (bolometric_luminosity / (4.0 * np.pi * sigma_sb * v0 ** 2 * time ** 2)) ** 0.25
|
|
1496
|
+
r_photosphere = (bolometric_luminosity / (4.0 * np.pi * sigma_sb * temperature_floor ** 4)) ** 0.5
|
|
1497
|
+
|
|
1498
|
+
# check temperature floor conditions
|
|
1499
|
+
mask = temperature <= temperature_floor
|
|
1500
|
+
temperature[mask] = temperature_floor
|
|
1501
|
+
mask = np.logical_not(mask)
|
|
1502
|
+
r_photosphere[mask] = v0 * time[mask]
|
|
1503
|
+
return bolometric_luminosity, temperature, r_photosphere
|
|
1504
|
+
|
|
1505
|
+
@citation_wrapper('https://ui.adsabs.harvard.edu/abs/2024arXiv240407271S/abstract, https://ui.adsabs.harvard.edu/abs/2024AnP...53600306R/abstract')
|
|
1506
|
+
def one_comp_kne_rosswog_heatingrate(time, redshift, mej, vej, ye, **kwargs):
|
|
1507
|
+
"""
|
|
1508
|
+
:param time: observer frame time in days
|
|
1509
|
+
:param redshift: redshift
|
|
1510
|
+
:param mej: ejecta mass in solar masses
|
|
1511
|
+
:param vej: minimum initial velocity
|
|
1512
|
+
:param kappa: gray opacity
|
|
1513
|
+
:param kwargs: Additional keyword arguments
|
|
1514
|
+
:param temperature_floor: Temperature floor in K (default 4000)
|
|
1515
|
+
:param heating_rate_perturbation: A fudge factor for heating rate to account for uncertainties in the heating rate.
|
|
1516
|
+
Default is 1.0 i.e., no perturbation.
|
|
1517
|
+
:param heating_rate_fudge: A fudge factor for each of the terms in the heating rate. Default to 1. i.e., no uncertainty
|
|
1518
|
+
:param frequency: Required if output_format is 'flux_density'.
|
|
1519
|
+
frequency to calculate - Must be same length as time array or a single number).
|
|
1520
|
+
:param bands: Required if output_format is 'magnitude' or 'flux'.
|
|
1521
|
+
:param output_format: 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
|
|
1522
|
+
:param lambda_array: Optional argument to set your desired wavelength array (in Angstroms) to evaluate the SED on.
|
|
1523
|
+
:param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
|
|
1524
|
+
:return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
|
|
1525
|
+
"""
|
|
1526
|
+
cosmology = kwargs.get('cosmology', cosmo)
|
|
1527
|
+
dl = cosmology.luminosity_distance(redshift).cgs.value
|
|
1528
|
+
time_temp = np.geomspace(1e-3, 7e6, 300) # in source frame
|
|
1529
|
+
time_obs = time
|
|
1530
|
+
_, temperature, r_photosphere = _one_component_kilonova_rosswog_heatingrate(time_temp, mej, vej, ye, **kwargs)
|
|
1531
|
+
|
|
1532
|
+
if kwargs['output_format'] == 'flux_density':
|
|
1533
|
+
time = time_obs * day_to_s
|
|
1534
|
+
frequency = kwargs['frequency']
|
|
1535
|
+
# interpolate properties onto observation times
|
|
1536
|
+
temp_func = interp1d(time_temp, y=temperature)
|
|
1537
|
+
rad_func = interp1d(time_temp, y=r_photosphere)
|
|
1538
|
+
# convert to source frame time and frequency
|
|
1539
|
+
frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
|
|
1540
|
+
|
|
1541
|
+
temp = temp_func(time)
|
|
1542
|
+
photosphere = rad_func(time)
|
|
1543
|
+
|
|
1544
|
+
flux_density = blackbody_to_flux_density(temperature=temp, r_photosphere=photosphere,
|
|
1545
|
+
dl=dl, frequency=frequency)
|
|
1546
|
+
|
|
1547
|
+
return flux_density.to(uu.mJy).value
|
|
1548
|
+
|
|
1549
|
+
else:
|
|
1550
|
+
lambda_observer_frame = kwargs.get('lambda_array', np.geomspace(100, 60000, 200))
|
|
1551
|
+
time_observer_frame = time_temp * (1. + redshift)
|
|
1552
|
+
frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
|
|
1553
|
+
redshift=redshift, time=time_observer_frame)
|
|
1554
|
+
fmjy = blackbody_to_flux_density(temperature=temperature,
|
|
1555
|
+
r_photosphere=r_photosphere, frequency=frequency[:, None], dl=dl)
|
|
1556
|
+
fmjy = fmjy.T
|
|
1557
|
+
spectra = fmjy.to(uu.mJy).to(uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom,
|
|
1558
|
+
equivalencies=uu.spectral_density(wav=lambda_observer_frame * uu.Angstrom))
|
|
1559
|
+
if kwargs['output_format'] == 'spectra':
|
|
1560
|
+
return namedtuple('output', ['time', 'lambdas', 'spectra'])(time=time_observer_frame,
|
|
1561
|
+
lambdas=lambda_observer_frame,
|
|
1562
|
+
spectra=spectra)
|
|
1563
|
+
else:
|
|
1564
|
+
return get_correct_output_format_from_spectra(time=time_obs, time_eval=time_observer_frame/day_to_s,
|
|
1565
|
+
spectra=spectra, lambda_array=lambda_observer_frame,
|
|
1566
|
+
**kwargs)
|
|
1567
|
+
|
|
1568
|
+
@citation_wrapper('https://ui.adsabs.harvard.edu/abs/2024arXiv240407271S/abstract, https://ui.adsabs.harvard.edu/abs/2024AnP...53600306R/abstract')
|
|
1569
|
+
def two_comp_kne_rosswog_heatingrate(time, redshift, mej_1, vej_1, temperature_floor_1, ye_1,
|
|
1570
|
+
mej_2, vej_2, temperature_floor_2, ye_2, **kwargs):
|
|
1571
|
+
"""
|
|
1572
|
+
:param time: observer frame time in days
|
|
1573
|
+
:param redshift: redshift
|
|
1574
|
+
:param mej_1: ejecta mass in solar masses of first component
|
|
1575
|
+
:param vej_1: minimum initial velocity of first component
|
|
1576
|
+
:param kappa_1: gray opacity of first component
|
|
1577
|
+
:param temperature_floor_1: floor temperature of first component
|
|
1578
|
+
:param mej_2: ejecta mass in solar masses of second component
|
|
1579
|
+
:param vej_2: minimum initial velocity of second component
|
|
1580
|
+
:param temperature_floor_2: floor temperature of second component
|
|
1581
|
+
:param kappa_2: gray opacity of second component
|
|
1582
|
+
:param kwargs: Additional keyword arguments
|
|
1583
|
+
:param heating_rate_perturbation: A fudge factor for heating rate to account for uncertainties in the heating rate.
|
|
1584
|
+
Default is 1.0 i.e., no perturbation.
|
|
1585
|
+
:param heating_rate_fudge: A fudge factor for each of the terms in the heating rate. Default to 1. i.e., no uncertainty
|
|
1586
|
+
:param frequency: Required if output_format is 'flux_density'.
|
|
1587
|
+
frequency to calculate - Must be same length as time array or a single number).
|
|
1588
|
+
:param bands: Required if output_format is 'magnitude' or 'flux'.
|
|
1589
|
+
:param output_format: 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
|
|
1590
|
+
:param lambda_array: Optional argument to set your desired wavelength array (in Angstroms) to evaluate the SED on.
|
|
1591
|
+
:param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
|
|
1592
|
+
:return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
|
|
1593
|
+
"""
|
|
1594
|
+
cosmology = kwargs.get('cosmology', cosmo)
|
|
1595
|
+
dl = cosmology.luminosity_distance(redshift).cgs.value
|
|
1596
|
+
time_temp = np.geomspace(1e-2, 7e6, 300) # in source frame
|
|
1597
|
+
time_obs = time
|
|
1598
|
+
|
|
1599
|
+
mej = [mej_1, mej_2]
|
|
1600
|
+
vej = [vej_1, vej_2]
|
|
1601
|
+
temperature_floor = [temperature_floor_1, temperature_floor_2]
|
|
1602
|
+
ye = [ye_1, ye_2]
|
|
1603
|
+
|
|
1604
|
+
if kwargs['output_format'] == 'flux_density':
|
|
1605
|
+
time = time * day_to_s
|
|
1606
|
+
frequency = kwargs['frequency']
|
|
1607
|
+
|
|
1608
|
+
# convert to source frame time and frequency
|
|
1609
|
+
frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
|
|
1610
|
+
|
|
1611
|
+
ff = np.zeros(len(time))
|
|
1612
|
+
for x in range(2):
|
|
1613
|
+
temp_kwargs = {}
|
|
1614
|
+
if 'heating_rate_fudge' in kwargs:
|
|
1615
|
+
temp_kwargs['heating_rate_fudge'] = kwargs['heating_rate_fudge']
|
|
1616
|
+
if 'heating_rate_perturbation' in kwargs:
|
|
1617
|
+
temp_kwargs['heating_rate_perturbation'] = kwargs['heating_rate_perturbation']
|
|
1618
|
+
temp_kwargs['temperature_floor'] = temperature_floor[x]
|
|
1619
|
+
_, temperature, r_photosphere = _one_component_kilonova_rosswog_heatingrate(time_temp, mej[x], vej[x], ye[x],
|
|
1620
|
+
**temp_kwargs)
|
|
1621
|
+
# interpolate properties onto observation times
|
|
1622
|
+
temp_func = interp1d(time_temp, y=temperature)
|
|
1623
|
+
rad_func = interp1d(time_temp, y=r_photosphere)
|
|
1624
|
+
temp = temp_func(time)
|
|
1625
|
+
photosphere = rad_func(time)
|
|
1626
|
+
flux_density = blackbody_to_flux_density(temperature=temp, r_photosphere=photosphere,
|
|
1627
|
+
dl=dl, frequency=frequency)
|
|
1628
|
+
units = flux_density.unit
|
|
1629
|
+
ff += flux_density.value
|
|
1630
|
+
|
|
1631
|
+
ff = ff * units
|
|
1632
|
+
return ff.to(uu.mJy).value
|
|
1633
|
+
|
|
1634
|
+
else:
|
|
1635
|
+
lambda_observer_frame = kwargs.get('lambda_array', np.geomspace(100, 60000, 200))
|
|
1636
|
+
time_observer_frame = time_temp * (1. + redshift)
|
|
1637
|
+
frequency, time = calc_kcorrected_properties(frequency=lambda_to_nu(lambda_observer_frame),
|
|
1638
|
+
redshift=redshift, time=time_observer_frame)
|
|
1639
|
+
full_spec = np.zeros((len(time), len(frequency)))
|
|
1640
|
+
|
|
1641
|
+
for x in range(2):
|
|
1642
|
+
temp_kwargs = {}
|
|
1643
|
+
if 'heating_rate_fudge' in kwargs:
|
|
1644
|
+
temp_kwargs['heating_rate_fudge'] = kwargs['heating_rate_fudge']
|
|
1645
|
+
if 'heating_rate_perturbation' in kwargs:
|
|
1646
|
+
temp_kwargs['heating_rate_perturbation'] = kwargs['heating_rate_perturbation']
|
|
1647
|
+
temp_kwargs['temperature_floor'] = temperature_floor[x]
|
|
1648
|
+
_, temperature, r_photosphere = _one_component_kilonova_rosswog_heatingrate(time_temp, mej[x], vej[x], ye[x],
|
|
1649
|
+
**temp_kwargs)
|
|
1650
|
+
fmjy = blackbody_to_flux_density(temperature=temperature,
|
|
1651
|
+
r_photosphere=r_photosphere, frequency=frequency[:, None], dl=dl)
|
|
1652
|
+
fmjy = fmjy.T
|
|
1653
|
+
spectra = fmjy.to(uu.mJy).to(uu.erg / uu.cm ** 2 / uu.s / uu.Angstrom,
|
|
1654
|
+
equivalencies=uu.spectral_density(wav=lambda_observer_frame * uu.Angstrom))
|
|
1655
|
+
units = spectra.unit
|
|
1656
|
+
full_spec += spectra.value
|
|
1657
|
+
|
|
1658
|
+
full_spec = full_spec * units
|
|
1659
|
+
if kwargs['output_format'] == 'spectra':
|
|
1660
|
+
return namedtuple('output', ['time', 'lambdas', 'spectra'])(time=time_observer_frame,
|
|
1661
|
+
lambdas=lambda_observer_frame,
|
|
1662
|
+
spectra=full_spec)
|
|
1663
|
+
else:
|
|
1664
|
+
return get_correct_output_format_from_spectra(time=time_obs, time_eval=time_observer_frame/day_to_s,
|
|
1665
|
+
spectra=full_spec, lambda_array=lambda_observer_frame,
|
|
1666
|
+
**kwargs)
|
|
1667
|
+
|
|
1419
1668
|
def _one_component_kilonova_model(time, mej, vej, kappa, **kwargs):
|
|
1420
1669
|
"""
|
|
1421
1670
|
:param time: source frame time in seconds
|
|
@@ -1444,7 +1693,7 @@ def _one_component_kilonova_model(time, mej, vej, kappa, **kwargs):
|
|
|
1444
1693
|
lum_in = 4.0e18 * (m0) * (0.5 - np.arctan((time - t0) / sig) / np.pi)**1.3
|
|
1445
1694
|
integrand = lum_in * e_th * (time/tdiff) * np.exp(time**2/tdiff**2)
|
|
1446
1695
|
bolometric_luminosity = np.zeros(len(time))
|
|
1447
|
-
bolometric_luminosity[1:] =
|
|
1696
|
+
bolometric_luminosity[1:] = cumulative_trapezoid(integrand, time)
|
|
1448
1697
|
bolometric_luminosity[0] = bolometric_luminosity[1]
|
|
1449
1698
|
bolometric_luminosity = bolometric_luminosity * np.exp(-time**2/tdiff**2) / tdiff
|
|
1450
1699
|
|
|
@@ -1479,7 +1728,7 @@ def metzger_kilonova_model(time, redshift, mej, vej, beta, kappa, **kwargs):
|
|
|
1479
1728
|
"""
|
|
1480
1729
|
cosmology = kwargs.get('cosmology', cosmo)
|
|
1481
1730
|
dl = cosmology.luminosity_distance(redshift).cgs.value
|
|
1482
|
-
time_temp = np.geomspace(1e-4,
|
|
1731
|
+
time_temp = np.geomspace(1e-4, 7e6, 300) # in source frame
|
|
1483
1732
|
time_obs = time
|
|
1484
1733
|
bolometric_luminosity, temperature, r_photosphere = _metzger_kilonova_model(time_temp, mej, vej, beta,
|
|
1485
1734
|
kappa, **kwargs)
|