Beispiel #1
0
    def __init__( self, theta=power_angles(), \
                      scatm=ss.Scatmodel(), \
                      rad=0.1, ener=1.0, nx=1000 ):
        # Theta automatically sampled in log space.
        # If I don't do it this way, linear interpolation easily fails
        # for small angles (between theta[0] and theta[1]).  Since
        # most of my plots are in log-space, it makes more sense to
        # sample logarithmically.

        if np.size(theta) < 2:
            print('Error: Must give more than one theta value')
            self.theta = None
            self.rad   = None
            self.ener  = None
            self.scatm = None

        self.theta = theta
        self.rad   = rad
        self.ener  = ener
        self.scatm = scatm

        dxi = 1.0 / np.float(nx)
        xi  = np.arange( 0, 1.0, dxi ) + dxi
        itemp = np.array([])

        for th in self.theta:
            thscat = th / xi
            dsig = ss.Diffscat( theta=thscat, scatm=self.scatm, E=self.ener, a=self.rad ).dsig
            itemp = np.append( itemp, \
                                   c.intz( xi, dsig/(xi**2) ) )

        self.itemp = itemp * c.arcs2rad**2
Beispiel #2
0
def DChi( z, zp=0.0, cosm=Cosmology(), nz=100 ):
    """
    Calculates co-moving radial distance [Gpc] from zp to z using dx = cdt/a
    z    : float : redshift
    zp   ; float (0) : starting redshift
    cosm : Cosmology
    nz   : int (100) : number of z-values to use in calculation
    """
    zvals     = zvalues( zs=z, z0=zp, nz=nz )
    integrand = c.cperh0 * ( c.h0/cosm.h0 ) / np.sqrt( cosm.m * np.power(1+zvals,3) + cosm.l )
    return c.intz( zvals, integrand ) / (1e9 * c.pc2cm ) # Gpc, in comoving coordinates
Beispiel #3
0
def ScreenIGM(halo, zs=2.0, zg=1.0, md=1.5e-5, cosm=cosmo.Cosmology()):
    """
    FUNCTION ScreenIGM( halo, zs=2.0, zg=1.0, md=1.5e-5, cosm=cosmo.Cosmology() )
    MODIFIES halo.htype, halo.dist, halo.intensity, halo.taux
    --------------------------------------------------------------------
    halo : Halo object
    zs   : float : redshift of source
    zg   : float : redshift of screen
    md   : float : mass density of dust to use in screen [g cm^-2]
    cosm : cosmo.Cosmology
    """
    if zg >= zs:
        print "%% STOP: zg must be < zs"

    E0 = halo.energy
    alpha = halo.alpha
    scatm = halo.scatm

    # Store information about this halo calculation
    halo.htype = CosmHalo(zs=zs, zg=zg, cosm=cosm, igmtype="Screen")
    halo.dist = dust.Dustspectrum(rad=halo.rad, md=md)

    X = cosmo.DChi(zs, zp=zg, cosm=cosm) / cosmo.DChi(zs, cosm=cosm)  # Single value
    thscat = alpha / X  # Scattering angle required
    Eg = E0 * (1 + zg)  # Photon energy at the screen

    ## Single grain size case

    if type(halo.rad) == dust.Grain:
        dsig = ss.Diffscat(theta=thscat, a=halo.dist.a, E=Eg, scatm=scatm).dsig
        intensity = halo.dist.nd / np.power(X, 2) * dsig

    ## Distribution of grain sizes

    elif type(halo.rad) == dust.Dustdist:

        avals = halo.dist.a

        dsig = np.zeros(shape=(np.size(avals), np.size(thscat)))
        for i in range(np.size(avals)):
            dsig[i, :] = ss.Diffscat(theta=thscat, a=avals[i], E=Eg, scatm=scatm).dsig

        intensity = np.array([])
        for j in range(np.size(thscat)):
            itemp = halo.dist.nd * dsig[:, j] / np.power(X, 2)
            intensity = np.append(intensity, c.intz(avals, itemp))

    else:
        print "%% Must input type dust.Grain or dust.Dustdist"
        intensity = np.zeros(np.size(zpvals))

    halo.intensity = intensity * np.power(c.arcs2rad(), 2)  # arcsec^-2
    halo.taux = cosmo.CosmTauScreen(zg, E=halo.energy, dist=halo.dist, scatm=halo.scatm)
Beispiel #4
0
    def __init__( self, E=1.0, scatm=Scatmodel(), dist=dust.Dustspectrum() ):
        self.scatm  = scatm
        self.E      = E
        self.dist   = dist

        if scatm.stype == 'RG':
            print 'Rayleigh-Gans cross-section not currently supported for Kappaext'
            self.kappa = None
            return

        cm   = scatm.cmodel
        scat = scatm.smodel

        cgeo = np.pi * np.power( dist.a * c.micron2cm(), 2 )

        qext    = np.zeros( shape=( np.size(E),np.size(dist.a) )  )
        qext_pe = np.zeros( shape=( np.size(E),np.size(dist.a) )  )
        qext_pa = np.zeros( shape=( np.size(E),np.size(dist.a) )  )
                                
        # Test for graphite case
        if cm.cmtype == 'Graphite':
            cmGraphitePerp = cmi.CmGraphite(size=cm.size, orient='perp')
            cmGraphitePara = cmi.CmGraphite(size=cm.size, orient='para')

            if np.size(dist.a) > 1:
                for i in range( np.size(dist.a) ):
                    qext_pe[:,i] = scat.Qext( E, a=dist.a[i], cm=cmGraphitePerp )
                    qext_pa[:,i] = scat.Qext( E, a=dist.a[i], cm=cmGraphitePara )
            else:
                qext_pe = scat.Qext( E, a=dist.a, cm=cmGraphitePerp )
                qext_pa = scat.Qext( E, a=dist.a, cm=cmGraphitePara )
            
            qext    = ( qext_pa + 2.0 * qext_pe ) / 3.0

        else:
            if np.size(dist.a) > 1:
                for i in range( np.size(dist.a) ):
                    qext[:,i] = scat.Qext( E, a=dist.a[i], cm=cm )
            else:
                qext = scat.Qext( E, a=dist.a, cm=cm )

        if np.size(dist.a) == 1:
            kappa = dist.nd * qext * cgeo / dist.md
        else:
            kappa = np.array([])
            for j in range( np.size(E) ):
                kappa = np.append( kappa, \
                                   c.intz( dist.a, dist.nd * qext[j,:] * cgeo ) / dist.md )

        self.kappa = kappa
Beispiel #5
0
def CosmTauX( z, E=1.0, dist=dust.Powerlaw(), scatm=ss.Scatmodel(), cosm=Cosmology(), nz=100 ):
    """
    FUNCTION CosmTauX( z, E=1.0, dist=dust.Powerlaw(), scatm=ss.Scatmodel(), cosm=Cosmology(), nz=100 
    ---------------------------------
    INPUT
    z : redshift of source
    E : scalar or np.array [keV]
    dist  : dust.Powerlaw or dust.Grain
    scatm : ss.Scatmodel
    cosm  : cosm.Cosmology
    ---------------------------------
    OUTPUT
    tauX : scalar or np.array [optical depth to X-ray scattering]
           = kappa( dn/da da ) cosmdens (1+z)^2 cdz/hfac
    """

    zvals     = zvalues( zs=z, nz=nz )
    md        = Cosmdens( cosm=cosm ).md
    spec      = dust.Dustspectrum( rad=dist, md=md )

    if np.size(E) > 1:
        result = np.array([])
        for ener in E:
            Evals = ener * (1+zvals)
            kappa     = ss.Kappascat( E=Evals, scatm=scatm, dist=spec ).kappa
            hfac      = np.sqrt( cosm.m * np.power( 1+zvals, 3 ) + cosm.l )
            integrand = kappa * md * np.power( 1+zvals, 2 ) * \
                c.cperh0 * ( c.h0/cosm.h0 ) / hfac
            result    = np.append( result, c.intz( zvals, integrand ) )
    else:
        Evals     = E * (1 + zvals)
        kappa     = ss.Kappascat( E=Evals, scatm=scatm, dist=spec ).kappa
        hfac      = np.sqrt( cosm.m * np.power( 1+zvals, 3 ) + cosm.l )
        integrand = kappa * md * np.power( 1+zvals, 2 ) * c.cperh0 * ( c.h0/cosm.h0 ) / hfac
        result    = c.intz( zvals, integrand )

    return result
Beispiel #6
0
 def ecf( self, theta, nth=500 ):
     NE, NA = len(self.energy), len(self.alpha)
     result = np.zeros( NE ) # NE x NA
     taux   = self.taux
     tharray = np.linspace( min(self.alpha), theta, nth )
     
     if self.taux == None:
         print('ERROR: No taux is specified. Need to run halo calculation')
         return result
     
     for i in range(NE):
         interpH = interp1d( self.alpha, self.intensity[i,:] )
         result[i] = c.intz( tharray, interpH(tharray) * 2.0*np.pi*tharray ) / taux[i]
     
     return result
Beispiel #7
0
 def ecf(self, theta, nth=500):
     """
     Returns the enclosed fraction for the halo surface brightness
     profile, via integral(theta,2pi*theta*halo)/tau.
     theta : float : Value for which to compute enclosed fraction (arcseconds)
     nth   : int (500) : Number of angles to use in calculation
     """
     if self.htype == None:
         print "Error: Halo has not yet beein calculated."
         return
     interpH = interp1d(self.alpha, self.intensity)
     tharray = np.linspace(min(self.alpha), theta, nth)
     try:
         return c.intz(tharray, interpH(tharray) * 2.0 * np.pi * tharray) / self.taux
     except:
         print "Error: ECF calculation failed. Theta is likely out of bounds."
         return
Beispiel #8
0
    def __init__( self, E=1.0, scatm=Scatmodel(), dist=dust.Dustspectrum() ):
        self.scatm  = scatm
        self.E      = E
        self.dist   = dist

        cm   = scatm.cmodel
        scat = scatm.smodel

        cgeo = np.pi * np.power( dist.a * c.micron2cm(), 2 )

        qsca    = np.zeros( shape=( np.size(E),np.size(dist.a) )  )
        qsca_pe = np.zeros( shape=( np.size(E),np.size(dist.a) )  )
        qsca_pa = np.zeros( shape=( np.size(E),np.size(dist.a) )  )
                                
        # Test for graphite case
        if cm.cmtype == 'Graphite':
            cmGraphitePerp = cmi.CmGraphite(size=cm.size, orient='perp')
            cmGraphitePara = cmi.CmGraphite(size=cm.size, orient='para')

            if np.size(dist.a) > 1:
                for i in range( np.size(dist.a) ):
                    qsca_pe[:,i] = scat.Qsca( E, a=dist.a[i], cm=cmGraphitePerp )
                    qsca_pa[:,i] = scat.Qsca( E, a=dist.a[i], cm=cmGraphitePara )
            else:
                qsca_pe = scat.Qsca( E, a=dist.a, cm=cmGraphitePerp )
                qsca_pa = scat.Qsca( E, a=dist.a, cm=cmGraphitePara )
            
            qsca    = ( qsca_pa + 2.0 * qsca_pe ) / 3.0

        else:
            if np.size(dist.a) > 1:
                for i in range( np.size(dist.a) ):
                    qsca[:,i] = scat.Qsca( E, a=dist.a[i], cm=cm )
            else:
                qsca = scat.Qsca( E, a=dist.a, cm=cm )

        if np.size(dist.a) == 1:
            kappa = dist.nd * qsca * cgeo / dist.md
        else:
            kappa = np.array([])
            for j in range( np.size(E) ):
                kappa = np.append( kappa, \
                                   c.intz( dist.a, dist.nd * qsca[j,:] * cgeo ) / dist.md )

        self.kappa = kappa
Beispiel #9
0
def DiscreteISM( halo, xg=0.5, NH=1.0e20, d2g=0.009 ):
    """
    Calculate the X-ray scattering intensity for dust in an
    infinitesimally thin wall somewhere on the line of sight.
    
    | **MODIFIES**
    | halo.htype, halo.dist, halo.taux, halo.intensity
    
    | **INPUTS**
    | halo : Halo object
    | xg   : float : distance FROM source / distance between source and observer
    | NH   : float : column density [cm^-2]
    | d2g  : float : dust-to-gass mass ratio
    """
    E0    = halo.energy
    alpha = halo.alpha
    scatm = halo.scatm
    md    = NH * c.m_p * d2g

    halo.htype = GalHalo( xg=xg, NH=NH, d2g=d2g, ismtype='Screen' )
    halo.dist  = dust.Dustspectrum( rad=halo.rad, md=md )

    thscat = alpha / xg

    if type(halo.rad) == dust.Grain:
        dsig = ss.Diffscat( theta=thscat, a=halo.dist.a, E=E0, scatm=scatm ).dsig
        intensity = np.power( xg, -2.0 ) * dsig * halo.dist.nd

    elif type(halo.rad) == dust.Dustdist:
        avals  = halo.dist.a
        intensity = []
        for i in range( len(alpha) ):
            iatemp = np.zeros( shape=( len(avals),len(alpha) ) )
            for j in range( len(avals) ):
                dsig    = ss.Diffscat( theta=thscat, a=avals[j], E=E0, scatm=scatm ).dsig
                iatemp[j,:] = np.power(xg,-2.0) * dsig
            intensity.append( c.intz( avals, iatemp[:,i] * halo.dist.nd ) )
        intensity = np.array( intensity )
    else:
        print('%% Must input type dust.Grain or dust.Dustdist')
        intensity = np.zeros( np.size(xvals) )

    halo.intensity = intensity * np.power( c.arcs2rad, 2 )  # arcsec^-2
    halo.taux      = ss.Kappascat( E=halo.energy, scatm=halo.scatm, dist=halo.dist ).kappa * md
Beispiel #10
0
def DiscreteISM( halo, xg=0.5, NH=1.0e20, d2g=0.009 ):
    """
    FUNCTION DiscreteISM( halo, xg=0.5, NH=1.0e20, d2g=0.009 )
    MODIFIES halo.htype, halo.dist, halo.taux, halo.intensity
    ----------------------------------------------------------------------------
    halo : Halo object
    xg   : float : distance FROM source / distance between source and observer
    NH   : float : column density [cm^-2]
    d2g  : float : dust-to-gass mass ratio
    """
    E0    = halo.energy
    alpha = halo.alpha
    scatm = halo.scatm
    md    = NH * c.mp() * d2g

    halo.htype = GalHalo( xg=xg, NH=NH, d2g=d2g, ismtype='Screen' )
    halo.dist  = dust.Dustspectrum( rad=halo.rad, md=md )

    thscat = alpha / xg

    if type(halo.rad) == dust.Grain:
        dsig = ss.Diffscat( theta=thscat, a=halo.dist.a, E=E0, scatm=scatm ).dsig
        intensity = np.power( xg, -2.0 ) * dsig * halo.dist.nd

    elif type(halo.rad) == dust.Dustdist:
        avals  = halo.dist.a
        intensity = []
        for i in range( len(alpha) ):
            iatemp = np.zeros( shape=( len(avals),len(alpha) ) )
            for j in range( len(avals) ):
                dsig    = ss.Diffscat( theta=thscat, a=avals[j], E=E0, scatm=scatm ).dsig
                iatemp[j,:] = np.power(xg,-2.0) * dsig
            intensity.append( c.intz( avals, iatemp[:,i] * halo.dist.nd ) )
        intensity = np.array( intensity )
    else:
        print '%% Must input type dust.Grain or dust.Dustdist'
        intensity = np.zeros( np.size(xvals) )

    halo.intensity = intensity * np.power( c.arcs2rad(), 2 )  # arcsec^-2
    halo.taux      = ss.Kappascat( E=halo.energy, scatm=halo.scatm, dist=halo.dist ).kappa * md
Beispiel #11
0
    def __call__(self, with_mp=False):
        cm   = self.scatm.cmodel
        scat = self.scatm.smodel

        cgeo = np.pi * np.power( self.dist.a * c.micron2cm(), 2 )

        # Test for graphite case
        if cm.cmtype == 'Graphite':
            if np.size(self.dist.a) > 1:
                for i in range( np.size(self.dist.a) ):
                    self.qsca_pe[:,i] = scat.Qsca( self.E, a=self.dist.a[i], cm=cmi.CmGraphite(size=cm.size, orient='perp') )
                    self.qsca_pa[:,i] = scat.Qsca( self.E, a=self.dist.a[i], cm=cmi.CmGraphite(size=cm.size, orient='para') )
            else:
                self.qsca_pe = scat.Qsca( self.E, a=self.dist.a, cm=cmi.CmGraphite(size=cm.size, orient='perp') )
                self.qsca_pa = scat.Qsca( self.E, a=self.dist.a, cm=cmi.CmGraphite(size=cm.size, orient='para') )
            
            self.qsca = ( self.qsca_pa + 2.0 * self.qsca_pe ) / 3.0

        else:
            if np.size(self.dist.a) > 1:
                if with_mp:
                    pool = Pool(processes=2)
                    self.qsca = np.array(pool.map(self._one_scatter,self.dist.a)).T
                else:
                    for i in range( np.size(self.dist.a) ):
                        self.qsca[:,i] = self._one_scatter(self.dist.a[i])
            else:
                self.qsca = scat.Qsca( self.E, a=self.dist.a, cm=cm )

        if np.size(self.dist.a) == 1:
            kappa = self.dist.nd * self.qsca * cgeo / self.dist.md
        else:
            kappa = np.array([])
            for j in range( np.size(self.E) ):
                kappa = np.append( kappa, \
                                   c.intz( self.dist.a, self.dist.nd * self.qsca[j,:] * cgeo ) / self.dist.md )

        self.kappa = kappa
Beispiel #12
0
 def ecf( self, theta, nth=500 ):
     """
     Returns the enclosed fraction for the halo surface brightness
     profile, as a function of energy via 
     integral(theta,2pi*theta*halo)/total_halo_counts
     -------------------------------------------------------------------------
     theta : float : Value for which to compute enclosed fraction (arcseconds)
     nth   : int (500) : Number of angles to use in calculation
     """
     NE, NA = len(self.energy), len(self.alpha)
     result = np.zeros( NE ) # NE x NA
     taux   = self.taux
     tharray = np.linspace( min(self.alpha), theta, nth )
     
     if self.taux == None:
         print 'ERROR: No taux is specified. Need to run halo calculation'
         return result
     
     for i in range(NE):
         interpH = interp1d( self.alpha, self.intensity[i,:] )
         result[i] = c.intz( tharray, interpH(tharray) * 2.0*np.pi*tharray ) / taux[i]
     
     return result
Beispiel #13
0
def UniformIGM(halo, zs=4.0, cosm=cosmo.Cosmology(), nz=500):
    """
    FUNCTION UniformIGM( halo, zs=4.0, cosm=cosmo.Cosmology(), nz=500 )
    MODIFIES halo.htype, halo.dist, halo.intensity, halo.taux
    --------------------------------------------------------------------
    halo : Halo object
    zs   : float : redshift of source
    cosm : cosmo.Cosmology
    nz   : int : number of z-values to use in integration
    """
    E0 = halo.energy
    alpha = halo.alpha
    scatm = halo.scatm

    halo.htype = CosmHalo(zs=zs, cosm=cosm, igmtype="Uniform")  # Stores information about this halo calc
    halo.dist = dust.Dustspectrum(rad=halo.rad, md=cosmo.Cosmdens(cosm=cosm).md)

    Dtot = cosmo.DChi(zs, cosm=cosm, nz=nz)
    zpvals = cosmo.zvalues(zs=zs - zs / nz, z0=0, nz=nz)

    DP = np.array([])
    for zp in zpvals:
        DP = np.append(DP, cosmo.DChi(zs, zp=zp, cosm=cosm))

    X = DP / Dtot

    c_H0_cm = c.cperh0() * (c.h0() / cosm.h0)  # cm
    hfac = np.sqrt(cosm.m * np.power(1 + zpvals, 3) + cosm.l)

    Evals = E0 * (1 + zpvals)

    ## Single grain case

    if type(halo.rad) == dust.Grain:

        intensity = np.array([])

        f = 0.0
        cnt = 0.0
        na = np.size(alpha)
        for al in alpha:
            cnt += 1
            thscat = al / X  # np.size(thscat) = nz
            dsig = ss.Diffscat(theta=thscat, a=halo.dist.a, E=Evals, scatm=scatm).dsig
            itemp = c_H0_cm / hfac * np.power((1 + zpvals) / X, 2) * halo.dist.nd * dsig
            intensity = np.append(intensity, c.intz(zpvals, itemp))

    ## Dust distribution case

    elif type(halo.rad) == dust.Dustdist:

        avals = halo.dist.a
        intensity = np.array([])

        for al in alpha:
            thscat = al / X  # np.size(thscat) = nz

            iatemp = np.array([])
            for aa in avals:
                dsig = ss.Diffscat(theta=thscat, a=aa, E=Evals, scatm=scatm).dsig
                dtmp = c_H0_cm / hfac * np.power((1 + zpvals) / X, 2) * dsig
                iatemp = np.append(iatemp, c.intz(zpvals, dtmp))

            intensity = np.append(intensity, c.intz(avals, halo.dist.nd * iatemp))

    else:
        print "%% Must input type dust.Grain or dust.Dustdist"
        intensity = np.zeros(np.size(zpvals))

    # ----- Finally, set the halo intensity --------

    halo.intensity = intensity * np.power(c.arcs2rad(), 2)  # arcsec^-2
    halo.taux = cosmo.CosmTauX(zs, E=halo.energy, dist=halo.rad, scatm=halo.scatm, cosm=halo.htype.cosm)
Beispiel #14
0
 def ndens(self, md=MDUST):
     adep  = np.power( self.a, -self.p )   # um^-p
     dmda  = adep * 4./3. * np.pi * self.rho * np.power( self.a*c.micron2cm, 3 ) # g um^-p
     const = md / c.intz( self.a, dmda ) # cm^-? um^p-1
     return const * adep # cm^-? um^-1
Beispiel #15
0
 def dnda(self, md=1.5e-5):
     adep  = np.power( self.a, -self.p )   # um^-p
     dmda  = adep * 4./3. * np.pi * self.rho * np.power( self.a*c.micron2cm(), 3 ) # g um^-p
     const = md / c.intz( self.a, dmda ) # cm^-? um^p-1
     return const * adep # cm^-? um^-1
Beispiel #16
0
def make_WD01_Dustspectrum( R_V=3.1, bc=0.0, rad=DEFAULT_RAD, type='Graphite', gal='MW', verbose=True ):
    """
    make_WD01_Dustspectrum(
    R_V [float],
    bc [float],
    rad [np.array : grain sizes (um)],
    type [string : 'Graphite' or 'Silicate'] )
    gal [string : 'MW', 'LMC', or 'SMC'], 
    -------------------------------------------
    Returns a dust.Dustspectrum object containing a 
    (grain sizes), nd (dn/da), and md (total mass density of dust)
    
    >>> wd01_sil = make_WD01_Dustspectrum(type='Silicate')
    >>> (dust._integrate_dust_mass(wd01_sil)/wd01_sil.md) - 1.0 < 0.01
    
    >>> wd01_gra = make_WD01_Dustspectrum(type='Graphite')
    >>> (dust._integrate_dust_mass(wd01_gra)/wd01_gra.md) - 1.0 < 0.01
    """

    if type == 'Graphite':
        rho_d = 2.2  #g cm^-3
    elif type == 'Silicate':
        rho_d = 3.8
    else:
        print('Error: Dust type not recognized')
        return
    
    ANGS2MICRON = 1.e-10 * 1.e6
    a    = rad  # Easier than changing variable names further down
    a_cm = rad * c.micron2cm
    NA   = np.size( a )


    (alpha, beta, a_t, a_c, C) = get_dist_params( R_V=R_V, bc=bc, type=type, gal=gal, verbose=verbose )

    if type == 'Graphite':

        mc      = 12. * 1.67e-24   # Mass of carbon atom in grams (12 m_p)                                                  
        rho     = 2.24             # g cm^-3                                                                                
        sig     = 0.4
        a_01    = 3.5*ANGS2MICRON      # 3.5 angstroms in units of microns                                                  
        a_01_cm = a_01 * c.micron2cm
        bc1     = 0.75 * bc * 1.e-5
        B_1     = (3.0/(2*np.pi)**1.5) * np.exp(-4.5 * 0.4**2) / (rho*a_01_cm**3 * 0.4) \
            * bc1 * mc / (1 + special.erf( 3*0.4/np.sqrt(2) + np.log(a_01/3.5e-4)/(0.4*np.sqrt(2)) ) )
        
        a_02    = 30.0*ANGS2MICRON       # 30 angtroms in units of microns                                                  
        a_02_cm = a_02 * c.micron2cm
        bc2     = 0.25 * bc * 1.e-5
        B_2     = (3.0/(2*np.pi)**1.5) * np.exp(-4.5 * 0.4**2) / (rho*a_02_cm**3 * 0.4) \
            * bc2 * mc / (1 + special.erf( 3*0.4/np.sqrt(2) + np.log(a_02/3.5e-4)/(0.4*np.sqrt(2)) ) )
        
        D       = (B_1/a_cm) * np.exp( -0.5*( np.log(a/a_01)/sig )**2 ) + \
            (B_2/a_cm) * np.exp( -0.5*( np.log(a/a_02)/sig )**2 )

        Case_vsg = np.where( a < 3.5*ANGS2MICRON )
        if np.size(Case_vsg) != 0:
            D[Case_vsg] = 0.0

        Case_g = np.zeros( NA )
        case1g = np.where( np.logical_and(a > 3.5*ANGS2MICRON, a < a_t ) )
        case2g = np.where( a >= a_t )

        if np.size(case1g) != 0:
            Case_g[case1g] = 1.0
        if np.size(case2g) != 0:
            Case_g[case2g] = np.exp( -( (a[case2g]-a_t) / a_c )**3 )

        if beta >= 0:
            F_g  = 1 + beta * a / a_t
        if beta < 0:
            F_g  = 1.0 / (1 - beta * a / a_t)

        Dist_WD01 = D + C/a_cm * (a/a_t)**alpha * F_g * Case_g  #cm^-4 per n_H

    if type == 'Silicate':

        Case_s = np.zeros( NA )
        case1s = np.where( np.logical_and( a > 3.5*ANGS2MICRON, a < a_t ) )
        case2s = np.where( a >= a_t )

        if np.size(case1s) != 0:
            Case_s[case1s] = 1.0
        if np.size(case2s) != 0:
            Case_s[case2s] = np.exp( -( (a[case2s]-a_t)/a_c )**3 )

        F_s    = np.zeros( NA )
        if beta >= 0:
            F_s = 1 + beta * a / a_t
        if beta < 0:
            F_s = 1. / (1 - beta * a / a_t)

        Dist_WD01 = C/a_cm * (a/a_t)**alpha * F_s * Case_s #cm^-4 per n_H

    mg = 4.0/3.0*np.pi*a_cm**3 * rho_d  # mass of each dust grain
    Md = c.intz( a_cm, Dist_WD01 * mg )
    
    result = dust.Dustspectrum()
    result.a   = a
    result.rho = rho_d
    result.nd  = Dist_WD01 * c.micron2cm  # cm^-3 per um per n_H
    result.md  = Md

    return result
Beispiel #17
0
def make_WD01_Dustspectrum( R_V=3.1, bc=0.0, rad=dust.adist(), type='Graphite', gal='MW' ):
    """
    make_WD01_Dustspectrum(
    R_V [float],
    bc [float],
    rad [np.array : grain sizes (um)],
    type [string : 'Graphite' or 'Silicate'] )
    gal [string : 'MW', 'LMC', or 'SMC'], 
    -------------------------------------------
    Returns a dust.Dustspectrum object containing a (grain sizes), nd (dn/da), and md (total mass density of dust)
    """

    if type == 'Graphite':
        rho_d = 2.2  #g cm^-3
    elif type == 'Silicate':
        rho_d = 3.8
    else:
        print 'Error: Dust type not recognized'
        return

    dist   = dust.Dustdist( rad=rad, rho=rho_d, p=4 )
    result = dust.Dustspectrum( rad=dist )

    ANGS2MICRON = 1.e-10 * 1.e6
    a    = dist.a
    a_cm = dist.a * c.micron2cm()
    NA   = np.size( a )


    (alpha, beta, a_t, a_c, C) = get_dist_params( R_V=R_V, bc=bc, type=type, gal=gal )

    if type == 'Graphite':

        mc      = 12. * 1.67e-24   # Mass of carbon atom in grams (12 m_p)                                                  
        rho     = 2.24             # g cm^-3                                                                                
        sig     = 0.4
        a_01    = 3.5*ANGS2MICRON      # 3.5 angstroms in units of microns                                                  
        a_01_cm = a_01 * c.micron2cm()
        bc1     = 0.75 * bc * 1.e-5
        B_1     = (3.0/(2*np.pi)**1.5) * np.exp(-4.5 * 0.4**2) / (rho*a_01_cm**3 * 0.4) \
            * bc1 * mc / (1 + special.erf( 3*0.4/np.sqrt(2) + np.log(a_01/3.5e-4)/(0.4*np.sqrt(2)) ) )
        
        a_02    = 30.0*ANGS2MICRON       # 30 angtroms in units of microns                                                  
        a_02_cm = a_02 * c.micron2cm()
        bc2     = 0.25 * bc * 1.e-5
        B_2     = (3.0/(2*np.pi)**1.5) * np.exp(-4.5 * 0.4**2) / (rho*a_02_cm**3 * 0.4) \
            * bc2 * mc / (1 + special.erf( 3*0.4/np.sqrt(2) + np.log(a_02/3.5e-4)/(0.4*np.sqrt(2)) ) )
        
        D       = (B_1/a_cm) * np.exp( -0.5*( np.log(a/a_01)/sig )**2 ) + \
            (B_2/a_cm) * np.exp( -0.5*( np.log(a/a_02)/sig )**2 )

        Case_vsg = np.where( a < 3.5*ANGS2MICRON )
        if np.size(Case_vsg) != 0:
            D[Case_vsg] = 0.0

        Case_g = np.zeros( NA )
        case1g = np.where( np.logical_and(a > 3.5*ANGS2MICRON, a < a_t ) )
        case2g = np.where( a >= a_t )

        if np.size(case1g) != 0:
            Case_g[case1g] = 1.0
        if np.size(case2g) != 0:
            Case_g[case2g] = np.exp( -( (a[case2g]-a_t) / a_c )**3 )

        if beta >= 0:
            F_g  = 1 + beta * a / a_t
        if beta < 0:
            F_g  = 1.0 / (1 - beta * a / a_t)

        Dist_WD01 = D + C/a_cm * (a/a_t)**alpha * F_g * Case_g  #cm^-4 per n_H

    if type == 'Silicate':

        Case_s = np.zeros( NA )
        case1s = np.where( np.logical_and( a > 3.5*ANGS2MICRON, a < a_t ) )
        case2s = np.where( a >= a_t )

        if np.size(case1s) != 0:
            Case_s[case1s] = 1.0
        if np.size(case2s) != 0:
            Case_s[case2s] = np.exp( -( (a[case2s]-a_t)/a_c )**3 )

        F_s    = np.zeros( NA )
        if beta >= 0:
            F_s = 1 + beta * a / a_t
        if beta < 0:
            F_s = 1. / (1 - beta * a / a_t)

        Dist_WD01 = C/a_cm * (a/a_t)**alpha * F_s * Case_s #cm^-4 per n_H

    ## Modify result Dustspectrum so we get a proper WD01 dist!

    mg = 4.0/3.0*np.pi*a_cm**3 * rho_d  # mass of each dust grain
    Md = c.intz( a_cm, Dist_WD01 * mg )

    result.nd = Dist_WD01 * c.micron2cm()  # cm^-3 per um per n_H
    result.md = Md

    return result
Beispiel #18
0
def UniformISM( halo, NH=1.0e20, d2g=0.009, nx=1000, usepathdiff=False ):
    """
    Calculate the X-ray scattering intensity for dust distributed
    uniformly along the line of sight
    
    | **MODIFIES**
    | halo.htype, halo.dist, halo.taux, halo.intensity
    
    | **INPUTS**
    | halo : Halo object
    | NH   : float : column density [cm^-2]
    | d2g  : float : dust-to-gass mass ratio
    | nx   : int : number of values to use in integration
    | usepathdiff : boolean : True = use extinction due to path difference e^(-tau*path_diff)
    """
    E0    = halo.energy
    alpha = halo.alpha
    scatm = halo.scatm
    md    = NH * c.m_p * d2g

    halo.htype = GalHalo( NH=NH, d2g=d2g, ismtype='Uniform' )
    halo.dist  = dust.Dustspectrum( rad=halo.rad, md=md )
    halo.taux  = ss.Kappascat( E=halo.energy, scatm=halo.scatm, dist=halo.dist ).kappa * md

    dx    = 1.0 / nx
    xvals = np.arange( 0.0, 1.0, dx ) + dx

    #--- Single grain case ---

    if type( halo.rad ) == dust.Grain:

        intensity = np.array([])
        for al in alpha:
            thscat = al / xvals  # np.size(thscat) = nx
            dsig   = ss.Diffscat( theta=thscat, a=halo.dist.a, E=E0, scatm=scatm ).dsig

            delta_tau = 0.0
            if usepathdiff:
                print('Using path difference')
                delta_x   = path_diff( al, xvals )
                delta_tau = halo.taux * delta_x
                print(np.max( delta_x ))

            itemp  = np.power( xvals, -2.0 ) * dsig * halo.dist.nd * np.exp( -delta_tau )
            intensity = np.append( intensity, c.intz( xvals, itemp ) )

    #--- Dust distribution case ---

    elif type( halo.rad ) == dust.Dustdist:

        avals     = halo.dist.a
        intensity = np.array([])

        for al in alpha:
            thscat = al / xvals  # np.size(thscat) = nx
            iatemp    = np.array([])
            for aa in avals:
                dsig  = ss.Diffscat( theta=thscat, a=aa, E=E0, scatm=scatm ).dsig

                delta_tau = 0.0
                if usepathdiff:
                    print('Using path difference')
                    delta_x   = path_diff( al, xvals )
                    delta_tau = halo.taux * delta_x
                    print(max( delta_x ))

                dtemp  = np.power( xvals, -2.0 ) * dsig * np.exp( -delta_tau )
                iatemp = np.append( iatemp, c.intz( xvals, dtemp ) )

            intensity = np.append( intensity, c.intz( avals, halo.dist.nd * iatemp ) )

    else:
        print('%% Must input type dust.Grain or dust.Dustdist')
        intensity = np.zeros( np.size(xvals) )
        
    # Set the halo intensity

    halo.intensity  = intensity * np.power( c.arcs2rad, 2 )  # arcsec^-2