redback 1.0.0__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 (43) hide show
  1. redback/__init__.py +4 -0
  2. redback/constraints.py +31 -25
  3. redback/ejecta_relations.py +8 -8
  4. redback/get_data/lasair.py +3 -4
  5. redback/get_data/swift.py +7 -7
  6. redback/interaction_processes.py +1 -4
  7. redback/likelihoods.py +207 -21
  8. redback/plotting.py +11 -11
  9. redback/priors/csm_interaction.prior +6 -7
  10. redback/priors/csm_nickel.prior +3 -3
  11. redback/priors/one_comp_kne_rosswog_heatingrate.prior +5 -0
  12. redback/priors/one_component_nsbh_ejecta_relation.prior +1 -1
  13. redback/priors/tde_analytical.prior +5 -5
  14. redback/priors/tde_analytical_bolometric.prior +6 -4
  15. redback/priors/tophat_from_emulator.prior +9 -0
  16. redback/priors/two_comp_kne_rosswog_heatingrate.prior +9 -0
  17. redback/priors/two_component_nsbh_ejecta_relation.prior +1 -1
  18. redback/priors/two_layer_stratified_kilonova.prior +1 -1
  19. redback/priors.py +11 -0
  20. redback/sed.py +194 -2
  21. redback/simulate_transients.py +61 -32
  22. redback/tables/filters.csv +15 -1
  23. redback/tables/ztf.tar.gz +0 -0
  24. redback/transient/afterglow.py +3 -2
  25. redback/transient/kilonova.py +1 -1
  26. redback/transient/supernova.py +1 -1
  27. redback/transient/tde.py +1 -1
  28. redback/transient/transient.py +2 -2
  29. redback/transient_models/afterglow_models.py +42 -0
  30. redback/transient_models/combined_models.py +47 -32
  31. redback/transient_models/extinction_models.py +12 -5
  32. redback/transient_models/kilonova_models.py +247 -14
  33. redback/transient_models/magnetar_driven_ejecta_models.py +2 -2
  34. redback/transient_models/phenomenological_models.py +13 -0
  35. redback/transient_models/supernova_models.py +50 -36
  36. redback/transient_models/tde_models.py +126 -1
  37. redback/utils.py +283 -6
  38. {redback-1.0.0.dist-info → redback-1.0.2.dist-info}/METADATA +7 -4
  39. {redback-1.0.0.dist-info → redback-1.0.2.dist-info}/RECORD +42 -40
  40. {redback-1.0.0.dist-info → redback-1.0.2.dist-info}/WHEEL +1 -1
  41. redback/tables/ztf_obslog.csv +0 -106649
  42. {redback-1.0.0.dist-info → redback-1.0.2.dist-info}/LICENCE.md +0 -0
  43. {redback-1.0.0.dist-info → redback-1.0.2.dist-info}/top_level.txt +0 -0
@@ -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,7 +11,14 @@ extinction_afterglow_base_models = ['tophat', 'cocoon', 'gaussian',
12
11
  'kn_afterglow', 'cone_afterglow',
13
12
  'gaussiancore', 'gaussian',
14
13
  'smoothpowerlaw', 'powerlawcore',
15
- 'tophat']
14
+ 'tophat','tophat_from_emulator',
15
+ 'kilonova_afterglow_redback', 'kilonova_afterglow_nakarpiran',
16
+ 'tophat_redback', 'gaussian_redback', 'twocomponent_redback',
17
+ 'powerlaw_redback', 'alternativepowerlaw_redback', 'doublegaussian_redback',
18
+ 'tophat_redback_refreshed', 'gaussian_redback_refreshed',
19
+ 'twocomponent_redback_refreshed','powerlaw_redback_refreshed',
20
+ 'alternativepowerlaw_redback_refreshed', 'doublegaussian_redback_refreshed']
21
+
16
22
  extinction_integrated_flux_afterglow_models = extinction_afterglow_base_models
17
23
  extinction_supernova_base_models = ['sn_exponential_powerlaw', 'arnett', 'shock_cooling_and_arnett',
18
24
  'basic_magnetar_powered', 'slsn', 'magnetar_nickel',
@@ -20,16 +26,17 @@ extinction_supernova_base_models = ['sn_exponential_powerlaw', 'arnett', 'shock_
20
26
  'general_magnetar_slsn','general_magnetar_driven_supernova']
21
27
  extinction_kilonova_base_models = ['nicholl_bns', 'mosfit_rprocess', 'mosfit_kilonova',
22
28
  'power_law_stratified_kilonova','bulla_bns_kilonova',
23
- 'bulla_nsbh_kilonova', 'kasen_nsbh_kilonova','two_layer_stratified_kilonova',
29
+ 'bulla_nsbh_kilonova', 'kasen_bns_kilonova','two_layer_stratified_kilonova',
24
30
  'three_component_kilonova_model', 'two_component_kilonova_model',
25
31
  'one_component_kilonova_model', 'one_component_ejecta_relation',
26
32
  'one_component_ejecta_relation_projection', 'two_component_bns_ejecta_relation',
27
33
  'polytrope_eos_two_component_bns', 'one_component_nsbh_ejecta_relation',
28
34
  'two_component_nsbh_ejecta_relation','metzger_kilonova_model']
29
- extinction_tde_base_models = ['tde_analytical', 'tde_semianalytical', 'gaussianrise_metzger_tde']
35
+ extinction_tde_base_models = ['tde_analytical', 'tde_semianalytical', 'gaussianrise_cooling_envelope',
36
+ 'cooling_envelope', 'bpl_cooling_envelope']
30
37
  extinction_magnetar_driven_base_models = ['basic_mergernova', 'general_mergernova', 'general_mergernova_thermalisation',
31
38
  'general_mergernova_evolution', 'metzger_magnetar_driven_kilonova_model',
32
- 'general_metzger_magnetar_driven', 'general_magnetar_driven_thermalisation',
39
+ 'general_metzger_magnetar_driven', 'general_metzger_magnetar_driven_thermalisation',
33
40
  'general_metzger_magnetar_driven_evolution']
34
41
  extinction_shock_powered_base_models = ['shocked_cocoon', 'shock_cooling']
35
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]
@@ -1284,7 +1289,7 @@ def polytrope_eos_two_component_bns(time, redshift, mass_1, mass_2, log_p, gamm
1284
1289
 
1285
1290
  @citation_wrapper('redback')
1286
1291
  def one_component_nsbh_ejecta_relation(time, redshift, mass_bh, mass_ns,
1287
- chi_eff, lambda_ns, kappa, **kwargs):
1292
+ chi_bh, lambda_ns, kappa, **kwargs):
1288
1293
  """
1289
1294
  One component NSBH model
1290
1295
 
@@ -1292,7 +1297,7 @@ def one_component_nsbh_ejecta_relation(time, redshift, mass_bh, mass_ns,
1292
1297
  :param redshift: redshift
1293
1298
  :param mass_bh: mass of black hole
1294
1299
  :param mass_2: mass of neutron star
1295
- :param chi_eff: effective spin of black hole
1300
+ :param chi_bh: spin of black hole along z axis
1296
1301
  :param lambda_ns: tidal deformability of neutron star
1297
1302
  :param kappa: opacity
1298
1303
  :param kwargs: additional keyword arguments
@@ -1308,7 +1313,7 @@ def one_component_nsbh_ejecta_relation(time, redshift, mass_bh, mass_ns,
1308
1313
  :return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
1309
1314
  """
1310
1315
  ejecta_relation = kwargs.get('ejecta_relation', ejr.OneComponentNSBH)
1311
- ejecta_relation = ejecta_relation(mass_bh=mass_bh, mass_ns=mass_ns, chi_eff=chi_eff, lambda_ns=lambda_ns)
1316
+ ejecta_relation = ejecta_relation(mass_bh=mass_bh, mass_ns=mass_ns, chi_bh=chi_bh, lambda_ns=lambda_ns)
1312
1317
  mej = ejecta_relation.ejecta_mass
1313
1318
  vej = ejecta_relation.ejecta_velocity
1314
1319
  output = one_component_kilonova_model(time, redshift, mej, vej, kappa, **kwargs)
@@ -1316,7 +1321,7 @@ def one_component_nsbh_ejecta_relation(time, redshift, mass_bh, mass_ns,
1316
1321
 
1317
1322
  @citation_wrapper('redback')
1318
1323
  def two_component_nsbh_ejecta_relation(time, redshift, mass_bh, mass_ns,
1319
- chi_eff, lambda_ns, zeta, vej_2, kappa_1, kappa_2, tf_1, tf_2, **kwargs):
1324
+ chi_bh, lambda_ns, zeta, vej_2, kappa_1, kappa_2, tf_1, tf_2, **kwargs):
1320
1325
  """
1321
1326
  Two component NSBH model with dynamical and disk wind ejecta
1322
1327
 
@@ -1324,7 +1329,7 @@ def two_component_nsbh_ejecta_relation(time, redshift, mass_bh, mass_ns,
1324
1329
  :param redshift: redshift
1325
1330
  :param mass_bh: mass of black hole
1326
1331
  :param mass_2: mass of neutron star
1327
- :param chi_eff: effective spin of black hole
1332
+ :param chi_bh: spin of black hole along z axis
1328
1333
  :param lambda_ns: tidal deformability of neutron star
1329
1334
  :param zeta: fraction of disk that gets unbound
1330
1335
  :param vej_2: disk wind velocity in c
@@ -1344,7 +1349,7 @@ def two_component_nsbh_ejecta_relation(time, redshift, mass_bh, mass_ns,
1344
1349
  :return: set by output format - 'flux_density', 'magnitude', 'spectra', 'flux', 'sncosmo_source'
1345
1350
  """
1346
1351
  ejecta_relation = kwargs.get('ejecta_relation', ejr.TwoComponentNSBH)
1347
- ejecta_relation = ejecta_relation(mass_bh=mass_bh, mass_ns=mass_ns, chi_eff=chi_eff,
1352
+ ejecta_relation = ejecta_relation(mass_bh=mass_bh, mass_ns=mass_ns, chi_bh=chi_bh,
1348
1353
  lambda_ns=lambda_ns, zeta=zeta)
1349
1354
  mej_1 = ejecta_relation.dynamical_mej
1350
1355
  mej_2 = ejecta_relation.disk_wind_mej
@@ -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
@@ -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)