def get_spectrum(self, fname, gal_id, stype='out'): """ For combined spec files """ # if fname is None: # run = glob.glob('{0}/snap*.galaxy*.rt{1}.sed'.format(directory,stype)) # else: # run = glob.glob('{0}/{1}'.format(directory,fname)) # if len(run) > 1: # raise ValueError('More than one spectrum in directory') # elif len(run) == 0: # raise ValueError('No output spectrum in this directory') if gal_id is None: m = ModelOutput(filename=fname) else: m = ModelOutput(filename=fname, group=gal_id) wav, lum = m.get_sed(inclination='all', aperture=-1) # set units wav = np.asarray(wav) * u.micron lum = np.asarray(lum) * u.erg / u.s return (wav, lum)
def load_obs(sed_file): from hyperion.model import ModelOutput from astropy.cosmology import Planck15 from astropy import units as u from astropy import constants m = ModelOutput(sed_file) wav,flux = m.get_sed(inclination='all',aperture=-1) wav = np.asarray(wav)*u.micron #wav is in micron wav = wav.to(u.AA) #wav *= (1.+2.) flux = np.asarray(flux)*u.erg/u.s dl = 10.0*u.pc #dl = Planck15.luminosity_distance(2.0) dl = dl.to(u.cm) flux /= (4.*3.14*dl**2.) nu = constants.c.cgs/(wav.to(u.cm)) nu = nu.to(u.Hz) flux /= nu flux = flux.to(u.Jy) maggies = flux[0] / 3631. return maggies.value, wav
def build_obs(**kwargs): from hyperion.model import ModelOutput from astropy import units as u from astropy import constants print('galaxy: ', sys.argv[1]) m = ModelOutput( "/ufrc/narayanan/s.lower/pd_runs/simba_m25n512/snap305_dustscreen/snap305/snap305.galaxy" + str(sys.argv[1]) + ".rtout.sed") wav, flux = m.get_sed(inclination=0, aperture=-1) wav = np.asarray(wav) * u.micron #wav is in micron wav = wav.to(u.AA) flux = np.asarray(flux) * u.erg / u.s dl = (10. * u.pc).to(u.cm) flux /= (4. * 3.14 * dl**2.) nu = constants.c.cgs / (wav.to(u.cm)) nu = nu.to(u.Hz) flux /= nu flux = flux.to(u.Jy) maggies = flux / 3631. filters_unsorted = load_filters(filternames) waves_unsorted = [x.wave_mean for x in filters_unsorted] filters = [x for _, x in sorted(zip(waves_unsorted, filters_unsorted))] flx = [] flxe = [] for i in range(len(filters)): flux_range = [] wav_range = [] for j in filters[i].wavelength: flux_range.append(maggies[find_nearest(wav.value, j)].value) wav_range.append(wav[find_nearest(wav.value, j)].value) a = np.trapz(wav_range * filters[i].transmission * flux_range, wav_range, axis=-1) b = np.trapz(wav_range * filters[i].transmission, wav_range) flx.append(a / b) flxe.append(0.03 * flx[i]) flx = np.asarray(flx) flxe = np.asarray(flxe) flux_mag = flx unc_mag = flxe obs = {} obs['filters'] = filters obs['maggies'] = flux_mag obs['maggies_unc'] = unc_mag obs['phot_mask'] = np.isfinite(flux_mag) obs['wavelength'] = None obs['spectrum'] = None return obs
def test_docs_sed(self): import numpy as np from hyperion.model import ModelOutput from hyperion.util.constants import pc from fluxcompensator.sed import * # read in from HYPERION m = ModelOutput( os.path.join(os.path.dirname(__file__), 'B5_class2_45.rtout')) array = m.get_sed(group=0, inclination=0, distance=300 * pc, units='ergs/cm^2/s') # initial FluxCompensator array s = SyntheticSED(input_array=array, unit_out='ergs/cm^2/s', name='test_sed')
import numpy as np from hyperion.model import ModelOutput from hyperion.util.constants import kpc from astropy.io import fits for tau in [0.1, 1.0, 20.]: input_file = 'bm1_slab_effgrain_tau_{tau:05.2f}_seds.rtout'.format(tau=tau) m = ModelOutput(input_file) for iincl, theta in enumerate([0, 30, 60, 90, 120, 150, 180]): sed = m.get_sed(inclination=iincl, units='Jy', distance=10. * kpc, aperture=-1) output_file = 'seds/bm1_slab_effgrain_tau_{tau:06.2f}_theta_{theta:03d}_sed.dat'.format( tau=tau, theta=theta) np.savetxt(output_file, zip(sed.wav, sed.val), fmt="%10.4e")
'cav_theta','innerdustfile','outerdustfile','beta','L_sun','env_mass','env_power'] oldtypes = ['<S30','<S30','f8','f8','f8','f8','<S30','f8','f8','f8','<S30','<S30','f8','f8','f8','f8'] newgrid = Table(names=oldparams+['ext','inc']+names,dtype=oldtypes+['f8','f8']+['f8' for val in names]) # calculate value for each band for each model, extinction value and inclination for i in range(len(grid)): # load model fname = folder[0]+grid['name'][i]+'.rtout' if i%10 ==0: print "Model: ",fname if os.path.exists(fname):# and grid['env_rmax'][i]==5000.0 and grid['disk_mass'][i]==0.003: #print "Model found!" mo = ModelOutput(fname) # load sed from model sed = mo.get_sed(aperture=-1, inclination='all', distance=100.*pc,units='Jy') for extinction in extinctions: # calculate optical depth tau_ext1 = Chi(sed.wav)/Chi(0.550)/1.086 tau = tau_ext1*extinction #print "tau,",tau # calculate extinction for all inclinations ext = np.array([np.exp(-tau) for shape in range(sed.val.shape[0])]) #print "ext,",ext # apply extinction to model extinct_values = np.log10(sed.val.transpose()*ext.T) #print "extinct_values,extinct_values.shape",extinct_values,extinct_values.shape
import h5py import fsps #SKIRT STUFF sedfile = '/home/desika.narayanan/SKIRT/run/pd_test.dust_i90_sed.dat' run = '/ufrc/narayanan/desika.narayanan/pd/tests/SKIRT/mw_zoom/pd_skirt_comparison.134.rtout.sed' data = np.loadtxt(sedfile) skirt_lam = data[:, 0] skirt_flambda = data[:, 1] * u.W / u.m**2 / u.micron skirt_flambda = skirt_flambda.to(u.erg / u.s / u.cm**2. / u.angstrom) #PD stuff m = ModelOutput(run) pd_wav, pd_flux = m.get_sed(inclination='all', aperture=-1, units='ergs/s') distance = 1. * u.Mpc.to(u.cm) pd_flux *= u.erg / u.s pd_flux /= (4. * np.pi * distance**2. ) #SKIRT seems to say F = L/d^2 instead of F = L/(4*pi*d^2) pd_wav *= u.micron pd_flux /= pd_wav.to(u.angstrom) fig = plt.figure() ax = fig.add_subplot(111) ax.loglog(pd_wav, pd_flux[0, :], label='powderday', lw=3) ax.loglog(skirt_lam, skirt_flambda, label='SKIRT') plt.legend() ax.set_xlim([0.05, 1000]) ax.set_ylim([1.e-17, 1.e-8]) ax.set_xlabel(r'Wavelength ($\mu$m)')
import matplotlib.pyplot as plt from hyperion.model import ModelOutput from hyperion.util.constants import pc m = ModelOutput('class2_sed.rtout') fig = plt.figure() ax = fig.add_subplot(1, 1, 1) # Total SED sed = m.get_sed(inclination=0, aperture=-1, distance=300 * pc) ax.loglog(sed.wav, sed.val, color='black', lw=3, alpha=0.5) # Direct stellar photons sed = m.get_sed(inclination=0, aperture=-1, distance=300 * pc, component='source_emit') ax.loglog(sed.wav, sed.val, color='blue') # Scattered stellar photons sed = m.get_sed(inclination=0, aperture=-1, distance=300 * pc, component='source_scat') ax.loglog(sed.wav, sed.val, color='teal') # Direct dust photons sed = m.get_sed(inclination=0, aperture=-1, distance=300 * pc, component='dust_emit') ax.loglog(sed.wav, sed.val, color='red') # Scattered dust photons sed = m.get_sed(inclination=0, aperture=-1, distance=300 * pc,
def extract_hyperion(filename,indir=None,outdir=None,dstar=178.0,wl_aper=None,save=True): def l_bol(wl,fv,dist=178.0): import numpy as np import astropy.constants as const # wavelength unit: um # Flux density unit: Jy # # constants setup # c = const.c.cgs.value pc = const.pc.cgs.value PI = np.pi SL = const.L_sun.cgs.value # Convert the unit from Jy to erg s-1 cm-2 Hz-1 fv = np.array(fv)*1e-23 freq = c/(1e-4*np.array(wl)) diff_dum = freq[1:]-freq[0:-1] freq_interpol = np.hstack((freq[0:-1]+diff_dum/2.0,freq[0:-1]+diff_dum/2.0,freq[0],freq[-1])) freq_interpol = freq_interpol[np.argsort(freq_interpol)[::-1]] fv_interpol = np.empty(len(freq_interpol)) # calculate the histogram style of spectrum # for i in range(0,len(fv)): if i == 0: fv_interpol[i] = fv[i] else: fv_interpol[2*i-1] = fv[i-1] fv_interpol[2*i] = fv[i] fv_interpol[-1] = fv[-1] dv = freq_interpol[0:-1]-freq_interpol[1:] dv = np.delete(dv,np.where(dv==0)) fv = fv[np.argsort(freq)] freq = freq[np.argsort(freq)] return (np.trapz(fv,freq)*4.*PI*(dist*pc)**2)/SL import matplotlib.pyplot as plt import numpy as np import os from hyperion.model import ModelOutput from hyperion.model import Model from scipy.interpolate import interp1d from hyperion.util.constants import pc, c, lsun # Read in the observation data and calculate the noise & variance if indir == None: indir = '/Users/yaolun/bhr71/' if outdir == None: outdir = '/Users/yaolun/bhr71/hyperion/' # assign the file name from the input file print_name = os.path.splitext(os.path.basename(filename))[0] # [wl_pacs,flux_pacs,unc_pacs] = np.genfromtxt(indir+'BHR71_centralSpaxel_PointSourceCorrected_CorrectedYES_trim_continuum.txt',\ dtype='float',skip_header=1).T # Convert the unit from Jy to erg cm-2 Hz-1 flux_pacs = flux_pacs*1e-23 [wl_spire,flux_spire] = np.genfromtxt(indir+'BHR71_spire_corrected_continuum.txt',dtype='float',skip_header=1).T flux_spire = flux_spire*1e-23 wl_obs = np.hstack((wl_pacs,wl_spire)) flux_obs = np.hstack((flux_pacs,flux_spire)) [wl_pacs_data,flux_pacs_data,unc_pacs_data] = np.genfromtxt(indir+'BHR71_centralSpaxel_PointSourceCorrected_CorrectedYES_trim.txt',\ dtype='float').T [wl_spire_data,flux_spire_data] = np.genfromtxt(indir+'BHR71_spire_corrected.txt',\ dtype='float').T [wl_pacs_flat,flux_pacs_flat,unc_pacs_flat] = np.genfromtxt(indir+'BHR71_centralSpaxel_PointSourceCorrected_CorrectedYES_trim_flat_spectrum.txt',\ dtype='float',skip_header=1).T [wl_spire_flat,flux_spire_flat] = np.genfromtxt(indir+'BHR71_spire_corrected_flat_spectrum.txt',dtype='float',skip_header=1).T # Convert the unit from Jy to erg cm-2 Hz-1 flux_pacs_flat = flux_pacs_flat*1e-23 flux_spire_flat = flux_spire_flat*1e-23 flux_pacs_data = flux_pacs_data*1e-23 flux_spire_data = flux_spire_data*1e-23 wl_pacs_noise = wl_pacs_data flux_pacs_noise = flux_pacs_data-flux_pacs-flux_pacs_flat wl_spire_noise = wl_spire_data flux_spire_noise = flux_spire_data-flux_spire-flux_spire_flat # Read in the Spitzer IRS spectrum [wl_irs, flux_irs]= (np.genfromtxt(indir+'bhr71_spitzer_irs.txt',skip_header=2,dtype='float').T)[0:2] # Convert the unit from Jy to erg cm-2 Hz-1 flux_irs = flux_irs*1e-23 # Remove points with zero or negative flux ind = flux_irs > 0 wl_irs = wl_irs[ind] flux_irs = flux_irs[ind] # Calculate the local variance (for spire), use the instrument uncertainty for pacs # wl_noise_5 = wl_spire_noise[(wl_spire_noise > 194)*(wl_spire_noise <= 304)] flux_noise_5 = flux_spire_noise[(wl_spire_noise > 194)*(wl_spire_noise <= 304)] wl_noise_6 = wl_spire_noise[wl_spire_noise > 304] flux_noise_6 = flux_spire_noise[wl_spire_noise > 304] wl_noise = [wl_pacs_data[wl_pacs_data<=190.31],wl_noise_5,wl_noise_6] flux_noise = [unc_pacs[wl_pacs_data<=190.31],flux_noise_5,flux_noise_6] sig_num = 20 sigma_noise = [] for i in range(0,len(wl_noise)): sigma_dum = np.zeros([len(wl_noise[i])]) for iwl in range(0,len(wl_noise[i])): if iwl < sig_num/2: sigma_dum[iwl] = np.std(np.hstack((flux_noise[i][0:sig_num/2],flux_noise[i][0:sig_num/2-iwl]))) elif len(wl_noise[i])-iwl < sig_num/2: sigma_dum[iwl] = np.std(np.hstack((flux_noise[i][iwl:],flux_noise[i][len(wl_noise[i])-sig_num/2:]))) else: sigma_dum[iwl] = np.std(flux_noise[i][iwl-sig_num/2:iwl+sig_num/2]) sigma_noise = np.hstack((sigma_noise,sigma_dum)) sigma_noise = np.array(sigma_noise) # Read in the photometry data phot = np.genfromtxt(indir+'bhr71.txt',dtype=None,skip_header=1,comments='%') wl_phot = [] flux_phot = [] flux_sig_phot = [] note = [] for i in range(0,len(phot)): wl_phot.append(phot[i][0]) flux_phot.append(phot[i][1]) flux_sig_phot.append(phot[i][2]) note.append(phot[i][4]) wl_phot = np.array(wl_phot) # Convert the unit from Jy to erg cm-2 Hz-1 flux_phot = np.array(flux_phot)*1e-23 flux_sig_phot = np.array(flux_sig_phot)*1e-23 # Print the observed L_bol wl_tot = np.hstack((wl_irs,wl_obs,wl_phot)) flux_tot = np.hstack((flux_irs,flux_obs,flux_phot)) flux_tot = flux_tot[np.argsort(wl_tot)] wl_tot = wl_tot[np.argsort(wl_tot)] l_bol_obs = l_bol(wl_tot,flux_tot*1e23) # Open the model m = ModelOutput(filename) if wl_aper == None: wl_aper = [3.6, 4.5, 5.8, 8.0, 10, 16, 20, 24, 35, 70, 100, 160, 250, 350, 500, 850] # Create the plot mag = 1.5 fig = plt.figure(figsize=(8*mag,6*mag)) ax_sed = fig.add_subplot(1, 1, 1) # Plot the observed SED # plot the observed spectra pacs, = ax_sed.plot(np.log10(wl_pacs),np.log10(c/(wl_pacs*1e-4)*flux_pacs),'-',color='DimGray',linewidth=1.5*mag, alpha=0.7) spire, = ax_sed.plot(np.log10(wl_spire),np.log10(c/(wl_spire*1e-4)*flux_spire),'-',color='DimGray',linewidth=1.5*mag, alpha=0.7) irs, = ax_sed.plot(np.log10(wl_irs),np.log10(c/(wl_irs*1e-4)*flux_irs),'-',color='DimGray',linewidth=1.5*mag, alpha=0.7) # ax_sed.text(0.75,0.9,r'$\rm{L_{bol}= %5.2f L_{\odot}}$' % l_bol_obs,fontsize=mag*16,transform=ax_sed.transAxes) # plot the observed photometry data photometry, = ax_sed.plot(np.log10(wl_phot),np.log10(c/(wl_phot*1e-4)*flux_phot),'s',mfc='DimGray',mec='k',markersize=8) ax_sed.errorbar(np.log10(wl_phot),np.log10(c/(wl_phot*1e-4)*flux_phot),\ yerr=[np.log10(c/(wl_phot*1e-4)*flux_phot)-np.log10(c/(wl_phot*1e-4)*(flux_phot-flux_sig_phot)),\ np.log10(c/(wl_phot*1e-4)*(flux_phot+flux_sig_phot))-np.log10(c/(wl_phot*1e-4)*flux_phot)],\ fmt='s',mfc='DimGray',mec='k',markersize=8) # Extract the SED for the smallest inclination and largest aperture, and # scale to 300pc. In Python, negative indices can be used for lists and # arrays, and indicate the position from the end. So to get the SED in the # largest aperture, we set aperture=-1. # aperture group is aranged from smallest to infinite sed_inf = m.get_sed(group=0, inclination=0, aperture=-1, distance=dstar * pc) # l_bol_sim = l_bol(sed_inf.wav, sed_inf.val/(c/sed_inf.wav*1e4)*1e23) # print sed.wav, sed.val # print 'Bolometric luminosity of simulated spectrum: %5.2f lsun' % l_bol_sim # plot the simulated SED # sim, = ax_sed.plot(np.log10(sed_inf.wav), np.log10(sed_inf.val), '-', color='k', linewidth=1.5*mag, alpha=0.7) # get flux at different apertures flux_aper = np.empty_like(wl_aper) unc_aper = np.empty_like(wl_aper) for i in range(0, len(wl_aper)): sed_dum = m.get_sed(group=i+1, inclination=0, aperture=-1, distance=dstar * pc) # use a rectangle function the average the simulated SED # apply the spectral resolution if (wl_aper[i] < 50.) & (wl_aper[i] >= 5): res = 60. elif wl_aper[i] < 5: res = 10. else: res = 1000. ind = np.where((sed_dum.wav < wl_aper[i]*(1+1./res)) & (sed_dum.wav > wl_aper[i]*(1-1./res))) if len(ind[0]) != 0: flux_aper[i] = np.mean(sed_dum.val[ind]) else: f = interp1d(sed_dum.wav, sed_dum.val) flux_aper[i] = f(wl_aper[i]) # perform the same procedure of flux extraction of aperture flux with observed spectra wl_aper = np.array(wl_aper) obs_aper_wl = wl_aper[(wl_aper >= min(wl_irs)) & (wl_aper <= max(wl_spire))] obs_aper_sed = np.empty_like(obs_aper_wl) sed_tot = c/(wl_tot*1e-4)*flux_tot # wl_tot and flux_tot are already hstacked and sorted by wavelength for i in range(0, len(obs_aper_wl)): if (obs_aper_wl[i] < 50.) & (obs_aper_wl[i] >= 5): res = 60. elif obs_aper_wl[i] < 5: res = 10. else: res = 1000. ind = np.where((wl_tot < obs_aper_wl[i]*(1+1./res)) & (wl_tot > obs_aper_wl[i]*(1-1./res))) if len(ind[0]) != 0: obs_aper_sed[i] = np.mean(sed_tot[ind]) else: f = interp1d(wl_tot, sed_tot) obs_aper_sed[i] = f(wl_aper[i]) aper_obs, = ax_sed.plot(np.log10(obs_aper_wl),np.log10(obs_aper_sed), 's-', mec='None', mfc='r', color='r',markersize=10, linewidth=1.5) # # interpolate the uncertainty (maybe not the best way to do this) # print sed_dum.unc # f = interp1d(sed_dum.wav, sed_dum.unc) # unc_aper[i] = f(wl_aper[i]) # if wl_aper[i] == 9.7: # ax_sed.plot(np.log10(sed_dum.wav), np.log10(sed_dum.val), '-', linewidth=1.5*mag) # print l_bol(sed_dum.wav, sed_dum.val/(c/sed_dum.wav*1e4)*1e23) aper, = ax_sed.plot(np.log10(wl_aper),np.log10(flux_aper),'o-', mec='Blue', mfc='None', color='b',markersize=12, markeredgewidth=3, linewidth=1.7) # calculate the bolometric luminosity of the aperture l_bol_sim = l_bol(wl_aper, flux_aper/(c/np.array(wl_aper)*1e4)*1e23) print 'Bolometric luminosity of simulated spectrum: %5.2f lsun' % l_bol_sim # print out the sed into ascii file for reading in later if save == True: # unapertured SED foo = open(outdir+print_name+'_sed_inf.txt','w') foo.write('%12s \t %12s \n' % ('wave','vSv')) for i in range(0, len(sed_inf.wav)): foo.write('%12g \t %12g \n' % (sed_inf.wav[i], sed_inf.val[i])) foo.close() # SED with convolution of aperture sizes foo = open(outdir+print_name+'_sed_w_aperture.txt','w') foo.write('%12s \t %12s \n' % ('wave','vSv')) for i in range(0, len(wl_aper)): foo.write('%12g \t %12g \n' % (wl_aper[i], flux_aper[i])) foo.close() # Read in and plot the simulated SED produced by RADMC-3D using the same parameters # [wl,fit] = np.genfromtxt(indir+'hyperion/radmc_comparison/spectrum.out',dtype='float',skip_header=3).T # l_bol_radmc = l_bol(wl,fit*1e23/dstar**2) # radmc, = ax_sed.plot(np.log10(wl),np.log10(c/(wl*1e-4)*fit/dstar**2),'-',color='DimGray', linewidth=1.5*mag, alpha=0.5) # print the L bol of the simulated SED (both Hyperion and RADMC-3D) # lg_sim = ax_sed.legend([sim,radmc],[r'$\rm{L_{bol,sim}=%5.2f~L_{\odot},~L_{center}=9.18~L_{\odot}}$' % l_bol_sim, \ # r'$\rm{L_{bol,radmc3d}=%5.2f~L_{\odot},~L_{center}=9.18~L_{\odot}}$' % l_bol_radmc],\ # loc='lower right',fontsize=mag*16) # read the input central luminosity by reading in the source information from output file dum = Model() dum.use_sources(filename) L_cen = dum.sources[0].luminosity/lsun # lg_sim = ax_sed.legend([sim],[r'$\rm{L_{bol,sim}=%5.2f~L_{\odot},~L_{center}=%5.2f~L_{\odot}}$' % (l_bol_sim, L_cen)], \ # loc='lower right',fontsize=mag*16) # lg_sim = ax_sed.legend([sim],[r'$\rm{L_{bol,sim}=%5.2f~L_{\odot},~L_{bol,obs}=%5.2f~L_{\odot}}$' % (l_bol_sim, l_bol_obs)], \ # loc='lower right',fontsize=mag*16) # text = ax_sed.text(0.2 ,0.05 ,r'$\rm{L_{bol,simulation}=%5.2f~L_{\odot},~L_{bol,observation}=%5.2f~L_{\odot}}$' % (l_bol_sim, l_bol_obs),fontsize=mag*16,transform=ax_sed.transAxes) # text.set_bbox(dict( edgecolor='k',facecolor='None',alpha=0.3,pad=10.0)) # plot setting ax_sed.set_xlabel(r'$\rm{log\,\lambda\,({\mu}m)}$',fontsize=mag*20) ax_sed.set_ylabel(r'$\rm{log\,\nu S_{\nu}\,(erg\,cm^{-2}\,s^{-1})}$',fontsize=mag*20) [ax_sed.spines[axis].set_linewidth(1.5*mag) for axis in ['top','bottom','left','right']] ax_sed.minorticks_on() ax_sed.tick_params('both',labelsize=mag*18,width=1.5*mag,which='major',pad=15,length=5*mag) ax_sed.tick_params('both',labelsize=mag*18,width=1.5*mag,which='minor',pad=15,length=2.5*mag) ax_sed.set_ylim([-13,-7.5]) ax_sed.set_xlim([0,3]) # lg_data = ax_sed.legend([sim, aper], [r'$\rm{w/o~aperture}$', r'$\rm{w/~aperture}$'], \ # loc='upper left', fontsize=14*mag, framealpha=0.3, numpoints=1) lg_data = ax_sed.legend([irs, photometry, aper, aper_obs],\ [r'$\rm{observation}$',\ r'$\rm{photometry}$',r'$\rm{F_{aper,sim}}$',r'$\rm{F_{aper,obs}}$'],\ loc='upper left',fontsize=14*mag,numpoints=1,framealpha=0.3) # plt.gca().add_artist(lg_sim) # Write out the plot fig.savefig(outdir+print_name+'_sed.pdf',format='pdf',dpi=300,bbox_inches='tight') fig.clf() # Package for matching the colorbar from mpl_toolkits.axes_grid1 import make_axes_locatable # Extract the image for the first inclination, and scale to 300pc. We # have to specify group=1 as there is no image in group 0. image = m.get_image(group=len(wl_aper)+1, inclination=0, distance=dstar * pc, units='MJy/sr') # image = m.get_image(group=14, inclination=0, distance=dstar * pc, units='MJy/sr') # Open figure and create axes # fig = plt.figure(figsize=(8, 8)) fig, axarr = plt.subplots(3, 3, sharex='col', sharey='row',figsize=(13.5,12)) # Pre-set maximum for colorscales VMAX = {} # VMAX[3.6] = 10. # VMAX[24] = 100. # VMAX[160] = 2000. # VMAX[500] = 2000. VMAX[100] = 10. VMAX[250] = 100. VMAX[500] = 2000. VMAX[1000] = 2000. # We will now show four sub-plots, each one for a different wavelength # for i, wav in enumerate([3.6, 24, 160, 500]): # for i, wav in enumerate([100, 250, 500, 1000]): # for i, wav in enumerate([4.5, 9.7, 24, 40, 70, 100, 250, 500, 1000]): for i, wav in enumerate([3.6, 8.0, 9.7, 24, 40, 100, 250, 500, 1000]): # ax = fig.add_subplot(3, 3, i + 1) ax = axarr[i/3, i%3] # Find the closest wavelength iwav = np.argmin(np.abs(wav - image.wav)) # Calculate the image width in arcseconds given the distance used above rmax = max(m.get_quantities().r_wall) w = np.degrees(rmax / image.distance) * 3600. # w = np.degrees((1.5 * pc) / image.distance) * 60. # Image in the unit of MJy/sr # Change it into erg/s/cm2/Hz/sr factor = 1e-23*1e6 # avoid zero in log val = image.val[:, :, iwav] * factor + 1e-30 # This is the command to show the image. The parameters vmin and vmax are # the min and max levels for the colorscale (remove for default values). im = ax.imshow(np.log10(val), vmin= -22, vmax= -12, cmap=plt.cm.jet, origin='lower', extent=[-w, w, -w, w], aspect=1) # Colorbar setting # create an axes on the right side of ax. The width of cax will be 5% # of ax and the padding between cax and ax will be fixed at 0.05 inch. if (i+1) % 3 == 0: divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = fig.colorbar(im, cax=cax) cb.solids.set_edgecolor("face") cb.ax.minorticks_on() cb.ax.set_ylabel(r'$\rm{log(I_{\nu})\,[erg\,s^{-2}\,cm^{-2}\,Hz^{-1}\,sr^{-1}]}$',fontsize=12) cb_obj = plt.getp(cb.ax.axes, 'yticklabels') plt.setp(cb_obj,fontsize=12) if (i+1) == 7: # Finalize the plot ax.set_xlabel('RA Offset (arcsec)', fontsize=14) ax.set_ylabel('Dec Offset (arcsec)', fontsize=14) ax.tick_params(axis='both', which='major', labelsize=16) ax.set_adjustable('box-forced') ax.text(0.7,0.88,str(wav) + r'$\rm{\,\mu m}$',fontsize=18,color='white',weight='bold',transform=ax.transAxes) fig.subplots_adjust(hspace=0,wspace=-0.2) # Adjust the spaces between the subplots # plt.tight_layout() fig.savefig(outdir+print_name+'_cube_plot.png', format='png', dpi=300, bbox_inches='tight') fig.clf()
z = 2.025 with open('m100_sed/galaxy_selection.json', 'r') as fp: _dat = json.load(fp)[snap] gidx = list(_dat.keys()) hidx = np.array([int(h['hidx']) for k, h in _dat.items()]) #_coods = [h['lcone_pos'] for k,h in _dat.items()] for _gidx in ['3']: #gidx: # snap_fname = f'{rt_directory}/snap_{snap}/gal_{_gidx}/snap{snap}.galaxy*.rtout.sed' snap_fname = f'{rt_directory}/snap_{snap}/gal_{_gidx}/snap{snap}.galaxy*.rtout.sed' fname = glob.glob(snap_fname)[0] m = ModelOutput(filename=fname) #,group='00000') wav, lum = m.get_sed(inclination='all', aperture=-1) ## High res snap_fname = f'{rt_directory}/snap_{snap}_hires/gal_{_gidx}/snap{snap}.galaxy*.rtout.sed' fname = glob.glob(snap_fname)[0] m = ModelOutput(filename=fname) #,group='00000') wav_hr, lum_hr = m.get_sed(inclination='all', aperture=-1) # with h5py.File('sed_out.h5','a') as f: # f.create_group(_gidx) # dset = f.create_dataset('%s/Wavelength'%_gidx, data=wav) # dset.attrs['Units'] = 'microns' # dset = f.create_dataset('%s/SED'%_gidx, data=lum) # dset.attrs['Units'] = 'erg/s'
import matplotlib.pyplot as plt from hyperion.model import ModelOutput from hyperion.util.constants import pc m = ModelOutput('class2_sed.rtout') fig = plt.figure() ax = fig.add_subplot(1, 1, 1) # Extract all SEDs sed = m.get_sed(inclination='all', aperture=-1, distance=300 * pc) # Plot SED for each inclination for i in range(sed.val.shape[0]): ax.loglog(sed.wav, sed.val[i, :], color='black') ax.set_xlabel(r'$\lambda$ [$\mu$m]') ax.set_ylabel(r'$\lambda F_\lambda$ [ergs/s/cm$^2$]') ax.set_xlim(0.1, 2000.) ax.set_ylim(2.e-16, 2.e-9) fig.savefig('class2_sed_plot_incl.png')
def extract_hyperion(filename, indir=None, outdir=None, dstar=200.0, aperture=None, save=True, filter_func=False, plot_all=False, clean=False, exclude_wl=[], log=True, image=True, obj='BHR71', print_data_w_aper=False, mag=1.5): """ filename: The path to Hyperion output file indir: The path to the directory which contains observations data outdir: The path to the directory for storing extracted plots and ASCII files """ def l_bol(wl, fv, dstar): import numpy as np import astropy.constants as const # wavelength unit: um # Flux density unit: Jy # constants setup # c = const.c.cgs.value pc = const.pc.cgs.value PI = np.pi SL = const.L_sun.cgs.value # Convert the unit from Jy to erg s-1 cm-2 Hz-1 fv = np.array(fv) * 1e-23 freq = c / (1e-4 * np.array(wl)) diff_dum = freq[1:] - freq[0:-1] freq_interpol = np.hstack( (freq[0:-1] + diff_dum / 2.0, freq[0:-1] + diff_dum / 2.0, freq[0], freq[-1])) freq_interpol = freq_interpol[np.argsort(freq_interpol)[::-1]] fv_interpol = np.empty(len(freq_interpol)) # calculate the histogram style of spectrum # for i in range(0, len(fv)): if i == 0: fv_interpol[i] = fv[i] else: fv_interpol[2 * i - 1] = fv[i - 1] fv_interpol[2 * i] = fv[i] fv_interpol[-1] = fv[-1] dv = freq_interpol[0:-1] - freq_interpol[1:] dv = np.delete(dv, np.where(dv == 0)) fv = fv[np.argsort(freq)] freq = freq[np.argsort(freq)] return (np.trapz(fv, freq) * 4. * PI * (dstar * pc)**2) / SL # function for properly calculating uncertainty of spectrophotometry value def unc_spectrophoto(wl, unc, trans): # adopting smiliar procedure as Trapezoidal rule # (b-a) * [ f(a) + f(b) ] / 2 # return (np.sum(trans[:-1]**2 * unc[:-1]**2 * (wl[1:] - wl[:-1])**2) / np.trapz(trans, x=wl)**2)**0.5 # to avoid X server error import matplotlib as mpl mpl.use('Agg') # import matplotlib.pyplot as plt import numpy as np import os from hyperion.model import ModelOutput, Model from scipy.interpolate import interp1d from hyperion.util.constants import pc, c, lsun, au from astropy.io import ascii import sys from phot_filter import phot_filter from get_obs import get_obs # Open the model m = ModelOutput(filename) # Read in the observation data and calculate the noise & variance if indir == None: indir = raw_input('Path to the observation data: ') if outdir == None: outdir = raw_input('Path for the output: ') # assign the file name from the input file print_name = os.path.splitext(os.path.basename(filename))[0] # use a canned function to extract observational data obs_data = get_obs(indir, obj=obj) # unit in um, Jy wl_tot, flux_tot, unc_tot = obs_data['spec'] flux_tot = flux_tot * 1e-23 # convert unit from Jy to erg s-1 cm-2 Hz-1 unc_tot = unc_tot * 1e-23 l_bol_obs = l_bol(wl_tot, flux_tot * 1e23, dstar) wl_phot, flux_phot, flux_sig_phot = obs_data['phot'] flux_phot = flux_phot * 1e-23 # convert unit from Jy to erg s-1 cm-2 Hz-1 flux_sig_phot = flux_sig_phot * 1e-23 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, 850],\ '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, 24.5]} # assign wl_aper and aper from dictionary of aperture wl_aper = aperture['wave'] aper = aperture['aperture'] # create the non-repetitive aperture list and index array aper_reduced = sorted(list(set(aper))) index_reduced = np.arange( 1, len(aper_reduced) + 1) # '+1': the zeroth slice corresponds to infinite aperture # Create the plot fig = plt.figure(figsize=(8 * mag, 6 * mag)) ax_sed = fig.add_subplot(1, 1, 1) # Plot the observed SED if not clean: color_seq = ['Green', 'Red', 'Black'] else: color_seq = ['DimGray', 'DimGray', 'DimGray'] # plot the observations # plot in log scale if log: pacs, = ax_sed.plot( np.log10(wl_tot[(wl_tot > 40) & (wl_tot < 190.31)]), np.log10(c / (wl_tot[(wl_tot > 40) & (wl_tot < 190.31)] * 1e-4) * flux_tot[(wl_tot > 40) & (wl_tot < 190.31)]), '-', color=color_seq[0], linewidth=1.5 * mag, alpha=0.7) spire, = ax_sed.plot(np.log10(wl_tot[wl_tot > 194]), np.log10(c / (wl_tot[wl_tot > 194] * 1e-4) * flux_tot[wl_tot > 194]), '-', color=color_seq[1], linewidth=1.5 * mag, alpha=0.7) irs, = ax_sed.plot(np.log10(wl_tot[wl_tot < 40]), np.log10(c / (wl_tot[wl_tot < 40] * 1e-4) * flux_tot[wl_tot < 40]), '-', color=color_seq[2], linewidth=1.5 * mag, alpha=0.7) photometry, = ax_sed.plot(np.log10(wl_phot), np.log10(c / (wl_phot * 1e-4) * flux_phot), 's', mfc='DimGray', mec='k', markersize=8) # plot the observed photometry data ax_sed.errorbar( np.log10(wl_phot), np.log10(c / (wl_phot * 1e-4) * flux_phot), yerr=[ np.log10(c / (wl_phot * 1e-4) * flux_phot) - np.log10(c / (wl_phot * 1e-4) * (flux_phot - flux_sig_phot)), np.log10(c / (wl_phot * 1e-4) * (flux_phot + flux_sig_phot)) - np.log10(c / (wl_phot * 1e-4) * flux_phot) ], fmt='s', mfc='DimGray', mec='k', markersize=8) # plot in normal scale else: pacs, = ax_sed.plot( np.log10(wl_tot[(wl_tot > 40) & (wl_tot < 190.31)]), c / (wl_tot[(wl_tot > 40) & (wl_tot < 190.31)] * 1e-4) * flux_tot[(wl_tot > 40) & (wl_tot < 190.31)], '-', color=color_seq[0], linewidth=1.5 * mag, alpha=0.7) spire, = ax_sed.plot(np.log10(wl_tot[wl_tot > 194]), c / (wl_tot[wl_tot > 194] * 1e-4) * flux_tot[wl_tot > 194], '-', color=color_seq[1], linewidth=1.5 * mag, alpha=0.7) irs, = ax_sed.plot(np.log10(wl_tot[wl_tot < 40]), c / (wl_tot[wl_tot < 40] * 1e-4) * flux_tot[wl_tot < 40], '-', color=color_seq[2], linewidth=1.5 * mag, alpha=0.7) photometry, = ax_sed.plot(wl_phot, c / (wl_phot * 1e-4) * flux_phot, 's', mfc='DimGray', mec='k', markersize=8) # plot the observed photometry data ax_sed.errorbar( np.log10(wl_phot), c / (wl_phot * 1e-4) * flux_phot, yerr=[ c / (wl_phot * 1e-4) * flux_phot - c / (wl_phot * 1e-4) * (flux_phot - flux_sig_phot), c / (wl_phot * 1e-4) * (flux_phot + flux_sig_phot) - c / (wl_phot * 1e-4) * flux_phot ], fmt='s', mfc='DimGray', mec='k', markersize=8) # if keyword 'clean' is not set, print L_bol derived from observations at upper right corner. if not clean: ax_sed.text(0.75, 0.9, r'$\rm{L_{bol}= %5.2f L_{\odot}}$' % l_bol_obs, fontsize=mag * 16, transform=ax_sed.transAxes) # getting SED with infinite aperture sed_inf = m.get_sed(group=0, inclination=0, aperture=-1, distance=dstar * pc, uncertainties=True) # plot the simulated SED with infinite aperture if clean == False: sim, = ax_sed.plot(np.log10(sed_inf.wav), np.log10(sed_inf.val), '-', color='GoldenRod', linewidth=0.5 * mag) ax_sed.fill_between(np.log10(sed_inf.wav), np.log10(sed_inf.val - sed_inf.unc), np.log10(sed_inf.val + sed_inf.unc), color='GoldenRod', alpha=0.5) ####################################### # get fluxes with different apertures # ####################################### # this is non-reduced wavelength array because this is for printing out fluxes at all channels specified by users flux_aper = np.zeros_like(wl_aper, dtype=float) unc_aper = np.zeros_like(wl_aper, dtype=float) a = np.zeros_like(wl_aper) + 1 color_list = plt.cm.jet(np.linspace(0, 1, len(wl_aper) + 1)) for i in range(0, len(wl_aper)): # occasionally users might want not to report some wavelength channels if wl_aper[i] in exclude_wl: continue # getting simulated SED from Hyperion output. (have to match with the reduced index) sed_dum = m.get_sed( group=index_reduced[np.where(aper_reduced == aper[i])], inclination=0, aperture=-1, distance=dstar * pc, uncertainties=True) # plot the whole SED from this aperture (optional) if plot_all == True: ax_sed.plot(np.log10(sed_dum.wav), np.log10(sed_dum.val), '-', color=color_list[i]) ax_sed.fill_between(np.log10(sed_dum.wav), np.log10(sed_dum.val-sed_dum.unc), np.log10(sed_dum.val+sed_dum.unc),\ color=color_list[i], alpha=0.5) # Extracting spectrophotometry values from simulated SED # Not using the photometry filer function to extract spectrophotometry values # sort by wavelength first. sort_wl = np.argsort(sed_dum.wav) val_sort = sed_dum.val[sort_wl] unc_sort = sed_dum.unc[sort_wl] wav_sort = sed_dum.wav[sort_wl] # Before doing that, convert vSv to F_lambda flux_dum = val_sort / wav_sort unc_dum = unc_sort / wav_sort # If no using filter function to extract the spectrophotometry, # then use the spectral resolution. if filter_func == False: # use a rectangle function the average the simulated SED # apply the spectral resolution if (wl_aper[i] < 50.) & (wl_aper[i] >= 5): res = 60. elif wl_aper[i] < 5: res = 10. else: res = 1000. ind = np.where((wav_sort < wl_aper[i] * (1 + 1. / res)) & (wav_sort > wl_aper[i] * (1 - 1. / res))) if len(ind[0]) != 0: flux_aper[i] = np.mean(flux_dum[ind]) unc_aper[i] = np.mean(unc_dum[ind]) else: f = interp1d(wav_sort, flux_dum) f_unc = interp1d(wav_sort, unc_dum) flux_aper[i] = f(wl_aper[i]) unc_aper[i] = f_unc(wl_aper[i]) # Using photometry filter function to extract spectrophotometry values else: # apply the filter function # decide the filter name if wl_aper[i] == 70: fil_name = 'Herschel PACS 70um' elif wl_aper[i] == 100: fil_name = 'Herschel PACS 100um' elif wl_aper[i] == 160: fil_name = 'Herschel PACS 160um' elif wl_aper[i] == 250: fil_name = 'Herschel SPIRE 250um' elif wl_aper[i] == 350: fil_name = 'Herschel SPIRE 350um' elif wl_aper[i] == 500: fil_name = 'Herschel SPIRE 500um' elif wl_aper[i] == 3.6: fil_name = 'IRAC Channel 1' elif wl_aper[i] == 4.5: fil_name = 'IRAC Channel 2' elif wl_aper[i] == 5.8: fil_name = 'IRAC Channel 3' elif wl_aper[i] == 8.0: fil_name = 'IRAC Channel 4' elif wl_aper[i] == 24: fil_name = 'MIPS 24um' elif wl_aper[i] == 850: fil_name = 'SCUBA 850WB' else: fil_name = None if fil_name != None: filter_func = phot_filter(fil_name, indir) # Simulated SED should have enough wavelength coverage for applying photometry filters. f = interp1d(wav_sort, flux_dum) f_unc = interp1d(wav_sort, unc_dum) flux_aper[i] = np.trapz(f(filter_func['wave']/1e4)*\ filter_func['transmission'],x=filter_func['wave']/1e4 )/\ np.trapz(filter_func['transmission'], x=filter_func['wave']/1e4) # fix a bug unc_aper[i] = unc_spectrophoto( filter_func['wave'] / 1e4, f_unc(filter_func['wave'] / 1e4), filter_func['transmission']) else: # use a rectangle function the average the simulated SED # apply the spectral resolution if (wl_aper[i] < 50.) & (wl_aper[i] >= 5): res = 60. elif wl_aper[i] < 5: res = 10. else: res = 1000. ind = np.where((wav_sort < wl_aper[i] * (1 + 1. / res)) & (wav_sort > wl_aper[i] * (1 - 1. / res))) if len(ind[0]) != 0: flux_aper[i] = np.mean(flux_dum[ind]) unc_aper[i] = np.mean(unc_dum[ind]) else: f = interp1d(wav_sort, flux_dum) f_unc = interp1d(wav_sort, unc_dum) flux_aper[i] = f(wl_aper[i]) unc_aper[i] = f_unc(wl_aper[i]) # temperory step: solve issue of uncertainty greater than the value for i in range(len(wl_aper)): if unc_aper[i] >= flux_aper[i]: unc_aper[i] = flux_aper[i] - 1e-20 ########################### # Observations Extraction # ########################### # perform the same procedure of flux extraction of aperture flux with observed spectra # wl_aper = np.array(wl_aper, dtype=float) obs_aper_wl = wl_aper[(wl_aper >= min(wl_tot)) & (wl_aper <= max(wl_tot))] obs_aper_flux = np.zeros_like(obs_aper_wl) obs_aper_unc = np.zeros_like(obs_aper_wl) # have change the simulation part to work in F_lambda for fliter convolution # flux_tot and unc_tot have units of erg/s/cm2/Hz. Need to convert it to F_lambda (erg/s/cm2/um) fnu2fl = c / (wl_tot * 1e-4) / wl_tot # # wl_tot and flux_tot are already hstacked and sorted by wavelength for i in range(0, len(obs_aper_wl)): # sometime users want not report some wavelength channels if obs_aper_wl[i] in exclude_wl: continue if filter_func == False: # use a rectangle function the average the simulated SED # apply the spectral resolution if (obs_aper_wl[i] < 50.) & (obs_aper_wl[i] >= 5): res = 60. elif obs_aper_wl[i] < 5: res = 10. else: res = 1000. ind = np.where((wl_tot < obs_aper_wl[i] * (1 + 1. / res)) & (wl_tot > obs_aper_wl[i] * (1 - 1. / res))) if len(ind[0]) != 0: obs_aper_flux[i] = np.mean(fnu2fl[ind] * flux_tot[ind]) obs_aper_unc[i] = np.mean(fnu2fl[ind] * unc_tot[ind]) else: f = interp1d(wl_tot, fnu2fl * flux_tot) f_unc = interp1d(wl_tot, fnu2fl * unc_tot) obs_aper_flux[i] = f(obs_aper_wl[i]) obs_aper_unc[i] = f_unc(obs_aper_wl[i]) else: # apply the filter function # decide the filter name if obs_aper_wl[i] == 70: fil_name = 'Herschel PACS 70um' elif obs_aper_wl[i] == 100: fil_name = 'Herschel PACS 100um' elif obs_aper_wl[i] == 160: fil_name = 'Herschel PACS 160um' elif obs_aper_wl[i] == 250: fil_name = 'Herschel SPIRE 250um' elif obs_aper_wl[i] == 350: fil_name = 'Herschel SPIRE 350um' elif obs_aper_wl[i] == 500: fil_name = 'Herschel SPIRE 500um' elif obs_aper_wl[i] == 3.6: fil_name = 'IRAC Channel 1' elif obs_aper_wl[i] == 4.5: fil_name = 'IRAC Channel 2' elif obs_aper_wl[i] == 5.8: fil_name = 'IRAC Channel 3' elif obs_aper_wl[i] == 8.0: fil_name = 'IRAC Channel 4' elif obs_aper_wl[i] == 24: fil_name = 'MIPS 24um' elif obs_aper_wl[i] == 850: fil_name = 'SCUBA 850WB' # do not have SCUBA spectra else: fil_name = None if fil_name != None: filter_func = phot_filter(fil_name, indir) # Observed SED needs to be trimmed before applying photometry filters filter_func = filter_func[(filter_func['wave']/1e4 >= min(wl_tot))*\ ((filter_func['wave']/1e4 >= 54.8)+(filter_func['wave']/1e4 <= 36.0853))*\ ((filter_func['wave']/1e4 <= 95.05)+(filter_func['wave']/1e4 >=103))*\ ((filter_func['wave']/1e4 <= 190.31)+(filter_func['wave']/1e4 >= 195))*\ (filter_func['wave']/1e4 <= max(wl_tot))] f = interp1d(wl_tot, fnu2fl * flux_tot) f_unc = interp1d(wl_tot, fnu2fl * unc_tot) obs_aper_flux[i] = np.trapz(f(filter_func['wave']/1e4)*filter_func['transmission'], x=filter_func['wave']/1e4)/\ np.trapz(filter_func['transmission'], x=filter_func['wave']/1e4) obs_aper_unc[i] = unc_spectrophoto( filter_func['wave'] / 1e4, f_unc(filter_func['wave'] / 1e4), filter_func['transmission']) else: # use a rectangle function the average the simulated SED # apply the spectral resolution if (obs_aper_wl[i] < 50.) & (obs_aper_wl[i] >= 5): res = 60. elif obs_aper_wl[i] < 5: res = 10. else: res = 1000. ind = np.where((wl_tot < obs_aper_wl[i] * (1 + 1. / res)) & (wl_tot > obs_aper_wl[i] * (1 - 1. / res))) if len(ind[0]) != 0: obs_aper_flux[i] = np.mean(fnu2fl[ind] * flux_tot[ind]) obs_aper_unc[i] = np.mean(fnu2fl[ind] * unc_tot[ind]) else: f = interp1d(wl_tot, fnu2fl * flux_tot) f_unc = interp1d(wl_tot, fnu2fl * unc_tot) obs_aper_flux[i] = f(obs_aper_wl[i]) obs_aper_unc[i] = f_unc(obs_aper_wl[i]) # plot the aperture-extracted spectrophotometry fluxes from observed spectra and simulations # in log-scale if log: aper_obs = ax_sed.errorbar(np.log10(obs_aper_wl), np.log10(obs_aper_flux * obs_aper_wl ),\ yerr=[np.log10(obs_aper_flux*obs_aper_wl)-np.log10(obs_aper_flux*obs_aper_wl-obs_aper_unc*obs_aper_wl), np.log10(obs_aper_flux*obs_aper_wl+obs_aper_unc*obs_aper_wl)-np.log10(obs_aper_flux*obs_aper_wl)],\ fmt='s', mec='None', mfc='r', markersize=10, linewidth=1.5, ecolor='Red', elinewidth=3, capthick=3, barsabove=True) aper = ax_sed.errorbar(np.log10(wl_aper),np.log10(flux_aper*wl_aper),\ yerr=[np.log10(flux_aper*wl_aper)-np.log10(flux_aper*wl_aper-unc_aper*wl_aper), np.log10(flux_aper*wl_aper+unc_aper*wl_aper)-np.log10(flux_aper*wl_aper)],\ fmt='o', mec='Blue', mfc='None', color='b',markersize=12, markeredgewidth=2.5, linewidth=1.7, ecolor='Blue', elinewidth=3, barsabove=True) ax_sed.set_ylim([-14, -7]) ax_sed.set_xlim([0, 3.2]) # in normal scale (normal in y-axis) else: aper_obs = ax_sed.errorbar(np.log10(obs_aper_wl), obs_aper_flux*obs_aper_wl, yerr=obs_aper_unc*obs_aper_wl,\ fmt='s', mec='None', mfc='r', markersize=10, linewidth=1.5, ecolor='Red', elinewidth=3, capthick=3, barsabove=True) aper = ax_sed.errorbar(np.log10(wl_aper),flux_aper*wl_aper, yerr=unc_aper*wl_aper,\ fmt='o', mec='Blue', mfc='None', color='b',markersize=12, markeredgewidth=2.5, linewidth=1.7, ecolor='Blue', elinewidth=3, barsabove=True) ax_sed.set_xlim([0, 3.2]) # calculate the bolometric luminosity of the aperture # print flux_aper l_bol_sim = l_bol( wl_aper, flux_aper * wl_aper / (c / np.array(wl_aper) * 1e4) * 1e23, dstar) print 'Bolometric luminosity of simulated spectrum: %5.2f lsun' % l_bol_sim # print out the sed into ascii file for reading in later if save == True: # unapertured SED foo = open(outdir + print_name + '_sed_inf.txt', 'w') foo.write('%12s \t %12s \t %12s \n' % ('wave', 'vSv', 'sigma_vSv')) for i in range(0, len(sed_inf.wav)): foo.write('%12g \t %12g \t %12g \n' % (sed_inf.wav[i], sed_inf.val[i], sed_inf.unc[i])) foo.close() # SED with convolution of aperture sizes foo = open(outdir + print_name + '_sed_w_aperture.txt', 'w') foo.write('%12s \t %12s \t %12s \n' % ('wave', 'vSv', 'sigma_vSv')) for i in range(0, len(wl_aper)): foo.write('%12g \t %12g \t %12g \n' % (wl_aper[i], flux_aper[i] * wl_aper[i], unc_aper[i] * wl_aper[i])) foo.close() # print out the aperture-convolved fluxex from observations if print_data_w_aper: foo = open(outdir + print_name + '_obs_w_aperture.txt', 'w') foo.write('%12s \t %12s \t %12s \n' % ('wave', 'Jy', 'sigma_Jy')) for i in range(0, len(obs_aper_wl)): foo.write('%12g \t %12g \t %12g \n' % (obs_aper_wl[i], obs_aper_flux[i] * obs_aper_wl[i] / (c / obs_aper_wl[i] * 1e4) * 1e23, obs_aper_unc[i] * obs_aper_wl[i] / (c / obs_aper_wl[i] * 1e4) * 1e23)) foo.close() # read the input central luminosity by reading in the source information from output file dum = Model() dum.use_sources(filename) L_cen = dum.sources[0].luminosity / lsun # legend lg_data = ax_sed.legend([irs, photometry, aper, aper_obs], [ r'$\rm{observation}$', r'$\rm{photometry}$', r'$\rm{F_{aper,sim}}$', r'$\rm{F_{aper,obs}}$' ], loc='upper left', fontsize=14 * mag, numpoints=1, framealpha=0.3) if clean == False: lg_sim = ax_sed.legend([sim],[r'$\rm{L_{bol,sim}=%5.2f\,L_{\odot},\,L_{center}=%5.2f\,L_{\odot}}$' % (l_bol_sim, L_cen)], \ loc='lower right',fontsize=mag*16) plt.gca().add_artist(lg_data) # plot setting ax_sed.set_xlabel(r'$\rm{log\,\lambda\,[{\mu}m]}$', fontsize=mag * 20) ax_sed.set_ylabel(r'$\rm{log\,\nu S_{\nu}\,[erg\,s^{-1}\,cm^{-2}]}$', fontsize=mag * 20) [ ax_sed.spines[axis].set_linewidth(1.5 * mag) for axis in ['top', 'bottom', 'left', 'right'] ] ax_sed.minorticks_on() ax_sed.tick_params('both', labelsize=mag * 18, width=1.5 * mag, which='major', pad=15, length=5 * mag) ax_sed.tick_params('both', labelsize=mag * 18, width=1.5 * mag, which='minor', pad=15, length=2.5 * mag) # fix the tick label font ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral', size=mag * 18) for label in ax_sed.get_xticklabels(): label.set_fontproperties(ticks_font) for label in ax_sed.get_yticklabels(): label.set_fontproperties(ticks_font) # Write out the plot fig.savefig(outdir + print_name + '_sed.pdf', format='pdf', dpi=300, bbox_inches='tight') fig.clf() # option for suppress image plotting (for speed) if image: # Package for matching the colorbar from mpl_toolkits.axes_grid1 import make_axes_locatable, ImageGrid # Users may change the unit: mJy, Jy, MJy/sr, ergs/cm^2/s, ergs/cm^2/s/Hz # !!! image = m.get_image(group=len(aper_reduced) + 1, inclination=0, distance=dstar * pc, units='MJy/sr') # Open figure and create axes fig = plt.figure(figsize=(12, 12)) grid = ImageGrid(fig, 111, nrows_ncols=(3, 3), direction='row', add_all=True, label_mode='1', share_all=True, cbar_location='right', cbar_mode='single', cbar_size='3%', cbar_pad=0) for i, wav in enumerate([3.6, 8.0, 9.7, 24, 40, 100, 250, 500, 1000]): ax = grid[i] # Find the closest wavelength iwav = np.argmin(np.abs(wav - image.wav)) # Calculate the image width in arcseconds given the distance used above # get the max radius rmax = max(m.get_quantities().r_wall) w = np.degrees(rmax / image.distance) * 3600. # Image in the unit of MJy/sr # Change it into erg/s/cm2/Hz/sr factor = 1e-23 * 1e6 # avoid zero in log # flip the image, because the setup of inclination is upside down val = image.val[::-1, :, iwav] * factor + 1e-30 # This is the command to show the image. The parameters vmin and vmax are # the min and max levels for the colorscale (remove for default values). cmap = plt.cm.CMRmap im = ax.imshow(np.log10(val), vmin=-22, vmax=-12, cmap=cmap, origin='lower', extent=[-w, w, -w, w], aspect=1) ax.set_xlabel(r'$\rm{RA\,Offset\,[arcsec]}$', fontsize=14) ax.set_ylabel(r'$\rm{Dec\,Offset\,[arcsec]}$', fontsize=14) # fix the tick label font ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral', size=14) for label in ax.get_xticklabels(): label.set_fontproperties(ticks_font) for label in ax.get_yticklabels(): label.set_fontproperties(ticks_font) # Colorbar setting cb = ax.cax.colorbar(im) cb.solids.set_edgecolor('face') cb.ax.minorticks_on() cb.ax.set_ylabel( r'$\rm{log(I_{\nu})\,[erg\,s^{-1}\,cm^{-2}\,Hz^{-1}\,sr^{-1}]}$', fontsize=18) cb_obj = plt.getp(cb.ax.axes, 'yticklabels') plt.setp(cb_obj, fontsize=18) ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral', size=18) for label in cb.ax.get_yticklabels(): label.set_fontproperties(ticks_font) ax.tick_params(axis='both', which='major', labelsize=16) ax.text(0.7, 0.88, str(wav) + r'$\rm{\,\mu m}$', fontsize=16, color='white', transform=ax.transAxes) fig.savefig(outdir + print_name + '_image_gridplot.pdf', format='pdf', dpi=300, bbox_inches='tight') fig.clf()
def hyperion_sedcom(modellist, outdir, plotname, obs_data=None, labellist=None, lbol=False, legend=True, mag=1.5,\ obs_preset='sh', dstar=1, aper=[3.6, 4.5, 5.8, 8.0, 10, 20, 24, 70, 160, 250, 350, 500, 850]): """ obs_data: dictionary which obs_data['spec'] is spectrum and obs_data['phot'] is photometry obs_data['label'] = (wave, Fv, err) in um and Jy by default """ import numpy as np import os import matplotlib.pyplot as plt import astropy.constants as const from hyperion.model import ModelOutput from scipy.interpolate import interp1d from l_bol import l_bol import seaborn as sb # from seaborn import color_palette # from seaborn_color import seaborn_color # constant setup c = const.c.cgs.value pc = const.pc.cgs.value if labellist == None: if legend == True: print 'Model labels are not provided. Use their filename instead.' labellist = [] for i in range(0, len(modellist)): labellist.append( r'$\mathrm{' + os.path.splitext(os.path.basename(modellist[i]))[0] + '}$') # cm = seaborn_color('colorblind',len(modellist)) sb.set(style="white") cm = sb.color_palette('husl', len(modellist)) # create figure object fig = plt.figure(figsize=(8 * mag, 6 * mag)) ax = fig.add_subplot(111) # sb.set_style('ticks') print 'plotting with aperture at ', aper, 'um' # if the obs_data is provided than plot the observation first. In this way, models won't be blocked by data if obs_data != None: if 'spec' in obs_data.keys(): (wave, fv, err) = obs_data['spec'] vfv = c / (wave * 1e-4) * fv * 1e-23 l_bol_obs = l_bol(wave, fv, dstar) if legend == True: ax.text(0.75, 0.9, r'$\mathrm{L_{bol}= %5.2f L_{\odot}}$' % l_bol_obs, fontsize=mag * 16, transform=ax.transAxes) # general plotting scheme if obs_preset == None: spec, = ax.plot(np.log10(wave), np.log10(vfv), '-', color='k', linewidth=1.5 * mag, label=r'$\mathrm{observations}$') # plot spitzer, Herschel pacs and spire in different colors elif obs_preset == 'sh': # spitzer spitz, = ax.plot(np.log10(wave[wave < 50]),np.log10(vfv[wave < 50]),'-',color='b',linewidth=1*mag,\ label=r'$\mathrm{\it Spitzer}$') # herschel pacs, = ax.plot(np.log10(wave[(wave < 190.31) & (wave > 50)]),np.log10(vfv[(wave < 190.31) & (wave > 50)]),'-',\ color='Green',linewidth=1*mag, label=r'$\mathrm{{\it Herschel}-PACS}$') spire, = ax.plot(np.log10(wave[wave >= 190.31]),np.log10(vfv[wave >= 190.31]),'-',color='k',linewidth=1*mag,\ label=r'$\mathrm{{\it Herschel}-SPIRE}$') spec = [spitz, pacs, spire] if 'phot' in obs_data.keys(): (wave_p, fv_p, err_p) = obs_data['phot'] vfv_p = c / (wave_p * 1e-4) * fv_p * 1e-23 vfv_p_err = c / (wave_p * 1e-4) * err_p * 1e-23 phot, = ax.plot(np.log10(wave_p), np.log10(vfv_p), 's', mfc='DimGray', mec='k', markersize=8) ax.errorbar(np.log10(wave_p),np.log10(vfv_p),yerr=[np.log10(vfv_p)-np.log10(vfv_p-vfv_p_err), np.log10(vfv_p+vfv_p_err)-np.log10(vfv_p)],\ fmt='s',mfc='DimGray',mec='k',markersize=8) modplot = dict() for imod in range(0, len(modellist)): m = ModelOutput(modellist[imod]) # if not specified, distance of the star will be taken as 1 pc. if aper == None: sed_dum = m.get_sed(group=0, inclination=0, aperture=-1, distance=dstar * pc) modplot['mod' + str(imod + 1)], = ax_sed.plot( np.log10(sed_dum.wav), np.log10(sed_dum.val), '-', color='GoldenRod', linewidth=1.5 * mag) else: vfv_aper = np.empty_like(aper) for i in range(0, len(aper)): sed_dum = m.get_sed(group=i + 1, inclination=0, aperture=-1, distance=dstar * pc) f = interp1d(sed_dum.wav, sed_dum.val) vfv_aper[i] = f(aper[i]) modplot['mod'+str(imod+1)], = ax.plot(np.log10(aper),np.log10(vfv_aper),'o',mfc='None',mec=cm[imod],markersize=12,\ markeredgewidth=3, label=labellist[imod], linestyle='-',color=cm[imod],linewidth=1.5*mag) # plot fine tune ax.set_xlabel(r'$\mathrm{log~\lambda~({\mu}m)}$', fontsize=mag * 20) ax.set_ylabel(r'$\mathrm{log~\nu S_{\nu}~(erg/cm^{2}/s)}$', fontsize=mag * 20) [ ax.spines[axis].set_linewidth(1.5 * mag) for axis in ['top', 'bottom', 'left', 'right'] ] ax.minorticks_on() ax.tick_params('both', labelsize=mag * 18, width=1.5 * mag, which='major', pad=15, length=5 * mag) ax.tick_params('both', labelsize=mag * 18, width=1.5 * mag, which='minor', pad=15, length=2.5 * mag) if obs_preset == 'sh': ax.set_ylim([-14, -7]) ax.set_xlim([0, 3]) if legend == True: lg = ax.legend(loc='best', fontsize=14 * mag, numpoints=1, framealpha=0.3) # Write out the plot fig.savefig(outdir + plotname + '.pdf', format='pdf', dpi=300, bbox_inches='tight') fig.clf()
r2 = 1 - (ss_res / ss_tot) if (r2 <= fit_level): print("**BAD FIT**") lune_flux = -1.0 return line_flux except Exception as error: print(str(error)) return -1.0 # Main Program Code #get the SED and get the units right fname = '/blue/narayanan/prerakgarg/pd_runs/m25n512_jp/snap305_mono/snap305.galaxy100.rtout.sed' m = ModelOutput(fname) wav, nufnu = m.get_sed(inclination='all', aperture=-1) nufnu *= u.erg / u.s wav *= u.micron flam = (nufnu / wav).to(u.erg / u.s / u.micron) flam = flam[0] lam_cent = 0.6564 #micron of central wavelength left_edge = lam_cent * 0.999 #wavelength of left edge of line (guessed) right_edge = lam_cent * 1.001 #wavelength of right edge of line (guessed) line_flux = get_flux(lam_cent, left_edge, right_edge, wav.value, flam.value, 0.98) print("line flux :" + str(line_flux) + " ergs/s")
from hyperion.model import ModelOutput from hyperion.util.constants import pc for f in ['', '_noimaging', '_noray_dust', '_noray_sour', '_fewinitials']: print f m = ModelOutput('tutorial_model' + f + '.rtout') fig = plt.figure() plt.title((f)) ax = fig.add_subplot(1, 1, 1) # Direct stellar photons if f in ['', '_noimaging', '_noray_dust', '_fewinitials']: wav, nufnu = m.get_sed(inclination='all', aperture=-1, distance=300 * pc, component='source_emit') # Plot SED for each inclination for i in range(nufnu.shape[0]): ax.loglog(wav, nufnu[i, :], color='blue') # Scattered stellar photons wav, nufnu = m.get_sed(inclination='all', aperture=-1, distance=300 * pc, component='source_scat') # Plot SED for each inclination for i in range(nufnu.shape[0]): ax.loglog(wav, nufnu[i, :], color='teal') # Direct dust photons wav, nufnu = m.get_sed(inclination='all', aperture=-1, distance=300 * pc, component='dust_emit')
def plot_results(cli): file = filename(cli, "plot") file += ".rtout" # # Read in the model: # model = ModelOutput(file) los = [0 for k in range(3)] los[0] = '30degree' los[1] = '80degree' los[2] = '88degree' if(cli.mode == "images"): # # Extract the quantities # g = model.get_quantities() # # Get the wall positions: # ww = g.w_wall / pc zw = g.z_wall / pc pw = g.p_wall grid_Nw = len(ww) - 1 grid_Nz = len(zw) - 1 grid_Np = len(pw) - 1 # # Graphics: # fig = plt.figure() Imaxp = [0 for i in range(5)] Imaxp[0] = 1e-15 # in W/cm^2 Imaxp[1] = 1e-14 # in W/cm^2 Imaxp[2] = 1e-15 # in W/cm^2 Imaxp[3] = 1e-15 # in W/cm^2 Imaxp[4] = 1e-18 # in W/cm^2 for k in range(0, 3): if(cli.verbose): print("Group: ", k) image = model.get_image(distance=1e+7*pc, units='ergs/cm^2/s', inclination=0, component='total', group=k) #source_emit = model.get_image(distance=1e+7*pc, units='MJy/sr', inclination=0, component='source_emit', group=k) #dust_emit = model.get_image(distance=1e+7*pc, units='MJy/sr', inclination=0, component='dust_emit' , group=k) #source_scat = model.get_image(distance=1e+7*pc, units='MJy/sr', inclination=0, component='source_scat', group=k) #dust_scat = model.get_image(distance=1e+7*pc, units='MJy/sr', inclination=0, component='dust_scat' , group=k) if(cli.verbose): print(" Data cube: ", image.val.shape) print(" Wavelengths =", image.wav) print(" Uncertainties =", image.unc) image_Nx=image.val.shape[0] image_Ny=image.val.shape[1] Nwavelength=image.val.shape[2] if(cli.verbose): print(" Image Nx =", image_Nx) print(" Image Ny =", image_Ny) print(" Nwavelength =", Nwavelength) for i in range(0, Nwavelength): if(cli.verbose): print(" Image #", i,":") print(" Wavelength =", image.wav[i]) image.val[:, :, i] *= 1e-4 # in W/m^2 #Imin = np.min(image.val[:, :, i]) #Imax = np.max(image.val[:, :, i]) #Imax = Imaxp[i] #Imin = Imax/1e+20 Imax = np.max(image.val[:, :, i])/5 Imin = 0.0 if(cli.verbose): print(" Intensity min data values =", np.min(image.val[:, :, i])) print(" Intensity max data values =", np.max(image.val[:, :, i])) print(" Intensity min color-table =", Imin) print(" Intensity max color-table =", Imax) #ax = fig.add_subplot(2, 1, 2) ax = fig.add_subplot(1, 1, 1) # 'hot', see http://wiki.scipy.org/Cookbook/Matplotlib/Show_colormaps ax.imshow(image.val[:, :, i], vmin=Imin, vmax=Imax, cmap=plt.cm.hot, origin='lower') ax.set_xticks([0,100,200,300,400,500], minor=False) ax.set_yticks([0,100,200,300,400,500], minor=False) ax.set_xlabel('x (pixel)') ax.set_ylabel('y (pixel)') ax.set_title(str(image.wav[i]) + ' microns' + '\n' + los[k], y=0.88, x=0.5, color='white') #ax = fig.add_subplot(2, 1, 1) #ax.imshow([np.logspace(np.log10(Imin+1e-10),np.log10(Imax/10),100),np.logspace(np.log10(Imin+1e-10),np.log10(Imax/10),100)], vmin=Imin, vmax=Imax/10, cmap=plt.cm.gist_heat) #ax.set_xticks(np.logspace(np.log10(Imin+1e-10),np.log10(Imax/10),1), minor=False) ##ax.set_xticks(np.linspace(np.log10(Imin+1e-10),np.log10(Imax/10),10), minor=False) #ax.set_yticks([], minor=False) #ax.set_xlabel('flux (MJy/sr)') #x = plt.colorbar() #print(x) file = filename(cli, "plot") file += "_wavelength=" + str(image.wav[i]) + "micron_los=" + los[k] + ".png" fig.savefig(file, bbox_inches='tight') if(cli.verbose): print(" The image graphics was written to", file) plt.clf() elif(cli.mode == "seds"): # # Graphics: # fig = plt.figure() for k in range(0, 3): if(cli.verbose): print("Group: ", k) sed = model.get_sed(distance=1e+7*pc, inclination=0, aperture=-1, group=k) #units='ergs/cm^2/s' # = default, if distance is specified ax = fig.add_subplot(1, 1, 1) ax.loglog(sed.wav, sed.val) ax.set_xlabel(r'$\lambda$ [$\mu$m]') ax.set_ylabel(r'$\lambda F_\lambda$ [ergs/s/cm$^2$]') ax.set_xlim(0.09, 1000.0) ax.set_ylim(1.e-13, 1.e-7) file = filename(cli, "plot") file += "_los=" + los[k] + ".png" fig.savefig(file) if(cli.verbose): print(" The sed graphics was written to", file) plt.clf() # # Data files: # for k in range(0, 3): sed = model.get_sed(distance=1e+7*pc, inclination=0, aperture=-1, group=k) file = filename(cli, "plot") file += "_los=" + los[k] + ".dat" sedtable = open(file, 'w') sedtable.write("# wavelength [micron] - flux [erg cm^-2 s^-1]\n") for lp in range(0, len(sed.wav)): l = len(sed.wav)-lp-1 line = str("%.4e" % sed.wav[l]) + " " + str("%.4e" % sed.val[l]) + "\n" sedtable.write(line) sedtable.close() else: print("ERROR: The specified mode", mode, "is not available. Use 'images' or 'seds' only.")
import numpy as np from hyperion.model import ModelOutput from hyperion.util.constants import kpc from astropy.io import fits for tau in [0.1, 1.0, 20.]: input_file = 'bm1_slab_effgrain_tau_{tau:05.2f}_seds.rtout'.format(tau=tau) m = ModelOutput(input_file) for iincl, theta in enumerate([0, 30, 60, 90, 120, 150, 180]): sed = m.get_sed(inclination=iincl, units='Jy', distance=10. * kpc, aperture=-1) output_file = 'seds/bm1_slab_effgrain_tau_{tau:06.2f}_theta_{theta:03d}_sed.dat'.format(tau=tau, theta=theta) np.savetxt(output_file, zip(sed.wav, sed.val), fmt="%10.4e")
class YSOModelSim(object): def __init__(self,name,folder,T=9000,M_sun=5.6,L_sun=250,disk_mass=0.01,disk_rmax=100, env=True,env_type='power',rc=400,mdot=1e-8,env_mass=0.1,env_rmin=30,env_rmax=5000,cav=True,cav_r0=500,cav_rho_0=8e-24,cav_theta=25,env_power=-1.5, Npix=149,angles=[20.,45.,60.,80],angles2=[60.,60.,60.,60.], amb_dens=8e-24, disk="Flared",disk_rmin=1., amb_rmin=1., amb_rmax=1000., innerdustfile='OH5.hdf5', outerdustfile='d03_5.5_3.0_A.hdf5',beta=1.1): self.name=name self.folder=folder self.T=T self.M_sun=M_sun*msun self.L_sun=L_sun*lsun self.disk_mass=disk_mass*msun self.disk_rmax=disk_rmax*au self.disk_rmin=disk_rmin*au self.disk_h_0 = OptThinRadius(1600) self.env=env self.disk=disk self.env_type=env_type self.env_mass=env_mass*msun self.env_rmin=env_rmin*au self.env_rmax=env_rmax*au self.mdot=mdot #*msun/yr*self.M_sun # disk accretion rate self.rc=rc*au self.cav=cav self.cav_rho_0=cav_rho_0 self.cav_r0=cav_r0*au self.cav_theta=cav_theta self.Npix=Npix self.angles=angles self.angles2=angles2 self.amb_dens=amb_dens self.amb_rmin=amb_rmin self.amb_rmax=amb_rmax*au self.env_power=env_power self.dustfile=innerdustfile self.dustfile_out=outerdustfile self.limval = max(self.env_rmax,1000*au) self.beta = beta def modelDump(self): sp.call('rm %s.mod ' % (self.folder+self.name),shell=True) pickle.dump(self,open(self.folder+self.name+'.mod','wb')) time.sleep(2) def modelPrint(self): #string= self.folder+ self.name+'\n' string="T="+str(self.T)+"K"+'\n' string+= "M="+str(self.M_sun/msun)+'Msun'+'\n' string+= "L="+str(self.L_sun/lsun)+'Lsun'+'\n' string+= "Disk="+str(self.disk)+'\n' string+= "Disk_mass="+str(self.disk_mass/msun)+'Msun'+'\n' string+= "Disk_rmax="+str(self.disk_rmax/au)+'AU'+'\n' string+= "Disk_rmin="+str(self.disk_rmin/au)+'AU'+'\n' string+= "env="+str(self.env)+'\n' string+= "env_type="+self.env_type+'\n' string+= "env_mass="+str(self.env_mass/msun)+'Msun'+'\n' string+= "env_rmax="+str(self.env_rmax/au)+'AU'+'\n' string+= "env_rmin="+str(self.env_rmin/au)+'AU'+'\n' if self.env_type == 'ulrich' and self.env==True: string+= "mass_ulrich="+str((8.*np.pi*self.env_rho_0*self.rc**3*pow(self.env_rmax/self.rc,1.5)/(3.*np.sqrt(2)))/msun)+'Msun'+'\n' string+= "mdot="+str(self.mdot)+'Msun/yr'+'\n' # (only if env_type="Ulrich") string+= "rc="+str(self.rc/au)+'AU'+'\n' # (only if env_type="Ulrich") string+= "cav="+str(self.cav)+'\n' string+= "cav_theta="+str(self.cav_theta)+'\n' string+= "cav_r0="+str(self.cav_r0/au)+'\n' string+= "env_power="+str(self.env_power)+'\n' string+= "disk_h_0="+str(self.disk_h_0)+'\n' string+= "dustfile="+self.dustfile+'\n' string+= "dustfile_out="+self.dustfile_out+'\n' string+= "amb_dens="+str(self.amb_dens)+'\n' string+= "amb_rmin="+str(self.amb_rmin)+'\n' string+= "amb_rmax="+str(self.amb_rmax/au)+'\n' string+= "angles="+str(self.angles)+'\n' print string return string def dust_gen(self,dustfile,dustfile_out='d03_5.5_3.0_A.hdf5'): ### first, we need to load Tracy's dust files and manipulate them to feed to Hyperion ### wavelength (microns),Cext,Csca,Kappa,g,pmax,theta (ignored) ### albedo = Csca/Cext ### opacity kappa is in cm^2/gm, dust_gas extinction opactity (absorption+scattering) - assumes gas-to=dust raio of 100 ### see Whitney et al. 2003a # tracy_dust = np.loadtxt('Tracy_models/OH5.par') # ### format for dust: d = HenyeyGreensteinDust(nu, albedo, chi, g, p_lin_max) # nu = const.c.value/ (tracy_dust[:,0]*1e-6) # albedo = tracy_dust[:,2]/tracy_dust[:,1] # chi = tracy_dust[:,3] # g = tracy_dust[:,4] # p_lin_max = tracy_dust[:,5] # ### flip the table to have an increasing frequency # nu = nu[::-1] # albedo = albedo[::-1] # chi=chi[::-1] # g=g[::-1] # p_lin_max=p_lin_max[::-1] # ### create the dust model # d = HenyeyGreensteinDust(nu, albedo, chi, g, p_lin_max) # d.optical_properties.extrapolate_wav(0.001,1.e7) # d.plot('OH5.png') # d.write('OH5.hdf5') self.d = SphericalDust() self.d.read(dustfile) self.d.plot(str(dustfile.split(',')[:-1])+'.png') self.d_out = SphericalDust() self.d_out.read(dustfile_out) #self.d_out.read(dustfile) self.d_out.plot(str(dustfile_out.split(',')[:-1])+'.png') def initModel(self): ### Use Tracy parameter file to set up the model self.dust_gen(self.dustfile,self.dustfile_out) mi = AnalyticalYSOModel() mi.star.temperature = self.T mi.star.mass = self.M_sun mi.star.luminosity = self.L_sun mi.star.radius=np.sqrt(mi.star.luminosity/(4.0*np.pi*sigma*mi.star.temperature**4)) #m.star.luminosity = 4.0*np.pi*m.star.radius**2*sigma*m.star.temperature**4 print mi.star.luminosity/lsun self.luminosity=mi.star.luminosity/lsun if self.disk=="Flared": print "Adding flared disk" disk = mi.add_flared_disk() disk.dust=self.d if self.dustfile == 'd03_5.5_3.0_A.hdf5': disk.mass=self.disk_mass/100. else: disk.mass=self.disk_mass disk.rmin=OptThinRadius(1600) #self.disk_rmin print "disk.rmin = ",disk.rmin,disk.rmin/au disk.rmax=self.disk_rmax disk.r_0 = self.disk_rmin disk.h_0 = disk.r_0/10. #self.disk_h_0*au disk.beta=self.beta disk.p = -1. elif self.disk=="Alpha": print "Adding alpha disk" disk = mi.add_alpha_disk() disk.dust=self.d if self.dustfile == 'd03_5.5_3.0_A.hdf5': disk.mass=self.disk_mass/100. else: disk.mass=self.disk_mass disk.rmin=OptThinRadius(1600) disk.rmax=self.disk_rmax disk.r_0 = self.disk_rmin disk.h_0 = disk.r_0/10. #self.disk_h_0*au disk.beta=1.1 disk.p = -1 disk.mdot=self.mdot disk.star = mi.star #print 'Disk density:',disk.rho_0 if self.env==True and self.env_type=='power': envelope=mi.add_power_law_envelope() envelope.dust=self.d_out envelope.r_0=self.env_rmin #envelope.r_0 = OptThinRadius(1600) if self.dustfile_out == 'd03_5.5_3.0_A.hdf5': envelope.mass=self.env_mass/100. else: envelope.mass=self.env_mass envelope.rmin=self.env_rmin envelope.rmax=self.env_rmax envelope.power=self.env_power #print 'Envelope rho:',envelope.rho_0 elif self.env==True and self.env_type=='ulrich': envelope=mi.add_ulrich_envelope() envelope.dust=self.d_out envelope.mdot=1e-6*msun/yr # has little impact on the fluxes, so fixed envelope.rc=self.rc envelope.rmin=self.env_rmin envelope.rmax=self.env_rmax if self.env==True: self.env_rho_0 = envelope.rho_0 print 'Envelope rho:',envelope.rho_0 #print "Rho_0 = ",envelope.rho_0 if self.cav==True: cavity=envelope.add_bipolar_cavity() cavity.dust=self.d_out cavity.power=1.5 cavity.cap_to_envelope_density=True ### prevents the cavity density to go above the envelope's density cavity.r_0=self.cav_r0 cavity.theta_0=self.cav_theta cavity.rho_0=self.cav_rho_0 #in g/cm^3 cavity.rho_exp=0.0 # if self.env==True: # ambient=mi.add_ambient_medium(subtract=[envelope,disk]) # if self.dustfile_out == 'd03_5.5_3.0_A.hdf5': # ambient.rho=self.amb_dens/100. # else: ambient.rho=self.amb_dens # ambient.rmin=OptThinRadius(1600.) # ambient.rmax=self.env_rmax # ambient.dust=self.d_out '''*** Grid parameters ***''' mi.set_spherical_polar_grid_auto(199,49,1) # Specify that the specific energy and density are needed mi.conf.output.output_specific_energy = 'last' mi.conf.output.output_density = 'last' '''**** Output Data ****''' image = mi.add_peeled_images(sed=True,image=False) image.set_wavelength_range(150,1,3000) #image.set_image_size(self.Npix,self.Npix) #image.set_image_limits(-self.limval,self.limval,-self.limval,self.limval) image.set_aperture_range(1,100000.*au,100000.*au) image.set_viewing_angles(self.angles,self.angles2) #image.set_track_origin('detailed') image.set_uncertainties(True) ''' Use the modified random walk *** Advanced ***' YES = DIFFUSION = Whether to use the diffusion ''' if self.env==True: #mi.set_pda(True) mi.set_mrw(True) else: mi.set_pda(False) mi.set_mrw(False) # Use raytracing to improve s/n of thermal/source emission mi.set_raytracing(True) '''**** Preliminaries ****''' mi.set_n_initial_iterations(5) mi.set_n_photons(initial=1e6,imaging=1e6,raytracing_sources=1e5,raytracing_dust=1e6) mi.set_convergence(True, percentile=99.0, absolute=2.0, relative=1.1) self.m = mi def runModel(self): self.initModel() self.m.write(self.folder+self.name+'.rtin') self.m.run(self.folder+self.name+'.rtout', mpi=True,n_processes=6) def plotData(self,ax,sourcename): if sourcename != 'None': folder_export="/n/a2/mrizzo/Dropbox/SOFIA/Processed_Data/" sourcetable = pickle.load(open(folder_export+"totsourcetable_fits.data","r")) markers = ['v','p','D','^','h','o','*','x','d','<'] TwoMASS = ['j','h','ks'] uTwoMASS = ["e_"+col for col in TwoMASS] wlTwoMASS = [1.3,1.6,2.2] colTwoMASS = colors[0] markerTwoMASS = markers[0] labelTwoMASS = '2MASS' Spitzer = ['i1','i2','i3','i4','m1','m2'] uSpitzer = ["e_"+col for col in Spitzer] wlSpitzer = [3.6,4.5,5.8,8.,24,70] colSpitzer = colors[1] markerSpitzer = markers[1] labelSpitzer = 'Spitzer' WISE = ['w1','w2','w3','w4'] uWISE = ["e_"+col for col in WISE] wlWISE = [3.4,4.6,12,22] colWISE = colors[2] labelWISE = 'WISE' markerWISE = markers[2] SOFIA = ['F11','F19','F31','F37'] uSOFIA = ["e_"+col for col in SOFIA] wlSOFIA = [11.1,19.7,31.5,37.1] colSOFIA = colors[3] markerSOFIA = markers[3] labelSOFIA = 'SOFIA' IRAS = ['Fnu_12','Fnu_25','Fnu_60','Fnu_100'] uIRAS = ["e_"+col for col in IRAS] wlIRAS = [12,25,60,100] colIRAS = colors[4] markerIRAS = markers[4] labelIRAS = 'IRAS' AKARI = ['S65','S90','S140','S160'] uAKARI = ["e_"+col for col in AKARI] wlAKARI = [65,90,140,160] colAKARI = colors[5] markerAKARI = markers[5] labelAKARI = 'AKARI' ENOCH = ['Fp'] uENOCH = ["e_"+col for col in ENOCH] wlENOCH = [1300] colENOCH = colors[6] markerENOCH = markers[6] labelENOCH = 'ENOCH' HERSCHEL = ['H70','H160','H250','H350','H500'] uHERSCHEL = ["e_"+col for col in HERSCHEL] wlHERSCHEL = [70,160,250,350,500] colHERSCHEL = colors[7] markerHERSCHEL = markers[7] labelHERSCHEL = 'HERSCHEL' SCUBA = ['S450','S850','S1300'] uSCUBA = ["e_"+col for col in SCUBA] wlSCUBA = [450,850,1300] colSCUBA = colors[8] markerSCUBA = markers[8] labelSCUBA = 'SCUBA' alpha=1 sources = sourcetable.group_by('SOFIA_name') for key,sourcetable in zip(sources.groups.keys,sources.groups): if sourcename == sourcetable['SOFIA_name'][0]: #print sourcetable['SOFIA_name'][0] p.plotData(ax,sourcetable,markerTwoMASS,TwoMASS,uTwoMASS,wlTwoMASS,colTwoMASS,labelTwoMASS,alpha) p.plotData(ax,sourcetable,markerSpitzer,Spitzer,uSpitzer,wlSpitzer,colSpitzer,labelSpitzer,alpha) p.plotData(ax,sourcetable,markerWISE,WISE,uWISE,wlWISE,colWISE,labelWISE,alpha) p.plotData(ax,sourcetable,markerSOFIA,SOFIA,uSOFIA,wlSOFIA,colSOFIA,labelSOFIA,alpha) p.plotData(ax,sourcetable,markerIRAS,IRAS,uIRAS,wlIRAS,colIRAS,labelIRAS,alpha) p.plotData(ax,sourcetable,markerAKARI,AKARI,uAKARI,wlAKARI,colAKARI,labelAKARI,alpha) p.plotData(ax,sourcetable,markerENOCH,ENOCH,uENOCH,wlENOCH,colENOCH,labelENOCH,alpha) p.plotData(ax,sourcetable,markerHERSCHEL,HERSCHEL,uHERSCHEL,wlHERSCHEL,colHERSCHEL,labelHERSCHEL,alpha) p.plotData(ax,sourcetable,markerSCUBA,SCUBA,uSCUBA,wlSCUBA,colSCUBA,labelSCUBA,alpha) def calcChi2(self,dist_pc=140,extinction=0, sourcename='Oph.1'): self.dist=dist_pc*pc self.extinction=extinction chi = np.loadtxt('kmh94_3.1_full.chi') wav = np.loadtxt('kmh94_3.1_full.wav') Chi = interp1d(wav,chi,kind='linear') modelname = self.folder+self.name self.mo = ModelOutput(modelname+'.rtout') # get the sed of all inclination sed = self.mo.get_sed(aperture=-1, inclination='all', distance=self.dist,units='Jy') # calculate the optical depth at all wavelengths tau = self.extinction*Chi(sed.wav)/Chi(0.550)/1.086 # calculate extinction values ext = np.array([np.exp(-tau) for i in range(sed.val.shape[0])]) # apply extinction to model extinct_values = np.log10(sed.val.transpose()*ext.T) # data points and errors folder_export="/n/a2/mrizzo/Dropbox/SOFIA/Processed_Data/" sourcetable = pickle.load(open(folder_export+"totsourcetable_fits.data","r")) TwoMASS = ['j','h','ks'] uTwoMASS = ["e_"+col for col in TwoMASS] wlTwoMASS = [1.3,1.6,2.2] labelTwoMASS = '2MASS' Spitzer = ['i1','i2','i3','i4'] uSpitzer = ["e_"+col for col in Spitzer] wlSpitzer = [3.6,4.5,5.8,8.] labelSpitzer = 'Spitzer' SOFIA = ['F11','F19','F31','F37'] uSOFIA = ["e_"+col for col in SOFIA] wlSOFIA = [11.1,19.7,31.5,37.1] labelSOFIA = 'SOFIA' sources = sourcetable.group_by('SOFIA_name') for key,source in zip(sources.groups.keys,sources.groups): if sourcename == source['SOFIA_name'][0]: datapoints = source[TwoMASS+Spitzer+SOFIA] dataerrors = source[uTwoMASS+uSpitzer+uSOFIA] print p.nptable(datapoints),p.nptable(dataerrors) # calculate log10 of quantities required for chi squared logFnu = np.log10(p.nptable(datapoints))-0.5*(1./np.log(10.))*p.nptable(dataerrors)**2/p.nptable(datapoints)**2 varlogFnu = (1./np.log(10)/p.nptable(datapoints))**2*p.nptable(dataerrors)**2 print extinct_values,extinct_values.shape # for each inclination, calculate chi squared; need to interpolate to get model at required wavelengths Ninc = extinct_values.shape[1] chi2 = np.zeros(Ninc) wl=wlTwoMASS+wlSpitzer+wlSOFIA N = len(wl) for j in range(Ninc): interp_func = interp1d(sed.wav,extinct_values[:,j],kind='linear') interp_vals = interp_func(wl) chi2[j] = 1./N * np.sum((logFnu - interp_vals)**2/varlogFnu) print chi2 def plotModel(self,dist_pc=140,inc=3,extinction=0,show=False,sourcename='Oph.1'): self.dist=dist_pc*pc self.inc=inc self.extinction=extinction modelname = self.folder+self.name self.mo = ModelOutput(modelname+'.rtout') #tracy_dust = np.loadtxt('Tracy_models/OH5.par') chi = np.loadtxt('kmh94_3.1_full.chi') wav = np.loadtxt('kmh94_3.1_full.wav') Chi = interp1d(wav,chi,kind='linear') fig = plt.figure(figsize=(20,14)) ax=fig.add_subplot(2,3,1) sed = self.mo.get_sed(aperture=-1, inclination='all', distance=self.dist) #print tracy_dust[11,1],Cext(sed.wav[-1]),Cext(sed.wav[-1])/tracy_dust[11,1] tau = self.extinction*Chi(sed.wav)/Chi(0.550)/1.086 #print Cext(sed.wav)/tracy_dust[11,1] ext = np.array([np.exp(-tau) for i in range(sed.val.shape[0])]) #print tau,np.exp(-tau) ax.loglog(sed.wav, sed.val.transpose()*ext.T, color='black') ax.set_title(modelname+'_seds, Av='+str(self.extinction)) ax.set_xlim(sed.wav.min(), 1300) ax.set_ylim(1e-13, 1e-7) ax.set_xlabel(r'$\lambda$ [$\mu$m]') ax.set_ylabel(r'$\lambda F_\lambda$ [ergs/cm$^2/s$]') self.plotData(ax,sourcename) ax.set_xscale('log') ax.set_yscale('log') #ax.set_ylabel(r'$F_{Jy}$ [Jy]') #plt.legend(loc=4) ax=fig.add_subplot(2,3,2) sed = self.mo.get_sed(aperture=-1, inclination=self.inc, distance=self.dist) ext=np.exp(-tau) ax.loglog(sed.wav, sed.val.transpose()*ext.T, lw=3,color='black',label='source_total') ax.set_xlim(sed.wav.min(), 1300) ax.set_ylim(1e-13, 1e-7) ### for lamFlam sed = self.mo.get_sed(aperture=-1, inclination=self.inc, distance=self.dist,component='source_emit') ax.loglog(sed.wav, sed.val.transpose()*ext.T, color='blue',label='source_emit') sed = self.mo.get_sed(aperture=-1, inclination=self.inc, distance=self.dist,component='source_scat') ax.loglog(sed.wav, sed.val.transpose()*ext.T, color='teal',label='source_scat') sed = self.mo.get_sed(aperture=-1, inclination=self.inc, distance=self.dist,component='dust_emit') ax.loglog(sed.wav, sed.val.transpose()*ext.T, color='red',label='dust_emit') sed = self.mo.get_sed(aperture=-1, inclination=self.inc, distance=self.dist,component='dust_scat') ax.loglog(sed.wav, sed.val.transpose()*ext.T, color='orange',label='dust_scat') self.plotData(ax,sourcename) ax.set_xscale('log') ax.set_yscale('log') ax.set_title('seds_inc=inc') ax.set_xlabel(r'$\lambda$ [$\mu$m]') ax.set_ylabel(r'$\lambda F_\lambda$ [ergs/cm$^2/s$]') #ax.set_ylabel(r'$F_{Jy}$ [Jy]') leg = ax.legend(loc=4,fontsize='small') #leg = plt.gca().get_legend() #plt.setp(leg.get_text(),fontsize='small') # Extract the quantities g = self.mo.get_quantities() # Get the wall positions for r and theta rw, tw = g.r_wall / au, g.t_wall # Make a 2-d grid of the wall positions (used by pcolormesh) R, T = np.meshgrid(rw, tw) # Calculate the position of the cell walls in cartesian coordinates X, Z = R * np.sin(T), R * np.cos(T) # Make a plot in (x, z) space for different zooms from matplotlib.colors import LogNorm,PowerNorm # Make a plot in (r, theta) space ax = fig.add_subplot(2, 3, 3) if g.shape[-1]==2: c = ax.pcolormesh(X, Z, g['temperature'][0].array[0, :, :]+g['temperature'][1].array[0, :, :],norm=PowerNorm(gamma=0.5,vmin=1,vmax=500)) else : c = ax.pcolormesh(X, Z, g['temperature'][0].array[0, :, :],norm=PowerNorm(gamma=0.5,vmin=1,vmax=500)) #ax.set_xscale('log') #ax.set_yscale('log') ax.set_xlim(X.min(), X.max()/5.) ax.set_ylim(Z.min()/10., Z.max()/10.) ax.set_xlabel('x (au)') ax.set_ylabel('z (au)') #ax.set_yticks([np.pi, np.pi * 0.75, np.pi * 0.5, np.pi * 0.25, 0.]) #ax.set_yticklabels([r'$\pi$', r'$3\pi/4$', r'$\pi/2$', r'$\pi/4$', r'$0$']) cb = fig.colorbar(c) ax.set_title('Temperature structure') cb.set_label('Temperature (K)') #fig.savefig(modelname+'_temperature_spherical_rt.png', bbox_inches='tight') ax = fig.add_subplot(2, 3, 4) if g.shape[-1]==2: c = ax.pcolormesh(X, Z, g['density'][0].array[0, :, :]+g['density'][1].array[0, :, :],norm=LogNorm(vmin=1e-22,vmax=g['density'][0].array[0, :, :].max())) else : c = ax.pcolormesh(X, Z, g['density'][0].array[0, :, :],norm=LogNorm(vmin=1e-22,vmax=g['density'][0].array[0, :, :].max())) #ax.set_xscale('log') #ax.set_yscale('log') ax.set_xlim(X.min(), X.max()/5.) ax.set_ylim(Z.min()/10., Z.max()/10.) ax.set_xlabel('x (au)') ax.set_ylabel('z (au)') ax.set_title('Density structure') cb = fig.colorbar(c) cb.set_label('Density (g/cm2)') ### plot the convolved image with the 37 micron filter (manually set to slice 18 of the cube - this would change with wavelength coverage) ax = fig.add_subplot(2, 3, 5) self.image = self.mo.get_image(inclination=inc,distance=self.dist,units='Jy') fits.writeto(modelname+'_inc_'+str(inc)+'.fits',self.image.val.swapaxes(0,2).swapaxes(1,2),clobber=True) ### need to convolve the image with a Gaussian PSF pix = 2.*self.limval/au/self.Npix # in AU/pix pix_asec = pix/(self.dist/pc) # in asec/pix airy_asec = 3.5 #asec airy_pix = airy_asec/pix_asec # in pix gauss_pix = airy_pix/2.35 # in Gaussian std print "Gaussian std: ",gauss_pix from scipy.ndimage.filters import gaussian_filter as gauss #print [(i,sed.wav[i]) for i in range(len(sed.wav))] img37 = self.image.val[:,:,18] convol = gauss(img37,gauss_pix,mode='constant',cval=0.0) Nc = self.Npix/2 hw = min(int(20./pix_asec),Nc) #(max is Nc) #ax.imshow(img37,norm=LogNorm(vmin=1e-20,vmax=img37.max())) #ax.imshow(img37,interpolation='nearest') #ax.imshow(convol,norm=LogNorm(vmin=1e-20,vmax=img37.max())) #ax.imshow(convol,interpolation='nearest',norm=LogNorm(vmin=1e-20,vmax=img37.max())) ax.imshow(convol[Nc-hw:Nc+hw,Nc-hw:Nc+hw],interpolation='nearest',origin='lower',cmap=plt.get_cmap('gray')) airy_disk = plt.Circle((airy_pix*1.3,airy_pix*1.3),airy_pix,color=colors[3]) ax.add_artist(airy_disk) ax.text(airy_pix*3,airy_pix*1.3/2.0,'SOFIA 37um Airy disk',color=colors[3]) ax.set_title('Convolved image') fits.writeto(modelname+'_inc_'+str(inc)+'_convol37.fits',convol,clobber=True) ### draw a cross-section of the image to show the spatial extension in linear scale, to compare with what we observe in the model. ax = fig.add_subplot(2, 3, 6) ax.plot(range(Nc-hw,Nc+hw),convol[Nc-hw:Nc+hw,Nc-1],label='cross-section 1') ax.plot(range(Nc-hw,Nc+hw),convol[Nc-1,Nc-hw:Nc+hw],label='cross-section 2') maxconvol = convol[Nc-hw:Nc+hw,Nc-1].max() gauss = np.exp( -(np.array(range(-hw,hw))**2 / (2. * gauss_pix**2))) gauss/= gauss.max() gauss*=maxconvol ax.plot(range(Nc-hw,Nc+hw),gauss,label='SOFIA beam') leg = ax.legend(loc=2,fontsize='small') #leg = plt.gca().get_legend() #plt.setp(leg.get_text(),fontsize='small') ax.set_title('Cross section at the center') string=self.modelPrint() fig.text(0.0,0.14,string+'Av='+str(self.extinction)+'\n'+'dist='+str(self.dist/pc)+'\n',color='r') fig.savefig(modelname+'.png', bbox_inches='tight',dpi=300) if show: plt.show() def plotSim(self,dist_pc=140,inc=3,extinction=0,show=False): self.dist=dist_pc*pc self.inc=inc self.extinction=extinction modelname = self.folder+self.name self.mo = ModelOutput(modelname+'.rtout') #tracy_dust = np.loadtxt('Tracy_models/OH5.par') #chi = np.loadtxt('kmh94_3.1_full.chi') #wav = np.loadtxt('kmh94_3.1_full.wav') #Chi = interp1d(wav,chi,kind='linear') fig = plt.figure(figsize=(20,14)) ax=fig.add_subplot(1,3,1) sed = self.mo.get_sed(aperture=-1, inclination='all', distance=self.dist) #print tracy_dust[11,1],Cext(sed.wav[-1]),Cext(sed.wav[-1])/tracy_dust[11,1] #tau = self.extinction*Chi(sed.wav)/Chi(0.550)/1.086 #print Cext(sed.wav)/tracy_dust[11,1] #ext = np.array([np.exp(-tau) for i in range(sed.val.shape[0])]) #print tau,np.exp(-tau) ax.loglog(sed.wav, sed.val.transpose(), color='black') ax.set_title(modelname+'_seds, Av='+str(self.extinction)) ax.set_xlim(sed.wav.min(), 1300) ax.set_ylim(1e-13, 1e-7) ax.set_xlabel(r'$\lambda$ [$\mu$m]') ax.set_ylabel(r'$\lambda F_\lambda$ [ergs/cm$^2/s$]') #self.plotData(ax,sourcename) ax.set_xscale('log') ax.set_yscale('log') #ax.set_ylabel(r'$F_{Jy}$ [Jy]') #plt.legend(loc=4) # ax=fig.add_subplot(2,3,2) # sed = self.mo.get_sed(aperture=-1, inclination=self.inc, distance=self.dist) # ext=np.exp(-tau) # ax.loglog(sed.wav, sed.val.transpose()*ext.T, lw=3,color='black',label='source_total') # ax.set_xlim(sed.wav.min(), 1300) # ax.set_ylim(1e-13, 1e-7) ### for lamFlam # sed = self.mo.get_sed(aperture=-1, inclination=self.inc, distance=self.dist,component='source_emit') # ax.loglog(sed.wav, sed.val.transpose()*ext.T, color='blue',label='source_emit') # sed = self.mo.get_sed(aperture=-1, inclination=self.inc, distance=self.dist,component='source_scat') # ax.loglog(sed.wav, sed.val.transpose()*ext.T, color='teal',label='source_scat') # sed = self.mo.get_sed(aperture=-1, inclination=self.inc, distance=self.dist,component='dust_emit') # ax.loglog(sed.wav, sed.val.transpose()*ext.T, color='red',label='dust_emit') # sed = self.mo.get_sed(aperture=-1, inclination=self.inc, distance=self.dist,component='dust_scat') # ax.loglog(sed.wav, sed.val.transpose()*ext.T, color='orange',label='dust_scat') # #self.plotData(ax,sourcename) # ax.set_xscale('log') # ax.set_yscale('log') # ax.set_title('seds_inc=inc') # ax.set_xlabel(r'$\lambda$ [$\mu$m]') # ax.set_ylabel(r'$\lambda F_\lambda$ [ergs/cm$^2/s$]') # #ax.set_ylabel(r'$F_{Jy}$ [Jy]') # leg = ax.legend(loc=4,fontsize='small') #leg = plt.gca().get_legend() #plt.setp(leg.get_text(),fontsize='small') # Extract the quantities g = self.mo.get_quantities() # Get the wall positions for r and theta rw, tw = g.r_wall / au, g.t_wall # Make a 2-d grid of the wall positions (used by pcolormesh) R, T = np.meshgrid(rw, tw) # Calculate the position of the cell walls in cartesian coordinates X, Z = R * np.sin(T), R * np.cos(T) # Make a plot in (x, z) space for different zooms from matplotlib.colors import LogNorm,PowerNorm # Make a plot in (r, theta) space ax = fig.add_subplot(1, 3, 2) if g.shape[-1]==2: c = ax.pcolormesh(X, Z, g['temperature'][0].array[0, :, :]+g['temperature'][1].array[0, :, :],norm=PowerNorm(gamma=0.5,vmin=1,vmax=500)) else : c = ax.pcolormesh(X, Z, g['temperature'][0].array[0, :, :],norm=PowerNorm(gamma=0.5,vmin=1,vmax=500)) #ax.set_xscale('log') #ax.set_yscale('log') ax.set_xlim(X.min(), X.max()) ax.set_ylim(Z.min(), Z.max()) ax.set_xlabel('x (au)') ax.set_ylabel('z (au)') #ax.set_yticks([np.pi, np.pi * 0.75, np.pi * 0.5, np.pi * 0.25, 0.]) #ax.set_yticklabels([r'$\pi$', r'$3\pi/4$', r'$\pi/2$', r'$\pi/4$', r'$0$']) cb = fig.colorbar(c) ax.set_title('Temperature structure') cb.set_label('Temperature (K)') #fig.savefig(modelname+'_temperature_spherical_rt.png', bbox_inches='tight') ax = fig.add_subplot(1, 3, 3) if g.shape[-1]==2: c = ax.pcolormesh(X, Z, g['density'][0].array[0, :, :]+g['density'][1].array[0, :, :],norm=LogNorm(vmin=1e-22,vmax=g['density'][0].array[0, :, :].max())) else : c = ax.pcolormesh(X, Z, g['density'][0].array[0, :, :],norm=LogNorm(vmin=1e-22,vmax=g['density'][0].array[0, :, :].max())) #ax.set_xscale('log') #ax.set_yscale('log') ax.set_xlim(X.min(), X.max()) ax.set_ylim(Z.min(), Z.max()) ax.set_xlabel('x (au)') ax.set_ylabel('z (au)') ax.set_title('Density structure') cb = fig.colorbar(c) cb.set_label('Density (g/cm2)') # ### plot the convolved image with the 37 micron filter (manually set to slice 18 of the cube - this would change with wavelength coverage) # ax = fig.add_subplot(2, 3, 5) # self.image = self.mo.get_image(inclination=inc,distance=self.dist,units='Jy') # fits.writeto(modelname+'_inc_'+str(inc)+'.fits',self.image.val.swapaxes(0,2).swapaxes(1,2),clobber=True) # ### need to convolve the image with a Gaussian PSF # pix = 2.*self.limval/au/self.Npix # in AU/pix # pix_asec = pix/(self.dist/pc) # in asec/pix # airy_asec = 3.5 #asec # airy_pix = airy_asec/pix_asec # in pix # gauss_pix = airy_pix/2.35 # in Gaussian std # print "Gaussian std: ",gauss_pix # from scipy.ndimage.filters import gaussian_filter as gauss # #print [(i,sed.wav[i]) for i in range(len(sed.wav))] # img37 = self.image.val[:,:,18] # convol = gauss(img37,gauss_pix,mode='constant',cval=0.0) # Nc = self.Npix/2 # hw = min(int(20./pix_asec),Nc) #(max is Nc) # #ax.imshow(img37,norm=LogNorm(vmin=1e-20,vmax=img37.max())) # #ax.imshow(img37,interpolation='nearest') # #ax.imshow(convol,norm=LogNorm(vmin=1e-20,vmax=img37.max())) # #ax.imshow(convol,interpolation='nearest',norm=LogNorm(vmin=1e-20,vmax=img37.max())) # ax.imshow(convol[Nc-hw:Nc+hw,Nc-hw:Nc+hw],interpolation='nearest',origin='lower',cmap=plt.get_cmap('gray')) # airy_disk = plt.Circle((airy_pix*1.3,airy_pix*1.3),airy_pix,color=colors[3]) # ax.add_artist(airy_disk) # ax.text(airy_pix*3,airy_pix*1.3/2.0,'SOFIA 37um Airy disk',color=colors[3]) # ax.set_title('Convolved image') # fits.writeto(modelname+'_inc_'+str(inc)+'_convol37.fits',convol,clobber=True) # ### draw a cross-section of the image to show the spatial extension in linear scale, to compare with what we observe in the model. # ax = fig.add_subplot(2, 3, 6) # ax.plot(range(Nc-hw,Nc+hw),convol[Nc-hw:Nc+hw,Nc-1],label='cross-section 1') # ax.plot(range(Nc-hw,Nc+hw),convol[Nc-1,Nc-hw:Nc+hw],label='cross-section 2') # maxconvol = convol[Nc-hw:Nc+hw,Nc-1].max() # gauss = np.exp( -(np.array(range(-hw,hw))**2 / (2. * gauss_pix**2))) # gauss/= gauss.max() # gauss*=maxconvol # ax.plot(range(Nc-hw,Nc+hw),gauss,label='SOFIA beam') # leg = ax.legend(loc=2,fontsize='small') # #leg = plt.gca().get_legend() # #plt.setp(leg.get_text(),fontsize='small') # ax.set_title('Cross section at the center') string=self.modelPrint() fig.text(0.0,0.14,string+'Av='+str(self.extinction)+'\n'+'dist='+str(self.dist/pc)+'\n',color='r') fig.savefig(modelname+'.png', bbox_inches='tight',dpi=300) if show: plt.show()
import astropy.constants as constants import astropy.units as u from hyperion.model import ModelOutput import tqdm #galaxies = pd.read_pickle('/orange/narayanan/s.lower/simba/ml_SEDs_z0.pkl')['ID'] galaxies = spec_list = [] wave_list = [] for galaxy in tqdm.tqdm(galaxies): m = ModelOutput('/ufrc/narayanan/s.lower//pd_runs/simba_m25n512/snap305/mist_pd/snap305/snap305.galaxy'+"{:03d}".format(galaxy)+".rtout.sed") wav,flux = m.get_sed(inclination=0,aperture=-1) wav = np.asarray(wav)*u.micron truncate_llim = (np.abs(wav.value - 0.005)).argmin() truncate_ulim = (np.abs(wav.value - 1000.)).argmin() #print(truncate_llim) #print(wav[-1]) flux = np.asarray(flux)*u.erg/u.s dl = (10. * u.pc).to(u.cm) flux /= (4.*3.14*dl**2.) nu = constants.c.cgs/(wav.to(u.cm)) nu = nu.to(u.Hz) flux /= nu flux = flux[truncate_ulim:truncate_llim].to(u.mJy) spec_list.append(flux.value) wave_list.append(wav[truncate_ulim:truncate_llim].value)
Chi = interp1d(wav,chi,kind='linear') # now load up the grid name = ['IRAS20050'] folder = ['/cardini3/mrizzo/2012SOFIA/SED_Models/hyperion/IRAS20050_new/'] filename = folder[0]+name[0]+"_"+target+".grid.dat" if os.path.exists(filename): grid = pickle.load(open(filename,'r')) # for each fit that is desired, search for the right line in the grid fitnames = grid.group_by('name') for fitkey,fitname in zip(fitnames.groups.keys,fitnames.groups): name = fitkey['name'] #print name fname = folder[0]+name+'.rtout' mo = ModelOutput(fname) sed = mo.get_sed(aperture=-1, inclination='all', distance=dist,units='Jy') if name in plotlist: # sort table according to chi2 fitname.sort('chi2') # the first line is then the best fit. let's select the extinction extinction = fitname['ext'][0] print "extinction = ",extinction # inclination angles=np.arccos(np.linspace(0,1.,20))*180./np.pi incs=angles[::-1] #incs = [0.,10.,20.,30.,40.,50.,60.,70.,80.,90.] inc = int(np.argwhere(incs==fitname['inc'][0]))
def extract_hyperion(filename,indir=None,outdir=None,dstar=178.0,wl_aper=None,save=True,filter_func=False,\ plot_all=False,clean=False,exclude_wl=[],log=True): def l_bol(wl, fv, dist=178.0): import numpy as np import astropy.constants as const # wavelength unit: um # Flux density unit: Jy # # constants setup # c = const.c.cgs.value pc = const.pc.cgs.value PI = np.pi SL = const.L_sun.cgs.value # Convert the unit from Jy to erg s-1 cm-2 Hz-1 fv = np.array(fv) * 1e-23 freq = c / (1e-4 * np.array(wl)) diff_dum = freq[1:] - freq[0:-1] freq_interpol = np.hstack( (freq[0:-1] + diff_dum / 2.0, freq[0:-1] + diff_dum / 2.0, freq[0], freq[-1])) freq_interpol = freq_interpol[np.argsort(freq_interpol)[::-1]] fv_interpol = np.empty(len(freq_interpol)) # calculate the histogram style of spectrum # for i in range(0, len(fv)): if i == 0: fv_interpol[i] = fv[i] else: fv_interpol[2 * i - 1] = fv[i - 1] fv_interpol[2 * i] = fv[i] fv_interpol[-1] = fv[-1] dv = freq_interpol[0:-1] - freq_interpol[1:] dv = np.delete(dv, np.where(dv == 0)) fv = fv[np.argsort(freq)] freq = freq[np.argsort(freq)] return (np.trapz(fv, freq) * 4. * PI * (dist * pc)**2) / SL # to avoid X server error import matplotlib as mpl mpl.use('Agg') # import matplotlib.pyplot as plt import numpy as np import os from hyperion.model import ModelOutput, Model from scipy.interpolate import interp1d from hyperion.util.constants import pc, c, lsun, au from astropy.io import ascii import sys sys.path.append(os.path.expanduser('~') + '/programs/spectra_analysis/') from phot_filter import phot_filter from get_bhr71_obs import get_bhr71_obs # seaborn colormap, because jet is bad obviously import seaborn.apionly as sns # Read in the observation data and calculate the noise & variance if indir == None: indir = '/Users/yaolun/bhr71/' if outdir == None: outdir = '/Users/yaolun/bhr71/hyperion/' # assign the file name from the input file print_name = os.path.splitext(os.path.basename(filename))[0] # use a canned function to extract BHR71 observational data bhr71 = get_bhr71_obs(indir) # unit in um, Jy wl_tot, flux_tot, unc_tot = bhr71['spec'] flux_tot = flux_tot * 1e-23 # convert unit from Jy to erg s-1 cm-2 Hz-1 unc_tot = unc_tot * 1e-23 l_bol_obs = l_bol(wl_tot, flux_tot * 1e23) wl_phot, flux_phot, flux_sig_phot = bhr71['phot'] flux_phot = flux_phot * 1e-23 # convert unit from Jy to erg s-1 cm-2 Hz-1 flux_sig_phot = flux_sig_phot * 1e-23 # Print the observed L_bol # wl_tot = np.hstack((wl_irs,wl_obs,wl_phot)) # flux_tot = np.hstack((flux_irs,flux_obs,flux_phot)) # flux_tot = flux_tot[np.argsort(wl_tot)] # wl_tot = wl_tot[np.argsort(wl_tot)] # l_bol_obs = l_bol(wl_tot,flux_tot*1e23) # Open the model m = ModelOutput(filename) if wl_aper == None: wl_aper = [ 3.6, 4.5, 5.8, 8.0, 10, 16, 20, 24, 35, 70, 100, 160, 250, 350, 500, 850 ] # Create the plot mag = 1.5 fig = plt.figure(figsize=(8 * mag, 6 * mag)) ax_sed = fig.add_subplot(1, 1, 1) # Plot the observed SED # plot the observed spectra if not clean: color_seq = ['Green', 'Red', 'Blue'] else: color_seq = ['DimGray', 'DimGray', 'DimGray'] # plot the observations if log: pacs, = ax_sed.plot(np.log10(wl_tot[(wl_tot>40) & (wl_tot<190.31)]),\ np.log10(c/(wl_tot[(wl_tot>40) & (wl_tot<190.31)]*1e-4)*flux_tot[(wl_tot>40) & (wl_tot<190.31)]),\ '-',color=color_seq[0],linewidth=1.5*mag, alpha=0.7) spire, = ax_sed.plot(np.log10(wl_tot[wl_tot > 194]),np.log10(c/(wl_tot[wl_tot > 194]*1e-4)*flux_tot[wl_tot > 194]),\ '-',color=color_seq[1],linewidth=1.5*mag, alpha=0.7) irs, = ax_sed.plot(np.log10(wl_tot[wl_tot < 40]),np.log10(c/(wl_tot[wl_tot < 40]*1e-4)*flux_tot[wl_tot < 40]),\ '-',color=color_seq[2],linewidth=1.5*mag, alpha=0.7) photometry, = ax_sed.plot(np.log10(wl_phot), np.log10(c / (wl_phot * 1e-4) * flux_phot), 's', mfc='DimGray', mec='k', markersize=8) # plot the observed photometry data ax_sed.errorbar(np.log10(wl_phot),np.log10(c/(wl_phot*1e-4)*flux_phot),\ yerr=[np.log10(c/(wl_phot*1e-4)*flux_phot)-np.log10(c/(wl_phot*1e-4)*(flux_phot-flux_sig_phot)),\ np.log10(c/(wl_phot*1e-4)*(flux_phot+flux_sig_phot))-np.log10(c/(wl_phot*1e-4)*flux_phot)],\ fmt='s',mfc='DimGray',mec='k',markersize=8) else: pacs, = ax_sed.plot(np.log10(wl_tot[(wl_tot>40) & (wl_tot<190.31)]),\ c/(wl_tot[(wl_tot>40) & (wl_tot<190.31)]*1e-4)*flux_tot[(wl_tot>40) & (wl_tot<190.31)],\ '-',color=color_seq[0],linewidth=1.5*mag, alpha=0.7) spire, = ax_sed.plot(np.log10(wl_tot[wl_tot > 194]),c/(wl_tot[wl_tot > 194]*1e-4)*flux_tot[wl_tot > 194],\ '-',color=color_seq[1],linewidth=1.5*mag, alpha=0.7) irs, = ax_sed.plot(np.log10(wl_tot[wl_tot < 40]),c/(wl_tot[wl_tot < 40]*1e-4)*flux_tot[wl_tot < 40],\ '-',color=color_seq[2],linewidth=1.5*mag, alpha=0.7) photometry, = ax_sed.plot(wl_phot, c / (wl_phot * 1e-4) * flux_phot, 's', mfc='DimGray', mec='k', markersize=8) # plot the observed photometry data ax_sed.errorbar(np.log10(wl_phot),c/(wl_phot*1e-4)*flux_phot,\ yerr=[c/(wl_phot*1e-4)*flux_phot-c/(wl_phot*1e-4)*(flux_phot-flux_sig_phot),\ c/(wl_phot*1e-4)*(flux_phot+flux_sig_phot)-c/(wl_phot*1e-4)*flux_phot],\ fmt='s',mfc='DimGray',mec='k',markersize=8) if not clean: ax_sed.text(0.75, 0.9, r'$\rm{L_{bol}= %5.2f L_{\odot}}$' % l_bol_obs, fontsize=mag * 16, transform=ax_sed.transAxes) # else: # pacs, = ax_sed.plot(np.log10(wl_tot[(wl_tot>40) & (wl_tot<190.31)]),\ # np.log10(c/(wl_tot[(wl_tot>40) & (wl_tot<190.31)]*1e-4)*flux_tot[(wl_tot>40) & (wl_tot<190.31)]),\ # '-',color='DimGray',linewidth=1.5*mag, alpha=0.7) # spire, = ax_sed.plot(np.log10(wl_tot[wl_tot > 194]),np.log10(c/(wl_tot[wl_tot > 194]*1e-4)*flux_tot[wl_tot > 194]),\ # '-',color='DimGray',linewidth=1.5*mag, alpha=0.7) # irs, = ax_sed.plot(np.log10(wl_tot[wl_tot < 40]),np.log10(c/(wl_tot[wl_tot < 40]*1e-4)*flux_tot[wl_tot < 40]),\ # '-',color='DimGray',linewidth=1.5*mag, alpha=0.7) # Extract the SED for the smallest inclination and largest aperture, and # scale to 300pc. In Python, negative indices can be used for lists and # arrays, and indicate the position from the end. So to get the SED in the # largest aperture, we set aperture=-1. # aperture group is aranged from smallest to infinite sed_inf = m.get_sed(group=0, inclination=0, aperture=-1, distance=dstar * pc, uncertainties=True) # plot the simulated SED if clean == False: sim, = ax_sed.plot(np.log10(sed_inf.wav), np.log10(sed_inf.val), '-', color='GoldenRod', linewidth=0.5 * mag) ax_sed.fill_between(np.log10(sed_inf.wav), np.log10(sed_inf.val-sed_inf.unc), np.log10(sed_inf.val+sed_inf.unc),\ color='GoldenRod', alpha=0.5) # get flux at different apertures flux_aper = np.zeros_like(wl_aper, dtype=float) unc_aper = np.zeros_like(wl_aper, dtype=float) a = np.zeros_like(wl_aper) + 1 color_list = plt.cm.jet(np.linspace(0, 1, len(wl_aper) + 1)) for i in range(0, len(wl_aper)): if wl_aper[i] in exclude_wl: continue # if (wl_aper[i] == 5.8) or (wl_aper[i] == 8.0) or (wl_aper[i] == 10.5) or (wl_aper[i] == 11): # continue sed_dum = m.get_sed(group=i + 1, inclination=0, aperture=-1, distance=dstar * pc, uncertainties=True) if plot_all == True: ax_sed.plot(np.log10(sed_dum.wav), np.log10(sed_dum.val), '-', color=color_list[i]) ax_sed.fill_between(np.log10(sed_dum.wav), np.log10(sed_dum.val-sed_dum.unc), np.log10(sed_dum.val+sed_dum.unc),\ color=color_list[i], alpha=0.5) if filter_func == False: # use a rectangle function the average the simulated SED # apply the spectral resolution if (wl_aper[i] < 50.) & (wl_aper[i] >= 5): res = 60. elif wl_aper[i] < 5: res = 10. else: res = 1000. ind = np.where((sed_dum.wav < wl_aper[i] * (1 + 1. / res)) & (sed_dum.wav > wl_aper[i] * (1 - 1. / res))) if len(ind[0]) != 0: flux_aper[i] = np.mean(sed_dum.val[ind]) unc_aper[i] = np.mean(sed_dum.unc[ind]) else: f = interp1d(sed_dum.wav, sed_dum.val) f_unc = interp1d(sed_dum.wav, sed_dum.unc) flux_aper[i] = f(wl_aper[i]) unc_aper[i] = f_unc(wl_aper[i]) else: # apply the filter function # decide the filter name if wl_aper[i] == 70: fil_name = 'Herschel PACS 70um' elif wl_aper[i] == 100: fil_name = 'Herschel PACS 100um' elif wl_aper[i] == 160: fil_name = 'Herschel PACS 160um' elif wl_aper[i] == 250: fil_name = 'Herschel SPIRE 250um' elif wl_aper[i] == 350: fil_name = 'Herschel SPIRE 350um' elif wl_aper[i] == 500: fil_name = 'Herschel SPIRE 500um' elif wl_aper[i] == 3.6: fil_name = 'IRAC Channel 1' elif wl_aper[i] == 4.5: fil_name = 'IRAC Channel 2' elif wl_aper[i] == 5.8: fil_name = 'IRAC Channel 3' elif wl_aper[i] == 8.0: fil_name = 'IRAC Channel 4' elif wl_aper[i] == 24: fil_name = 'MIPS 24um' elif wl_aper[i] == 850: fil_name = 'SCUBA 850WB' else: fil_name = None if fil_name != None: filter_func = phot_filter(fil_name) # Simulated SED should have enough wavelength coverage for applying photometry filters. f = interp1d(sed_dum.wav, sed_dum.val) f_unc = interp1d(sed_dum.wav, sed_dum.unc) flux_aper[i] = np.trapz( filter_func['wave'] / 1e4, f(filter_func['wave'] / 1e4) * filter_func['transmission']) / np.trapz( filter_func['wave'] / 1e4, filter_func['transmission']) unc_aper[i] = abs( np.trapz((filter_func['wave'] / 1e4)**2, (f_unc(filter_func['wave'] / 1e4) * filter_func['transmission'])**2))**0.5 / abs( np.trapz(filter_func['wave'] / 1e4, filter_func['transmission'])) else: # use a rectangle function the average the simulated SED # apply the spectral resolution if (wl_aper[i] < 50.) & (wl_aper[i] >= 5): res = 60. elif wl_aper[i] < 5: res = 10. else: res = 1000. ind = np.where((sed_dum.wav < wl_aper[i] * (1 + 1. / res)) & (sed_dum.wav > wl_aper[i] * (1 - 1. / res))) if len(ind[0]) != 0: flux_aper[i] = np.mean(sed_dum.val[ind]) unc_aper[i] = np.mean(sed_dum.unc[ind]) else: f = interp1d(sed_dum.wav, sed_dum.val) f_unc = interp1d(sed_dum.wav, sed_dum.unc) flux_aper[i] = f(wl_aper[i]) unc_aper[i] = f_unc(wl_aper[i]) # temperory step: solve issue of uncertainty greater than the value for i in range(len(wl_aper)): if unc_aper[i] >= flux_aper[i]: unc_aper[i] = flux_aper[i] - 1e-20 # perform the same procedure of flux extraction of aperture flux with observed spectra wl_aper = np.array(wl_aper, dtype=float) obs_aper_wl = wl_aper[(wl_aper >= min(wl_tot)) & (wl_aper <= max(wl_tot))] obs_aper_sed = np.zeros_like(obs_aper_wl) obs_aper_sed_unc = np.zeros_like(obs_aper_wl) sed_tot = c / (wl_tot * 1e-4) * flux_tot sed_unc_tot = c / (wl_tot * 1e-4) * unc_tot # wl_tot and flux_tot are already hstacked and sorted by wavelength for i in range(0, len(obs_aper_wl)): if obs_aper_wl[i] in exclude_wl: continue if filter_func == False: # use a rectangle function the average the simulated SED # apply the spectral resolution if (obs_aper_wl[i] < 50.) & (obs_aper_wl[i] >= 5): res = 60. elif obs_aper_wl[i] < 5: res = 10. else: res = 1000. ind = np.where((wl_tot < obs_aper_wl[i] * (1 + 1. / res)) & (wl_tot > obs_aper_wl[i] * (1 - 1. / res))) if len(ind[0]) != 0: obs_aper_sed[i] = np.mean(sed_tot[ind]) obs_aper_sed_unc[i] = np.mean(sed_unc_tot[ind]) else: f = interp1d(wl_tot, sed_tot) f_unc = interp1d(wl_tot, sed_unc_tot) obs_aper_sed[i] = f(obs_aper_wl[i]) obs_aper_sed_unc[i] = f_unc(obs_aper_wl[i]) else: # apply the filter function # decide the filter name if obs_aper_wl[i] == 70: fil_name = 'Herschel PACS 70um' elif obs_aper_wl[i] == 100: fil_name = 'Herschel PACS 100um' elif obs_aper_wl[i] == 160: fil_name = 'Herschel PACS 160um' elif obs_aper_wl[i] == 250: fil_name = 'Herschel SPIRE 250um' elif obs_aper_wl[i] == 350: fil_name = 'Herschel SPIRE 350um' elif obs_aper_wl[i] == 500: fil_name = 'Herschel SPIRE 500um' elif obs_aper_wl[i] == 3.6: fil_name = 'IRAC Channel 1' elif obs_aper_wl[i] == 4.5: fil_name = 'IRAC Channel 2' elif obs_aper_wl[i] == 5.8: fil_name = 'IRAC Channel 3' elif obs_aper_wl[i] == 8.0: fil_name = 'IRAC Channel 4' elif obs_aper_wl[i] == 24: fil_name = 'MIPS 24um' # elif obs_aper_wl[i] == 850: # fil_name = 'SCUBA 850WB' # do not have SCUBA spectra else: fil_name = None # print obs_aper_wl[i], fil_name if fil_name != None: filter_func = phot_filter(fil_name) # Observed SED needs to be trimmed before applying photometry filters filter_func = filter_func[(filter_func['wave']/1e4 >= min(wl_tot))*\ ((filter_func['wave']/1e4 >= 54.8)+(filter_func['wave']/1e4 <= 36.0853))*\ ((filter_func['wave']/1e4 <= 95.05)+(filter_func['wave']/1e4 >=103))*\ ((filter_func['wave']/1e4 <= 190.31)+(filter_func['wave']/1e4 >= 195))*\ (filter_func['wave']/1e4 <= max(wl_tot))] f = interp1d(wl_tot, sed_tot) f_unc = interp1d(wl_tot, sed_unc_tot) obs_aper_sed[i] = np.trapz( filter_func['wave'] / 1e4, f(filter_func['wave'] / 1e4) * filter_func['transmission']) / np.trapz( filter_func['wave'] / 1e4, filter_func['transmission']) obs_aper_sed_unc[i] = abs( np.trapz((filter_func['wave'] / 1e4)**2, (f_unc(filter_func['wave'] / 1e4) * filter_func['transmission'])**2))**0.5 / abs( np.trapz(filter_func['wave'] / 1e4, filter_func['transmission'])) else: # use a rectangle function the average the simulated SED # apply the spectral resolution if (obs_aper_wl[i] < 50.) & (obs_aper_wl[i] >= 5): res = 60. elif obs_aper_wl[i] < 5: res = 10. else: res = 1000. ind = np.where((wl_tot < obs_aper_wl[i] * (1 + 1. / res)) & (wl_tot > obs_aper_wl[i] * (1 - 1. / res))) if len(ind[0]) != 0: obs_aper_sed[i] = np.mean(sed_tot[ind]) obs_aper_sed_unc[i] = np.mean(sed_unc_tot[ind]) else: f = interp1d(wl_tot, sed_tot) f_unc = interp1d(wl_tot, sed_unc_tot) obs_aper_sed[i] = f(obs_aper_wl[i]) obs_aper_sed_unc[i] = f_unc(obs_aper_wl[i]) # if clean == False: # if log: # aper_obs = ax_sed.errorbar(np.log10(obs_aper_wl), np.log10(obs_aper_sed), \ # yerr=[np.log10(obs_aper_sed)-np.log10(obs_aper_sed-obs_aper_sed_unc), np.log10(obs_aper_sed+obs_aper_sed_unc)-np.log10(obs_aper_sed)],\ # fmt='s', mec='Magenta', mfc='Magenta', markersize=10, elinewidth=3, ecolor='Magenta',capthick=3,barsabove=True) # aper = ax_sed.errorbar(np.log10(wl_aper), np.log10(flux_aper),\ # yerr=[np.log10(flux_aper)-np.log10(flux_aper-unc_aper), np.log10(flux_aper+unc_aper)-np.log10(flux_aper)],\ # fmt='o', mfc='None', mec='k', ecolor='Black', markersize=12, markeredgewidth=3, elinewidth=3, barsabove=True) # else: # aper_obs = ax_sed.errorbar(obs_aper_wl, obs_aper_sed, yerr=obs_aper_sed_unc,\ # fmt='s', mec='Magenta', mfc='Magenta', markersize=10, elinewidth=3, ecolor='Magenta',capthick=3,barsabove=True) # aper = ax_sed.errorbar(wl_aper, flux_aper, yerr=unc_aper,\ # fmt='o', mfc='None', mec='k', ecolor='Black', markersize=12, markeredgewidth=3, elinewidth=3, barsabove=True) # else: if log: aper_obs = ax_sed.errorbar(np.log10(obs_aper_wl), np.log10(obs_aper_sed),\ yerr=[np.log10(obs_aper_sed)-np.log10(obs_aper_sed-obs_aper_sed_unc), np.log10(obs_aper_sed+obs_aper_sed_unc)-np.log10(obs_aper_sed)],\ fmt='s', mec='None', mfc='r', markersize=10, linewidth=1.5, ecolor='Red', elinewidth=3, capthick=3, barsabove=True) aper = ax_sed.errorbar(np.log10(wl_aper),np.log10(flux_aper),\ yerr=[np.log10(flux_aper)-np.log10(flux_aper-unc_aper), np.log10(flux_aper+unc_aper)-np.log10(flux_aper)],\ fmt='o', mec='Blue', mfc='None', color='b',markersize=12, markeredgewidth=2.5, linewidth=1.7, ecolor='Blue', elinewidth=3, barsabove=True) ax_sed.set_ylim([-14, -7]) ax_sed.set_xlim([0, 3]) else: aper_obs = ax_sed.errorbar(np.log10(obs_aper_wl), obs_aper_sed, yerr=obs_aper_sed_unc,\ fmt='s', mec='None', mfc='r', markersize=10, linewidth=1.5, ecolor='Red', elinewidth=3, capthick=3, barsabove=True) aper = ax_sed.errorbar(np.log10(wl_aper),flux_aper, yerr=unc_aper,\ fmt='o', mec='Blue', mfc='None', color='b',markersize=12, markeredgewidth=2.5, linewidth=1.7, ecolor='Blue', elinewidth=3, barsabove=True) # ax_sed.set_xlim([1, 1000]) ax_sed.set_xlim([0, 3]) # ax_sed.set_ylim([1e-14, 1e-8]) # calculate the bolometric luminosity of the aperture # print flux_aper l_bol_sim = l_bol(wl_aper, flux_aper / (c / np.array(wl_aper) * 1e4) * 1e23) print 'Bolometric luminosity of simulated spectrum: %5.2f lsun' % l_bol_sim # print out the sed into ascii file for reading in later if save == True: # unapertured SED foo = open(outdir + print_name + '_sed_inf.txt', 'w') foo.write('%12s \t %12s \t %12s \n' % ('wave', 'vSv', 'sigma_vSv')) for i in range(0, len(sed_inf.wav)): foo.write('%12g \t %12g \t %12g \n' % (sed_inf.wav[i], sed_inf.val[i], sed_inf.unc[i])) foo.close() # SED with convolution of aperture sizes foo = open(outdir + print_name + '_sed_w_aperture.txt', 'w') foo.write('%12s \t %12s \t %12s \n' % ('wave', 'vSv', 'sigma_vSv')) for i in range(0, len(wl_aper)): foo.write('%12g \t %12g \t %12g \n' % (wl_aper[i], flux_aper[i], unc_aper[i])) foo.close() # Read in and plot the simulated SED produced by RADMC-3D using the same parameters # [wl,fit] = np.genfromtxt(indir+'hyperion/radmc_comparison/spectrum.out',dtype='float',skip_header=3).T # l_bol_radmc = l_bol(wl,fit*1e23/dstar**2) # radmc, = ax_sed.plot(np.log10(wl),np.log10(c/(wl*1e-4)*fit/dstar**2),'-',color='DimGray', linewidth=1.5*mag, alpha=0.5) # print the L bol of the simulated SED (both Hyperion and RADMC-3D) # lg_sim = ax_sed.legend([sim,radmc],[r'$\rm{L_{bol,sim}=%5.2f\,L_{\odot},\,L_{center}=9.18\,L_{\odot}}$' % l_bol_sim, \ # r'$\rm{L_{bol,radmc3d}=%5.2f\,L_{\odot},\,L_{center}=9.18\,L_{\odot}}$' % l_bol_radmc],\ # loc='lower right',fontsize=mag*16) # read the input central luminosity by reading in the source information from output file dum = Model() dum.use_sources(filename) L_cen = dum.sources[0].luminosity / lsun # legend lg_data = ax_sed.legend([irs, photometry, aper, aper_obs],\ [r'$\rm{observation}$',\ r'$\rm{photometry}$',r'$\rm{F_{aper,sim}}$',r'$\rm{F_{aper,obs}}$'],\ loc='upper left',fontsize=14*mag,numpoints=1,framealpha=0.3) if clean == False: lg_sim = ax_sed.legend([sim],[r'$\rm{L_{bol,sim}=%5.2f\,L_{\odot},\,L_{center}=%5.2f\,L_{\odot}}$' % (l_bol_sim, L_cen)], \ loc='lower right',fontsize=mag*16) plt.gca().add_artist(lg_data) # plot setting ax_sed.set_xlabel(r'$\rm{log\,\lambda\,({\mu}m)}$', fontsize=mag * 20) ax_sed.set_ylabel(r'$\rm{log\,\nu S_{\nu}\,(erg/cm^{2}/s)}$', fontsize=mag * 20) [ ax_sed.spines[axis].set_linewidth(1.5 * mag) for axis in ['top', 'bottom', 'left', 'right'] ] ax_sed.minorticks_on() ax_sed.tick_params('both', labelsize=mag * 18, width=1.5 * mag, which='major', pad=15, length=5 * mag) ax_sed.tick_params('both', labelsize=mag * 18, width=1.5 * mag, which='minor', pad=15, length=2.5 * mag) # fix the tick label font ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral', size=mag * 18) for label in ax_sed.get_xticklabels(): label.set_fontproperties(ticks_font) for label in ax_sed.get_yticklabels(): label.set_fontproperties(ticks_font) # if clean == False: # lg_data = ax_sed.legend([irs, pacs, spire,photometry],[r'$\rm{{\it Spitzer}-IRS}$',r'$\rm{{\it Herschel}-PACS}$',r'$\rm{{\it Herschel}-SPIRE}$',r'$\rm{Photometry}$'],\ # loc='upper left',fontsize=14*mag,numpoints=1,framealpha=0.3) # plt.gca().add_artist(lg_sim) # else: # lg_data = ax_sed.legend([irs, photometry, aper, aper_obs],\ # [r'$\rm{observation}$',\ # r'$\rm{photometry}$',r'$\rm{F_{aper,sim}}$',r'$\rm{F_{aper,obs}}$'],\ # loc='upper left',fontsize=14*mag,numpoints=1,framealpha=0.3) # Write out the plot fig.savefig(outdir + print_name + '_sed.pdf', format='pdf', dpi=300, bbox_inches='tight') fig.clf() # Package for matching the colorbar from mpl_toolkits.axes_grid1 import make_axes_locatable # Extract the image for the first inclination, and scale to 300pc. We # have to specify group=1 as there is no image in group 0. image = m.get_image(group=len(wl_aper) + 1, inclination=0, distance=dstar * pc, units='MJy/sr') # image = m.get_image(group=14, inclination=0, distance=dstar * pc, units='MJy/sr') # Open figure and create axes # fig = plt.figure(figsize=(8, 8)) fig, axarr = plt.subplots(3, 3, sharex='col', sharey='row', figsize=(13.5, 12)) # Pre-set maximum for colorscales VMAX = {} # VMAX[3.6] = 10. # VMAX[24] = 100. # VMAX[160] = 2000. # VMAX[500] = 2000. VMAX[100] = 10. VMAX[250] = 100. VMAX[500] = 2000. VMAX[1000] = 2000. # We will now show four sub-plots, each one for a different wavelength # for i, wav in enumerate([3.6, 24, 160, 500]): # for i, wav in enumerate([100, 250, 500, 1000]): # for i, wav in enumerate([4.5, 9.7, 24, 40, 70, 100, 250, 500, 1000]): for i, wav in enumerate([3.6, 8.0, 9.7, 24, 40, 100, 250, 500, 1000]): # ax = fig.add_subplot(3, 3, i + 1) ax = axarr[i / 3, i % 3] # Find the closest wavelength iwav = np.argmin(np.abs(wav - image.wav)) # Calculate the image width in arcseconds given the distance used above # get the max radius rmax = max(m.get_quantities().r_wall) w = np.degrees(rmax / image.distance) * 3600. # Image in the unit of MJy/sr # Change it into erg/s/cm2/Hz/sr factor = 1e-23 * 1e6 # avoid zero in log # flip the image, because the setup of inclination is upside down val = image.val[::-1, :, iwav] * factor + 1e-30 # val = image.val[:, :, iwav] * factor + 1e-30 # This is the command to show the image. The parameters vmin and vmax are # the min and max levels for the colorscale (remove for default values). # cmap = sns.cubehelix_palette(start=0.1, rot=-0.7, gamma=0.2, as_cmap=True) cmap = plt.cm.CMRmap im = ax.imshow(np.log10(val), vmin=-22, vmax=-12, cmap=cmap, origin='lower', extent=[-w, w, -w, w], aspect=1) # fix the tick label font ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral', size=14) for label in ax.get_xticklabels(): label.set_fontproperties(ticks_font) for label in ax.get_yticklabels(): label.set_fontproperties(ticks_font) # Colorbar setting # create an axes on the right side of ax. The width of cax will be 5% # of ax and the padding between cax and ax will be fixed at 0.05 inch. if (i + 1) % 3 == 0: divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = fig.colorbar(im, cax=cax) cb.solids.set_edgecolor("face") cb.ax.minorticks_on() cb.ax.set_ylabel( r'$\rm{log(I_{\nu})\,[erg\,s^{-1}\,cm^{-2}\,Hz^{-1}\,sr^{-1}]}$', fontsize=12) cb_obj = plt.getp(cb.ax.axes, 'yticklabels') plt.setp(cb_obj, fontsize=12) # fix the tick label font ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral', size=12) for label in cb.ax.get_yticklabels(): label.set_fontproperties(ticks_font) if (i + 1) == 7: # Finalize the plot ax.set_xlabel(r'$\rm{RA\,Offset\,(arcsec)}$', fontsize=14) ax.set_ylabel(r'$\rm{Dec\,Offset\,(arcsec)}$', fontsize=14) ax.tick_params(axis='both', which='major', labelsize=16) ax.set_adjustable('box-forced') ax.text(0.7, 0.88, str(wav) + r'$\rm{\,\mu m}$', fontsize=16, color='white', transform=ax.transAxes) fig.subplots_adjust(hspace=0, wspace=-0.2) # Adjust the spaces between the subplots # plt.tight_layout() fig.savefig(outdir + print_name + '_cube_plot.png', format='png', dpi=300, bbox_inches='tight') fig.clf()
def AlphaHyperion(rtout, aperfile, dstar, wave_center, lbollsmm=False): import matplotlib as mpl mpl.use('Agg') import matplotlib.pyplot as plt import numpy as np import os from hyperion.model import ModelOutput, Model from hyperion.util.constants import pc, c, lsun, au from astropy.io import ascii def getAlpha(spec, wave_center, plot=False, plotname=None): """ spec = {'Wavelength(um)': wave, 'Flux_Density(Jy)': flux, 'Uncertainty(Jy)': unc} """ from astropy.modeling import models, fitting, powerlaws from scipy.interpolate import interp1d import astropy.constants as const import numpy as np c = const.c.cgs.value # initial guess x_ref = c / 1e5 / wave_center f_flux = interp1d(c / 1e5 / spec['Wavelength(um)'], spec['Flux_Density(Jy)']) amp = f_flux(x_ref) alpha = 0 # unit conversions freq_dum = (c/1e5/spec['Wavelength(um)'])\ [(c/1e5/spec['Wavelength(um)']>= x_ref-100) & (c/1e5/spec['Wavelength(um)']<= x_ref+100)] flux_dum = spec['Flux_Density(Jy)']\ [(c/1e5/spec['Wavelength(um)']>= x_ref-100) & (c/1e5/spec['Wavelength(um)']<= x_ref+100)] pow_model = powerlaws.PowerLaw1D(amp, x_ref, alpha) fitter = fitting.LevMarLSQFitter() fit = fitter(pow_model, freq_dum, flux_dum) alpha = -fit.alpha.value if fitter.fit_info['param_cov'] is None: alpha_err = np.nan else: alpha_err = fitter.fit_info['param_cov'][2, 2]**0.5 if plot: # to avoid X server error import matplotlib as mpl mpl.use('Agg') # import matplotlib.pyplot as plt fig = plt.figure(figsize=(10, 6)) ax = fig.add_subplot(111) ax.plot(freq_dum, flux_dum, 'o') ax.plot(freq_dum, fit(freq_dum), '-', color='k') ax.text(0.6, 0.05, r'$\alpha_{500} = %3.2f \pm %3.2f$' % (alpha, alpha_err), transform=ax.transAxes, fontsize=18) [ ax.spines[axis].set_linewidth(1.5) for axis in ['top', 'bottom', 'left', 'right'] ] ax.minorticks_on() ax.tick_params('both', labelsize=18, width=1.5, which='major', pad=10, length=5) ax.tick_params('both', labelsize=18, width=1.5, which='minor', pad=10, length=2.5) ax.set_xlabel('Frequency [GHz]', fontsize=18) ax.set_ylabel('Flux Density [Jy]', fontsize=18) ax.set_xlim([400, 2000]) fig.savefig(plotname + 'Alpha500Hyperion.pdf', format='pdf', dpi=300, bbox_inches='tight') fig.clf() return (alpha, alpha_err) def lsubmm(low_wave, spec, dist): """ spec = 'Wavelength(um)' and 'Flux_Density(Jy)' dist: distance in parsec """ import sys import os sys.path.append(os.path.expanduser('~') + '/programs/misc/hyperion/') from l_bol import l_bol l = l_bol(spec['Wavelength(um)'][spec['Wavelength(um)'] >= low_wave], spec['Flux_Density(Jy)'][spec['Wavelength(um)'] >= low_wave], dist) return l # get aperture list aperture = ascii.read(aperfile) # create the non-repetitive aperture list and index array aper_reduced = list(set(aperture['aperture(arcsec)'])) # read in Hyperion output m = ModelOutput(rtout) # list for storing outputs alpha = [] alpha_err = [] aperture_list = [] # option for calculating Lbol/Lsumm at the same time if lbollsmm: lbol = [] lsmm = [] # fig = plt.figure() # ax = fig.add_subplot(111) # iterate through apertures for i in range(0, len(aper_reduced)): # getting simulated SED from Hyperion output. (have to match with the reduced index) sed_dum = m.get_sed(group=i, inclination=0, aperture=-1, distance=dstar * pc, uncertainties=True) # get aperture from the output SED aperture_list.append(sed_dum.ap_min / (dstar * pc) / (1 / 3600. * np.pi / 180.) * 2) # ax.plot(sed_dum.wav, sed_dum.val, label='{:4.1f}'.format(aperture_list[i])) # construct 'spec' dictionary sorter = np.argsort(sed_dum.wav) spec = { 'Wavelength(um)': sed_dum.wav[sorter], 'Flux_Density(Jy)': (sed_dum.val / (c / sed_dum.wav * 1e4) * 1e23)[sorter], 'Uncertainty(Jy)': (sed_dum.unc / (c / sed_dum.wav * 1e4) * 1e23)[sorter] } # option for calculating Lbol/Lsumm at the same time if lbollsmm: # model_name = os.path.basename(rtout).split('.')[0] # data = ascii.read(lbollsmm+model_name+'_sed_w_aperture.txt') # specphot = {'Wavelength(um)': data['wave'], # 'Flux_Density(Jy)': data['vSv']/(c/np.array(data['wave'])*1e4)*1e23} # lbol.append(lsubmm(specphot['Wavelength(um)'].min(), specphot, dstar)) # lsmm.append(lsubmm(350.0, specphot, dstar)) lbol.append(lsubmm(spec['Wavelength(um)'].min(), spec, dstar)) lsmm.append(lsubmm(350.0, spec, dstar)) # get alpha plotname = '/home/bettyjo/yaolun/test/' + str(aperture_list[-1]) + '_' alpha_dum, alpha_err_dum = getAlpha(spec, wave_center, plot=False, plotname=plotname) alpha.append(alpha_dum) alpha_err.append(alpha_err_dum) # ax.set_xscale('log') # ax.set_yscale('log') # ax.legend(ncol=2, loc='best') # fig.savefig('/Users/yaolun/test/sed_test.pdf', format='pdf', dpi=300, bbox_inches='tight') if not lbollsmm: return np.array(aperture_list), np.array(alpha), np.array(alpha_err) else: return np.array(aperture_list), np.array(alpha), np.array( alpha_err), np.array(lbol), np.array(lsmm)
from hyperion.util.constants import kpc import matplotlib.pyplot as plt if not os.path.exists('seds'): os.mkdir('seds') for model_path in glob.glob(os.path.join('models', '*_seds.rtout')): m = ModelOutput(model_path) model_name = os.path.basename(model_path).replace('_seds.rtout', '') for iincl, theta in enumerate([0, 30, 60, 90, 120, 150, 180]): sed_total = m.get_sed(inclination=iincl, units='Jy', distance=10. * kpc, aperture=-1, group=0, component='total') sed_semit = m.get_sed(inclination=iincl, units='Jy', distance=10. * kpc, aperture=-1, group=0, component='source_emit') sed_sscat = m.get_sed(inclination=iincl, units='Jy', distance=10. * kpc, aperture=-1, group=0, component='source_scat') sed_demit = m.get_sed(inclination=iincl, units='Jy', distance=10. * kpc, aperture=-1, group=0, component='dust_emit') sed_dscat = m.get_sed(inclination=iincl, units='Jy', distance=10. * kpc, aperture=-1, group=0, component='dust_scat') sed_trans = m.get_sed(inclination=iincl, units='Jy', distance=10. * kpc, aperture=-1, group=1, component='source_emit') output_file = 'seds/{name}_i{theta:03d}a000.sed'.format(name=model_name, theta=theta) # TODO: remove me once fixed upstream output_file = output_file.replace('t1e+0', 't1e0').replace('t1e+1', 't1e1').replace('t1e+2', 't1e2') np.savetxt(output_file, list(zip(sed_total.wav, sed_total.val, sed_semit.val,
newgrid = Table(names=oldparams+['ext','inc','chi2','chi2_old','n'],dtype=oldtypes+['f8','f8','f8','f8','i8']) # calculate chi squared metric for each run of the grid #len(grid)-150, for i in range(len(grid)): #for i in range(1): # load model fname = folder[0]+grid['name'][i]+'.rtout' if i%10 ==0: print "Model: ",fname if os.path.exists(fname):# and grid['env_rmax'][i]==5000.0 and grid['disk_mass'][i]==0.003: #print "Model found!" mo = ModelOutput(fname) # load sed from model sed = mo.get_sed(aperture=-1, inclination='all', distance=distance(target),units='Jy') for extinction in extinctions: # calculate optical depth tau_ext1 = Chi(sed.wav)/Chi(0.550)/1.086 tau = tau_ext1*extinction #print "tau,",tau # calculate extinction for all inclinations ext = np.array([np.exp(-tau) for shape in range(sed.val.shape[0])]) #print "ext,",ext # apply extinction to model extinct_values = np.log10(sed.val.transpose()*ext.T) #print "extinct_values,extinct_values.shape",extinct_values,extinct_values.shape
lum_source_downsampled[i] = lum_source[idx].value return source_lam_downsampled, lum_source_downsampled #check if path exists - if not, create it #if not os.path.exists(output_directory): os.makedirs(output_directory) sed_file = glob(sed_directory + '/*galaxy' + str(galaxy_num) + '.rtout.sed')[0] #print(sed_file) stellar_file = glob(sources_directory + '/*.galaxy' + str(galaxy_num) + '.rtout.sed')[0] comp_sed = ModelOutput(sed_file) wav_rest_sed, dum_lum_obs_sed = comp_sed.get_sed(inclination='all', aperture=-1) wav_rest_sed = wav_rest_sed * u.micron #wav is in micron nu_rest_sed = constants.c.cgs / wav_rest_sed.cgs lum_obs_sed = dum_lum_obs_sed lum_obs_sed = lum_obs_sed * u.erg / u.s nu_rest_sed = constants.c.cgs / (wav_rest_sed.to(u.cm)) fnu_obs_sed = lum_obs_sed.to(u.Lsun) fnu_obs_sed /= nu_rest_sed.to(u.Hz) fnu_obs_sed = fnu_obs_sed.to(u.Lsun / u.Hz) #stellar_sed = np.load(stellar_file) #nu_rest_stellar = stellar_sed['nu'] #Hz #fnu_rest_stellar = stellar_sed['fnu'] #Lsun/Hz #fnu_rest_stellar = fnu_rest_stellar * u.Lsun/u.Hz #nu_rest_stellar = nu_rest_stellar * u.Hz #lum_rest_stellar = fnu_rest_stellar * nu_rest_stellar
def extract_hyperion(filename, indir=None, outdir=None, dstar=178.0, wl_aper=None, save=True): def l_bol(wl, fv, dist=178.0): import numpy as np import astropy.constants as const # wavelength unit: um # Flux density unit: Jy # # constants setup # c = const.c.cgs.value pc = const.pc.cgs.value PI = np.pi SL = const.L_sun.cgs.value # Convert the unit from Jy to erg s-1 cm-2 Hz-1 fv = np.array(fv) * 1e-23 freq = c / (1e-4 * np.array(wl)) diff_dum = freq[1:] - freq[0:-1] freq_interpol = np.hstack( (freq[0:-1] + diff_dum / 2.0, freq[0:-1] + diff_dum / 2.0, freq[0], freq[-1])) freq_interpol = freq_interpol[np.argsort(freq_interpol)[::-1]] fv_interpol = np.empty(len(freq_interpol)) # calculate the histogram style of spectrum # for i in range(0, len(fv)): if i == 0: fv_interpol[i] = fv[i] else: fv_interpol[2 * i - 1] = fv[i - 1] fv_interpol[2 * i] = fv[i] fv_interpol[-1] = fv[-1] dv = freq_interpol[0:-1] - freq_interpol[1:] dv = np.delete(dv, np.where(dv == 0)) fv = fv[np.argsort(freq)] freq = freq[np.argsort(freq)] return (np.trapz(fv, freq) * 4. * PI * (dist * pc)**2) / SL import matplotlib.pyplot as plt import numpy as np import os from hyperion.model import ModelOutput from hyperion.model import Model from scipy.interpolate import interp1d from hyperion.util.constants import pc, c, lsun # Read in the observation data and calculate the noise & variance if indir == None: indir = '/Users/yaolun/bhr71/' if outdir == None: outdir = '/Users/yaolun/bhr71/hyperion/' # assign the file name from the input file print_name = os.path.splitext(os.path.basename(filename))[0] # [wl_pacs,flux_pacs,unc_pacs] = np.genfromtxt(indir+'BHR71_centralSpaxel_PointSourceCorrected_CorrectedYES_trim_continuum.txt',\ dtype='float',skip_header=1).T # Convert the unit from Jy to erg cm-2 Hz-1 flux_pacs = flux_pacs * 1e-23 [wl_spire, flux_spire] = np.genfromtxt(indir + 'BHR71_spire_corrected_continuum.txt', dtype='float', skip_header=1).T flux_spire = flux_spire * 1e-23 wl_obs = np.hstack((wl_pacs, wl_spire)) flux_obs = np.hstack((flux_pacs, flux_spire)) [wl_pacs_data,flux_pacs_data,unc_pacs_data] = np.genfromtxt(indir+'BHR71_centralSpaxel_PointSourceCorrected_CorrectedYES_trim.txt',\ dtype='float').T [wl_spire_data,flux_spire_data] = np.genfromtxt(indir+'BHR71_spire_corrected.txt',\ dtype='float').T [wl_pacs_flat,flux_pacs_flat,unc_pacs_flat] = np.genfromtxt(indir+'BHR71_centralSpaxel_PointSourceCorrected_CorrectedYES_trim_flat_spectrum.txt',\ dtype='float',skip_header=1).T [wl_spire_flat, flux_spire_flat ] = np.genfromtxt(indir + 'BHR71_spire_corrected_flat_spectrum.txt', dtype='float', skip_header=1).T # Convert the unit from Jy to erg cm-2 Hz-1 flux_pacs_flat = flux_pacs_flat * 1e-23 flux_spire_flat = flux_spire_flat * 1e-23 flux_pacs_data = flux_pacs_data * 1e-23 flux_spire_data = flux_spire_data * 1e-23 wl_pacs_noise = wl_pacs_data flux_pacs_noise = flux_pacs_data - flux_pacs - flux_pacs_flat wl_spire_noise = wl_spire_data flux_spire_noise = flux_spire_data - flux_spire - flux_spire_flat # Read in the Spitzer IRS spectrum [wl_irs, flux_irs] = (np.genfromtxt(indir + 'bhr71_spitzer_irs.txt', skip_header=2, dtype='float').T)[0:2] # Convert the unit from Jy to erg cm-2 Hz-1 flux_irs = flux_irs * 1e-23 # Remove points with zero or negative flux ind = flux_irs > 0 wl_irs = wl_irs[ind] flux_irs = flux_irs[ind] # Calculate the local variance (for spire), use the instrument uncertainty for pacs # wl_noise_5 = wl_spire_noise[(wl_spire_noise > 194) * (wl_spire_noise <= 304)] flux_noise_5 = flux_spire_noise[(wl_spire_noise > 194) * (wl_spire_noise <= 304)] wl_noise_6 = wl_spire_noise[wl_spire_noise > 304] flux_noise_6 = flux_spire_noise[wl_spire_noise > 304] wl_noise = [wl_pacs_data[wl_pacs_data <= 190.31], wl_noise_5, wl_noise_6] flux_noise = [unc_pacs[wl_pacs_data <= 190.31], flux_noise_5, flux_noise_6] sig_num = 20 sigma_noise = [] for i in range(0, len(wl_noise)): sigma_dum = np.zeros([len(wl_noise[i])]) for iwl in range(0, len(wl_noise[i])): if iwl < sig_num / 2: sigma_dum[iwl] = np.std( np.hstack((flux_noise[i][0:sig_num / 2], flux_noise[i][0:sig_num / 2 - iwl]))) elif len(wl_noise[i]) - iwl < sig_num / 2: sigma_dum[iwl] = np.std( np.hstack( (flux_noise[i][iwl:], flux_noise[i][len(wl_noise[i]) - sig_num / 2:]))) else: sigma_dum[iwl] = np.std(flux_noise[i][iwl - sig_num / 2:iwl + sig_num / 2]) sigma_noise = np.hstack((sigma_noise, sigma_dum)) sigma_noise = np.array(sigma_noise) # Read in the photometry data phot = np.genfromtxt(indir + 'bhr71.txt', dtype=None, skip_header=1, comments='%') wl_phot = [] flux_phot = [] flux_sig_phot = [] note = [] for i in range(0, len(phot)): wl_phot.append(phot[i][0]) flux_phot.append(phot[i][1]) flux_sig_phot.append(phot[i][2]) note.append(phot[i][4]) wl_phot = np.array(wl_phot) # Convert the unit from Jy to erg cm-2 Hz-1 flux_phot = np.array(flux_phot) * 1e-23 flux_sig_phot = np.array(flux_sig_phot) * 1e-23 # Print the observed L_bol wl_tot = np.hstack((wl_irs, wl_obs, wl_phot)) flux_tot = np.hstack((flux_irs, flux_obs, flux_phot)) flux_tot = flux_tot[np.argsort(wl_tot)] wl_tot = wl_tot[np.argsort(wl_tot)] l_bol_obs = l_bol(wl_tot, flux_tot * 1e23) # Open the model m = ModelOutput(filename) if wl_aper == None: wl_aper = [ 3.6, 4.5, 5.8, 8.0, 10, 16, 20, 24, 35, 70, 100, 160, 250, 350, 500, 850 ] # Create the plot mag = 1.5 fig = plt.figure(figsize=(8 * mag, 6 * mag)) ax_sed = fig.add_subplot(1, 1, 1) # Plot the observed SED # plot the observed spectra pacs, = ax_sed.plot(np.log10(wl_pacs), np.log10(c / (wl_pacs * 1e-4) * flux_pacs), '-', color='DimGray', linewidth=1.5 * mag, alpha=0.7) spire, = ax_sed.plot(np.log10(wl_spire), np.log10(c / (wl_spire * 1e-4) * flux_spire), '-', color='DimGray', linewidth=1.5 * mag, alpha=0.7) irs, = ax_sed.plot(np.log10(wl_irs), np.log10(c / (wl_irs * 1e-4) * flux_irs), '-', color='DimGray', linewidth=1.5 * mag, alpha=0.7) # ax_sed.text(0.75,0.9,r'$\rm{L_{bol}= %5.2f L_{\odot}}$' % l_bol_obs,fontsize=mag*16,transform=ax_sed.transAxes) # plot the observed photometry data photometry, = ax_sed.plot(np.log10(wl_phot), np.log10(c / (wl_phot * 1e-4) * flux_phot), 's', mfc='DimGray', mec='k', markersize=8) ax_sed.errorbar(np.log10(wl_phot),np.log10(c/(wl_phot*1e-4)*flux_phot),\ yerr=[np.log10(c/(wl_phot*1e-4)*flux_phot)-np.log10(c/(wl_phot*1e-4)*(flux_phot-flux_sig_phot)),\ np.log10(c/(wl_phot*1e-4)*(flux_phot+flux_sig_phot))-np.log10(c/(wl_phot*1e-4)*flux_phot)],\ fmt='s',mfc='DimGray',mec='k',markersize=8) # Extract the SED for the smallest inclination and largest aperture, and # scale to 300pc. In Python, negative indices can be used for lists and # arrays, and indicate the position from the end. So to get the SED in the # largest aperture, we set aperture=-1. # aperture group is aranged from smallest to infinite sed_inf = m.get_sed(group=0, inclination=0, aperture=-1, distance=dstar * pc) # l_bol_sim = l_bol(sed_inf.wav, sed_inf.val/(c/sed_inf.wav*1e4)*1e23) # print sed.wav, sed.val # print 'Bolometric luminosity of simulated spectrum: %5.2f lsun' % l_bol_sim # plot the simulated SED # sim, = ax_sed.plot(np.log10(sed_inf.wav), np.log10(sed_inf.val), '-', color='k', linewidth=1.5*mag, alpha=0.7) # get flux at different apertures flux_aper = np.empty_like(wl_aper) unc_aper = np.empty_like(wl_aper) for i in range(0, len(wl_aper)): sed_dum = m.get_sed(group=i + 1, inclination=0, aperture=-1, distance=dstar * pc) # use a rectangle function the average the simulated SED # apply the spectral resolution if (wl_aper[i] < 50.) & (wl_aper[i] >= 5): res = 60. elif wl_aper[i] < 5: res = 10. else: res = 1000. ind = np.where((sed_dum.wav < wl_aper[i] * (1 + 1. / res)) & (sed_dum.wav > wl_aper[i] * (1 - 1. / res))) if len(ind[0]) != 0: flux_aper[i] = np.mean(sed_dum.val[ind]) else: f = interp1d(sed_dum.wav, sed_dum.val) flux_aper[i] = f(wl_aper[i]) # perform the same procedure of flux extraction of aperture flux with observed spectra wl_aper = np.array(wl_aper) obs_aper_wl = wl_aper[(wl_aper >= min(wl_irs)) & (wl_aper <= max(wl_spire))] obs_aper_sed = np.empty_like(obs_aper_wl) sed_tot = c / (wl_tot * 1e-4) * flux_tot # wl_tot and flux_tot are already hstacked and sorted by wavelength for i in range(0, len(obs_aper_wl)): if (obs_aper_wl[i] < 50.) & (obs_aper_wl[i] >= 5): res = 60. elif obs_aper_wl[i] < 5: res = 10. else: res = 1000. ind = np.where((wl_tot < obs_aper_wl[i] * (1 + 1. / res)) & (wl_tot > obs_aper_wl[i] * (1 - 1. / res))) if len(ind[0]) != 0: obs_aper_sed[i] = np.mean(sed_tot[ind]) else: f = interp1d(wl_tot, sed_tot) obs_aper_sed[i] = f(wl_aper[i]) aper_obs, = ax_sed.plot(np.log10(obs_aper_wl), np.log10(obs_aper_sed), 's-', mec='None', mfc='r', color='r', markersize=10, linewidth=1.5) # # interpolate the uncertainty (maybe not the best way to do this) # print sed_dum.unc # f = interp1d(sed_dum.wav, sed_dum.unc) # unc_aper[i] = f(wl_aper[i]) # if wl_aper[i] == 9.7: # ax_sed.plot(np.log10(sed_dum.wav), np.log10(sed_dum.val), '-', linewidth=1.5*mag) # print l_bol(sed_dum.wav, sed_dum.val/(c/sed_dum.wav*1e4)*1e23) aper, = ax_sed.plot(np.log10(wl_aper), np.log10(flux_aper), 'o-', mec='Blue', mfc='None', color='b', markersize=12, markeredgewidth=3, linewidth=1.7) # calculate the bolometric luminosity of the aperture l_bol_sim = l_bol(wl_aper, flux_aper / (c / np.array(wl_aper) * 1e4) * 1e23) print 'Bolometric luminosity of simulated spectrum: %5.2f lsun' % l_bol_sim # print out the sed into ascii file for reading in later if save == True: # unapertured SED foo = open(outdir + print_name + '_sed_inf.txt', 'w') foo.write('%12s \t %12s \n' % ('wave', 'vSv')) for i in range(0, len(sed_inf.wav)): foo.write('%12g \t %12g \n' % (sed_inf.wav[i], sed_inf.val[i])) foo.close() # SED with convolution of aperture sizes foo = open(outdir + print_name + '_sed_w_aperture.txt', 'w') foo.write('%12s \t %12s \n' % ('wave', 'vSv')) for i in range(0, len(wl_aper)): foo.write('%12g \t %12g \n' % (wl_aper[i], flux_aper[i])) foo.close() # Read in and plot the simulated SED produced by RADMC-3D using the same parameters # [wl,fit] = np.genfromtxt(indir+'hyperion/radmc_comparison/spectrum.out',dtype='float',skip_header=3).T # l_bol_radmc = l_bol(wl,fit*1e23/dstar**2) # radmc, = ax_sed.plot(np.log10(wl),np.log10(c/(wl*1e-4)*fit/dstar**2),'-',color='DimGray', linewidth=1.5*mag, alpha=0.5) # print the L bol of the simulated SED (both Hyperion and RADMC-3D) # lg_sim = ax_sed.legend([sim,radmc],[r'$\rm{L_{bol,sim}=%5.2f~L_{\odot},~L_{center}=9.18~L_{\odot}}$' % l_bol_sim, \ # r'$\rm{L_{bol,radmc3d}=%5.2f~L_{\odot},~L_{center}=9.18~L_{\odot}}$' % l_bol_radmc],\ # loc='lower right',fontsize=mag*16) # read the input central luminosity by reading in the source information from output file dum = Model() dum.use_sources(filename) L_cen = dum.sources[0].luminosity / lsun # lg_sim = ax_sed.legend([sim],[r'$\rm{L_{bol,sim}=%5.2f~L_{\odot},~L_{center}=%5.2f~L_{\odot}}$' % (l_bol_sim, L_cen)], \ # loc='lower right',fontsize=mag*16) # lg_sim = ax_sed.legend([sim],[r'$\rm{L_{bol,sim}=%5.2f~L_{\odot},~L_{bol,obs}=%5.2f~L_{\odot}}$' % (l_bol_sim, l_bol_obs)], \ # loc='lower right',fontsize=mag*16) # text = ax_sed.text(0.2 ,0.05 ,r'$\rm{L_{bol,simulation}=%5.2f~L_{\odot},~L_{bol,observation}=%5.2f~L_{\odot}}$' % (l_bol_sim, l_bol_obs),fontsize=mag*16,transform=ax_sed.transAxes) # text.set_bbox(dict( edgecolor='k',facecolor='None',alpha=0.3,pad=10.0)) # plot setting ax_sed.set_xlabel(r'$\rm{log\,\lambda\,({\mu}m)}$', fontsize=mag * 20) ax_sed.set_ylabel(r'$\rm{log\,\nu S_{\nu}\,(erg\,cm^{-2}\,s^{-1})}$', fontsize=mag * 20) [ ax_sed.spines[axis].set_linewidth(1.5 * mag) for axis in ['top', 'bottom', 'left', 'right'] ] ax_sed.minorticks_on() ax_sed.tick_params('both', labelsize=mag * 18, width=1.5 * mag, which='major', pad=15, length=5 * mag) ax_sed.tick_params('both', labelsize=mag * 18, width=1.5 * mag, which='minor', pad=15, length=2.5 * mag) ax_sed.set_ylim([-13, -7.5]) ax_sed.set_xlim([0, 3]) # lg_data = ax_sed.legend([sim, aper], [r'$\rm{w/o~aperture}$', r'$\rm{w/~aperture}$'], \ # loc='upper left', fontsize=14*mag, framealpha=0.3, numpoints=1) lg_data = ax_sed.legend([irs, photometry, aper, aper_obs],\ [r'$\rm{observation}$',\ r'$\rm{photometry}$',r'$\rm{F_{aper,sim}}$',r'$\rm{F_{aper,obs}}$'],\ loc='upper left',fontsize=14*mag,numpoints=1,framealpha=0.3) # plt.gca().add_artist(lg_sim) # Write out the plot fig.savefig(outdir + print_name + '_sed.pdf', format='pdf', dpi=300, bbox_inches='tight') fig.clf() # Package for matching the colorbar from mpl_toolkits.axes_grid1 import make_axes_locatable # Extract the image for the first inclination, and scale to 300pc. We # have to specify group=1 as there is no image in group 0. image = m.get_image(group=len(wl_aper) + 1, inclination=0, distance=dstar * pc, units='MJy/sr') # image = m.get_image(group=14, inclination=0, distance=dstar * pc, units='MJy/sr') # Open figure and create axes # fig = plt.figure(figsize=(8, 8)) fig, axarr = plt.subplots(3, 3, sharex='col', sharey='row', figsize=(13.5, 12)) # Pre-set maximum for colorscales VMAX = {} # VMAX[3.6] = 10. # VMAX[24] = 100. # VMAX[160] = 2000. # VMAX[500] = 2000. VMAX[100] = 10. VMAX[250] = 100. VMAX[500] = 2000. VMAX[1000] = 2000. # We will now show four sub-plots, each one for a different wavelength # for i, wav in enumerate([3.6, 24, 160, 500]): # for i, wav in enumerate([100, 250, 500, 1000]): # for i, wav in enumerate([4.5, 9.7, 24, 40, 70, 100, 250, 500, 1000]): for i, wav in enumerate([3.6, 8.0, 9.7, 24, 40, 100, 250, 500, 1000]): # ax = fig.add_subplot(3, 3, i + 1) ax = axarr[i / 3, i % 3] # Find the closest wavelength iwav = np.argmin(np.abs(wav - image.wav)) # Calculate the image width in arcseconds given the distance used above rmax = max(m.get_quantities().r_wall) w = np.degrees(rmax / image.distance) * 3600. # w = np.degrees((1.5 * pc) / image.distance) * 60. # Image in the unit of MJy/sr # Change it into erg/s/cm2/Hz/sr factor = 1e-23 * 1e6 # avoid zero in log val = image.val[:, :, iwav] * factor + 1e-30 # This is the command to show the image. The parameters vmin and vmax are # the min and max levels for the colorscale (remove for default values). im = ax.imshow(np.log10(val), vmin=-22, vmax=-12, cmap=plt.cm.jet, origin='lower', extent=[-w, w, -w, w], aspect=1) # Colorbar setting # create an axes on the right side of ax. The width of cax will be 5% # of ax and the padding between cax and ax will be fixed at 0.05 inch. if (i + 1) % 3 == 0: divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) cb = fig.colorbar(im, cax=cax) cb.solids.set_edgecolor("face") cb.ax.minorticks_on() cb.ax.set_ylabel( r'$\rm{log(I_{\nu})\,[erg\,s^{-2}\,cm^{-2}\,Hz^{-1}\,sr^{-1}]}$', fontsize=12) cb_obj = plt.getp(cb.ax.axes, 'yticklabels') plt.setp(cb_obj, fontsize=12) if (i + 1) == 7: # Finalize the plot ax.set_xlabel('RA Offset (arcsec)', fontsize=14) ax.set_ylabel('Dec Offset (arcsec)', fontsize=14) ax.tick_params(axis='both', which='major', labelsize=16) ax.set_adjustable('box-forced') ax.text(0.7, 0.88, str(wav) + r'$\rm{\,\mu m}$', fontsize=18, color='white', weight='bold', transform=ax.transAxes) fig.subplots_adjust(hspace=0, wspace=-0.2) # Adjust the spaces between the subplots # plt.tight_layout() fig.savefig(outdir + print_name + '_cube_plot.png', format='png', dpi=300, bbox_inches='tight') fig.clf()
def hyperion_sedcom(modellist, outdir, plotname, obs_data=None, labellist=None, lbol=False, legend=True, mag=1.5,\ obs_preset='sh', dstar=1, aper=[3.6, 4.5, 5.8, 8.0, 10, 20, 24, 70, 160, 250, 350, 500, 850]): """ obs_data: dictionary which obs_data['spec'] is spectrum and obs_data['phot'] is photometry obs_data['label'] = (wave, Fv, err) in um and Jy by default """ import numpy as np import os import matplotlib.pyplot as plt import astropy.constants as const from hyperion.model import ModelOutput from scipy.interpolate import interp1d from l_bol import l_bol import seaborn as sb # from seaborn import color_palette # from seaborn_color import seaborn_color # constant setup c = const.c.cgs.value pc = const.pc.cgs.value if labellist == None: if legend == True: print 'Model labels are not provided. Use their filename instead.' labellist = [] for i in range(0, len(modellist)): labellist.append(r'$\mathrm{'+os.path.splitext(os.path.basename(modellist[i]))[0]+'}$') # cm = seaborn_color('colorblind',len(modellist)) sb.set(style="white") cm = sb.color_palette('husl', len(modellist)) # create figure object fig = plt.figure(figsize=(8*mag,6*mag)) ax = fig.add_subplot(111) # sb.set_style('ticks') print 'plotting with aperture at ', aper, 'um' # if the obs_data is provided than plot the observation first. In this way, models won't be blocked by data if obs_data != None: if 'spec' in obs_data.keys(): (wave, fv, err) = obs_data['spec'] vfv = c/(wave*1e-4)*fv*1e-23 l_bol_obs = l_bol(wave, fv, dstar) if legend == True: ax.text(0.75,0.9,r'$\mathrm{L_{bol}= %5.2f L_{\odot}}$' % l_bol_obs,fontsize=mag*16,transform=ax.transAxes) # general plotting scheme if obs_preset == None: spec, = ax.plot(np.log10(wave),np.log10(vfv),'-',color='k',linewidth=1.5*mag, label=r'$\mathrm{observations}$') # plot spitzer, Herschel pacs and spire in different colors elif obs_preset == 'sh': # spitzer spitz, = ax.plot(np.log10(wave[wave < 50]),np.log10(vfv[wave < 50]),'-',color='b',linewidth=1*mag,\ label=r'$\mathrm{\it Spitzer}$') # herschel pacs, = ax.plot(np.log10(wave[(wave < 190.31) & (wave > 50)]),np.log10(vfv[(wave < 190.31) & (wave > 50)]),'-',\ color='Green',linewidth=1*mag, label=r'$\mathrm{{\it Herschel}-PACS}$') spire, = ax.plot(np.log10(wave[wave >= 190.31]),np.log10(vfv[wave >= 190.31]),'-',color='k',linewidth=1*mag,\ label=r'$\mathrm{{\it Herschel}-SPIRE}$') spec = [spitz, pacs, spire] if 'phot' in obs_data.keys(): (wave_p, fv_p, err_p) = obs_data['phot'] vfv_p = c/(wave_p*1e-4)*fv_p*1e-23 vfv_p_err = c/(wave_p*1e-4)*err_p*1e-23 phot, = ax.plot(np.log10(wave_p),np.log10(vfv_p),'s',mfc='DimGray',mec='k',markersize=8) ax.errorbar(np.log10(wave_p),np.log10(vfv_p),yerr=[np.log10(vfv_p)-np.log10(vfv_p-vfv_p_err), np.log10(vfv_p+vfv_p_err)-np.log10(vfv_p)],\ fmt='s',mfc='DimGray',mec='k',markersize=8) modplot = dict() for imod in range(0, len(modellist)): m = ModelOutput(modellist[imod]) # if not specified, distance of the star will be taken as 1 pc. if aper == None: sed_dum = m.get_sed(group=0, inclination=0, aperture=-1, distance=dstar * pc) modplot['mod'+str(imod+1)], = ax_sed.plot(np.log10(sed_dum.wav), np.log10(sed_dum.val), '-', color='GoldenRod', linewidth=1.5*mag) else: vfv_aper = np.empty_like(aper) for i in range(0, len(aper)): sed_dum = m.get_sed(group=i+1, inclination=0, aperture=-1, distance=dstar * pc) f = interp1d(sed_dum.wav, sed_dum.val) vfv_aper[i] = f(aper[i]) modplot['mod'+str(imod+1)], = ax.plot(np.log10(aper),np.log10(vfv_aper),'o',mfc='None',mec=cm[imod],markersize=12,\ markeredgewidth=3, label=labellist[imod], linestyle='-',color=cm[imod],linewidth=1.5*mag) # plot fine tune ax.set_xlabel(r'$\mathrm{log~\lambda~({\mu}m)}$',fontsize=mag*20) ax.set_ylabel(r'$\mathrm{log~\nu S_{\nu}~(erg/cm^{2}/s)}$',fontsize=mag*20) [ax.spines[axis].set_linewidth(1.5*mag) for axis in ['top','bottom','left','right']] ax.minorticks_on() ax.tick_params('both',labelsize=mag*18,width=1.5*mag,which='major',pad=15,length=5*mag) ax.tick_params('both',labelsize=mag*18,width=1.5*mag,which='minor',pad=15,length=2.5*mag) if obs_preset == 'sh': ax.set_ylim([-14,-7]) ax.set_xlim([0,3]) if legend == True: lg = ax.legend(loc='best',fontsize=14*mag,numpoints=1,framealpha=0.3) # Write out the plot fig.savefig(outdir+plotname+'.pdf',format='pdf',dpi=300,bbox_inches='tight') fig.clf()
def plot_results(cli): file = filename(cli, "plot") file += ".rtout" # # Read in the model: # model = ModelOutput(file) if(cli.mode == "images"): # # Extract the quantities # g = model.get_quantities() # # Get the wall positions: # ww = g.w_wall / pc zw = g.z_wall / pc pw = g.p_wall grid_Nw = len(ww) - 1 grid_Nz = len(zw) - 1 grid_Np = len(pw) - 1 # # Graphics: # fig = plt.figure() los = [0 for i in range(3)] los[0] = 'x' los[1] = 'y' los[2] = 'z' #Imaxp = [0 for i in range(4)] ##Imaxp[0] = 1e-4 #Imaxp[1] = 1e-5 #Imaxp[2] = 1e-7 #Imaxp[3] = 1e-8 for k in range(0, 3): if(cli.verbose): print("Group: ", k) image = model.get_image(distance=1*pc, units='MJy/sr', inclination=0, component='total', group=k) source_emit = model.get_image(distance=1*pc, units='MJy/sr', inclination=0, component='source_emit', group=k) dust_emit = model.get_image(distance=1*pc, units='MJy/sr', inclination=0, component='dust_emit' , group=k) source_scat = model.get_image(distance=1*pc, units='MJy/sr', inclination=0, component='source_scat', group=k) dust_scat = model.get_image(distance=1*pc, units='MJy/sr', inclination=0, component='dust_scat' , group=k) if(cli.verbose): print(" Data cube: ", image.val.shape) print(" Wavelengths =", image.wav) print(" Uncertainties =", image.unc) image_Nx=image.val.shape[0] image_Ny=image.val.shape[1] Nwavelength=image.val.shape[2] if(cli.verbose): print(" Image Nx =", image_Nx) print(" Image Ny =", image_Ny) print(" Nwavelength =", Nwavelength) for i in range(0, Nwavelength): if(cli.verbose): print(" Image #", i,":") print(" Wavelength =", image.wav[i]) Imin = np.min(image.val[:, :, i]) Imax = np.max(image.val[:, :, i]) # TODO: compute the mean value as well and use this for specifying the maximum value/color?! if(cli.verbose): print(" Intensity min =", Imin) print(" Intensity max =", Imax) #Imax=Imaxp[i] #ax = fig.add_subplot(2, 1, 2) ax = fig.add_subplot(1, 1, 1) if(image.wav[i] < 10.0): ax.imshow(source_scat.val[:, :, i] + dust_scat.val[:, :, i], vmin=Imin, vmax=Imax/10, cmap=plt.cm.gist_heat, origin='lower') else: ax.imshow(image.val[:, :, i], vmin=Imin, vmax=Imax/10, cmap=plt.cm.gist_heat, origin='lower') ax.set_xticks([0,100,200,300], minor=False) ax.set_yticks([0,100,200,300], minor=False) ax.set_xlabel('x (pixel)') ax.set_ylabel('y (pixel)') ax.set_title(str(image.wav[i]) + ' microns' + '\n' + los[k] + '-direction', y=0.88, x=0.5, color='white') #ax = fig.add_subplot(2, 1, 1) #ax.imshow([np.logspace(np.log10(Imin+1e-10),np.log10(Imax/10),100),np.logspace(np.log10(Imin+1e-10),np.log10(Imax/10),100)], vmin=Imin, vmax=Imax/10, cmap=plt.cm.gist_heat) #ax.set_xticks(np.logspace(np.log10(Imin+1e-10),np.log10(Imax/10),1), minor=False) ##ax.set_xticks(np.linspace(np.log10(Imin+1e-10),np.log10(Imax/10),10), minor=False) #ax.set_yticks([], minor=False) #ax.set_xlabel('flux (MJy/sr)') file = filename(cli, "plot") file += "_wavelength=" + str(image.wav[i]) + "micron_los=" + los[k] + ".png" fig.savefig(file, bbox_inches='tight') if(cli.verbose): print(" The image graphics was written to", file) plt.clf() elif(cli.mode == "sed"): # # Graphics: # fig = plt.figure() z_center = [0 for i in range(3)] z_center[0] = '2.5' z_center[1] = '5.0' z_center[2] = '7.5' for k in range(0, 3): if(cli.verbose): print("Group: ", k) sed = model.get_sed(distance=1*pc, inclination=0, aperture=-1, group=k) ax = fig.add_subplot(1, 1, 1) ax.loglog(sed.wav, sed.val) ax.set_xlabel(r'$\lambda$ [$\mu$m]') ax.set_ylabel(r'$\lambda F_\lambda$ [ergs/s/cm$^2$]') ax.set_xlim(0.01, 2000.0) #ax.set_ylim(2.e-16, 2.e-9) file = filename(cli, "plot") file += "_z=" + z_center[k] + ".png" fig.savefig(file) if(cli.verbose): print(" The sed graphics was written to", file) plt.clf() else: print("ERROR: The specified mode", mode, "is not available. Use 'images' or 'sed' only.")
def extract_hyperion(filename,indir=None,outdir=None,dstar=200.0,aperture=None, save=True,filter_func=False,plot_all=False,clean=False, exclude_wl=[],log=True,image=True,obj='BHR71', print_data_w_aper=False,mag=1.5): """ filename: The path to Hyperion output file indir: The path to the directory which contains observations data outdir: The path to the directory for storing extracted plots and ASCII files """ def l_bol(wl,fv,dstar): import numpy as np import astropy.constants as const # wavelength unit: um # Flux density unit: Jy # constants setup # c = const.c.cgs.value pc = const.pc.cgs.value PI = np.pi SL = const.L_sun.cgs.value # Convert the unit from Jy to erg s-1 cm-2 Hz-1 fv = np.array(fv)*1e-23 freq = c/(1e-4*np.array(wl)) diff_dum = freq[1:]-freq[0:-1] freq_interpol = np.hstack((freq[0:-1]+diff_dum/2.0,freq[0:-1]+diff_dum/2.0,freq[0],freq[-1])) freq_interpol = freq_interpol[np.argsort(freq_interpol)[::-1]] fv_interpol = np.empty(len(freq_interpol)) # calculate the histogram style of spectrum # for i in range(0,len(fv)): if i == 0: fv_interpol[i] = fv[i] else: fv_interpol[2*i-1] = fv[i-1] fv_interpol[2*i] = fv[i] fv_interpol[-1] = fv[-1] dv = freq_interpol[0:-1]-freq_interpol[1:] dv = np.delete(dv,np.where(dv==0)) fv = fv[np.argsort(freq)] freq = freq[np.argsort(freq)] return (np.trapz(fv,freq)*4.*PI*(dstar*pc)**2)/SL # function for properly calculating uncertainty of spectrophotometry value def unc_spectrophoto(wl, unc, trans): # adopting smiliar procedure as Trapezoidal rule # (b-a) * [ f(a) + f(b) ] / 2 # return ( np.sum( trans[:-1]**2 * unc[:-1]**2 * (wl[1:]-wl[:-1])**2 ) / np.trapz(trans, x=wl)**2 )**0.5 # to avoid X server error import matplotlib as mpl mpl.use('Agg') # import matplotlib.pyplot as plt import numpy as np import os from hyperion.model import ModelOutput, Model from scipy.interpolate import interp1d from hyperion.util.constants import pc, c, lsun, au from astropy.io import ascii import sys from phot_filter import phot_filter from get_obs import get_obs # Open the model m = ModelOutput(filename) # Read in the observation data and calculate the noise & variance if indir == None: indir = raw_input('Path to the observation data: ') if outdir == None: outdir = raw_input('Path for the output: ') # assign the file name from the input file print_name = os.path.splitext(os.path.basename(filename))[0] # use a canned function to extract observational data obs_data = get_obs(indir, obj=obj) # unit in um, Jy wl_tot, flux_tot, unc_tot = obs_data['spec'] flux_tot = flux_tot*1e-23 # convert unit from Jy to erg s-1 cm-2 Hz-1 unc_tot = unc_tot*1e-23 l_bol_obs = l_bol(wl_tot, flux_tot*1e23, dstar) wl_phot, flux_phot, flux_sig_phot = obs_data['phot'] flux_phot = flux_phot*1e-23 # convert unit from Jy to erg s-1 cm-2 Hz-1 flux_sig_phot = flux_sig_phot*1e-23 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, 850],\ '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, 24.5]} # 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) # '+1': the zeroth slice corresponds to infinite aperture # Create the plot fig = plt.figure(figsize=(8*mag,6*mag)) ax_sed = fig.add_subplot(1, 1, 1) # Plot the observed SED if not clean: color_seq = ['Green','Red','Black'] else: color_seq = ['DimGray','DimGray','DimGray'] # plot the observations # plot in log scale if log: pacs, = ax_sed.plot(np.log10(wl_tot[(wl_tot>40) & (wl_tot<190.31)]), np.log10(c/(wl_tot[(wl_tot>40) & (wl_tot<190.31)]*1e-4)*flux_tot[(wl_tot>40) & (wl_tot<190.31)]), '-',color=color_seq[0],linewidth=1.5*mag, alpha=0.7) spire, = ax_sed.plot(np.log10(wl_tot[wl_tot > 194]),np.log10(c/(wl_tot[wl_tot > 194]*1e-4)*flux_tot[wl_tot > 194]), '-',color=color_seq[1],linewidth=1.5*mag, alpha=0.7) irs, = ax_sed.plot(np.log10(wl_tot[wl_tot < 40]),np.log10(c/(wl_tot[wl_tot < 40]*1e-4)*flux_tot[wl_tot < 40]), '-',color=color_seq[2],linewidth=1.5*mag, alpha=0.7) photometry, = ax_sed.plot(np.log10(wl_phot),np.log10(c/(wl_phot*1e-4)*flux_phot),'s',mfc='DimGray',mec='k',markersize=8) # plot the observed photometry data ax_sed.errorbar(np.log10(wl_phot),np.log10(c/(wl_phot*1e-4)*flux_phot), yerr=[np.log10(c/(wl_phot*1e-4)*flux_phot)-np.log10(c/(wl_phot*1e-4)*(flux_phot-flux_sig_phot)), np.log10(c/(wl_phot*1e-4)*(flux_phot+flux_sig_phot))-np.log10(c/(wl_phot*1e-4)*flux_phot)], fmt='s',mfc='DimGray',mec='k',markersize=8) # plot in normal scale else: pacs, = ax_sed.plot(np.log10(wl_tot[(wl_tot>40) & (wl_tot<190.31)]), c/(wl_tot[(wl_tot>40) & (wl_tot<190.31)]*1e-4)*flux_tot[(wl_tot>40) & (wl_tot<190.31)], '-',color=color_seq[0],linewidth=1.5*mag, alpha=0.7) spire, = ax_sed.plot(np.log10(wl_tot[wl_tot > 194]),c/(wl_tot[wl_tot > 194]*1e-4)*flux_tot[wl_tot > 194], '-',color=color_seq[1],linewidth=1.5*mag, alpha=0.7) irs, = ax_sed.plot(np.log10(wl_tot[wl_tot < 40]),c/(wl_tot[wl_tot < 40]*1e-4)*flux_tot[wl_tot < 40], '-',color=color_seq[2],linewidth=1.5*mag, alpha=0.7) photometry, = ax_sed.plot(wl_phot,c/(wl_phot*1e-4)*flux_phot,'s',mfc='DimGray',mec='k',markersize=8) # plot the observed photometry data ax_sed.errorbar(np.log10(wl_phot),c/(wl_phot*1e-4)*flux_phot, yerr=[c/(wl_phot*1e-4)*flux_phot-c/(wl_phot*1e-4)*(flux_phot-flux_sig_phot), c/(wl_phot*1e-4)*(flux_phot+flux_sig_phot)-c/(wl_phot*1e-4)*flux_phot], fmt='s',mfc='DimGray',mec='k',markersize=8) # if keyword 'clean' is not set, print L_bol derived from observations at upper right corner. if not clean: ax_sed.text(0.75,0.9,r'$\rm{L_{bol}= %5.2f L_{\odot}}$' % l_bol_obs, fontsize=mag*16,transform=ax_sed.transAxes) # getting SED with infinite aperture sed_inf = m.get_sed(group=0, inclination=0, aperture=-1, distance=dstar*pc, uncertainties=True) # plot the simulated SED with infinite aperture if clean == False: sim, = ax_sed.plot(np.log10(sed_inf.wav), np.log10(sed_inf.val), '-', color='GoldenRod', linewidth=0.5*mag) ax_sed.fill_between(np.log10(sed_inf.wav), np.log10(sed_inf.val-sed_inf.unc), np.log10(sed_inf.val+sed_inf.unc),color='GoldenRod', alpha=0.5) ####################################### # get fluxes with different apertures # ####################################### # this is non-reduced wavelength array because this is for printing out fluxes at all channels specified by users flux_aper = np.zeros_like(wl_aper, dtype=float) unc_aper = np.zeros_like(wl_aper, dtype=float) a = np.zeros_like(wl_aper) + 1 color_list = plt.cm.jet(np.linspace(0, 1, len(wl_aper)+1)) for i in range(0, len(wl_aper)): # occasionally users might want not to report some wavelength channels if wl_aper[i] in exclude_wl: continue # getting simulated SED from Hyperion output. (have to match with the reduced index) sed_dum = m.get_sed(group=index_reduced[np.where(aper_reduced == aper[i])], inclination=0,aperture=-1,distance=dstar*pc, uncertainties=True) # plot the whole SED from this aperture (optional) if plot_all == True: ax_sed.plot(np.log10(sed_dum.wav), np.log10(sed_dum.val),'-', color=color_list[i]) ax_sed.fill_between(np.log10(sed_dum.wav), np.log10(sed_dum.val-sed_dum.unc), np.log10(sed_dum.val+sed_dum.unc),\ color=color_list[i], alpha=0.5) # Extracting spectrophotometry values from simulated SED # Not using the photometry filer function to extract spectrophotometry values # sort by wavelength first. sort_wl = np.argsort(sed_dum.wav) val_sort = sed_dum.val[sort_wl] unc_sort = sed_dum.unc[sort_wl] wav_sort = sed_dum.wav[sort_wl] # Before doing that, convert vSv to F_lambda flux_dum = val_sort / wav_sort unc_dum = unc_sort / wav_sort # If no using filter function to extract the spectrophotometry, # then use the spectral resolution. if filter_func == False: # use a rectangle function the average the simulated SED # apply the spectral resolution if (wl_aper[i] < 50.) & (wl_aper[i] >= 5): res = 60. elif wl_aper[i] < 5: res = 10. else: res = 1000. ind = np.where((wav_sort < wl_aper[i]*(1+1./res)) & (wav_sort > wl_aper[i]*(1-1./res))) if len(ind[0]) != 0: flux_aper[i] = np.mean(flux_dum[ind]) unc_aper[i] = np.mean(unc_dum[ind]) else: f = interp1d(wav_sort, flux_dum) f_unc = interp1d(wav_sort, unc_dum) flux_aper[i] = f(wl_aper[i]) unc_aper[i] = f_unc(wl_aper[i]) # Using photometry filter function to extract spectrophotometry values else: # apply the filter function # decide the filter name if wl_aper[i] == 70: fil_name = 'Herschel PACS 70um' elif wl_aper[i] == 100: fil_name = 'Herschel PACS 100um' elif wl_aper[i] == 160: fil_name = 'Herschel PACS 160um' elif wl_aper[i] == 250: fil_name = 'Herschel SPIRE 250um' elif wl_aper[i] == 350: fil_name = 'Herschel SPIRE 350um' elif wl_aper[i] == 500: fil_name = 'Herschel SPIRE 500um' elif wl_aper[i] == 3.6: fil_name = 'IRAC Channel 1' elif wl_aper[i] == 4.5: fil_name = 'IRAC Channel 2' elif wl_aper[i] == 5.8: fil_name = 'IRAC Channel 3' elif wl_aper[i] == 8.0: fil_name = 'IRAC Channel 4' elif wl_aper[i] == 24: fil_name = 'MIPS 24um' elif wl_aper[i] == 850: fil_name = 'SCUBA 850WB' else: fil_name = None if fil_name != None: filter_func = phot_filter(fil_name) # Simulated SED should have enough wavelength coverage for applying photometry filters. f = interp1d(wav_sort, flux_dum) f_unc = interp1d(wav_sort, unc_dum) flux_aper[i] = np.trapz(f(filter_func['wave']/1e4)*\ filter_func['transmission'],x=filter_func['wave']/1e4 )/\ np.trapz(filter_func['transmission'], x=filter_func['wave']/1e4) # fix a bug unc_aper[i] = unc_spectrophoto(filter_func['wave']/1e4, f_unc(filter_func['wave']/1e4), filter_func['transmission']) else: # use a rectangle function the average the simulated SED # apply the spectral resolution if (wl_aper[i] < 50.) & (wl_aper[i] >= 5): res = 60. elif wl_aper[i] < 5: res = 10. else: res = 1000. ind = np.where((wav_sort < wl_aper[i]*(1+1./res)) & (wav_sort > wl_aper[i]*(1-1./res))) if len(ind[0]) != 0: flux_aper[i] = np.mean(flux_dum[ind]) unc_aper[i] = np.mean(unc_dum[ind]) else: f = interp1d(wav_sort, flux_dum) f_unc = interp1d(wav_sort, unc_dum) flux_aper[i] = f(wl_aper[i]) unc_aper[i] = f_unc(wl_aper[i]) # temperory step: solve issue of uncertainty greater than the value for i in range(len(wl_aper)): if unc_aper[i] >= flux_aper[i]: unc_aper[i] = flux_aper[i] - 1e-20 ########################### # Observations Extraction # ########################### # perform the same procedure of flux extraction of aperture flux with observed spectra # wl_aper = np.array(wl_aper, dtype=float) obs_aper_wl = wl_aper[(wl_aper >= min(wl_tot)) & (wl_aper <= max(wl_tot))] obs_aper_flux = np.zeros_like(obs_aper_wl) obs_aper_unc = np.zeros_like(obs_aper_wl) # have change the simulation part to work in F_lambda for fliter convolution # flux_tot and unc_tot have units of erg/s/cm2/Hz. Need to convert it to F_lambda (erg/s/cm2/um) fnu2fl = c/(wl_tot*1e-4)/wl_tot # # wl_tot and flux_tot are already hstacked and sorted by wavelength for i in range(0, len(obs_aper_wl)): # sometime users want not report some wavelength channels if obs_aper_wl[i] in exclude_wl: continue if filter_func == False: # use a rectangle function the average the simulated SED # apply the spectral resolution if (obs_aper_wl[i] < 50.) & (obs_aper_wl[i] >= 5): res = 60. elif obs_aper_wl[i] < 5: res = 10. else: res = 1000. ind = np.where((wl_tot < obs_aper_wl[i]*(1+1./res)) & (wl_tot > obs_aper_wl[i]*(1-1./res))) if len(ind[0]) != 0: obs_aper_flux[i] = np.mean(fnu2fl[ind]*flux_tot[ind]) obs_aper_unc[i] = np.mean(fnu2fl[ind]*unc_tot[ind]) else: f = interp1d(wl_tot, fnu2fl*flux_tot) f_unc = interp1d(wl_tot, fnu2fl*unc_tot) obs_aper_flux[i] = f(obs_aper_wl[i]) obs_aper_unc[i] = f_unc(obs_aper_wl[i]) else: # apply the filter function # decide the filter name if obs_aper_wl[i] == 70: fil_name = 'Herschel PACS 70um' elif obs_aper_wl[i] == 100: fil_name = 'Herschel PACS 100um' elif obs_aper_wl[i] == 160: fil_name = 'Herschel PACS 160um' elif obs_aper_wl[i] == 250: fil_name = 'Herschel SPIRE 250um' elif obs_aper_wl[i] == 350: fil_name = 'Herschel SPIRE 350um' elif obs_aper_wl[i] == 500: fil_name = 'Herschel SPIRE 500um' elif obs_aper_wl[i] == 3.6: fil_name = 'IRAC Channel 1' elif obs_aper_wl[i] == 4.5: fil_name = 'IRAC Channel 2' elif obs_aper_wl[i] == 5.8: fil_name = 'IRAC Channel 3' elif obs_aper_wl[i] == 8.0: fil_name = 'IRAC Channel 4' elif obs_aper_wl[i] == 24: fil_name = 'MIPS 24um' elif obs_aper_wl[i] == 850: fil_name = 'SCUBA 850WB' # do not have SCUBA spectra else: fil_name = None if fil_name != None: filter_func = phot_filter(fil_name) # Observed SED needs to be trimmed before applying photometry filters filter_func = filter_func[(filter_func['wave']/1e4 >= min(wl_tot))*\ ((filter_func['wave']/1e4 >= 54.8)+(filter_func['wave']/1e4 <= 36.0853))*\ ((filter_func['wave']/1e4 <= 95.05)+(filter_func['wave']/1e4 >=103))*\ ((filter_func['wave']/1e4 <= 190.31)+(filter_func['wave']/1e4 >= 195))*\ (filter_func['wave']/1e4 <= max(wl_tot))] f = interp1d(wl_tot, fnu2fl*flux_tot) f_unc = interp1d(wl_tot, fnu2fl*unc_tot) obs_aper_flux[i] = np.trapz(f(filter_func['wave']/1e4)*filter_func['transmission'], x=filter_func['wave']/1e4)/\ np.trapz(filter_func['transmission'], x=filter_func['wave']/1e4) obs_aper_unc[i] = unc_spectrophoto(filter_func['wave']/1e4, f_unc(filter_func['wave']/1e4), filter_func['transmission']) else: # use a rectangle function the average the simulated SED # apply the spectral resolution if (obs_aper_wl[i] < 50.) & (obs_aper_wl[i] >= 5): res = 60. elif obs_aper_wl[i] < 5: res = 10. else: res = 1000. ind = np.where((wl_tot < obs_aper_wl[i]*(1+1./res)) & (wl_tot > obs_aper_wl[i]*(1-1./res))) if len(ind[0]) != 0: obs_aper_flux[i] = np.mean(fnu2fl[ind]*flux_tot[ind]) obs_aper_unc[i] = np.mean(fnu2fl[ind]*unc_tot[ind]) else: f = interp1d(wl_tot, fnu2fl*flux_tot) f_unc = interp1d(wl_tot, fnu2fl*unc_tot) obs_aper_flux[i] = f(obs_aper_wl[i]) obs_aper_unc[i] = f_unc(obs_aper_wl[i]) # plot the aperture-extracted spectrophotometry fluxes from observed spectra and simulations # in log-scale if log: aper_obs = ax_sed.errorbar(np.log10(obs_aper_wl), np.log10(obs_aper_flux * obs_aper_wl ),\ yerr=[np.log10(obs_aper_flux*obs_aper_wl)-np.log10(obs_aper_flux*obs_aper_wl-obs_aper_unc*obs_aper_wl), np.log10(obs_aper_flux*obs_aper_wl+obs_aper_unc*obs_aper_wl)-np.log10(obs_aper_flux*obs_aper_wl)],\ fmt='s', mec='None', mfc='r', markersize=10, linewidth=1.5, ecolor='Red', elinewidth=3, capthick=3, barsabove=True) aper = ax_sed.errorbar(np.log10(wl_aper),np.log10(flux_aper*wl_aper),\ yerr=[np.log10(flux_aper*wl_aper)-np.log10(flux_aper*wl_aper-unc_aper*wl_aper), np.log10(flux_aper*wl_aper+unc_aper*wl_aper)-np.log10(flux_aper*wl_aper)],\ fmt='o', mec='Blue', mfc='None', color='b',markersize=12, markeredgewidth=2.5, linewidth=1.7, ecolor='Blue', elinewidth=3, barsabove=True) ax_sed.set_ylim([-14,-7]) ax_sed.set_xlim([0,3.2]) # in normal scale (normal in y-axis) else: aper_obs = ax_sed.errorbar(np.log10(obs_aper_wl), obs_aper_flux*obs_aper_wl, yerr=obs_aper_unc*obs_aper_wl,\ fmt='s', mec='None', mfc='r', markersize=10, linewidth=1.5, ecolor='Red', elinewidth=3, capthick=3, barsabove=True) aper = ax_sed.errorbar(np.log10(wl_aper),flux_aper*wl_aper, yerr=unc_aper*wl_aper,\ fmt='o', mec='Blue', mfc='None', color='b',markersize=12, markeredgewidth=2.5, linewidth=1.7, ecolor='Blue', elinewidth=3, barsabove=True) ax_sed.set_xlim([0,3.2]) # calculate the bolometric luminosity of the aperture # print flux_aper l_bol_sim = l_bol(wl_aper, flux_aper*wl_aper/(c/np.array(wl_aper)*1e4)*1e23, dstar) print 'Bolometric luminosity of simulated spectrum: %5.2f lsun' % l_bol_sim # print out the sed into ascii file for reading in later if save == True: # unapertured SED foo = open(outdir+print_name+'_sed_inf.txt','w') foo.write('%12s \t %12s \t %12s \n' % ('wave','vSv','sigma_vSv')) for i in range(0, len(sed_inf.wav)): foo.write('%12g \t %12g \t %12g \n' % (sed_inf.wav[i], sed_inf.val[i], sed_inf.unc[i])) foo.close() # SED with convolution of aperture sizes foo = open(outdir+print_name+'_sed_w_aperture.txt','w') foo.write('%12s \t %12s \t %12s \n' % ('wave','vSv','sigma_vSv')) for i in range(0, len(wl_aper)): foo.write('%12g \t %12g \t %12g \n' % (wl_aper[i], flux_aper[i]*wl_aper[i], unc_aper[i]*wl_aper[i])) foo.close() # print out the aperture-convolved fluxex from observations if print_data_w_aper: foo = open(outdir+print_name+'_obs_w_aperture.txt','w') foo.write('%12s \t %12s \t %12s \n' % ('wave','Jy','sigma_Jy')) for i in range(0, len(obs_aper_wl)): foo.write('%12g \t %12g \t %12g \n' % (obs_aper_wl[i], obs_aper_flux[i]*obs_aper_wl[i]/(c/obs_aper_wl[i]*1e4)*1e23, obs_aper_unc[i]*obs_aper_wl[i]/(c/obs_aper_wl[i]*1e4)*1e23)) foo.close() # read the input central luminosity by reading in the source information from output file dum = Model() dum.use_sources(filename) L_cen = dum.sources[0].luminosity/lsun # legend lg_data = ax_sed.legend([irs, photometry, aper, aper_obs], [r'$\rm{observation}$', r'$\rm{photometry}$',r'$\rm{F_{aper,sim}}$',r'$\rm{F_{aper,obs}}$'], loc='upper left',fontsize=14*mag,numpoints=1,framealpha=0.3) if clean == False: lg_sim = ax_sed.legend([sim],[r'$\rm{L_{bol,sim}=%5.2f\,L_{\odot},\,L_{center}=%5.2f\,L_{\odot}}$' % (l_bol_sim, L_cen)], \ loc='lower right',fontsize=mag*16) plt.gca().add_artist(lg_data) # plot setting ax_sed.set_xlabel(r'$\rm{log\,\lambda\,[{\mu}m]}$',fontsize=mag*20) ax_sed.set_ylabel(r'$\rm{log\,\nu S_{\nu}\,[erg\,s^{-1}\,cm^{-2}]}$',fontsize=mag*20) [ax_sed.spines[axis].set_linewidth(1.5*mag) for axis in ['top','bottom','left','right']] ax_sed.minorticks_on() ax_sed.tick_params('both',labelsize=mag*18,width=1.5*mag,which='major',pad=15,length=5*mag) ax_sed.tick_params('both',labelsize=mag*18,width=1.5*mag,which='minor',pad=15,length=2.5*mag) # fix the tick label font ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',size=mag*18) for label in ax_sed.get_xticklabels(): label.set_fontproperties(ticks_font) for label in ax_sed.get_yticklabels(): label.set_fontproperties(ticks_font) # Write out the plot fig.savefig(outdir+print_name+'_sed.pdf',format='pdf',dpi=300,bbox_inches='tight') fig.clf() # option for suppress image plotting (for speed) if image: # Package for matching the colorbar from mpl_toolkits.axes_grid1 import make_axes_locatable, ImageGrid # Users may change the unit: mJy, Jy, MJy/sr, ergs/cm^2/s, ergs/cm^2/s/Hz # !!! image = m.get_image(group=len(aper_reduced)+1, inclination=0, distance=dstar*pc, units='MJy/sr') # Open figure and create axes fig = plt.figure(figsize=(12,12)) grid = ImageGrid(fig, 111,nrows_ncols=(3,3),direction='row', add_all=True,label_mode='1',share_all=True, cbar_location='right',cbar_mode='single', cbar_size='3%',cbar_pad=0) for i, wav in enumerate([3.6, 8.0, 9.7, 24, 40, 100, 250, 500, 1000]): ax = grid[i] # Find the closest wavelength iwav = np.argmin(np.abs(wav - image.wav)) # Calculate the image width in arcseconds given the distance used above # get the max radius rmax = max(m.get_quantities().r_wall) w = np.degrees(rmax / image.distance) * 3600. # Image in the unit of MJy/sr # Change it into erg/s/cm2/Hz/sr factor = 1e-23*1e6 # avoid zero in log # flip the image, because the setup of inclination is upside down val = image.val[::-1, :, iwav] * factor + 1e-30 # This is the command to show the image. The parameters vmin and vmax are # the min and max levels for the colorscale (remove for default values). cmap = plt.cm.CMRmap im = ax.imshow(np.log10(val), vmin= -22, vmax= -12, cmap=cmap, origin='lower', extent=[-w, w, -w, w], aspect=1) ax.set_xlabel(r'$\rm{RA\,Offset\,[arcsec]}$', fontsize=14) ax.set_ylabel(r'$\rm{Dec\,Offset\,[arcsec]}$', fontsize=14) # fix the tick label font ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',size=14) for label in ax.get_xticklabels(): label.set_fontproperties(ticks_font) for label in ax.get_yticklabels(): label.set_fontproperties(ticks_font) # Colorbar setting cb = ax.cax.colorbar(im) cb.solids.set_edgecolor('face') cb.ax.minorticks_on() cb.ax.set_ylabel(r'$\rm{log(I_{\nu})\,[erg\,s^{-1}\,cm^{-2}\,Hz^{-1}\,sr^{-1}]}$',fontsize=18) cb_obj = plt.getp(cb.ax.axes, 'yticklabels') plt.setp(cb_obj,fontsize=18) ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',size=18) for label in cb.ax.get_yticklabels(): label.set_fontproperties(ticks_font) ax.tick_params(axis='both', which='major', labelsize=16) ax.text(0.7,0.88,str(wav) + r'$\rm{\,\mu m}$',fontsize=16,color='white', transform=ax.transAxes) fig.savefig(outdir+print_name+'_image_gridplot.pdf', format='pdf', dpi=300, bbox_inches='tight') fig.clf()
import matplotlib.pyplot as plt from hyperion.model import ModelOutput from hyperion.util.constants import pc mo = ModelOutput('class1_example.rtout') sed = mo.get_sed(aperture=-1, distance=140. * pc) image = mo.get_image(inclination=0,distance=300*pc,units='Jy') fig = plt.figure(figsize=(5, 4)) ax = fig.add_subplot(1, 1, 1) ax.loglog(sed.wav, sed.val.transpose(), color='black') ax.set_xlim(0.03, 2000.) ax.set_ylim(2.e-15, 1e-8) ax.set_xlabel(r'$\lambda$ [$\mu$m]') ax.set_ylabel(r'$\lambda F_\lambda$ [ergs/cm$^2/s$]') #ax2 = fig_add_subplot(1,1,2) #ax.imshow(image,origin='lower') fig.savefig('class1_example_sed.png', bbox_inches='tight')
metallicity_logzsol = [] gal_count = [] filter_list = [] pd_list = glob.glob(pd_dir+'/*.rtout.sed') snap_num = int(pd_list[0].split('snap')[2].split('.')[0]) print('loading galaxy list') galaxy_list = [] for i in pd_list: galaxy_list.append(int(i.split('.')[2].split('galaxy')[1])) for galaxy in tqdm.tqdm(galaxy_list): m = ModelOutput(pd_dir+'/snap'+str(snap_num)+'.galaxy'+str(galaxy)+'.rtout.sed') ds = yt.load(snaps_dir+'/galaxy_'+str(galaxy)+'.hdf5', 'r') wave, flx = m.get_sed(inclination=0, aperture=-1) gal_count.append(galaxy) #get mock photometry wave = np.asarray(wave)*u.micron if obs_frame: wav = wave[::-1].to(u.AA)*(1 + float(z)) else: wav = wave[::-1].to(u.AA) flux = np.asarray(flx)[::-1]*u.erg/u.s if float(z) == 0.0: dl = (10*u.pc).to(u.cm) else: dl = Planck15.luminosity_distance(float(z)).to('cm') flux /= (4.*3.14*dl**2.)
plt.rcParams['axes.titlesize'] = 20 plt.rcParams['font.size'] = 12 plt.rcParams['lines.linewidth'] = 2.0 plt.rcParams['lines.markersize'] = 8 plt.rcParams['legend.fontsize'] = 10 #### Read in AA Tau Model ####### #this model was computed by Hyperion using the AATau_example.py script, #which depends on the AATau_example.rtin and kt04000g+3.5z-2.0.ascii files AATau_mo = ModelOutput('Hyperion/AATau_example.rtout') #### plot the AA Tau SED w/ mid-IR fluxes for comparison #### #start by pulling in the SED info AATau_sed = AATau_mo.get_sed( aperture=-1, distance=137. * pc) #<--- using distance estimate corresponding to Gaia DR2 parallax #now define the number of inclinations we want to plot, and the color-map we want to use for them inclinations_to_use = [0, 2, 4, 6, 8, 10, 12, 14, 15, 16, 17, 18] number_of_inclinations_to_use = len(inclinations_to_use) cmap = plt.get_cmap('RdBu') colors = [cmap(i) for i in np.linspace(0, 1, number_of_inclinations_to_use)] #now actually make plot of the SEDs fig = plt.figure(figsize=(5, 4)) ax = fig.add_subplot(1, 1, 1) #for i in range(AATau_sed.val.shape[0]): for i in range(number_of_inclinations_to_use): #print(i, inclinations_to_use[i]) ax.loglog(AATau_sed.wav,
import matplotlib.pyplot as plt from hyperion.model import ModelOutput from hyperion.util.constants import pc mo = ModelOutput('class1_example.rtout') sed = mo.get_sed(aperture=-1, distance=140. * pc) fig = plt.figure(figsize=(5, 4)) ax = fig.add_subplot(1, 1, 1) ax.loglog(sed.wav, sed.val.transpose(), color='black') ax.set_xlim(0.03, 2000.) ax.set_ylim(2.e-15, 1e-8) ax.set_xlabel(r'$\lambda$ [$\mu$m]') ax.set_ylabel(r'$\lambda F_\lambda$ [ergs/cm$^2/s$]') fig.savefig('class1_example_sed.png', bbox_inches='tight')
Source_Distance = 268 * pc OutPutFiles = ["Model_FourShells_EvenMass.rtout", "Model_FourShells_UnEvenMass.rtout", "Model_InnerShell_Only.rtout", "Model_OuterShell_Only_K2010.rtout", "Model_OuterShell_Only_M2010.rtout", "Model_ShellThree_Only.rtout", "Model_ShellTwo_Only.rtout"] #RT output files #Getting Instrument Filters for Filter Convolution of the SED Filter_Library = pyphot.get_library(fname="Ampere_FiterProfile_Library.hdf5") #Filter names of the photometric points in my SED as given in the Ampere Filter porifles library. Filter_Names = np.array(['GAIADR2_Gbp', 'GAIADR2_G', 'GAIADR2_Grp', '2MASS_J', '2MASS_H', '2MASS_Ks', 'COBE_DIRBE_1.25', 'COBE_DIRBE_2.2', 'COBE_DIRBE_3.5', 'COBE_DIRBE_4.9', 'WISE_RSR_W3', 'WISE_RSR_W4', 'AKARI_S9W', 'AKARI_L18W', 'AKARI_FIS_N60', 'AKARI_FIS_WIDES', 'AKARI_FIS_WIDEL', 'IRAS_12', 'IRAS_25', 'IRAS_60', 'IRAS_100', 'HERSCHEL_PACS_BLUE', 'HERSCHEL_PACS_RED', 'HERSCHEL_SPIRE_PSW', 'HERSCHEL_SPIRE_PMW', 'HERSCHEL_SPIRE_PLW', 'JCMT_SCUBA2_450', 'JCMT_SCUBA2_850']) for filename in OutPutFiles: model = ModelOutput(filename) sed = model.get_sed(group=0, inclination='all', aperture=-1, distance=Source_Distance, units='Jy') #print(sed.wav) #print(sed.val) RT_SED_wavelengths = sed.wav #sed.wav = list of wavelengths created based on the limits (100, 0.3, 1200.) given during SED creation in RT modelling stage. Pre Convolution with Filters RT_SED_Fluxes = sed.val[0] #Fluxes of the SED derived during RT modelling. Pre Convolution with Filters #[0] - Hyperion has gives a list of arrays instead of an array. So we need to pick the zeroth element array even if the rest are empty. #Extracting the correct filters from the filt.library Filters = Filter_Library.load_filters(Filter_Names, interp=True, lamb=RT_SED_wavelengths*pyphot.unit['micron']) #pyphot.unit['micron'] tells pyphot that the wavlengths are in micron units. #Convolving with Filter Profiles filter_info, Convolved_Model_SED_Fluxes = pyphot.extractPhotometry(RT_SED_wavelengths, RT_SED_Fluxes, Filters, Fnu=True, absFlux=False)#, progress=False) #filter_info saves info about the filt. profiles. SED flux units = Jy Conv_SED_Wavelengths = np.array([a.magnitude for a in filter_info]) #Extracting the convolved SED wavelengths from the filter_info. Units=micron
import matplotlib.pyplot as plt from hyperion.model import ModelOutput from hyperion.util.constants import pc m = ModelOutput("class2_sed.rtout") fig = plt.figure() ax = fig.add_subplot(1, 1, 1) # Total SED wav, nufnu = m.get_sed(inclination=0, aperture=-1, distance=300 * pc) ax.loglog(wav, nufnu, color="black", lw=3, alpha=0.5) # Direct stellar photons wav, nufnu = m.get_sed(inclination=0, aperture=-1, distance=300 * pc, component="source_emit") ax.loglog(wav, nufnu, color="blue") # Scattered stellar photons wav, nufnu = m.get_sed(inclination=0, aperture=-1, distance=300 * pc, component="source_scat") ax.loglog(wav, nufnu, color="teal") # Direct dust photons wav, nufnu = m.get_sed(inclination=0, aperture=-1, distance=300 * pc, component="dust_emit") ax.loglog(wav, nufnu, color="red") # Scattered dust photons wav, nufnu = m.get_sed(inclination=0, aperture=-1, distance=300 * pc, component="dust_scat") ax.loglog(wav, nufnu, color="orange")
angles=np.arccos(np.linspace(0,1.,20))*180./np.pi inclinations=angles[::-1] d = SphericalDust() d.read('d03_5.5_3.0_A.hdf5') chi = d.optical_properties.chi chi = chi[::-1] wav = d.optical_properties.wav wav = wav[::-1] Chi = interp1d(wav,chi,kind='linear') sorted_grid = pickle.load(open(folder[0]+name[0]+"_"+target+".grid.dat",'r')) best_model_fname = folder[0]+sorted_grid['name'][0]+'.rtout' best_model = ModelOutput(fname) inc = int(np.argwhere(inclinations==sorted_grid['inc'][0])) sed = best_model.get_sed(aperture=-1, inclination=inc, distance=dist,units='Jy') N = len(sed.wav) vec = np.zeros(N,len(target_list)+1) vec[:,0] = sed.wav for i in range(len(target_list)): target = target_list[i] sorted_grid = pickle.load(open(folder[0]+name[0]+"_"+target+".grid.dat",'r')) best_model_fname = folder[0]+sorted_grid['name'][0]+'.rtout' best_model = ModelOutput(fname) extinction = sorted_grid['ext'][0] # get inclination inc = int(np.argwhere(inclinations==sorted_grid['inc'][0])) # get sed for best fit
from hyperion.model import ModelOutput from hyperion.util.constants import pc # Open the model - we specify the name without the .rtout extension m = ModelOutput('test_disc.rtout') # Create the plot fig = plt.figure() ax = fig.add_subplot(1, 1, 1) # Extract the SED for the smallest inclination and largest aperture, and # scale to 300pc. In Python, negative indices can be used for lists and # arrays, and indicate the position from the end. So to get the SED in the # largest aperture, we set aperture=-1. wav, nufnu = m.get_sed(inclination=0, aperture=-1, distance=300 * pc) # Plot the SED. The loglog command is similar to plot, but automatically # sets the x and y axes to be on a log scale. ax.loglog(wav, nufnu) # Add some axis labels (we are using LaTeX here) ax.set_xlabel(r'$\lambda$ [$\mu$m]') ax.set_ylabel(r'$\lambda F_\lambda$ [ergs/s/cm$^2$]') # Set view limits ax.set_xlim(0.1, 5000.) ax.set_ylim(1.e-15, 2.e-10) # Write out the plot fig.savefig('sed.png')
name = grid['name'][i] fname = folder[0]+name+'.rtout' print fname mo = ModelOutput(fname) # load extinction extinction = grid['ext'][i] #print "extinction = ",extinction # load inclination incs=angles[::-1] inc = int(np.argwhere(incs==grid['inc'][i])) #print inc # get the sed sed = mo.get_sed(aperture=-1, inclination=inc, distance=distance(target),uncertainties=True) #print name #print sed.unc/sed.val #plt.plot(sed.wav,sed.unc/sed.val) #plt.show() # calculate optical depth tau_ext1 = Chi(sed.wav)/Chi(0.550)/1.086 #print "sed.wav = ",sed.wav #print "tau_ext1 = ",tau_ext1 tau = tau_ext1*extinction #print "tau,",tau # calculate extinction for all inclinations ext = np.array(np.exp(-tau)) #print "exp(tau):",ext