In this tutorial you will learn step-by-step to use gappa in order to
In [ ]:
%matplotlib inline
import gappa as gp
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
Get an energy axis:
In [ ]:
# note: all input energies are in erg!
emin = 1e-3 * gp.TeV_to_erg
emax = 1e4 * gp.TeV_to_erg
e = np.logspace(np.log10(emin),np.log10(emax),100)
Make your spectral assumption:
In [ ]:
# my choice is a power-law for the electrons
# and protons with spectral index 'spind' and
# exp.cut-off at 'ecute'(electrons) and 'ecutp'(protons)
# plus a oscillation for the protons
spind = 2.1
ecute = 1e2 * gp.TeV_to_erg
ecutp = 1e3 * gp.TeV_to_erg
# energy in particles
we = 1e47
wp = 1e50
nel = e**(-spind) * np.exp(-e/ecute)
npr = e**(-spind) * np.exp(-e/ecutp) * (1 + np.sin(5*np.log10(e)))
Roughly normalise with numpy:
In [ ]:
nel *= we/np.sum((e * nel)[1:]* np.diff(e))
npr *= wp/np.sum((e * npr)[1:]* np.diff(e))
And the result looks like this:
In [ ]:
plt.loglog(e,e*e*npr,c="red")
plt.loglog(e,e*e*nel,c="blue")
plt.ylim(1.e38,1.e54)
Initialise a gappa Radiation object and set these spectra:
In [ ]:
rad = gp.Radiation()
# gappa takes 2D arrays as input
rad.SetElectrons(zip(e,nel))
rad.SetProtons(zip(e,npr))
Now set some parameters:
In [ ]:
# BField in Gauss
rad.SetBField(1e-5)
# Distance in pc
rad.SetDistance(1e3)
# Ambient density in cm^-3
rad.SetAmbientDensity(1.)
In order to set radiation fields, you can either
In [ ]:
# again, energies are always in erg!
rad.AddThermalTargetPhotons(2.7,0.25*gp.eV_to_erg) #CMB
rad.AddThermalTargetPhotons(50.,0.5*gp.eV_to_erg) #some FIR field
targ = np.array(rad.GetTargetPhotons())
plt.loglog(targ[:,0],targ[:,1])
plt.ylim(1e13,1e19)
Add a crazy radiation field:
In [ ]:
et = np.logspace(-20,-13,100)
nt = 1.e16*(1.+10.*np.sin(10.*np.log10(et))/np.log10(et))
rad.AddArbitraryTargetPhotons(zip(et,nt))
targ = np.array(rad.GetTargetPhotons())
In [ ]:
plt.loglog(targ[:,0],targ[:,1])
plt.ylim(1e13,1e19)
Finally, calculate and retrieve the SEDs:
In [ ]:
rad.CalculateDifferentialPhotonSpectrum()
to = np.array(rad.GetTotalSED())
pp = np.array(rad.GetPPSED())
ic = np.array(rad.GetICSED())
br = np.array(rad.GetBremsstrahlungSED())
sy = np.array(rad.GetSynchrotronSED())
In [ ]:
plt.loglog(to[:,0],to[:,1],c="black")
plt.loglog(pp[:,0],pp[:,1],c="green")
plt.loglog(sy[:,0],sy[:,1],c="blue")
plt.loglog(br[:,0],br[:,1],c="red")
plt.loglog(ic[:,0],ic[:,1],c="orange")
plt.ylim(1e-14,1e-9)
In [ ]:
# note: all times are in years
age = 1e3
tmin = 1e1
tmax = age * 1e6 # this has to be high!
t = np.logspace(np.log10(tmin),np.log10(tmax),200)
Now define luminosity and B-field evolution.
NOTE: If you have time-dependent losses, the speed of the
calculation is determined by the strength of the losses.
The higher the losses (e.g. very high B-field), the slower.
In [ ]:
bt = 1e-3 / np.sqrt(t)
lumt = 1e38/(1. + t/500.)**2
In [ ]:
plt.plot(t,bt)
plt.xlim(0.,1000.)
In [ ]:
plt.plot(t,lumt)
plt.xlim(0.,1000.)
Create a 'Particle' object and set these evolutions
In [ ]:
par = gp.Particles()
par.SetAge(age)
par.SetBFieldLookup(zip(t,bt))
par.SetLuminosityLookup(zip(t,lumt))
par.SetAmbientDensity(2.)
For IC losses, a lookup has to be created.
This is done with the 'Radiation' object.
Let's just use the previously defined radiation field.
In [ ]:
rad.CreateICLossLookup()
icl = np.array(rad.GetICLossLookup())
In [ ]:
plt.loglog(icl[:,0],icl[:,1],c="black")
In [ ]:
par.SetICLossLookup(icl)
The only thing missing is the shape of the injection spectrum.
Let's assume our source is injecting a broken power law:
In [ ]:
par.SetLowSpectralIndex(1.5)
par.SetSpectralIndex(2.5)
par.SetBreakEnergy(0.1*gp.TeV_to_erg)
par.SetEmax(5e2)
Now we can do the evolution calculation!
In [ ]:
par.CalculateParticleSpectrum("electrons")
el = np.array(par.GetParticleSED())
In [ ]:
plt.loglog(el[:,0],el[:,1],c="black")
plt.ylim(1e41,1e48)
par.SetAge(.1*age)
par.CalculateParticleSpectrum("electrons")
el2 = np.array(par.GetParticleSED())
plt.loglog(el2[:,0],el2[:,1],c="red")
par.SetAge(10.*age)
par.CalculateParticleSpectrum("electrons")
el3 = np.array(par.GetParticleSED())
plt.loglog(el3[:,0],el3[:,1],c="blue")
par.SetAge(100.*age)
par.CalculateParticleSpectrum("electrons")
el4 = np.array(par.GetParticleSED())
plt.loglog(el4[:,0],el4[:,1],c="orange")
Now let's calculate the radiation spectrum.
Here, we set the parameters of the radiation object that
corresponds to the what's in the 'Particle' object at t=age
In [ ]:
rad.SetBField(par.GetBField())
rad.SetAmbientDensity(par.GetAmbientDensity())
rad.SetElectrons(par.GetParticleSpectrum())
print par.GetBField()
rad.CalculateDifferentialPhotonSpectrum()
to = np.array(rad.GetTotalSED())
pp = np.array(rad.GetPPSED())
ic = np.array(rad.GetICSED())
br = np.array(rad.GetBremsstrahlungSED())
sy = np.array(rad.GetSynchrotronSED())
And plot it:
In [ ]:
#plt.loglog(to[:,0],to[:,1],c="black")
plt.loglog(sy[:,0],sy[:,1],c="blue")
plt.loglog(br[:,0],br[:,1],c="red")
plt.loglog(ic[:,0],ic[:,1],c="orange")
plt.ylim(1e-16,1e-9)
In [ ]:
bb = 20000
xx = 20*np.random.random(bb)-10
yy = 20*np.random.random(bb)-5
Initialise an 'Astro' object:
In [ ]:
ao = gp.Astro()
Function that gets hydrogen densities at (x,y,0) coordinates,
either from the original model by Ferriere 2001 and modulated
with spiral arms:
In [ ]:
def get_densities(xx,yy):
nn = []
nnmod = []
for i in xrange(len(xx)):
n = ao.HIDensity(xx[i],yy[i],0.)+ao.H2Density(xx[i],yy[i],0.)
nn.append(n)
nm = ao.ModulateGasDensityWithSpirals(n,xx[i],yy[i],0.)
nnmod.append(nm)
return nn,nnmod
In [ ]:
nn,nnmod = get_densities(xx,yy)
Plot the unmodulated and modulated densities:
In [ ]:
plt.hist2d(xx,yy,weights=nn,normed=False,bins=(50,50),cmap=plt.cm.copper_r,alpha=1.,norm=LogNorm())
cb = plt.colorbar()
In [ ]:
plt.hist2d(xx,yy,weights=nnmod,normed=False,bins=(50,50),cmap=plt.cm.copper_r,alpha=1.,norm=LogNorm())
cb = plt.colorbar()
Disable an arm, change the arm model, change the arms width:
In [ ]:
ao.DisableArm(1)
dummy,nnmodnoarm = get_densities(xx,yy)
ao.EnableArm(4)
ao.SetSpiralArmModel("TaylorCordes")
dummy,nnmodtc = get_densities(xx,yy)
ao.SetArmWidth(0.2)
dummy,nnmodthin = get_densities(xx,yy)
In [ ]:
plt.hist2d(xx,yy,weights=nnmodnoarm,normed=False,bins=(50,50),cmap=plt.cm.copper_r,alpha=1.,norm=LogNorm())
cb = plt.colorbar()
In [ ]:
plt.hist2d(xx,yy,weights=nnmodtc,normed=False,bins=(50,50),cmap=plt.cm.copper_r,alpha=1.,norm=LogNorm())
cb = plt.colorbar()
In [ ]:
plt.hist2d(xx,yy,weights=nnmodthin,normed=False,bins=(50,50),cmap=plt.cm.copper_r,alpha=1.,norm=LogNorm())
cb = plt.colorbar()
Now get some random positions in the galaxy that follows
the Case&Bhattacharya surface density model:
In [ ]:
ao.SetSpiralArmModel("Vallee")
pos = np.array(ao.DiceGalacticPositions(100))
plt.hist2d(xx,yy,weights=nnmod,normed=False,bins=(50,50),cmap=plt.cm.copper_r,alpha=1.,norm=LogNorm())
cb = plt.colorbar()
plt.scatter(pos[:,0],pos[:,1],c="white")