def test_vs_RADEX(): for filename,coll_ID,Tex_values,tau_nu_values in\ zip(filenames,collider_names,RADEX_Tex,RADEX_tau_nu): lamda_filepath = os.path.join(here,filename) params = zip(Ntot_values,width_v_values,Tkin_values, coll_partner_densities_values,test_trans,Tex_values,tau_nu_values) for Ntot,width_v,Tkin,collp_dens,trans_num,Tex,tau_nu in params: coll_partner_densities = {coll_ID:collp_dens} test_nebula = nebula.Nebula( data_filepath=lamda_filepath,geometry=geometry, ext_background=ext_background,Tkin=Tkin, coll_partner_densities=coll_partner_densities, Ntot=Ntot,line_profile=line_profile,width_v=width_v) test_nebula.solve_radiative_transfer() fluxes = test_nebula.observed_fluxes( source_surface=surface,d_observer=distance) #see radex_output_readme.txt or RADEX manual for explanation of the follwing formula trans = test_nebula.emitting_molecule.rad_transitions[trans_num] RADEX_intensity = (helpers.B_nu(nu=trans.nu0,T=Tex)- ext_background(trans.nu0))\ * (1-np.exp(-tau_nu)) RADEX_flux = np.pi*RADEX_intensity*trans.line_profile.width_nu pyradex_flux = fluxes[trans_num] print('RADEX flux: {:g}; pyradex flux: {:g}'.format(RADEX_flux,pyradex_flux)) pyradex_tau = test_nebula.tau_nu0[trans_num] print('RADEX tau: {:g}; pyradex tau: {:g}'.format(tau_nu,pyradex_tau)) print('RADEX Tex: {:g} K; pyradex Tex: {:g} K'.format(Tex,test_nebula.Tex[trans_num])) assert np.isclose(RADEX_flux,pyradex_flux,atol=0,rtol=0.7) assert np.isclose(pyradex_tau,tau_nu,atol=0.01,rtol=0.1) print('\n')
def compute_line_fluxes(self, solid_angle): '''Compute the observed spectra and total fluxes for each line. This requires that the radiative transfer has been solved. This method computes the attributes obs_line_fluxes (total observed line fluxes in W/m2) and obs_line_spectra (observed line spectra in W/m2/Hz). Parameters: --------------- solid_angle: float the solid angle of the source in [rad2] ''' self.obs_line_fluxes = [] self.obs_line_spectra = [] for i, line in enumerate(self.emitting_molecule.rad_transitions): nu_array = line.line_profile.nu_array x1 = self.level_pop[line.low.number] x2 = self.level_pop[line.up.number] source_function = helpers.B_nu(T=self.Tex[i], nu=nu_array) tau_nu = line.tau_nu_array(N1=x1 * self.Ntot, N2=x2 * self.Ntot) line_flux_nu = self.geometry.compute_flux_nu( tau_nu=tau_nu, source_function=source_function, solid_angle=solid_angle) self.obs_line_spectra.append(line_flux_nu) #W/m2/Hz line_flux = np.trapz(line_flux_nu, line.line_profile.nu_array) #[W/m2] self.obs_line_fluxes.append(line_flux)
def test_compute_line_fluxes(): n = thin_LTE_test_nebula.Ntot / (2 * r) tot_particles = n * 4 / 3 * r**3 * np.pi up_level_particles = np.array([ tot_particles * expected_LTE_level_pop[trans.up.number] for trans in thin_LTE_test_nebula.emitting_molecule.rad_transitions ]) A21 = [ trans.A21 for trans in thin_LTE_test_nebula.emitting_molecule.rad_transitions ] Delta_E = [ trans.Delta_E for trans in thin_LTE_test_nebula.emitting_molecule.rad_transitions ] expected_LTE_fluxes_thin = up_level_particles * A21 * Delta_E / ( 4 * np.pi * r**2) assert np.allclose(thin_LTE_test_nebula.line_fluxes, expected_LTE_fluxes_thin, atol=0, rtol=1e-2) thick_LTE_test_nebula.solve_radiative_transfer() #the higher transitions might not be optically thick, so just test the lowest transition: lowest_trans = thick_LTE_test_nebula.emitting_molecule.rad_transitions[0] expected_thick_LTE_flux_lowest_trans = np.pi*helpers.B_nu(nu=lowest_trans.nu0,T=Tkin)\ * lowest_trans.line_profile.width_nu assert np.isclose(thick_LTE_test_nebula.line_fluxes[0], expected_thick_LTE_flux_lowest_trans, atol=0, rtol=1e-2)
def test_CMB_background(): test_nu = np.logspace(np.log10(1), np.log10(1000), 20) * constants.giga test_z = (0, 2) for z in test_z: CMB = helpers.generate_CMB_background(z=z) assert np.all( CMB(test_nu) == helpers.B_nu(nu=test_nu, T=2.73 * (1 + z)))
def compute_line_fluxes(self): '''Compute the flux for each line. This requires that the radiative transfer has been solved''' self.line_fluxes = [] for i, line in enumerate(self.emitting_molecule.rad_transitions): nu_array = line.line_profile.nu_array x1 = self.level_pop[line.low.number] x2 = self.level_pop[line.up.number] source_function = helpers.B_nu(T=self.Tex[i], nu=nu_array) tau_nu = line.tau_nu_array(N1=x1 * self.Ntot, N2=x2 * self.Ntot) line_flux_nu = self.geometry.compute_flux_nu( tau_nu=tau_nu, source_function=source_function) line_flux = np.trapz(line_flux_nu, line.line_profile.nu_array) #[W/m2] self.line_fluxes.append(line_flux)
def test_compute_line_fluxes(): for geo,neb in nebulae.items(): if 'RADEX' in geo or 'slab' in geo: continue Ntot = neb['thin_LTE'].Ntot if 'sphere' in geo: volume = 4/3*r**3*np.pi n = Ntot/(2*r) elif 'slab' in geo: volume = slab_surface*slab_depth n = Ntot/slab_depth tot_particles = n*volume thin_LTE_rad_transitions = neb['thin_LTE'].emitting_molecule.rad_transitions up_level_particles = np.array( [tot_particles*expected_LTE_level_pop[trans.up.number] for trans in thin_LTE_rad_transitions]) A21 = np.array([trans.A21 for trans in thin_LTE_rad_transitions]) Delta_E = np.array([trans.Delta_E for trans in thin_LTE_rad_transitions]) energy_flux = up_level_particles*A21*Delta_E #W if 'sphere' in geo: expected_LTE_fluxes_thin = energy_flux/(4*np.pi*d**2) elif 'slab' in geo: #not isotropic, so I can't do the same thing as for sphere expected_LTE_fluxes_thin = energy_flux/(4*np.pi*slab_surface)\ *get_solid_angle(geo) line_profile_nu0 = np.array([trans.line_profile.phi_nu(trans.nu0) for trans in thin_LTE_rad_transitions]) expected_LTE_fluxes_nu_thin = expected_LTE_fluxes_thin*line_profile_nu0 assert np.allclose(neb['thin_LTE'].obs_line_fluxes,expected_LTE_fluxes_thin, atol=0,rtol=1e-2) line_fluxes_nu_thin = [np.max(fluxes_nu) for fluxes_nu in neb['thin_LTE'].obs_line_spectra] assert np.allclose(line_fluxes_nu_thin,expected_LTE_fluxes_nu_thin, atol=0,rtol=1e-2) #the higher transitions might not be optically thick, so just test the #lowest transition: lowest_trans = neb['thick_LTE'].emitting_molecule.rad_transitions[0] expected_thick_LTE_flux_nu = helpers.B_nu(nu=lowest_trans.nu0,T=Tkin)\ *get_solid_angle(geo) expected_thick_LTE_flux = expected_thick_LTE_flux_nu\ * lowest_trans.line_profile.width_nu assert np.isclose(neb['thick_LTE'].obs_line_fluxes[0], expected_thick_LTE_flux,atol=0,rtol=1e-2)
def test_vs_RADEX(): for filename, coll_ID in zip(filenames, collider_names): specie = filename[:-4] lamda_filepath = os.path.join(here, filename) params = zip(Ntot_values, width_v_values, Tkin_values, coll_partner_densities_values, test_trans) for i, (Ntot, width_v, Tkin, collp_dens, trans_num) in enumerate(params): coll_partner_densities = {coll_ID: collp_dens} for geo in geometries: Omega = get_solid_angle(geo) print('looking at {:s}, {:s} (case {:d})'.format( specie, geo, i)) test_nebula = nebula.Nebula( datafilepath=lamda_filepath, geometry=geo, ext_background=ext_background, Tkin=Tkin, coll_partner_densities=coll_partner_densities, Ntot=Ntot, line_profile=line_profile, width_v=width_v) test_nebula.solve_radiative_transfer() test_nebula.compute_line_fluxes(solid_angle=Omega) trans = test_nebula.emitting_molecule.rad_transitions[ trans_num] if 'sphere' in geo: radex = RADEX['sphere'] elif 'slab' in geo: radex = RADEX['slab'] Tex = radex[specie]['Tex'][i] tau_nu = radex[specie]['tau'][i] #see radex_output_readme.txt or RADEX manual for explanation of the #follwing formula RADEX_intensity = (helpers.B_nu(nu=trans.nu0,T=Tex) -ext_background(trans.nu0))\ * (1-np.exp(-tau_nu)) RADEX_flux = RADEX_intensity * trans.line_profile.width_nu * Omega pyradex_flux = test_nebula.obs_line_fluxes[trans_num] print('RADEX flux: {:g}; pyradex flux: {:g}'.format( RADEX_flux, pyradex_flux)) pyradex_tau = test_nebula.tau_nu0[trans_num] pyradex_Tex = test_nebula.Tex[trans_num] print('RADEX tau: {:g}; pyradex tau: {:g}'.format( tau_nu, pyradex_tau)) print('RADEX Tex: {:g} K; pyradex Tex: {:g} K'.format( Tex, pyradex_Tex)) if 'RADEX' in geo: atol_flux = 0 rtol_flux = 0.3 atol_tau = 0.1 rtol_tau = 0.1 atol_Tex = 1 rtol_Tex = 0.2 else: atol_flux = 0 rtol_flux = 0.7 atol_tau = 0.1 rtol_tau = 0.5 atol_Tex = 1 rtol_Tex = 0.5 if pyradex_tau < 0: assert tau_nu < 0 assert Tex < 0 assert pyradex_Tex < 0 else: assert np.isclose(pyradex_tau, tau_nu, atol=atol_tau, rtol=rtol_tau) assert np.isclose(RADEX_flux, pyradex_flux, atol=atol_flux, rtol=rtol_flux) assert np.isclose(Tex, pyradex_Tex, atol=atol_Tex, rtol=rtol_Tex) print('\n') print('\n')
test_molecule = molecule.Molecule.from_LAMDA_datafile( data_filepath=lamda_filepath) Tkin = 100 expected_LTE_level_pop = test_molecule.LTE_level_pop(Tkin) coll_partner_densities_default = { 'para-H2': 1e1 / constants.centi**3, 'ortho-H2': 1e1 / constants.centi**3 } coll_partner_densities_large = { 'para-H2': 1e10 / constants.centi**3, 'ortho-H2': 1e10 / constants.centi**3 } coll_partner_densities_0 = {'para-H2': 0, 'ortho-H2': 0} Jbar_lines_0 = np.zeros(test_molecule.n_rad_transitions) Jbar_lines_B_nu = [ helpers.B_nu(nu=trans.nu0, T=Tkin) for trans in test_molecule.rad_transitions ] beta_lines_thin = np.ones(test_molecule.n_rad_transitions) I_ext_lines_0 = np.zeros(test_molecule.n_rad_transitions) def get_level_pops(coll_partner_densities, Jbar_lines, beta_lines, I_ext_lines): kwargs = { 'molecule': test_molecule, 'coll_partner_densities': coll_partner_densities, 'Tkin': Tkin } rate_equations_std = nebula.RateEquations(mode='std', **kwargs) level_pop_std = rate_equations_std.solve(Jbar_lines=Jbar_lines)
from scipy import constants import numpy as np here = os.path.dirname(os.path.abspath(__file__)) lamda_filepath = os.path.join(here,'co.dat') test_molecule = molecule.Molecule.from_LAMDA_datafile(datafilepath=lamda_filepath) Tkin = 100 expected_LTE_level_pop = test_molecule.LTE_level_pop(Tkin) coll_partner_densities_default = {'para-H2':1e1/constants.centi**3, 'ortho-H2':1e1/constants.centi**3} coll_partner_densities_large = {'para-H2':1e10/constants.centi**3, 'ortho-H2':1e10/constants.centi**3} coll_partner_densities_0 = {'para-H2':0,'ortho-H2':0} Jbar_lines_0 = np.zeros(test_molecule.n_rad_transitions) Jbar_lines_B_nu = [helpers.B_nu(nu=trans.nu0,T=Tkin) for trans in test_molecule.rad_transitions] beta_lines_thin = np.ones(test_molecule.n_rad_transitions) I_ext_lines_0 = np.zeros(test_molecule.n_rad_transitions) def get_level_pops(coll_partner_densities,Jbar_lines,beta_lines,I_ext_lines): kwargs = {'molecule':test_molecule, 'coll_partner_densities':coll_partner_densities,'Tkin':Tkin} rate_equations_std = nebula.RateEquations(mode='std',**kwargs) level_pop_std = rate_equations_std.solve(Jbar_lines=Jbar_lines) rate_equations_ALI = nebula.RateEquations(mode='ALI',**kwargs) level_pop_ALI = rate_equations_ALI.solve( beta_lines=beta_lines,I_ext_lines=I_ext_lines) return level_pop_std,level_pop_ALI def test_compute_level_populations_no_excitation():