def spire_postprocess1(indir, outdir, obsid, obj): """ Dedicated for 1-D spectra analysis. convert the ASCII format of the spectra to a better format for reading, and perform spectrum trimming. """ from astropy.io import ascii, fits import numpy as np # read in the spectrum spire_spec = ascii.read(indir + obsid + 'spire_sect.txt', data_start=4) # convert it to the usual format spire_wl = np.hstack(( spire_spec['wave_segm1_0'][spire_spec['wave_segm1_0'] >= 310].data, spire_spec['wave_segm2_0'][(spire_spec['wave_segm2_0'] < 310) & (spire_spec['wave_segm2_0'] > 195)].data)) spire_flux = np.hstack(( spire_spec['flux_segm1_0'][spire_spec['wave_segm1_0'] >= 310].data, spire_spec['flux_segm2_0'][(spire_spec['wave_segm2_0'] < 310) & (spire_spec['wave_segm2_0'] > 195)].data)) sorter = np.argsort(spire_wl) spire_wl = spire_wl[sorter].data spire_flux = spire_flux[sorter].data # Write to file foo = open(outdir + obj + '/spire/data/' + obj + '_spire_corrected.txt', 'w') foo.write('%s \t %s \n' % ('Wavelength(um)', 'Flux_Density(Jy)')) for i in range(len(spire_wl)): foo.write('%f \t %f \n' % (spire_wl[i], spire_flux[i])) foo.close() # perform line fitting import pidly # grad13yy # idl = pidly.IDL('/Applications/exelis/idl83/bin/idl') # bettyjo idl = pidly.IDL('/opt/local/exelis/idl83/bin/idl') idl('.r ' + os.path.expanduser('~') + '/programs/line_fitting/extract_spire.pro') # read the coordinates from cube fits file hdu = fits.open(obsid + '_spectrum_extended_HR_aNB_15.fits') ra = hdu[0].header['RA'] dec = hdu[0].header['DEC'] idl.pro('extract_spire', indir=outdir + obj + '/spire/data/', filename=obj + '_spire_corrected', outdir=outdir + obj + '/spire/advanced_products/', plotdir=outdir + obj + '/spire/advanced_products/plots/', localbaseline=10, global_noise=20, ra=ra, dec=dec, noiselevel=3, fx=1, object=obj, flat=1, continuum=1, double_gauss=1, no_plot=0)
def sheq_averages(shot, time, return_all=False): """ Returns flux-surface averaged quantities of physical significance. Inputs: - shot = MST shot number, corresponding to an existing NCT run. - time = Time point in ms, corresponding to an existing NCT run. - return_all = Set to True to instead return the full sh_averages.pro structure. """ idl = pidly.IDL() idl('.r /home/pdvanmeter/lib/idl/startup.pro') idl('.r run_sheq') idl('averages = sheq_flux_avg({0:}, {1:})'.format(shot, time)) avg = AttrDict(idl.ev('averages')) idl.close() if return_all: return avg else: return AttrDict({ 'rhop':avg.rhop, 'rhoh':avg.rhoh, 'J_pol':avg.jpol/1e6, 'J_tor':avg.jtor/1e6, 'B_pol':avg.bpol, 'B_tor':avg.btor, 'B':avg.b, 'B2':avg.b2, 'JB':-avg.jb/1e6, 'J_para':-avg.jb/avg.b/1e6, 'mua':-avg.mua, 'q':-avg.q, 'delta':float(avg.delta_axis) })
def get_flux(burst_data, t, ftopt, band): ''' do this in the burst#_fitting folder. burst_data = file path to the burst_data.dat file containing photometry t = time in seconds you wish to obtain the flux ftopt = file path to the ftopt fitting parameter file band = string of desired band (J, H, or K) ''' band = band.upper() #making sure band in upper case import pidly idl_path = '/Applications/itt/idl71/bin/idl' idl = pidly.IDL(idl_path) #Performing Fit IDL_command = "lcurve, '" + str( burst_data) + "', reffilt='J', ftopt='" + str( ftopt) + "', timeunit='sec', yr=[21,12], tspec=" + str( t) + "., captionfmt='(F6.2)', /residual" idl(IDL_command) #Read the filename filename = burst_data.rstrip('.dat') + 'datased.dat' f = open(filename, 'r') lines = f.readlines() for line in lines: if band in line: flux = (line.split()[1], line.split()[2]) return flux
def kelly(x1, x2, x1err=[], x2err=[], cerr=[], logify=True, miniter=5000, maxiter=1e5, metro=True, silent=True): """ Python wrapper for the linear regression MCMC of Kelly (2007). Requires pidly (http://astronomy.sussex.ac.uk/~anthonys/pidly/) and an IDL license. Parameters ---------- x1 : array of floats Independent variable, or observable x2 : array of floats Dependent variable x1err : array of floats (optional) Uncertainties on the independent variable x2err : array of floats (optional) Uncertainties on the dependent variable cerr : array of floats (optional) Covariances of the uncertainties in the dependent and independent variables """ import pidly n = len(x1) if len(x2) != n: raise ValueError('x1 and x2 must have same length') if len(x1err) == 0: x1err = numpy.zeros(n) if len(x2err) == 0: x2err = numpy.zeros(n) if logify: x1, x2, x1err, x2err = to_log(x1, x2, x1err, x2err) idl = pidly.IDL() idl('x1 = %s' %list(x1)) idl('x2 = %s' %list(x2)) cmd = 'linmix_err, x1, x2, fit' if len(x1err) == n: idl('x1err = %s' %list(x1err)) cmd += ', xsig=x1err' if len(x2err) == n: idl('x2err = %s' %list(x2err)) cmd += ', ysig=x2err' if len(cerr) == n: idl('cerr = %s' %list(cerr)) cmd += ', xycov=cerr' cmd += ', miniter=%d, maxiter=%d' %(miniter, maxiter) if metro: cmd += ', /metro' if silent: cmd += ', /silent' idl(cmd) alpha = idl.ev('fit.alpha') beta = idl.ev('fit.beta') sigma = numpy.sqrt(idl.ev('fit.sigsqr')) return alpha, beta, sigma
def find(fits_file,thresh=100, fwhm=18 ): idl = pidly.IDL() idl('.compile find') idl('.compile fits_read') idl('fits_read, "'+fits_file+'", im, hdr') idl('find, im, x, y, flux, sharp, round, '+str(thresh)+','+str(fwhm)+', [0.1,1.0] , [-1.0,1.0]') import pdb;pdb.set_trace() return idl.x, idl.y, idl.flux
def idl_init(): """Initialise IDL by setting paths and compiling relevant files. """ idl = pidly.IDL() idl("!path = '/home/thomasn/idl_libraries/coyote:' + !path") idl(".compile /home/thomasn/grids/gaussbroad.pro") idl(".compile /home/thomasn/grids/get_spec.pro") idl("grid='/home/thomasn/grids/grid_synthspec.sav'") return idl
def find(imfile,psffile, xr, yr, abs_thresh=.1, corr=0.5): ''' uses a known reference psf to find the positions for a star in the new frame ''' idl = pidly.IDL() idl.xr = np.array(xr) idl.yr = np.array(yr) idl('corr = '+str(corr)) idl("fits_read, '"+imfile+"', image, hdr") idl("fits_read, '"+psffile+"', psf, hdr") idl('starfinder, image, psf, background = background,'+str(abs_thresh)+',corr, N_ITER = 2, x, y, f, sx, sy, sf, c,STARS = stars') return idl.x, idl.y, idl.f, idl.c
def load_brightness(shot_num, t_start=8.0, t_end=28.0, delta=0.1, smooth=10.0): """ Function: st = load_brightness(shot_num, t_start, t_end, delta, smooth) This version of load_brightness interfaces directly with the IDL implementation, via the pidly interface. Inputs: - shot_num = [INT] The MST shot ID for the desired set of data - t_start = [FLOAT] The start time for the desired interval of SXR data. - t_end = [FLOAT] The end time for the desired interval of SXR data. - delta = [FLOAT] The desired sampling window for SXR data. - smooth = [FLOAT] The size of the smoothing window (10.0 is standard). Outputs: - st['key'] = [DICT] Nested dictionary containing the SXR tomography diagnostic data, indexed by camera label. """ # Access (and initialize, if needed) the pidly object and assemble the command string idl = pidly.IDL() idl_str = "n2d = NICKAL2_signal(" + str(shot_num) + ", tstart=" + str( t_start) idl_str += ", tend=" + str(t_end) + ", delta=" + str( delta) + ", sm=" + str(smooth) + ")" idl('cd, "/home/pdvanmeter/lib/idl"') idl('.r NICKAL2_signal') idl(idl_str) # Extract the data from IDL and format data = { 'AlBe': idl.ev('n2d.data.al'), 'SiBe': idl.ev('n2d.data.si'), 'ZrMylar': idl.ev('n2d.data.zr') } error = { 'AlBe': idl.ev('n2d.err.al'), 'SiBe': idl.ev('n2d.err.si'), 'ZrMylar': idl.ev('n2d.err.zr') } noise = { 'AlBe': idl.ev('n2d.noise.al'), 'SiBe': idl.ev('n2d.noise.si'), 'ZrMylar': idl.ev('n2d.noise.zr') } tiempo = idl.ev('n2d.time') # Put the result together st = {'bright': data, 'sigma': error, 'noise': noise, 'time': tiempo} idl.close() return AttrDict(st)
def __init__(self, shell, gdl=False): """ Parameters ---------- shell : IPython shell """ super(IDLMagics, self).__init__(shell) #TODO: allow specifying path, executible on %load_ext try: self._idl = pidly.IDL() except ExceptionPexpect: try: # NB that pidly returns when it reads the text prompt--needs to # match that of the interpreter! self._idl = pidly.IDL('gdl', idl_prompt='GDL>') print 'IDL not found, using GDL' except ExceptionPexpect: raise IDLMagicError('Neither IDL or GDL interpreters found') self._plot_format = 'png' # Allow publish_display_data to be overridden for # testing purposes. self._publish_display_data = publish_display_data
def idl_track(query, max_disp, min_appearances, memory=3): """Call Crocker/Weeks track.pro from IDL using pidly module. Returns one big array, where the last column is the probe ID.""" idl = pidly.IDL() logger.info("Opened IDL process.") idl('pt = get_sql("{}")'.format(query)) logger.info( "IDL is done loading features from the database. Now tracking....") idl('t=track(pt, {}, goodenough={}, memory={})'.format( max_disp, min_appearances, memory)) logger.info("IDL finished tracking. Now piping data into Python....") # 0: x, 1: y, 2: mass, 3: size, 4: ecc, 5: frame, 6: probe_id t = idl.ev('t') idl.close() return t
def __init__(self, gdl_path='/usr/bin/gdl'): self.idl = pidly.IDL(gdl_path, idl_prompt='GDL> ') self.l1b_data = None self.bands = { 'PARASOL': [ '443', '490p', '490u', '490q', '565', '670p', '670u', '670q', '763', '765', '865p', '865u', '865q', '910', '1020' ], 'MERIS': [ '412', '443', '490', '510', '560', '620', '665', '681', '708', '753', '761', '778', '865', '885', '900' ] } ## !!! these are the same as DIMITRI FOR NOW!! CHECK self.sensor_name = 'PARASOL' self.num_bands = 16
def extract_im(imfile, xr, yr, fr, sigfile, psf_size, abs_thresh=15, corr=0.5, residual_file='none', back=False, find_pos=True): ''' runs starfinder ''' idl = pidly.IDL() idl.xr = np.array(xr) idl.yr = np.array(yr) idl.fr = np.array(fr) idl('corr = ' + str(corr)) #import pdb;pdb.set_trace() idl("fits_read, '" + imfile + "', image, hdr") idl('fits_read, "' + sigfile + '", std_noise, hdr') idl('psf_extract, xr, yr, [0], [0], image,' + str(psf_size) + ', psf, psf_fwhm, background, iter=2,/rad_norm') #smarter version of postfix pf = imfile.split('.')[-1] #import pdb;pdb.set_trace() idl('fits_write,"' + imfile.replace('.' + pf, '_psf.' + pf) + '", psf') #import pdb;pdb.set_trace() if back: idl('fits_read, "back.fits", background, bhdr') if find_pos: idl('starfinder, image, psf, background = background,' + str(abs_thresh) + ',corr, N_ITER = 2, x, y, f, sx, sy, sf, c,STARS = stars') else: idl('starfinder, image, psf, background = background,' + str(abs_thresh) + ',corr, N_ITER = 2, x, y, f, sx, sy, sf, c,X_INPUT=xr, Y_INPUT=yr, F_INPUT=fr,STARS = stars' ) if residual_file != 'none': idl('fits_write,"' + residual_file + '", image-stars, hdr') #idl('fits_write,"'+residual_file.replace('res', 'stars')+'", stars, hdr') return idl.x, idl.y, idl.f, idl.c
def get_flux_grid(shot, time, phi=222.5*deg2rad): """ Use SHEq to directly access the NCT output to evaluate rho on a grid of (R,Z) points. Inputs: - shot = MST shot number, corresponding to an existing NCT run. - time = Time point in ms, corresponding to an existing NCT run. - phi = Toroidal angle in radians. """ idl = pidly.IDL() idl('.r /home/pdvanmeter/lib/idl/startup.pro') idl('.r run_sheq') idl('flux = run_sheq({0:}, {1:}, phi0={2:})'.format(shot, time, phi)) flux_grid = idl.ev('flux') idl.close() flux_grid['rho'] = flux_grid['rho'].T return AttrDict(flux_grid)
def SPIRE1d_fit(indir, objname, global_dir, wl_shift=0): import os from astropy.io import ascii if not os.path.isfile(indir+'data/'+objname+'_spire_corrected.txt'): print(objname+' is not found.') return None # read RA/Dec radec_slw = ascii.read(indir+'/data/cube/'+objname+'_radec_slw.txt') import pidly idl = pidly.IDL('/opt/local/exelis/idl83/bin/idl') idl('.r /home/bettyjo/yaolun/programs/line_fitting/gauss.pro') idl('.r /home/bettyjo/yaolun/programs/line_fitting/extract_spire.pro') idl.pro('extract_spire', indir=indir+'data/', filename=objname+'_spire_corrected', outdir=indir+'advanced_products/', plotdir=indir+'advanced_products/plots/', noiselevel=3, ra=radec_slw['RA(deg)'][radec_slw['Pixel'] == 'SLWC3'], dec=radec_slw['Dec(deg)'][radec_slw['Pixel'] == 'SLWC3'], global_noise=20, localbaseline=10, continuum=1, flat=1, object=objname, double_gauss=1, fx=1, current_pix=1, print_all=global_dir+'_lines', wl_shift=wl_shift)
def dewarp(cam, pardir, indir=None, outdir=None): '''Do the dewarping following the NICI campaign paper ( http://iopscience.iop.org/article/10.1086/679508/pdf ). This uses IDL, so make sure it is installed. Wrapper is pidly''' import pidly fnwarp = os.path.join(pardir, 'niciwarp_' + cam + '.sav') print('Dewarping using IDL. Assuming dewarp file is {}'.format(fnwarp)) filetable = ascii.read(os.path.join(indir, 'filetable_bkgrnd.csv'), delimiter=',') filetable[ 'fndewarped'] = 'error_in_dewarping_the_filename' * 3 #make sure string is long enough nfiles = len(filetable) print('Dewarping the {} files'.format(nfiles)) idl = pidly.IDL() idl('restore,"' + fnwarp + '"') for ifile in range(nfiles): if (ifile % 10) == 0: #somehow IDL crashes after ~25 images. restart it more often print('Dewarping file {} / {} files'.format(ifile, nfiles)) #if (ifile != 0) and (ifile != nfiles-1): idl.close() #idl = pidly.IDL() #idl('restore,"'+fnwarp+'"') fn = filetable['fninterm'][ifile] fnout = os.path.join(outdir, os.path.split(fn)[-1]) filetable['fndewarped'][ifile] = fnout idl('fits_open,"' + fn + '", fcb') idl('fits_read, fcb, im, hdr') idl('fits_close,fcb') idl('im_w = poly_2d(im, kx, ky, 2, cubic=-0.5)') idl('fits_open,"' + fnout + '",fout,/WRITE') idl('fits_write,fout,im_w,hdr') idl('fits_close,fout') idl.close() ascii.write(filetable, output=os.path.join(outdir, 'filetable_bkgrnd.csv'), delimiter=',', overwrite=True)
def cdf_pacs_1d(osbid, objname, outdir, fits_for_header, line_fitting_dir): """ cubedir: the directory contains FITS rebinned cube outcubedir: the directory contains ASCII style spectra for each spaxel out1ddir: the directory contains ASCII style 1-D spectrum """ from pacs_weight import pacs_weight import numpy as np import matplotlib.pyplot as plt from astropy.io import ascii, fits import pidly idl = pidly.IDL('/Applications/exelis/idl83/bin/idl') # outdir = '/Users/yaolun/bhr71/best_calibrated/' # cubedir = '/Users/yaolun/bhr71/data/HSA/' # photpath = '/Users/yaolun/bhr71/best_calibrated/bhr71.txt' cubedir = outdir+'data/fits/' cubefile = [cubedir+'OBSID_'+obsid[0]+'_blue_finalcubes_slice00_os8_sf7.fits', cubedir+'OBSID_'+obsid[0]+'_red_finalcubes_slice00_os8_sf7.fits', cubedit+'OBSID_'+obsid[1]+'_blue_finalcubes_slice00_os8_sf7.fits', cubedir+'OBSID_'+obsid[1]+'_red_finalcubes_slice00_os8_sf7.fits',] idl('.r '+line_fitting_dir+'get_pacs.pro') idl.pro('get_pacs', outdir=outdir+'data/cube/', objname=objname, filename=cubefile, suffix='os8_sf7') wl, flux = pacs_weight(outdir+'data/cube/', objname, 31.8, outdir+'data/', fits_for_header, suffix='os8_sf7') idl('.r '+line_fitting_dir+'gauss.pro') idl('.r '+line_fitting_dir+'extract_pacs.pro') idl.pro('extract_pacs', indir=outdir+'data/', filename=objname+'_pacs_weighted', outdir=outdir+'advanced_products/', plotdir=outdir+'advanced_products/plots/', noiselevel=3, ra=0, dec=0, global_noise=20, localbaseline=10, opt_width=1, continuum=1, flat=1, object=objname, double_gauss=1, fixed_width=1)
def call_func(func_name, idl_path='idl', *func_args, **func_kwargs): idl = pidly.IDL(idl_path) result = idl.func(func_name, *func_args, **func_kwargs) idl.close() return result
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
def mtf_plot_results(imageRoot, dataDir='/u/jlu/data/w51/09jun26/combo/', starsSuffix='_0.8_stf.lis'): img, hdr = pyfits.getdata(dataDir + imageRoot + '.fits', header=True) import pidly idl = pidly.IDL() print 'MTF: Restoring IDL variables' mtfData = imageRoot + '_mtfdata.save' mtfFit = imageRoot + '_mtffit.save' idl('restore, "' + mtfData + '"') idl('restore, "' + mtfFit + '"') ########## # Plot the 1D and 2D power spectrum of the source distribution ########## stfLis = dataDir + 'starfinder/' + imageRoot + starsSuffix _lis = asciidata.open(stfLis) mag = _lis[1].tonumpy() x = _lis[3].tonumpy() y = _lis[4].tonumpy() flux = 10**((mag[0] - mag)/2.5) sources = np.zeros(img.shape, dtype=float) xpix = np.array(np.round(x), dtype=int) ypix = np.array(np.round(y), dtype=int) sources[xpix, ypix] = flux F = fftpack.fftshift( fftpack.fft2(sources) ) psd2D = np.abs(F)**2 psd1D = radialProfile.azimuthalAverage(psd2D) # py.figure(1) # py.clf() # py.imshow(np.log10(psd2D)) # py.figure(2) # py.clf() # py.semilogy(psd1D) # py.xlabel('Spatial Frequency') # py.ylabel('Power Spectrum') # py.figure(3) # py.clf() # py.semilogy(idl.nu, idl.spdist) # py.xlabel('Spatial Frequency') # py.ylabel('Power Spectrum') # py.show() ########## # Plot up the best-fit power spectrum ########## print params idl('pspec_fit = mtffunc_keck(nu, params, spdist=spdist)') idl('mtf = mtffunc_keck(nu, params)') nu = idl.nu power = idl.power pspec_fit = idl.pspec_fit mtf = idl.mtf resid = power - pspec_fit print nu.shape print pspec_fit.shape py.clf() # py.semilogy(nu, power) py.semilogy(nu, pspec_fit) # py.semilogy(nu, mtf) # py.semilogy(nu, np.abs(resid)) py.xlabel('Spatial Frequency') py.ylabel('Power Spectrum') py.legend(('Data', 'Best Fit', 'MTF', 'Residuals')) py.show()
def mtf_play(imageRoot, dataDir='/u/jlu/data/w51/09jun26/combo/', starsSuffix='_0.8_stf.lis', resolvedSources=None, maskSize=150): import pidly idl = pidly.IDL() ############################## # H-band wide image ############################## imageFile = dataDir + imageRoot + '.fits' img, hdr = pyfits.getdata(imageFile, header=True) wavelength = hdr['CENWAVE'] * 1e-6 # Mask resolved sources if resolvedSources != None: print 'MTF: Masking %d resolved sources' % len(resolvedSources) img = mask_image(imageFile, resolvedSources, maskSize=maskSize) gcutil.rmall([imageRoot + '_masked.fits']) pyfits.writeto(imageRoot + '_masked.fits', img) # Load up the image print 'MTF: Load the science image.' idl('im = readfits("' + imageRoot + '_masked.fits")') print 'MTF: Set initial guesses for parameters' #definitions of starting parameters [from fitmtf_keck.pro] # # lambda=1.65d-6 # wavelength in meters # F=557.0 # effective focal length of Keck AO (narrow) # D=10.99 # primary's diameter in meters # pupil=0.266 # central obscuration # pupil='largehex' # NIRC2 pupil-stop # Apix=27d-6 # width of detector's pixel in meters # L0=20. # outer scale of turbulence in meters # sigma=.56 # Infl Func width on primary in meters # w=1.3 # Influence Function height # Delta=0 # wavefront measurement error # Cmult=10. # multiplicative constant # N=1d-2 # additive noise floor constant # r0=0.5 # wavelength specific fried parameter in meters idl('startp = {lambda:' + str(wavelength) + ', ' + 'D:10.99, F:139.9, APIX:27e-6, ' + 'pupil:"largehex", L0:30.0, SIGMA:0.56, ' + 'W:1.3, Delta:0.0, Cmult:1.0, N:1e-5, R0:0.5}') # Load up the starfinder results for this image print 'MTF: Read in preliminary starlist.' stfLis = dataDir + 'starfinder/' + imageRoot + starsSuffix idl('readcol, "' + stfLis + '", name, mag, time, x, y, ' + 'snr, corr, frames, fwhm, format="(A,F,F,F,F,F,F,F,F)"') idl('flux = 10^((mag[0] - mag)/2.5)') # Create sources array (delta functions * flux) for the stars. print 'MTF: Creating 2D source array' idl('sources = im') idl('sources[*] = 0.') idl('sources[x, y] = flux') mtfData = imageRoot + '_mtfdata.save' mtfFit = imageRoot + '_mtffit.save' print 'MTF: Calling getmtf' idl('getmtf, im, startp, nu, power, error, spdist, deltas=sources') idl('save, nu, power, error, spdist, filename="'+mtfData+'"') # Fit the power spectrum print 'MTF: Fitting the power spectrum (round 1)' idl('print, startp') idl('fitmtf_keck, "'+mtfData+'", params, perror, ' + 'start=startp, relstep=0.2')
# Master script for CDF reduction with the method used in BHR71 paper. # library import import os import pidly if 'bettyjo' in os.path.expanduser('~'): idl = pidly.IDL('/opt/local/exelis/idl83/bin/idl') else: idl = pidly.IDL('/Applications/exelis/idl83/bin/idl') from astropy.io import ascii import sys sys.path.append(os.path.expanduser('~') + '/programs/line_fitting/') sys.path.append(os.path.expanduser('~') + '/programs/spectra_analysis/') from PreFittedModify import * from spire_spectral_index import spire_spectral_index from cdfPacs1d import cdfPacs1d # some info about the observational programs # COPS-SPIRE source list obsid_spire = [ 1342242620, 1342242621, 1342245084, 1342245094, 1342245857, 1342247625, 1342248246, 1342248249, 1342249053, 1342249470, 1342249474, 1342249475, 1342249476, 1342249477, 1342250509, 1342250510, 1342250512, 1342250515, 1342251285, 1342251286, 1342251287, 1342251290, 1342253646, 1342253649, 1342253652, 1342254037, 1342252897 ] # SECT cannot converage at L1489 1342249473, L1527 1342250511, HH100 1342252897
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,record=True,dstar=178.,\ aperture=None,dyn_cav=False,fix_params=None,alma=False,power=2,better_im=False,ellipsoid=False,\ TSC_dir='~/programs/misc/TSC/', IDL_path='/Applications/exelis/idl83/bin/idl',auto_disk=0.25): """ 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 """ 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 outflow_inner_edge import outflow_inner_edge from pprint import pprint # import pdb # pdb.set_trace() # Constants setup c = const.c.cgs.value 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 g2d = 100. mmw = 2.37 # Kauffmann 2008 m = Model() # 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_radmc['wl'], dust_radmc['abs'], dust_radmc['scat'], dust_radmc['g']] = np.genfromtxt(dust_file,skip_header=2).T [dust['nu'], dust['albedo'], dust['chi'], dust['g']] = np.genfromtxt(dust_file).T # opacity per mass of dust? # dust_hy = dict() # dust_hy['nu'] = c/dust_radmc['wl']*1e4 # ind = np.argsort(dust_hy['nu']) # dust_hy['nu'] = dust_hy['nu'][ind] # dust_hy['albedo'] = (dust_radmc['scat']/(dust_radmc['abs']+dust_radmc['scat']))[ind] # dust_hy['chi'] = (dust_radmc['abs']+dust_radmc['scat'])[ind] # dust_hy['g'] = dust_radmc['g'][ind] # dust_hy['p_lin_max'] = 0*dust_radmc['wl'][ind] # assume no polarization # d = HenyeyGreensteinDust(dust_hy['nu'], dust_hy['albedo'], dust_hy['chi'], dust_hy['g'], dust_hy['p_lin_max']) 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.) # try to solve the freq. problem d.optical_properties.extrapolate_nu(3.28e15, 4e15) # 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 # Calculation inherited from the script used for RADMC-3D # 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 # params = np.genfromtxt(indir+'/tsc_params.dat', dtype=None) dict_params = params # input_reader(params_file) # 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 # M_env_dot = dict_params['M_env_dot']*MS/yr # R_cen = dict_params['R_cen']*AU # R_inf = dict_params['R_inf']*AU # 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: a_out = 130 * 178. * AU b_out = 50 * 178. * AU z_out = a_out # a_in = 77.5 * 178. * AU # b_in = 30 * 178. * AU a_in = dict_params['a_in'] * 178. * AU b_in = a_in / a_out * b_out z_in = a_in # rho_cav_out = 1e4 * mh # rho_cav_in = 1e3 * mh 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 # Do the variable conversion # cs = (G * M_env_dot / 0.975)**(1/3.) # cm/s # t = R_inf / cs / yr # in year # mstar = M_env_dot * t * yr # omega = (R_cen * 16*cs**8 / (G**3 * mstar**3))**0.5 # print the variables for radmc3d 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 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]) # phic = 0.5*( phii[0:nz-1] + phii[1:nz] ) # 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: # c0 = R_env_max**(-0.5)*np.sqrt(1/np.sin(np.radians(theta_cav))**3-1/np.sin(np.radians(theta_cav))) # 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 = 5.27e-18 # 1.6e-17 # 5.27e-18 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) 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) 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 = R_env_max**(-0.5)*np.sqrt(1/np.sin(np.radians(theta_cav))**3-1/np.sin(np.radians(theta_cav))) 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('/Applications/exelis/idl82/bin/idl') idl = pidly.IDL(IDL_path) idl('.r ' + TSC_dir + 'tsc.pro') # idl.pro('tsc_run', outdir=outdir, grid=[nxx,ny,nz], time=t, c_s=cs, omega=omega, rstar=rstar, renv_min=R_env_min, renv_max=R_env_max) # idl.pro('tsc_run', outdir=outdir, grid=[nxx,ny,nz], time=t, c_s=cs, omega=omega, rstar=rstar, renv_min=R_env_min, renv_max=min([R_inf,max(ri)])) # min([R_inf,max(ri)]) # # only run TSC calculation within infall radius # modify the rc array rc_idl = rc[(rc < min([R_inf, max(ri)]))] idl.pro( 'tsc_run', outdir=outdir, rc=rc_idl, thetac=thetac, time=t, c_s=cs, omega=omega, renv_min=R_env_min ) #, rstar=rstar, renv_min=R_env_min, renv_max=min([R_inf,max(ri)])) # min([R_inf,max(ri)]) else: print 'Read the pre-computed TSC model.' rc_idl = rc[(rc < min([R_inf, max(ri)]))] # read in the exist file rho_env_tsc_idl = np.genfromtxt(outdir + 'rhoenv.dat').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.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 # rho_env_copy = np.array(rho_env_tsc) # if max(rc) > R_inf: # ind_infall = np.where(rc <= R_inf)[0][-1] # print ind_infall # for ithetac in range(0, len(thetac)): # # rho_dum = np.log10(rho_env_copy[(rc > R_inf) & (np.isnan(rho_env_copy[:,ithetac]) == False),ithetac]) # # rc_dum = np.log10(rc[(rc > R_inf) & (np.isnan(rho_env_copy[:,ithetac]) == False)]) # # rc_dum_nan = np.log10(rc[(rc > R_inf) & (np.isnan(rho_env_copy[:,ithetac]) == True)]) # # # print rc_dum # # for i in range(0, len(rc_dum_nan)): # # rho_extrapol = poly(rc_dum, rho_dum, rc_dum_nan[i]) # # rho_env_copy[(np.log10(rc) == rc_dum_nan[i]),ithetac] = 10**rho_extrapol # # # for i in range(ind_infall, len(rc)): # rho_env_copy[i, ithetac] = 10**(np.log10(rho_env_copy[ind_infall, ithetac]) - 2*(np.log10(rc[i]/rc[ind_infall]))) # rho_env2d = rho_env_copy # rho_env = np.empty((nx,ny,nz)) # for i in range(0, nz): # rho_env[:,:,i] = rho_env2d # 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 = np.empty((nx, ny, nz)) for i in range(0, nz): rho_env[:, :, i] = rho_env_tsc2d 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)]) # 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 if 'rho_cav_center' in locals() == False: rho_cav_center = 5.27e-18 # 1.6e-17 # 5.27e-18 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) 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) 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 # 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-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 # rho_env = rho_env + 1e-40 # rho_disk = rho_disk + 1e-40 # rho = rho + 1e-40 # 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 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: # rc setting # mat.rcParams['text.usetex'] = True # mat.rcParams['font.family'] = 'serif' # mat.rcParams['font.serif'] = 'Times' # mat.rcParams['font.sans-serif'] = 'Computer Modern Sans serif' # Plot the azimuthal averaged density fig = plt.figure(figsize=(8, 6)) ax_env = fig.add_subplot(111, projection='polar') # take the weighted average # rho2d is the 2-D projection of gas density rho2d = np.sum(rho**2, axis=2) / np.sum(rho, axis=2) zmin = 1e-22 / mmw / mh 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=1e9)) # np.nanmax(rho2d_exp/mmw/mh) ax_env.set_xlabel(r'$\rm{Polar\,angle\,(Degree)}$', fontsize=20) ax_env.set_ylabel(r'$\rm{Radius\,(AU)}$', fontsize=20) ax_env.tick_params(labelsize=20) ax_env.set_yticks(np.arange(0, R_env_max / AU, R_env_max / AU / 5)) # ax_env.set_ylim([0,10000]) 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}}$']) # 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) 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}}$']) 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] alpha = np.linspace(0.3, 1.0, len(plot_grid)) for i in plot_grid: rho_rad, = ax.plot(np.log10(rc / AU), np.log10(rho2d[:, i] / g2d / mmw / mh), '-', color='b', linewidth=2, markersize=3, alpha=alpha[plot_grid.index(i)]) tsc_only, = ax.plot(np.log10(rc / AU), np.log10(rho_env_tsc2d[:, i] / mmw / mh), 'o', color='r', linewidth=2, markersize=3, alpha=alpha[plot_grid.index(i)]) 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) # sisslope, = ax.plot(np.log10(rc/AU), -2*np.log10(rc/AU)+A-(-2)*np.log10(plot_r_inf), linestyle='--', color='Orange', linewidth=1.5) # gt_R_cen_slope, = ax.plot(np.log10(rc/AU), -1.5*np.log10(rc/AU)+B-(-1.5)*np.log10(plot_r_inf), linestyle='--', color='Orange', linewidth=1.5) # lt_R_cen_slope, = ax.plot(np.log10(rc/AU), -0.5*np.log10(rc/AU)+A-(-0.5)*np.log10(plot_r_inf), linestyle='--', color='Orange', linewidth=1.5) lg = plt.legend([rho_rad, tsc_only, rinf, cen_r],\ [r'$\rm{\rho_{dust}}$',r'$\rm{\rho_{tsc}}$',r'$\rm{infall\,radius}$',r'$\rm{centrifugal\,radius}$'],\ fontsize=20, numpoints=1) ax.set_xlabel(r'$\rm{log(Radius)\,(AU)}$', fontsize=20) ax.set_ylabel(r'$\rm{log(Gas \slash 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, 15]) fig.gca().set_xlim(left=np.log10(0.05)) # ax.set_xlim([np.log10(0.8),np.log10(10000)]) # subplot shows the radial density profile along the midplane ax_mid = plt.axes([0.2, 0.2, 0.2, 0.2], frameon=True) ax_mid.plot(np.log10(rc / AU), np.log10(rho2d[:, 199] / g2d / mmw / mh), 'o', color='b', linewidth=1, markersize=2) ax_mid.plot(np.log10(rc / AU), np.log10(rho_env_tsc2d[:, 199] / mmw / mh), '-', color='r', linewidth=1, markersize=2) # ax_mid.set_ylim([0,10]) # ax_mid.set_xlim([np.log10(0.8),np.log10(10000)]) ax_mid.set_ylim([0, 15]) 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) # temperary for comparing full TSC and infall-only TSC model # import sys # sys.path.append(os.path.expanduser('~')+'/programs/misc/') # from tsc_comparison import tsc_com # rho_tsc, rho_ulrich = tsc_com() m.add_density_grid(rho_dust.T, d) # m.add_density_grid(rho.T, outdir+'oh5.hdf5') # numpy read the array in reverse order # 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) # # add an infrared source at the center # L_IR = 0.04 # ir_source = m.add_spherical_source() # ir_source.luminosity = L_IR*LS # ir_source.radius = rstar # [cm] # ir_source.temperature = 500 # [K] peak at 10 um # ir_source.position = (0., 0., 0.) # print 'Additional IR source, L_IR = %5.2f L_sun' % L_IR # Setting up the wavelength for monochromatic radiative transfer lambda0 = 0.1 lambda1 = 2.0 lambda2 = 50.0 lambda3 = 95.0 lambda4 = 200.0 lambda5 = 314.0 lambda6 = 1000.0 n01 = 10.0 n12 = 20.0 n23 = 50.0 lam01 = lambda0 * (lambda1 / lambda0)**(np.arange(n01) / n01) lam12 = lambda1 * (lambda2 / lambda1)**(np.arange(n12) / n12) lam23 = lambda2 * (lambda6 / lambda2)**(np.arange(n23 + 1) / n23) lam = np.concatenate([lam01, lam12, lam23]) nlam = len(lam) # Create camera wavelength points n12 = 70.0 n23 = 70.0 n34 = 70.0 n45 = 50.0 n56 = 50.0 lam12 = lambda1 * (lambda2 / lambda1)**(np.arange(n12) / n12) lam23 = lambda2 * (lambda3 / lambda2)**(np.arange(n23) / n23) lam34 = lambda3 * (lambda4 / lambda3)**(np.arange(n34) / n34) lam45 = lambda4 * (lambda5 / lambda4)**(np.arange(n45) / n45) lam56 = lambda5 * (lambda6 / lambda5)**(np.arange(n56 + 1) / n56) lam_cam = np.concatenate([lam12, lam23, lam34, lam45, lam56]) n_lam_cam = len(lam_cam) # Radiative transfer setting # number of photons for temp and image lam_list = lam.tolist() # print lam_list 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: # Monechromatic radiative transfer setting m.set_monochromatic(True, wavelengths=lam_list) m.set_n_photons(initial=1000000, imaging_sources=im_photon, imaging_dust=im_photon, raytracing_sources=1000000, raytracing_dust=1000000) else: # regular wavelength grid setting m.set_n_photons(initial=1000000, imaging=im_photon, raytracing_sources=1000000, raytracing_dust=1000000) # number of iteration to compute dust specific energy (temperature) m.set_n_initial_iterations(20) # m.set_convergence(True, percentile=95., absolute=1.5, relative=1.02) m.set_convergence(True, percentile=dict_params['percentile'], absolute=dict_params['absolute'], relative=dict_params['relative']) m.set_mrw(True) # Gamma = 1 by default # m.set_forced_first_scattering(forced_first_scattering=True) # Setting up images and SEDs # 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(1400, 2.0, 1400.0) 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 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, 35, 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) # name = np.arange(1,len(wl_aper)+1) # aper = np.empty_like(wl_aper) # for i in range(0, len(wl_aper)): # if wl_aper[i] < 5: # # aper[i] = 1.2 * 7 # aper[i] = 1.8 * 4 # elif (wl_aper[i] < 14) & (wl_aper[i] >=5): # # aper[i] = 7.2 * wl_aper[i]/10. # aper[i] = 1.8 * 4 # elif (wl_aper[i] >= 14) & (wl_aper[i] <40): # # aper[i] = 7.2 * 2 # aper[i] = 5.1 * 4 # else: # aper[i] = 24.5 # dict_peel_sed = {} # for i in range(0, len(wl_aper)): # aper_dum = aper[i]/2 * (1/3600.*np.pi/180.)*dstar*pc # dict_peel_sed[str(name[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(name[i])].set_wavelength_range(1300, 2.0, 1300.0) # dict_peel_sed[str(name[i])].set_wavelength_range(1000, 2.0, 1000.0) # dict_peel_sed[str(name[i])].set_viewing_angles([dict_params['view_angle']], [0.0]) # # aperture should be given in cm # dict_peel_sed[str(name[i])].set_aperture_range(1, aper_dum, aper_dum) # dict_peel_sed[str(name[i])].set_uncertainties(True) # dict_peel_sed[str(name[i])].set_output_bytes(8) 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( 1400, 2.0, 1400.0) 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(1400, 2.0, 1400.0) # pixel number syn_im.set_image_size(300, 300) 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) # output as 64-bit 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() # In[112]: # 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 # from input_reader import input_reader_table # from pprint import pprint # filename = '/Users/yaolun/programs/misc/hyperion/test_input.txt' # params = input_reader_table(filename) # pprint(params[0]) # indir = '/Users/yaolun/test/' # outdir = '/Users/yaolun/test/' # dust_file = '/Users/yaolun/programs/misc/oh5_hyperion.txt' # # dust_file = '/Users/yaolun/Copy/dust_model/Ormel2011/hyperion/(ic-sil,gra)3opc.txt' # # fix_params = {'R_min': 0.14} # fix_params = {} # setup_model(indir,outdir,'model_test',params[0],dust_file,plot=True,record=False,\ # idl=False,radmc=False,fix_params=fix_params,ellipsoid=False)
def call_pro(pro_name, idl_path='idl', **pro_kwargs): idl = pidly.IDL(idl_path) idl.pro(pro_name, **pro_kwargs) idl.close()
def rotate_shift_align(xcen, ycen, angle, skysub_science_array, objname, sciheader, current_dir, imsize=1024): ''' rotate_shift_align ---------- Procedure to rotate reduced science images (if needed), shift them, and then combine into a final reduced science frame. Inputs ---------- xcen : (array) array of x-centers for each image ycen : (array) array of y-centers for each image angle : (list) list of length n containing rotation angle of each image skysub_science_array : (array) stacked (x by y by n) array of reduced, sky-subtracted science image data objname : (string) name of object sciheader : (FITS header) header from the first science image in the stack current_dir : (string) path to current directory to update pIDLy imsize : image dimensions, default = 1024 Returns ---------- name : (FITS image) reduced, combined frame in form of objname + '_' + date + '_final.fits' Dependents ---------- reduced_science_array : this should be the output from the sky_subtract function measure_star_centers : needed to provide the input x, y center positions ''' date = sciheader['UTSTART'] date = date[0:10] n = skysub_science_array.shape[2] #The position of the star in the first image #is used as the reference position corners = np.zeros([2,4,n]) #xcen, ycen are the list of coordinates for the stars in each image old_xcen = np.copy(xcen) old_ycen = np.copy(ycen) for ii in range(0, n): corners[0,0,ii]= 0 corners[0,1,ii]= 0 corners[0,2,ii]= imsize corners[0,3,ii]= imsize corners[1,0,ii]= 0 corners[1,1,ii]= imsize corners[1,2,ii]= 0 corners[1,3,ii]= imsize if angle[ii] != 0: #If we need to rotate, do this now #update both star position, and corner positions #Rotation matrix new_x = (np.cos(angle[ii])*xcen[ii]) + (-(np.sin(angle[ii])*ycen[ii])) new_y = (np.sin(angle[ii])*xcen[ii]) + (np.cos(angle[ii])*ycen[ii]) xcen[ii] = new_x ycen[ii] = new_y for jj in range(0,4): new_x = (np.cos(angle[ii])*corners[1,jj,ii]) + (-(np.sin(angle[ii])*corners[0,jj,ii])) new_y = (np.sin(angle[ii])*corners[1,jj,ii]) + (np.cos(angle[ii])*corners[0,jj,ii]) corners[:,jj,ii] = [new_y, new_x] # define reference image star position if ii == 0: star = [ycen[ii], xcen[ii]] else: # define offsets for each image dx = star[1] - xcen[ii] dy = star[0] - ycen[ii] corners[1,:,ii] += dx corners[0,:,ii] += dy # Set so that the image starts at 0,0 dx = np.min(corners[1,:,:]) star[1] -= dx corners[1,:,:] -= dx dy = np.min(corners[0,:,:]) star[0] -= dy corners[0,:,:] -= dy # and find the maximum size xsize = int(np.ceil(np.max(corners[1,:,:]))) ysize = int(np.ceil(np.max(corners[0,:,:]))) print(xsize,ysize) # Restore your original list of star positions within the non-rotated/shifted images xcen = np.copy(old_xcen) ycen = np.copy(old_ycen) # now shift each of the science frames to match reference big_im = np.zeros([ysize,xsize,n]) for ii in range(0, n): xarr = np.array([np.arange(xsize),]*ysize, dtype=np.float64) yarr = np.array([np.arange(ysize),]*xsize, dtype=np.float64).transpose() if angle[ii] != 0.0: new_x = (np.cos(angle[ii])*xcen[ii]) + (-(np.sin(angle[ii])*ycen[ii])) new_y = (np.sin(angle[ii])*xcen[ii]) + (np.cos(angle[ii])*ycen[ii]) xcen[ii] = new_x ycen[ii] = new_y xshift = star[1] - xcen[ii] yshift = star[0] - ycen[ii] new_x = (np.cos(-angle[ii])*xshift) + (-(np.sin(-angle[ii])*yshift)) new_y = (np.sin(-angle[ii])*xshift) + (np.cos(-angle[ii])*yshift) xshift = new_x yshift = new_y new_x = (np.cos(-angle[ii])*xarr) + (-(np.sin(-angle[ii])*yarr)) new_y = (np.sin(-angle[ii])*xarr) + (np.cos(-angle[ii])*yarr) xarr = new_x yarr = new_y xarr -= xshift yarr -= yshift else: xshift = star[1] - xcen[ii] yshift = star[0] - ycen[ii] xarr -= xshift yarr -= yshift shifted_tmp = sp.ndimage.map_coordinates(skysub_science_array[:,:,ii], [yarr.reshape((1,xsize*ysize)), xarr.reshape((1,xsize*ysize))], mode='constant', cval=0.0, order=3) shifted_tmp = shifted_tmp.reshape((ysize,xsize)) shifted_tmp[np.where(shifted_tmp == 0)] = np.nan big_im[:,:,ii] = shifted_tmp print(f"Shifting image {ii} of {n}...") shiftname = objname + '-' + date + '-MMT-00' + str(ii) + '.fits' if ii >= 10: shiftname = objname + '-'+ date + '-MMT-0' + str(ii) + '.fits' if ii >= 100: shiftname = objname + '-' + date + '-MMT-' + str(ii) + '.fits' sciheader['CRPIX1A'] = (star[1],'primary star X-center') sciheader['CRPIX2A'] = (star[0],'primary star Y-center') sciheader['CRVAL1A'] = (0,'') sciheader['CRVAL2A'] = (0,'') sciheader['CTYPE1A'] = ('Xprime','') sciheader['CTYPE2A'] = ('Yprime','') sciheader['CD1_1A'] = (1,'') sciheader['CD1_2A'] = (0,'') sciheader['CD2_1A'] = (0,'') sciheader['CD2_2A'] = (1,'') sciheader['BZERO'] = (0,'') fits.writeto(shiftname, big_im[:,:,ii], sciheader, overwrite = True, output_verify = 'silentfix') # median combine the shifted science frames to produce final image! date = sciheader['UTSTART'] date = date[0:10] name = objname + '_' + date + '_final.fits' sciheader['CRPIX1A'] = (star[1],'primary star X-center') sciheader['CRPIX2A'] = (star[0],'primary star Y-center') sciheader['CRVAL1A'] = (0,'') sciheader['CRVAL2A'] = (0,'') sciheader['CTYPE1A'] = ('Xprime','') sciheader['CTYPE2A'] = ('Yprime','') sciheader['CD1_1A'] = (1,'') sciheader['CD1_2A'] = (0,'') sciheader['CD2_1A'] = (0,'') sciheader['CD2_2A'] = (1,'') sciheader['BZERO'] = (0,'') fits.writeto('tmp.fits', big_im, sciheader, overwrite = True, output_verify='silentfix') del skysub_science_array del big_im del shifted_tmp idl = pidly.IDL('/Applications/exelis/idl/bin/idl') # ensure that idl thinks we're in the same place the console does idl_changedir = 'cd, ' + f'"{current_dir}"' idl(idl_changedir) idl('name = "'+ name +'"') idl('big_im = mrdfits("tmp.fits",0,header,/fscale,/silent)') idl('big_im = transpose(big_im,[1,2,0])') idl('mwrfits,big_im,"stack.fits",/create') idl('med_im = median(big_im,dimension=3)') idl('sxdelpar,header,"NAXIS3"') idl('mwrfits,med_im,name,header,/create') os.remove('tmp.fits') idl.close() return
def kelly(x1, x2, x1err=[], x2err=[], cerr=[], logify=True, miniter=5000, maxiter=1e5, metro=True, silent=True, output='percentiles', full_output=None): """ Python wrapper for the linear regression MCMC of Kelly (2007). Requires pidly (http://astronomy.sussex.ac.uk/~anthonys/pidly/) and an IDL license. Parameters ---------- x1 : array of floats Independent variable, or observable x2 : array of floats Dependent variable x1err : array of floats (optional) Uncertainties on the independent variable x2err : array of floats (optional) Uncertainties on the dependent variable cerr : array of floats (optional) Covariances of the uncertainties in the dependent and independent variables output : {'full', 'percentiles', 'std'} whether to return the full posterior distributions, the median and lower and upper uncertainties, or the median and standard deviation. Default 'percentiles'. full_output : bool (optional) For backward compatibility. `full_output=True` sets `output='full'` and `full_output=False` sets `output='std'`. If not specified, this parameter is ignored. DEPRECATED. Returns ------- a, b, s : float arrays normalization, slope and intrinsic scatter, depending on the `output` parameter """ assert output in ('full', 'percentiles', 'std'), \ 'Invalid value of argument output. See function help for details.' # import here so it's not required if any other function is called import pidly n = len(x1) assert len(x2) == n, 'x1 and x2 must have same length' if len(x1err) == 0: x1err = np.zeros(n) if len(x2err) == 0: x2err = np.zeros(n) if len(cerr) == 0: cerr = np.zeros(n) if logify: x1, x1errr = to_log(x1, x1err) x2, x1errr = to_log(x2, x2err) idl = pidly.IDL() idl('x1', x1) idl('x2', x2) cmd = 'linmix_err, x1, x2, fit' if len(x1err) == n: idl('x1err', x1err) cmd += ', xsig=x1err' if len(x2err) == n: idl('x2err', x2err) cmd += ', ysig=x2err' if len(cerr) == n: idl('cerr', cerr) cmd += ', xycov=cerr' cmd += ', miniter={0}, maxiter={1}'.format(miniter, maxiter) if metro: cmd += ', /metro' if silent: cmd += ', /silent' idl(cmd) alpha = idl.ev('fit.alpha') beta = idl.ev('fit.beta') sigma = np.sqrt(idl.ev('fit.sigsqr')) if full_output is not None: msg = 'argument full_output is deprecated. Please use the argument' \ ' output instead.' warnings.warn(msg, DeprecationWarning) output = 'full' if full_output else 'std' if output == 'full': output = alpha, beta, sigma elif output == 'percentiles': out = np.array( [[np.median(i), np.percentile(i, 16), np.percentile(i, 84)] for i in (alpha, beta, sigma)]) out[:,1:] = np.abs(out[:,1:] - out[:,0,np.newaxis]) elif output == 'std': out = np.array( [[np.median(i), np.std(i)] for i in (alpha, beta, sigma)]) return out
def gas_velo_at_particle_pos(varfiles='last4', sim=False, scheme='tsc', use_IDL=False, OVERWRITE=False): """This script calulates the gas velocity at the particle position and stores this together with particle position, containing grid cell idicies, particle velocities, and particle index in a gas_velo_at_particle_pos file. Args: varfiles: specifiy varfiles for calculation, e.g. 'last', 'first', 'all', 'VAR###', 'last4', 'first3' scheme: possible are: - ngp: nearest grid point - cic: cloud in cell - tsc: triangular shaped cloud OVERWRITE: set to True to overwrite already calculated results """ import pencilnew as pcn from os.path import exists import numpy as np GAS_VELO_TAG = 'gas_velo_at_particle_pos' if sim == False: sim = pcn.get_sim() if sim == False: print('! ERROR: Specify simulation object!') return False SIM = sim if use_IDL: print('? WARNING: IDL VERSION OF THIS SCRIPT BY JOHANSEN, not recommended for 2D data') import pidly; print '## starting IDL engine..'; IDL = pidly.IDL(long_delay=0.05) # start IDL engine ## skip if nothing is new if (not OVERWRITE) and (exists(join(SIM.pc_datadir, 'sigma.pkl'))) and (exists(join(SIM.pc_datadir, 'zeta.pkl'))): print('~ '+SIM.name+' is already calculated and up-to-date! -> skipping it!') else: ## start calculations print('~ Calculating gas_velo_at_particle_pos for "'+SIM.name+'" in "'+SIM.path+'"') IDL.pro('gas_velo_at_particle_pos', datadir=SIM.datadir, destination=GAS_VELO_TAG, doforthelastNvar=varfiles[4:]) files = [i.split('_')[-1].split('.sav')[0] for i in listdir(join(SIM.pendatadir,GAS_VELO_TAG)) if i.startswith(GAS_VELO_TAG) and i.endswith('.sav') or i.endswith('.pkl')] if files == []: print('!! ERROR: No calc_gas_speed_at_particle_position-files found for '+SIM.name+'! Use idl script to produce them first!') IDL.close() return True else: print('~ Calculating gas_velo_at_particle_pos for "'+SIM.name+'" in "'+SIM.path+'"') save_destination = join(SIM.pc_datadir, GAS_VELO_TAG); mkdir(save_destination) varlist = SIM.get_varlist(pos=varfiles, particle=False); pvarlist = SIM.get_varlist(pos=varfiles, particle=True) for f, p in zip(varlist, pvarlist): save_filename = GAS_VELO_TAG+'_'+scheme+'_'+f[3:] if not OVERWRITE and exists(save_filename, folder=save_destination): continue print('## Reading '+f+' ...') ff = pcn.read.var(datadir=SIM.datadir, varfile=f, quiet=True, trimall=False) pp = pc.read.pvar(datadir=SIM.datadir, varfile=p) ## remove ghost zones from grid, call the reduced grid the "real grid" realgridx = ff.x[ff.l1:ff.l2]; realgridy = ff.y[ff.m1:ff.m2]; realgridz = ff.z[ff.n1:ff.n2] nx = ff.l2-ff.l1; ny = ff.m2-ff.m1; nz = ff.n2-ff.n1 ## prepare list for all quantities l_ipars = pp.ipars # particle number KNOWN l_px = pp.xp; l_py = pp.yp; l_pz = pp.zp # particle absolut position KNOWN l_vx = pp.vpx; l_vy = pp.vpy; l_vz = pp.vpz # particle velocity KNOWN l_rix = []; l_riy = []; l_riz = [] # particle untrimmed realgrid index (grid index = l/m/n + readgrid index ???) l_ix = []; l_iy = []; l_iz = [] # particle grid index (in untrimmed grid) l_ux = []; l_uy = []; l_uz = [] # underlying gas velocity at position of particle ## get index of realgrid cell for each particle for i in range(len(l_ipars)): l_rix.append(np.abs(realgridx-l_px[i]).argmin()) l_riy.append(np.abs(realgridy-l_py[i]).argmin()) l_riz.append(np.abs(realgridz-l_pz[i]).argmin()) ## convert into untrimmed grid l_ix = np.array(l_rix)+ff.l1; l_iy = np.array(l_riy)+ff.m1; l_iz = np.array(l_riz)+ff.n1 ## NGP if scheme == 'ngp' or scheme == 'NGP': print('## Calculating gas velocities via '+scheme) l_ux = ff.ux[l_iz, l_iy, l_ix] l_uy = ff.uy[l_iz, l_iy, l_ix] l_uz = ff.uz[l_iz, l_iy, l_ix] ## CIC if scheme == 'cic' or scheme == 'CIC': print('## Calculating gas velocities via '+scheme) for ix0, iy0, iz0, px, py, pz in zip(l_ix, l_iy, l_iz, l_px, l_py, l_pz): # for each particle if ff.x[ix0] > px: ix0 = ix0-1 # ix0 must be left to particle if ff.y[iy0] > py: iy0 = iy0-1 # iy0 must be below the particle if ff.z[iz0] > pz: iz0 = iz0-1 # iz0 must be under particle ix1=ix0; iy1=iy0; iz1=iz0 # if a dim. is zero, this is default, else: if nx > 1: ix1 = ix0+1; dx_1 = 1./ff.dx # if a dim is non-zero, ajust ix1 to right cell if ny > 1: iy1 = iy0+1; dy_1 = 1./ff.dy # if a dim is non-zero, ajust iy1 to above cell if nz > 1: iz1 = iz0+1; dz_1 = 1./ff.dz # if a dim is non-zero, ajust iz1 to above cell ux = 0.; uy = 0.; uz = 0. for ix in [ix0, ix1]: for iy in [iy0, iy1]: for iz in [iz0, iz1]: weight = 1. if nx > 1: weight = weight * ( 1. - abs(px-ff.x[ix])*dx_1) if ny > 1: weight = weight * ( 1. - abs(py-ff.y[iy])*dy_1) if nz > 1: weight = weight * ( 1. - abs(pz-ff.z[iz])*dz_1) ux = ux + weight*ff.ux[iz, iy, ix] uy = uy + weight*ff.uy[iz, iy, ix] uz = uz + weight*ff.uz[iz, iy, ix] if iz0 == iz1: break # beware of degeneracy: if iy0 == iy1: break # beware of degeneracy: if ix0 == ix1: break # beware of degeneracy: l_ux.append(ux); l_uy.append(uy); l_uz.append(uz) ## TSC if scheme == 'tsc' or scheme == 'TSC': for ix0, iy0, iz0, px, py, pz in zip(l_ix, l_iy, l_iz, l_px, l_py, l_pz): # for each particle ixx0 = ix0; ixx1 = ix0 # beware of degeneracy iyy0 = iy0; iyy1 = iy0 izz0 = iz0; izz1 = iz0 if nx > 1: ixx0 = ix0-1; ixx1 = ix0+1; dx_1 = 1./ff.dx; dx_2 = 1./ff.dx**2 if ny > 1: iyy0 = iy0-1; iyy1 = iy0+1; dy_1 = 1./ff.dy; dy_2 = 1./ff.dy**2 if nz > 1: izz0 = iz0-1; izz1 = iz0+1; dz_1 = 1./ff.dz; dz_2 = 1./ff.dz**2 ux = 0.; uy = 0.; uz = 0. for ix in [ix0, ixx0, ixx1]: weight_x = 0. if ix-ix0 == -1 or ix-ix0 == 1: weight_x = 1.125 - 1.5*abs(px-ff.x[ix])*dx_1 + 0.5*abs(px-ff.x[ix])**2*dx_2 elif nx != 1: weight_x = 0.75 - (px-ff.x[ix])**2*dx_2 for iy in [iy0, iyy0, iyy1]: weight_y = 0. if iy-iy0 == -1 or iy-iy0 == 1: weight_y = 1.125 - 1.5*abs(py-ff.y[iy])*dy_1 + 0.5*abs(py-ff.y[iy])**2*dy_2 elif ny != 1: weight_y = 0.75 - (py-ff.y[iy])**2*dy_2 for iz in [iz0, izz0, izz1]: weight_z = 0. if iz-iz0 == -1 or iz-iz0 == 1: weight_z = 1.125 - 1.5*abs(pz-ff.z[iz])*dz_1 + 0.5*abs(pz-ff.z[iz])**2*dz_2 elif nz != 1: weight_z = 0.75 - (pz-ff.z[iz])**2*dz_2 weight = 1. if nx > 1: weight = weight * weight_x if ny > 1: weight = weight * weight_y if nz > 1: weight = weight * weight_z ux = ux + weight*ff.ux[iz, iy, ix] uy = uy + weight*ff.uy[iz, iy, ix] uz = uz + weight*ff.uz[iz, iy, ix] if izz0 == izz1: break # beware of degeneracy: if iyy0 == iyy1: break # beware of degeneracy: if ixx0 == ixx1: break # beware of degeneracy: l_ux.append(ux); l_uy.append(uy); l_uz.append(uz) ## Convert all information into a single record array data_set = np.core.records.fromarrays( [l_ipars.astype('int'), l_px, l_py, l_pz, l_vx, l_vy, l_vz, l_rix, l_riy, l_riz, l_ix, l_iy, l_iz, l_ux, l_uy, l_uz], names = 'ipar, ipx, ipy, ipz, vx, vy, vz, rix, riy, riz, ix, iy, iz, ux, uy, uz', formats = 'int, float, float, float, float, float, float, int, int, int, int, int, int, float, float, float' ) gas_velo_at_particle_pos = np.sort(data_set, order=['ix', 'iy', 'iz']) Nix = int(gas_velo_at_particle_pos['rix'].max()+1) Niy = int(gas_velo_at_particle_pos['riy'].max()+1) Niz = int(gas_velo_at_particle_pos['riz'].max()+1) Npar_arr = np.array([gas_velo_at_particle_pos['rix'], gas_velo_at_particle_pos['riy'], gas_velo_at_particle_pos['riz']]) #rgrid_edges = (grid.x[1:]-(grid.x[1:]-grid.x[:-1])/2)[2:-2] xrange=np.arange(0,float(gas_velo_at_particle_pos['rix'].max())+2); xrange=xrange-0.5 yrange=np.arange(0,float(gas_velo_at_particle_pos['riy'].max())+2) zrange=np.arange(0,float(gas_velo_at_particle_pos['riz'].max())+2) Npar_hist, edges = np.histogramdd(Npar_arr.T, bins=(xrange, yrange, zrange)) Npar_hist, edges = np.histogramdd(Npar_arr.T, bins=(Nix, Niy, Niz)) gas_velo_at_particle_pos = { 'time': ff.t, 'par_pos': np.array([gas_velo_at_particle_pos['ipx'], gas_velo_at_particle_pos['ipy'], gas_velo_at_particle_pos['ipz']]), 'par_velo': np.array([gas_velo_at_particle_pos['vx'], gas_velo_at_particle_pos['vy'], gas_velo_at_particle_pos['vz']]), 'par_idx': np.array([gas_velo_at_particle_pos['rix'], gas_velo_at_particle_pos['riy'], gas_velo_at_particle_pos['riz']]), 'npar': np.array(Npar_hist[gas_velo_at_particle_pos['rix'], gas_velo_at_particle_pos['riy'], gas_velo_at_particle_pos['riz']]), 'gas_velo': np.array([gas_velo_at_particle_pos['ux'], gas_velo_at_particle_pos['uy'], gas_velo_at_particle_pos['uz']]) } print('## Saving dataset into '+save_destination+'...') pkl_save({'gas_velo_at_particle_pos': gas_velo_at_particle_pos, 't': ff.t}, save_filename, folder=save_destination) print('## Done!')
import numpy as np import pandas as pd import pidly import glob import json if __name__ == "__main__": input_dir = "../data/ew_known/tame_inputs/" output_dir = "../data/ew_known/tame_outputs_windowsize/" spectra = glob.glob(input_dir + "*wavsoln.fits") parameter = 'SPACING' parameter_space = np.linspace(1.5, 5.5, 5) idl = pidly.IDL('/Applications/exelis/idl/bin/idl') for spectrum in spectra: spec_label = spectrum.split('/')[-1].split('_wavsoln')[0] print(spec_label) line_dict = {} for parameter_value in parameter_space: # Read in Parameter File df = pd.read_csv('tame.par', delim_whitespace=True, header=None) # Modify Parameter File (Sweep Parameter & Working File) df.at[df.index[df[0] == "LOWERCUT"].tolist()[0], 1] = '0.99' # Obtained from extended_calibration.ipynb df.at[df.index[df[0] == "WORKNAME"].tolist()[0], 1] = input_dir + spec_label df.at[df.index[df[0] == "SPECTRUM"].tolist()[0], 1] = input_dir + spec_label+'.lpx'
def load_brightness(shot_num, t_start=8.0, t_end=28.0, delta=0.1, smooth=10.0, exclude=[20, 59, 60], adj=None, cmd_str=''): """ Function: st = load_brightness(shot_num, t_start, t_end, delta, smooth, exclude, adj, cmd_str) This version of load_brightness interfaces directly with the IDL implementation, via the pidly interface (see the signals README for instructions on setting this up). Inputs: - shot_num = [INT] The MST shot ID for the desired set of data - t_start = [FLOAT] The start time for the desired interval of SXR data. - t_end = [FLOAT] The end time for the desired interval of SXR data. - delta = [FLOAT] The desired sampling window for SXR data. Set to None to get the full signal. Note that sampling error will not be available in that case. - smooth = [FLOAT] The size of the smoothing window (10.0 is standard). - exclude = [[INT]] List of logicals which were excluded in the data file. By defaults excludes the NickAl2 channels. For older data make sure to exclude 69 - adj = [[FLOAT]] The time adjustment due to SXR trigger settings. Set to 0 for data past mid-2016 - cmd_str = [STR] Additional string to append to the IDL command. Outputs: - st['key'] = [DICT] Nested dictionary containing the SXR tomography diagnostic data, indexed by camera label. """ # Access (and initialize, if needed) the pidly object and assemble the command string idl = pidly.IDL() idl_str = "staus = sxr_mst_get_signals(St, /ms, shot=" + str( shot_num) + ", tst = " + str(t_start) + ", excl = " + str(exclude) idl_str += ", tend = " + str(t_end) # Optional keywods if delta is not None: idl_str += ", delta = " + str(delta) if smooth is not None: idl_str += ", sm = " + str(smooth) if len(cmd_str) == 0: idl_str += ")" else: idl_str += ", " + cmd_str + ")" # Create the structure in IDL and begin exporting the contents idl(idl_str) sxr_data = idl.ev('st.bright.data', use_cache=True) sxr_impact = idl.ev('st.bright.prel', use_cache=True) sxr_angles = idl.ev('st.bright.phi', use_cache=True) sxr_noise = idl.ev('st.bright.off_str.sxr_r_noise', use_cache=True) sxr_time = idl.ev('st.bright.time', use_cache=True) if delta is not None: sxr_error = idl.ev('st.bright.err', use_cache=True) # Organize the data by probe label and thick/thin convention. Now automated to account for excluded probes filt_list = [ 'A thick', 'B thick', 'C thick', 'D thick', 'A thin', 'B thin', 'C thin', 'D thin' ] brightness = {} impact_p = {} impact_angle = {} sigma = {} off_noise = {} logicals_inc = {} # Manual index in order to allow exclusion of specified logicals index = 0 for filt in filt_list: base_logical = filt_list.index(filt) * 10 + 1 data = [] error = [] impact = [] angles = [] noise = [] logs = [] for logical in range(base_logical, base_logical + 10): if logical not in exclude: data.append(np.transpose(sxr_data[:, index])) impact.append(sxr_impact[index]) angles.append(sxr_angles[index]) noise.append(sxr_noise[index]) logs.append(logical) if delta is not None: error.append(np.transpose(sxr_error[:, index])) else: error.append([]) index += 1 # Store into the dictionary brightness[filt] = np.array(data) sigma[filt] = np.array(error) impact_p[filt] = np.array(impact) impact_angle[filt] = np.array(angles) off_noise[filt] = np.array(noise) logicals_inc[filt] = logs # Also store same basic configuration info - logical indexing is fine config = { 'filters': idl.ev('st.bright.FILTERBE_THICK', use_cache=True), 'alpha': idl.ev('st.bright.alfa', use_cache=True), 'gain': idl.ev('st.bright.gain', use_cache=True), 'insertion': idl.ev('st.bright.insertion', use_cache=True) } # Assemble these into a single dictionary st = { 'bright': brightness, 'p': impact_p, 'phi': impact_angle, 'sigma': sigma, 'noise': sigma, 'logical': logicals_inc, 'shot': shot_num, 'time': sxr_time, 'config': config } # Close the IDL instance to prevent runaway processes idl.close() return AttrDict(st)
def get_data(self, trange, norm=0, atrange=[1.0, 1.1], res=0, verbose=1): if norm == 0: if verbose == 1: print('Data is not normalized') elif norm == 1: if verbose == 1: print('Data is normalized by trange average') elif norm == 2: if verbose == 1: print('Data is normalized by atrange average') self.trange = trange # open idl idl = pidly.IDL('/fusion/usc/opt/idl/idl84/bin/idl') # --- loop starts --- # clist_temp = self.clist.copy() for i, cname in enumerate(clist_temp): # set node if cname in VAR_NODE: node ='{:s}'.format(VAR_NODE[cname]) else: node = cname # load data try: #idl.pro('gadat,time,data,/alldata',node,self.shot,XMIN=self.trange[0]*1000.0,XMAX=self.trange[1]*1000.0) idl.pro('gadat2,time,data,/alldata',node,self.shot,XMIN=self.trange[0]*1000.0,XMAX=self.trange[1]*1000.0) time, v = idl.time, idl.data if verbose == 1: print("Read {:d} - {:s} (number of data points = {:d})".format(self.shot, node, len(v))) except: self.clist.remove(cname) if verbose == 1: print("Failed {:s}".format(node)) continue # [ms] -> [s] time = time/1000.0 # set data size idx = np.where((time >= trange[0])*(time <= trange[1])) idx1 = int(idx[0][0]) idx2 = int(idx[0][-1]+1) time = time[idx1:idx2] v = v[idx1:idx2] if norm == 1: v = v/np.mean(v) - 1 # expand dimension - concatenate v = np.expand_dims(v, axis=0) if i == 0: data = v else: data = np.concatenate((data, v), axis=0) # --- loop ends --- # self.time = time self.fs = round(1/(time[1] - time[0])/1000)*1000 self.data = data # get channel position self.channel_position() # close idl idl.close() return time, data
def invert_brightness(shot_num, t_start=8.0, t_end=28.0, delta=0.1, smooth=10.0, exclude=[20, 59, 60], thick=False, thin=False, **kwargs): """ Perform a tomographic inversion using the Cormack-Bessel technique. Makes use of Paolo's IDL library. Inputs: - shot_num = [INT] The MST shot ID for the desired set of data Optional: - t_start = [FLOAT] The start time for the desired interval of SXR data. - t_end = [FLOAT] The end time for the desired interval of SXR data. - delta = [FLOAT] The desired sampling window for SXR data. - smooth = [FLOAT] The size of the smoothing window (10.0 is standard). - exclude = [[INT]] List of logicals which were excluded in the data file. By default excludes the NickAl2 channels. For older data make sure to still exclude 69. - thick = [BOOL] Include only thick filter data. - thin = [BOOL] Include only thick filter data. - kwargs = Additional keywords are used to change the inversion Inversion keywords: Other keyword arguments will be used to alter the inversion options array passed directly to the IDL routine. The allowed arguments, according to the IDL documentation, are: ka = $ [ $ 'name=Cormack' # inversion method 'base=Bessel' # radial function base 'matname=matrix.dat' # not important 'mc=1' # n. of angular (poloidal) cos components 'ms=1' # n. of angular (poloidal) sin components 'ls=6' # n. of radial components 'svd_tol=0.100' # svd threshold 'p_ref=[0.0,0,0,0.0]' # coordinates of the origin of the axis # where the inversion will be performed 'n_nch=5' # n. of added edge lines of sight 'mst'=1 # specifies that we are working on Mst SXR data ] Note: The values of p_ref are [x0, y0, z0], signifying the location of the magnetic axis. These values are measured in meters, and z0 will typically be set to zero. The defaults arguments are p_ref = [0.06, 0.0, 0.0], signifying a 6cm Shafranov shift. Note: The value of svd_tol is the tolerance for stopping the iterative SVD inversion process. The default is 0.06, but can be increased (up to 0.1) as needed to smooth the reconstruction. """ # Load the data into idl idl = pidly.IDL() idl_str = "staus = sxr_mst_get_signals(St, /ms, shot=" + str( shot_num) + ", tst = " + str(t_start) idl_str += ", excl = " + str(exclude) + ", tend = " + str(t_end) idl_str += ", delta = " + str(delta) + ", sm = " + str(smooth) + ')' idl(idl_str) # Format keywords - check for supplied arguments and change if necessary ka = { 'name': 'Cormack', 'base': 'bessel', 'matname': 'matrix.dat', 'mc': 1, 'ms': 1, 'ls': 6, 'svd_tol': 0.06, 'p_ref': [0.06, 0.00, 0.0] } if len(kwargs) > 0: for key, value in kwargs.items(): ka[key] = value ka_str = 'ka = ' + str( ['{0:}={1:}'.format(key, value) for key, value in ka.items()]) idl(ka_str) idl_str = "st_out = sxr_MST_get_emiss(st, st_emiss=st_emiss, status=status, ka=ka" if thick: idl_str += ', /thick' elif thin: idl_str += ', /thin' idl_str += ')' # Do the inversion idl(idl_str) # Import the data into python results = { 'emiss': idl.ev('st_emiss.emiss', use_cache=True).T, 'time': idl.ev('st_emiss.t', use_cache=True), 'xs': idl.ev('st_emiss.x_emiss', use_cache=True), 'ys': idl.ev('st_emiss.y_emiss', use_cache=True), 'major': idl.ev('st_emiss.majr'), 'radius': idl.ev('st_emiss.radius'), 'kwargs': ka } # Close the IDL instance to prevent runaway processes idl.close() return AttrDict(results)