Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
    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 = {}
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
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)
Ejemplo n.º 7
0
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
Ejemplo n.º 8
0
    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])