def dump_data(pf,model): ad = pf.all_data() particle_fh2 = ad["gasfh2"] particle_fh1 = np.ones(len(particle_fh2))-particle_fh2 particle_gas_mass = ad["gasmasses"] particle_star_mass = ad["starmasses"] particle_star_metallicity = ad["starmetals"] particle_stellar_formation_time = ad["starformationtime"] particle_sfr = ad['gassfr'].in_units('Msun/yr') #these are in try/excepts in case we're not dealing with gadget and yt 3.x try: grid_gas_mass = ad["gassmoothedmasses"] except: grid_gas_mass = -1 try: grid_gas_metallicity = ad["gassmoothedmetals"] except: grid_gas_metallicity = -1 try: grid_star_mass = ad["starsmoothedmasses"] except: grid_star_mass = -1 #get tdust m = ModelOutput(model.outputfile+'.sed') oct = m.get_quantities() tdust_pf = oct.to_yt() tdust_ad = tdust_pf.all_data() tdust = tdust_ad[ ('gas', 'temperature')] try: outfile = cfg.model.PD_output_dir+"grid_physical_properties."+cfg.model.snapnum_str+'_galaxy'+cfg.model.galaxy_num_str+".npz" except: outfile = cfg.model.PD_output_dir+"grid_physical_properties."+cfg.model.snapnum_str+".npz" np.savez(outfile,particle_fh2=particle_fh2,particle_fh1 = particle_fh1,particle_gas_mass = particle_gas_mass,particle_star_mass = particle_star_mass,particle_star_metallicity = particle_star_metallicity,particle_stellar_formation_time = particle_stellar_formation_time,grid_gas_metallicity = grid_gas_metallicity,grid_gas_mass = grid_gas_mass,grid_star_mass = grid_star_mass,particle_sfr = particle_sfr,tdust = tdust)
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 export_to_fits(cli): # # Read in the model: # file = filename(cli, "plot") file += ".rtout" model = ModelOutput(file) # # Write fits file: # if(cli.mode == "images"): los = [0 for i in range(3)] los[0] = 'x' los[1] = 'y' los[2] = 'z' for k in range(0, 3): image = model.get_image(distance=1*pc, units='MJy/sr', inclination=0, component='total', group=k) Nwavelength=image.val.shape[2] for i in range(0, Nwavelength): file = filename(cli, "fits") file += "_wavelength=" + str(image.wav[i]) + "micron_los=" + los[k] + ".fits" fits.writeto(file, image.val[:, :, i], clobber=True) if(cli.verbose): print(" The fits file was written to", file) else: print("ERROR: The specified mode", mode, "is not available. Use 'images' only.")
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 get_image(filename, dist): try: m = ModelOutput(filename) return m.get_image(inclination='all', distance=luminosity_distance, units='Jy') except (OSError, ValueError) as e: print("OS Error in reading in: " + filename) pass
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_example(self): import numpy as np from hyperion.model import ModelOutput from hyperion.util.constants import pc from fluxcompensator.cube import * from fluxcompensator.psf import * from fluxcompensator.utils.resolution import * # read in from HYPERION m = ModelOutput( os.path.join(os.path.dirname(__file__), 'hyperion_output.rtout')) array = m.get_image(group=0, inclination=0, distance=300 * pc, units='ergs/cm^2/s') # initial FluxCompensator array c = SyntheticCube(input_array=array, unit_out='ergs/cm^2/s', name='test_cube') # dered with provided extinction law ext = c.extinction(A_v=20.) # change resolution to 10-times of the initial zoom = ext.change_resolution(new_resolution=10 * ext.resolution['arcsec'], grid_plot=True) import fluxcompensator.database.missions as PSFs # call object from the psf database psf_object = getattr(PSFs, 'PACS1_PSF') # convolve with PSF psf = zoom.convolve_psf(psf_object) import fluxcompensator.database.missions as filters # call object from the filter database filter_input = getattr(filters, 'PACS1_FILTER') # convolve with filter filtered = psf.convolve_filter(filter_input, plot_rebin=None, plot_rebin_dpi=None) # add noise noise = filtered.add_noise(mu_noise=0, sigma_noise=5e-15, diagnostics=None)
def __init__(self, rtout, velfile, cs, age, omega, rmin=0, mmw=2.37, g2d=100, truncate=None, debug=False, load_full=True, fix_tsc=True, hybrid_tsc=False, interpolate=False, TSC_dir='', tsc_outdir=''): self.rtout = rtout self.velfile = velfile if load_full: self.hyperion = ModelOutput(rtout) self.hy_grid = self.hyperion.get_quantities() self.rmin = rmin * 1e2 # rmin defined in LIME, which use SI unit self.mmw = mmw self.g2d = g2d self.cs = cs # in km/s self.age = age # in year # YLY update - add omega self.omega = omega self.r_inf = self.cs * 1e5 * self.age * yr # in cm # option to truncate the sphere to be a cylinder # the value is given in au to specify the radius of the truncated cylinder viewed from the observer self.truncate = truncate # debug option: print out every call to getDensity, getVelocity and getAbundance self.debug = debug # option to use simple Trapezoid rule average for getting density, temperature, and velocity self.interpolate = interpolate self.tsc2d = getTSC(age, cs, omega, velfile=velfile, TSC_dir=TSC_dir, outdir=tsc_outdir, outname='tsc_regrid')
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 extract(model): # Extract model name model_name = os.path.basename(model).replace('.rtout', '').replace('external_', '') m = ModelOutput(model) wav, flux = m.get_image(group=0, units='MJy/sr', distance=1000. * kpc) # distance should not matter as long as it is large flux = flux[0, :, :, :] # Convolve with filters flux_conv = np.zeros((len(filters), flux.shape[0], flux.shape[1])) for i, filtname in enumerate(filters): transmission = rebin_filter(filtname, c / (wav * 1.e-4)) flux_conv[i, :, :] = np.sum(transmission[np.newaxis, np.newaxis:] * flux, axis=2) pyfits.writeto('models/external/external_%s.fits' % model_name, flux, clobber=True) pyfits.writeto('models/external/external_%s_conv.fits' % model_name, flux_conv, clobber=True)
def setup_method(self, method): import numpy as np from hyperion.model import ModelOutput from hyperion.util.constants import kpc from fluxcompensator.cube import * # read in from HYPERION m = ModelOutput( os.path.join(os.path.dirname(__file__), 'hyperion_output.rtout')) array = m.get_image(group=0, inclination=0, distance=10 * kpc, units='ergs/cm^2/s') # initial FluxCompensator array self.FC_object = SyntheticCube(input_array=array, unit_out='ergs/cm^2/s', name='test_cube')
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')
def getRadialDensity(rtout, angle, plotdir): """ """ import numpy as np from hyperion.model import ModelOutput m = ModelOutput(rtout) q = m.get_quantities() r_wall = q.r_wall; theta_wall = q.t_wall; phi_wall = q.p_wall # get the cell coordinates rc = r_wall[0:len(r_wall)-1] + 0.5*(r_wall[1:len(r_wall)]-r_wall[0:len(r_wall)-1]) thetac = theta_wall[0:len(theta_wall)-1] + \ 0.5*(theta_wall[1:len(theta_wall)]-theta_wall[0:len(theta_wall)-1]) phic = phi_wall[0:len(phi_wall)-1] + \ 0.5*(phi_wall[1:len(phi_wall)]-phi_wall[0:len(phi_wall)-1]) # rho = q['density'].array[0] # find the closest angle in the thetac grid ind = np.argsort(abs(thetac-angle*np.pi/180.))[0] return rc, rho[0,ind,:]
def load_data(self, key, file_name=None, source=None, incl=None, angle=None, dtype=None): """Load data for key. Parameters: key: data to load. filename: file to open. source: source object. incl: inclination index. angle: inclination angle (model config must be pre-loaded) dtype: data type. """ if key == 'model': assert os.path.isfile(file_name) self.data[key] = ModelOutput(file_name) elif file_name and dtype: assert os.path.isfile(file_name) self.data[key] = load_data_by_type(file_name, dtype.lower(), REGISTERED_CLASSES) elif key == 'sed': assert incl is not None or (angle is not None and \ self.config is not None) wlg, F = self.data['model'].get_sed( group=0, distance=source.distance.cgs.value, inclination=incl, units='Jy') data = np.array(zip(wlg, F[0]), dtype=[('wlg', float), ('F', float)]) self.data[key] = SED(data=data, units={ 'wlg': 1. * u.micron, 'F': 1. * u.Jy }) else: raise NotImplementedError
name = ['model'] 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]))
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}_images.rtout'.format(tau=tau) m = ModelOutput(input_file) for iincl, theta in enumerate([0, 30, 60, 90, 120, 150, 180]): image = m.get_image(inclination=iincl, units='MJy/sr', distance=10. * kpc) for iwav, wav in enumerate([0.165, 0.570, 21.3, 161.6]): output_file = 'images/bm1_slab_effgrain_tau_{tau:06.2f}_theta_{theta:03d}_wave_{wav:07.3f}.fits'.format(tau=tau, theta=theta, wav=wav) fits.writeto(output_file, image.val[:, :, iwav], clobber=True)
import numpy as np from hyperion.model import ModelOutput from hyperion.util.constants import au, lsun RES = 256 mo = ModelOutput('bm2_eff_vor_temperature.rtout') g = mo.get_quantities() from scipy.spatial import cKDTree sites = np.array([g.x, g.y, g.z]).transpose() tree = cKDTree(sites) ymin, ymax = 0 * au, 60 * au zmin, zmax = 0 * au, 60 * au y = np.linspace(ymin, ymax, RES) z = np.linspace(zmin, zmax, RES) Y, Z = np.meshgrid(y, z) YR = Y.ravel() ZR = Z.ravel() for x_cut in [10 * au, 26.666667 * au]: XR = np.ones(YR.shape) * x_cut map_sites = np.array([XR, YR, ZR]).transpose()
dust_mass_Msun = [] sfr100 = [] 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:
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')
import pyfits from hyperion.model import ModelOutput from hyperion.util.constants import pc # Open the model - we specify the name without the .rtout extension m = ModelOutput('tutorial_model.rtout') # 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 wav, nufnu = m.get_image(group=1, inclination=0, distance=300 * pc) # The image extracted above is a 3D array. We can write it out to FITS. # We need to swap some of the directions around so as to be able to use # the ds9 slider to change the wavelength of the image. pyfits.writeto('image_cube.fits', nufnu.swapaxes(0, 2).swapaxes(1, 2), \ clobber=True) # We can also just output one of the wavelengths pyfits.writeto('image_slice.fits', nufnu[:, :, 0], clobber=True)
matplotlib.use('Agg') import numpy as np from astropy.io import fits from hyperion.model import ModelOutput 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)
type=float, help='A single wavelength in microns, if producing a monochromatic image.') parser.add_argument('-d', '--dat', action='store_true', help='If enabled, saves a ".dat" file with image data.') parser.add_argument('--vmin', type=float, help='Minimum of colorbar scale, in units of ergs/s.') parser.add_argument('--vmax', type=float, help='Maximum of colorbar scale, in units of ergs/s.') args = parser.parse_args() m = ModelOutput(pathch(args.infile)) if args.outfile is None: args.outfile = os.path.dirname(args.infile) # 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(units='ergs/s') # Open figure and create axes fig = plt.figure() ax = fig.add_subplot(111) # Calculate the image width in kpc w = image.x_max * u.cm w = w.to(u.kpc)
filename = '/Users/yaolun/bhr71/hyperion/cycle9/model34.rtout' outdir = '/Users/yaolun/test/' dist = 178. wave = 500. from hyperion.model import ModelOutput import astropy.constants as const import numpy as np import matplotlib.pyplot as plt from matplotlib import font_manager from mpl_toolkits.axes_grid1 import make_axes_locatable # constant setup pc = const.pc.cgs.value m = ModelOutput(filename) image = m.get_image(group=22, inclination=0, distance=dist * pc, units='MJy/sr') # Find the closest wavelength iwav = np.argmin(np.abs(wave - 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
Filter_Library = pyphot.get_library(fname="Ampere_FiterProfile_Library.hdf5") #Getting Instrument Filters for Filter Convolution of the SED #Filter names of the image wavelengths as given in the Ampere Filter porifles library. #'HERSCHEL_PACS_BLUE', 'HERSCHEL_PACS_RED', 'JCMT_SCUBA2_450', 'JCMT_SCUBA2_850' #Needed for Beam Conv model_max_envelope_size = 80 #Values used in RT modelling model_arcsec_size = model_max_envelope_size * 3 #Values used in RT modelling model_pix_size = 400 #Values used in RT modelling - (400 x 400 pixels) model_pix_arcsec = model_arcsec_size / model_pix_size #Size of each pixel in model image in arcsecs for filename in OutPutFiles: model = ModelOutput(filename) wavelength_group = np.array([1, 2, 3, 4]) #wavelength group in data cube to exract the image at the wanted wavelength. Groups (in the order written out in RT modelling code) =>> 0 - SED (ignore here as we need the images) // 1 - PACS 70; 2 - PACS 160; 3 - SCUBA2 450; 4 - SCUBA2 850 for group_val in wavelength_group: #print(group_val) #Applying Filer convolution to the Model image at each wavelength Filter_Name, Filter_ConvImage = Image_FilterConvolve(model, Source_Distance, Filter_Library, group_val) #Creating .fits files of the filter convolved image at each wavelength hdu = fits.PrimaryHDU(Filter_ConvImage) hdulist = fits.HDUList([hdu]) hdulist[0].header['Filter'] = Filter_Name[0] hdulist[0].header['BUNIT'] = "Jy"
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,
import os import numpy as np import matplotlib.pyplot as plt from hyperion.model import ModelOutput from hyperion.util.constants import pc # Create output directory if it does not already exist if not os.path.exists('frames'): os.mkdir('frames') # Open model m = ModelOutput('flyaround_cube.rtout') # Read image from model image = m.get_image(distance=300 * pc, units='MJy/sr') # image.val is now an array with four dimensions (n_view, n_y, n_x, n_wav) for iview in range(image.val.shape[0]): # Open figure and create axes fig = plt.figure(figsize=(3, 3)) ax = fig.add_subplot(1, 1, 1) # This is the command to show the image. The parameters vmin and vmax are # the min and max levels for the grayscale (remove for default values). # The colormap is set here to be a heat map. Other possible heat maps # include plt.cm.gray (grayscale), plt.cm.gist_yarg (inverted grayscale), # plt.cm.jet (default, colorful). The np.sqrt() is used to plot the
source_lam_downsampled[i] = source_lam[idx].value 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
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')
import numpy as np import matplotlib as mpl mpl.use('Agg') import matplotlib.pyplot as plt from hyperion.model import ModelOutput from hyperion.util.constants import pc # Create output directory if it does not already exist if not os.path.exists('frames'): os.mkdir('frames') # Open model m = ModelOutput('tutorial_model.rtout') # Read image from model wav, nufnu = m.get_image(group=2, distance=300 * pc) # nufnu is now an array with four dimensions (n_view, n_wav, n_y, n_x) # Fix the wavelength to the first one and cycle through viewing angles iwav = 0 print "Wavelength is %g microns" % wav[iwav] for iview in range(nufnu.shape[0]): # Open figure and create axes fig = plt.figure() ax = fig.add_subplot(1, 1, 1)
def convolve(image_file, filterfilenames, filter_data): # Load the model output object m = ModelOutput(image_file) # Get the image image = m.get_image(units='ergs/s') # Get image bounds for correct scaling w = image.x_max * u.cm w = w.to(u.kpc) # This is where the convolved images will go image_data = [] # List the filters that shouldn't be used in convolution skip_conv = ['arbitrary.filter', 'pdfilters.dat'] # Loop through the filters and match wavelengths to those in the image for i in range(len(filterfilenames)): # Skip "arbitrary.filter" if it is selected if filterfilenames[i] in skip_conv: print(" Skipping convolution of default filter") continue print("\n Convolving filter {}...".format(filterfilenames[i])) wavs = filter_data[i][:, 0] # Figure out which indices of the image wavelengths correspond to # this filter indices = [] for wav in wavs: diffs = np.abs(image.wav - wav) # Make sure the closest wavelength is *really* close --- there # could be rounding errors, but we don't want to accidentally grab # the wrong wavelength if min(diffs) <= 1e-10: indices.append(diffs.argmin()) if len(indices) != len(wavs): raise ValueError( "Filter wavelength mismatch with available image wavelengths") # Get the monochromatic images at each wavelength in the filter images = [image.val[0, :, :, j] for j in indices] print(' Found {} monochromatic images'.format(len(images))) # Show wavelengths and weights from filter file wavelengths = [image.wav[j] for j in indices] weights = filter_data[i][:, 1] print('\n Wavelength Weight') print(' ---------- ------') for k in range(len(wavelengths)): print(' {:.2E} {:.2E}'.format( wavelengths[k], weights[k])) # Apply appropriate transmissivities from filter file image_data.append(np.average(images, axis=0, weights=weights)) # Save the image data and filter information as an .hdf5 file f = h5py.File( cfg.model.PD_output_dir + "convolved." + cfg.model.snapnum_str + ".hdf5", "w") f.create_dataset("image_data", data=image_data) f['image_data'].attrs['width'] = w.value f['image_data'].attrs['width_unit'] = np.bytes_('kpc') # Don't add the names of filters that were skipped trimmed_names = list(set(filterfilenames) - set(skip_conv)) f.create_dataset("filter_names", data=trimmed_names) for i in range(len(filterfilenames)): f.create_dataset(filterfilenames[i], data=filter_data[i]) f.close()
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')
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()
import numpy as np import matplotlib.pyplot as plt from hyperion.model import ModelOutput from hyperion.util.constants import pc # Open the model m = ModelOutput('simple_cube.rtout') # 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(inclination=0, distance=300 * pc, units='MJy/sr') # Open figure and create axes fig = plt.figure(figsize=(8, 8)) # Pre-set maximum for colorscales VMAX = {} VMAX[1] = 10. VMAX[30] = 100. VMAX[100] = 2000. VMAX[300] = 2000. # We will now show four sub-plots, each one for a different wavelength for i, wav in enumerate([1, 30, 100, 300]): ax = fig.add_subplot(2, 2, i + 1) # Find the closest wavelength iwav = np.argmin(np.abs(wav - image.wav))
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 DIG_source_add(m,reg,df_nu): print("--------------------------------\n") print("Adding DIG to Source List in source_creation\n") print("--------------------------------\n") print ("Getting specific energy dumped in each grid cell") try: rtout = cfg.model.outputfile + '.sed' try: grid_properties = np.load(cfg.model.PD_output_dir+"/grid_physical_properties."+cfg.model.snapnum_str+'_galaxy'+cfg.model.galaxy_num_str+".npz") except: grid_properties = np.load(cfg.model.PD_output_dir+"/grid_physical_properties."+cfg.model.snapnum_str+".npz") cell_info = np.load(cfg.model.PD_output_dir+"/cell_info."+cfg.model.snapnum_str+"_"+cfg.model.galaxy_num_str+".npz") except: print ("ERROR: Can't proceed with DIG nebular emission calculation. Code is unable to find the required files.") print ("Make sure you have the rtout.sed, grid_physical_properties.npz and cell_info.npz for the corresponding galaxy.") return m_out = ModelOutput(rtout) oct = m_out.get_quantities() grid = oct order = find_order(grid.refined) refined = grid.refined[order] quantities = {} for field in grid.quantities: quantities[('gas', field)] = grid.quantities[field][0][order][~refined] cell_width = cell_info["fw1"][:,0] mass = (quantities['gas','density']*units.g/units.cm**3).value * (cell_width**3) met = grid_properties["grid_gas_metallicity"] specific_energy = (quantities['gas','specific_energy']*units.erg/units.s/units.g).value specific_energy = (specific_energy * mass) # in ergs/s # Black 1987 curve has a integrated ergs/s/cm2 of 0.0278 so the factor we need to multiply it by is given by this value factor = specific_energy/(cell_width**2)/(0.0278) mask1 = np.where(mass != 0 )[0] mask = np.where((mass != 0 ) & (factor >= cfg.par.DIG_min_factor))[0] # Masking out all grid cells that have no gas mass and where the specific emergy is too low print (len(factor), len(mask1), len(mask)) factor = factor[mask] cell_width = cell_width[mask] cell_x = (cell_info["xmax"] - cell_info["xmin"])[mask] cell_y = (cell_info["ymax"] - cell_info["ymin"])[mask] cell_z = (cell_info["zmax"] - cell_info["zmin"])[mask] pos = np.vstack([cell_x, cell_y, cell_z]).transpose() met = grid_properties["grid_gas_metallicity"][:, mask] met = np.transpose(met) fnu_arr = sg.get_dig_seds(factor, cell_width, met) dat = np.load(cfg.par.pd_source_dir + "/powderday/nebular_emission/data/black_1987.npz") spec_lam = dat["lam"] nu = 1.e8 * constants.c.cgs.value / spec_lam for i in range(len(factor)): fnu = fnu_arr[i,:] nu, fnu = wavelength_compress(nu,fnu,df_nu) nu = nu[::-1] fnu = fnu[::-1] lum = np.absolute(np.trapz(fnu,x=nu))*constants.L_sun.cgs.value source = m.add_point_source() source.luminosity = lum # [ergs/s] source.spectrum = (nu,fnu) source.position = pos[i] # [cm]
def azimuthal_avg_radial_intensity(wave, imgpath, source_center, rtout, plotname, annulus_width=10, group=8, dstar=200.): import numpy as np import matplotlib as mpl # to avoid X server error mpl.use('Agg') from astropy.io import ascii, fits import matplotlib.pyplot as plt from photutils import aperture_photometry as ap from photutils import CircularAperture, CircularAnnulus from astropy import units as u from astropy.coordinates import SkyCoord from astropy import wcs from hyperion.model import ModelOutput import astropy.constants as const import os pc = const.pc.cgs.value AU = const.au.cgs.value # source_center = '12 01 36.3 -65 08 53.0' # Read in data and set up coversions im_hdu = fits.open(imgpath) im = im_hdu[1].data # error if (wave < 200.0) & (wave > 70.0): im_err = im_hdu[5].data elif (wave > 200.0) & (wave < 670.0): im_err = im_hdu[5].data else: im_err_exten = raw_input( 'The extension that includes the image error: ') im_err = im_hdu[int(im_err_exten)].data w = wcs.WCS(im_hdu[1].header) coord = SkyCoord(source_center, unit=(u.hourangle, u.deg)) pixcoord = w.wcs_world2pix(coord.ra.degree, coord.dec.degree, 1) pix2arcsec = abs(im_hdu[1].header['CDELT1']) * 3600. # convert intensity unit from MJy/sr to Jy/pixel factor = 1e6 / 4.25e10 * abs( im_hdu[1].header['CDELT1'] * im_hdu[1].header['CDELT2']) * 3600**2 # radial grid in arcsec # annulus_width = 10 r = np.arange(10, 200, annulus_width, dtype=float) I = np.empty_like(r[:-1]) I_err = np.empty_like(r[:-1]) # iteration for ir in range(len(r) - 1): aperture = CircularAnnulus((pixcoord[0], pixcoord[1]), r_in=r[ir] / pix2arcsec, r_out=r[ir + 1] / pix2arcsec) # print aperture.r_in phot = ap(im, aperture, error=im_err) I[ir] = phot['aperture_sum'].data * factor / aperture.area() I_err[ir] = phot['aperture_sum_err'].data * factor / aperture.area() # print r[ir], I[ir] # read in from RTout rtout = ModelOutput(rtout) # setting up parameters # dstar = 200. # group = 8 # wave = 500.0 im = rtout.get_image(group=group, inclination=0, distance=dstar * pc, units='Jy', uncertainties=True) # Find the closest wavelength iwav = np.argmin(np.abs(wave - im.wav)) # avoid zero when log, and flip the image val = im.val[::-1, :, iwav] unc = im.unc[::-1, :, iwav] w = np.degrees(max(rtout.get_quantities().r_wall) / im.distance) * 3600 npix = len(val[:, 0]) pix2arcsec = 2 * w / npix # radial grid in arcsec # annulus_width = 10 r = np.arange(10, 200, annulus_width, dtype=float) I_sim = np.empty_like(r[:-1]) I_sim_err = np.empty_like(r[:-1]) # iteration for ir in range(len(r) - 1): aperture = CircularAnnulus((npix / 2. + 0.5, npix / 2. + 0.5), r_in=r[ir] / pix2arcsec, r_out=r[ir + 1] / pix2arcsec) # print aperture.r_in phot = ap(val, aperture, error=unc) I_sim[ir] = phot['aperture_sum'].data / aperture.area() I_sim_err[ir] = phot['aperture_sum_err'].data / aperture.area() # print r[ir], I_sim[ir] # write the numbers into file foo = open(plotname + '_radial_profile_' + str(wave) + 'um.txt', 'w') # print some header info foo.write('# wavelength ' + str(wave) + ' um \n') foo.write('# image file ' + os.path.basename(imgpath) + ' \n') foo.write('# annulus width ' + str(annulus_width) + ' arcsec \n') # write profiles foo.write('r_in[arcsec] \t I \t I_err \t I_sim \t I_sim_err \n') for i in range(len(I)): foo.write('%f \t %e \t %e \t %e \t %e \n' % (r[i], I[i], I_err[i], I_sim[i], I_sim_err[i])) foo.close() # plot fig = plt.figure(figsize=(8, 6)) ax = fig.add_subplot(111) I_sim_hi = np.log10( (I_sim + I_sim_err) / I_sim.max()) - np.log10(I_sim / I_sim.max()) I_sim_low = np.log10(I_sim / I_sim.max()) - np.log10( (I_sim - I_sim_err) / I_sim.max()) I_hi = np.log10((I + I_err) / I.max()) - np.log10(I / I.max()) I_low = np.log10(I / I.max()) - np.log10((I - I_err) / I.max()) i_sim = ax.errorbar(np.log10(r[:-1] * dstar), np.log10(I_sim / I_sim.max()), yerr=(I_sim_low, I_sim_hi), marker='o', linestyle='-', mec='None', markersize=10) i = ax.errorbar(np.log10(r[:-1] * dstar), np.log10(I / I.max()), yerr=(I_low, I_hi), marker='o', linestyle='-', mec='None', markersize=10) ax.legend([i, i_sim], [r'$\rm{observation}$', r'$\rm{simulation}$'], fontsize=16, numpoints=1, loc='upper right') [ 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(r'$\rm{log(Radius)\,[AU]}$', fontsize=18) ax.set_ylabel(r'$\rm{log(I\,/\,I_{max})}$', fontsize=18) # fix the tick label font ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral', size=18) for label in ax.get_xticklabels(): label.set_fontproperties(ticks_font) for label in ax.get_yticklabels(): label.set_fontproperties(ticks_font) fig.savefig(plotname + '_radial_profile_' + str(wave) + 'um.pdf', format='pdf', dpi=300, bbox_inches='tight') fig.clf()
from astropy import constants 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])
class Hyperion2LIME: """ Class for importing Hyperion result to LIME IMPORTANT: LIME uses SI units, while Hyperion uses CGS units. """ def __init__(self, rtout, velfile, cs, age, omega, rmin=0, mmw=2.37, g2d=100, truncate=None, debug=False, load_full=True, fix_tsc=True, hybrid_tsc=False, interpolate=False, TSC_dir='', tsc_outdir=''): self.rtout = rtout self.velfile = velfile if load_full: self.hyperion = ModelOutput(rtout) self.hy_grid = self.hyperion.get_quantities() self.rmin = rmin * 1e2 # rmin defined in LIME, which use SI unit self.mmw = mmw self.g2d = g2d self.cs = cs # in km/s self.age = age # in year # YLY update - add omega self.omega = omega self.r_inf = self.cs * 1e5 * self.age * yr # in cm # option to truncate the sphere to be a cylinder # the value is given in au to specify the radius of the truncated cylinder viewed from the observer self.truncate = truncate # debug option: print out every call to getDensity, getVelocity and getAbundance self.debug = debug # option to use simple Trapezoid rule average for getting density, temperature, and velocity self.interpolate = interpolate self.tsc2d = getTSC(age, cs, omega, velfile=velfile, TSC_dir=TSC_dir, outdir=tsc_outdir, outname='tsc_regrid') # # velocity grid construction # if load_full: # # ascii.read() fails for large file. Use pandas instead # self.tsc = pd.read_csv(velfile, skiprows=1, delim_whitespace=True, header=None) # self.tsc.columns = ['lp', 'xr', 'theta', 'ro', 'ur', 'utheta', 'uphi'] # # self.xr = np.unique(self.tsc['xr']) # reduce radius: x = r/(a*t) = r/r_inf # self.xr_wall = np.hstack(([2*self.xr[0]-self.xr[1]], # (self.xr[:-1]+self.xr[1:])/2, # [2*self.xr[-1]-self.xr[-2]])) # self.theta = np.unique(self.tsc['theta']) # self.theta_wall = np.hstack(([2*self.theta[0]-self.theta[1]], # (self.theta[:-1]+self.theta[1:])/2, # [2*self.theta[-1]-self.theta[-2]])) # self.nxr = len(self.xr) # self.ntheta = len(self.theta) # # # the output of TSC fortran binary is in mass density # self.tsc_rho2d = 1/(4*np.pi*G*(self.age*yr)**2)/mh/mmw * np.array(self.tsc['ro']).reshape([self.nxr, self.ntheta]) # # # self.vr2d = np.array(self.tsc['ur']).reshape([self.nxr, self.ntheta]) * self.cs*1e5 # # self.vtheta2d = np.array(self.tsc['utheta']).reshape([self.nxr, self.ntheta]) * self.cs*1e5 # # self.vphi2d = np.array(self.tsc['uphi']).reshape([self.nxr, self.ntheta]) * self.cs*1e5 # # # in unit of km/s # self.vr2d = np.reshape(self.tsc['ur'].to_numpy(), (self.nxr, self.ntheta)) * np.float64(self.cs) # self.vtheta2d = np.reshape(self.tsc['utheta'].to_numpy(), (self.nxr, self.ntheta)) * np.float64(self.cs) # self.vphi2d = np.reshape(self.tsc['uphi'].to_numpy(), (self.nxr, self.ntheta)) * np.float64(self.cs) # # if fix_tsc: # # fix the discontinuity in v_r # # vr = vr + offset * log(xr)/log(xr_break) for xr >= xr_break # for i in range(self.ntheta): # dvr = abs((self.vr2d[1:,i] - self.vr2d[:-1,i])/self.vr2d[1:,i]) # break_pt = self.xr[1:][(dvr > 0.05) & (self.xr[1:] > 1e-3) & (self.xr[1:] < 1-2e-3)] # if len(break_pt) > 0: # offset = self.vr2d[(self.xr < break_pt),i].max() - self.vr2d[(self.xr > break_pt),i].min() # self.vr2d[(self.xr >= break_pt),i] = self.vr2d[(self.xr >= break_pt),i] + offset*np.log10(self.xr[self.xr >= break_pt])/np.log10(break_pt) # # YLY update - 091118 # # fix the discontinuity in v_phi # for i in range(self.ntheta): # dvr = abs((self.vphi2d[1:,i] - self.vphi2d[:-1,i])/self.vphi2d[1:,i]) # break_pt = self.xr[1:][(dvr > 0.1) & (self.xr[1:] > 1e-3) & (self.xr[1:] < 1-2e-3)] # if len(break_pt) > 0: # offset = self.vphi2d[(self.xr < break_pt),i].min() - self.vphi2d[(self.xr > break_pt),i].max() # self.vphi2d[(self.xr >= break_pt),i] = self.vphi2d[(self.xr >= break_pt),i] + offset*np.log10(self.xr[self.xr >= break_pt])/np.log10(break_pt) # # # hybrid TSC kinematics that switches to angular momentum conservation within the centrifugal radius # if hybrid_tsc: # from scipy.interpolate import interp1d # for i in range(self.ntheta): # rCR = self.omega**2 * G**3 * (0.975*(self.cs*1e5)**3/G*(self.age*3600*24*365))**3 * np.sin(self.theta[i])**4 / (16*(self.cs*1e5)**8) # if rCR/self.r_inf >= self.xr.min(): # f_vr = interp1d(self.xr, self.vr2d[:,i]) # vr_rCR = f_vr(rCR/self.r_inf) # f_vphi = interp1d(self.xr, self.vphi2d[:,i]) # vphi_rCR = f_vphi(rCR/self.r_inf) # # # radius in cylinderical coordinates # wCR = np.sin(self.theta[i]) * rCR # J = vphi_rCR * wCR # M = (vr_rCR**2 + vphi_rCR**2) * wCR / (2*G) # # w = self.xr*np.sin(self.theta[i])*self.r_inf # self.vr2d[(self.xr <= rCR/self.r_inf), i] = -( 2*G*M/w[self.xr <= rCR/self.r_inf] - J**2/(w[self.xr <= rCR/self.r_inf])**2 )**0.5 # self.vphi2d[(self.xr <= rCR/self.r_inf), i] = J/(w[self.xr <= rCR/self.r_inf]) # # self.tsc2d = {'vr2d': self.vr2d, 'vtheta2d': self.vtheta2d, 'vphi2d': self.vphi2d} def Cart2Spherical(self, x, y, z, unit_convert=True): """ if unit_convert, the inputs (x, y, z) are meter. The outputs are in cm. """ if unit_convert: x, y, z = x * 1e2, y * 1e2, z * 1e2 r_in = (x**2 + y**2 + z**2)**0.5 if r_in != 0: t_in = np.arccos(z / r_in) else: t_in = 0 # if x != 0: # p_in = np.sign(y)*np.arctan(y/x) # the input phi is irrelevant in axisymmetric model # else: # p_in = np.sign(y)*np.pi/2 p_in = np.arctan2(y, x) if r_in < self.rmin: r_in = self.rmin return (r_in, t_in, p_in) def Spherical2Cart(self, r, t, p): """ This is only valid for axisymmetric model """ x = r * np.sin(t) * np.cos(p) y = r * np.sin(t) * np.sin(p) z = r * np.cos(t) return (x, y, z) def Spherical2Cart_vector(self, coord_sph, v_sph): r, theta, phi = coord_sph vr, vt, vp = v_sph transform = np.matrix([[ np.sin(theta) * np.cos(phi), np.cos(theta) * np.cos(phi), -np.sin(phi) ], [ np.sin(theta) * np.sin(phi), np.cos(theta) * np.sin(phi), np.cos(phi) ], [np.cos(theta), -np.sin(theta), 0]]) v_cart = transform.dot(np.array([vr, vt, vp])) return list(map(float, np.asarray(v_cart).flatten())) def locateCell(self, coord, wall_grid): """ return the indice of cell at given coordinates """ r, t, p = coord r_wall, t_wall, p_wall = wall_grid r_ind = min(np.argsort(abs(r_wall - r))[:2]) t_ind = min(np.argsort(abs(t_wall - t))[:2]) p_ind = min(np.argsort(abs(p_wall - p))[:2]) return (r_ind, t_ind, p_ind) # def interpolateCell(self, coord, cube, wall_grid): # """ # return the interpolated value at given data cube at given coordinates # """ # r, t, p = coord # r_wall, t_wall, p_wall = wall_grid # # # the cell center # r_ind = min(np.argsort(abs(r_wall-r))[:2]) # t_ind = min(np.argsort(abs(t_wall-t))[:2]) # p_ind = min(np.argsort(abs(p_wall-p))[:2]) # # # simple Trapezoid rule # val_dum = 0 # for ri in r_ind: # for ti in t_ind: # for pi in p_ind: # val_dum += cube[ri, ti, pi] # val = val_dum/8.0 # # return val def locateCell2d(self, coord, wall_grid): """ return the indice of cell at given coordinates """ r, t = coord r_wall, t_wall = wall_grid r_ind = min(np.argsort(abs(r_wall - r))[:2]) t_ind = min(np.argsort(abs(t_wall - t))[:2]) return (r_ind, t_ind) # def interpolateCell2d(self, coord, cube, wall_grid): # """ # return the interpolated value at given data cube at given coordinates # """ # r, t= coord # r_wall, t_wall = wall_grid # # r_ind = np.argsort(abs(r_wall-r))[:2] # t_ind = np.argsort(abs(t_wall-t))[:2] # # # simple Trapezoid rule # val = (cube[r_ind[0], t_ind[0]] + cube[r_ind[0], t_ind[1]] + # cube[r_ind[1], t_ind[0]] + cube[r_ind[1], t_ind[1]])/4.0 # # return val def getDensity(self, x, y, z, version='gridding', theta_cav=None): (r_in, t_in, p_in) = self.Cart2Spherical(x, y, z) if self.truncate != None: if (y**2 + z**2)**0.5 > self.truncate * au_si: return 0.0 if version == 'hyperion': r_wall = self.hy_grid.r_wall t_wall = self.hy_grid.t_wall p_wall = self.hy_grid.p_wall self.rho = self.hy_grid.quantities['density'][0].T if not self.interpolate: indice = self.locateCell((r_in, t_in, p_in), (r_wall, t_wall, p_wall)) rho = self.rho[indice] else: rho = self.interpolateCell((r_in, t_in, p_in), self.rho, (r_wall, t_wall, p_wall)) # LIME needs molecule number density per cubic meter # if self.debug: # foo = open('density.log', 'a') # foo.write('%e \t %e \t %e \t %e\n' % (x,y,z,float(self.rho[indice])*self.g2d/mh/self.mmw*1e6)) # foo.close() return float(rho) * self.g2d / mh / self.mmw * 1e6 elif version == 'gridding': # check for cavity # determine whether the cell is in the cavity # if (theta_cav != None) and (theta_cav != 0): # # using R = 10000 AU as the reference point # c0 = (10000.*au_cgs)**(-0.5)*\ # np.sqrt(1/np.sin(np.radians(theta_cav))**3-1/np.sin(np.radians(theta_cav))) # # # related coordinates # w = abs(r_in*np.cos(np.pi/2 - t_in)) # _z = r_in*np.sin(np.pi/2 - t_in) # # # condition for open cavity # z_cav = c0*abs(w)**1.5 # cav_con = abs(_z) > abs(z_cav) # # if cav_con: # # this is still wrong, because in the "correct" model setup. The cavity does not have zero density. # rho = 0.0 # return float(rho) # isothermal solution if r_in > self.r_inf: rho = (self.cs * 1e5)**2 / (2 * np.pi * G * (r_in)**2) / mh / self.mmw * 1e6 # TSC solution else: if not self.interpolate: ind = self.locateCell2d( (r_in, t_in), (self.tsc2d['xr_wall'] * self.r_inf, self.tsc2d['theta_wall'])) rho = self.tsc2d['rho2d'][ ind] * 1e6 # has been divided by "mh" and "mmw" else: rho = self.interpolateCell2d( (r_in, t_in), self.tsc2d['rho2d'], (self.tsc2d['xr_wall'] * self.r_inf, self.tsc2d['theta_wall'])) * 1e6 return float(rho) def getTemperature(self, x, y, z, external_heating=False, r_break=None): r_wall = self.hy_grid.r_wall t_wall = self.hy_grid.t_wall p_wall = self.hy_grid.p_wall self.temp = self.hy_grid.quantities['temperature'][0].T if self.truncate != None: if (y**2 + z**2)**0.5 > self.truncate * au_si: return 0.0 (r_in, t_in, p_in) = self.Cart2Spherical(x, y, z) if not self.interpolate: indice = self.locateCell((r_in, t_in, p_in), (r_wall, t_wall, p_wall)) temp = self.temp[indice] else: temp = self.interpolateCell((r_in, t_in, p_in), cube, (r_wall, t_wall, p_wall)) # if external_heating: # # get the temperature at the outermost radius # indice_lowT = self.locateCell(((r_wall[-1]+r_wall[-2])/2, t_in, p_in), (r_wall, t_wall, p_wall)) # lowT = self.temp[indice_lowT] # # the inner radius where the temperature correction starts to apply # # User-defined value # # r_break = 13000*au_cgs # # r_break = 2600*au_cgs # r_break = r_break*au_cgs # # if (lowT < 15) and (r_in >= r_break): # dT = (r_in - r_break)*(15-lowT)/((r_wall[-1]+r_wall[-2])/2 - r_break) # if float(temp) + float(dT) >= 0.0: # return float(temp) + float(dT) # else: # return 0.0 # test for a different approach of external heating if external_heating: from scipy.interpolate import interp1d # get the temperature at the outermost radius rc = (r_wall[1:] + r_wall[:-1]) / 2 indice_Tmin = self.locateCell((rc.max(), t_in, p_in), (r_wall, t_wall, p_wall)) Tmin = self.temp[indice_Tmin] # set an inner radius that the external heating will apply for skipping the disk, where temperature may be lower than 10 K # take two times the centrifugal radius rCen = self.omega**2 * G**3 * (0.975 * (self.cs * 1e5)**3 / G * (self.age * yr))**3 / ( 16 * (self.cs * 1e5)**8) r_ext_min = 2 * rCen if (temp < 10.0) and (r_in >= r_ext_min) and (Tmin < 15.0): rc = (r_wall[1:] + r_wall[:-1]) / 2 f_temp = interp1d( self.temp[(rc > r_ext_min), indice_Tmin[1], indice_Tmin[2]], rc[rc > r_ext_min]) r10K = f_temp(10.0) dT = (r_in - r10K) / (rc.max() - r10K) * (15.0 - Tmin) temp = float(temp) + float(dT) if float(temp) >= 0.0: return float(temp) else: return 0.0 def getVelocity(self, x, y, z, sph=False, unit_convert=True, vr_factor=1.0, vr_offset=0.0): """ cs: effecitve sound speed in km/s; age: the time since the collapse began in year. vr_offset: in km/s """ (r_in, t_in, p_in) = self.Cart2Spherical(x, y, z, unit_convert=unit_convert) if self.truncate != None: if (y**2 + z**2)**0.5 > self.truncate * au_si: v_out = [0.0, 0.0, 0.0] return v_out # outside of infall radius, the envelope is static # if r_in > self.r_inf: # v_sph = [0.0+vr_offset*1e3, 0.0, 0.0] # v_out = self.Spherical2Cart_vector((r_in, t_in, p_in), v_sph) # return v_out # if the input radius is smaller than the minimum in xr array, # use the minimum in xr array instead. # UPDATE (081518): return zero velocity instead if r_in < self.tsc2d['xr_wall'].min() * self.r_inf: r_in = self.tsc2d['xrc'].min() * self.r_inf v_out = [0.0, 0.0, 0.0] return v_out if not self.interpolate: ind = self.locateCell2d( (r_in, t_in), (self.tsc2d['xr_wall'] * self.r_inf, self.tsc2d['theta_wall'])) v_sph = list( map(float, [ self.tsc2d['vr2d'][ind] * 1e5 / 1e2, self.tsc2d['vtheta2d'][ind] * 1e5 / 1e2, self.tsc2d['vphi2d'][ind] * 1e5 / 1e2 ])) else: vr = self.interpolateCell2d((r_in, t_in), self.tsc2d['vr2d'], (self.tsc2d['xr_wall'] * self.r_inf, self.tsc2d['theta_wall'])) * 1e5 vtheta = self.interpolateCell2d( (r_in, t_in), self.tsc2d['vtheta2d'], (self.tsc2d['xr_wall'] * self.r_inf, self.tsc2d['theta_wall'])) * 1e5 vphi = self.interpolateCell2d((r_in, t_in), self.tsc2d['vphi2d'], (self.tsc2d['xr_wall'] * self.r_inf, self.tsc2d['theta_wall'])) * 1e5 v_sph = list(map(float, [vr / 1e2, vtheta / 1e2, vphi / 1e2])) # test for artifically reducing the radial velocity v_sph[0] = v_sph[0] * vr_factor # + vr_offset*1e3 # flatten out at the vr_offset # if v_sph[0] > vr_offset*1e3: # v_sph[0] = vr_offset*1e3 # Note infall velocity should be negative # A hybrid outer envelope model: -0.5 km/s uniformly within 1e4 AU and static beyond. # static envelope beyond 3000 AU # the vr_offset has a parabolic curve as a function of radius (e.g. Keto+2015) # parameter is taken from Keto+2015. y = a(r - r_max)^2 # vr is negative if v_sph[0] > vr_offset * 1e3: v_sph[0] = 50.0 * (r_in - (r_wall[-1] + r_wall[-2]) / 2)**2 * 1e3 if sph: return v_sph v_out = self.Spherical2Cart_vector((r_in, t_in, p_in), v_sph) if self.debug: foo = open('velocity.log', 'a') foo.write('%e \t %e \t %e \t %f \t %f \t %f\n' % (x, y, z, v_out[0], v_out[1], v_out[2])) foo.close() return v_out def getFFVelocity(self, x, y, z, J, M, sph=False, unit_convert=True, vr_factor=1.0): """ cs: effecitve sound speed in km/s; age: the time since the collapse began in year. """ (r_in, t_in, p_in) = self.Cart2Spherical(x, y, z, unit_convert=unit_convert) if self.truncate != None: if (y**2 + z**2)**0.5 > self.truncate * au_si: v_out = [0.0, 0.0, 0.0] return v_out # if the input radius is smaller than the minimum in xr array, # use the minimum in xr array instead. # UPDATE: return zero velocity instead if r_in < self.xr_wall.min() * self.r_inf: r_in = self.xr.min() * self.r_inf v_out = [0.0, 0.0, 0.0] return v_out # use the Sakai model M = M * MS # centrifugal barrier cb = J**2 / (2 * G * M) if 2 * G * M / r_in - J**2 / r_in**2 >= 0: vr = (2 * G * M / r_in - J**2 / r_in**2)**0.5 * vr_factor else: vr = 0.0 # let vk = vp at CB M_k = J**2 / (G * cb) vp = J / r_in vk = (G * M_k / r_in)**0.5 if r_in >= cb: v_sph = [-vr / 1e2, 0.0, vp / 1e2] else: v_sph = [-vr / 1e2, 0.0, vk / 1e2] if sph: return v_sph v_out = self.Spherical2Cart_vector((r_in, t_in, p_in), v_sph) if self.debug: foo = open('velocity.log', 'a') foo.write('%e \t %e \t %e \t %f \t %f \t %f\n' % (x, y, z, v_out[0], v_out[1], v_out[2])) foo.close() return v_out def getVelocity2(self, x, y, z, sph=False, unit_convert=True): """ new method to interpolate the velocity cs: effecitve sound speed in km/s; age: the time since the collapse began in year. """ (r_in, t_in, p_in) = self.Cart2Spherical(x, y, z, unit_convert=unit_convert) if self.truncate != None: if (y**2 + z**2)**0.5 > self.truncate * au_si: v_out = [0.0, 0.0, 0.0] return v_out # outside of infall radius, the envelope is static if r_in > self.r_inf: v_out = [0.0, 0.0, 0.0] return v_out # if the input radius is smaller than the minimum in xr array, # use the minimum in xr array instead. if r_in < self.tsc2d['xr_wall'].min() * self.r_inf: r_in = self.tsc2d['xrc'].min() * self.r_inf # TODO: raise warning # r, t = 10*au, np.radians(30.) # print(r, t) r_corners = np.argsort(abs(r_in - self.tsc2d['xrc'] * self.r_inf))[:2] theta_corners = np.argsort(abs(t_in - self.tsc2d['thetac']))[:2] # print(r_corners, theta_corners) # initialize the velocity vector in spherical coordinates # TODO: use scipy interp2d v_sph = [] for k in ['vr2d', 'vtheta2d', 'vphi2d']: f = interp2d(self.tsc2d['xrc'][r_corners] * self.r_inf, self.tsc2d['thetac'][theta_corners], self.tsc2d[k][np.ix_(r_corners, theta_corners)]) v_sph.append(float(f(r_in, t_in) * 1e5 / 1e2)) # v_r, v_theta, v_phi = 0.0, 0.0, 0.0 # for rc in r_corners: # for tc in theta_corners: # v_r += self.vr2d[rc, tc] # v_theta += self.vtheta2d[rc, tc] # v_phi += self.vphi2d[rc, tc] # v_r = v_r/4 # v_theta = v_theta/4 # v_phi = v_phi/4 # # v_sph = list(map(float, [v_r/1e2, v_theta/1e2, v_phi/1e2])) # convert to SI unit (meter) if sph: return v_sph v_out = self.Spherical2Cart_vector((r_in, t_in, p_in), v_sph) if self.debug: foo = open('velocity.log', 'a') foo.write('%e \t %e \t %e \t %f \t %f \t %f\n' % (x, y, z, v_out[0], v_out[1], v_out[2])) foo.close() return v_out def getAbundance(self, x, y, z, config, tol=10, theta_cav=None): # tol: the size (in AU) of the linear region between two steps # (try to avoid "cannot find cell" problem in LIME) # a_params = [abundance at outer region, # fraction of outer abundance to the inner abundance, # the ratio of the outer radius of the inner region to the infall radius] # abundances = [3.5e-8, 3.5e-9] # inner, outer if self.truncate != None: if (y**2 + z**2)**0.5 > self.truncate * au_si: return 0.0 tol = tol * au_cgs (r_in, t_in, p_in) = self.Cart2Spherical(x, y, z) # determine whether the cell is in the cavity if (theta_cav != None) and (theta_cav != 0): # using R = 10000 AU as the reference point c0 = (10000.*au_cgs)**(-0.5)*\ np.sqrt(1/np.sin(np.radians(theta_cav))**3-1/np.sin(np.radians(theta_cav))) # related coordinates w = abs(r_in * np.cos(np.pi / 2 - t_in)) _z = r_in * np.sin(np.pi / 2 - t_in) # condition for open cavity z_cav = c0 * abs(w)**1.5 cav_con = abs(_z) > abs(z_cav) if cav_con: abundance = 0.0 return float(abundance) # single negative drop case # TODO: adopt a more generic model name, but keep backward compatability. if (config['a_model'] == 'neg_step1') or (config['a_model'] == 'step1'): a0 = float(config['a_params0']) a1 = float(config['a_params1']) a2 = float(config['a_params2']) if (r_in - a2 * self.r_inf) > tol / 2: abundance = a0 elif abs(r_in - a2 * self.r_inf) <= tol / 2: abundance = a0 * a1 + (r_in - (a2 * self.r_inf - tol / 2)) * ( a0 - a0 * a1) / tol else: abundance = a0 * a1 elif (config['a_model'] == 'neg_step2') or (config['a_model'] == 'step2'): a0 = float(config['a_params0']) a1 = float(config['a_params1']) a2 = float(config['a_params2']) a3 = float(config['a_params3']) a4 = float(config['a_params4']) if (r_in - a2 * self.r_inf) > tol / 2: abundance = a0 # linear interpolation from the outer region to the first step elif abs(r_in - a2 * self.r_inf) <= tol / 2: abundance = a0 * a1 + (r_in - (a2 * self.r_inf - tol / 2)) * ( a0 - a0 * a1) / tol # first step elif (r_in - a4 * au_cgs) > tol / 5 / 2 and (a2 * self.r_inf - r_in) > tol / 2: abundance = a0 * a1 # linear interpolation from the first step to the second step elif abs(r_in - a4 * au_cgs) <= tol / 5 / 2: abundance = a0 * a3 + (r_in - (a4 * au_cgs - tol / 5 / 2)) * ( a0 * a1 - a0 * a3) / (tol / 5) else: abundance = a0 * a3 elif (config['a_model'] == 'drop'): a0 = float(config['a_params0']) a1 = float(config['a_params1']) a2 = float(config['a_params2']) a3 = float(config['a_params3']) a4 = float(config['a_params4']) if (r_in - a2 * au_cgs) > tol / 2: abundance = a0 # linear interpolation from the outer region to the first step elif abs(r_in - a2 * au_cgs) <= tol / 2: abundance = a1 + (r_in - (a2 * au_cgs - tol / 2)) * (a0 - a1) / tol # first step elif (r_in - a4 * au_cgs) > tol / 5 / 2 and (a2 * au_cgs - r_in) > tol / 2: abundance = a1 # linear interpolation from the first step to the second step elif abs(r_in - a4 * au_cgs) <= tol / 5 / 2: abundance = a3 + (r_in - (a4 * au_cgs - tol / 5 / 2)) * ( a1 - a3) / (tol / 5) else: abundance = a3 elif (config['a_model'] == 'drop2'): a0 = float(config['a_params0']) a1 = float(config['a_params1']) a2 = float(config['a_params2']) a3 = float(config['a_params3']) a4 = float(config['a_params4']) if (r_in - a2 * au_cgs) > tol / 2: abundance = a0 # linear interpolation from the outer region to the first step elif abs(r_in - a2 * au_cgs) <= tol / 2: abundance = a1 + (r_in - (a2 * au_cgs - tol / 2)) * (a0 - a1) / tol # first step elif (r_in - a4 * au_cgs) > tol / 5 / 2 and (a2 * au_cgs - r_in) > tol / 2: abundance = a1 # linear interpolation from the first step to the second step elif abs(r_in - a4 * au_cgs) <= tol / 5 / 2: abundance = a3 + (r_in - (a4 * au_cgs - tol / 5 / 2)) * ( a1 - a3) / (tol / 5) elif r_in >= 13 * au_cgs: abundance = a3 else: abundance = 1e-20 elif (config['a_model'] == 'drop3'): a0 = float(config['a_params0']) # undelepted abundance a1 = float(config['a_params1']) # depleted abundance a2 = float(config['a_params2']) # evaporation temperature (K) a3 = float(config['a_params3']) # depletion density (cm-3) a4 = float(config['a_params4'] ) # the temperature H2O starts to destory HCO+ if a4 == -1: a4 = np.inf temp = self.getTemperature(x, y, z) density = self.getDensity(x, y, z) / 1e6 if (temp <= a2) and (density >= a3): abundance = a1 elif (temp <= a4): abundance = a0 else: abundance = 1e-20 elif config['a_model'] == 'uniform': abundance = float(config['a_params0']) elif config['a_model'] == 'lognorm': a0 = float(config['a_params0']) a1 = float(config['a_params1']) a2 = float(config['a_params2']) a3 = float(config['a_params3']) # r_in for power law decrease if r_in >= a2 * self.r_inf: abundance = a0 elif (r_in < a2 * self.r_inf) & (r_in > a3 * au_cgs): abundance = a0 * a1 + a0 * (1 - a1) / ( np.log10(self.r_inf * a2) - np.log10(a3 * au_cgs)) * ( np.log10(r_in) - np.log10(a3 * au_cgs)) else: abundance = a0 * a1 elif config['a_model'] == 'powerlaw': a0 = float(config['a_params0']) a1 = float(config['a_params1']) a2 = float(config['a_params2']) a3 = float(config['a_params3']) a4 = float(config['a_params4']) # re-define rMin # rmin = 100*au_cgs rmin = self.rmin if r_in >= a2 * self.r_inf: abundance = a0 elif (r_in >= rmin) and (r_in < a2 * self.r_inf): # y = Ax^a3+B A = a0 * (1 - a1) / ((a2 * self.r_inf)**a3 - rmin**a3) B = a0 - a0 * (1 - a1) * (a2 * self.r_inf)**a3 / ( (a2 * self.r_inf)**a3 - rmin**a3) abundance = A * r_in**a3 + B else: abundance = a0 * a1 # option to cap the maximum value of abundance if a4 > 0: if abundance > abs(a4): abundance = abs(a4) elif config['a_model'] == 'powerlaw2': a0 = float(config['a_params0']) a1 = float(config['a_params1']) a2 = float(config['a_params2']) a3 = float(config['a_params3']) a4 = float(config['a_params4']) # re-define rMin # rmin = 100*au_cgs rmin = self.rmin if r_in >= a2 * self.r_inf: abundance = a0 elif (r_in >= rmin) and (r_in < a2 * self.r_inf): # y = Ax^a3+B A = a0 * (1 - a1) / ((a2 * self.r_inf)**a3 - rmin**a3) B = a0 - a0 * (1 - a1) * (a2 * self.r_inf)**a3 / ( (a2 * self.r_inf)**a3 - rmin**a3) abundance = A * r_in**a3 + B else: abundance = a0 * a1 # add the evaporation zone # TODO: parametrize the setup if (r_in <= 100 * au_cgs) and (r_in >= 13 * au_cgs): abundance = 1e-10 # option to cap the maximum value of abundance if a4 > 0: if abundance > abs(a4): abundance = abs(a4) elif config['a_model'] == 'chem': a0 = float(config['a_params0']) # peak abundance a1 = float(config['a_params1']) # inner abundance a2 = float(config['a_params2']) # peak radius a3 = float(config['a_params3']) # inner decrease power a4 = float(config['a_params4']) # outer decrease power # radius of the evaporation front, determined by the extent of COM emission rCOM = 100 * au_cgs if r_in >= a2 * self.r_inf: # y = Ax^a, a < 0 A_out = a0 / (a2 * self.r_inf)**a4 abundance = A_out * r_in**a4 elif (r_in >= rCOM) and (r_in < a2 * self.r_inf): # y = Ax^a, a > 0 A_in = a0 / (a2 * self.r_inf)**a3 abundance = A_in * r_in**a3 else: abundance = a1 elif config['a_model'] == 'chem2': a0 = float(config['a_params0']) # peak abundance a1 = float(config['a_params1']) # inner abundance a2 = float(config['a_params2']) # inner peak radius [AU] a3 = float(config['a_params3']) # outer peak radius [AU] a4 = config[ 'a_params4'] # inner/outer radius of the evaporation region # radius of the evaporation front, determined by the extent of COM emission if (a4 == '-1') or (a4 == '2.0/-2.0'): # for backward compatability rCOM = 100 * au_cgs rCen = 13 * au_cgs else: rCen = float(a4.split(',')[0]) * au_cgs rCOM = float(a4.split(',')[1]) * au_cgs # innerExpo, outerExpo = [float(i) for i in config['a_params4'].split('/')] # fix the decreasing/increasing powers innerExpo = 2.0 outerExpo = -2.0 if r_in >= a3 * au_cgs: # y = Ax^a, a < 0 A_out = a0 / (a3 * au_cgs)**outerExpo abundance = A_out * r_in**outerExpo elif (r_in < a3 * au_cgs) and (r_in >= a2 * au_cgs): abundance = a0 elif (r_in >= rCOM) and (r_in < a2 * au_cgs): # y = Ax^a, a > 0 A_in = a0 / (a2 * au_cgs)**innerExpo abundance = A_in * r_in**innerExpo elif (r_in >= rCen) and (r_in < rCOM): # centrifugal radius abundance = a1 else: abundance = 1e-20 elif config['a_model'] == 'chem3': a0 = float(config['a_params0']) # peak abundance a1 = float(config['a_params1']) # inner abundance a2 = list(map(float, config['a_params2'].split( ','))) # inner/outer radius for the maximum abundance [AU] a3 = list(map(float, config['a_params3'].split( ','))) # inner/outer radius for the evaporation zone [AU] a4 = list(map(float, config['a_params4'].split( ','))) # inner/outer decreasing power # radius of the evaporation front, determined by the extent of COM emission rEvap_inner = a3[0] * au_cgs rEvap_outer = a3[1] * au_cgs # test the case of a broken power law for the freeze-out zone # In this case, there will be three values for both a2 and a4 # The input powers are stored as - # innerExpo for all powers except for the last one # outerExpo for the last power # fix the decreasing/increasing powers innerExpo = a4[:-1] outerExpo = a4[-1] # calculate the constants for each freeze-out zone A = [] for i, (r_out, pow) in enumerate(zip(a2[:-1][::-1], innerExpo[::-1])): if i == 0: previous_pow = 0.0 _A = (r_out * au_cgs)**(-pow) else: _A = _A * (r_out * au_cgs)**(previous_pow - pow) previous_pow = pow A.append(a0 * _A) A = A[::-1] if r_in >= a2[-1] * au_cgs: # y = Ax^a, a < 0 A_out = a0 / (a2[-1] * au_cgs)**outerExpo abundance = A_out * r_in**outerExpo elif (r_in < a2[-1] * au_cgs) and (r_in >= a2[-2] * au_cgs): abundance = a0 # freeze-out zone elif (r_in >= rEvap_outer) and (r_in < a2[-2] * au_cgs): # y = Ax^a, a > 0 # determine which freeze-out zone ind_zone = a2[:-1].index( min([ rr for i, rr in enumerate(a2[:-1]) if rr * au_cgs - r_in > 0 ])) A_in = A[ind_zone] Expo = innerExpo[ind_zone] # A_in = a0 / (a2[0]*au_cgs)**innerExpo # abundance = A_in * r_in**innerExpo abundance = A_in * r_in**Expo elif (r_in >= rEvap_inner) and (r_in < rEvap_outer): # centrifugal radius abundance = a1 else: abundance = 0.0 elif config[ 'a_model'] == 'chem4': # mostly for CS, which has two evaporation fronts, one for CO, and one for CS. a0 = float(config['a_params0']) # peak abundance a1 = list(map( float, config['a_params1'].split(','))) # TWO inner abundance a2 = list(map(float, config['a_params2'].split( ','))) # inner/outer radius for the maximum abundance [AU] a3 = list( map(float, config['a_params3'].split(',')) ) # inner/middle/outer radius for the evaporation zone [AU] a4 = list(map(float, config['a_params4'].split( ','))) # inner/outer decreasing power # radius of the evaporation front, determined by the extent of COM emission rEvap_inner = a3[0] * au_cgs rEvap_middle = a3[1] * au_cgs rEvap_outer = a3[2] * au_cgs # test the case of a broken power law for the freeze-out zone # In this case, there will be three values for both a2 and a4 # The input powers are stored as - # innerExpo for all powers except for the last one # outerExpo for the last power # fix the decreasing/increasing powers innerExpo = a4[:-1] outerExpo = a4[-1] # calculate the constants for each freeze-out zone A = [] for i, (r_out, pow) in enumerate(zip(a2[:-1][::-1], innerExpo[::-1])): if i == 0: previous_pow = 0.0 _A = (r_out * au_cgs)**(-pow) else: _A = _A * (r_out * au_cgs)**(previous_pow - pow) previous_pow = pow A.append(a0 * _A) A = A[::-1] if r_in >= a2[-1] * au_cgs: # y = Ax^a, a < 0 A_out = a0 / (a2[-1] * au_cgs)**outerExpo abundance = A_out * r_in**outerExpo elif (r_in < a2[-1] * au_cgs) and (r_in >= a2[-2] * au_cgs): abundance = a0 # freeze-out zone elif (r_in >= rEvap_outer) and (r_in < a2[-2] * au_cgs): # y = Ax^a, a > 0 # determine which freeze-out zone ind_zone = a2[:-1].index( min([ rr for i, rr in enumerate(a2[:-1]) if rr * au_cgs - r_in > 0 ])) A_in = A[ind_zone] Expo = innerExpo[ind_zone] # A_in = a0 / (a2[0]*au_cgs)**innerExpo # abundance = A_in * r_in**innerExpo abundance = A_in * r_in**Expo elif (r_in >= rEvap_middle) and ( r_in < rEvap_outer): # 1st evaporation zone abundance = a1[1] elif (r_in >= rEvap_inner) and ( r_in < rEvap_middle): # 1st evaporation zone abundance = a1[0] else: abundance = 0.0 elif config['a_model'] == 'interp': filename = config['a_params0'] adata = io.ascii.read(filename, names=['radius', 'abundance']) f_a = interp1d(adata['radius'], adata['abundance']) if (r_in < adata['radius'].min() * au_cgs) or ( r_in > adata['radius'].max() * au_cgs): abundance = 1e-40 else: abundance = f_a(r_in / au_cgs) else: print('Cannot recognize the input a_model', config['a_model']) return False if self.debug: foo = open('abundance.log', 'a') foo.write('%e \t %e \t %e \t %f\n' % (x, y, z, abundance)) foo.close() # uniform abundance # abundance = 3.5e-9 return float(abundance) def radialSmoothing(self, x, y, z, variable, kernel='boxcar', smooth_factor=2, config=None): # convert the coordinates from Cartian to spherical (r_in, t_in, p_in) = self.Cart2Spherical(x, y, z) # r-array for smoothing smoothL = r_in / smooth_factor * au_cgs r_arr = np.arange(r_in - smoothL / 2, r_in + smoothL / 2, smoothL / 50) # 50 bins # setup the smoothing kernel # it is not really a smoothing kernel, more like a local mean def averageKernel(kernel, r, var): if kernel == 'boxcar': out = np.mean(var) return out # run the corresponding look-up function for the desired variable var_arr = np.empty_like(r_arr) for i, r in enumerate(r_arr): (xd, yd, zd) = self.Spherical2Cart(r, t_in, p_in) if variable == 'abundance': var_arr[i] = self.getAbundance(xd / 1e2, yd / 1e2, zd / 1e2, config) var = averageKernel(kernel, r, var_arr) return float(var)
def temp_hyperion(rtout,outdir, bb_dust=False): import numpy as np import matplotlib as mpl mpl.use('Agg') import matplotlib.pyplot as plt import os from hyperion.model import ModelOutput import astropy.constants as const from matplotlib.colors import LogNorm # seaborn colormap import seaborn.apionly as sns # constants setup AU = const.au.cgs.value # misc variable setup print_name = os.path.splitext(os.path.basename(rtout))[0] m = ModelOutput(rtout) q = m.get_quantities() # get the grid info ri, thetai = q.r_wall, q.t_wall rc = 0.5*( ri[0:len(ri)-1] + ri[1:len(ri)] ) thetac = 0.5*( thetai[0:len(thetai)-1] + thetai[1:len(thetai)] ) # get the temperature profile # and average across azimuthal angle # temperature array in [phi, theta, r] temp = q['temperature'][0].array.T temp2d = np.sum(temp**2, axis=2)/np.sum(temp, axis=2) temp2d_exp = np.hstack((temp2d,temp2d,temp2d[:,0:1])) thetac_exp = np.hstack((thetac-np.pi/2, thetac+np.pi/2, thetac[0]-np.pi/2)) mag = 1 fig = plt.figure(figsize=(mag*8,mag*6)) ax = fig.add_subplot(111, projection='polar') # cmap = sns.cubehelix_palette(light=1, as_cmap=True) cmap = plt.cm.CMRmap im = ax.pcolormesh(thetac_exp, rc/AU, temp2d_exp, cmap=cmap, norm=LogNorm(vmin=5, vmax=100)) # # cmap = plt.cm.RdBu_r # im = ax.pcolormesh(thetac_exp, np.log10(rc/AU), temp2d_exp/10, cmap=cmap, norm=LogNorm(vmin=0.1, vmax=10)) # print temp2d_exp.min(), temp2d_exp.max() im.set_edgecolor('face') ax.set_xlabel(r'$\rm{Polar\,angle\,(Degree)}$',fontsize=20) # ax.set_ylabel(r'$\rm{Radius\,(AU)}$',fontsize=20, labelpad=-140, color='grey') # ax.set_ylabel('',fontsize=20, labelpad=-140, color='grey') ax.tick_params(labelsize=16) ax.tick_params(axis='y', colors='grey') ax.set_yticks(np.hstack((np.arange(0,(int(max(rc)/AU/10000.)+1)*10000, 10000),max(rc)/AU))) # # ax.set_yticks(np.log10(np.array([1, 10, 100, 1000, 10000, max(rc)/AU]))) # ax.set_yticklabels([]) ax.grid(True, color='LightGray', linewidth=1.5) # ax.grid(True, color='k', linewidth=1) ax.set_xticklabels([r'$\rm{90^{\circ}}$',r'$\rm{45^{\circ}}$',r'$\rm{0^{\circ}}$',r'$\rm{-45^{\circ}}$',\ r'$\rm{-90^{\circ}}$',r'$\rm{-135^{\circ}}$',r'$\rm{180^{\circ}}$',r'$\rm{135^{\circ}}$']) cb = fig.colorbar(im, pad=0.1) cb.ax.set_ylabel(r'$\rm{Averaged\,Temperature\,(K)}$',fontsize=20) cb.set_ticks([5,10,20,30,40,50,60,70,80,90,100]) cb.set_ticklabels([r'$\rm{5}$',r'$\rm{10}$',r'$\rm{20}$',r'$\rm{30}$',r'$\rm{40}$',r'$\rm{50}$',r'$\rm{60}$',r'$\rm{70}$',r'$\rm{80}$',r'$\rm{90}$',r'$\rm{>100}$']) # # cb.ax.set_ylabel(r'$\rm{log(T/10)}$',fontsize=20) # cb.set_ticks([0.1, 10**-0.5, 1, 10**0.5, 10]) # cb.set_ticklabels([r'$\rm{-1}$',r'$\rm{-0.5}$',r'$\rm{0}$',r'$\rm{0.5}$',r'$\rm{\geq 1}$']) # cb_obj = plt.getp(cb.ax.axes, 'yticklabels') plt.setp(cb_obj,fontsize=20) # fix the tick label font ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',size=20) for label in ax.get_yticklabels(): label.set_fontproperties(ticks_font) fig.savefig(outdir+print_name+'_temperature.png', format='png', dpi=300, bbox_inches='tight') fig.clf() # Plot the radial temperature profile fig = plt.figure(figsize=(12,9)) ax = fig.add_subplot(111) plot_grid = [0,99,199] label_grid = [r'$\rm{outflow}$', r'$\rm{45^{\circ}}$', r'$\rm{midplane}$'] alpha = np.linspace(0.3,1.0,len(plot_grid)) color_list = [[0.8507598215729224, 0.6322174528970308, 0.6702243543099417],\ [0.5687505862870377, 0.3322661256969763, 0.516976691731939],\ [0.1750865648952205, 0.11840023306916837, 0.24215989137836502]] for i in plot_grid: temp_rad, = ax.plot(np.log10(rc/AU), np.log10(temp2d[:,i]),'-',color=color_list[plot_grid.index(i)],\ linewidth=2, markersize=3,label=label_grid[plot_grid.index(i)]) # plot the theoretical prediction for black body dust without considering the extinction if bb_dust == True: from hyperion.model import Model sigma = const.sigma_sb.cgs.value lsun = const.L_sun.cgs.value dum = Model() dum.use_sources(rtout) L_cen = dum.sources[0].luminosity/lsun t_bbdust = (L_cen*lsun/(16*np.pi*sigma*rc**2))**(0.25) temp_bbdust, = ax.plot(np.log10(rc/AU), np.log10(t_bbdust), '--', color='r', linewidth=2.5,label=r'$\rm{blackbody\,dust}$') ax.legend(loc='upper right', numpoints=1, fontsize=24) ax.set_xlabel(r'$\rm{log\,R\,(AU)}$',fontsize=24) ax.set_ylabel(r'$\rm{log\,T\,(K)}$',fontsize=24) [ax.spines[axis].set_linewidth(2) for axis in ['top','bottom','left','right']] ax.minorticks_on() ax.tick_params('both',labelsize=24,width=2,which='major',pad=15,length=5) ax.tick_params('both',labelsize=24,width=2,which='minor',pad=15,length=2.5) # fix the tick label font ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',size=24) for label in ax.get_xticklabels(): label.set_fontproperties(ticks_font) for label in ax.get_yticklabels(): label.set_fontproperties(ticks_font) ax.set_ylim([0,4]) fig.gca().set_xlim(left=np.log10(0.05)) # ax.set_xlim([np.log10(0.8),np.log10(10000)]) fig.savefig(outdir+print_name+'_temp_radial.pdf',format='pdf',dpi=300,bbox_inches='tight') fig.clf()
def hyperion_image(rtout, wave, plotdir, printname, dstar=200., group=0, marker=0, size='full', convolve=False, unit=None, scalebar=None): # to avoid X server error import matplotlib as mpl mpl.use('Agg') import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl import astropy.constants as const from hyperion.model import ModelOutput # Package for matching the colorbar from mpl_toolkits.axes_grid1 import make_axes_locatable pc = const.pc.cgs.value if unit == None: unit = 'erg\,s^{-1}\,cm^{-2}\,Hz^{-1}\,sr^{-1}' m = ModelOutput(rtout) # Extract the image. image = m.get_image(group=group, inclination=0, distance=dstar * pc, units='MJy/sr') # print np.shape(image.val) # Open figure and create axes fig = plt.figure(figsize=(8,8)) ax = fig.add_subplot(111) # Find the closest wavelength iwav = np.argmin(np.abs(wave - 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 factor = 1 # avoid zero in log # flip the image, because the setup of inclination is upside down val = image.val[::-1, :, iwav] * factor + 1e-30 if convolve: from astropy.convolution import convolve, Gaussian2DKernel img_res = 2*w/len(val[:,0]) kernel = Gaussian2DKernel(0.27/2.354/img_res) val = convolve(val, kernel) if size != 'full': pix_e2c = (w-size/2.)/w * len(val[:,0])/2 val = val[pix_e2c:-pix_e2c, pix_e2c:-pix_e2c] w = size/2. # 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(val, # norm=mpl.colors.LogNorm(vmin=1.515e-01, vmax=4.118e+01), norm=mpl.colors.LogNorm(vmin=1e-04, vmax=1e+01), cmap=cmap, origin='lower', extent=[-w, w, -w, w], aspect=1) # draw the flux extraction regions # x = 100 # y = 100 # area = x*y / 4.25e10 # offset = 50 # # pos_n = (len(val[0,:])/2.-1,len(val[0,:])/2.-1 + offset*len(val[0,:])/2/w) # pos_s = (len(val[0,:])/2.-1,len(val[0,:])/2.-1 - offset*len(val[0,:])/2/w) # # import matplotlib.patches as patches # ax.add_patch(patches.Rectangle((-x/2, -y), x, y, fill=False, edgecolor='lime')) # ax.add_patch(patches.Rectangle((-x/2, 0), x, y, fill=False, edgecolor='lime')) # plot the marker for center position by default or user input offset ax.plot([0],[-marker], '+', color='lime', markersize=10, mew=2) ax.set_xlim([-w,w]) ax.set_ylim([-w,w]) # ax.plot([0],[-10], '+', color='m', markersize=10, mew=2) print(w) # plot scalebar if scalebar != None: ax.plot([0.85*w-scalebar, 0.85*w], [-0.8*w, -0.8*w], color='w', linewidth=3) # add text ax.text(0.85*w-scalebar/2, -0.9*w, r'$\rm{'+str(scalebar)+"\,arcsec}$", color='w', fontsize=18, fontweight='bold', ha='center') # fix the tick label font ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',size=16) 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. 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{Intensity\,['+unit+']}$',fontsize=16) cb.ax.tick_params('both', width=1.5, which='major', length=3) cb.ax.tick_params('both', width=1.5, which='minor', length=2) cb_obj = plt.getp(cb.ax.axes, 'yticklabels') plt.setp(cb_obj,fontsize=18) # fix the tick label font ticks_font = mpl.font_manager.FontProperties(family='STIXGeneral',size=18) for label in cb.ax.get_yticklabels(): label.set_fontproperties(ticks_font) ax.set_xlabel(r'$\rm{RA\,Offset\,[arcsec]}$', fontsize=16) ax.set_ylabel(r'$\rm{Dec\,Offset\,[arcsec]}$', fontsize=16) # set the frame color ax.spines['bottom'].set_color('white') ax.spines['top'].set_color('white') ax.spines['left'].set_color('white') ax.spines['right'].set_color('white') ax.tick_params(axis='both', which='major', width=1.5, labelsize=18, color='white', length=5) ax.text(0.7,0.88,str(wave) + r'$\rm{\,\mu m}$',fontsize=20,color='white', transform=ax.transAxes) fig.savefig(plotdir+printname+'_image_'+str(wave)+'.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 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")
print "No grid reference file found!" oldparams = ['name', 'folder','T','M_sun','env_rmax','env_rmin','disk','disk_mass','disk_rmax',\ '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
import numpy as np from PIL import Image from hyperion.model import ModelOutput from hyperion.util.constants import pc m = ModelOutput('simple_cube.rtout') image = m.get_image(inclination=0, distance=300 * pc, units='MJy/sr') # Extract the slices we want to use for red, green, and blue r = image.val[:, :, 17] g = image.val[:, :, 18] b = image.val[:, :, 19] # Now we need to rescale the values we want to the range 0 to 255, clip values # outside the range, and convert to unsigned 8-bit integers. We also use a sqrt # stretch (hence the ** 0.5) r = np.clip((r / 0.5)**0.5 * 255., 0., 255.) r = np.array(r, dtype=np.uint8) g = np.clip((g / 2)**0.5 * 255., 0., 255.) g = np.array(g, dtype=np.uint8) b = np.clip((b / 4.)**0.5 * 255., 0., 255.) b = np.array(b, dtype=np.uint8) # We now convert to image objects image_r = Image.fromarray(r) image_g = Image.fromarray(g) image_b = Image.fromarray(b)
m.set_spherical_polar_grid(r, t, p) dens = zeros((nr - 1, nt - 1, np - 1)) + 1.0e-17 m.add_density_grid(dens, d) source = m.add_spherical_source() source.luminosity = lsun source.radius = rsun source.temperature = 4000. m.set_n_photons(initial=1000000, imaging=0) m.set_convergence(True, percentile=99., absolute=2., relative=1.02) m.write("test_spherical.rtin") m.run("test_spherical.rtout", mpi=False) n = ModelOutput('test_spherical.rtout') grid = n.get_quantities() temp = grid.quantities['temperature'][0] for i in range(9): plt.imshow(temp[i,:,:],origin="lower",interpolation="nearest", \ vmin=temp.min(),vmax=temp.max()) plt.colorbar() plt.show()
import matplotlib.pyplot as plt from hyperion.model import ModelOutput from hyperion.util.constants import pc mo = ModelOutput('pure_scattering.rtout') wav, fnu = mo.get_image(inclination=0, units='MJy/sr', distance=300. * pc) wav, pol = mo.get_image(inclination=0, stokes='linpol') fig = plt.figure(figsize=(8, 8)) # Make total intensity sub-plot ax = fig.add_axes([0.1, 0.3, 0.4, 0.4]) ax.imshow(fnu[:, :, 0], extent=[-13, 13, -13, 13], interpolation='none', cmap=plt.cm.gist_heat, origin='lower', vmin=0., vmax=4e9) ax.set_xlim(-13., 13.) ax.set_ylim(-13., 13.) ax.set_xlabel("x (solar radii)") ax.set_ylabel("y (solar radii)") ax.set_title("Surface brightness") # Make linear polarization sub-plot ax = fig.add_axes([0.51, 0.3, 0.4, 0.4]) im = ax.imshow(pol[:, :, 0] * 100., extent=[-13, 13, -13, 13], interpolation='none', cmap=plt.cm.gist_heat, origin='lower', vmin=0., vmax=100.) ax.set_xlim(-13., 13.) ax.set_ylim(-13., 13.)
wav = np.loadtxt('kmh94_3.1_full.wav') 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.]
import numpy as np import matplotlib.pyplot as plt from hyperion.model import ModelOutput from hyperion.util.integrate import integrate_loglog # Use LaTeX for plots plt.rc('text', usetex=True) # Open the output file m = ModelOutput('example_isrf.rtout') # Get an all-sky flux map image = m.get_image(units='ergs/cm^2/s/Hz', inclination=0) # Compute the frequency-integrated flux fint = np.zeros(image.val.shape[:-1]) for (j, i) in np.ndindex(fint.shape): fint[j, i] = integrate_loglog(image.nu, image.val[j, i, :]) # Find the area of each pixel l = np.radians(np.linspace(180., -180., fint.shape[1] + 1)) b = np.radians(np.linspace(-90., 90., fint.shape[0] + 1)) dl = l[1:] - l[:-1] db = np.sin(b[1:]) - np.sin(b[:-1]) DL, DB = np.meshgrid(dl, db) area = np.abs(DL * DB) # Compute the intensity intensity = fint / area
import matplotlib as mpl mpl.use('Agg') import matplotlib.pyplot as plt 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)
ax_top = grid[i].twiny() ax_top.set_xlabel(r'$\rm{log(radius)\,[AU]}$', fontsize=16) ax_top.set_xticks(r_ticks) ax_top.set_xticklabels(r_tick_labels) ax_top.tick_params('x', labelsize=14) else: r_ticks = scale(np.array([0,1,2,3,4]), (np.log10(0.14), np.log10(41253)), (-w,w)) ax_top = grid[i].twiny() ax_top.set_xticks(r_ticks) ax_top.set_xticklabels([]) grid[i].tick_params('both',labelsize=14) for i in range(4,8): # get the H-band simulated image m = ModelOutput(filename[i-4]) image = m.get_image(group=0, inclination=0, distance=178 * pc, units='MJy/sr') # Find the closest wavelength iwav = np.argmin(np.abs(wave - 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
g2d = 100 mmw = 2.37 mh = const.m_p.cgs.value + const.m_e.cgs.value AU = const.au.cgs.value model = np.arange(99,133).astype('str') # color map cmap = plt.cm.viridis color_array = [cmap(np.linspace(0, 0.9, len(model))[i]) for i in range(len(model))] fig = plt.figure(figsize=(8,6)) ax = fig.add_subplot(111) for i in range(len(model)): m = ModelOutput('/home/bettyjo/yaolun/hyperion/bhr71/controlled/model'+model[i]+'/model'+model[i]+'.rtout') q = m.get_quantities() r = q.r_wall rc = 0.5*(r[0:len(r)-1]+r[1:len(r)]) rho = q['density'][0].array rho2d = np.sum(rho**2,axis=0)/np.sum(rho,axis=0) plt.plot(np.log10(rc[rc > 0.14*AU]/AU), np.log10(rho2d[199,rc > 0.14*AU]/g2d/mmw/mh)-0.1*i, '-', color=color_array[i], linewidth=1) ax.set_ylim([-2,9]) ax.set_xlabel(r'$\rm{log(Radius)\,(AU)}$',fontsize=20) ax.set_ylabel(r'$\rm{log(Dust\,Density)\,(cm^{-3})}$',fontsize=20) [ax.spines[axis].set_linewidth(1.5) for axis in ['top','bottom','left','right']] ax.minorticks_on() ax.tick_params('both',labelsize=18,width=1.5,which='major',pad=15,length=5) ax.tick_params('both',labelsize=18,width=1.5,which='minor',pad=15,length=2.5)
import numpy as np from hyperion.model import ModelOutput import matplotlib.pyplot as plt from yt.mods import write_bitmap, ColorTransferFunction plt.rcParams['font.family'] = 'Arial' # Read in model from Hyperion m = ModelOutput('pla704850_lev7_129.rtout') grid = m.get_quantities() # Convert quantities to yt pf = grid.to_yt() # Instantiate the ColorTransferfunction. tmin, tmax = 1.3, 2.3 tf_temp = ColorTransferFunction((tmin, tmax)) dmin, dmax = -20, -16 tf_dens = ColorTransferFunction((dmin, dmax)) # Set up the camera parameters: center, looking direction, width, resolution c = (pf.domain_right_edge + pf.domain_left_edge) / 2.0 L = np.array([1.0, 1.0, 1.0]) W = 0.7 / pf["unitary"] N = 512 # Create camera objects cam_temp = pf.h.camera(c, L, W, N, tf_temp,
#Script showing how to extract some rtout files that were run on an #octree format from __future__ import print_function from hyperion.model import ModelOutput from hyperion.grid.yt3_wrappers import find_order import astropy.units as u import numpy as np run = '/home/desika.narayanan/pd_git/tests/SKIRT/gizmo_mw_zoom/pd_skirt_comparison.134.rtout.sed' m = ModelOutput(run) oct = m.get_quantities() #ds = oct.to_yt() #ripped from hyperion/grid/yt3_wrappers.py -- we do this because #something about load_octree in yt4.x is only returning the first cell grid = oct order = find_order(grid.refined) refined = grid.refined[order] quantities = {} for field in grid.quantities: quantities[('gas', field)] = np.atleast_2d(grid.quantities[field][0][order][~refined]).transpose() specific_energy = quantities['gas','specific_energy']*u.erg/u.s/u.g dust_temp = quantities['gas','temperature']*u.K dust_density = quantities['gas','density']*u.g/u.cm**3
oldparams = ['name', 'folder','T','M_sun','env_rmax','env_rmin','disk','disk_mass','disk_rmax',\ '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','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