def time_dependent(t_rad, t_kin, nc_h): # set the initial abundances for t = 0 n_levels = len(species_data.energy_levels.data) #initial_fractional_abundances_wrathmall = numpy.ones(n_levels_wrathmall) \ # / n_levels_wrathmall initial_fractional_abundances = numpy.random.rand(n_levels) #initial_fractional_abundances[0] = 0.8 #initial_fractional_abundances[1] = 1.e-3 initial_fractional_abundances = \ initial_fractional_abundances/initial_fractional_abundances.sum() y_0 = initial_fractional_abundances solver = ode(ode_rhs, jac=jac).set_integrator( 'lsoda', #method='bdf', with_jacobian=True, rtol=1e-14, atol=1e-14) solver.set_initial_value(y_0, t_0) step_counter = 0 t_all = [] x_all = [] while solver.t < t_f: solver.integrate(solver.t + dt) t_all.append(solver.t) x_all.append(solver.y) rel_diff = None if len(x_all) >= 2: y_2 = x_all[-2] y_1 = x_all[-1] rel_diff = numpy.abs((y_2 - y_1) / y_1) if (rel_diff < 1e-8).all(): break if step_counter % 100 == 0: print('{} t={:e} 1-x.sum()={:e}'.format( step_counter, solver.t, 1.0 - solver.y.sum())) if rel_diff is not None: print( numpy.where((rel_diff < 1e-6).all())[0].size, rel_diff.mean()) step_counter += 1 t_all, x_all = numpy.array(t_all), numpy.vstack(x_all) pop_dens_eq = population_density_at_steady_state( species_data, t_kin, t_rad, nc_h) return t_all, x_all, pop_dens_eq
def test_that_two_level_analytic_pop_dens_ratios_are_computed_correctly(): # # load the two level species data # species_data = DataLoader().load('two_level_1') n_c = 1e6 * u.meter ** -3 t_rad = 1000.0 * u.Kelvin # # for each value in the temperature range # - compute the population density ration numerically # - compute the population density analytically # # plot the comaprision # ratio_numeric_vs_t_kin = [] ratio_analytic_vs_t_kin = [] t_kin_range = numpy.logspace(1.0, 10.0, 50) * u.Kelvin for t_kin in t_kin_range: pop_dens_eq_numeric = population_density_at_steady_state( species_data, t_kin, t_rad, n_c) pop_dens_eq_ratio_numeric = pop_dens_eq_numeric[1] / pop_dens_eq_numeric[0] ratio_numeric_vs_t_kin.append(pop_dens_eq_ratio_numeric) pop_dens_eq_ratio_analytic = analytic.population_density_ratio_two_level( species_data.energy_levels.data['g'], species_data.energy_levels.data['E'], species_data.k_dex_matrix_interpolator(t_kin)[1, 0], species_data.a_matrix[1, 0], n_c, t_kin, t_rad ) ratio_analytic_vs_t_kin.append(pop_dens_eq_ratio_analytic) print(t_kin) ratio_numeric_vs_t_kin = numpy.array(ratio_numeric_vs_t_kin).flatten() ratio_analytic_vs_t_kin = numpy.array(ratio_analytic_vs_t_kin).flatten() relative_error = numpy.abs( 1.0 - numpy.array(ratio_numeric_vs_t_kin) / numpy.array( ratio_analytic_vs_t_kin) ) assert relative_error.max() < 1.2e-15 assert relative_error.std() < 5.0e-16
for nc_index, nc_h in enumerate(nc_h_rng): lambda_vs_t_kin = [] lambda_vs_t_kin_wrathmall = [] pop_dens_vs_t_kin = [] for i, t_kin in enumerate(t_rng): print(t_kin, nc_h) lambda_vs_t_kin += [ cooling_rate_at_steady_state(species_data, t_kin, t_rad, nc_h) ] pop_dens_vs_t_kin += [ population_density_at_steady_state(species_data, t_kin, t_rad, nc_h) ] lambda_vs_t_kin_wrathmall += [ cooling_rate_at_steady_state(species_data_wrathmall, t_kin, t_rad, nc_h) ] print(t_kin, pop_dens_vs_t_kin[i][0], pop_dens_vs_t_kin[i][2], pop_dens_vs_t_kin[i][4], pop_dens_vs_t_kin[i][6], pop_dens_vs_t_kin[i][8], pop_dens_vs_t_kin[i][10], pop_dens_vs_t_kin[i][12], pop_dens_vs_t_kin[i][14], pop_dens_vs_t_kin[i][16], pop_dens_vs_t_kin[i][1], pop_dens_vs_t_kin[i][3], pop_dens_vs_t_kin[i][5], pop_dens_vs_t_kin[i][7], pop_dens_vs_t_kin[i][9], pop_dens_vs_t_kin[i][11], pop_dens_vs_t_kin[i][13], pop_dens_vs_t_kin[i][15], pop_dens_vs_t_kin[i][17])
# # for each value in the temperature range # - compute the population density ration numerically # - compute the population density analytically # # plot the comaprision # ratio_numeric_vs_t_kin = [] ratio_analytic_vs_t_kin = [] t_kin_range = numpy.logspace(1.0, 10.0, 50) * u.Kelvin for t_kin in t_kin_range: # population densities using matrix inversion pop_dens_eq_numeric = population_density_at_steady_state( species_data, t_kin, t_rad, n_c ) pop_dens_eq_ratio_numeric = pop_dens_eq_numeric[1] / pop_dens_eq_numeric[0] ratio_numeric_vs_t_kin.append(pop_dens_eq_ratio_numeric) # popultation densities using analytic expressions pop_dens_eq_ratio_analytic = analytic.population_density_ratio_two_level( species_data.energy_levels.data['g'], species_data.energy_levels.data['E'], species_data.k_dex_matrix_interpolator(t_kin)[1, 0], species_data.a_matrix[1, 0], n_c, t_kin, t_rad )
# the kinetic temperature of the gas t_kin = 3000.0 * u.Kelvin t_rad = 30.0 * u.Kelvin species_data = DataLoader().load('two_level_1') t_kin_range = logspace(2.0, 6.0, 100) * u.K x_exact = array([ population_denisty_ratio_two_level_no_radiation(species_data, T_kin, nc) for T_kin in t_kin_range ], 'f8') x_numerical = array([ population_density_at_steady_state(species_data, T_kin, 0.0, nc) for T_kin in t_kin_range ], 'f8')[:, :, 0] # plot the relative population densities as a function of temperatures pylab.figure() pylab.loglog(t_kin_range, x_exact[:, 0], 'r-', label='x_0 exact') pylab.loglog(t_kin_range, x_numerical[:, 0], 'ro', label='x_0 numerical') pylab.loglog(t_kin_range, x_exact[:, 1], 'b-', label='x_1 exact') pylab.loglog(t_kin_range, x_numerical[:, 1], 'bo', label='x_1 numerical') pylab.legend() pylab.title('fractional population densities of levels 0 and level 1') pylab.show() rel_errors = fabs(1.0 - x_numerical / x_exact)