redback 1.0.31__py3-none-any.whl → 1.1__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 (48) hide show
  1. redback/__init__.py +3 -2
  2. redback/analysis.py +321 -4
  3. redback/filters.py +57 -23
  4. redback/get_data/directory.py +18 -0
  5. redback/likelihoods.py +260 -0
  6. redback/model_library.py +12 -2
  7. redback/plotting.py +335 -4
  8. redback/priors/blackbody_spectrum_with_absorption_and_emission_lines.prior +9 -0
  9. redback/priors/csm_shock_and_arnett_two_rphots.prior +11 -0
  10. redback/priors/exp_rise_powerlaw_decline.prior +6 -0
  11. redback/priors/powerlaw_spectrum_with_absorption_and_emission_lines.prior +8 -0
  12. redback/priors/shockcooling_morag.prior +6 -0
  13. redback/priors/shockcooling_morag_and_arnett.prior +10 -0
  14. redback/priors/shockcooling_morag_and_arnett_bolometric.prior +9 -0
  15. redback/priors/shockcooling_morag_bolometric.prior +5 -0
  16. redback/priors/shockcooling_sapirandwaxman.prior +6 -0
  17. redback/priors/shockcooling_sapirandwaxman_bolometric.prior +5 -0
  18. redback/priors/shockcooling_sapirwaxman_and_arnett.prior +10 -0
  19. redback/priors/shockcooling_sapirwaxman_and_arnett_bolometric.prior +9 -0
  20. redback/priors/shocked_cocoon_and_arnett.prior +13 -0
  21. redback/priors/synchrotron_ism.prior +6 -0
  22. redback/priors/synchrotron_massloss.prior +6 -0
  23. redback/priors/synchrotron_pldensity.prior +7 -0
  24. redback/priors/thermal_synchrotron_v2_fluxdensity.prior +8 -0
  25. redback/priors/thermal_synchrotron_v2_lnu.prior +7 -0
  26. redback/priors.py +10 -3
  27. redback/result.py +9 -1
  28. redback/sampler.py +46 -4
  29. redback/sed.py +48 -1
  30. redback/simulate_transients.py +5 -1
  31. redback/tables/filters.csv +265 -254
  32. redback/transient/__init__.py +2 -3
  33. redback/transient/transient.py +648 -10
  34. redback/transient_models/__init__.py +3 -2
  35. redback/transient_models/extinction_models.py +3 -2
  36. redback/transient_models/gaussianprocess_models.py +45 -0
  37. redback/transient_models/general_synchrotron_models.py +296 -6
  38. redback/transient_models/phenomenological_models.py +154 -7
  39. redback/transient_models/shock_powered_models.py +503 -40
  40. redback/transient_models/spectral_models.py +82 -0
  41. redback/transient_models/supernova_models.py +333 -7
  42. redback/transient_models/tde_models.py +57 -41
  43. redback/utils.py +302 -51
  44. {redback-1.0.31.dist-info → redback-1.1.dist-info}/METADATA +8 -6
  45. {redback-1.0.31.dist-info → redback-1.1.dist-info}/RECORD +48 -29
  46. {redback-1.0.31.dist-info → redback-1.1.dist-info}/WHEEL +1 -1
  47. {redback-1.0.31.dist-info → redback-1.1.dist-info/licenses}/LICENCE.md +0 -0
  48. {redback-1.0.31.dist-info → redback-1.1.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,5 @@
1
- from redback.transient_models import afterglow_models, \
1
+ from redback.transient_models import (afterglow_models, \
2
2
  extinction_models, kilonova_models, fireball_models, \
3
3
  gaussianprocess_models, magnetar_models, magnetar_driven_ejecta_models, phase_models, prompt_models, \
4
- shock_powered_models, supernova_models, tde_models, integrated_flux_afterglow_models, phenomenological_models, combined_models
4
+ shock_powered_models, supernova_models, tde_models, integrated_flux_afterglow_models, phenomenological_models, \
5
+ combined_models, spectral_models,)
@@ -23,7 +23,8 @@ extinction_integrated_flux_afterglow_models = extinction_afterglow_base_models
23
23
  extinction_supernova_base_models = ['sn_exponential_powerlaw', 'arnett', 'shock_cooling_and_arnett',
24
24
  'basic_magnetar_powered', 'slsn', 'magnetar_nickel',
25
25
  'csm_interaction', 'csm_nickel', 'type_1a', 'type_1c',
26
- 'general_magnetar_slsn','general_magnetar_driven_supernova', 'sn_fallback']
26
+ 'general_magnetar_slsn','general_magnetar_driven_supernova', 'sn_fallback',
27
+ 'csm_shock_and_arnett', 'shocked_cocoon_and_arnett', 'csm_shock_and_arnett_two_rphots']
27
28
  extinction_kilonova_base_models = ['nicholl_bns', 'mosfit_rprocess', 'mosfit_kilonova',
28
29
  'power_law_stratified_kilonova','bulla_bns_kilonova',
29
30
  'bulla_nsbh_kilonova', 'kasen_bns_kilonova','two_layer_stratified_kilonova',
@@ -38,7 +39,7 @@ extinction_magnetar_driven_base_models = ['basic_mergernova', 'general_mergernov
38
39
  'general_mergernova_evolution', 'metzger_magnetar_driven_kilonova_model',
39
40
  'general_metzger_magnetar_driven', 'general_metzger_magnetar_driven_thermalisation',
40
41
  'general_metzger_magnetar_driven_evolution']
41
- extinction_shock_powered_base_models = ['shocked_cocoon', 'shock_cooling']
42
+ extinction_shock_powered_base_models = ['shocked_cocoon', 'shock_cooling', 'csm_shock_breakout']
42
43
 
43
44
  extinction_model_library = {'kilonova': extinction_kilonova_base_models,
44
45
  'supernova': extinction_supernova_base_models,
@@ -0,0 +1,45 @@
1
+ import george.modeling
2
+ from redback.transient_models import phenomenological_models as pm
3
+
4
+ def calculate_flux_with_labels(time, t0, tau_rise, tau_fall, labels, **kwargs):
5
+ """
6
+ Calculate flux for multiple sets of parameters using the Bazin function,
7
+ where parameters are indexed by the provided labels.
8
+
9
+ :param time: time array in arbitrary units
10
+ :param t0: start time
11
+ :param tau_rise: exponential rise time
12
+ :param tau_fall: exponential fall time
13
+ :param labels: list of strings to generate parameter names
14
+ :param kwargs: keyword arguments for parameters in the form a_{label}, b_{label}, etc.
15
+ :return: dictionary with labels as keys and flux arrays as values
16
+ """
17
+ a_values = []
18
+ b_values = []
19
+
20
+ for label in labels:
21
+ a_key = f'a_{label}'
22
+ b_key = f'b_{label}'
23
+ if a_key in kwargs and b_key in kwargs:
24
+ a_values.append(kwargs[a_key])
25
+ b_values.append(kwargs[b_key])
26
+ else:
27
+ raise ValueError(f"Missing parameters for label '{label}'.")
28
+
29
+ # Call bazin_sne once with all aa and bb values
30
+ flux_matrix = pm.bazin_sne(time, a_values, b_values, t0, tau_rise, tau_fall)
31
+
32
+ # Construct the result dictionary with labels
33
+ flux_results = {f'{label}': flux_matrix[i] for i, label in enumerate(labels)}
34
+
35
+ return flux_results
36
+
37
+ class BazinGPModel(george.modeling.Model):
38
+ def __init__(self, band_labels):
39
+ self.parameter_names = ['t0', 'tau_rise', 'tau_fall']
40
+ self.band_labels = band_labels
41
+ for label in band_labels:
42
+ self.parameter_names.extend([f'a_{label}', f'b_{label}'])
43
+
44
+ def get_flux(self, t):
45
+ return calculate_flux_with_labels(t, **self.get_parameter_vector())
@@ -1,7 +1,7 @@
1
1
  import numpy as np
2
2
  from redback.transient_models.magnetar_models import magnetar_only, basic_magnetar
3
3
  from redback.transient_models.magnetar_driven_ejecta_models import _ejecta_dynamics_and_interaction
4
- from redback.transient_models.shock_powered_models import _emissivity_pl, _emissivity_thermal, _tau_nu
4
+ from redback.transient_models.shock_powered_models import _emissivity_pl, _emissivity_thermal, _tau_nu, _c_j, _c_alpha, _g_theta, _low_freq_apl_correction, _low_freq_jpl_correction
5
5
  from redback.transient_models.afterglow_models import _get_kn_dynamics, _pnu_synchrotron
6
6
  from astropy.cosmology import Planck18 as cosmo
7
7
  from redback.utils import calc_kcorrected_properties, citation_wrapper, logger, get_csm_properties, nu_to_lambda, lambda_to_nu, velocity_from_lorentz_factor, calc_ABmag_from_flux_density
@@ -10,6 +10,7 @@ from scipy import integrate
10
10
  from scipy.interpolate import interp1d
11
11
  import astropy.units as uu
12
12
  from collections import namedtuple
13
+ from scipy import special
13
14
 
14
15
  def _calc_free_free_abs(frequency, Y_fe, Zbar, mej, radius_2darray, F_nu_2darray):
15
16
  """
@@ -97,7 +98,7 @@ def pwn(time, redshift, mej, l0, tau_sd, nn, eps_b, gamma_b, **kwargs):
97
98
  :param eps_b: magnetization of the PWN
98
99
  :param gamma_b: Lorentz factor of electrons at synchrotron break
99
100
  :param kwargs: Additional parameters -
100
- :param E_sn: supernova explosion energy
101
+ :param E_k: initial ejecta kinetic energy
101
102
  :param kappa: opacity (used only in dynamics and optical absorption)
102
103
  :param kappa_gamma: gamma-ray opacity used to calculate magnetar thermalisation efficiency (used only in dynamics)
103
104
  :param q1: low energy spectral index (must be < 2)
@@ -114,7 +115,7 @@ def pwn(time, redshift, mej, l0, tau_sd, nn, eps_b, gamma_b, **kwargs):
114
115
  :return: flux density or AB magnitude or dynamics output
115
116
  """
116
117
  #get parameter values or use defaults
117
- E_sn = kwargs.get('E_sn', 1.0e51)
118
+ E_sn = kwargs.get('E_k', 1.0e51)
118
119
  kappa = kwargs.get('kappa', 0.1)
119
120
  if 'kappa' in kwargs:
120
121
  del kwargs['kappa']
@@ -129,7 +130,8 @@ def pwn(time, redshift, mej, l0, tau_sd, nn, eps_b, gamma_b, **kwargs):
129
130
  ejecta_radius = 1.0e11
130
131
  epse=1.0-eps_b
131
132
  n_ism = 1.0e-5
132
- dl = cosmo.luminosity_distance(redshift).cgs.value
133
+ cosmology = kwargs.get('cosmology', cosmo)
134
+ dl = cosmology.luminosity_distance(redshift).cgs.value
133
135
  pair_cascade_switch = kwargs.get('pair_cascade_switch', False)
134
136
  use_r_process = kwargs.get('use_r_process', False)
135
137
  nu_M=3.8e22*np.ones(2500)
@@ -421,7 +423,7 @@ def thermal_synchrotron_fluxdensity(time, redshift, logn0, v0, logr0, eta, logep
421
423
  :param mu_e: mean molecular weight per electron, default is 1.18
422
424
  :param kwargs: extra parameters to change physics and other settings
423
425
  :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
424
- :return: flux density
426
+ :return: flux density in mJy
425
427
  """
426
428
  frequency = kwargs['frequency']
427
429
  frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
@@ -432,7 +434,7 @@ def thermal_synchrotron_fluxdensity(time, redshift, logn0, v0, logr0, eta, logep
432
434
  dl = cosmology.luminosity_distance(redshift).cgs.value
433
435
  lnu = thermal_synchrotron_lnu(time,logn0, v0, logr0, eta, logepse, logepsb, xi, p,**new_kwargs)
434
436
  flux_density = lnu / (4.0 * np.pi * dl**2)
435
- return flux_density
437
+ return flux_density*1.0e26
436
438
 
437
439
  @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2022MNRAS.511.5328G/abstract')
438
440
  def tde_synchrotron(time, redshift, Mej, vej, logepse, logepsb, p, **kwargs):
@@ -516,3 +518,291 @@ def tde_synchrotron(time, redshift, Mej, vej, logepse, logepsb, p, **kwargs):
516
518
  else:
517
519
  flux_density = Fvb * ((frequency / vb) ** (-beta1 * s) + (frequency / vb) ** (-beta2 * s)) ** (-1.0 / s)
518
520
  return flux_density
521
+
522
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2007ihea.book.....R/abstract, https://ui.adsabs.harvard.edu/abs/2017hsn..book..875C/abstract')
523
+ def synchrotron_massloss(time, redshift, v_s, log_Mdot_vwind, logepsb, logepse, p, **kwargs):
524
+ """
525
+ :param time: time in observer frame in days
526
+ :param redshift: redshift
527
+ :param v_s: velocity of the shock (km/s)
528
+ :param log Mdot_vwind: log10 of the mass loss rate over wind velocity ((solar mass / year)/(km / s))
529
+ :param logepse: log10 epsilon_e; electron thermalisation efficiency
530
+ :param logepsb: log10 epsilon_b; magnetic field amplification efficiency
531
+ :param p: electron power law slope
532
+ :param kwargs: extra parameters to change physics/settings
533
+ :param frequency: frequency to calculate model on - Must be same length as time array or a single number)
534
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
535
+ :return: flux density
536
+ """
537
+ cosmology = kwargs.get('cosmology', cosmo)
538
+ dl = cosmology.luminosity_distance(redshift).cgs.value
539
+ frequency = kwargs['frequency']
540
+ if isinstance(frequency, float):
541
+ frequency = np.ones(len(time)) * frequency
542
+ frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
543
+
544
+ eps_e = 10.0 ** logepse
545
+ eps_b = 10.0 ** logepsb
546
+ v_cgs = v_s * km_cgs
547
+ t_cgs = time * day_to_s
548
+ r_s = v_cgs * t_cgs
549
+ Mdot_vwind = 10.0 ** log_Mdot_vwind
550
+ Md_vw_cgs = Mdot_vwind * solar_mass / (day_to_s * 365.24) / km_cgs #g/cm
551
+ nu_0 = 1.253e19
552
+
553
+ rho_csm = Md_vw_cgs / (4.0 * np.pi * r_s ** 2.0)
554
+ u_b = eps_b * rho_csm * v_cgs ** 2.0
555
+ B = np.sqrt(8 * np.pi * u_b)
556
+ N_0 = 4.0 / 3.0 * np.pi * r_s ** 3.0 * eps_e * rho_csm / proton_mass
557
+ C_0 = 4.0 / 3.0 * N_0 * sigma_T * speed_of_light * u_b
558
+ nu_L = qe * B / (2 * np.pi * electron_mass * speed_of_light)
559
+
560
+ L_nu = C_0 / (2.0 * nu_L) * (frequency / nu_L) ** ((1.0 - p) / 2.0)
561
+ flux_density = L_nu / (4.0 * np.pi * dl**2) / 1.0e-26
562
+
563
+ Fv0 = C_0 / (2.0 * nu_L) / (4.0 * np.pi * dl**2)
564
+ beta = 1.0 - (1.0 - p) / 2.0
565
+ nu_ssa = (dl**2 * 3.0**1.5 * qe**0.5 * B**0.5 * Fv0 * nu_L**(beta - 1.0) / (4.0 * np.pi**1.5 * r_s**2 * speed_of_light**0.5 * electron_mass**1.5))**(2.0 / (2.0 * beta + 3.0))
566
+ Fv_ssa = Fv0 * (nu_ssa / nu_L) ** (1-beta)
567
+
568
+ if (np.min(frequency) < np.max(nu_ssa)):
569
+ msk = (frequency < nu_ssa)
570
+ flux_density[msk] = Fv_ssa[msk] * (frequency[msk] / nu_ssa[msk]) ** 2.5 / 1.0e-26
571
+
572
+ return flux_density
573
+
574
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2007ihea.book.....R/abstract, https://ui.adsabs.harvard.edu/abs/2017hsn..book..875C/abstract')
575
+ def synchrotron_ism(time, redshift, v_s, logn0, logepsb, logepse, p, **kwargs):
576
+ """
577
+ :param time: time in observer frame in days
578
+ :param redshift: redshift
579
+ :param v_s: velocity of the shock (km/s)
580
+ :param logn0: log10 of the circumburst density (cm^-3)
581
+ :param logepse: log10 epsilon_e; electron thermalisation efficiency
582
+ :param logepsb: log10 epsilon_b; magnetic field amplification efficiency
583
+ :param p: electron power law slope
584
+ :param kwargs: extra parameters to change physics/settings
585
+ :param frequency: frequency to calculate model on - Must be same length as time array or a single number)
586
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
587
+ :return: flux density
588
+ """
589
+ cosmology = kwargs.get('cosmology', cosmo)
590
+ dl = cosmology.luminosity_distance(redshift).cgs.value
591
+ frequency = kwargs['frequency']
592
+ if isinstance(frequency, float):
593
+ frequency = np.ones(len(time)) * frequency
594
+ frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
595
+
596
+ n_ism = 10.0 ** logn0
597
+ eps_e = 10.0 ** logepse
598
+ eps_b = 10.0 ** logepsb
599
+ v_cgs = v_s * km_cgs
600
+ t_cgs = time * day_to_s
601
+ r_s = v_cgs * t_cgs
602
+ nu_0 = 1.253e19
603
+
604
+ rho_csm = proton_mass * n_ism
605
+ u_b = eps_b * rho_csm * v_cgs ** 2.0
606
+ B = np.sqrt(8 * np.pi * u_b)
607
+ N_0 = 4.0 / 3.0 * np.pi * r_s ** 3.0 * eps_e * n_ism
608
+ C_0 = 4.0 / 3.0 * N_0 * sigma_T * speed_of_light * u_b
609
+ nu_L = qe * B / (2 * np.pi * electron_mass * speed_of_light)
610
+
611
+ L_nu = C_0 / (2.0 * nu_L) * (frequency / nu_L) ** ((1.0 - p) / 2.0)
612
+ flux_density = L_nu / (4.0 * np.pi * dl**2) / 1.0e-26
613
+
614
+ Fv0 = C_0 / (2.0 * nu_L) / (4.0 * np.pi * dl**2)
615
+ beta = 1.0 - (1.0 - p) / 2.0
616
+ nu_ssa = (dl**2 * 3.0**1.5 * qe**0.5 * B**0.5 * Fv0 * nu_L**(beta - 1.0) / (4.0 * np.pi**1.5 * r_s**2 * speed_of_light**0.5 * electron_mass**1.5))**(2.0 / (2.0 * beta + 3.0))
617
+ Fv_ssa = Fv0 * (nu_ssa / nu_L) ** (1-beta)
618
+
619
+ if (np.min(frequency) < np.max(nu_ssa)):
620
+ msk = (frequency < nu_ssa)
621
+ flux_density[msk] = Fv_ssa[msk] * (frequency[msk] / nu_ssa[msk]) ** 2.5 / 1.0e-26
622
+
623
+ return flux_density
624
+
625
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2007ihea.book.....R/abstract, https://ui.adsabs.harvard.edu/abs/2017hsn..book..875C/abstract')
626
+ def synchrotron_pldensity(time, redshift, v_s, logA, s, logepsb, logepse, p, **kwargs):
627
+ """
628
+ :param time: time in observer frame in days
629
+ :param redshift: redshift
630
+ :param v_s: velocity of the shock (km/s)
631
+ :param logA: log10 of the circumstellar material density at R=1e15 cm (cm^-3)
632
+ :param s: power law index of the circumstellar material density profile
633
+ :param logepse: log10 epsilon_e; electron thermalisation efficiency
634
+ :param logepsb: log10 epsilon_b; magnetic field amplification efficiency
635
+ :param p: electron power law slope
636
+ :param kwargs: extra parameters to change physics/settings
637
+ :param frequency: frequency to calculate model on - Must be same length as time array or a single number)
638
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
639
+ :return: flux density
640
+ """
641
+ cosmology = kwargs.get('cosmology', cosmo)
642
+ dl = cosmology.luminosity_distance(redshift).cgs.value
643
+ frequency = kwargs['frequency']
644
+ if isinstance(frequency, float):
645
+ frequency = np.ones(len(time)) * frequency
646
+ frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
647
+
648
+ A = 10.0 ** logA
649
+ eps_e = 10.0 ** logepse
650
+ eps_b = 10.0 ** logepsb
651
+ v_cgs = v_s * km_cgs
652
+ t_cgs = time * day_to_s
653
+ r_s = v_cgs * t_cgs
654
+ nu_0 = 1.253e19
655
+
656
+ n_csm = A * (r_s / 1e15) **(-s)
657
+ rho_csm = n_csm * proton_mass
658
+ u_b = eps_b * rho_csm * v_cgs ** 2.0
659
+ B = np.sqrt(8 * np.pi * u_b)
660
+ N_0 = 4.0 / 3.0 * np.pi * r_s ** 3.0 * eps_e * n_csm
661
+ C_0 = 4.0 / 3.0 * N_0 * sigma_T * speed_of_light * u_b
662
+ nu_L = qe * B / (2 * np.pi * electron_mass * speed_of_light)
663
+
664
+ L_nu = C_0 / (2.0 * nu_L) * (frequency / nu_L) ** ((1.0 - p) / 2.0)
665
+ flux_density = L_nu / (4.0 * np.pi * dl**2) / 1.0e-26
666
+
667
+ Fv0 = C_0 / (2.0 * nu_L) / (4.0 * np.pi * dl**2)
668
+ beta = 1.0 - (1.0 - p) / 2.0
669
+ nu_ssa = (dl**2 * 3.0**1.5 * qe**0.5 * B**0.5 * Fv0 * nu_L**(beta - 1.0) / (4.0 * np.pi**1.5 * r_s**2 * speed_of_light**0.5 * electron_mass**1.5))**(2.0 / (2.0 * beta + 3.0))
670
+ Fv_ssa = Fv0 * (nu_ssa / nu_L) ** (1-beta)
671
+
672
+ if (np.min(frequency) < np.max(nu_ssa)):
673
+ msk = (frequency < nu_ssa)
674
+ flux_density[msk] = Fv_ssa[msk] * (frequency[msk] / nu_ssa[msk]) ** 2.5 / 1.0e-26
675
+
676
+ return flux_density
677
+
678
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2024ApJ...977..134M/abstract, https://ui.adsabs.harvard.edu/abs/2021ApJ...923L..14M/abstract')
679
+ def thermal_synchrotron_v2_lnu(time, bG_sh, log_Mdot_vwind, n_ism, logepse, logepsb, xi, p, **kwargs):
680
+ """
681
+ :param time: time in source frame in days
682
+ :param bG_sh: Proper-velocity of the shock (bG_sh = Gamma_sh*beta_sh)
683
+ :param log Mdot_vwind: log10 of the mass loss rate over wind velocity ((solar mass / year)/(km / s))
684
+ :param n_ism: the circumburst density of the ISM (cm^-3)
685
+ :param logepse: log10 epsilon_e; electron thermalisation efficiency
686
+ :param logepsb: log10 epsilon_b; magnetic field amplification efficiency
687
+ :param xi: fraction of energy carried by power law electrons
688
+ :param p: electron power law slope
689
+ :param kwargs: extra parameters to change physics/settings
690
+ :param frequency: frequency to calculate model on - Must be same length as time array or a single number)
691
+ :param mu: mean molecular weight, default is 0.62
692
+ :param mu_e: mean molecular weight per electron, default is 1.18
693
+ :param ell_dec: Deceleration parameter defined in eq. (1) of MQ24, default is 1.0
694
+ :param f: Volume-filling factor defined in eq. (3) of MQ24, default is 3.0/16.0
695
+ :return: lnu
696
+ """
697
+ mu = kwargs.get('mu', 0.62)
698
+ mu_e = kwargs.get('mu_e', 1.18)
699
+ ell_dec = kwargs.get('ell_dec', 1.0)
700
+ f = kwargs.get('f', 3.0/16.0)
701
+ epsilon_T = 10**logepse
702
+ epsilon_B = 10**logepsb
703
+ frequency = kwargs['frequency']
704
+ t = time * day_to_s
705
+
706
+ Mdot_vwind = 10.0 ** log_Mdot_vwind
707
+ Md_vw_cgs = Mdot_vwind * solar_mass / (day_to_s * 365.24) / km_cgs #g/cm
708
+
709
+ R = (1.0 + bG_sh**2)**0.5 * bG_sh * speed_of_light * ell_dec * t
710
+ bG = 0.5 * (bG_sh**2 - 2.0 + (bG_sh**4 + 5.0 * bG_sh**2 + 4.0)**0.5)**0.5
711
+ Gamma = (1.0 + bG**2)**0.5
712
+
713
+ #total ISM number density is sum of wind and flat density component
714
+ Mdot_over_vw = 4.0 * np.pi * mu * proton_mass * R**2 * n_ism + Md_vw_cgs
715
+ n = Md_vw_cgs / (4.0 * np.pi * mu * proton_mass * R**2) + n_ism
716
+
717
+ if Gamma==1:
718
+ # fix bG << 1 case where numerical accuracy fails
719
+ Theta = (2.0 / 3.0) * epsilon_T * (9.0 * mu * proton_mass / (32.0 * mu_e * electron_mass)) * ((16.0 / 9.0) * bG**2)
720
+ Gamma_minus_one = 0.5 * bG**2
721
+ else:
722
+ g = (4.0 + Gamma**(-1.0)) / 3.0
723
+ Theta0 = epsilon_T * ((Gamma - 1.0) * ((g * Gamma + 1.0) / (g - 1.0)) * mu * proton_mass)/(4.0 * Gamma * mu_e * electron_mass)
724
+ Theta = (5.0 * Theta0 - 6.0 + (25.0 * Theta0**2 + 180.0 * Theta0 + 36.0)**0.5) / 30.0
725
+ Gamma_minus_one = Gamma - 1.0
726
+
727
+ # prefactor for the luminosity, eq. (B13); Note---with respect to eq. (B13), this definition omits f(Theta), which we instead absorb into I`(x) below.
728
+ L_tilde = ((4.0 * 2.0**0.5 * qe**3 * mu_e * epsilon_B**0.5 * f / (3.0**0.5 * mu * proton_mass * electron_mass * speed_of_light))
729
+ * Mdot_over_vw**1.5 * Gamma**1.5 * Gamma_minus_one**0.5)
730
+
731
+ # prefactor for the optical-depth, eq. (B14); Note---with respect to eq. (B13), this definition omits f(Theta), which we instead absorb into I`(x) below.
732
+ tau_Theta = ((2.0**0.5 * qe * mu_e * f / (3.0**2.5 * mu * proton_mass * speed_of_light * epsilon_B**0.5))
733
+ * Mdot_over_vw**0.5 * Theta**(-5.0) * Gamma**(-0.5) * Gamma_minus_one**(-0.5))
734
+
735
+ # post-shock magnetic field
736
+ B = (8.0 * epsilon_B * Mdot_over_vw * Gamma * Gamma_minus_one )**0.5 / ((1.0 + bG_sh**2)**0.5 *bG_sh * t)
737
+ # thermal synchrotron frequeny (in observer frame)
738
+ nu_T = 3.0 * Gamma * Theta**2 * qe * B / (4.0 * np.pi * electron_mass * speed_of_light)
739
+ x = frequency / nu_T
740
+
741
+ aa = (6.0 + 15.0 * Theta) / (4.0 + 5.0 * Theta)
742
+ gamma_m = 1.0 + aa * Theta
743
+
744
+ # the relative fraction of power-law to thermal electron energy densities
745
+ delta = xi/epsilon_T
746
+ # coefficient that multiplies power-law term in square-brackets in eq. (B10)
747
+ a = (8.0 * np.pi / 3.0**0.5) *_c_j(p) * delta * _g_theta(Theta, p=p)
748
+ # coefficient that multiplies power-law term in square-brackets in eq. (B11)
749
+ b = (3.0**1.5 / np.pi) *_c_alpha(p) * delta * _g_theta(Theta, p=p)
750
+
751
+ # include low-frequeny corrections to the coefficients `a` and `b` defied above (see e.g. low_freq_jpl_correction function for more information)
752
+ a_corr = _low_freq_jpl_correction(x, Theta, p)
753
+ b_corr = _low_freq_apl_correction(x, Theta, p)
754
+
755
+ # an estimate of the Lorentz factor above which electrons cool quickly
756
+ gamma_cool = 6.0 * np.pi * electron_mass * speed_of_light / (sigma_T * B**2 * Gamma * t)
757
+ # the Lorentz factor of thermal electrons contributing most to emission at frequency x
758
+ gamma_th = Theta * np.maximum(1.0, (2.0 * x)**(1.0 / 3.0))
759
+ # the Lorentz factor of power-law electrons contributing most to emission at frequency x
760
+ gamma_pl = np.maximum(gamma_m, Theta * x**0.5)
761
+ # correction terms for fast-cooling regime
762
+ cooling_correction_th = np.minimum(1.0, gamma_cool / gamma_th)
763
+ cooling_correction_pl = np.minimum(1.0, gamma_cool / gamma_pl)
764
+
765
+ I_of_x = 4.0505 * x**(-1.0 / 6.0) * (1.0 + 0.40 * x**(-0.25) + 0.5316 * x**(-0.5)) * np.exp(-1.8899 * x**(1.0 / 3.0))
766
+ f_fun = 2.0 * Theta**2 / special.kn(2 , 1.0 / Theta)
767
+ I = I_of_x*f_fun
768
+ I[np.isnan(I)+np.isinf(I)] = 0.0
769
+
770
+ # calculate the optical depth (eq. B11)
771
+ tau = tau_Theta *((I / x) * cooling_correction_th + b * x**(-0.5 * (p + 4.0)) * b_corr * cooling_correction_pl)
772
+ tau_fun = np.ones_like(tau)
773
+ tau_fun[tau > 1e-9] = (1.0 - np.exp(-tau[tau > 1e-9]) )/tau[tau > 1e-9]
774
+
775
+ # calculate the specific luminosity (eq. B10)
776
+ L_nu = L_tilde * (x * I * cooling_correction_th + a * x**(-0.5*(p - 1.0)) * a_corr * cooling_correction_pl) * tau_fun
777
+ return L_nu
778
+
779
+ @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2024ApJ...977..134M/abstract, https://ui.adsabs.harvard.edu/abs/2021ApJ...923L..14M/abstract')
780
+ def thermal_synchrotron_v2_fluxdensity(time, redshift, bG_sh, log_Mdot_vwind, n_ism, logepse, logepsb, xi, p, **kwargs):
781
+ """
782
+ :param time: time in source frame in days
783
+ :param redshift: redshift
784
+ :param bG_sh: Proper-velocity of the shock (bG_sh = Gamma_sh*beta_sh)
785
+ :param log Mdot_vwind: log10 of the mass loss rate over wind velocity ((solar mass / year)/(km / s))
786
+ :param n_ism: the circumburst density of the ISM (cm^-3)
787
+ :param logepse: log10 epsilon_e; electron thermalisation efficiency
788
+ :param logepsb: log10 epsilon_b; magnetic field amplification efficiency
789
+ :param xi: fraction of energy carried by power law electrons
790
+ :param p: electron power law slope
791
+ :param kwargs: extra parameters to change physics/settings
792
+ :param frequency: frequency to calculate model on - Must be same length as time array or a single number)
793
+ :param mu: mean molecular weight, default is 0.62
794
+ :param mu_e: mean molecular weight per electron, default is 1.18
795
+ :param ell_dec: Deceleration parameter defined in eq. (1) of MQ24, default is 1.0
796
+ :param f: Volume-filling factor defined in eq. (3) of MQ24, default is 3.0/16.0
797
+ :param cosmology: Cosmology to use for luminosity distance calculation. Defaults to Planck18. Must be a astropy.cosmology object.
798
+ :return: flux density in mJy
799
+ """
800
+ frequency = kwargs['frequency']
801
+ frequency, time = calc_kcorrected_properties(frequency=frequency, redshift=redshift, time=time)
802
+ new_kwargs = kwargs.copy()
803
+ new_kwargs['frequency'] = frequency
804
+ cosmology = kwargs.get('cosmology', cosmo)
805
+ dl = cosmology.luminosity_distance(redshift).cgs.value
806
+ lnu = thermal_synchrotron_v2_lnu(time, bG_sh, log_Mdot_vwind, n_ism, logepse, logepsb, xi, p, **new_kwargs)
807
+ flux_density = lnu / (4.0 * np.pi * dl**2)/1.0e-26
808
+ return flux_density
@@ -1,21 +1,153 @@
1
1
  import numpy as np
2
2
  from redback.utils import citation_wrapper
3
+ from redback.constants import speed_of_light_si
4
+
5
+
6
+ def exp_rise_powerlaw_decline(t, t0, m_peak, tau_rise, alpha, t_peak, **kwargs):
7
+ """
8
+ Compute a smooth light-curve model (in magnitudes) with an exponential rise
9
+ transitioning into a power-law decline, with a smooth (blended) peak.
10
+ In all filters the shape is determined by the same t0, tau_rise, alpha, and t_peak;
11
+ only m_peak differs from filter to filter.
12
+
13
+ For t < t0, the function returns np.nan.
14
+ For t >= t0, the model is constructed as a blend of:
15
+
16
+ Rising phase:
17
+ m_rise(t) = m_peak + 1.086 * ((t_peak - t) / tau_rise)
18
+ Declining phase:
19
+ m_decline(t) = m_peak + 2.5 * alpha * log10((t - t0)/(t_peak - t0))
20
+
21
+ A smooth transition is achieved by the switching (weight) function:
22
+
23
+ weight(t) = 0.5 * [1 + tanh((t - t_peak)/delta)]
24
+
25
+ so that the final magnitude is:
26
+
27
+ m(t) = (1 - weight(t)) * m_rise(t) + weight(t) * m_decline(t)
28
+
29
+ At t = t_peak, weight = 0.5 and both m_rise and m_decline equal m_peak,
30
+ ensuring a smooth peak.
31
+
32
+ Parameters
33
+ ----------
34
+ t : array_like
35
+ 1D array of times (e.g., in modified Julian days) at which to evaluate the model.
36
+ t0 : float
37
+ Start time of the transient event (e.g., explosion), in MJD.
38
+ m_peak : float or array_like
39
+ Peak magnitude(s) at t = t_peak. If an array is provided, each element is taken
40
+ to correspond to a different filter.
41
+ tau_rise : float
42
+ Characteristic timescale (in days) for the exponential rise.
43
+ alpha : float
44
+ Power-law decay index governing the decline.
45
+ t_peak : float
46
+ Time (in MJD) at peak brightness (must satisfy t_peak > t0).
47
+ delta : float, optional
48
+ Smoothing parameter (in days) controlling the width of the transition around t_peak.
49
+ If not provided, defaults to 50% of (t_peak - t0).
50
+
51
+ Returns
52
+ -------
53
+ m_model : ndarray
54
+ If m_peak is an array (multiple filters), returns a 2D array of shape (n_times, n_filters);
55
+ if m_peak is a scalar, returns a 1D array (with NaN for t < t0).
56
+
57
+ Examples
58
+ --------
59
+ Single filter:
60
+
61
+ >>> t = np.linspace(58990, 59050, 300)
62
+ >>> model1 = exp_rise_powerlaw_decline(t, t0=59000, m_peak=17.0, tau_rise=3.0,
63
+ ... alpha=1.5, t_peak=59010)
64
+
65
+ Multiple filters (e.g., g, r, i bands):
66
+
67
+ >>> t = np.linspace(58990, 59050, 300)
68
+ >>> m_peaks = np.array([17.0, 17.5, 18.0])
69
+ >>> model_multi = exp_rise_powerlaw_decline(t, t0=59000, m_peak=m_peaks, tau_rise=3.0,
70
+ ... alpha=1.5, t_peak=59010)
71
+ >>> print(model_multi.shape) # Expected shape: (300, 3)
72
+ """
73
+ # Convert t to a numpy array and force 1D.
74
+ t = np.asarray(t).flatten()
75
+ delta = kwargs.get('delta', 0.5)
76
+
77
+ # Define default smoothing parameter delta if not provided.
78
+ # if delta is None:
79
+ delta = (t_peak - t0) * delta # default: 50% of the interval [t0, t_peak]
80
+
81
+ # Ensure m_peak is at least 1D (so a scalar becomes an array of length 1).
82
+ m_peak = np.atleast_1d(m_peak)
83
+ n_filters = m_peak.shape[0]
84
+ n_times = t.shape[0]
85
+
86
+ # Preallocate model magnitude array with shape (n_times, n_filters)
87
+ m_model = np.full((n_times, n_filters), np.nan, dtype=float)
88
+
89
+ # Create a mask for times t >= t0.
90
+ valid = t >= t0
91
+ # Reshape t into a column vector for broadcasting: shape (n_times, 1)
92
+ t_col = t.reshape(-1, 1)
93
+
94
+ # Compute the switching (weight) function: weight = 0 when t << t_peak, 1 when t >> t_peak.
95
+ weight = 0.5 * (1 + np.tanh((t_col - t_peak) / delta))
96
+
97
+ # Rising phase model: for t < t_peak the flux is rising toward peak.
98
+ # m_rise = m_peak + 1.086 * ((t_peak - t) / tau_rise)
99
+ m_rise = m_peak[None, :] + 1.086 * ((t_peak - t_col) / tau_rise)
100
+
101
+ # Declining phase model: power-law decline in flux gives a logarithmic increase in magnitude.
102
+ # m_decline = m_peak + 2.5 * alpha * log10((t - t0)/(t_peak - t0))
103
+ ratio = (t_col - t0) / (t_peak - t0)
104
+ m_decline = m_peak[None, :] + 2.5 * alpha * np.log10(ratio)
105
+
106
+ # Blend the two components using the switching weight.
107
+ # For t << t_peak, tanh term ≈ -1 so weight ~ 0 and m ~ m_rise.
108
+ # For t >> t_peak, tanh term ≈ +1 so weight ~ 1 and m ~ m_decline.
109
+ m_blend = (1 - weight) * m_rise + weight * m_decline
110
+
111
+ # Update m_model for valid times (t >= t0). For t < t0, m_model remains NaN.
112
+ m_model[valid, :] = m_blend[valid, :]
113
+
114
+ # If m_peak was given as a scalar, return a 1D array.
115
+ if n_filters == 1:
116
+ return m_model.flatten()
117
+ return m_model
3
118
 
4
119
  @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2009A%26A...499..653B/abstract')
5
120
  def bazin_sne(time, aa, bb, t0, tau_rise, tau_fall, **kwargs):
6
121
  """
7
- Bazin function for CCSN light curves
122
+ Bazin function for CCSN light curves with vectorized inputs.
8
123
 
9
124
  :param time: time array in arbitrary units
10
- :param aa: Normalisation on the Bazin function
11
- :param bb: Additive constant
125
+ :param aa: array (or float) of normalisations, if array this is unique to each 'band'
126
+ :param bb: array (or float) of additive constants, if array this is unique to each 'band'
12
127
  :param t0: start time
13
128
  :param tau_rise: exponential rise time
14
129
  :param tau_fall: exponential fall time
15
- :return: flux in units set by AA
130
+ :return: matrix of flux values in units set by AA
16
131
  """
17
- flux = aa * np.exp(-((time - t0) / tau_fall) / (1 + np.exp(-(time - t0) / tau_rise))) + bb
18
- return flux
132
+ if isinstance(aa, float):
133
+ aa_values = [aa]
134
+ bb_values = [bb]
135
+ else:
136
+ aa_values = aa
137
+ bb_values = bb
138
+
139
+ if len(aa_values) != len(bb_values):
140
+ raise ValueError("Length of aa_values and bb_values must be the same.")
141
+
142
+ # Compute flux for all aa and bb values
143
+ flux_matrix = np.array([
144
+ aa * (np.exp(-((time - t0) / tau_fall)) / (1 + np.exp(-(time - t0) / tau_rise))) + bb
145
+ for aa, bb in zip(aa_values, bb_values)
146
+ ])
147
+ if isinstance(aa, float):
148
+ return flux_matrix[0]
149
+ else:
150
+ return flux_matrix
19
151
 
20
152
  @citation_wrapper('https://ui.adsabs.harvard.edu/abs/2019ApJ...884...83V/abstract, https://ui.adsabs.harvard.edu/abs/1982ApJ...253..785A/abstract')
21
153
  def villar_sne(time, aa, cc, t0, tau_rise, tau_fall, gamma, nu, **kwargs):
@@ -25,7 +157,7 @@ def villar_sne(time, aa, cc, t0, tau_rise, tau_fall, gamma, nu, **kwargs):
25
157
  :param time: time array in arbitrary units
26
158
  :param aa: normalisation on the Villar function, amplotude
27
159
  :param cc: additive constant, baseline flux
28
- :param t0: start time
160
+ :param t0: "start" time
29
161
  :param tau_rise: exponential rise time
30
162
  :param tau_fall: exponential fall time
31
163
  :param gamma: plateau duration
@@ -68,6 +200,21 @@ def line_spectrum(wavelength, line_amp, cont_amp, x0, **kwargs):
68
200
  spectrum = line_amp / cont_amp * np.exp(-(wavelength - x0) ** 2. / (2 * cont_amp ** 2) )
69
201
  return spectrum
70
202
 
203
+ def line_spectrum_with_velocity_dispersion(angstroms, wavelength_center, line_strength, velocity_dispersion):
204
+ """
205
+ A Gaussian line profile with velocity dispersion
206
+
207
+ :param angstroms: wavelength array in angstroms or arbitrary units
208
+ :param wavelength_center: center of the line in angstroms
209
+ :param line_strength: line amplitude scale
210
+ :param velocity_dispersion: velocity in m/s
211
+ :return: spectrum in whatever units set by line_strength
212
+ """
213
+
214
+ # Calculate the Doppler shift for each wavelength using Gaussian profile
215
+ intensity = line_strength * np.exp(-0.5 * ((angstroms - wavelength_center) / wavelength_center * speed_of_light_si / velocity_dispersion) ** 2)
216
+ return intensity
217
+
71
218
  def gaussian_rise(time, a_1, peak_time, sigma_t, **kwargs):
72
219
  """
73
220
  :param time: time array in whatver time units