def get_cluster_properties(hdf_dir, snap, dist_cut, props): """ Load in filenames of available clusters and save desired properties into a pandas dataframe""" # Load filenames cluster_fnames = [f for f in listdir( hdf_dir) if isfile(join(hdf_dir, f))] # Initialise pandas dataframe ndex = np.arange(0, len(cluster_fnames)) cluster_props = pd.DataFrame(index=ndex, columns=props) cluster_props['fname'] = cluster_fnames # Get cluster properties for each cluster. for i in ndex: cluster_data = pd.read_hdf(hdf_dir + cluster_props.loc[i, 'fname'], 'cluster_evo', mode='r', where="""var in [redshift,hmass,rvir,\ snapid,x_comov,y_comov,z_comov]""") halo_data = pd.read_hdf(hdf_dir + cluster_props.loc[i, 'fname'], 'halo_evo', mode='r', where="""snap in [""" + str(snap) + """] and \ var in [snapid, host_id,x_comov,y_comov,z_comov,hmass]""") # Mass at snap. cluster_props.loc[i, 'mass'] = cluster_data.loc[snap, 'hmass'] # Get number of subhalos for each cluster, find unique ones u, idx = np.unique( halo_data.loc[snap, :, 'snapid'], return_index=True) num_subs = np.sum(halo_data.loc[ snap, :, 'host_id'][idx] == cluster_data.loc[snap, 'snapid']) cluster_props.loc[i, 'num_subs'] = num_subs # Find mass diff in time diff from snap. for time_req in range(1, 4): ages = (WMAP7.age(cluster_data.loc[ snap, 'redshift']) - WMAP7.age(cluster_data.loc[:, 'redshift'])) idx = (np.abs(ages.value - time_req)).argmin() snap_inq = idx + cluster_data.index.get_level_values('snap')[0] cluster_props.loc[i, 'mass_time_diff_' + str(time_req)] = (cluster_data.loc[ snap, 'hmass'] - cluster_data.loc[snap_inq, 'hmass']) # Find number of groups halo_data = halo_data.drop_duplicates() rad_select = (np.sqrt((np.power(halo_data.loc[:, :, 'x_comov'].subtract( cluster_data.loc[:, 'x_comov']), 2) + np.power(halo_data.loc[:, :, 'y_comov'].subtract( cluster_data.loc[:, 'y_comov']), 2) + np.power(halo_data.loc[:, :, 'z_comov'].subtract( cluster_data.loc[:, 'z_comov']), 2))) < dist_cut) mass_select = halo_data.loc[:, :, 'hmass'] > 1e13 num_grps = np.sum(mass_select & rad_select) cluster_props.loc[i, 'num_grps'] = num_grps return cluster_props, ndex
def plot_evolution(plotlabel, galaxy_counts, num_members, num_members_std, resultsdirs, colors, symbols, lbtimes, plot_lookback_times, plot_redshifts, plotsdir, labels): # # Plot fractional number of galaxies in compact groups vs. redshift # figname = os.path.join(plotsdir, '{0}_frac_galaxies_evolution.eps'.format(plotlabel)) frac_galaxies = np.array([[ df / galaxy_counts['num_galaxies'][snapnum] for snapnum, df in enumerate(num_members[result_ind]) ] for result_ind in range(len(resultsdirs))]) frac_galaxies_std = frac_galaxies * np.sqrt( np.array( [[(num_members_std / df)**2. + (galaxy_counts['std_galaxies'][snapnum] / galaxy_counts['num_galaxies'][snapnum])**2. for snapnum, (df, num_members_std) in enumerate( zip(num_members[result_ind], num_members_std[result_ind]))] for result_ind in range(len(resultsdirs))])) fig = plt.figure() ax = fig.add_subplot(111) ax2 = ax.twiny() for ind, (frac_galaxy, frac_galaxy_std) in enumerate( zip(frac_galaxies, frac_galaxies_std)): ax.plot(lbtimes, 100. * frac_galaxy, color=colors[ind], marker=symbols[ind], label=labels[ind]) ax.fill_between(lbtimes, 100. * (frac_galaxy - frac_galaxy_std), 100. * (frac_galaxy + frac_galaxy_std), facecolor=colors[ind], edgecolor='none', alpha=0.6) ax.set_xlabel('Lookback Time (Gyr)') ax.set_ylabel( 'Percent of non-dwarf Galaxies in that are currently in \nor have ever been in Compact Groups' ) ax.legend(loc='best', fontsize=12, numpoints=1) ax.set_xlim(0, WMAP7.age(0).to('Gyr').value) m = np.max(frac_galaxies) ax.set_ylim(0, 10) #ax.set_yscale('log') ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(plot_lookback_times) ax2.set_xticklabels(plot_redshifts) ax2.set_xlabel('Redshift') ax2.grid(False) plt.savefig(figname) plt.close() return
def _init_code(self): """Compute the age of the Universe at a given redshift """ self.redshift = float(self.parameters["redshift"]) # Raise an error when applying a negative redshift. This module is # not for blue-shifting. if self.redshift < 0.: raise Exception("The redshift provided is negative <{}>." .format(self.redshift)) self.universe_age = cosmology.age(self.redshift).value * 1000. if self.redshift == 0.: self.luminosity_distance = 10. * parsec else: self.luminosity_distance = ( cosmology.luminosity_distance(self.redshift).value * 1e6 * parsec) # We do not define the values of the IGM attenuation component yet. # This is because we need the wavelength grid for that first. This # will be assigned on the first call. self.igm_attenuation = {}
def main(datadir='/data', resultsdirs=['results'], plotsdir='plots', labels=['results'], counts_file='galaxy_counts.txt', snapnum_file='snapnum_redshift.csv', dwarf_limit=0.05, plotlabel='', evolution=False): """ Plot results of Millennium Simulation compact group analysis """ if not os.path.isdir(datadir): raise ValueError("{0} not found!".format(datadir)) for resultsdir in resultsdirs: if not os.path.isdir(resultsdir): raise ValueError("{0} not found!".format(resultsdir)) if not os.path.isdir(plotsdir): os.mkdir(plotsdir) if not os.path.exists(snapnum_file): raise ValueError("{0} not found!".format(snapnum_file)) # # Read snapnum file to convert from snapnum to redshift # snap_to_z = pandas.read_csv(snapnum_file, header=0, comment='#', skip_blank_lines=True, index_col=0, skipinitialspace=True) # # Determine number of snapnums we have in datadir # if evolution: data_snapnum_dirs = np.arange(64) else: data_snapnum_dirs = np.sort( glob.glob(os.path.join(datadir, 'snapnum_*'))) print("Found {0} snapnum directories in {1}.".format( len(data_snapnum_dirs), datadir)) if len(data_snapnum_dirs) == 0 and not os.path.exists(counts_file): return # # Count the number and standard devation of non-dwarf galaxies in raw data files # if os.path.exists(counts_file): print("Found {0}".format(counts_file)) else: generate_snapnum_counts(datadir, data_snapnum_dirs, data_file, dwarf_limit, counts_file) # # Read the galaxy counts file # galaxy_counts = pandas.read_csv(counts_file, header=0, comment='#', skip_blank_lines=True, index_col=0, skipinitialspace=True) # # Get results from each resultsdir # if evolution: num_members, num_members_std = data_read_in_evolution( resultsdirs, data_snapnum_dirs) else: members, groups, num_non_dwarf_members, non_dwarf_members, num_members_std, num_non_dwarf_members_std, num_groups_std = data_read_in( resultsdirs, data_snapnum_dirs, datadir) # # Convert snapnums to redshifts and to lookback times # snapnums = [snapnum for snapnum in range(len(data_snapnum_dirs))] redshifts = np.array([snap_to_z['Z'][snapnum] for snapnum in snapnums]) lbtimes = WMAP7.lookback_time(redshifts).value plot_redshifts = [0.0, 0.1, 0.2, 0.3, 0.5, 1, 1.5, 2, 3, 5, 10] plot_lookback_times = WMAP7.lookback_time(plot_redshifts).value # colors = ['#d73027', '#fc8d59', '#fee090'] symbols = ['o', 's', '^', '*', 'p'] # # Make Evolution Plots # if evolution: plot_evolution(plotlabel, galaxy_counts, num_members, num_members_std, resultsdirs, colors, symbols, lbtimes, plot_lookback_times, plot_redshifts, plotsdir, labels) return # # Plot total number of compact groups vs. redshift # figname = os.path.join(plotsdir, '{0}_num_groups.eps'.format(plotlabel)) num_cgs = np.array([[len(df) for df in groups[result_ind]] for result_ind in range(len(resultsdirs))]) fig = plt.figure() ax = fig.add_subplot(111) ax2 = ax.twiny() for ind, (num_cg, num_cg_std) in enumerate(zip(num_cgs, num_groups_std)): ax.plot(lbtimes, num_cg, color=colors[ind], marker=symbols[ind], label=labels[ind]) ax.fill_between(lbtimes, num_cg - num_cg_std, num_cg + num_cg_std, facecolor=colors[ind], edgecolor="none", alpha=0.6) ax.set_xlabel('Lookback Time (Gyr)') ax.set_ylabel('Number of Compact Groups') ax.set_yscale('log') ax.set_xlim(0, WMAP7.age(0).to('Gyr').value) ax.set_ylim(1.e2, 1.e5) ax.legend(loc='best', fontsize=12, numpoints=1) ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(plot_lookback_times) ax2.set_xticklabels(plot_redshifts) ax2.set_xlabel('Redshift') ax2.grid(False) plt.savefig(figname) plt.close() # # Plot total number of galaxies in compact groups vs. redshift # figname = os.path.join(plotsdir, '{0}_num_members.eps'.format(plotlabel)) num_galaxies = np.array([[len(df) for df in non_dwarf_members[result_ind]] for result_ind in range(len(resultsdirs))]) fig = plt.figure() ax = fig.add_subplot(111) ax2 = ax.twiny() for ind, (num_galaxy, num_galaxy_std) in enumerate( zip(num_galaxies, num_non_dwarf_members_std)): ax.plot(lbtimes, num_galaxy, color=colors[ind], marker=symbols[ind], label=labels[ind]) ax.fill_between(lbtimes, num_galaxy - num_galaxy_std, num_galaxy + num_galaxy_std, facecolor=colors[ind], edgecolor='none', alpha=0.6) ax.set_xlabel('Lookback Time (Gyr)') ax.set_ylabel('Number of non-dwarf Compact Group Members') ax.set_yscale('log') ax.legend(loc='best', fontsize=12, numpoints=1) ax.set_xlim(0, WMAP7.age(0).to('Gyr').value) ax.set_ylim(1.e3, 5.e5) ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(plot_lookback_times) ax2.set_xticklabels(plot_redshifts) ax2.set_xlabel('Redshift') ax2.grid(False) plt.savefig(figname) plt.close() # # Plot fractional number of galaxies in compact groups vs. redshift # figname = os.path.join(plotsdir, '{0}_frac_galaxies.eps'.format(plotlabel)) frac_galaxies = np.array([[ len(df) / galaxy_counts['num_galaxies'][snapnum] for snapnum, df in enumerate(non_dwarf_members[result_ind]) ] for result_ind in range(len(resultsdirs))]) frac_galaxies_std = frac_galaxies * np.sqrt( np.array([[(num_galaxy_std / len(df))**2. + (galaxy_counts['std_galaxies'][snapnum] / galaxy_counts['num_galaxies'][snapnum])**2. for snapnum, (df, num_galaxy_std) in enumerate( zip(non_dwarf_members[result_ind], num_non_dwarf_members_std[result_ind]))] for result_ind in range(len(resultsdirs))])) fig = plt.figure() ax = fig.add_subplot(111) ax2 = ax.twiny() for ind, (frac_galaxy, frac_galaxy_std) in enumerate( zip(frac_galaxies, frac_galaxies_std)): ax.plot(lbtimes, 100. * frac_galaxy, color=colors[ind], marker=symbols[ind], label=labels[ind]) ax.fill_between(lbtimes, 100. * (frac_galaxy - frac_galaxy_std), 100. * (frac_galaxy + frac_galaxy_std), facecolor=colors[ind], edgecolor='none', alpha=0.6) ax.set_xlabel('Lookback Time (Gyr)') ax.set_ylabel('Percent of non-dwarf Galaxies in Compact Groups') #ax.set_yscale('log') ax.legend(loc='best', fontsize=12, numpoints=1) ax.set_xlim(0, WMAP7.age(0).to('Gyr').value) ax.set_ylim(0., 1.5) ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(plot_lookback_times) ax2.set_xticklabels(plot_redshifts) ax2.set_xlabel('Redshift') ax2.grid(False) plt.savefig(figname) plt.close() return # # Now with redshift # # # Plot total number of compact groups vs. redshift # num_cgs = [len(df) for df in groups] fig = plt.figure() ax = fig.add_subplot(111) ax2 = ax.twiny() ax.plot(redshifts, num_cgs, 'k-') ax.plot(redshifts, num_cgs, 'ko') ax.set_xlabel('Redshift') ax.set_ylabel('Number of Compact Groups') ax.set_yscale('log') ax.set_xlim(0, 12) ax.set_ylim(1.e2, 1.e5) ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(np.arange(13)) ax2.set_xticklabels(WMAP7.lookback_time(np.arange(13)).value) ax2.set_xlabel('Lookback time (Gyr)') ax2.grid(False) plt.savefig('num_groups_z.eps') plt.close() # # Plot total number of galaxies in compact groups vs. redshift # num_galaxies = [len(df) for df in non_dwarf_members] fig = plt.figure() ax = fig.add_subplot(111) ax2 = ax.twiny() ax.plot(redshifts, num_galaxies, 'k-') ax.plot(redshifts, num_galaxies, 'ko') ax.set_xlabel('Redshift') ax.set_ylabel('Number of non-dwarf Compact Group Members') ax.set_yscale('log') ax.set_xlim(0, 12) ax.set_ylim(1.e2, 1.e5) ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(np.arange(13)) ax2.set_xticklabels(WMAP7.lookback_time(np.arange(13)).value) ax2.set_xlabel('Lookback time (Gyr)') ax2.grid(False) plt.savefig('num_members_z.eps') plt.close() # # Plot fractional number of galaxies in compact groups vs. redshift # frac_galaxies = [ len(df) / galaxy_counts['num_galaxies'][snapnum] for snapnum, df in enumerate(non_dwarf_members) ] fig = plt.figure() ax = fig.add_subplot(111) ax2 = ax.twiny() ax.plot(redshifts, frac_galaxies, 'k-') ax.plot(redshifts, frac_galaxies, 'ko') ax.set_xlabel('Redshift') ax.set_ylabel('Fracion of non-dwarf Galaxies in Compact Groups') ax.set_xlim(0, 12) ax.set_ylim(1.e-4, 1.e-2) ax2.set_xlim(ax.get_xlim()) ax2.set_xticks(np.arange(13)) ax2.set_xticklabels(WMAP7.lookback_time(np.arange(13)).value) ax2.set_xlabel('Lookback time (Gyr)') ax2.grid(False) plt.savefig('frac_galaxies_z.eps') plt.close() return
def solve(self,param): """ Solves the radiative transfer equation for the given source and the parameters. The solver calls grid parameters and initializes the starting grid with the initial conditions for the densities and the temperature. Using the time step, the radiative transfer equations are used to update the k-th cell from the radial grid for a certain time step dt_init. Then the solver moves on to the (k+1)-th cell, and uses the values calculated from the k-th cell in order to calculate the optical depth, which requires information of the densities from all prior cells. For each cell, we sum up the three densities from the starting cell up to the current cell and use these values to evaluate the 12 integrals in the equations, which is done by interpolation of the tables we generated previously. After each cell is updated for some time dt_init, we start again with the first cell and use the calculation from the previous time step as the initial condition and repeat the same process until the radial cells are updated l times such that l*dt_init has reached the evolution time. After the solver is finished we compare the ionization fronts of two consecutive runs and require an accuracy of 5% in order to finish the calculations. If the accuracy is not reached we store the values from the run and start again with time step size dt_init/2 and a radial grid with half the step size from the previous run. This process is repeated until the desired accuracy is reached. """ print('Solving the radiative equations...') t_start_solver = datetime.datetime.now() self.initialise_grid_param() z_reion = self.grid_param['z_reion'] gamma_2c = self.grid_param['gamma_2c'] T_gamma = self.grid_param['T_gamma'] C = self.grid_param['C'] dt_init = self.grid_param['dt_init'] dn = self.grid_param['dn'] r_grid0 = linspace(self.grid_param['r_start'], self.grid_param['r_end'], dn) r_grid = linspace(self.grid_param['r_start'], self.grid_param['r_end'], dn) n_HII_grid = zeros_like(r_grid0) n_HeII_grid = zeros_like(r_grid0) n_HeIII_grid = zeros_like(r_grid0) self.create_table(param = param) N = r_grid.size n_HI = self.Gamma_grid_info['input']['n_HI'] n_HeI = self.Gamma_grid_info['input']['n_HeI'] points = (n_HI, n_HeI) if self.M >= 10 ** 8: method = 'LSODA' else: method = 'LSODA' while True: time_grid = [] Ion_front_grid = [] dn = self.grid_param['dn'] n_HII0 = copy(n_HII_grid[:]) n_HeII0 = copy(n_HeII_grid[:]) n_HeIII0 = copy(n_HeIII_grid[:]) n_HII_grid = zeros_like(r_grid) n_HeII_grid = zeros_like(r_grid) n_HeIII_grid = zeros_like(r_grid) T_grid = zeros_like(r_grid) T_grid += T_gamma.value * (1 + z_reion) ** 1 / (1 + 250) l = 0 print('Number of time steps: ', int(math.ceil(self.grid_param['t_life'] / dt_init.value))) Gamma_info = self.Gamma_grid_info['Gamma'] JHI_1, JHI_2, JHI_3 = Gamma_info['HI_1'], Gamma_info['HI_2'], Gamma_info['HI_3'] JHeI_1, JHeI_2, JHeI_3, JHeII = Gamma_info['HeI_1'], Gamma_info['HeI_2'], Gamma_info['HeI_3'], Gamma_info[ 'HeII'] JT_HI_1, JT_HeI_1, JT_HeII_1 = Gamma_info['T_HI_1'], Gamma_info['T_HeI_1'], Gamma_info['T_HeII_1'] JT_2a, JT_2b = Gamma_info['T_2a'], Gamma_info['T_2b'] while l * self.grid_param['dt_init'].value <= self.grid_param['t_life']: if l % 5 == 0 and l!=0: print('Current Time step: ', l) # Calculate the redshift z(t) age = pl.age(z_reion) age = age.to(u.s) age += l * self.grid_param['dt_init'] func = lambda z: pl.age(z).to(u.s).value - age.value zstar = fsolve(func, z_reion) # Initialize the values to evaluate the integrals K_HI = 0 K_HeI = 0 K_HeII = 0 for k in (arange(0, r_grid.size, 1)): table_grid = self.Gamma_grid_info['input']['r_grid'] dr_initial = table_grid[1]-table_grid[0] dr_current = r_grid[1] - r_grid[0] correction = dr_current / dr_initial if k > 0: dr_current = r_grid[k] - r_grid[k-1] correction = dr_current / dr_initial n_HI00 = n_H(zstar,C) - n_HII_grid[k - 1] if n_HI00 < 0: n_HI00 = 0 n_HeI00 = n_He(zstar, C) - n_HeII_grid[k - 1] - n_HeIII_grid[k - 1] if n_HeI00 < 0: n_HeI00 = 0 if n_HeI00 > n_He(zstar, C): n_HeI00 = n_He(zstar, C) K_HI += abs(nan_to_num(n_HI00)+nan_to_num(n_HeII_grid[k - 1]))*correction K_HeI += abs(nan_to_num(n_HeI00))*correction K_HeII += abs(nan_to_num(n_HeII_grid[k - 1]))*correction if self.lifetime is not None and l * self.grid_param['dt_init'].value > ( (self.lifetime * u.Myr).to(u.s)).value: I1_HI = 0 I2_HI = 0 I3_HI = 0 I1_HeI = 0 I2_HeI = 0 I3_HeI = 0 I1_HeII = 0 I1_T_HI = 0 I1_T_HeI = 0 I1_T_HeII = 0 I2_Ta = 0 I2_Tb = 0 else: r2 = r_grid[k] ** 2 n_corr = exp(-dr_current*diff*K_HeII) corr_ag = (integrate.quad(lambda x: x ** -self.alpha, E_0, E_upp)[0]) / ( integrate.quad(lambda x: x ** -self.alpha, E_0, 0.1 * E_upp)[0]) # numerical correction if self.M == self.Gamma_grid_info['input']['M']: m_corr = 1 else: m_corr = self.M/self.Gamma_grid_info['input']['M'] I1_HI = interpolate.interpn(points, JHI_1, (K_HI, K_HeI), method='linear') * n_corr * m_corr / r2 *corr_ag I2_HI = interpolate.interpn(points, JHI_2, (K_HI, K_HeI), method='linear') * n_corr * m_corr / r2 *corr_ag I3_HI = interpolate.interpn(points, JHI_3, (K_HI, K_HeI), method='linear') * n_corr * m_corr / r2 *corr_ag I1_HeI = interpolate.interpn(points, JHeI_1, (K_HI, K_HeI), method='linear') * n_corr * m_corr / r2 *corr_ag I2_HeI = interpolate.interpn(points, JHeI_2, (K_HI, K_HeI), method='linear') * n_corr * m_corr / r2 *corr_ag I3_HeI = interpolate.interpn(points, JHeI_3, (K_HI, K_HeI), method='linear') * n_corr * m_corr / r2 *corr_ag I1_HeII = interpolate.interpn(points, JHeII, (K_HI, K_HeI), method='linear') * n_corr * m_corr / r2 *corr_ag I1_T_HI = interpolate.interpn(points, JT_HI_1, (K_HI, K_HeI), method='linear') * n_corr * m_corr / r2 *corr_ag I1_T_HeI = interpolate.interpn(points, JT_HeI_1, (K_HI, K_HeI), method='linear') * n_corr * m_corr / r2 *corr_ag I1_T_HeII = interpolate.interpn(points, JT_HeII_1, (K_HI, K_HeI), method='linear') * n_corr * m_corr / r2 *corr_ag I2_Ta = interpolate.interpn(points, JT_2a, (K_HI, K_HeI), method='linear') * n_corr * m_corr / r2 *corr_ag I2_Tb = interpolate.interpn(points, JT_2b, (K_HI, K_HeI), method='linear') * n_corr * m_corr / r2 *corr_ag def rhs(t, n): """ Calculate the RHS of the radiative transfer equations. RHS of the coupled nHII, n_HeII, n_HeIII and T equations. The equations are labelled as A,B,C, and D and the rest of the variables are the terms contained in the respective equations. Parameters ---------- t : float Time of evaluation in s. n : array-like 1-D array containing the variables nHII, nHeII, nHeIII, T for evaluating the RHS. Returns ------- array_like The RHS of the radiative transfer equations. """ if isnan(n[0]) or isnan(n[1]) or isnan(n[2]) or isnan(n[3]): print('Warning: calculations contain nan values, check the rhs') n_HIIx = n[0] n_HIx = n_H(zstar, C) - n[0] if isnan(n_HIIx): n_HIIx = n_H(zstar, C) n_HIx = 0 if n_HIIx > n_H(zstar, C): n_HIIx = n_H(zstar, C) n_HIx = 0 if n_HIIx < 0: n_HIIx = 0 n_HIx = n_H(zstar, C) n_HeIIx = n[1] n_HeIIIx = n[2] n_HeIx = n_He(zstar, C) - n[1] - n[2] if isnan(n_HeIIIx): n_HeIIIx = n_He(zstar, C) n_HeIIx = 0 n_HeIx = 0 if n_HeIIIx > n_He(zstar, C): n_HeIIIx = n_He(zstar, C) n_HeIIx = 0 n_HeIx = 0 if n_HeIIIx < 0: n_HeIIIx = 0 n_HeIIx = 0 n_HeIx = n_He(zstar, C) Tx = n[3] if isnan(Tx): print('Tx is nan') if (Tx < T_gamma.value * (1 + zstar) ** 1 / (1 + 250)): Tx = T_gamma.value * (1 + zstar) ** 1 / (1 + 250) n_ee = n_HIIx + n_HeIIx + 2 * n_HeIIIx mu = (n_H(zstar, C) + 4 * n_He(zstar, C)) / ( n_H(zstar, C) + n_He(zstar, C) + n_ee) n_B = n_H(zstar, C) + n_He(zstar, C) + n_ee A1_HI = xi_HI(Tx) * n_HIx * n_ee A1_HeI = xi_HeI(Tx) * n_HeIx * n_ee A1_HeII = xi_HeII(Tx) * n_HeIIx * n_ee A2_HII = eta_HII(Tx) * n_HIIx * n_ee A2_HeII = eta_HeII(Tx) * n_HeIIx * n_ee A2_HeIII = eta_HeIII(Tx) * n_HeIIIx * n_ee A3 = omega_HeII(Tx) * n_ee * n_HeIIIx A4_HI = psi_HI(Tx) * n_HIx * n_ee A4_HeI = psi_HeI(Tx, n_ee, n_HeIIx) * n_ee A4_HeII = psi_HeII(Tx) * n_HeIIx * n_ee A5 = theta_ff(Tx) * (n_HIIx + n_HeIIx + 4 * n_HeIIIx) * n_ee H = pl.H(zstar) H = H.to(u.s ** -1) A6 = (2 * H * kb * Tx * n_B / mu).value A = gamma_HI(n_HIIx, n_HeIx, n_HeIIx, n_HeIIIx, Tx, I1_HI, I2_HI, I3_HI, zstar,C, gamma_2c) * n_HIx - alpha_HII( Tx) * n_HIIx * n_ee B = gamma_HeI(n_HIIx, n_HeIx, n_HeIIx, n_HeIIIx, I1_HeI, I2_HeI, I3_HeI, zstar, C) * n_HeIx + beta_HeI( Tx) * n_ee * n_HeIx - beta_HeII(Tx) * n_ee * n_HeIIx - alpha_HeII( Tx) * n_ee * n_HeIIx + alpha_HeIII(Tx) * n_ee * n_HeIIIx - zeta_HeII( Tx) * n_ee * n_HeIIx Cc = gamma_HeII(I1_HeII) * n_HeIIx + beta_HeII( Tx) * n_ee * n_HeIIx - alpha_HeIII(Tx) * n_ee * n_HeIIIx Dd = (Tx / mu) * (-mu / (n_H(zstar, C) + n_He(zstar, C) + n_ee)) * (A + B + 2 * Cc) D = (2 / 3) * mu / (kb.value * n_B) * ( f_Heat(n_HIIx/n_H(zstar,C), zstar) * n_HIx * I1_T_HI + f_Heat(n_HIIx/n_H(zstar,C), zstar) * n_HeIx * I1_T_HeI + f_Heat( n_HIIx/n_H(zstar,C), zstar) * n_HeIIx * I1_T_HeII + sigma_s.value * n_ee / (m_e * c ** 2).value * ( I2_Ta + Tx * I2_Tb) - ( A1_HI + A1_HeI + A1_HeII + A2_HII + A2_HeII + A2_HeIII + A3 + A4_HI + A4_HeI + A4_HeII + A5 + A6)) + Dd return ravel(array([A, B, Cc, D])) y0 = zeros(4) y0[0] = n_HII_grid[k] y0[1] = n_HeII_grid[k] y0[2] = n_HeIII_grid[k] y0[3] = T_grid[k] t_start_solve_TIME = datetime.datetime.now() sol = integrate.solve_ivp(rhs, [l * dt_init.value, (l + 1) * dt_init.value], y0, method=method) n_HII_grid[k] = sol.y[0, -1] n_HeII_grid[k] = sol.y[1, -1] n_HeIII_grid[k] = sol.y[2, -1] T_grid[k] = nan_to_num(sol.y[3, -1]) if isnan(n_HII_grid[k]): n_HII_grid[k] = n_H(zstar, C) if n_HII_grid[k] > n_H(zstar, C): n_HII_grid[k] = n_H(zstar, C) if n_HeII_grid[k] > n_He(zstar, C): n_HeII_grid[k] = n_He(zstar, C) n_HeIII_grid[k] = 0 if isnan(n_HeIII_grid[k]): n_HeIII_grid[k] = n_He(zstar, C) if n_HeIII_grid[k] > n_He(zstar, C): n_HeIII_grid[k] = n_He(zstar, C) n_HeII_grid[k] = 0 if isnan(n_HeII_grid[k]): print('Warning: Calculations contains NaNs.') n_HeII_grid[k] = n_He(zstar, C)-n_HeIII_grid[k] time_grid.append(l * self.grid_param['dt_init'].value) Ion_front_grid.append(find_Ifront(n_HII_grid/n_H(zstar,C), r_grid, zstar)) l += 1 r1 = find_Ifront(n_HII0/n_H(zstar,C), r_grid0, zstar, show=True) r2 = find_Ifront(n_HII_grid/n_H(zstar,C), r_grid, zstar, show=True) time_step = datetime.datetime.now() print('The accuracy is: ', abs((r1 - r2) / min(abs(r1), abs(r2))), ' -> 0.05 needed. It took : ', time_step-t_start_solver) if abs((r1 - r2) / min(abs(r1), abs(r2))) > 0.05 or r2 == self.r_start.value: if r2 == self.r_start.value: print('Ionization front is still at the starting point. Starting again with smaller steps... ') r_grid0 = copy(r_grid[:]) print('old:', r_grid0.size) r_grid = adaptive_mesh(r_grid0,1-n_HII_grid/n_H(zstar, C), 0.01, 0.99) print('new:', r_grid.size) else: time_grid = array([time_grid]) time_grid = time_grid.reshape(time_grid.size, 1) Ion_front_grid = array([Ion_front_grid]) Ion_front_grid = Ion_front_grid.reshape(Ion_front_grid.size, 1) time_end_solve = datetime.datetime.now() print('solver took :', time_end_solve-t_start_solver) break age = pl.age(self.z) age = age.to(u.s) age += self.evol func = lambda z: pl.age(z).to(u.s).value - age.value znow = fsolve(func, z_reion) self.n_HI_grid = n_H(znow,self.C) - n_HII_grid self.n_HII_grid = n_HII_grid self.n_HeI_grid = n_He(znow,self.C) - n_HeII_grid - n_HeIII_grid self.n_HeII_grid = n_HeII_grid self.n_HeIII_grid = n_HeIII_grid self.n_H = n_H(znow,self.C) self.n_He = n_He(znow,self.C) self.T_grid = T_grid self.r_grid = r_grid self.time_grid = time_grid
def backsplash_analysis_single_cluster(hdf_dir, cluster_name, plot_dir, snap): """ Backsplash analysis contamination for single cluster""" print('Analysing single object:', cluster_name) # Read in data. t0 = time.time() halo_data = pd.read_hdf(hdf_dir + cluster_name + '_tracking.hdf5', 'halo_evo', mode='r', where="""var in \ [x_comov,y_comov,z_comov,redshift,snapid,hmass,gmass,mtot]""") cluster_data = pd.read_hdf(hdf_dir + cluster_name + '_tracking.hdf5', 'cluster_evo', mode='r', where='var in [x_comov,y_comov,z_comov,rvir,redshift,hmass]') cluster_data = cluster_data.sort_index() print('Done data read in', time.time() - t0, 's') # Parameters redshift = cluster_data.loc[snap, 'redshift'] rvir = cluster_data.loc[snap, 'rvir'] masscut = 0 # 100 * 9e8 # Calculate d_min vs d_z d_min, d_z, d = calculate_dmin_dz(halo_data, cluster_data, snap, rvir) # Find snapshot at which d_min occurs. idx_mins = d.groupby(['halo_id']).idxmin().values snap_mins = [x[0] for x in idx_mins] # Find properties of things at snapshot of d_min for later selection. # Pandas only slices unique snapshots, need loop. unique_snap_mins = np.unique(snap_mins) cluster_rvir_snaps = cluster_data.loc[snap_mins, 'rvir'].values redshift_at_snaps = cluster_data.loc[snap_mins, 'redshift'].values cluster_rvir_mins = np.zeros(np.size(snap_mins)) dmin_redshifts = np.zeros(np.size(snap_mins)) for i in range(0, np.size(unique_snap_mins)): ith_snap = unique_snap_mins[i] cluster_rvir_mins += (snap_mins == ith_snap) * \ cluster_rvir_snaps[i] dmin_redshifts += (snap_mins == ith_snap) * \ redshift_at_snaps[i] # Select out backsplash and calcukate percent. region_select, backsplash_select = select_backsplash( halo_data, snap, masscut, d_z, d_min) backsplash_percentage = calculate_backsplash_percent(halo_data, region_select, backsplash_select, snap) # Plot parameters halo_mass = halo_data.loc[snap, :, 'hmass'] gfrac = (halo_data.loc[snap, :, 'gmass'].values / halo_data.loc[snap, :, 'mtot'].values) time_since_dmin = WMAP7.age(redshift) - WMAP7.age(dmin_redshifts) # Plot parameters prop = [halo_mass.values, gfrac, time_since_dmin] plot_vmin = [halo_mass.values.min(), 1e-4, 1e-7] plot_vmax = [halo_mass.values.max(), gfrac.max(), 8] cbar_label = ['Halo mass', 'Gas fraction', r'Time since $D_{min}$ [Gyr]'] scat_cmap = ['Blues', 'Greens', 'Purples'] save_label = ['hm_', 'gfrac_', 'time_'] # Plots of various properties. for i in range(0, len(prop)): dmin_vs_dz(snap, redshift, d_z, d_min, cluster_name, backsplash_percentage, prop[i], plot_vmin[i], plot_vmax[i], cbar_label[i], scat_cmap[i], save_label[i], plot_dir) projected_backsplash_cluster(snap, redshift, plot_dir, cluster_name, halo_data, cluster_data, d_z, d_min)
if (args.calibration_run == 'True'): def epsilon_efficency_fct(Mh_in, size_in=1.0): ''' This function returns an efficency from the calibrated distribution for a given halo mass. ''' return (np.zeros(size_in)) else: epsilon_efficency_fct = read_in_efficency.read_in_efficency( path_SFH_cat + args.filename_efficiency) # get SFH: random burst in last step t_snapshots = 10**3 * cosmo.age(z_table_in).value # in Myr # split halo in bins def get_halo_ids(number_of_bins, idx_halo_key=1.0, **kwargs): idx_all_halos = range(len(M_table_in)) idx_bins_all_halos = np.array_split(idx_all_halos, number_of_bins) print idx_bins_all_halos[int(float(idx_halo_key)) - 1] return (idx_bins_all_halos[int(float(idx_halo_key)) - 1] ) # -1 since slurm counts from 1 (and not from 0) idx_halo_considered = get_halo_ids(**run_params) # loop over all halos
def solve(self): """ Solves the radiative transfer equation for the given source and the parameters. The solver calls grid parameters and initializes the starting grid with the initial conditions for the densities and the temperature. Using the time step, the radiative transfer equations are used to update the k-th cell from the radial grid for a certain time step dt_init. Then the solver moves on to the (k+1)-th cell, and uses the values calculated from the k-th cell in order to calculate the optical depth, which requires information of the densities from all prior cells. For each cell, we sum up the three densities from the starting cell up to the current cell and use these values to evaluate the 12 integrals in the equations, which is done by interpolation of the tables we generated previously. After each cell is updated for some time dt_init, we start again with the first cell and use the calculation from the previous time step as the initial condition and repeat the same process until the radial cells are updated l times such that l*dt_init has reached the evolution time. After the solver is finished we compare the ionization fronts of two consecutive runs and require an accuracy of 5% in order to finish the calculations. If the accuracy is not reached we store the values from the run and start again with time step size dt_init/2 and a radial grid with half the step size from the previous run. This process is repeated until the desired accuracy is reached. """ print('Solving the radiative equations...') self.initialise_grid_param() z_reion = self.grid_param['z_reion'] gamma_2c = self.grid_param['gamma_2c'] T_gamma = self.grid_param['T_gamma'] dt_init = self.grid_param['dt_init'] dn = self.grid_param['dn'] r_grid0 = log10( logspace(log10(self.grid_param['r_start'].value), log10(self.grid_param['r_end'].value), dn)) n_HII_grid = zeros_like(r_grid0) * cm_3 n_HeII_grid = zeros_like(r_grid0) * cm_3 n_HeIII_grid = zeros_like(r_grid0) * cm_3 while True: time_grid = [] Ion_front_grid = [] dn = self.grid_param['dn'] r_grid = log10( logspace(log10(self.grid_param['r_start'].value), log10(self.grid_param['r_end'].value), dn)) n_HII0 = copy(n_HII_grid[:]) * cm_3 n_HeII0 = copy(n_HeII_grid[:]) * cm_3 n_HeIII0 = copy(n_HeIII_grid[:]) * cm_3 n_HII_grid = zeros_like(r_grid) * cm_3 n_HeII_grid = zeros_like(r_grid) * cm_3 n_HeIII_grid = zeros_like(r_grid) * cm_3 T_grid = zeros_like(r_grid) * u.K T_grid += T_gamma * (1 + z_reion)**1 / (1 + 250) l = 0 print('Number of time steps: ', int(math.ceil(self.grid_param['t_life'] / dt_init.value))) N = r_grid.size n_HI = linspace(0, 10000 * (N - 1) * n_H(z_reion), 20) n_HeI = linspace(0, 10000 * (N - 1) * n_He(z_reion), 20) n_HeII = linspace(0, 10000 * (N - 1) * n_He(z_reion), 20) points = (n_HI, n_HeI, n_HeII) self.create_table() Gamma_info = self.Gamma_grid_info['Gamma'] JHI_1, JHI_2, JHI_3 = Gamma_info['HI_1'], Gamma_info[ 'HI_2'], Gamma_info['HI_3'] JHeI_1, JHeI_2, JHeI_3, JHeII = Gamma_info['HeI_1'], Gamma_info[ 'HeI_2'], Gamma_info['HeI_3'], Gamma_info['HeII'] JT_HI_1, JT_HeI_1, JT_HeII_1 = Gamma_info['T_HI_1'], Gamma_info[ 'T_HeI_1'], Gamma_info['T_HeII_1'] JT_2a, JT_2b = Gamma_info['T_2a'], Gamma_info['T_2b'] while l * self.grid_param['dt_init'].value <= self.grid_param[ 't_life']: print('Current Time step: ', l) # Calculate the redshift z(t) age = pl.age(z_reion) age = age.to(u.s) age += l * self.grid_param['dt_init'] func = lambda z: pl.age(z).to(u.s).value - age.value zstar = fsolve(func, z_reion) # Initialize the values to evaluate the integrals K_HI = 0 * cm_3 K_HeI = 0 * cm_3 K_HeII = 0 * cm_3 for k in (arange(0, r_grid.size, 1)): lgdr = r_grid[1] - r_grid[0] if k > 0: n_HI00 = n_H(z_reion) - n_HII_grid[k - 1] if n_HI00 < 0: n_HI00 = 0 n_HeI00 = n_He(z_reion) - n_HeII_grid[ k - 1] - n_HeIII_grid[k - 1] if n_HeI00 < 0: n_HeI00 = 0 * cm_3 K_HI += nan_to_num(n_HI00) * 10**(lgdr * (k - 1)) K_HeI += nan_to_num(n_HeI00) * 10**(lgdr * (k - 1)) K_HeII += abs(nan_to_num( n_HeII_grid[k - 1])) * 10**(lgdr * (k - 1)) if self.lifetime is not None and l * self.grid_param[ 'dt_init'].value > ( (lifetime * u.Myr).to(u.s)).value: I1_HI = 0 * s1 I2_HI = 0 * s1 I3_HI = 0 * s1 I1_HeI = 0 * s1 I2_HeI = 0 * s1 I3_HeI = 0 * s1 I1_HeII = 0 * s1 I1_T_HI = 0 * s1 I1_T_HeI = 0 * s1 I1_T_HeII = 0 * s1 I2_Ta = 0 * s1 I2_Tb = 0 * s1 else: r2 = (4 * pi * (10**r_grid[k])**2) I1_HI = interpolate.interpn(points, JHI_1, (K_HI, K_HeI, K_HeII), method='linear') / r2 I2_HI = interpolate.interpn(points, JHI_2, (K_HI, K_HeI, K_HeII), method='linear') / r2 I3_HI = interpolate.interpn(points, JHI_3, (K_HI, K_HeI, K_HeII), method='linear') / r2 I1_HeI = interpolate.interpn(points, JHeI_1, (K_HI, K_HeI, K_HeII), method='linear') / r2 I2_HeI = interpolate.interpn(points, JHeI_2, (K_HI, K_HeI, K_HeII), method='linear') / r2 I3_HeI = interpolate.interpn(points, JHeI_3, (K_HI, K_HeI, K_HeII), method='linear') / r2 I1_HeII = interpolate.interpn(points, JHeII, (K_HI, K_HeI, K_HeII), method='linear') / r2 I1_T_HI = interpolate.interpn(points, JT_HI_1, (K_HI, K_HeI, K_HeII), method='linear') / r2 I1_T_HeI = interpolate.interpn(points, JT_HeI_1, (K_HI, K_HeI, K_HeII), method='linear') / r2 I1_T_HeII = interpolate.interpn(points, JT_HeII_1, (K_HI, K_HeI, K_HeII), method='linear') / r2 I2_Ta = interpolate.interpn(points, JT_2a, (K_HI, K_HeI, K_HeII), method='linear') / r2 I2_Tb = interpolate.interpn(points, JT_2b, (K_HI, K_HeI, K_HeII), method='linear') / r2 def gamma_HI(n_HIIx, n_HeIx, n_HeIIx, n_HeIIIx, Tx): """ Calculate gamma_HI given the densities and the temperature Parameters ---------- n_HIIx : float Ionized hydrogen density in cm**-3. n_HeIx : float Neutral helium density in cm**-3. n_HeIIx : float Single ionized helium density in cm**-3. n_HeIIIx : float Double ionized helium density in cm**-3. Tx : float Temperature of the gas in K. Returns ------- float Gamma_HI for the radiative transfer equation. """ n_e = n_HIIx + n_HeIIx + 2 * n_HeIIIx if n_H(z_reion).value == n_HIIx or n_He( z_reion).value - n_HeIIx - n_HeIIIx == 0: factor = 0 else: factor = abs( (n_He(z_reion).value - n_HeIIx - n_HeIIIx) / (n_H(z_reion).value - n_HIIx)) return (gamma_2c.value + beta_HI(Tx) * n_e + I1_HI + f_H(n_HIIx, z_reion) * I2_HI + f_H(n_HIIx, z_reion) * factor * I3_HI) def gamma_HeI(n_HIIx, n_HeIx, n_HeIIx, n_HeIIIx): """ Calculate gamma_HeI given the densities and the temperature Parameters ---------- n_HIIx : float Ionized hydrogen density in cm**-3. n_HeIx : float Neutral helium density in cm**-3. n_HeIIx : float Single ionized helium density in cm**-3. n_HeIIIx : float Double ionized helium density in cm**-3. Returns ------- float Gamma_HeI for the radiative transfer equation. """ if n_H(z_reion).value == n_HIIx or n_He( z_reion).value - n_HeIIx - n_HeIIIx == 0: factor = 0 else: factor = abs( nan_to_num(n_H(z_reion).value - n_HIIx) / (n_He(z_reion).value - n_HeIIx - n_HeIIIx)) return (I1_HeI + f_He(n_HIIx, z_reion) * I2_HeI + f_He(n_HIIx, z_reion) * factor * I3_HeI) def gamma_HeII(n_HIIx, n_HeIx, n_HeIIx, n_HeIIIx): """ Calculate gamma_HeII given the densities and the temperature Parameters ---------- n_HIIx : float Ionized hydrogen density in cm**-3. n_HeIx : float Neutral helium density in cm**-3. n_HeIIx : float Single ionized helium density in cm**-3. n_HeIIIx : float Double ionized helium density in cm**-3. Returns ------- float Gamma_HeII for the radiative transfer equation. """ return I1_HeII def rhs(t, n): """ Calculate the RHS of the radiative transfer equations. RHS of the coupled nHII, n_HeII, n_HeIII and T equations. The equations are labelled as A,B,C, and D and the rest of the variables are the terms contained in the respective equations. Parameters ---------- t : float Time of evaluation in s. n : array-like 1-D array containing the variables nHII, nHeII, nHeIII, T for evaluating the RHS. Returns ------- array_like The RHS of the radiative transfer equations. """ n_HIx = n_H(z_reion).value - n[0] n_HIIx = n[0] if n_HIx < 0: n_HIx = 0 n_HIIx = n_H(z_reion).value if n_HIIx > n_H(z_reion).value: n_HIIx = n_H(z_reion).value n_HIx = 0 if n_HIIx < 0: n_HIIx = 0 n_HIx = n_H(z_reion).value n_HeIx = n_He(z_reion).value - (n[1] + n[2]) n_HeIIx = n[1] n_HeIIIx = n[2] if n_HeIx > n_He(z_reion).value: n_HeIx = n_He(z_reion).value n_HeIIx = 0 n_HeIIIx = 0 if n_HeIx < 0: n_HeIx = 0 if n_HeIIx > n_He(z_reion).value: n_HeIIx = n_He(z_reion).value n_HeIx = 0 n_HeIIIx = 0 if n_HeIIx < 0: n_HeIIx = 0 if n_HeIIIx > n_He(z_reion).value: n_HeIIIx = n_He(z_reion).value n_HeIIx = 0 n_HeIx = 0 if n_HeIIIx < 0: n_HeIIIx = 0 Tx = n[3] n_ee = n_HIIx + n_HeIIx + 2 * n_HeIIIx mu = (n_H(z_reion).value + 4 * n_He(z_reion).value) / ( n_H(z_reion).value + n_He(z_reion).value + n_ee) n_B = n_H(z_reion).value + n_He(z_reion).value + n_ee A1_HI = xi_HI(Tx) * n_HIx * n_ee A1_HeI = xi_HeI(Tx) * n_HeIx * n_ee A1_HeII = xi_HeII(Tx) * n_HeIIx * n_ee A2_HII = eta_HII(Tx) * n_HIIx * n_ee A2_HeII = eta_HeII(Tx) * n_HeIIx * n_ee A2_HeIII = eta_HeIII(Tx) * n_HeIIIx * n_ee A3 = omega_HeII(Tx) * n_ee * n_HeIIIx A4_HI = psi_HI(Tx) * n_HIx * n_ee A4_HeI = psi_HeI(Tx, n_ee, n_HeIIx) * n_ee A4_HeII = psi_HeII(Tx) * n_HeIIx * n_ee A5 = theta_ff(Tx) * (n_HIIx + n_HeIIx + 4 * n_HeIIIx) * n_ee H = pl.H(zstar) H = H.to(u.s**-1) A6 = (2 * H * kb * Tx * u.K * n_B / mu).value A = gamma_HI(n_HIIx, n_HeIx, n_HeIIx, n_HeIIIx, Tx ) * n_HIx - alpha_HII(Tx) * n_HIIx * n_ee B = gamma_HeI( n_HIIx, n_HeIx, n_HeIIx, n_HeIIIx ) * n_HeIx + beta_HeI(Tx) * n_ee * n_HeIx - beta_HeII( Tx) * n_ee * n_HeIIx - alpha_HeII( Tx) * n_ee * n_HeIIx + alpha_HeIII( Tx) * n_ee * n_HeIIIx - zeta_HeII( Tx) * n_ee * n_HeIIx C = gamma_HeII(n_HIIx, n_HeIx, n_HeIIx, n_HeIIIx) * n_HeIIx + beta_HeII( Tx) * n_ee * n_HeIIx - alpha_HeIII( Tx) * n_ee * n_HeIIIx Dd = (Tx / mu) * ( -mu / (n_H(z_reion).value + n_He(z_reion).value + n_ee)) * (A + B + 2 * C) D = (2 / 3) * mu / (kb.value * n_B) * ( f_Heat(n_HIIx, z_reion) * n_HIx * I1_T_HI + f_Heat(n_HIIx, z_reion) * n_HeIx * I1_T_HeI + f_Heat(n_HIIx, z_reion) * n_HeIIx * I1_T_HeII + sigma_s.value * n_ee / (m_e * c**2).value * (I2_Ta + Tx * I2_Tb) - (A1_HI + A1_HeI + A1_HeII + A2_HII + A2_HeII + A2_HeIII + A3 + A4_HI + A4_HeI + A4_HeII + A5 + A6)) + Dd return ravel(array([A, B, C, D])) y0 = zeros(4) y0[0] = n_HII_grid[k].value y0[1] = n_HeII_grid[k].value y0[2] = n_HeIII_grid[k].value y0[3] = T_grid[k].value sol = integrate.solve_ivp( rhs, [l * dt_init.value, (l + 1) * dt_init.value], y0, method='LSODA') n_HII_grid[k] = sol.y[0, -1] * cm_3 if n_HII_grid[k] > n_H(z_reion): n_HII_grid[k] = n_H(z_reion) n_HeII_grid[k] = sol.y[1, -1] * cm_3 n_HeIII_grid[k] = sol.y[2, -1] * cm_3 if n_HeIII_grid[k] > n_He(z_reion): n_HeIII_grid[k] = n_He(z_reion) if n_He(z_reion) - n_HeII_grid[k] - n_HeIII_grid[k] < 0: n_HeII_grid[k] = n_He(z_reion) - n_HeIII_grid[k] T_grid[k] = sol.y[3, -1] * u.K time_grid.append(l * self.grid_param['dt_init'].value) Ion_front_grid.append(find_Ifront(n_HII_grid, r_grid, z_reion)) l += 1 r1 = find_Ifront(n_HII0, 10**r_grid0, z_reion, show=True) r2 = find_Ifront(n_HII_grid, 10**r_grid, z_reion, show=True) print('The accuracy is: ', abs((r1 - r2) / min(abs(r1), abs(r2))), ' -> 0.05 needed') if abs((r1 - r2) / min(abs(r1), abs(r2))) > 0.05 or r2 == self.r_start.value: if r2 == self.r_start.value: print( 'Ionization front is still at the starting point. Starting again with smaller steps...' ) r_grid0 = log10( logspace(log10(self.grid_param['r_start'].value), log10(self.grid_param['r_end'].value), dn)) self.grid_param['dn'] *= 2 self.grid_param['dt_init'] /= 2 else: print('... radiative equations solved') break self.n_HI_grid = n_H(self.z) - n_HII_grid self.n_HII_grid = n_HII_grid self.n_HeI_grid = n_He(self.z) - n_HeII_grid - n_HeIII_grid self.n_HeII_grid = n_HeII_grid self.n_HeIII_grid = n_HeIII_grid self.n_H = n_H(self.z) self.n_He = n_He(self.z) self.T_grid = T_grid self.r_grid = r_grid self.time_grid = array([time_grid]) self.Ion_front_grid = array([Ion_front_grid])