コード例 #1
0
from hyperion.model import AnalyticalYSOModel
from hyperion.util.constants import au, lsun, rsun, tsun, msun

# Initialize model
m = AnalyticalYSOModel()

# Set up star
m.star.radius = 1.5 * rsun
m.star.temperature = tsun
m.star.luminosity = lsun

# Set up disk
d = m.add_flared_disk()
d.rmin = 10 * rsun
d.rmax = 30. * au
d.mass = 0.01 * msun
d.p = -1
d.beta = 1.25
d.r_0 = 10. * au
d.h_0 = 0.4 * au
d.dust = 'kmh_lite.hdf5'

# Set up grid
m.set_spherical_polar_grid_auto(400, 100, 1)

# Don't compute temperatures
m.set_n_initial_iterations(0)

# Don't re-emit photons
m.set_kill_on_absorb(True)
コード例 #2
0
ファイル: hyperion_ulrich.py プロジェクト: yaolun/misc
# Variable setup
#
rstar = 5 * RS
tstar = 4500
R_env_max = 1.000000e+04 * AU
R_env_min = 8.000000e-01 * AU
R_cen = 1.500000e+01 * AU
theta_cav = 0.0  # no cavity
M_env_dot = 3.000000e-05 * MS / yr
mstar = 9.844506e-01 * MS
rin = rstar
rout = R_env_max
rcen = R_cen

m = AnalyticalYSOModel()

# Define the luminsoity source
source = m.add_spherical_source()
source.luminosity = (4 * PI * rstar**2) * sigma * (tstar**4)  # [ergs/s]
source.radius = rstar  # [cm]
source.temperature = tstar  # [K]
source.position = (0., 0., 0.)
source.mass = mstar
print 'L_center =  % 5.2f L_sun' % ((4 * PI * rstar**2) * sigma *
                                    (tstar**4) / LS)

# Envelope structure
#
envelope = m.add_ulrich_envelope()
envelope.mdot = M_env_dot  # Infall rate
コード例 #3
0
ファイル: setup_model_ext.py プロジェクト: yaolun/misc
def setup_model(outdir,record_dir,outname,params,dust_file,tsc=True,idl=False,plot=False,\
                low_res=True,flat=True,scale=1,radmc=False,mono=False,mono_wave=None,
                record=True,dstar=200.,aperture=None,dyn_cav=False,fix_params=None,
                power=2,better_im=False,ellipsoid=False,TSC_dir='~/programs/misc/TSC/',
                IDL_path='/Applications/exelis/idl83/bin/idl',auto_disk=0.25,fast_plot=False,
                image_only=False, tsc_com=False, ext_source=None):
    """
    params = dictionary of the model parameters
    'alma' keyword is obsoleted
    outdir: The directory for storing Hyperion input files
    record_dir: The directory contains "model_list.txt" for recording parameters
    TSC_dir: Path the TSC-related IDL routines
    IDL_path: The IDL executable
    fast_plot: Do not plot the polar plot of the density because the rendering
               takes quite a lot of time.
    mono: monochromatic radiative transfer mode (need to specify the wavelength
          or a list of wavelength with 'mono_wave')
    image_only: only run for images
    """
    import numpy as np
    import astropy.constants as const
    from astropy.io import ascii
    import scipy as sci
    # to avoid X server error
    import matplotlib as mpl
    mpl.use('Agg')
    #
    import matplotlib.pyplot as plt
    import os
    from matplotlib.colors import LogNorm
    from scipy.integrate import nquad
    from hyperion.model import Model
    from record_hyperion import record_hyperion
    from outflow_inner_edge import outflow_inner_edge
    from pprint import pprint

    # Constants setup
    c         = const.c.cgs.value
    AU        = const.au.cgs.value     # Astronomical Unit       [cm]
    pc        = const.pc.cgs.value     # Parsec                  [cm]
    MS        = const.M_sun.cgs.value  # Solar mass              [g]
    LS        = const.L_sun.cgs.value  # Solar luminosity        [erg/s]
    RS        = const.R_sun.cgs.value  # Solar radius            [cm]
    G         = const.G.cgs.value      # Gravitational constant  [cm3/g/s^2]
    yr        = 60*60*24*365           # Years in seconds
    PI        = np.pi                  # PI constant
    sigma     = const.sigma_sb.cgs.value  # Stefan-Boltzmann constant
    mh        = const.m_p.cgs.value + const.m_e.cgs.value
    g2d       = 100.
    mmw       = 2.37                   # Kauffmann 2008

    m = Model()

    # min and max wavelength to compute (need to define them first for checking dust properties)
    # !!!
    wav_min = 2.0
    wav_max = 1400.
    wav_num = 1400

    # Create dust properties
    # Hyperion needs nu, albedo, chi, g, p_lin_max
    from hyperion.dust import HenyeyGreensteinDust
    # Read in the dust opacity table used by RADMC-3D
    dust = dict()
    [dust['nu'], dust['albedo'], dust['chi'], dust['g']] = np.genfromtxt(dust_file).T
    d = HenyeyGreensteinDust(dust['nu'], dust['albedo'], dust['chi'], dust['g'], dust['g']*0)
    # dust sublimation option
    d.set_sublimation_temperature('slow', temperature=1600.0)
    d.set_lte_emissivities(n_temp=3000,
                           temp_min=0.1,
                           temp_max=2000.)
    # if the min and/or max wavelength fall out of range
    if c/wav_min/1e-4 > dust['nu'].max():
        d.optical_properties.extrapolate_nu(dust['nu'].min(), c/wav_min/1e-4)
        print 'minimum wavelength is out of dust model.  The dust model is extrapolated.'
    if c/wav_max/1e-4 < dust['nu'].min():
        d.optical_properties.extrapolate_nu(c/wav_max/1e-4, dust['nu'].max())
        print 'maximum wavelength is out of dust model.  The dust model is extrapolated.'

    # try to solve the freq. problem
    d.optical_properties.extrapolate_nu(3.28e15, 5e15)
    #
    d.write(outdir+os.path.basename(dust_file).split('.')[0]+'.hdf5')
    d.plot(outdir+os.path.basename(dust_file).split('.')[0]+'.png')
    plt.clf()

    # Grids and Density

    # Grid Parameters
    nx        = 300L
    if low_res == True:
        nx    = 100L
    ny        = 400L
    nz        = 50L
    [nx, ny, nz] = [int(scale*nx), int(scale*ny), int(scale*nz)]

    # TSC model input setting
    dict_params = params
    # TSC model parameter
    cs        = dict_params['Cs']*1e5
    t         = dict_params['age']  # year
    omega     = dict_params['Omega0']
    # calculate related parameters
    M_env_dot = 0.975*cs**3/G
    mstar     = M_env_dot * t * yr
    R_cen     = omega**2 * G**3 * mstar**3 /(16*cs**8)
    R_inf     = cs * t * yr
    # protostar parameter
    tstar     = dict_params['tstar']
    R_env_max = dict_params['R_env_max']*AU
    theta_cav = dict_params['theta_cav']
    rho_cav_center = dict_params['rho_cav_center']
    rho_cav_edge   = dict_params['rho_cav_edge']*AU
    rstar     = dict_params['rstar']*RS
    # Mostly fixed parameter
    M_disk    = dict_params['M_disk']*MS
    beta      = dict_params['beta']
    h100      = dict_params['h100']*AU
    rho_cav   = dict_params['rho_cav']
    # make M_disk varies with mstar, which is the mass of star+disk
    if auto_disk != None:
        if M_disk != 0:
            print 'M_disk is reset to %4f of mstar (star+disk)' % auto_disk
            M_disk = mstar * auto_disk
        else:
            print 'M_disk = 0 is found.  M_disk is set to 0.'

    # ellipsoid cavity parameter
    if ellipsoid == True:
        # the numbers are given in arcsec
        a_out = 130 * dstar * AU
        b_out = 50  * dstar * AU
        z_out = a_out
        a_in  = dict_params['a_in'] * dstar * AU
        b_in  = a_in/a_out*b_out
        z_in  = a_in
        rho_cav_out = dict_params['rho_cav_out'] * mh
        rho_cav_in  = dict_params['rho_cav_in']  * mh
    # Calculate the dust sublimation radius
    T_sub = 1600
    a     = 1   # in micron
    # realistic dust
    # d_sub = 2.9388e7*(a/0.1)**-0.2 * (4*np.pi*rstar**2*sigma*tstar**4/LS)**0.5 / T_sub**3 *AU
    # black body dust
    d_sub = (LS/16./np.pi/sigma/AU**2*(4*np.pi*rstar**2*sigma*tstar**4/LS)/T_sub**4)**0.5 *AU
    # use the dust sublimation radius as the inner radius of disk and envelope
    R_disk_min = d_sub
    R_env_min  = d_sub
    rin        = rstar
    rout       = R_env_max
    R_disk_max = R_cen

    # print the variables
    print 'Dust sublimation radius %6f AU' % (d_sub/AU)
    print 'M_star %4f Solar mass' % (mstar/MS)
    print 'Infall radius %4f AU' % (R_inf / AU)

    # if there is any parameter found in fix_params, then fix them
    if fix_params != None:
        if 'R_min' in fix_params.keys():
            R_disk_min = fix_params['R_min']*AU
            R_env_min  = fix_params['R_min']*AU

    # Make the Coordinates
    #
    # if ext_source != None:
    #     rout = R_env_max*1.1
    ri           = rin * (rout/rin)**(np.arange(nx+1).astype(dtype='float')/float(nx))
    ri           = np.hstack((0.0, ri))
    thetai       = PI*np.arange(ny+1).astype(dtype='float')/float(ny)
    phii         = PI*2.0*np.arange(nz+1).astype(dtype='float')/float(nz)

    # Keep the constant cell size in r-direction at large radii
    #
    if flat == True:
        ri_cellsize = ri[1:-1]-ri[0:-2]
        ind = np.where(ri_cellsize/AU > 100.0)[0][0]       # The largest cell size is 100 AU
        ri = np.hstack((ri[0:ind],ri[ind]+np.arange(np.ceil((rout-ri[ind])/100/AU))*100*AU))
        nxx = nx
        nx = len(ri)-1
    # Assign the coordinates of the center of cell as its coordinates.
    #
    rc           = 0.5*( ri[0:nx]     + ri[1:nx+1] )
    thetac       = 0.5*( thetai[0:ny] + thetai[1:ny+1] )
    phic         = 0.5*( phii[0:nz]   + phii[1:nz+1] )

    # for non-TSC model
    if tsc_com:
        import hyperion as hp
        from hyperion.model import AnalyticalYSOModel

        non_tsc = AnalyticalYSOModel()

        # Define the luminsoity source
        nt_source = non_tsc.add_spherical_source()
        nt_source.luminosity = (4*PI*rstar**2)*sigma*(tstar**4)  # [ergs/s]
        nt_source.radius = rstar  # [cm]
        nt_source.temperature = tstar  # [K]
        nt_source.position = (0., 0., 0.)
        nt_source.mass = mstar

        # Envelope structure
        #
        nt_envelope = non_tsc.add_ulrich_envelope()
        nt_envelope.mdot = M_env_dot    # Infall rate
        nt_envelope.rmin = rin          # Inner radius
        nt_envelope.rc   = R_cen        # Centrifugal radius
        nt_envelope.rmax = R_env_max    # Outer radius
        nt_envelope.star = nt_source

        nt_grid = hp.grid.SphericalPolarGrid(ri, thetai, phii)

        rho_env_ulrich = nt_envelope.density(nt_grid).T
        rho_env_ulrich2d = np.sum(rho_env_ulrich**2,axis=2)/np.sum(rho_env_ulrich,axis=2)

    # Make the dust density model
    # Make the density profile of the envelope
    #
    total_mass = 0
    if tsc == False:
        print 'Calculating the dust density profile with infall solution...'
        if theta_cav != 0:
            # using R = 10000 AU as the reference point
            c0 = (10000.*AU)**(-0.5)*np.sqrt(1/np.sin(np.radians(theta_cav))**3-1/np.sin(np.radians(theta_cav)))
        else:
            c0 = 0
        rho_env  = np.zeros([len(rc),len(thetac),len(phic)])
        rho_disk = np.zeros([len(rc),len(thetac),len(phic)])
        rho      = np.zeros([len(rc),len(thetac),len(phic)])

        if dyn_cav == True:
            print 'WARNING: Calculation of interdependent cavity property has not implemented in infall-only solution!'
        # Normalization for the total disk mass
        def f(w,z,beta,rstar,h100):
            f = 2*PI*w*(1-np.sqrt(rstar/w))*(rstar/w)**(beta+1)*np.exp(-0.5*(z/(w**beta*h100/100**beta))**2)
            return f

        rho_0 = M_disk/(nquad(f,[[R_disk_min,R_disk_max],[-R_env_max,R_env_max]], args=(beta,rstar,h100)))[0]
        i = 0
        j = 0
        if 'rho_cav_center' in locals() == False:
            rho_cav_center = 5e-19
            print 'Use 5.27e-18 as the default value for cavity center'
        if 'rho_cav_edge' in locals() == False:
            rho_cav_edge = 40*AU
            print 'Use 40 AU as the default value for size of the inner region'
        discont = 1
        for ir in range(0,len(rc)):
            for itheta in range(0,len(thetac)):
                for iphi in range(0,len(phic)):
                    if rc[ir] > R_env_min:
                        # Envelope profile
                        w = abs(rc[ir]*np.cos(np.pi/2 - thetac[itheta]))
                        z = rc[ir]*np.sin(np.pi/2 - thetac[itheta])

                        if ellipsoid == False:
                            z_cav = c0*abs(w)**1.5
                            if z_cav == 0:
                                z_cav = R_env_max
                            cav_con = abs(z) > abs(z_cav)
                            if theta_cav == 90:
                                cav_con = True
                        else:
                            # condition for the outer ellipsoid
                            cav_con = (2*(w/b_out)**2 + ((abs(z)-z_out)/a_out)**2) < 1
                        if cav_con:
                            # open cavity
                            if ellipsoid == False:
                                if rho_cav_edge == 0:
                                    rho_cav_edge = R_env_min
                                if (rc[ir] <= rho_cav_edge) & (rc[ir] >= R_env_min):
                                    rho_env[ir,itheta,iphi] = g2d * rho_cav_center
                                else:
                                    rho_env[ir,itheta,iphi] = g2d * rho_cav_center*discont*(rho_cav_edge/rc[ir])**power
                                i += 1
                            else:
                                # condition for the inner ellipsoid
                                if (2*(w/b_in)**2 + ((abs(z)-z_in)/a_in)**2) > 1:
                                    rho_env[ir,itheta,iphi] = rho_cav_out
                                else:
                                    rho_env[ir,itheta,iphi] = rho_cav_in
                                i +=1
                        else:
                            j += 1
                            mu = abs(np.cos(thetac[itheta]))
                            # Implement new root finding algorithm
                            roots = np.roots(np.array([1.0, 0.0, rc[ir]/R_cen-1.0, -mu*rc[ir]/R_cen]))
                            if len(roots[roots.imag == 0]) == 1:
                                if (abs(roots[roots.imag == 0]) - 1.0) <= 0.0:
                                    mu_o_dum = roots[roots.imag == 0]
                                else:
                                    mu_o_dum = -0.5
                                    print 'Problem with cubic solving, cos(theta) = ', mu_o_dum
                                    print 'parameters are ', np.array([1.0, 0.0, rc[ir]/R_cen-1.0, -mu*rc[ir]/R_cen])
                            else:
                                mu_o_dum = -0.5
                                for imu in range(0, len(roots)):
                                    if roots[imu]*mu >= 0.0:
                                        if (abs((abs(roots[imu]) - 1.0)) <= 1e-5):
                                            mu_o_dum = 1.0 * np.sign(mu)
                                        else:
                                            mu_o_dum = roots[imu]
                                if mu_o_dum == -0.5:
                                    print 'Problem with cubic solving, roots are: ', roots
                            mu_o = mu_o_dum.real
                            rho_env[ir,itheta,iphi] = M_env_dot/(4*PI*(G*mstar*R_cen**3)**0.5)*(rc[ir]/R_cen)**(-3./2)*(1+mu/mu_o)**(-0.5)*(mu/mu_o+2*mu_o**2*R_cen/rc[ir])**(-1)
                        # Disk profile
                        if ((w >= R_disk_min) and (w <= R_disk_max)) == True:
                            h = ((w/(100*AU))**beta)*h100
                            rho_disk[ir,itheta,iphi] = rho_0*(1-np.sqrt(rstar/w))*(rstar/w)**(beta+1)*np.exp(-0.5*(z/h)**2)
                        # Combine envelope and disk
                        rho[ir,itheta,iphi] = rho_disk[ir,itheta,iphi] + rho_env[ir,itheta,iphi]
                    else:
                        rho[ir,itheta,iphi] = 1e-30
                    # add the dust mass into the total count
                    cell_mass = rho[ir, itheta, iphi] * (1/3.)*(ri[ir+1]**3 - ri[ir]**3) * (phii[iphi+1]-phii[iphi]) * -(np.cos(thetai[itheta+1])-np.cos(thetai[itheta]))
                    total_mass = total_mass + cell_mass

        rho_env  = rho_env  + 1e-40
        rho_disk = rho_disk + 1e-40
        rho      = rho      + 1e-40
    # TSC model
    else:
        print 'Calculating the dust density profile with TSC solution...'
        if theta_cav != 0:
            c0 = (1e4*AU)**(-0.5)*np.sqrt(1/np.sin(np.radians(theta_cav))**3-1/np.sin(np.radians(theta_cav)))
        else:
            c0 = 0
        # If needed, calculate the TSC model via IDL
        #
        if idl == True:
            print 'Using IDL to calculate the TSC model.  Make sure you are running this on mechine with IDL.'
            import pidly
            idl = pidly.IDL(IDL_path)
            idl('.r '+TSC_dir+'tsc.pro')
            idl('.r '+TSC_dir+'tsc_run.pro')
            #
            # only run TSC calculation within infall radius
            # modify the rc array
            ind_infall = np.where(rc >= R_inf)[0][0]
            if max(ri) > R_inf:
                rc_idl = rc[0:ind_infall+1]
            else:
                rc_idl = rc[rc < max(ri)]
            idl.pro('tsc_run', indir=TSC_dir, outdir=outdir, rc=rc_idl, thetac=thetac, time=t,
                    c_s=cs, omega=omega, renv_min=R_env_min)
            file_idl = 'rhoenv.dat'
        else:
            print 'Read the pre-computed TSC model.'
            ind_infall = np.where(rc >= R_inf)[0][0]
            if max(ri) > R_inf:
                rc_idl = rc[0:ind_infall+1]
            else:
                rc_idl = rc[rc < max(ri)]
            if idl != False:
                file_idl = idl

        # read in the exist file
        rho_env_tsc_idl = np.genfromtxt(outdir+file_idl).T
        # because only region within infall radius is calculated by IDL program,
        # need to project it to the original grid
        rho_env_tsc = np.zeros([len(rc), len(thetac)])
        for irc in range(len(rc)):
            if rc[irc] in rc_idl:
                rho_env_tsc[irc,:] = rho_env_tsc_idl[np.squeeze(np.where(rc_idl == rc[irc])),:]

        # extrapolate for the NaN values at the outer radius, usually at radius beyond the infall radius
        # using r^-2 profile at radius greater than infall radius
        # and map the 2d strcuture onto 3-D grid
        # map TSC solution from IDL to actual 2-D grid
        rho_env_tsc2d = np.empty((nx,ny))
        if max(ri) > R_inf:
            for i in range(0, len(rc)):
                if i <= ind_infall:
                    rho_env_tsc2d[i,:] = rho_env_tsc[i,:]
                else:
                    rho_env_tsc2d[i,:] =  10**(np.log10(rho_env_tsc[ind_infall,:]) - 2*(np.log10(rc[i]/rc[ind_infall])))
        else:
            rho_env_tsc2d = rho_env_tsc
        # map it to 3-D grid
        rho_env = np.empty((nx,ny,nz))
        for i in range(0, nz):
            rho_env[:,:,i] = rho_env_tsc2d

        # typical no used.  Just an approach I tried to make the size of the
        # constant desnity region self-consistent with the outflow cavity.
        if dyn_cav == True:
            print 'Calculate the cavity properties using the criteria that swept-up mass = outflowed mass'
            # using swept-up mass = flow mass to derive the edge of the extended flat density region
            v_outflow = 1e2 * 1e5
            rho_cav_edge = outflow_inner_edge(np.copy(rho_env), (ri,thetai,phii),M_env_dot,v_outflow,theta_cav, R_env_min)
            dict_params['rho_cav_edge'] = rho_cav_edge
            # assume gas-to-dust ratio = 100
            rho_cav_center = 0.01 * 0.1*M_env_dot*rho_cav_edge/v_outflow/2 / (2*np.pi/3*rho_cav_edge**3*(1-np.cos(np.radians(theta_cav))))
            dict_params['rho_cav_center'] = rho_cav_center
            print 'inner edge is %5f AU and density is %e g/cm3' % (rho_cav_edge/AU, rho_cav_center)

        # create the array of density of disk and the whole structure
        #
        rho_disk = np.zeros([len(rc),len(thetac),len(phic)])
        rho      = np.zeros([len(rc),len(thetac),len(phic)])

        # non-TSC option
        if tsc_com:
            rho_ulrich = np.zeros([len(rc),len(thetac),len(phic)])

        # Calculate the disk scale height by the normalization of h100
        def f(w,z,beta,rstar,h100):
            f = 2*PI*w*(1-np.sqrt(rstar/w))*(rstar/w)**(beta+1)*np.exp(-0.5*(z/(w**beta*h100/100**beta))**2)
            return f
        # The function for calculating the normalization of disk using the total disk mass
        #
        rho_0 = M_disk/(nquad(f,[[R_disk_min,R_disk_max],[-R_env_max,R_env_max]], args=(beta,rstar,h100)))[0]
        i = 0
        j = 0

        # put in default outflow cavity setting if nothing is specified
        if 'rho_cav_center' in locals() == False:
            rho_cav_center = 5e-19
            print 'Use 5e-19 as the default value for cavity center'
        if 'rho_cav_edge' in locals() == False:
            rho_cav_edge = 40*AU
            print 'Use 40 AU as the default value for size of the inner region'
        discont = 1
        for ir in range(0,len(rc)):
            for itheta in range(0,len(thetac)):
                for iphi in range(0,len(phic)):
                    # for external heating option
                    if (rc[ir] > R_env_min):
                        # Envelope profile
                        w = abs(rc[ir]*np.cos(np.pi/2 - thetac[itheta]))
                        z = rc[ir]*np.sin(np.pi/2 - thetac[itheta])

                        if ellipsoid == False:
                            z_cav = c0*abs(w)**1.5
                            if z_cav == 0:
                                z_cav = R_env_max
                            cav_con = abs(z) > abs(z_cav)
                        else:
                            # condition for the outer ellipsoid
                            cav_con = (2*(w/b_out)**2 + ((abs(z)-z_out)/a_out)**2) < 1
                        if cav_con:
                            # open cavity
                            if ellipsoid == False:
                                if rho_cav_edge == 0:
                                    rho_cav_edge = R_env_min
                                if (rc[ir] <= rho_cav_edge) & (rc[ir] >= R_env_min):
                                    rho_env[ir,itheta,iphi] = g2d * rho_cav_center#*((rc[ir]/AU)**2)
                                    if tsc_com:
                                        rho_env_ulrich[ir,itheta,iphi] = rho_env[ir,itheta,iphi]
                                else:
                                    rho_env[ir,itheta,iphi] = g2d * rho_cav_center*discont*(rho_cav_edge/rc[ir])**power
                                    if tsc_com:
                                        rho_env_ulrich[ir,itheta,iphi] = rho_env[ir,itheta,iphi]
                                i += 1
                            else:
                                # condition for the inner ellipsoid
                                if (2*(w/b_in)**2 + ((abs(z)-z_in)/a_in)**2) > 1:
                                    rho_env[ir,itheta,iphi] = rho_cav_out
                                    if tsc_com:
                                        rho_env_ulrich[ir,itheta,iphi] = rho_env[ir,itheta,iphi]
                                else:
                                    rho_env[ir,itheta,iphi] = rho_cav_in
                                    if tsc_com:
                                        rho_env_ulrich[ir,itheta,iphi] = rho_env[ir,itheta,iphi]
                                i +=1

                        # Disk profile
                        if ((w >= R_disk_min) and (w <= R_disk_max)) == True:
                            h = ((w/(100*AU))**beta)*h100
                            rho_disk[ir,itheta,iphi] = rho_0*(1-np.sqrt(rstar/w))*(rstar/w)**(beta+1)*np.exp(-0.5*(z/h)**2)
                        # Combine envelope and disk
                        rho[ir,itheta,iphi] = rho_disk[ir,itheta,iphi] + rho_env[ir,itheta,iphi]
                        if tsc_com:
                            rho_ulrich[ir,itheta,iphi] = rho_disk[ir,itheta,iphi] + rho_env_ulrich[ir,itheta,iphi]
                    else:
                        rho[ir,itheta,iphi] = 1e-40
                        if tsc_com:
                            rho[ir,itheta,iphi] = 1e-40
                    # add the dust mass into the total count
                    cell_mass = rho[ir, itheta, iphi] * (1/3.)*(ri[ir+1]**3 - ri[ir]**3) * (phii[iphi+1]-phii[iphi]) * -(np.cos(thetai[itheta+1])-np.cos(thetai[itheta]))
                    total_mass = total_mass + cell_mass
    # apply gas-to-dust ratio of 100
    rho_dust = rho/g2d
    if tsc_com:
        rho_ulrich_dust = rho_ulrich/g2d
    total_mass_dust = total_mass/MS/g2d
    print 'Total dust mass = %f Solar mass' % total_mass_dust

    if record == True:
        # Record the input and calculated parameters
        params = dict_params.copy()
        params.update({'d_sub': d_sub/AU, 'M_env_dot': M_env_dot/MS*yr, 'R_inf': R_inf/AU, 'R_cen': R_cen/AU, 'mstar': mstar/MS, 'M_tot_gas': total_mass/MS})
        record_hyperion(params,record_dir)

    if plot == True:
        # rho2d is the 2-D projection of gas density
        # take the weighted average
        rho2d = np.sum(rho**2,axis=2)/np.sum(rho,axis=2)

        if tsc_com:
            rho2d = np.sum(rho_ulrich**2,axis=2)/np.sum(rho_ulrich,axis=2)

        if fast_plot == False:
            # Plot the azimuthal averaged density
            fig = plt.figure(figsize=(8,6))
            ax_env  = fig.add_subplot(111,projection='polar')

            zmin = 1e-22/mmw/mh
            zmin = 1e-1
            cmap = plt.cm.CMRmap
            rho2d_exp = np.hstack((rho2d,rho2d,rho2d[:,0:1]))
            thetac_exp = np.hstack((thetac-PI/2, thetac+PI/2, thetac[0]-PI/2))
            # plot the gas density
            img_env = ax_env.pcolormesh(thetac_exp,rc/AU,rho2d_exp/mmw/mh,cmap=cmap,norm=LogNorm(vmin=zmin,vmax=1e6)) # np.nanmax(rho2d_exp/mmw/mh)

            ax_env.set_xlabel(r'$\rm{Polar\,angle\,(Degree)}$',fontsize=20)
            ax_env.set_ylabel('',fontsize=20, labelpad=-140)
            ax_env.tick_params(labelsize=18)
            ax_env.set_yticks(np.hstack((np.arange(0,(int(R_env_max/AU/10000.)+1)*10000, 10000),R_env_max/AU)))
            ax_env.set_xticklabels([r'$\rm{90^{\circ}}$',r'$\rm{45^{\circ}}$',r'$\rm{0^{\circ}}$',r'$\rm{-45^{\circ}}$',\
                                    r'$\rm{-90^{\circ}}$',r'$\rm{-135^{\circ}}$',r'$\rm{180^{\circ}}$',r'$\rm{135^{\circ}}$'])
            ax_env.set_yticklabels([])
            # fix the tick label font
            ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',size=20)
            for label in ax_env.get_yticklabels():
                label.set_fontproperties(ticks_font)

            ax_env.grid(True, color='LightGray', linewidth=1)
            cb = fig.colorbar(img_env, pad=0.1)
            cb.ax.set_ylabel(r'$\rm{Averaged\,Gas\,Density\,(cm^{-3})}$',fontsize=20)
            # cb.set_ticks([1e2,1e3,1e4,1e5,1e6,1e7,1e8,1e9])
            # cb.set_ticklabels([r'$\rm{10^{2}}$',r'$\rm{10^{3}}$',r'$\rm{10^{4}}$',r'$\rm{10^{5}}$',r'$\rm{10^{6}}$',\
            #                    r'$\rm{10^{7}}$',r'$\rm{10^{8}}$',r'$\rm{\geq 10^{9}}$'])
            # lower density ticks
            cb.set_ticks([1e-1,1e0,1e1,1e2,1e3,1e4,1e5,1e6])
            cb.set_ticklabels([r'$\rm{10^{-1}}$',r'$\rm{10^{0}}$',r'$\rm{10^{1}}$',r'$\rm{10^{2}}$',r'$\rm{10^{3}}$',
                               r'$\rm{10^{4}}$',r'$\rm{10^{5}}$',r'$\rm{\geq 10^{6}}$'])

            cb_obj = plt.getp(cb.ax.axes, 'yticklabels')
            plt.setp(cb_obj,fontsize=20)
            fig.savefig(outdir+outname+'_gas_density.png', format='png', dpi=300, bbox_inches='tight')
            fig.clf()

        # Plot the radial density profile
        fig = plt.figure(figsize=(12,9))
        ax = fig.add_subplot(111)

        plot_grid = [0,49,99,149,199]
        color_grid = ['#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00']
        label = [r'$\rm{\theta='+str(int(np.degrees(thetai[plot_grid[0]])))+'^{\circ}}$',\
                 r'$\rm{\theta='+str(int(np.degrees(thetai[plot_grid[1]])))+'^{\circ}}$',\
                 r'$\rm{\theta='+str(1+int(np.degrees(thetai[plot_grid[2]])))+'^{\circ}}$',\
                 r'$\rm{\theta='+str(int(np.degrees(thetai[plot_grid[3]])))+'^{\circ}}$',\
                 r'$\rm{\theta='+str(1+int(np.degrees(thetai[plot_grid[4]])))+'^{\circ}}$']
        alpha = np.linspace(0.3,1.0,len(plot_grid))
        for i in plot_grid:
            ax.plot(np.log10(rc[rc > 0.14*AU]/AU), np.log10(rho2d[rc > 0.14*AU,i]/g2d/mmw/mh)+plot_grid[::-1].index(i)*-0.2,'-',color=color_grid[plot_grid.index(i)],mec='None',linewidth=2.5, \
                    markersize=3, label=label[plot_grid.index(i)]) # alpha=alpha[plot_grid.index(i)],
        ax.axvline(np.log10(R_inf/AU), linestyle='--', color='k', linewidth=1.5, label=r'$\rm{infall\,radius}$')
        ax.axvline(np.log10(R_cen/AU), linestyle=':', color='k', linewidth=1.5, label=r'$\rm{centrifugal\,radius}$')

        lg = plt.legend(fontsize=20, numpoints=1, ncol=2, framealpha=0.7, loc='upper right')

        ax.set_xlabel(r'$\rm{log(Radius)\,(AU)}$',fontsize=20)
        ax.set_ylabel(r'$\rm{log(Dust\,Density)\,(cm^{-3})}$',fontsize=20)
        [ax.spines[axis].set_linewidth(1.5) for axis in ['top','bottom','left','right']]
        ax.minorticks_on()
        ax.tick_params('both',labelsize=18,width=1.5,which='major',pad=15,length=5)
        ax.tick_params('both',labelsize=18,width=1.5,which='minor',pad=15,length=2.5)

        # fix the tick label font
        ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',size=18)
        for label in ax.get_xticklabels():
            label.set_fontproperties(ticks_font)
        for label in ax.get_yticklabels():
            label.set_fontproperties(ticks_font)

        ax.set_ylim([0,11])
        fig.gca().set_xlim(left=np.log10(0.05))
        fig.savefig(outdir+outname+'_gas_radial.pdf',format='pdf',dpi=300,bbox_inches='tight')
        fig.clf()

    # Insert the calculated grid and dust density profile into hyperion
    m.set_spherical_polar_grid(ri, thetai, phii)

    m.add_density_grid(rho_dust.T, d)
    # for non-TSC option
    if tsc_com:
        m.add_density_grid(rho_ulrich_dust.T, d)

    # Define the luminsoity source
    source = m.add_spherical_source()
    source.luminosity = (4*PI*rstar**2)*sigma*(tstar**4)  # [ergs/s]
    source.radius = rstar  # [cm]
    source.temperature = tstar  # [K]
    source.position = (0., 0., 0.)
    print 'L_center =  % 5.2f L_sun' % ((4*PI*rstar**2)*sigma*(tstar**4)/LS)

    # if ext_source != None:
    #     # add external heating - ISRF
    #     # use standard receipe from Hyperion doc
    #     isrf = ascii.read(ext_source, names=['wavelength', 'J_lambda'])
    #     isrf_nu = c/(isrf['wavelength']*1e-4)
    #     isrf_jnu = isrf['J_lambda']*isrf['wavelength']/isrf_nu
    #
    #     if 'mmp83' in ext_source:
    #         FOUR_PI_JNU = 0.0217
    #     else:
    #         FOUR_PI_JNU = raw_input('What is the FOUR_PI_JNU value?')
    #
    #     s_isrf = m.add_external_spherical_source()
    #     s_isrf.radius = R_env_max
    #     s_isrf.spectrum = (isrf_nu, isrf_jnu)
    #     s_isrf.luminosity = PI * R_env_max**2 * FOUR_PI_JNU

    m.set_raytracing(True)
    # option of using more photons for imaging
    if better_im == False:
        im_photon = 1e6
    else:
        im_photon = 5e7

    if mono == True:
        if (type(mono_wave) == int) or (type(mono_wave) == float) or (type(mono_wave) == str):
            mono_wave = float(mono_wave)
            mono_wave = [mono_wave]

        # Monochromatic radiative transfer setting
        m.set_monochromatic(True, wavelengths=mono_wave)
        m.set_n_photons(initial=1e6, imaging_sources=im_photon,
            imaging_dust=im_photon,raytracing_sources=1e6, raytracing_dust=1e6)
    else:
        # regular wavelength grid setting
        m.set_n_photons(initial=1e6, imaging=im_photon,raytracing_sources=1e6,
                        raytracing_dust=1e6)
    # number of iteration to compute dust specific energy (temperature)
    m.set_n_initial_iterations(20)
    m.set_convergence(True, percentile=dict_params['percentile'],
                            absolute=dict_params['absolute'],
                            relative=dict_params['relative'])
    m.set_mrw(True)   # Gamma = 1 by default

    # Setting up images and SEDs
    if not image_only:
        # SED setting
        # Infinite aperture
        syn_inf = m.add_peeled_images(image=False)
        # use the index of wavelength array used by the monochromatic radiative transfer
        if mono == False:
            syn_inf.set_wavelength_range(wav_num, wav_min, wav_max)
        syn_inf.set_viewing_angles([dict_params['view_angle']], [0.0])
        syn_inf.set_uncertainties(True)
        syn_inf.set_output_bytes(8)

        # aperture
        # 7.2 in 10 um scaled by lambda / 10
        # flatten beyond 20 um
        # default aperture (should always specify a set of apertures)
        if aperture == None:
            aperture = {'wave': [3.6, 4.5, 5.8, 8.0, 8.5, 9, 9.7, 10, 10.5, 11, 16, 20, 24, 30, 70, 100, 160, 250, 350, 500, 1300],\
                        'aperture': [7.2, 7.2, 7.2, 7.2, 7.2, 7.2, 7.2, 7.2, 7.2, 7.2, 20.4, 20.4, 20.4, 20.4, 24.5, 24.5, 24.5, 24.5, 24.5, 24.5, 101]}
        # assign wl_aper and aper from dictionary of aperture
        wl_aper = aperture['wave']
        aper    = aperture['aperture']
        # create the non-repetitive aperture list and index array
        aper_reduced = list(set(aper))
        index_reduced = np.arange(1, len(aper_reduced)+1)

        dict_peel_sed = {}
        for i in range(0, len(aper_reduced)):
            aper_dum = aper_reduced[i]/2 * (1/3600.*np.pi/180.)*dstar*pc
            dict_peel_sed[str(index_reduced[i])] = m.add_peeled_images(image=False)
            # use the index of wavelength array used by the monochromatic radiative transfer
            if mono == False:
                dict_peel_sed[str(index_reduced[i])].set_wavelength_range(wav_num, wav_min, wav_max)
            dict_peel_sed[str(index_reduced[i])].set_viewing_angles([dict_params['view_angle']], [0.0])
            # aperture should be given in cm and its the radius of the aperture
            dict_peel_sed[str(index_reduced[i])].set_aperture_range(1, aper_dum, aper_dum)
            dict_peel_sed[str(index_reduced[i])].set_uncertainties(True)
            dict_peel_sed[str(index_reduced[i])].set_output_bytes(8)

    # image setting
    syn_im = m.add_peeled_images(sed=False)
    # use the index of wavelength array used by the monochromatic radiative transfer
    if mono == False:
        syn_im.set_wavelength_range(wav_num, wav_min, wav_max)
    # pixel number
    # !!!
    if not mono:
        pix_num = 300
    else:
        pix_num = 8000
    #
    syn_im.set_image_size(pix_num, pix_num)
    syn_im.set_image_limits(-R_env_max, R_env_max, -R_env_max, R_env_max)
    syn_im.set_viewing_angles([dict_params['view_angle']], [0.0])
    syn_im.set_uncertainties(True)
    syn_im.set_output_bytes(8)

    # Output setting
    # Density
    m.conf.output.output_density = 'last'

    # Density difference (shows where dust was destroyed)
    m.conf.output.output_density_diff = 'none'

    # Energy absorbed (using pathlengths)
    m.conf.output.output_specific_energy = 'last'

    # Number of unique photons that passed through the cell
    m.conf.output.output_n_photons = 'last'

    m.write(outdir+outname+'.rtin')

    if radmc == True:
        # RADMC-3D still use a pre-defined aperture with lazy for-loop
        aper = np.zeros([len(lam)])
        ind = 0
        for wl in lam:
            if wl < 5:
                aper[ind] = 8.4
            elif wl >= 5 and wl < 14:
                aper[ind] = 1.8 * 4
            elif wl >= 14 and wl < 40:
                aper[ind] = 5.1 * 4
            else:
                aper[ind] = 24.5
            ind += 1

        # Write the wavelength_micron.inp file
        #
        f_wave = open(outdir+'wavelength_micron.inp','w')
        f_wave.write('%d \n' % int(nlam))
        for ilam in range(0,nlam):
            f_wave.write('%f \n' % lam[ilam])
        f_wave.close()

        # Write the camera_wavelength_micron.inp file
        #
        f_wave_cam = open(outdir+'camera_wavelength_micron.inp','w')
        f_wave_cam.write('%d \n' % int(nlam))
        for ilam in range(0,nlam):
            f_wave_cam.write('%f \n' % lam[ilam])
        f_wave_cam.close()

        # Write the aperture_info.inp
        #
        f_aper = open(outdir+'aperture_info.inp','w')
        f_aper.write('1 \n')
        f_aper.write('%d \n' % int(nlam))
        for iaper in range(0, len(aper)):
            f_aper.write('%f \t %f \n' % (lam[iaper],aper[iaper]/2))
        f_aper.close()

        # Write the stars.inp file
        #
        f_star = open(outdir+'stars.inp','w')
        f_star.write('2\n')
        f_star.write('1 \t %d \n' % int(nlam))
        f_star.write('\n')
        f_star.write('%e \t %e \t %e \t %e \t %e \n' % (rstar*0.9999,mstar,0,0,0))
        f_star.write('\n')
        for ilam in range(0,nlam):
            f_star.write('%f \n' % lam[ilam])
        f_star.write('\n')
        f_star.write('%f \n' % -tstar)
        f_star.close()

        # Write the grid file
        #
        f_grid = open(outdir+'amr_grid.inp','w')
        f_grid.write('1\n')                               # iformat
        f_grid.write('0\n')                               # AMR grid style  (0=regular grid, no AMR)
        f_grid.write('150\n')                             # Coordinate system  coordsystem<100: Cartisian; 100<=coordsystem<200: Spherical; 200<=coordsystem<300: Cylindrical
        f_grid.write('0\n')                               # gridinfo
        f_grid.write('1 \t 1 \t 1 \n')                    # Include x,y,z coordinate
        f_grid.write('%d \t %d \t %d \n' % (int(nx)-1,int(ny),int(nz)))    # Size of the grid
        [f_grid.write('%e \n' % ri[ir]) for ir in range(1,len(ri))]
        [f_grid.write('%f \n' % thetai[itheta]) for itheta in range(0,len(thetai))]
        [f_grid.write('%f \n' % phii[iphi]) for iphi in range(0,len(phii))]
        f_grid.close()

        # Write the density file
        #
        f_dust = open(outdir+'dust_density.inp','w')
        f_dust.write('1 \n')                      # format number
        f_dust.write('%d \n' % int((nx-1)*ny*nz)) # Nr of cells
        f_dust.write('1 \n')                      # Nr of dust species
        for iphi in range(0,len(phic)):
            for itheta in range(0,len(thetac)):
                for ir in range(1,len(rc)):
                    f_dust.write('%e \n' % rho_dust[ir,itheta,iphi])
        f_dust.close()

        # Write the dust opacity table
        f_dustkappa = open(outdir+'dustkappa_oh5_extended.inp','w')
        f_dustkappa.write('3 \n')                       # format index for including g-factor
        f_dustkappa.write('%d \n' % len(dust['nu']))    # number of wavlength/frequency in the table
        for i in range(len(dust['nu'])):
            f_dustkappa.write('%f \t %f \t %f \t %f \n' % (c/dust['nu'][i]*1e4, dust['chi'][i], dust['chi'][i]*dust['albedo'][i]/(1-dust['albedo'][i]), dust['g'][i]))
        f_dustkappa.close()

        # Write the Dust opacity control file
        #
        f_opac = open(outdir+'dustopac.inp','w')
        f_opac.write('2               Format number of this file\n')
        f_opac.write('1               Nr of dust species\n')
        f_opac.write('============================================================================\n')
        f_opac.write('1               Way in which this dust species is read\n')
        f_opac.write('0               0=Thermal grain\n')
        # f_opac.write('klaus           Extension of name of dustkappa_***.inp file\n')
        f_opac.write('oh5_extended    Extension of name of dustkappa_***.inp file\n')
        f_opac.write('----------------------------------------------------------------------------\n')
        f_opac.close()

        # Write the radmc3d.inp control file
        #
        f_control = open(outdir+'radmc3d.inp','w')
        f_control.write('nphot = %d \n' % 100000)
        f_control.write('scattering_mode_max = 2\n')
        f_control.write('camera_min_drr = 0.1\n')
        f_control.write('camera_min_dangle = 0.1\n')
        f_control.write('camera_spher_cavity_relres = 0.1\n')
        f_control.write('istar_sphere = 1\n')
        f_control.write('modified_random_walk = 1\n')
        f_control.close()

    return m
コード例 #4
0
ファイル: setup_model_v2.py プロジェクト: yaolun/misc
def setup_model(outdir, record_dir, outname, params, dust_file, wav_range, aperture,
                tsc=True, idl=False, plot=False, low_res=True, max_rCell=100,
                scale=1, radmc=False, mono_wave=None, norecord=False,
                dstar=200., dyn_cav=False, fix_params=None,
                power=2, mc_photons=1e6, im_photons=1e6, ellipsoid=False,
                TSC_dir='~/programs/misc/TSC/',
                IDL_path='/Applications/exelis/idl83/bin/idl', auto_disk=0.25,
                fast_plot=False, image_only=False, ulrich=False):
    """
    params = dictionary of the model parameters
    'alma' keyword is obsoleted
    outdir: The directory for storing Hyperion input files
    record_dir: The directory contains "model_list.txt" for recording parameters
    TSC_dir: Path the TSC-related IDL routines
    IDL_path: The IDL executable
    fast_plot: Do not plot the polar plot of the density because the rendering
               takes quite a lot of time.
    mono: monochromatic radiative transfer mode (need to specify the wavelength
          or a list of wavelength with 'mono_wave')
    image_only: only run for images
    """
    import numpy as np
    import astropy.constants as const
    import scipy as sci
    # to avoid X server error
    import matplotlib as mpl
    mpl.use('Agg')
    #
    import matplotlib.pyplot as plt
    import os
    from matplotlib.colors import LogNorm
    from scipy.integrate import nquad
    from hyperion.model import Model
    from record_hyperion import record_hyperion
    from pprint import pprint

    # Constants setup
    c         = const.c.cgs.value
    AU        = const.au.cgs.value     # Astronomical Unit       [cm]
    pc        = const.pc.cgs.value     # Parsec                  [cm]
    MS        = const.M_sun.cgs.value  # Solar mass              [g]
    LS        = const.L_sun.cgs.value  # Solar luminosity        [erg/s]
    RS        = const.R_sun.cgs.value  # Solar radius            [cm]
    G         = const.G.cgs.value      # Gravitational constant  [cm3/g/s^2]
    yr        = 60*60*24*365           # Years in seconds
    PI        = np.pi                  # PI constant
    sigma     = const.sigma_sb.cgs.value  # Stefan-Boltzmann constant
    mh        = const.m_p.cgs.value + const.m_e.cgs.value
    g2d       = 100.
    mmw       = 2.37                   # Kauffmann 2008

    m = Model()

    # min and max wavelength to compute (need to define them first for checking dust properties)
    wav_min, wav_max, wav_num = wav_range

    # Create dust properties
    # Hyperion needs nu, albedo, chi, g, p_lin_max
    from hyperion.dust import HenyeyGreensteinDust
    dust = dict()
    [dust['nu'], dust['albedo'], dust['chi'], dust['g']] = np.genfromtxt(dust_file).T
    d = HenyeyGreensteinDust(dust['nu'], dust['albedo'], dust['chi'], dust['g'], dust['g']*0)
    # dust sublimation option
    # dust sublimation temperture specified here
    T_sub = 1600.0
    d.set_sublimation_temperature('slow', temperature=T_sub)
    d.set_lte_emissivities(n_temp=3000,
                           temp_min=0.1,
                           temp_max=2000.)
    # if the min and/or max wavelength fall out of range
    if c/wav_min/1e-4 > dust['nu'].max():
        d.optical_properties.extrapolate_nu(dust['nu'].min(), c/wav_min/1e-4)
        print('minimum wavelength is out of dust model.  The dust model is extrapolated.')
    if c/wav_max/1e-4 < dust['nu'].min():
        d.optical_properties.extrapolate_nu(c/wav_max/1e-4, dust['nu'].max())
        print('maximum wavelength is out of dust model.  The dust model is extrapolated.')

    # try to solve the freq. problem
    d.optical_properties.extrapolate_nu(3.28e15, 5e15)
    #
    d.write(outdir+os.path.basename(dust_file).split('.')[0]+'.hdf5')
    d.plot(outdir+os.path.basename(dust_file).split('.')[0]+'.png')
    plt.clf()

    # Grids and Density

    # Grid Parameters
    nx        = 300L
    if low_res == True:
        nx    = 100L
    ny        = 400L
    nz        = 50L
    [nx, ny, nz] = [int(scale*nx), int(scale*ny), int(scale*nz)]

    # TSC model input setting
    dict_params = params
    # TSC model parameter
    cs        = dict_params['Cs']*1e5
    t         = dict_params['age']  # year
    omega     = dict_params['Omega0']
    # calculate related parameters
    M_env_dot = 0.975*cs**3/G
    mstar     = M_env_dot * t * yr
    R_cen     = omega**2 * G**3 * mstar**3 /(16*cs**8)
    R_inf     = cs * t * yr
    # protostar parameter
    tstar     = dict_params['tstar']
    R_env_max = dict_params['R_env_max']*AU
    theta_cav = dict_params['theta_cav']
    rho_cav_center = dict_params['rho_cav_center']
    rho_cav_edge   = dict_params['rho_cav_edge']*AU
    rstar     = dict_params['rstar']*RS
    # Mostly fixed parameter
    M_disk    = dict_params['M_disk']*MS
    beta      = dict_params['beta']
    h100      = dict_params['h100']*AU
    rho_cav   = dict_params['rho_cav']
    # make M_disk varies with mstar, which is the mass of star+disk
    if auto_disk != None:
        if M_disk != 0:
            print('M_disk is reset to %4f of mstar (star+disk)' % auto_disk)
            M_disk = mstar * auto_disk
        else:
            print('M_disk = 0 is found.  M_disk is set to 0.')

    # ellipsoid cavity parameter
    if ellipsoid == True:
        print('Use ellipsoid cavity (experimental)')
        # the numbers are given in arcsec
        a_out = 130 * dstar * AU
        b_out = 50  * dstar * AU
        z_out = a_out
        a_in  = dict_params['a_in'] * dstar * AU
        b_in  = a_in/a_out*b_out
        z_in  = a_in
        rho_cav_out = dict_params['rho_cav_out'] * mh
        rho_cav_in  = dict_params['rho_cav_in']  * mh

    # Calculate the dust sublimation radius
    # dust sublimation temperature specified when setting up the dust properties
    # realistic dust
    # a     = 1   # in micron
    # d_sub = 2.9388e7*(a/0.1)**-0.2 * (4*np.pi*rstar**2*sigma*tstar**4/LS)**0.5 / T_sub**3 *AU
    # black body dust
    d_sub = (LS/16./np.pi/sigma/AU**2*(4*np.pi*rstar**2*sigma*tstar**4/LS)/T_sub**4)**0.5 *AU
    # use the dust sublimation radius as the inner radius of disk and envelope
    R_disk_min = d_sub
    R_env_min  = d_sub
    rin        = rstar
    rout       = R_env_max
    R_disk_max = R_cen

    # print the variables
    print('Dust sublimation radius %6f AU' % (d_sub/AU))
    print('M_star %4f Solar mass' % (mstar/MS))
    print('Infall radius %4f AU' % (R_inf / AU))

    # if there is any parameter found in fix_params, then fix them
    if fix_params != None:
        if 'R_min' in fix_params.keys():
            R_disk_min = fix_params['R_min']*AU
            R_env_min  = fix_params['R_min']*AU

    # Make the Coordinates
    #
    ri           = rin * (rout/rin)**(np.arange(nx+1).astype(dtype='float')/float(nx))
    ri           = np.hstack((0.0, ri))
    thetai       = PI*np.arange(ny+1).astype(dtype='float')/float(ny)
    phii         = PI*2.0*np.arange(nz+1).astype(dtype='float')/float(nz)

    # Keep the constant cell size in r-direction at large radii
    #
    if max_rCell != None:
        ri_cellsize = ri[1:-1]-ri[0:-2]
        ind = np.where(ri_cellsize/AU > max_rCell)[0][0]       # The largest cell size is 100 AU
        ri = np.hstack((ri[0:ind],
                        ri[ind]+np.arange(np.ceil((rout-ri[ind])/max_rCell/AU))*max_rCell*AU))
        nxx = nx
        nx = len(ri)-1
    # Assign the coordinates of the center of cell as its coordinates.
    #
    rc           = 0.5*( ri[0:nx]     + ri[1:nx+1] )
    thetac       = 0.5*( thetai[0:ny] + thetai[1:ny+1] )
    phic         = 0.5*( phii[0:nz]   + phii[1:nz+1] )

    # for non-TSC model
    if ulrich:
        import hyperion as hp
        from hyperion.model import AnalyticalYSOModel

        non_tsc = AnalyticalYSOModel()

        # Define the luminsoity source
        nt_source = non_tsc.add_spherical_source()
        nt_source.luminosity = (4*PI*rstar**2)*sigma*(tstar**4)  # [ergs/s]
        nt_source.radius = rstar  # [cm]
        nt_source.temperature = tstar  # [K]
        nt_source.position = (0., 0., 0.)
        nt_source.mass = mstar

        # Envelope structure
        #
        nt_envelope = non_tsc.add_ulrich_envelope()
        nt_envelope.mdot = M_env_dot    # Infall rate
        nt_envelope.rmin = rin          # Inner radius
        nt_envelope.rc   = R_cen        # Centrifugal radius
        nt_envelope.rmax = R_env_max    # Outer radius
        nt_envelope.star = nt_source

        nt_grid = hp.grid.SphericalPolarGrid(ri, thetai, phii)

        rho_env_ulrich = nt_envelope.density(nt_grid).T
        rho_env_ulrich2d = np.sum(rho_env_ulrich**2, axis=2)/np.sum(rho_env_ulrich, axis=2)

    # Make the dust density model
    #
    # total mass counter
    total_mass = 0

    # normalization constant for cavity shape
    if theta_cav != 0:
        # using R = 10000 AU as the reference point
        c0 = (10000.*AU)**(-0.5)*\
             np.sqrt(1/np.sin(np.radians(theta_cav))**3-1/np.sin(np.radians(theta_cav)))
    else:
        c0 = 0

    # empty density grid to be filled later
    rho = np.zeros([len(rc), len(thetac), len(phic)])

    # Normalization for the total disk mass
    def f(w, z, beta, rstar, h100):
        f = 2*PI*w*(1-np.sqrt(rstar/w))*(rstar/w)**(beta+1)*np.exp(-0.5*(z/(w**beta*h100/100**beta))**2)
        return f
    rho_0 = M_disk/(nquad(f,[[R_disk_min,R_disk_max],[-R_env_max,R_env_max]], args=(beta,rstar,h100)))[0]

    # TODO: review
    if dyn_cav == True:
        if not tsc:
            print('WARNING: Calculation of interdependent cavity property has not implemented in infall-only solution!')
        else:
            from outflow_inner_edge import outflow_inner_edge
            # typical no used.  Just an approach I tried to make the size of the
            # constant desnity region self-consistent with the outflow cavity.
            print 'Calculate the cavity properties using the criteria that swept-up mass = outflowed mass'
            # using swept-up mass = flow mass to derive the edge of the extended flat density region
            v_outflow = 1e2 * 1e5
            rho_cav_edge = outflow_inner_edge(np.copy(rho_env), (ri,thetai,phii),M_env_dot,v_outflow,theta_cav, R_env_min)
            dict_params['rho_cav_edge'] = rho_cav_edge
            # assume gas-to-dust ratio = 100
            rho_cav_center = 0.01 * 0.1*M_env_dot*rho_cav_edge/v_outflow/2 / (2*np.pi/3*rho_cav_edge**3*(1-np.cos(np.radians(theta_cav))))
            dict_params['rho_cav_center'] = rho_cav_center
            print 'inner edge is %5f AU and density is %e g/cm3' % (rho_cav_edge/AU, rho_cav_center)


    # default setting for the density profile in cavity
    if 'rho_cav_center' in locals() == False:
        rho_cav_center = 5e-19
        print('Use 5e-19 as the default value for cavity center')
    if 'rho_cav_edge' in locals() == False:
        rho_cav_edge = 40*AU
        print('Use 40 AU as the default value for size of the inner region')
    # discontinuity factor inside and outside of cavity inner edge
    discont = 1
    # determine the edge of constant region in the cavity
    if rho_cav_edge == 0:
        rho_cav_edge = R_env_min


    if not tsc:
        print('Calculating the dust density profile with infall solution...')

        for ir in range(0,len(rc)):
            for itheta in range(0,len(thetac)):
                for iphi in range(0,len(phic)):
                    if rc[ir] > R_env_min:
                        # related coordinates
                        w = abs(rc[ir]*np.cos(np.pi/2 - thetac[itheta]))
                        z = rc[ir]*np.sin(np.pi/2 - thetac[itheta])

                        # Disk profile or envelope/cavity
                        if ((w >= R_disk_min) and (w <= R_disk_max)):
                            h = ((w/(100*AU))**beta)*h100
                            rho_dum = rho_0*(1-np.sqrt(rstar/w))*(rstar/w)**(beta+1)*np.exp(-0.5*(z/h)**2)
                        else:
                            # determine whether the current cell is in the cavity
                            if ellipsoid == False:
                                z_cav = c0*abs(w)**1.5
                                if z_cav == 0:
                                    z_cav = R_env_max
                                cav_con = abs(z) > abs(z_cav)
                                if theta_cav == 90:
                                    cav_con = True
                            else:
                                # condition for the outer ellipsoid
                                cav_con = (2*(w/b_out)**2 + ((abs(z)-z_out)/a_out)**2) < 1

                            # cavity density
                            if cav_con:
                                # open cavity
                                if ellipsoid == False:
                                    if (rc[ir] <= rho_cav_edge) & (rc[ir] >= R_env_min):
                                        rho_dum = g2d * rho_cav_center
                                    else:
                                        rho_dum = g2d * rho_cav_center*discont*(rho_cav_edge/rc[ir])**power
                                else:
                                    # condition for the inner ellipsoid
                                    if (2*(w/b_in)**2 + ((abs(z)-z_in)/a_in)**2) > 1:
                                        rho_dum = rho_cav_out
                                    else:
                                        rho_dum = rho_cav_in
                            # envelope density
                            else:
                                mu = abs(np.cos(thetac[itheta]))
                                # Implement new root finding algorithm
                                roots = np.roots(np.array([1.0, 0.0, rc[ir]/R_cen-1.0, -mu*rc[ir]/R_cen]))
                                if len(roots[roots.imag == 0]) == 1:
                                    if (abs(roots[roots.imag == 0]) - 1.0) <= 0.0:
                                        mu_o_dum = roots[roots.imag == 0]
                                    else:
                                        mu_o_dum = -0.5
                                        print('Problem with cubic solving, cos(theta) = ', mu_o_dum)
                                        print('parameters are ', np.array([1.0, 0.0, rc[ir]/R_cen-1.0, -mu*rc[ir]/R_cen]))
                                else:
                                    mu_o_dum = -0.5
                                    for imu in range(0, len(roots)):
                                        if roots[imu]*mu >= 0.0:
                                            if (abs((abs(roots[imu]) - 1.0)) <= 1e-5):
                                                mu_o_dum = 1.0 * np.sign(mu)
                                            else:
                                                mu_o_dum = roots[imu]
                                    if mu_o_dum == -0.5:
                                        print('Problem with cubic solving, roots are: ', roots)
                                mu_o = mu_o_dum.real
                                rho_dum = M_env_dot/(4*PI*(G*mstar*R_cen**3)**0.5)*(rc[ir]/R_cen)**(-3./2)*(1+mu/mu_o)**(-0.5)*(mu/mu_o+2*mu_o**2*R_cen/rc[ir])**(-1)
                        rho[ir,itheta,iphi] = rho_dum
                    else:
                        rho[ir,itheta,iphi] = 1e-30
                    # add the dust mass into the total count
                    cell_mass = rho[ir, itheta, iphi] * (1/3.)*(ri[ir+1]**3 - ri[ir]**3) * (phii[iphi+1]-phii[iphi]) * -(np.cos(thetai[itheta+1])-np.cos(thetai[itheta]))
                    total_mass = total_mass + cell_mass

    # TSC model
    else:
        print('Calculating the dust density profile with TSC solution...')

        # If needed, calculate the TSC model via IDL
        #
        if idl == True:
            print('Using IDL to calculate the TSC model.  Make sure you are running this on mechine with IDL.')
            import pidly
            idl = pidly.IDL(IDL_path)
            idl('.r '+TSC_dir+'tsc.pro')
            idl('.r '+TSC_dir+'tsc_run.pro')
            #
            # only run TSC calculation within infall radius
            # modify the rc array
            ind_infall = np.where(rc >= R_inf)[0][0]
            if max(ri) > R_inf:
                rc_idl = rc[0:ind_infall+1]
            else:
                rc_idl = rc[rc < max(ri)]
            idl.pro('tsc_run', indir=TSC_dir, outdir=outdir, rc=rc_idl, thetac=thetac, time=t,
                    c_s=cs, omega=omega, renv_min=R_env_min)
            file_idl = 'rhoenv.dat'
        else:
            print('Read the pre-computed TSC model.')
            ind_infall = np.where(rc >= R_inf)[0][0]
            if max(ri) > R_inf:
                rc_idl = rc[0:ind_infall+1]
            else:
                rc_idl = rc[rc < max(ri)]
            if idl != False:
                file_idl = idl

        # read in the exist file
        rho_env_tsc_idl = np.genfromtxt(outdir+file_idl).T
        # because only region within infall radius is calculated by IDL program,
        # need to project it to the original grid
        rho_env_tsc = np.zeros([len(rc), len(thetac)])
        for irc in range(len(rc)):
            if rc[irc] in rc_idl:
                rho_env_tsc[irc,:] = rho_env_tsc_idl[np.squeeze(np.where(rc_idl == rc[irc])),:]

        # extrapolate for the NaN values at the outer radius, usually at radius beyond the infall radius
        # using r^-2 profile at radius greater than infall radius
        # and map the 2d strcuture onto 3-D grid
        # map TSC solution from IDL to actual 2-D grid
        rho_env_tsc2d = np.empty((nx,ny))
        if max(ri) > R_inf:
            for i in range(0, len(rc)):
                if i <= ind_infall:
                    rho_env_tsc2d[i,:] = rho_env_tsc[i,:]
                else:
                    rho_env_tsc2d[i,:] = 10**(np.log10(rho_env_tsc[ind_infall,:]) - 2*(np.log10(rc[i]/rc[ind_infall])))
        else:
            rho_env_tsc2d = rho_env_tsc

        # map it to 3-D grid
        rho_env = np.repeat(rho_env_tsc2d[:,:,np.newaxis], nz, axis=2)

        for ir in range(0,len(rc)):
            for itheta in range(0,len(thetac)):
                for iphi in range(0,len(phic)):
                    if rc[ir] > R_env_min:
                        # related coordinates
                        w = abs(rc[ir]*np.cos(np.pi/2 - thetac[itheta]))
                        z = rc[ir]*np.sin(np.pi/2 - thetac[itheta])

                        # initialize dummer rho for disk and cavity
                        rho_dum = 0
                        # Disk profile
                        if ((w >= R_disk_min) and (w <= R_disk_max)) == True:
                            h = ((w/(100*AU))**beta)*h100
                            rho_dum = rho_0*(1-np.sqrt(rstar/w))*(rstar/w)**(beta+1)*np.exp(-0.5*(z/h)**2)
                        else:
                        # determine whether the current cell is in the cavity
                            if ellipsoid == False:
                                z_cav = c0*abs(w)**1.5
                                if z_cav == 0:
                                    z_cav = R_env_max
                                cav_con = abs(z) > abs(z_cav)
                            else:
                                # condition for the outer ellipsoid
                                cav_con = (2*(w/b_out)**2 + ((abs(z)-z_out)/a_out)**2) < 1

                            if cav_con:
                                # open cavity
                                if ellipsoid == False:
                                    if (rc[ir] <= rho_cav_edge) & (rc[ir] >= R_env_min):
                                        rho_dum = g2d * rho_cav_center
                                    else:
                                        rho_dum = g2d * rho_cav_center*discont*(rho_cav_edge/rc[ir])**power
                                else:
                                    # condition for the inner ellipsoid
                                    if (2*(w/b_in)**2 + ((abs(z)-z_in)/a_in)**2) > 1:
                                        rho_dum = rho_cav_out
                                    else:
                                        rho_dum = rho_cav_in

                        rho[ir, itheta, iphi] = rho_env[ir, itheta, iphi] + rho_dum

                    else:
                        rho[ir,itheta,iphi] = 1e-40

                    # add the dust mass into the total count
                    cell_mass = rho[ir, itheta, iphi] * (1/3.)*(ri[ir+1]**3 - ri[ir]**3) * (phii[iphi+1]-phii[iphi]) * -(np.cos(thetai[itheta+1])-np.cos(thetai[itheta]))
                    total_mass = total_mass + cell_mass
    # apply gas-to-dust ratio of 100
    rho_dust = rho/g2d
    total_mass_dust = total_mass/MS/g2d
    print('Total dust mass = %f Solar mass' % total_mass_dust)

    # Insert the calculated grid and dust density profile into hyperion
    m.set_spherical_polar_grid(ri, thetai, phii)
    m.add_density_grid(rho_dust.T, d)

    # Define the luminsoity source
    source = m.add_spherical_source()
    source.luminosity = (4*PI*rstar**2)*sigma*(tstar**4)  # [ergs/s]
    source.radius = rstar  # [cm]
    source.temperature = tstar  # [K]
    source.position = (0., 0., 0.)
    print('L_center =  % 5.2f L_sun' % ((4*PI*rstar**2)*sigma*(tstar**4)/LS))

    # radiative transfer settigs
    m.set_raytracing(True)

    # determine the number of photons for imaging
    # the case of monochromatic
    if mono_wave != None:
        if (type(mono_wave) == int) or (type(mono_wave) == float) or (type(mono_wave) == str):
            mono_wave = float(mono_wave)
            mono_wave = [mono_wave]

        # Monochromatic radiative transfer setting
        m.set_monochromatic(True, wavelengths=mono_wave)
        m.set_n_photons(initial=mc_photons, imaging_sources=im_photon,
                        imaging_dust=im_photon, raytracing_sources=im_photon,
                        raytracing_dust=im_photon)
    # regular SED
    else:
        m.set_n_photons(initial=mc_photons, imaging=im_photon * wav_num,
                        raytracing_sources=im_photon,
                        raytracing_dust=im_photon)
    # number of iteration to compute dust specific energy (temperature)
    m.set_n_initial_iterations(20)
    m.set_convergence(True, percentile=dict_params['percentile'],
                            absolute=dict_params['absolute'],
                            relative=dict_params['relative'])
    m.set_mrw(True)   # Gamma = 1 by default

    # Setting up images and SEDs
    if not image_only:
        # SED setting
        # Infinite aperture
        syn_inf = m.add_peeled_images(image=False)
        # use the index of wavelength array used by the monochromatic radiative transfer
        if mono_wave == None:
            syn_inf.set_wavelength_range(wav_num, wav_min, wav_max)
        syn_inf.set_viewing_angles([dict_params['view_angle']], [0.0])
        syn_inf.set_uncertainties(True)
        syn_inf.set_output_bytes(8)

        # aperture
        # 7.2 in 10 um scaled by lambda / 10
        # flatten beyond 20 um
        # default aperture (should always specify a set of apertures)

        # assign wl_aper and aper from dictionary of aperture
        wl_aper = aperture['wave']
        aper    = aperture['aperture']
        # create the non-repetitive aperture list and index array
        aper_reduced = sorted(list(set(aper)))
        index_reduced = np.arange(1, len(aper_reduced)+1)

        dict_peel_sed = {}
        for i in range(0, len(aper_reduced)):
            aper_dum = aper_reduced[i]/2 * (1/3600.*np.pi/180.)*dstar*pc
            dict_peel_sed[str(index_reduced[i])] = m.add_peeled_images(image=False)
            # use the index of wavelength array used by the monochromatic radiative transfer
            if mono == False:
                dict_peel_sed[str(index_reduced[i])].set_wavelength_range(wav_num, wav_min, wav_max)
            dict_peel_sed[str(index_reduced[i])].set_viewing_angles([dict_params['view_angle']], [0.0])
            # aperture should be given in cm and its the radius of the aperture
            dict_peel_sed[str(index_reduced[i])].set_aperture_range(1, aper_dum, aper_dum)
            dict_peel_sed[str(index_reduced[i])].set_uncertainties(True)
            dict_peel_sed[str(index_reduced[i])].set_output_bytes(8)

    # image setting
    syn_im = m.add_peeled_images(sed=False)
    # use the index of wavelength array used by the monochromatic radiative transfer
    if mono_wave == None:
        syn_im.set_wavelength_range(wav_num, wav_min, wav_max)
        pix_num = 300
    else:
        pix_num = 8000
    #
    syn_im.set_image_size(pix_num, pix_num)
    syn_im.set_image_limits(-R_env_max, R_env_max, -R_env_max, R_env_max)
    syn_im.set_viewing_angles([dict_params['view_angle']], [0.0])
    syn_im.set_uncertainties(True)
    syn_im.set_output_bytes(8)

    # Output setting
    # Density
    m.conf.output.output_density = 'last'
    # Density difference (shows where dust was destroyed)
    m.conf.output.output_density_diff = 'none'
    # Energy absorbed (using pathlengths)
    m.conf.output.output_specific_energy = 'last'
    # Number of unique photons that passed through the cell
    m.conf.output.output_n_photons = 'last'
    m.write(outdir+outname+'.rtin')

    if plot:
        # rho2d is the 2-D projection of gas density
        # take the weighted average
        rho2d = np.sum(rho**2, axis=2)/np.sum(rho, axis=2)

        if fast_plot == False:
            # Plot the azimuthal averaged density
            fig = plt.figure(figsize=(8,6))
            ax_env  = fig.add_subplot(111, projection='polar')

            # zmin = 1e-22/mmw/mh
            zmin = 1e-1
            cmap = plt.cm.CMRmap
            rho2d_exp = np.hstack((rho2d, rho2d, rho2d[:,0:1]))
            thetac_exp = np.hstack((thetac-PI/2, thetac+PI/2, thetac[0]-PI/2))
            # plot the gas density
            img_env = ax_env.pcolormesh(thetac_exp, rc/AU, rho2d_exp/mmw/mh,
                                        cmap=cmap,
                                        norm=LogNorm(vmin=zmin,vmax=1e6))

            ax_env.set_xlabel(r'$\rm{Polar\,angle\,(Degree)}$',fontsize=20)
            ax_env.set_ylabel('', fontsize=20, labelpad=-140)
            ax_env.tick_params(labelsize=18)
            ax_env.set_yticks(np.hstack((np.arange(0,(int(R_env_max/AU/10000.)+1)*10000, 10000),R_env_max/AU)))
            ax_env.set_xticklabels([r'$\rm{90^{\circ}}$',r'$\rm{45^{\circ}}$',r'$\rm{0^{\circ}}$',r'$\rm{-45^{\circ}}$',\
                                    r'$\rm{-90^{\circ}}$',r'$\rm{-135^{\circ}}$',r'$\rm{180^{\circ}}$',r'$\rm{135^{\circ}}$'])
            ax_env.set_yticklabels([])
            # fix the tick label font
            ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',size=20)
            for label in ax_env.get_yticklabels():
                label.set_fontproperties(ticks_font)

            ax_env.grid(True, color='LightGray', linewidth=1.5)
            cb = fig.colorbar(img_env, pad=0.1)
            cb.ax.set_ylabel(r'$\rm{Averaged\,Gas\,Density\,(cm^{-3})}$',fontsize=20)
            cb.set_ticks([1e-1,1e0,1e1,1e2,1e3,1e4,1e5,1e6])
            cb.set_ticklabels([r'$\rm{10^{-1}}$',r'$\rm{10^{0}}$',r'$\rm{10^{1}}$',r'$\rm{10^{2}}$',r'$\rm{10^{3}}$',
                               r'$\rm{10^{4}}$',r'$\rm{10^{5}}$',r'$\rm{\geq 10^{6}}$'])

            cb_obj = plt.getp(cb.ax.axes, 'yticklabels')
            plt.setp(cb_obj, fontsize=20)
            fig.savefig(outdir+outname+'_gas_density.png', format='png', dpi=300, bbox_inches='tight')
            fig.clf()

        # Plot the radial density profile
        fig = plt.figure(figsize=(12,9))
        ax = fig.add_subplot(111)

        plot_grid = [0, 49, 99, 149, 199]
        color_grid = ['#e41a1c', '#377eb8', '#4daf4a', '#984ea3', '#ff7f00']
        label = [r'$\rm{\theta='+str(int(np.degrees(thetai[plot_grid[0]])))+'^{\circ}}$',
                 r'$\rm{\theta='+str(int(np.degrees(thetai[plot_grid[1]])))+'^{\circ}}$',
                 r'$\rm{\theta='+str(1+int(np.degrees(thetai[plot_grid[2]])))+'^{\circ}}$',
                 r'$\rm{\theta='+str(int(np.degrees(thetai[plot_grid[3]])))+'^{\circ}}$',
                 r'$\rm{\theta='+str(1+int(np.degrees(thetai[plot_grid[4]])))+'^{\circ}}$']
        alpha = np.linspace(0.3, 1.0, len(plot_grid))
        for i in plot_grid:
            ax.plot(np.log10(rc[rc > 0.14*AU]/AU), np.log10(rho2d[rc > 0.14*AU,i]/g2d/mmw/mh)+plot_grid[::-1].index(i)*-0.2,'-',color=color_grid[plot_grid.index(i)],mec='None',linewidth=2.5, \
                    markersize=3, label=label[plot_grid.index(i)])
        ax.axvline(np.log10(R_inf/AU), linestyle='--', color='k', linewidth=1.5, label=r'$\rm{infall\,radius}$')
        ax.axvline(np.log10(R_cen/AU), linestyle=':', color='k', linewidth=1.5, label=r'$\rm{centrifugal\,radius}$')

        lg = plt.legend(fontsize=20, numpoints=1, ncol=2, framealpha=0.7, loc='upper right')

        ax.set_xlabel(r'$\rm{log(Radius)\,(AU)}$', fontsize=20)
        ax.set_ylabel(r'$\rm{log(Dust\,Density)\,(cm^{-3})}$', fontsize=20)
        [ax.spines[axis].set_linewidth(1.5) for axis in ['top','bottom','left','right']]
        ax.minorticks_on()
        ax.tick_params('both', labelsize=18, width=1.5, which='major', pad=15, length=5)
        ax.tick_params('both', labelsize=18, width=1.5, which='minor', pad=15, length=2.5)

        # fix the tick label font
        ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',size=18)
        for label in ax.get_xticklabels():
            label.set_fontproperties(ticks_font)
        for label in ax.get_yticklabels():
            label.set_fontproperties(ticks_font)

        ax.set_ylim([0,11])
        fig.gca().set_xlim(left=np.log10(0.05))
        fig.savefig(outdir+outname+'_gas_radial.pdf',format='pdf',dpi=300,bbox_inches='tight')
        fig.clf()

    # Record the input and calculated parameters
    if not norecord == True:
        params = dict_params.copy()
        params.update({'d_sub': d_sub/AU,
                       'M_env_dot': M_env_dot/MS*yr,
                       'R_inf': R_inf/AU,
                       'R_cen': R_cen/AU,
                       'mstar': mstar/MS,
                       'M_tot_gas': total_mass/MS})
        record_hyperion(params,record_dir)


    return m
コード例 #5
0
import numpy as np

from hyperion.model import AnalyticalYSOModel
from hyperion.util.constants import rsun, au, msun, sigma

# Initalize the model
m = AnalyticalYSOModel()

# Set the stellar parameters
m.star.radius = 2. * rsun
m.star.temperature = 4000.
m.star.luminosity = 4 * (2. * rsun)**2 * sigma * 4000**4

# Add a flared disk
disk = m.add_flared_disk()
disk.mass = 0.01 * msun
disk.rmin = 10 * m.star.radius
disk.rmax = 200 * au
disk.r_0 = m.star.radius
disk.h_0 = 0.01 * disk.r_0
disk.p = -1.0
disk.beta = 1.25
disk.dust = 'kmh_lite.hdf5'

# Use raytracing to improve s/n of thermal/source emission
m.set_raytracing(True)

# Use the modified random walk
m.set_mrw(True, gamma=2.)

# Set up grid
コード例 #6
0
from hyperion.model import AnalyticalYSOModel
from hyperion.util.constants import lsun, rsun, tsun, msun, au

# Initialize model and set up density grid
m = AnalyticalYSOModel()

# Set up the central source
m.star.radius = rsun
m.star.temperature = tsun
m.star.luminosity = lsun

# Set up a simple flared disk
d = m.add_flared_disk()
d.mass = 0.001 * msun
d.rmin = 0.1 * au
d.rmax = 100. * au
d.p = -1
d.beta = 1.25
d.h_0 = 0.01 * au
d.r_0 = au
d.dust = 'kmh_lite.hdf5'

# Specify that the specific energy and density are needed
m.conf.output.output_specific_energy = 'last'
m.conf.output.output_density = 'last'

# Set the number of photons
m.set_n_photons(initial=1000000, imaging=0)

# Set up the grid
m.set_spherical_polar_grid_auto(400, 300, 1)
コード例 #7
0
ファイル: setup.py プロジェクト: koepferl/tutorial_loops
from hyperion.model import AnalyticalYSOModel
from hyperion.util.constants import pc, lsun, rsun, msun, au,pi
from hyperion.model import ModelOutput
import numpy as np

for j in [0.0001, 0.0000001, 0.0000000001]:
    m = AnalyticalYSOModel()
    m.set_n_photons(initial=10000, imaging=10000)

    m.star.luminosity = 5 * lsun
    m.star.radius = 2 * rsun
    m.star.temperature = 6000.

    disk = m.add_flared_disk()
    print 'disk.mass = ', j * 0.01, 'msun'
    disk.mass = 0.01 * j * msun     # Disk mass

    disk.rmin = 10 * rsun               # Inner radius
    disk.rmax = 300 * au                # Outer radius
    disk.r_0 = 100. * au                # Radius at which h_0 is defined
    disk.h_0 = 5 * au                   # Disk scaleheight at r_0
    disk.p = -1                         # Radial surface density exponent
    disk.beta = 1.25                    # Disk flaring power

    envelope = m.add_power_law_envelope()
    envelope.mass = 0.001 * msun          # Envelope mass
    envelope.rmin = au                  # Inner radius
    envelope.rmax = 10000 * au          # Outer radius
    envelope.power = -2                 # Radial power
    envelope.r_0 = au                   # Inner density radius
コード例 #8
0
ファイル: hyperion_ulrich.py プロジェクト: yaolun/misc
# Variable setup
#
rstar     = 5 * RS
tstar     = 4500
R_env_max = 1.000000e+04 * AU
R_env_min = 8.000000e-01 * AU
R_cen     = 1.500000e+01 * AU
theta_cav = 0.0            # no cavity
M_env_dot = 3.000000e-05 * MS/yr
mstar     = 9.844506e-01 * MS
rin       = rstar
rout      = R_env_max
rcen      = R_cen

m = AnalyticalYSOModel()

# Define the luminsoity source
source = m.add_spherical_source()
source.luminosity = (4*PI*rstar**2)*sigma*(tstar**4)  # [ergs/s]
source.radius = rstar  # [cm]
source.temperature = tstar  # [K]
source.position = (0., 0., 0.)
source.mass = mstar
print 'L_center =  % 5.2f L_sun' % ((4*PI*rstar**2)*sigma*(tstar**4)/LS)

# Envelope structure
#
envelope = m.add_ulrich_envelope()
envelope.mdot = M_env_dot    # Infall rate
envelope.rmin = rin          # Inner radius
コード例 #9
0
def setup_model(parfile, output, imaging=True):

    # Read in model parameters
    par = read_parfile(parfile, nested=True)

    # Find all dust files
    dust_files = {}
    for par_name in par:
        if 'dust' in par[par_name]:
            dust_file = par[par_name]['dust']
            dust_files[dust_file] = SphericalDust(dust_file)

    # Find dimensionality of problem:
    if 'disk' in par:
        ndim = 2
        optimize = False
    elif 'cavity' in par:
        ndim = 2
        optimize = False
    elif 'envelope' in par and 'rc' in par['envelope']:
        ndim = 2
        optimize = False
    else:
        ndim = 1
        optimize = True

    # Set up model
    m = AnalyticalYSOModel(output)

    if not 'star' in par:
        raise Exception("Cannot compute a model without a central source")

    # Set radius and luminosity
    m.star.radius = par['star']['radius'] * rsun
    m.star.luminosity = 4. * pi * (par['star']['radius'] * rsun) ** 2. \
                        * sigma * par['star']['temperature'] ** 4.

    # Interpolate and set spectrum
    nu, fnu = interp_atmos(par['star']['temperature'])
    m.star.spectrum = (nu, fnu)

    subtract_from_ambient = []

    if 'disk' in par:

        # Add the flared disk component
        disk = m.add_flared_disk()

        # Basic parameters
        disk.mass = par['disk']['mass'] * msun
        disk.rmax = par['disk']['rmax'] * au
        disk.p = par['disk']['p']
        disk.beta = par['disk']['beta']
        disk.h_0 = par['disk']['h100'] * au
        disk.r_0 = 100. * au

        # Set inner and outer walls to be spherical
        disk.cylindrical_inner_rim = False
        disk.cylindrical_outer_rim = False

        # Set dust
        disk.dust = dust_files[par['disk']['dust']]

        # Inner radius
        if 'rmin' in par['disk']:
            disk.rmin = par['disk']['rmin'] * OptThinRadius(TSUB)
        else:
            disk.rmin = OptThinRadius(TSUB)

        # Settling
        if 'eta' in par['disk']:
            raise Exception("Dust settling not implemented")

        # Accretion luminosity
        if 'lacc' in par['disk']:
            raise Exception("Accretion luminosity not implemented")
            # m.setup_magnetospheric_accretion(par['disk']['lacc'] * lsun,
            #                                  par['disk']['rtrunc'],
            #                                  par['star']['fspot'], disk)

        subtract_from_ambient.append(disk)

    if 'envelope' in par:

        if 'rc' in par['envelope']:  # Ulrich envelope

            envelope = m.add_ulrich_envelope()
            envelope.rho_0 = par['envelope']['rho_0']
            envelope.rc = par['envelope']['rc'] * au

        elif 'power' in par['envelope']:  # Power-law envelope

            envelope = m.add_power_law_envelope()
            envelope.power = par['envelope']['power']
            envelope.rho_0 = par['envelope']['rho_0']
            envelope.r_0 = 1000. * au

        # Set dust
        envelope.dust = dust_files[par['envelope']['dust']]

        # Inner radius
        if 'rmin' in par['envelope']:
            envelope.rmin = par['envelope']['rmin'] * OptThinRadius(TSUB)
        else:
            envelope.rmin = OptThinRadius(TSUB)

        subtract_from_ambient.append(envelope)

    if 'cavity' in par:

        if not 'envelope' in par:
            raise Exception("Can't have a bipolar cavity without an envelope")

        # Add the bipolar cavity component
        cavity = envelope.add_bipolar_cavity()

        # Basic parameters
        cavity.power = par['cavity']['power']
        cavity.r_0 = 10000 * au
        cavity.theta_0 = par['cavity']['theta_0']
        cavity.rho_0 = par['cavity']['rho_0']
        cavity.rho_exp = 0.

        # Very important is that the cavity density should not be *larger* than
        # the envelope density.
        cavity.cap_to_envelope_density = True

        # Set dust
        cavity.dust = dust_files[par['cavity']['dust']]

        subtract_from_ambient.append(cavity)

    if 'ambient' in par:

        # Add the ambient medium contribution
        ambient = m.add_ambient_medium(subtract=subtract_from_ambient)

        # Set the density, temperature, and dust properties
        ambient.rho = par['ambient']['density']
        ambient.temperature = par['ambient']['temperature']
        ambient.dust = dust_files[par['ambient']['dust']]

        # If there is an envelope, set the outer radius to where the
        # optically thin temperature would transition to the ambient medium
        # temperature
        if 'envelope' in par:

            # Find radius where the optically thin temperature drops to the
            # ambient temperature. We can do this only if we've already set
            # up all the sources of emission beforehand (which we have)
            rmax_temp = OptThinRadius(ambient.temperature).evaluate(m.star, envelope.dust)

            # Find radius where the envelope density drops to the ambient density
            rmax_dens = envelope.outermost_radius(ambient.rho)

            # If disk radius is larger than this, use that instead
            if 'disk' in par:
                if disk.rmax > rmax_dens:
                    rmax_dens = disk.rmax

            # Pick the largest
            if rmax_temp < rmax_dens:
                print("Setting envelope outer radius to that where rho(r) = rho_amb")
                envelope.rmax = rmax_dens
            else:
                print("Setting envelope outer radius to that where T_thin(r) = T_amb")
                envelope.rmax = OptThinRadius(ambient.temperature)

            ambient.rmax = envelope.rmax

        else:

            if 'disk' in par:

                # Find radius where the optically thin temperature drops to the
                # ambient temperature. We can do this only if we've already set
                # up all the sources of emission beforehand (which we have)
                rmax_temp = OptThinRadius(ambient.temperature).evaluate(m.star, ambient.dust)

                # Find outer disk radius
                rmax_dens = disk.rmax

                # Pick the largest
                if rmax_temp < rmax_dens:
                    print("Setting ambient outer radius to outer disk radius")
                    ambient.rmax = rmax_dens
                else:
                    print("Setting ambient outer radius to that where T_thin(r) = T_amb")
                    ambient.rmax = OptThinRadius(ambient.temperature)

            else:

                ambient.rmax = OptThinRadius(ambient.temperature)

        # The inner radius for the ambient medium should be the largest of
        # the inner radii for the disk and envelope
        if 'envelope' in par and 'rmin' in par['envelope']:
            if 'disk' in par and 'rmin' in par['disk']:
                ambient.rmin = max(par['disk']['rmin'], \
                                   par['envelope']['rmin']) \
                               * OptThinRadius(TSUB)
            else:
                ambient.rmin = par['envelope']['rmin'] * OptThinRadius(TSUB)
        elif 'disk' in par and 'rmin' in par['disk']:
            ambient.rmin = par['disk']['rmin'] * OptThinRadius(TSUB)
        else:
            ambient.rmin = OptThinRadius(TSUB)

        # The ambient medium needs to go out to sqrt(2.) times the envelope
        # radius to make sure the slab is full (don't need to do sqrt(3)
        # because we only need a cylinder along line of sight)
        ambient.rmax *= np.sqrt(2.)

        # Make sure that the temperature in the model is always at least
        # the ambient temperature
        m.set_minimum_temperature(ambient.temperature)

    else:

        # Make sure that the temperature in the model is always at least
        # the CMB temperature
        m.set_minimum_temperature(2.725)

        if 'envelope' in par:
            raise Exception("Can't have an envelope without an ambient medium")

    # Use raytracing to improve s/n of thermal/source emission
    m.set_raytracing(True)

    # Use the modified random walk
    m.set_mrw(True, gamma=2.)

    # Use the partial diffusion approximation
    m.set_pda(True)

    # Improve s/n of scattering by forcing the first interaction
    m.set_forced_first_scattering(True)

    # Set up grid.
    if ndim == 1:
        m.set_spherical_polar_grid_auto(400, 1, 1)
    else:
        m.set_spherical_polar_grid_auto(400, 300, 1)

    # Find the range of radii spanned by the grid
    rmin, rmax = m.radial_range()

    # Set up SEDs
    image = m.add_peeled_images(sed=True, image=False)
    image.set_wavelength_range(200, 0.01, 5000.)

    if 'ambient' in par:
        image.set_aperture_range(20, rmin, rmax / np.sqrt(2.))
    else:
        image.set_aperture_range(20, rmin, rmax)

    image.set_output_bytes(8)
    image.set_track_origin(True)
    image.set_uncertainties(True)
    image.set_stokes(True)

    if ndim == 1:

        # Viewing angle does not matter
        image.set_viewing_angles([45.], [45.])

    else:

        # Use stratified random sampling to ensure that all models
        # contain a viewing angle in each bin, but also ensure we have a
        # continuum of viewing angles over all models
        xi = np.random.uniform(0., 90./float(NVIEW), NVIEW)
        theta = xi + np.linspace(0., 90. * (1. - 1./float(NVIEW)), NVIEW)
        image.set_viewing_angles(theta, np.repeat(45., NVIEW))

    if 'ambient' in par:  # take a slab to avoid spherical geometrical effects
        w = ambient.rmax / np.sqrt(2.)
        image.set_depth(-w, w)
    else:  # don't need to take a slab, as no ambient material or envelope
        image.set_depth(-np.inf, np.inf)

    # Set number of photons

    if imaging:
        n_imaging=1e6
        n_raytracing_sources=10000
        n_raytracing_dust=1e6
    else:
        n_imaging=0
        n_raytracing_sources=0
        n_raytracing_dust=0

    if ndim == 1:
        m.set_n_photons(initial=100, imaging=n_imaging,
                        raytracing_sources=n_raytracing_sources,
                        raytracing_dust=n_raytracing_dust)
    else:
        m.set_n_photons(initial=1000000, imaging=n_imaging,
                        raytracing_sources=n_raytracing_sources,
                        raytracing_dust=n_raytracing_dust)

    # Set physical array output to 32-bit
    m.set_output_bytes(4)

    # Set maximum of 10^8 interactions per photon
    m.set_max_interactions(1e8)

    # Only request certain arrays to be output
    m.conf.output.output_density = 'none'
    m.conf.output.output_specific_energy = 'last'
    m.conf.output.output_n_photons = 'none'
    m.conf.output.output_density_diff = 'last'

    # Set number of temperature iterations and convergence criterion
    m.set_n_initial_iterations(10)
    m.set_convergence(True, percentile=99.0, absolute=2.0, relative=1.1)

    # Don't copy the full input into the output files
    m.set_copy_input(False)

    # Check whether the model is very optically thick

    mf = m.to_model()

    if 'envelope' in par:

        from hyperion.model.helpers import tau_to_radius
        surface = tau_to_radius(mf, tau=1., wav=5e3)
        rtau = np.min(surface)

        if rtau > rmin and optimize:
            log.warn("tau_5mm > 1 for all (theta,phi) values - truncating "
                     "inner envelope from {0:.3f}au to {1:.3f}au".format(mf.grid.r_wall[1] / au, rtau / au))
            for item in mf.grid['density']:
                item.array[mf.grid.gr < rtau] = 0.

    # Write out file
    mf.write(copy=False, absolute_paths=False,
             physics_dtype=np.float32, wall_dtype=float)
コード例 #10
0
import numpy as np

from hyperion.model import AnalyticalYSOModel
from hyperion.util.constants import rsun, lsun, au, msun, yr, c

# Initalize the model
m = AnalyticalYSOModel()

# Read in stellar spectrum
wav, fnu = np.loadtxt('kt04000g+3.5z-2.0.ascii', unpack=True)
nu = c / (wav * 1.e-4)

# Set the stellar parameters
m.star.radius = 1.85 * rsun
m.star.spectrum = (nu, fnu)
m.star.luminosity = lsun
m.star.mass = 0.8 * msun

# Add a flared disk
disk = m.add_flared_disk()
disk.mass = 0.03 * msun
disk.rmin = 7 * m.star.radius
disk.rmax = 400 * au  #from quote of Andrews & Williams
disk.r_0 = 0.08 * au  #m.star.radius
disk.h_0 = 0.01 * disk.r_0
disk.p = -1.0
disk.beta = 1.25
disk.dust = 'kmh_lite.hdf5'

## # Add an Ulrich envelope
## envelope = m.add_ulrich_envelope()
コード例 #11
0
ファイル: test_disc.py プロジェクト: koepferl/spherical
from hyperion.model import AnalyticalYSOModel
from hyperion.util.constants import pc, lsun, rsun, msun, au,pi
from hyperion.model import ModelOutput
import numpy as np

m = AnalyticalYSOModel()
m.set_n_photons(initial=100000, imaging=100000)
m.star.luminosity = 5 * lsun
m.star.radius = 2 * rsun
m.star.temperature = 6000.

disk = m.add_flared_disk()
disk.mass = 0.01 * msun             # Disk mass
disk.rmin = 10 * rsun               # Inner radius
disk.rmax = 300 * au                # Outer radius
disk.r_0 = 100. * au                # Radius at which h_0 is defined
disk.h_0 = 5 * au                   # Disk scaleheight at r_0
disk.p = -1                         # Radial surface density exponent
disk.beta = 1.25                    # Disk flaring power

envelope = m.add_power_law_envelope()
envelope.mass = 0.001 * msun          # Envelope mass
envelope.rmin = au                  # Inner radius
envelope.rmax = 10000 * au          # Outer radius
envelope.power = -2                 # Radial power
envelope.r_0 = au                   # Inner density radius

#dust
disk.dust = 'www003.hdf5'
envelope.dust = 'kmh.hdf5'
#cavity.dust = 'kmh_hdf5'
コード例 #12
0
ファイル: tsc_comparison.py プロジェクト: yaolun/misc
def tsc_com(params_table, plot=True, disk=False):
    import numpy as np
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    from matplotlib.colors import LogNorm
    import astropy.constants as const
    import os
    import scipy as sci
    from scipy.optimize import fsolve
    from scipy.optimize import newton
    from scipy.integrate import nquad
    import sys
    sys.path.append("/Users/yaolun/programs/misc/hyperion/")
    from input_reader import input_reader_table
    home = os.path.expanduser('~')

    # read the TSC model
    # Constant Setup
    #
    AU        = 1.49598e13     # Astronomical Unit       [cm]
    pc        = 3.08572e18     # Parsec                  [cm]
    MS        = 1.98892e33     # Solar mass              [g]
    LS        = 3.8525e33      # Solar luminosity        [erg/s]
    RS        = 6.96e10        # Solar radius            [cm]
    G         = 6.67259e-8     # Gravitational constant  [cm3/g/s^2]
    yr        = 60*60*24*365   # Years in seconds
    PI        = np.pi          # PI constant
    sigma     = const.sigma_sb.cgs.value  # Stefan-Boltzmann constant
    mh        = const.m_p.cgs.value + const.m_e.cgs.value

    # read parameter from input_table
    # params_table = '/Users/yaolun/programs/misc/hyperion/test_input.txt'
    params = input_reader_table(params_table)[0]
    # force omega = 4.1e-13 to emphasize the difference
    # params['Omega0'] = 4.1e-13
    #
    rstar     = params['rstar'] * RS
    tstar     = params['tstar']
    R_env_max = params['R_env_max'] * AU
    T_sub = 1600
    a     = 1   #in micron
    d_sub = (LS/16./np.pi/sigma/AU**2*(4*np.pi*rstar**2*sigma*tstar**4/LS)/T_sub**4)**0.5 *AU
    R_env_min = d_sub
    R_cen     = params['Omega0']**2 * G**3 * (0.975*(params['Cs']*1e5)**3/G*params['age']*yr)**3 /(16*(params['Cs']*1e5)**8)
    R_inf     = params['Cs']*1e5*params['age']*yr
    R_disk_min= d_sub
    R_disk_max= R_cen
    theta_cav = params['theta_cav']
    beta      = params['beta']
    h100      = params['h100'] * AU
    M_env_dot = 0.975*(params['Cs']*1e5)**3/G
    M_disk    = params['M_disk'] * MS
    mstar     = M_env_dot * params['age']*yr
    rin       = rstar
    rout      = R_env_max
    rho_cav_center = params['rho_cav_center']
    rho_cav_edge = params['rho_cav_edge'] * AU

    # Grid Parameters
    nx        = 100L
    ny        = 400L
    nz        = 50L

    # Make the Coordinates
    #
    ri           = rin * (rout/rin)**(np.arange(nx+1).astype(dtype='float')/float(nx))
    ri           = np.hstack((0.0, ri))
    thetai       = PI*np.arange(ny+1).astype(dtype='float')/float(ny)
    phii         = PI*2.0*np.arange(nz+1).astype(dtype='float')/float(nz)

    # Keep the constant cell size in r-direction
    #

    ri_cellsize = ri[1:-1]-ri[0:-2]
    ind = np.where(ri_cellsize/AU > 100.0)[0][0]       # The largest cell size is 100 AU
    ri = np.hstack((ri[0:ind],ri[ind]+np.arange(np.ceil((rout-ri[ind])/100/AU))*100*AU))
    nx = len(ri)-1

    # Assign the coordinates of the center of cell as its coordinates.
    #
    rc           = 0.5*( ri[0:nx]     + ri[1:nx+1] )
    thetac       = 0.5*( thetai[0:ny] + thetai[1:ny+1] )
    phic         = 0.5*( phii[0:nz]   + phii[1:nz+1] )

    if disk == False:
        rho_env_tsc_idl = np.genfromtxt('/Users/yaolun/test/model32_rhoenv.dat').T
    else:
        rho_env_tsc_idl = np.genfromtxt('/Users/yaolun/test/model32_rhoenv.dat').T

    rc_idl = rc[(rc < min([R_inf,max(ri)]))]

    # because only region within infall radius is calculated by IDL program, need to project it to the original grid
    rho_env_tsc = np.zeros([len(rc), len(thetac)])
    for irc in range(len(rc)):
        if rc[irc] in rc_idl:
            rho_env_tsc[irc,:] = rho_env_tsc_idl[np.where(rc_idl == rc[irc]),:]

    # extrapolate for the NaN values at the outer radius, usually at radius beyond the infall radius
    # using r^-2 profile at radius greater than infall radius
    # and map the 2d strcuture onto 3d grid
    def poly(x, y, x0, deg=2):
        import numpy as np
        p = np.polyfit(x, y, deg)
        y0 = 0
        for i in range(0, len(p)):
            y0 = y0 + p[i]*x0**(len(p)-i-1)
        return y0
    # map TSC solution from IDL to actual 2-D grid
    rho_env_tsc2d = np.empty((nx,ny))
    if max(ri) > R_inf:
        ind_infall = np.where(rc <= R_inf)[0][-1]
        for i in range(0, len(rc)):
            if i <= ind_infall:
                rho_env_tsc2d[i,:] = rho_env_tsc[i,:]
            else:
                rho_env_tsc2d[i,:] =  10**(np.log10(rho_env_tsc[ind_infall,:]) - 2*(np.log10(rc[i]/rc[ind_infall])))
    else:
        rho_env_tsc2d = rho_env_tsc
    # map it to 3-D grid
    rho_env_tsc = np.empty((nx,ny,nz))
    for i in range(0, nz):
        rho_env_tsc[:,:,i] = rho_env_tsc2d

    # calculate the infall-only solution

    import hyperion as hp
    from hyperion.model import Model
    from hyperion.model import AnalyticalYSOModel

    m = AnalyticalYSOModel()

    # Define the luminsoity source
    source = m.add_spherical_source()
    source.luminosity = (4*PI*rstar**2)*sigma*(tstar**4)  # [ergs/s]
    source.radius = rstar  # [cm]
    source.temperature = tstar  # [K]
    source.position = (0., 0., 0.)
    source.mass = mstar
    print 'L_center =  % 5.2f L_sun' % ((4*PI*rstar**2)*sigma*(tstar**4)/LS)

    # Envelope structure
    #
    envelope = m.add_ulrich_envelope()
    envelope.mdot = M_env_dot    # Infall rate
    envelope.rmin = rin          # Inner radius
    envelope.rc   = R_cen        # Centrifugal radius
    envelope.rmax = R_env_max    # Outer radius
    envelope.star = source

    grid = hp.grid.SphericalPolarGrid(ri, thetai, phii)

    rho_env_ulrich = envelope.density(grid).T
    rho_env_ulrich2d = np.sum(rho_env_ulrich**2,axis=2)/np.sum(rho_env_ulrich,axis=2)

    # calculate the full density field

    # Grids and Density
    # Calculation inherited from the script used for RADMC-3D

    # Make the dust density model
    # Make the density profile of the envelope
    #
    print 'Calculating the dust density profile...'
    if theta_cav != 0:
        c0 = (1e4*AU)**(-0.5)*np.sqrt(1/np.sin(np.radians(theta_cav))**3-1/np.sin(np.radians(theta_cav)))
    else:
        c0 = 0
        print 'No cavity is applied'
    rho_tsc  = np.zeros([len(rc),len(thetac),len(phic)])
    rho_ulrich = np.zeros([len(rc),len(thetac),len(phic)])
    rho_disk = np.zeros([len(rc), len(thetac), len(phic)])

    # function for normalizing the disk mass
    def f(w,z,beta,rstar,h100):
        f = 2*PI*w*(1-np.sqrt(rstar/w))*(rstar/w)**(beta+1)*np.exp(-0.5*(z/(w**beta*h100/100**beta))**2)
        return f
    rho_0 = M_disk/(nquad(f,[[R_disk_min,R_disk_max],[-R_env_max,R_env_max]], args=(beta,rstar,h100)))[0]
    #
    total_mass_tsc = 0
    total_mass_ulrich = 0
    #
    for ir in range(0,len(rc)):
        for itheta in range(0,len(thetac)):
            for iphi in range(0,len(phic)):
                if rc[ir] > R_env_min:
                    # Envelope profile
                    w = abs(rc[ir]*np.cos(np.pi/2 - thetac[itheta]))
                    z = rc[ir]*np.sin(np.pi/2 - thetac[itheta])
                    z_cav = c0*abs(w)**1.5
                    if z_cav == 0:
                        z_cav = R_env_max
                    # Cavity
                    if abs(z) > abs(z_cav):
                        # Modification for using density gradient in the cavity
                        # option for using a power law profile without constant region
                        if rho_cav_edge == 0:
                            rho_cav_edge = R_env_min
                        # the rho_cav_center is the dust density calculated from mass loss rate
                        # gas-to-dust ratio of 100 is applied after the whole calculation, therefore need to time 100 now
                        if (rc[ir] <= rho_cav_edge) & (rc[ir] >= R_env_min):
                            rho_env_tsc[ir,itheta,iphi] = 100 * rho_cav_center#*((rc[ir]/AU)**2)
                            rho_env_ulrich[ir,itheta,iphi] = 100 * rho_cav_center
                        else:
                            rho_env_tsc[ir,itheta,iphi] = 100 * rho_cav_center*(rho_cav_edge/rc[ir])**2
                            rho_env_ulrich[ir,itheta,iphi] = 100 * rho_cav_center*(rho_cav_edge/rc[ir])**2

                    # manually calculate the infall-only solution
                    else:
                        mu = abs(np.cos(thetac[itheta]))
                        # Implement new root finding algorithm
                        roots = np.roots(np.array([1.0, 0.0, rc[ir]/R_cen-1.0, -mu*rc[ir]/R_cen]))
                        if len(roots[roots.imag == 0]) == 1:
                            if (abs(roots[roots.imag == 0]) - 1.0) <= 0.0:
                                mu_o_dum = roots[roots.imag == 0]
                            else:
                                mu_o_dum = -0.5
                                print 'Problem with cubic solving, cos(theta) = ', mu_o_dum
                                print 'parameters are ', np.array([1.0, 0.0, rc[ir]/R_cen-1.0, -mu*rc[ir]/R_cen])
                        else:
                            mu_o_dum = -0.5
                            for imu in range(0, len(roots)):
                                if roots[imu]*mu >= 0.0:
                                    if (abs((abs(roots[imu]) - 1.0)) <= 1e-5):
                                        mu_o_dum = 1.0 * np.sign(mu)
                                    else:
                                        mu_o_dum = roots[imu]
                            if mu_o_dum == -0.5:
                                print 'Problem with cubic solving, roots are: ', roots
                        mu_o = mu_o_dum.real
                        rho_env_ulrich[ir,itheta,iphi] = M_env_dot/(4*PI*(G*mstar*R_cen**3)**0.5)*(rc[ir]/R_cen)**(-3./2)*(1+mu/mu_o)**(-0.5)*(mu/mu_o+2*mu_o**2*R_cen/rc[ir])**(-1)

                    # Disk profile
                    if ((w >= R_disk_min) and (w <= R_disk_max)) == True:
                        h = ((w/(100*AU))**beta)*h100
                        rho_disk[ir,itheta,iphi] = rho_0*(1-np.sqrt(rstar/w))*(rstar/w)**(beta+1)*np.exp(-0.5*(z/h)**2)

                    # Combine envelope and disk
                    rho_tsc[ir,itheta,iphi] = rho_disk[ir,itheta,iphi]*0 + rho_env_tsc[ir,itheta,iphi]
                    rho_ulrich[ir,itheta,iphi] = rho_disk[ir,itheta,iphi]*0 + rho_env_ulrich[ir,itheta,iphi]# rho_env_ulrich[ir,itheta,iphi]
                else:
                    rho_tsc[ir,itheta,iphi] = 1e-40
                    rho_ulrich[ir,itheta,iphi] = 1e-40
                # add the dust mass into the total count
                cell_mass_tsc = rho_tsc[ir, itheta, iphi] * (1/3.)*(ri[ir+1]**3 - ri[ir]**3) * (phii[iphi+1]-phii[iphi]) * -(np.cos(thetai[itheta+1])-np.cos(thetai[itheta]))
                total_mass_tsc = total_mass_tsc + cell_mass_tsc

                cell_mass_ulrich = rho_ulrich[ir, itheta, iphi] * (1/3.)*(ri[ir+1]**3 - ri[ir]**3) * (phii[iphi+1]-phii[iphi]) * -(np.cos(thetai[itheta+1])-np.cos(thetai[itheta]))
                total_mass_ulrich = total_mass_ulrich + cell_mass_ulrich

    print total_mass_tsc, total_mass_ulrich
    # create 2d projection
    rho_tsc2d = np.sum(rho_tsc**2,axis=2)/np.sum(rho_tsc,axis=2)
    rho_ulrich2d = np.sum(rho_ulrich**2,axis=2)/np.sum(rho_ulrich,axis=2)

    # print min(rc)/AU, max(rc)/AU

    if plot == True:
        # make plots

        fig = plt.figure(figsize=(8,6))
        ax = fig.add_subplot(111)

        plot_grid = [199]
        # alpha = np.linspace(0.3,1.0,len(plot_grid))
        alpha = [1]
        for i in plot_grid:
            tsc, = ax.plot(np.log10(rc/AU), np.log10(rho_env_tsc2d[:,i]/mh), alpha=alpha[plot_grid.index(i)], color='b', linewidth=2)
            ulrich, = ax.plot(np.log10(rc/AU), np.log10(rho_env_ulrich2d[:,i]/mh), alpha=alpha[plot_grid.index(i)], color='r', linewidth=2)

        rinf = ax.axvline(np.log10(R_inf/AU), linestyle='--', color='k', linewidth=1.5)
        cen_r = ax.axvline(np.log10(R_cen/AU), linestyle=':', color='k', linewidth=1.5)

        ax.legend([tsc, ulrich, rinf, cen_r], [r'$\rm{full\,TSC}$', r'$\rm{infall-only\,TSC}$', r'$\rm{infall\,radius}$', r'$\rm{centrifugal\,radius}$'],\
                  fontsize=16, numpoints=1, loc='lower center')

        ax.set_ylim([0, 15])
        ax.set_xlim(left=np.log10(d_sub/AU))
        ax.set_xlabel(r'$\rm{log(radius)\,[AU]}$', fontsize=18)
        ax.set_ylabel(r'$\rm{log(gas\,density)\,[g\,cm^{-3}]}$', fontsize=18)
        [ax.spines[axis].set_linewidth(1.5) for axis in ['top','bottom','left','right']]
        ax.minorticks_on()
        ax.tick_params('both',labelsize=18,width=1.5,which='major',pad=15,length=5)
        ax.tick_params('both',labelsize=18,width=1.5,which='minor',pad=15,length=2.5)

        # fix the tick label font
        ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',size=18)
        for label in ax.get_xticklabels():
            label.set_fontproperties(ticks_font)
        for label in ax.get_yticklabels():
            label.set_fontproperties(ticks_font)

        fig.savefig('/Users/yaolun/test/tsc_comparison.pdf', format='pdf', dpi=300, bbox_inches='tight')

    return rho_tsc/100, rho_ulrich/100
コード例 #13
0
ファイル: models.py プロジェクト: mjrfringes/SED_Modeling
	def initModel(self):
		### Use Tracy parameter file to set up the model 
		self.dust_gen(self.dustfile,self.dustfile_out)
		mi = AnalyticalYSOModel()

		mi.star.temperature = self.T
		mi.star.mass = self.M_sun
		mi.star.luminosity = self.L_sun
		mi.star.radius=np.sqrt(mi.star.luminosity/(4.0*np.pi*sigma*mi.star.temperature**4))
		#m.star.luminosity = 4.0*np.pi*m.star.radius**2*sigma*m.star.temperature**4
		print mi.star.luminosity/lsun
		self.luminosity=mi.star.luminosity/lsun

		if self.disk=="Flared":
			print "Adding flared disk"
			disk = mi.add_flared_disk()
			disk.dust=self.d
			if self.dustfile == 'd03_5.5_3.0_A.hdf5':
				disk.mass=self.disk_mass/100.
			else: disk.mass=self.disk_mass
			disk.rmin=OptThinRadius(1600) #self.disk_rmin
			print "disk.rmin = ",disk.rmin,disk.rmin/au
			disk.rmax=self.disk_rmax
			disk.r_0 = self.disk_rmin
			disk.h_0 = disk.r_0/10. #self.disk_h_0*au
			disk.beta=self.beta
			disk.p = -1.
		elif self.disk=="Alpha":
			print "Adding alpha disk"
			disk = mi.add_alpha_disk()
			disk.dust=self.d
			if self.dustfile == 'd03_5.5_3.0_A.hdf5':
				disk.mass=self.disk_mass/100.
			else: disk.mass=self.disk_mass
			disk.rmin=OptThinRadius(1600)
			disk.rmax=self.disk_rmax
			disk.r_0 = self.disk_rmin
			disk.h_0 = disk.r_0/10. #self.disk_h_0*au
			disk.beta=1.1
			disk.p = -1
			disk.mdot=self.mdot
			disk.star = mi.star
			
		#print 'Disk density:',disk.rho_0

		
		if self.env==True and self.env_type=='power':
			envelope=mi.add_power_law_envelope()
			envelope.dust=self.d_out
			envelope.r_0=self.env_rmin
			#envelope.r_0 = OptThinRadius(1600)
			if self.dustfile_out == 'd03_5.5_3.0_A.hdf5':
				envelope.mass=self.env_mass/100.
			else: envelope.mass=self.env_mass
			envelope.rmin=self.env_rmin
			envelope.rmax=self.env_rmax
			envelope.power=self.env_power
			#print 'Envelope rho:',envelope.rho_0
		elif self.env==True and self.env_type=='ulrich':
			envelope=mi.add_ulrich_envelope()
			envelope.dust=self.d_out
			envelope.mdot=1e-6*msun/yr # has little impact on the fluxes, so fixed
			envelope.rc=self.rc
			envelope.rmin=self.env_rmin
			envelope.rmax=self.env_rmax
		if self.env==True:
			self.env_rho_0 = envelope.rho_0
			print 'Envelope rho:',envelope.rho_0

		#print "Rho_0 = ",envelope.rho_0
		if self.cav==True:
			cavity=envelope.add_bipolar_cavity()
			cavity.dust=self.d_out
			cavity.power=1.5
			cavity.cap_to_envelope_density=True ### prevents the cavity density to go above the envelope's density
			cavity.r_0=self.cav_r0
			cavity.theta_0=self.cav_theta
			cavity.rho_0=self.cav_rho_0 #in g/cm^3
			cavity.rho_exp=0.0
			
		
#		if self.env==True:
#			ambient=mi.add_ambient_medium(subtract=[envelope,disk])
#		if self.dustfile_out == 'd03_5.5_3.0_A.hdf5':
#			ambient.rho=self.amb_dens/100.
#		else: ambient.rho=self.amb_dens
#		ambient.rmin=OptThinRadius(1600.)
#		ambient.rmax=self.env_rmax
#		ambient.dust=self.d_out
		

		'''*** Grid parameters ***'''
		mi.set_spherical_polar_grid_auto(199,49,1)

		# Specify that the specific energy and density are needed
		mi.conf.output.output_specific_energy = 'last'
		mi.conf.output.output_density = 'last'


		'''**** Output Data ****'''
		image = mi.add_peeled_images(sed=True,image=False)
		image.set_wavelength_range(150,1,3000)
		#image.set_image_size(self.Npix,self.Npix)
		#image.set_image_limits(-self.limval,self.limval,-self.limval,self.limval)
		image.set_aperture_range(1,100000.*au,100000.*au)
		image.set_viewing_angles(self.angles,self.angles2)
		#image.set_track_origin('detailed')
		image.set_uncertainties(True)

		''' Use the modified random walk
		*** Advanced ***'
		YES = DIFFUSION  = Whether to use the diffusion
		'''
		if self.env==True:
			#mi.set_pda(True)
			mi.set_mrw(True)
		else:
			mi.set_pda(False)
			mi.set_mrw(False)

		# Use raytracing to improve s/n of thermal/source emission
		mi.set_raytracing(True)


		'''**** Preliminaries ****'''
		mi.set_n_initial_iterations(5)
		mi.set_n_photons(initial=1e6,imaging=1e6,raytracing_sources=1e5,raytracing_dust=1e6)
		mi.set_convergence(True, percentile=99.0, absolute=2.0, relative=1.1)
		self.m = mi
コード例 #14
0
ファイル: tsc_comparison.py プロジェクト: yaolun/misc
def tsc_com(params_table, plot=True, disk=False):
    import numpy as np
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    from matplotlib.colors import LogNorm
    import astropy.constants as const
    import os
    import scipy as sci
    from scipy.optimize import fsolve
    from scipy.optimize import newton
    from scipy.integrate import nquad
    import sys
    sys.path.append("/Users/yaolun/programs/misc/hyperion/")
    from input_reader import input_reader_table
    home = os.path.expanduser('~')

    # read the TSC model
    # Constant Setup
    #
    AU = 1.49598e13  # Astronomical Unit       [cm]
    pc = 3.08572e18  # Parsec                  [cm]
    MS = 1.98892e33  # Solar mass              [g]
    LS = 3.8525e33  # Solar luminosity        [erg/s]
    RS = 6.96e10  # Solar radius            [cm]
    G = 6.67259e-8  # Gravitational constant  [cm3/g/s^2]
    yr = 60 * 60 * 24 * 365  # Years in seconds
    PI = np.pi  # PI constant
    sigma = const.sigma_sb.cgs.value  # Stefan-Boltzmann constant
    mh = const.m_p.cgs.value + const.m_e.cgs.value

    # read parameter from input_table
    # params_table = '/Users/yaolun/programs/misc/hyperion/test_input.txt'
    params = input_reader_table(params_table)[0]
    # force omega = 4.1e-13 to emphasize the difference
    # params['Omega0'] = 4.1e-13
    #
    rstar = params['rstar'] * RS
    tstar = params['tstar']
    R_env_max = params['R_env_max'] * AU
    T_sub = 1600
    a = 1  #in micron
    d_sub = (LS / 16. / np.pi / sigma / AU**2 *
             (4 * np.pi * rstar**2 * sigma * tstar**4 / LS) /
             T_sub**4)**0.5 * AU
    R_env_min = d_sub
    R_cen = params['Omega0']**2 * G**3 * (0.975 * (params['Cs'] * 1e5)**3 / G *
                                          params['age'] *
                                          yr)**3 / (16 *
                                                    (params['Cs'] * 1e5)**8)
    R_inf = params['Cs'] * 1e5 * params['age'] * yr
    R_disk_min = d_sub
    R_disk_max = R_cen
    theta_cav = params['theta_cav']
    beta = params['beta']
    h100 = params['h100'] * AU
    M_env_dot = 0.975 * (params['Cs'] * 1e5)**3 / G
    M_disk = params['M_disk'] * MS
    mstar = M_env_dot * params['age'] * yr
    rin = rstar
    rout = R_env_max
    rho_cav_center = params['rho_cav_center']
    rho_cav_edge = params['rho_cav_edge'] * AU

    # Grid Parameters
    nx = 100L
    ny = 400L
    nz = 50L

    # Make the Coordinates
    #
    ri = rin * (rout / rin)**(np.arange(nx + 1).astype(dtype='float') /
                              float(nx))
    ri = np.hstack((0.0, ri))
    thetai = PI * np.arange(ny + 1).astype(dtype='float') / float(ny)
    phii = PI * 2.0 * np.arange(nz + 1).astype(dtype='float') / float(nz)

    # Keep the constant cell size in r-direction
    #

    ri_cellsize = ri[1:-1] - ri[0:-2]
    ind = np.where(
        ri_cellsize / AU > 100.0)[0][0]  # The largest cell size is 100 AU
    ri = np.hstack(
        (ri[0:ind], ri[ind] + np.arange(np.ceil(
            (rout - ri[ind]) / 100 / AU)) * 100 * AU))
    nx = len(ri) - 1

    # Assign the coordinates of the center of cell as its coordinates.
    #
    rc = 0.5 * (ri[0:nx] + ri[1:nx + 1])
    thetac = 0.5 * (thetai[0:ny] + thetai[1:ny + 1])
    phic = 0.5 * (phii[0:nz] + phii[1:nz + 1])

    if disk == False:
        rho_env_tsc_idl = np.genfromtxt(
            '/Users/yaolun/test/model32_rhoenv.dat').T
    else:
        rho_env_tsc_idl = np.genfromtxt(
            '/Users/yaolun/test/model32_rhoenv.dat').T

    rc_idl = rc[(rc < min([R_inf, max(ri)]))]

    # because only region within infall radius is calculated by IDL program, need to project it to the original grid
    rho_env_tsc = np.zeros([len(rc), len(thetac)])
    for irc in range(len(rc)):
        if rc[irc] in rc_idl:
            rho_env_tsc[irc, :] = rho_env_tsc_idl[np.where(
                rc_idl == rc[irc]), :]

    # extrapolate for the NaN values at the outer radius, usually at radius beyond the infall radius
    # using r^-2 profile at radius greater than infall radius
    # and map the 2d strcuture onto 3d grid
    def poly(x, y, x0, deg=2):
        import numpy as np
        p = np.polyfit(x, y, deg)
        y0 = 0
        for i in range(0, len(p)):
            y0 = y0 + p[i] * x0**(len(p) - i - 1)
        return y0

    # map TSC solution from IDL to actual 2-D grid
    rho_env_tsc2d = np.empty((nx, ny))
    if max(ri) > R_inf:
        ind_infall = np.where(rc <= R_inf)[0][-1]
        for i in range(0, len(rc)):
            if i <= ind_infall:
                rho_env_tsc2d[i, :] = rho_env_tsc[i, :]
            else:
                rho_env_tsc2d[i, :] = 10**(
                    np.log10(rho_env_tsc[ind_infall, :]) - 2 *
                    (np.log10(rc[i] / rc[ind_infall])))
    else:
        rho_env_tsc2d = rho_env_tsc
    # map it to 3-D grid
    rho_env_tsc = np.empty((nx, ny, nz))
    for i in range(0, nz):
        rho_env_tsc[:, :, i] = rho_env_tsc2d

    # calculate the infall-only solution

    import hyperion as hp
    from hyperion.model import Model
    from hyperion.model import AnalyticalYSOModel

    m = AnalyticalYSOModel()

    # Define the luminsoity source
    source = m.add_spherical_source()
    source.luminosity = (4 * PI * rstar**2) * sigma * (tstar**4)  # [ergs/s]
    source.radius = rstar  # [cm]
    source.temperature = tstar  # [K]
    source.position = (0., 0., 0.)
    source.mass = mstar
    print 'L_center =  % 5.2f L_sun' % ((4 * PI * rstar**2) * sigma *
                                        (tstar**4) / LS)

    # Envelope structure
    #
    envelope = m.add_ulrich_envelope()
    envelope.mdot = M_env_dot  # Infall rate
    envelope.rmin = rin  # Inner radius
    envelope.rc = R_cen  # Centrifugal radius
    envelope.rmax = R_env_max  # Outer radius
    envelope.star = source

    grid = hp.grid.SphericalPolarGrid(ri, thetai, phii)

    rho_env_ulrich = envelope.density(grid).T
    rho_env_ulrich2d = np.sum(rho_env_ulrich**2, axis=2) / np.sum(
        rho_env_ulrich, axis=2)

    # calculate the full density field

    # Grids and Density
    # Calculation inherited from the script used for RADMC-3D

    # Make the dust density model
    # Make the density profile of the envelope
    #
    print 'Calculating the dust density profile...'
    if theta_cav != 0:
        c0 = (1e4 *
              AU)**(-0.5) * np.sqrt(1 / np.sin(np.radians(theta_cav))**3 -
                                    1 / np.sin(np.radians(theta_cav)))
    else:
        c0 = 0
        print 'No cavity is applied'
    rho_tsc = np.zeros([len(rc), len(thetac), len(phic)])
    rho_ulrich = np.zeros([len(rc), len(thetac), len(phic)])
    rho_disk = np.zeros([len(rc), len(thetac), len(phic)])

    # function for normalizing the disk mass
    def f(w, z, beta, rstar, h100):
        f = 2 * PI * w * (1 - np.sqrt(rstar / w)) * (rstar / w)**(
            beta + 1) * np.exp(-0.5 * (z / (w**beta * h100 / 100**beta))**2)
        return f

    rho_0 = M_disk / (nquad(
        f, [[R_disk_min, R_disk_max], [-R_env_max, R_env_max]],
        args=(beta, rstar, h100)))[0]
    #
    total_mass_tsc = 0
    total_mass_ulrich = 0
    #
    for ir in range(0, len(rc)):
        for itheta in range(0, len(thetac)):
            for iphi in range(0, len(phic)):
                if rc[ir] > R_env_min:
                    # Envelope profile
                    w = abs(rc[ir] * np.cos(np.pi / 2 - thetac[itheta]))
                    z = rc[ir] * np.sin(np.pi / 2 - thetac[itheta])
                    z_cav = c0 * abs(w)**1.5
                    if z_cav == 0:
                        z_cav = R_env_max
                    # Cavity
                    if abs(z) > abs(z_cav):
                        # Modification for using density gradient in the cavity
                        # option for using a power law profile without constant region
                        if rho_cav_edge == 0:
                            rho_cav_edge = R_env_min
                        # the rho_cav_center is the dust density calculated from mass loss rate
                        # gas-to-dust ratio of 100 is applied after the whole calculation, therefore need to time 100 now
                        if (rc[ir] <= rho_cav_edge) & (rc[ir] >= R_env_min):
                            rho_env_tsc[
                                ir, itheta,
                                iphi] = 100 * rho_cav_center  #*((rc[ir]/AU)**2)
                            rho_env_ulrich[ir, itheta,
                                           iphi] = 100 * rho_cav_center
                        else:
                            rho_env_tsc[ir, itheta,
                                        iphi] = 100 * rho_cav_center * (
                                            rho_cav_edge / rc[ir])**2
                            rho_env_ulrich[ir, itheta,
                                           iphi] = 100 * rho_cav_center * (
                                               rho_cav_edge / rc[ir])**2

                    # manually calculate the infall-only solution
                    else:
                        mu = abs(np.cos(thetac[itheta]))
                        # Implement new root finding algorithm
                        roots = np.roots(
                            np.array([
                                1.0, 0.0, rc[ir] / R_cen - 1.0,
                                -mu * rc[ir] / R_cen
                            ]))
                        if len(roots[roots.imag == 0]) == 1:
                            if (abs(roots[roots.imag == 0]) - 1.0) <= 0.0:
                                mu_o_dum = roots[roots.imag == 0]
                            else:
                                mu_o_dum = -0.5
                                print 'Problem with cubic solving, cos(theta) = ', mu_o_dum
                                print 'parameters are ', np.array([
                                    1.0, 0.0, rc[ir] / R_cen - 1.0,
                                    -mu * rc[ir] / R_cen
                                ])
                        else:
                            mu_o_dum = -0.5
                            for imu in range(0, len(roots)):
                                if roots[imu] * mu >= 0.0:
                                    if (abs((abs(roots[imu]) - 1.0)) <= 1e-5):
                                        mu_o_dum = 1.0 * np.sign(mu)
                                    else:
                                        mu_o_dum = roots[imu]
                            if mu_o_dum == -0.5:
                                print 'Problem with cubic solving, roots are: ', roots
                        mu_o = mu_o_dum.real
                        rho_env_ulrich[ir, itheta, iphi] = M_env_dot / (
                            4 * PI *
                            (G * mstar * R_cen**3)**0.5) * (rc[ir] / R_cen)**(
                                -3. / 2) * (1 + mu / mu_o)**(-0.5) * (
                                    mu / mu_o +
                                    2 * mu_o**2 * R_cen / rc[ir])**(-1)

                    # Disk profile
                    if ((w >= R_disk_min) and (w <= R_disk_max)) == True:
                        h = ((w / (100 * AU))**beta) * h100
                        rho_disk[ir, itheta,
                                 iphi] = rho_0 * (1 - np.sqrt(rstar / w)) * (
                                     rstar / w)**(beta + 1) * np.exp(
                                         -0.5 * (z / h)**2)

                    # Combine envelope and disk
                    rho_tsc[ir, itheta, iphi] = rho_disk[
                        ir, itheta, iphi] * 0 + rho_env_tsc[ir, itheta, iphi]
                    rho_ulrich[ir, itheta, iphi] = rho_disk[
                        ir, itheta, iphi] * 0 + rho_env_ulrich[
                            ir, itheta, iphi]  # rho_env_ulrich[ir,itheta,iphi]
                else:
                    rho_tsc[ir, itheta, iphi] = 1e-40
                    rho_ulrich[ir, itheta, iphi] = 1e-40
                # add the dust mass into the total count
                cell_mass_tsc = rho_tsc[ir, itheta, iphi] * (1 / 3.) * (
                    ri[ir + 1]**3 - ri[ir]**3) * (
                        phii[iphi + 1] - phii[iphi]
                    ) * -(np.cos(thetai[itheta + 1]) - np.cos(thetai[itheta]))
                total_mass_tsc = total_mass_tsc + cell_mass_tsc

                cell_mass_ulrich = rho_ulrich[ir, itheta, iphi] * (1 / 3.) * (
                    ri[ir + 1]**3 - ri[ir]**3) * (
                        phii[iphi + 1] - phii[iphi]
                    ) * -(np.cos(thetai[itheta + 1]) - np.cos(thetai[itheta]))
                total_mass_ulrich = total_mass_ulrich + cell_mass_ulrich

    print total_mass_tsc, total_mass_ulrich
    # create 2d projection
    rho_tsc2d = np.sum(rho_tsc**2, axis=2) / np.sum(rho_tsc, axis=2)
    rho_ulrich2d = np.sum(rho_ulrich**2, axis=2) / np.sum(rho_ulrich, axis=2)

    # print min(rc)/AU, max(rc)/AU

    if plot == True:
        # make plots

        fig = plt.figure(figsize=(8, 6))
        ax = fig.add_subplot(111)

        plot_grid = [199]
        # alpha = np.linspace(0.3,1.0,len(plot_grid))
        alpha = [1]
        for i in plot_grid:
            tsc, = ax.plot(np.log10(rc / AU),
                           np.log10(rho_env_tsc2d[:, i] / mh),
                           alpha=alpha[plot_grid.index(i)],
                           color='b',
                           linewidth=2)
            ulrich, = ax.plot(np.log10(rc / AU),
                              np.log10(rho_env_ulrich2d[:, i] / mh),
                              alpha=alpha[plot_grid.index(i)],
                              color='r',
                              linewidth=2)

        rinf = ax.axvline(np.log10(R_inf / AU),
                          linestyle='--',
                          color='k',
                          linewidth=1.5)
        cen_r = ax.axvline(np.log10(R_cen / AU),
                           linestyle=':',
                           color='k',
                           linewidth=1.5)

        ax.legend([tsc, ulrich, rinf, cen_r], [r'$\rm{full\,TSC}$', r'$\rm{infall-only\,TSC}$', r'$\rm{infall\,radius}$', r'$\rm{centrifugal\,radius}$'],\
                  fontsize=16, numpoints=1, loc='lower center')

        ax.set_ylim([0, 15])
        ax.set_xlim(left=np.log10(d_sub / AU))
        ax.set_xlabel(r'$\rm{log(radius)\,[AU]}$', fontsize=18)
        ax.set_ylabel(r'$\rm{log(gas\,density)\,[g\,cm^{-3}]}$', fontsize=18)
        [
            ax.spines[axis].set_linewidth(1.5)
            for axis in ['top', 'bottom', 'left', 'right']
        ]
        ax.minorticks_on()
        ax.tick_params('both',
                       labelsize=18,
                       width=1.5,
                       which='major',
                       pad=15,
                       length=5)
        ax.tick_params('both',
                       labelsize=18,
                       width=1.5,
                       which='minor',
                       pad=15,
                       length=2.5)

        # fix the tick label font
        ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',
                                                     size=18)
        for label in ax.get_xticklabels():
            label.set_fontproperties(ticks_font)
        for label in ax.get_yticklabels():
            label.set_fontproperties(ticks_font)

        fig.savefig('/Users/yaolun/test/tsc_comparison.pdf',
                    format='pdf',
                    dpi=300,
                    bbox_inches='tight')

    return rho_tsc / 100, rho_ulrich / 100
コード例 #15
0
import numpy as np

from hyperion.model import AnalyticalYSOModel
from hyperion.util.constants import rsun, lsun, au, msun, yr, c

# Initalize the model
m = AnalyticalYSOModel()

# Read in stellar spectrum
wav, fnu = np.loadtxt('kt04000g+3.5z-2.0.ascii', unpack=True)
nu = c / (wav * 1.e-4)

# Set the stellar parameters
m.star.radius = 2.09 * rsun
m.star.spectrum = (nu, fnu)
m.star.luminosity = lsun
m.star.mass = 0.5 * msun

# Add a flared disk
disk = m.add_flared_disk()
disk.mass = 0.01 * msun
disk.rmin = 7 * m.star.radius
disk.rmax = 200 * au
disk.r_0 = m.star.radius
disk.h_0 = 0.01 * disk.r_0
disk.p = -1.0
disk.beta = 1.25
disk.dust = 'kmh_lite.hdf5'

# Add an Ulrich envelope
envelope = m.add_ulrich_envelope()
コード例 #16
0
def ShellThree_Only(dust_file_name, fnu, nu, stellar_luminoisity, stellar_temperature,  stellar_radius, total_shell_mass, uant_distance, expansion_velocity, MaxCSE_outer_rad, Photon_Number, CPU_Number):

	# Initalize the model
	model = AnalyticalYSOModel() #We use the YSO model with modified parameters to match an AGB star with a detached shell

	# Set the stellar parameters
	model.star.spectrum = (nu, fnu)
	model.star.luminosity = stellar_luminoisity
	#model.star.mass = 2 * msun #Guesstimate 1.3 - 3 Msun #Not needed for RT modelling normally. Very difficult to estimate.
	model.star.radius = stellar_radius


	#Power-law spherically symmetric envelope - Only Detached Shell - Need to add constant outflow envelope on top of this to account for the ML after the thermal pulse. 
	envelope_shell = model.add_power_law_envelope()
	envelope_shell.mass = total_shell_mass          
	envelope_shell.rmin = (41.5 * uant_distance) * au          # Shell 3 inner radius converted to au - from GD+2001&2003 AND M2010
	envelope_shell.rmax = (44.5 * uant_distance) * au          # Shell 3 outer radius converted to au - from GD+2001&2003 AND M2010
	envelope_shell.r_0 = envelope_shell.rmin
	envelope_shell.power = -2                        # Radial power #Constant Outflow envelope
	envelope_shell.dust =  dust_file_name #Using a standard Hyperion Dust model. Needs to be modified a lot for U Ant

	envelope_CSE_Max = (MaxCSE_outer_rad * uant_distance) * au    # Outer radius- estimating the total emission will be ~ this radius - pre&post thermal pulse. Units = cm


	# Set up grid to run the model on
	model.set_spherical_polar_grid_auto(100, 1, 1) #(n_r, n_theta, n_phi) - in a spherical envelope theta and phi are uniform and 1. n_r = number of r radii to seperate the grid to. 


	# Use raytracing to improve s/n of thermal/source emission
	model.set_raytracing(raytracing=True)

	# Set up SED - Get SED output
	sed = model.add_peeled_images(sed=True, image=False)
	sed.set_uncertainties(uncertainties=True)
	sed.set_viewing_angles([45], [45]) #(np.linspace(0., 90., 10), np.repeat(45., 10)) #Veiw the source at 45degrees from the pole and theta = 45
	sed.set_wavelength_range(100, 0.3, 1200.) #(n_wav, wav_min, wav_max) #Get the SED from 1micron to 2000micron in 100 wavelengths

	#Set up Image - Get image output - RT calculated for bins of wavelengths - PACS 70
	image_70 = model.add_peeled_images(sed=False, image=True)
	image_70.set_uncertainties(uncertainties=True)
	image_70.set_viewing_angles([45], [45]) #(np.linspace(0., 90., 10), np.repeat(45., 10)) #Veiw the source at 45degrees from the pole and theta = 45
	image_70.set_wavelength_range(30, 60, 90) #(n_wav, wav_min, wav_max) - PACS 70 filter profile limits 60 - 90 and get 30 image cube to get images at ~1 micron per image 
	image_70.set_image_size(400, 400) #Size of image in pixels
	image_70.set_image_limits(-1.5 * envelope_CSE_Max, 1.5 * envelope_CSE_Max, -1.5 * envelope_CSE_Max, 1.5 * envelope_CSE_Max)

	#Set up Image - Get image output - RT calculated for bins of wavelengths - PACS 160
	image_160 = model.add_peeled_images(sed=False, image=True)
	image_160.set_uncertainties(uncertainties=True)
	image_160.set_viewing_angles([45], [45]) #(np.linspace(0., 90., 10), np.repeat(45., 10)) #Veiw the source at 45degrees from the pole and theta = 45
	image_160.set_wavelength_range(30, 130, 220) #(n_wav, wav_min, wav_max) - PACS 160 filter profile limits 130 - 220 and get 30 image cube to get images at ~3 micron per image  
	image_160.set_image_size(400, 400) #Size of image in pixels
	image_160.set_image_limits(-1.5 * envelope_CSE_Max, 1.5 * envelope_CSE_Max, -1.5 * envelope_CSE_Max, 1.5 * envelope_CSE_Max)

	#Set up Image - Get image output - RT calculated for bins of wavelengths - SCUBA-2 450
	image_450 = model.add_peeled_images(sed=False, image=True)
	image_450.set_uncertainties(uncertainties=True)
	image_450.set_viewing_angles([45], [45]) #(np.linspace(0., 90., 10), np.repeat(45., 10)) #Veiw the source at 45degrees from the pole and theta = 45
	image_450.set_wavelength_range(30, 410, 480) #(n_wav, wav_min, wav_max) -  - SCUBA-2 450 filter profile limits 790 - 940 and get 30 image cube to get images at ~2 micron per image 
	image_450.set_image_size(400, 400) #Size of image in pixels
	image_450.set_image_limits(-1.5 * envelope_CSE_Max, 1.5 * envelope_CSE_Max, -1.5 * envelope_CSE_Max, 1.5 * envelope_CSE_Max)

	#Set up Image - Get image output - RT calculated for bins of wavelengths - SCUBA-2 850
	image_850 = model.add_peeled_images(sed=False, image=True)
	image_850.set_uncertainties(uncertainties=True)
	image_850.set_viewing_angles([45], [45]) #(np.linspace(0., 90., 10), np.repeat(45., 10)) #Veiw the source at 45degrees from the pole and theta = 45
	image_850.set_wavelength_range(30, 790, 940) #(n_wav, wav_min, wav_max) - SCUBA-2 850 filter profile limits 790 - 940 and get 30 image cube to get images at ~5 micron per image 
	image_850.set_image_size(400, 400) #Size of image in pixels
	image_850.set_image_limits(-1.5 * envelope_CSE_Max, 1.5 * envelope_CSE_Max, -1.5 * envelope_CSE_Max, 1.5 * envelope_CSE_Max)


	# Set number of photons
	model.set_n_photons(initial=Photon_Number, imaging=Photon_Number, raytracing_sources=Photon_Number, raytracing_dust=Photon_Number)

	# Set number of temperature iterations and convergence criterion
	model.set_n_initial_iterations(5)
	model.set_convergence(True, percentile=99.0, absolute=2.0, relative=1.1)

	# Write out file
	Input_ShellThree_Only = 'Model_ShellThree_Only.rtin' #File which saves all the input above so that fortran can run internally for RT modelling
	Output_ShellThree_Only = 'Model_ShellThree_Only.rtout'
	
	model.write(Input_ShellThree_Only)
	model.run(Output_ShellThree_Only, mpi=True, n_processes=CPU_Number)

	return Input_ShellThree_Only, Output_ShellThree_Only
コード例 #17
0
ファイル: test_disc.py プロジェクト: koepferl/cylindrical
from hyperion.model import AnalyticalYSOModel
from hyperion.util.constants import pc, lsun, rsun, msun, au,pi
from hyperion.model import ModelOutput
import numpy as np

m = AnalyticalYSOModel()
m.set_n_photons(initial=100000, imaging=100000)
m.star.luminosity = 5 * lsun
m.star.radius = 2 * rsun
m.star.temperature = 6000.

disk = m.add_flared_disk()
disk.mass = 0.01 * msun             # Disk mass
disk.rmin = 10 * rsun               # Inner radius
disk.rmax = 300 * au                # Outer radius
disk.r_0 = 100. * au                # Radius at which h_0 is defined
disk.h_0 = 5 * au                   # Disk scaleheight at r_0
disk.p = -1                         # Radial surface density exponent
disk.beta = 1.25                    # Disk flaring power

#envelope = m.add_power_law_envelope()
#envelope.mass = 0.001 * msun          # Envelope mass
#envelope.rmin = au                  # Inner radius
#envelope.rmax = 10000 * au          # Outer radius
#envelope.power = -2                 # Radial power
#envelope.r_0 = au                   # Inner density radius

#dust
disk.dust = 'www003.hdf5'
#envelope.dust = 'kmh.hdf5'
#cavity.dust = 'kmh_hdf5'
コード例 #18
0
ファイル: class2_sed_setup.py プロジェクト: nj22/hyperion
import numpy as np

from hyperion.model import AnalyticalYSOModel
from hyperion.util.constants import rsun, au, msun, sigma

# Initalize the model
m = AnalyticalYSOModel()

# Set the stellar parameters
m.star.radius = 2.0 * rsun
m.star.temperature = 4000.0
m.star.luminosity = 4 * (2.0 * rsun) ** 2 * sigma * 4000 ** 4

# Add a flared disk
disk = m.add_flared_disk()
disk.mass = 0.01 * msun
disk.rmin = 10 * m.star.radius
disk.rmax = 200 * au
disk.r_0 = m.star.radius
disk.h_0 = 0.01 * disk.r_0
disk.p = -1.0
disk.beta = 1.25
disk.dust = "kmh_lite.hdf5"

# Use raytracing to improve s/n of thermal/source emission
m.set_raytracing(True)

# Use the modified random walk
m.set_mrw(True, gamma=2.0)

# Set up grid