redback 1.0.3__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.
- redback/__init__.py +3 -2
- redback/analysis.py +321 -4
- redback/filters.py +57 -23
- redback/get_data/directory.py +18 -0
- redback/likelihoods.py +260 -0
- redback/model_library.py +12 -2
- redback/plotting.py +335 -4
- redback/priors/blackbody_spectrum_with_absorption_and_emission_lines.prior +9 -0
- redback/priors/csm_shock_and_arnett_two_rphots.prior +11 -0
- redback/priors/exp_rise_powerlaw_decline.prior +6 -0
- redback/priors/powerlaw_spectrum_with_absorption_and_emission_lines.prior +8 -0
- redback/priors/shockcooling_morag.prior +6 -0
- redback/priors/shockcooling_morag_and_arnett.prior +10 -0
- redback/priors/shockcooling_morag_and_arnett_bolometric.prior +9 -0
- redback/priors/shockcooling_morag_bolometric.prior +5 -0
- redback/priors/shockcooling_sapirandwaxman.prior +6 -0
- redback/priors/shockcooling_sapirandwaxman_bolometric.prior +5 -0
- redback/priors/shockcooling_sapirwaxman_and_arnett.prior +10 -0
- redback/priors/shockcooling_sapirwaxman_and_arnett_bolometric.prior +9 -0
- redback/priors/shocked_cocoon_and_arnett.prior +13 -0
- redback/priors/synchrotron_ism.prior +6 -0
- redback/priors/synchrotron_massloss.prior +6 -0
- redback/priors/synchrotron_pldensity.prior +7 -0
- redback/priors/thermal_synchrotron_v2_fluxdensity.prior +8 -0
- redback/priors/thermal_synchrotron_v2_lnu.prior +7 -0
- redback/priors.py +10 -3
- redback/result.py +9 -1
- redback/sampler.py +46 -4
- redback/sed.py +48 -1
- redback/simulate_transients.py +5 -1
- redback/tables/filters.csv +265 -254
- redback/transient/__init__.py +2 -3
- redback/transient/transient.py +648 -10
- redback/transient_models/__init__.py +3 -2
- redback/transient_models/extinction_models.py +3 -2
- redback/transient_models/gaussianprocess_models.py +45 -0
- redback/transient_models/general_synchrotron_models.py +296 -6
- redback/transient_models/phenomenological_models.py +154 -7
- redback/transient_models/shock_powered_models.py +503 -40
- redback/transient_models/spectral_models.py +82 -0
- redback/transient_models/supernova_models.py +333 -7
- redback/transient_models/tde_models.py +57 -41
- redback/utils.py +302 -51
- {redback-1.0.3.dist-info → redback-1.1.dist-info}/METADATA +8 -6
- {redback-1.0.3.dist-info → redback-1.1.dist-info}/RECORD +48 -29
- {redback-1.0.3.dist-info → redback-1.1.dist-info}/WHEEL +1 -1
- {redback-1.0.3.dist-info → redback-1.1.dist-info/licenses}/LICENCE.md +0 -0
- {redback-1.0.3.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,
|
|
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
|
|
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('
|
|
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
|
-
|
|
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:
|
|
11
|
-
:param bb:
|
|
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
|
-
|
|
18
|
-
|
|
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
|