def ElectronEblAbsorbedSynIC(pars, data): # Match parameters to ECPL properties, and give them the appropriate units amplitude = 10**pars[0] / u.eV e_break = (10**pars[1]) * u.TeV alpha1 = pars[2] alpha2 = pars[3] B = pars[4] * u.uG # Define the redshift of the source, and absorption model redshift = pars[5] * u.dimensionless_unscaled EBL_transmitance = EblAbsorptionModel(redshift, "Dominguez") # Initialize instances of the particle distribution and radiative models BPL = BrokenPowerLaw(amplitude, 1.0 * u.TeV, e_break, alpha1, alpha2) # Compute IC on a CMB component IC = InverseCompton(BPL, seed_photon_fields=["CMB"], Eemin=10 * u.GeV) SYN = Synchrotron(BPL, B=B) # compute flux at the energies given in data['energy'] model = EBL_transmitance.transmission(data) * IC.flux( data, distance=1.0 * u.kpc) + SYN.flux(data, distance=1.0 * u.kpc) # The first array returned will be compared to the observed spectrum for # fitting. All subsequent objects will be stored in the sampler metadata # blobs. return model, IC.compute_We(Eemin=1 * u.TeV)
def ElectronIC(pars, data): # Match parameters to ECPL properties, and give them the appropriate units amplitude = pars[0] / u.eV alpha = pars[1] e_cutoff = (10 ** pars[2]) * u.TeV # Initialize instances of the particle distribution and radiative model ECPL = ExponentialCutoffPowerLaw(amplitude, 10.0 * u.TeV, alpha, e_cutoff) # Compute IC on CMB and on a FIR component with values from GALPROP for the # position of RXJ1713 IC = InverseCompton( ECPL, seed_photon_fields=[ "CMB", ["FIR", 26.5 * u.K, 0.415 * u.eV / u.cm ** 3], ], Eemin=100 * u.GeV, ) # compute flux at the energies given in data['energy'], and convert to units # of flux data model = IC.flux(data, distance=1.0 * u.kpc).to(data["flux"].unit) # Save this realization of the particle distribution function elec_energy = np.logspace(11, 15, 100) * u.eV nelec = ECPL(elec_energy) # Compute and save total energy in electrons above 1 TeV We = IC.compute_We(Eemin=1 * u.TeV) # The first array returned will be compared to the observed spectrum for # fitting. All subsequent objects will be stores in the sampler metadata # blobs. return model, (elec_energy, nelec), We
def ElectronIC(pars, data): # Match parameters to ECPL properties, and give them the appropriate units amplitude = pars[0] / u.eV alpha = pars[1] e_cutoff = (10**pars[2]) * u.TeV # Initialize instances of the particle distribution and radiative model ECPL = ExponentialCutoffPowerLaw(amplitude, 10. * u.TeV, alpha, e_cutoff) IC = InverseCompton(ECPL, seed_photon_fields=[ 'CMB', ['FIR', 26.5 * u.K, 0.415 * u.eV / u.cm**3] ]) # compute flux at the energies given in data['energy'], and convert to # units of flux data model = IC.flux(data, distance=1.0 * u.kpc) # Save this realization of the particle distribution function elec_energy = np.logspace(11, 15, 100) * u.eV nelec = ECPL(elec_energy) # Compute and save total energy in electrons above 1 TeV We = IC.compute_We(Eemin=1 * u.TeV) # The first array returned will be compared to the observed spectrum for # fitting. All subsequent objects will be stores in the sampler metadata # blobs. return model, (elec_energy, nelec), We
def ElectronSynIC(pars, data): # Match parameters to ECPL properties, and give them the appropriate units amplitude = 10 ** pars[0] / u.eV alpha = pars[1] e_cutoff = (10 ** pars[2]) * u.TeV B = pars[3] * u.uG # Initialize instances of the particle distribution and radiative models ECPL = ExponentialCutoffPowerLaw(amplitude, 10.0 * u.TeV, alpha, e_cutoff) # Compute IC on CMB and on a FIR component with values from GALPROP for the # position of RXJ1713 IC = InverseCompton( ECPL, seed_photon_fields=[ "CMB", ["FIR", 26.5 * u.K, 0.415 * u.eV / u.cm ** 3], ], Eemin=100 * u.GeV, ) SYN = Synchrotron(ECPL, B=B) # compute flux at the energies given in data['energy'] model = IC.flux(data, distance=1.0 * u.kpc) + SYN.flux( data, distance=1.0 * u.kpc ) # The first array returned will be compared to the observed spectrum for # fitting. All subsequent objects will be stored in the sampler metadata # blobs. return model, IC.compute_We(Eemin=1 * u.TeV)
def ElectronSynIC(pars, data): # Match parameters to ECPL properties, and give them the appropriate units amplitude = 10**pars[0] / u.eV alpha = pars[1] e_cutoff = (10**pars[2]) * u.TeV B = pars[3] * u.uG # Initialize instances of the particle distribution and radiative models ECPL = ExponentialCutoffPowerLaw(amplitude, 10. * u.TeV, alpha, e_cutoff) # Compute IC on CMB and on a FIR component with values from GALPROP for the # position of RXJ1713 IC = InverseCompton(ECPL, seed_photon_fields=[ 'CMB', ['FIR', 26.5 * u.K, 0.415 * u.eV / u.cm**3] ], Eemin=100 * u.GeV) SYN = Synchrotron(ECPL, B=B) # compute flux at the energies given in data['energy'] model = (IC.flux(data, distance=1.0 * u.kpc) + SYN.flux(data, distance=1.0 * u.kpc)) # The first array returned will be compared to the observed spectrum for # fitting. All subsequent objects will be stored in the sampler metadata # blobs. return model, IC.compute_We(Eemin=1 * u.TeV)
def ElectronEblAbsorbedSynIC(pars, data): # Match parameters to ECPL properties, and give them the appropriate units amplitude = 10**pars[0] / u.eV e_break = (10**pars[1]) * u.TeV alpha1 = pars[2] alpha2 = pars[3] B = pars[4] * u.uG # Define the redshift of the source, and absorption model redshift = pars[5] * u.dimensionless_unscaled EBL_transmitance = EblAbsorptionModel(redshift, 'Dominguez') # Initialize instances of the particle distribution and radiative models BPL = BrokenPowerLaw(amplitude, 1. * u.TeV, e_break, alpha1, alpha2) # Compute IC on a CMB component IC = InverseCompton( BPL, seed_photon_fields=['CMB'], Eemin=10 * u.GeV) SYN = Synchrotron(BPL, B=B) # compute flux at the energies given in data['energy'] model = (EBL_transmitance.transmission(data) * IC.flux(data, distance=1.0 * u.kpc) + SYN.flux(data, distance=1.0 * u.kpc)) # The first array returned will be compared to the observed spectrum for # fitting. All subsequent objects will be stored in the sampler metadata # blobs. return model, IC.compute_We(Eemin=1 * u.TeV)
def ElectronIC(pars, data): """ Define particle distribution model, radiative model, and return model flux at data energy values """ ECPL = ExponentialCutoffPowerLaw(pars[0] / u.eV, 10.0 * u.TeV, pars[1], 10**pars[2] * u.TeV) IC = InverseCompton(ECPL, seed_photon_fields=["CMB"]) return IC.flux(data, distance=1.0 * u.kpc)
def ElectronIC(pars, data): """ Define particle distribution model, radiative model, and return model flux at data energy values """ ECPL = ExponentialCutoffPowerLaw(pars[0] / u.eV, 10. * u.TeV, pars[1], 10**pars[2] * u.TeV) IC = InverseCompton(ECPL, seed_photon_fields=['CMB']) return IC.flux(data, distance=1.0 * u.kpc)
class ElectronIC(SpectralModel): """This class inherits from SpectralModel in 3ML, and can be used to infer the population of electrons in a source. The fit works as follows: 1. Choose a parametric form for the electron spectrum, e.g., a power law with an exponential cutoff. 2. Use Inverse Compton scattering to calculate the gamma-ray flux. 3. Fit the calculated gamma-ray flux to the data using one of the plugins available in 3ML. The free parameters of this model include the parameters of the electron spectrum and the distance to the source. Additional quantities which affect the calculation are the components of the interstellar radiation field (ISRF) which contribute to the IC flux. These are not floated in the fit. Users may wish to obtain an estimate of the ISRF in the vicinity of the source of interest using GALPROP. """ def setup(self): self.functionName = "ElectronIC" self.formula = r"$f(E)=A(E/E_{\rm piv}}^\gamma}$" self.parameters = collections.OrderedDict() self.parameters["gamma"] = Parameter("gamma", -2., -10., 10, 0.1, fixed=False, nuisance=False, dataset=None) self.parameters["logA"] = Parameter("logA", -4., -40., 30, 0.1, fixed=False, nuisance=False, dataset=None) self.parameters["Epiv"] = Parameter("Epiv", 1., 1e-10, 1e10, 1., fixed=True, unit="keV") self.parameters["dist"] = Parameter("dist", 1., 1e-10, 1e10, 1., fixed=True) self.ncalls = 0 self.pdist_unit = 1. / u.Unit(m_e * c**2) self.PL = PowerLaw(1 * self.pdist_unit, 1 * u.keV, -2.5) self.IC = InverseCompton( self.PL, seed_photon_fields=[ 'CMB', ['FIR', 26.5 * u.K, 0.415 * u.eV / u.cm**3] ], Eemin=1 * u.TeV) # def integral(E1, E2): # a = self.parameters["gamma"].value # Ep = self.parameters["Epiv"].value # A = 10.**self.parameters["logA"].value # # if a == -1.: # def f(energy): # return A * E0 * np.log(energy) # else: # def f(energy): # return A * energy * (energy/Ep)**a / (a + 1.) # return f(E2) - f(E1) # # self.integral = integral def __call__(self, energy): # pdist_unit = 1. / u.Unit(m_e * c**2) self.ncalls += 1 # Convert spectral index to naima sign convention a = -self.parameters["gamma"].value # Convert to naima base units: all energies in keV Ep = self.parameters["Epiv"].value * u.keV # Normalization is actually for electron differential spectrum A = 10.**self.parameters["logA"].value * self.pdist_unit # Initialize the electron particle distribution self.PL.amplitude = A self.PL.e_0 = Ep self.PL.alpha = a # Fix the distance of the source, in kpc dist = self.parameters["dist"].value * u.kpc if type(energy) is float or type(energy) is int: E = [energy] * u.keV else: E = energy * u.keV icFlux = self.IC.flux(E, distance=dist) return icFlux.to(1. / (u.keV * u.cm**2 * u.s)).value def electronFlux(self, energy): # Convert spectral index to naima sign convention a = -self.parameters["gamma"].value # Convert to naima base units: all energies in keV Ep = self.parameters["Epiv"].value * u.keV # Normalization is actually for electron differential spectrum A = 10.**self.parameters["logA"].value * self.pdist_unit # Initialize the electron particle distribution PL = PowerLaw(A, Ep, a) if type(energy) is float or type(energy) is int: E = [energy] * u.keV else: E = energy * u.keV return PL(E).to(1. / u.keV).value def photonFlux(self, E1, E2): return self.integral(E1, E2) def energyFlux(self, E1, E2): a = self.parameters["gamma"].value Ep = self.parameters["Epiv"].value A = 10.**self.parameters["logA"].value if a == 2: def eF(E): return np.maximum(A * np.log(E / Ep), 1e-100) else: def eF(E): return np.maximum(A * np.power(E / Ep, 2 - a) / (2 - a), 1e-100) return (eF(E2) - eF(E1)) * self.keVtoErg
# In[47]: #gamma-ray flux dN/dE #energies at which we want to evaluate the spectrum Egamma = np.logspace(-6, 5, 100) * u.GeV #source distance D=2*u.kpc #get_ipython().magic(u'matplotlib inline') plt.clf() plt.loglog(Egamma, synch.flux(Egamma, distance=D), label="Synchrotron emission") plt.loglog(Egamma, IC.flux(Egamma, distance=D), label="IC emission") plt.loglog(Egamma, brems.flux(Egamma, distance=D), label="Bremsstrahlung") plt.ylabel("Emission spectrum dN/dE [1/eV/cm^2/s]") plt.xlabel("Photon energy [GeV]") plt.ylim(1e-30,1e2) plt.legend() plt.savefig("PhotonFlux.png" ) # In[49]: #gamma-ray SED E^2 dN/dE #energies at which we want to evaluate the spectrum Egamma = np.logspace(-6, 6, 100) * u.GeV
#gamma-ray flux dN/dE #energies at which we want to evaluate the spectrum Egamma = np.logspace(-6, 5, 100) * u.GeV #source distance D = 2 * u.kpc #get_ipython().magic(u'matplotlib inline') plt.clf() plt.loglog(Egamma, synch.flux(Egamma, distance=D), label="Synchrotron emission") plt.loglog(Egamma, IC.flux(Egamma, distance=D), label="IC emission") plt.loglog(Egamma, brems.flux(Egamma, distance=D), label="Bremsstrahlung") plt.ylabel("Emission spectrum dN/dE [1/eV/cm^2/s]") plt.xlabel("Photon energy [GeV]") plt.ylim(1e-30, 1e2) plt.legend() plt.savefig("PhotonFlux.png") # In[49]: #gamma-ray SED E^2 dN/dE #energies at which we want to evaluate the spectrum Egamma = np.logspace(-6, 6, 100) * u.GeV