Esempio n. 1
0
        def _check_if_fields_saved(dsname, dataset):

            if not all([
                    y in dataset.keys()
                    for y in ['species', 'metal_species', 'abundance_fields']
            ]):

                gal = Galaxy(dsname)
                if ABUNDANCES is None:
                    abundance_fields = utilities.abundance_ratios_from_fields(
                        gal.ds.derived_field_list,
                        select_denom=ABUNDANCE_DENOM)
                else:
                    abundance_fields = ABUNDANCES
                species = utilities.species_from_fields(
                    gal.ds.field_list, include_primordial=True)
                metal_species = utilities.species_from_fields(
                    gal.ds.field_list)

                # save field names
                if not ('species' in dataset.keys()):
                    dataset['species'] = species
                if not ('metal_species' in dataset.keys()):
                    dataset['metal_species'] = metal_species
                if not ('abundance_fields' in dataset.keys()):
                    dataset['abundance_fields'] = abundance_fields

                del (gal)
                return
Esempio n. 2
0
def read_all_data(directory='.'):

    # First lets do some hacky BS
    bash_commands = [
        "grep --no-filename -e '^StellarAbundances P' ./enzo_job*.out  > SA_temp.dat",
        'sed -e "s/StellarAbundances P(//g" -i SA_temp.dat', "awk " + "'{$1=" +
        '""; print $0}' + "' SA_temp.dat > StellarAbundances.dat",
        "rm SA_temp.dat"
    ]

    for bc in bash_commands:
        subprocess.call(bc, shell=True)

    try:
        # need simulation parameter file to get column names
        ds_names = glob.glob(directory + "/DD????/DD????")
        ds = yt.load(ds_names[-1])
        species = ['H', 'He'] + species_from_fields(ds.field_list)
    except:
        species = [
            'H', 'He', 'C', 'N', 'O', 'K', 'Fe', 'Zn', 'Sr', 'Ba', 'AGB',
            'PopIII', 'SNIa', 'SNII'
        ]

    _col_names = _base_col_names + species
    _dtypes = _base_dtypes + [float] * len(species)
    _ndtypes = [(x, y) for x, y in zip(_col_names, _dtypes)]

    data = np.genfromtxt(directory + '/StellarAbundances.dat',
                         dtype=_ndtypes,
                         invalid_raise=False)

    return data
Esempio n. 3
0
def generate_all_stats(outfile='gas_abundances.h5',
                       dir='./abundances/',
                       overwrite=False,
                       nproc=1,
                       output_interval=None):
    """
    For all data files, generate gas abundance statistics for all
    element fractions and abundance ratios (as defined below). This is
    an expensive operation.


    """

    if not os.path.exists(dir):
        os.makedirs(dir)

    hdf5_filename = dir + outfile

    if not os.path.isfile(hdf5_filename) or overwrite:
        hf = h5py.File(hdf5_filename, 'w')
        hf.close()

    # set to some large number if needed and not set
    if (nproc > 1) and (output_interval is None):
        output_interval = 9999

    hf = dd.io.load(hdf5_filename)

    ds_list = np.sort( glob.glob('./DD???0/DD???0') + glob.glob('./DD???2/DD???2') + glob.glob('./DD???4/DD???4') +\
                       glob.glob('./DD???6/DD???6') + glob.glob('./DD???8/DD???8'))

    print("WARNING: Only doing limited number of outputs for ease of use")

    for i, dsname in enumerate(ds_list):
        ds = yt.load(dsname)
        if ds.parameters['NumberOfParticles'] > 0:
            start_index = i
            del (ds)
            break
        del (ds)

    times = np.zeros(np.size(ds_list))
    ds_list = ds_list[start_index:]
    times = times[start_index:]

    # get the fields
    ds = yt.load(ds_list[0])
    metals = utilities.species_from_fields(ds.field_list)

    # additional fraction fields for the non-equillibrium chemistry species
    if NONEQFIELDS is None:
        fraction_fields = [
            'H_p0_fraction', 'H_p1_fraction', 'He_p0_fraction',
            'He_p1_fraction', 'He_p2_fraction', 'H2_fraction'
        ]
    else:
        fraction_fields = NONEQFIELDS

    if not (METALS is None):
        metals = METALS

    for m in metals:
        fraction_fields += [m + '_Fraction']

    # make the abundance ratio fields
    #   - should do everything over H
    #   - should do everything over Fe
    #   - should do everything over Mg

    # loop through all data files
    if nproc == 1:
        for i, dsname in enumerate(ds_list):
            print(i, dsname)
            groupname = dsname.rsplit('/')[1]
            gal = Galaxy(groupname)

            # if first loop, define the fields
            if i == 0:
                # limit ourselves to Fe and H demoninators for now to speed up computation
                if ABUNDANCES is None:
                    abundance_fields = utilities.abundance_ratios_from_fields(
                        gal.ds.derived_field_list,
                        select_denom=ABUNDANCE_DENOM)
                else:
                    abundance_fields = ABUNDANCES

                species = utilities.species_from_fields(
                    gal.ds.field_list, include_primordial=True)
                metal_species = utilities.species_from_fields(
                    gal.ds.field_list)

            # don't recompute things unless overwrite is set
            if groupname in hf.keys() and (not overwrite):
                continue

            hf[groupname] = {}  # make an empty key for this group
            g = hf[groupname]

            g['general'] = {}
            g['general']['Time'] = gal.ds.current_time.convert_to_units(
                'Myr').value

            # generalized function to loop through all mask types and compute stats
            gas_data = compute_stats_all_masks(
                gal,
                fraction_fields=fraction_fields,
                abundance_fields=abundance_fields)

            # make the stats group and the histogram group
            for k in gas_data.keys():
                g[k] = gas_data[k]

            del (gal)

        # save field names
        if not ('species' in hf.keys()):
            hf['species'] = species
        if not ('metal_species' in hf.keys()):
            hf['metal_species'] = metal_species
        if not ('abundance_fields' in hf.keys()):
            hf['abundance_fields'] = abundance_fields

    else:  # parallel

        # select out data sets that already exist in output
        if not overwrite:
            ds_list = [
                x for x in ds_list
                if (not any([x.rsplit('/')[1] in y for y in hf.keys()]))
            ]

        # construct the pool, and map the results to a holder
        #   pool splits computation among processors

        def _check_if_fields_saved(dsname, dataset):

            if not all([
                    y in dataset.keys()
                    for y in ['species', 'metal_species', 'abundance_fields']
            ]):

                gal = Galaxy(dsname)
                if ABUNDANCES is None:
                    abundance_fields = utilities.abundance_ratios_from_fields(
                        gal.ds.derived_field_list,
                        select_denom=ABUNDANCE_DENOM)
                else:
                    abundance_fields = ABUNDANCES
                species = utilities.species_from_fields(
                    gal.ds.field_list, include_primordial=True)
                metal_species = utilities.species_from_fields(
                    gal.ds.field_list)

                # save field names
                if not ('species' in dataset.keys()):
                    dataset['species'] = species
                if not ('metal_species' in dataset.keys()):
                    dataset['metal_species'] = metal_species
                if not ('abundance_fields' in dataset.keys()):
                    dataset['abundance_fields'] = abundance_fields

                del (gal)
                return

        #
        # do this in a loop, so we can save progressively once a full set of processors is complete
        #   saves you if there is a crash (kinda). This way we do better memory management if
        #   operating on many large datasets.
        #
        iter_count = 0
        for sub_list in itertools.zip_longest(*(iter(ds_list), ) * nproc):

            sub_list = list(sub_list)
            sub_list = [s for s in sub_list
                        if s is not None]  # remove None values
            reduced_nproc = np.min([len(sub_list),
                                    nproc])  # only run on needed processors

            pool = Pool(reduced_nproc)
            results = pool.map_async(
                _parallel_loop_star,
                zip(sub_list, itertools.repeat(fraction_fields)))
            pool.close()  # no more processes
            pool.join()  # wait and join running processes

            # gather results and add to output
            for r in results.get():
                hf[list(r.keys())[0]] = r[list(r.keys())[0]]

            # save output!
            if not (iter_count % output_interval):
                _check_if_fields_saved(ds_list[0].split('/')[1], hf)
                dd.io.save(hdf5_filename, hf)

            del (results)
            iter_count = iter_count + 1

        # define these fields (which are defined in the Pool funtion but don't want to
        # deal with passing this back) ------
        if len(ds_list) > 0:

            _check_if_fields_saved(ds_list[0].split('/')[1], hf)

    #
    # Output
    #
    dd.io.save(hdf5_filename, hf)

    return
Esempio n. 4
0
def _parallel_loop(dsname, fraction_fields):

    groupname = dsname.rsplit('/')[1]
    print("starting computation on ", groupname)
    gal = Galaxy(groupname)

    #
    #
    #
    #
    # limit ourselves to Fe and H demoninators for now to speed up computation
    if ABUNDANCES is None:
        abundance_fields = utilities.abundance_ratios_from_fields(
            gal.ds.derived_field_list, select_denom=ABUNDANCE_DENOM)
    else:
        abundance_fields = ABUNDANCES


#    abundance_fields = ['O_over_H']
    species = utilities.species_from_fields(gal.ds.field_list,
                                            include_primordial=True)
    metal_species = utilities.species_from_fields(gal.ds.field_list)

    #
    #    don't recompute things unless overwrite is set
    #
    #    if (not overwrite) and (existing_keys is None):
    #        print "Cannot check for overwrites without knowing existing data"
    #        raise ValueError
    #
    #
    #        if (groupname in existing_keys) and (not overwrite):
    #           return {groupname + '_skip_this_one' : {}} # g['skip_this_one_' + dsname]

    combine_fields = None
    combine_fname = './combine_elements_gas_abundances.dat'
    if os.path.isfile(combine_fname):
        combine_fields = np.genfromtxt(combine_fname, dtype='str')

    #print(combine_fields)

    dictionary = {groupname: {}}
    #hf[groupname] = {} # make an empty key for this group
    g = dictionary[groupname]

    g['general'] = {}
    g['general']['Time'] = gal.ds.current_time.convert_to_units('Myr').value
    # generalized function to loop through all mask types and compute stats
    gas_data = compute_stats_all_masks(gal,
                                       fraction_fields=fraction_fields,
                                       abundance_fields=abundance_fields,
                                       combine_fields=combine_fields)

    # make the stats group and the histogram group
    for k in gas_data.keys():
        g[k] = gas_data[k]

    del (gal)

    print("ending computation on ", groupname)

    return dictionary
Esempio n. 5
0
def check_all_masses(ds, data, ds0=None, time_cut=-1.0):

    pt = data['particle_type']

    # cut out DM
    select = pt >= 11

    pt = pt[select]

    bm = data['birth_mass'][select].value
    pm = data['particle_mass'][select].convert_to_units('Msun').value
    z = data['metallicity_fraction'][select].value

    elements = util.species_from_fields(ds.field_list)

    all_stars = generate_model_stars(
        bm,
        z,
        abund=elements,
        include_popIII=ds.parameters['IndividualStarPopIIIFormation'])

    lifetime = data['dynamical_time'][select].convert_to_units('Myr')
    birth = data['creation_time'][select].convert_to_units('Myr')
    age = ds.current_time.convert_to_units('Myr') - birth

    model_wind_ejecta = {}  # total_wind_ejecta
    for k in all_stars[0].wind_ejecta_masses().keys():
        model_wind_ejecta[k] = np.array(
            [x.wind_ejecta_masses()[k] for x in all_stars])

    model_sn_ejecta = {}
    for k in all_stars[0].sn_ejecta_masses.keys():
        model_sn_ejecta[k] = np.array(
            [x.sn_ejecta_masses[k] for x in all_stars])

    # correct for AGB stars that haven't died
    AGB = (bm < 8.0) * (pt == 11)
    select = (bm > 8.0) * (pt == 11)
    factor = age / lifetime
    factor[factor > 1.0] = 1.0

    time_select = birth > time_cut

    #
    # Apply correction and zero out SN abundances for stars that have not gone SNe
    #
    for k in list(model_wind_ejecta.keys()):
        model_wind_ejecta[k][AGB] = 0.0
        model_sn_ejecta[k][(pt == 11)] = 0.0  # regular stars
        model_sn_ejecta[k][(pt == 14)] = 0.0  # popIII stars
        model_wind_ejecta[k][
            select] = model_wind_ejecta[k][select] * factor[select]

    total_model_ejecta = {}
    for k in list(model_wind_ejecta.keys()):
        total_model_ejecta[k] = np.sum(
            model_sn_ejecta[k][time_select]) + np.sum(
                model_wind_ejecta[k][time_select])

    #print("xxxxxx", np.sum(model_sn_ejecta['O']), np.sum(model_sn_ejecta['O'][bm>8.0]), np.sum(model_sn_ejecta['O'][bm<8.0]))
    # construct the indivdual mode dictionary
    separate_mode_ejecta = {
        'AGB': {},
        'SWind': {},
        'SNII': {},
        'SNIa': {},
        'PopIII': {},
        'Total': {}
    }
    for k in list(model_wind_ejecta.keys()):
        separate_mode_ejecta['PopIII'][k] = np.sum(
            model_sn_ejecta[k][(pt == 13) * (z < 2.2E-6)])
        separate_mode_ejecta['SNII'][k] = np.sum(
            model_sn_ejecta[k][(bm > 8.0) * (z > 2.2E-6)])
        separate_mode_ejecta['SNIa'][k] = np.sum(
            model_sn_ejecta[k][(bm < 8.0) * (z > 2.2E-6)])
        separate_mode_ejecta['SWind'][k] = np.sum(
            model_wind_ejecta[k][bm > 8.0])
        separate_mode_ejecta['AGB'][k] = np.sum(model_wind_ejecta[k][bm < 8.0])
        separate_mode_ejecta['Total'][k] = np.sum([
            separate_mode_ejecta[x][k]
            for x in ['AGB', 'SWind', 'SNII', 'SNIa', 'PopIII']
        ])
    for k in list(separate_mode_ejecta.keys()):
        separate_mode_ejecta[k]['Total Tracked Metals'] = np.sum([
            separate_mode_ejecta[k][x]
            for x in list(separate_mode_ejecta[k].keys())
            if (not x in ['m_tot', 'm_metal', 'H', 'He'])
        ])

    if os.path.exists(str(ds) + '_galaxy_data.h5'):
        dd_data = dd.io.load(str(ds) + '_galaxy_data.h5')
        dd_data['gas_meta_data']['masses']['Type'] = separate_mode_ejecta
        dd.io.save(str(ds) + '_galaxy_data.h5', dd_data)

    # now do this for the individual abundances on grid:
    grid_masses = {}
    for k in list(model_wind_ejecta.keys()):
        if k is 'm_tot' or k is 'm_metal':
            continue

        grid_masses[k] = np.sum(data[k + '_Density'] * ds.mass_unit / ds.length_unit**3 *\
                                   data['cell_volume']).convert_to_units('Msun').value

        if not (ds0 is None):
            grid_masses[k] = grid_masses[k] - np.sum(ds0[k + '_Density'] * ds0.mass_unit / ds0.length_unit**3 *\
                                       ds0['cell_volume']).convert_to_units('Msun').value


#        else:
#            grid_masses[k] = grid_masses[k] - 1.0E-10 * np.sum(data['cell_mass'].to('Msun')).value

    gal = Galaxy(str(ds))
    outflow_masses = gal.boundary_mass_flux

    #print total_model_ejecta
    #print grid_masses
    #print outflow_masses

    for k in separate_mode_ejecta.keys():
        print(k, separate_mode_ejecta[k]['O'], separate_mode_ejecta[k]['N'])

    print(list(grid_masses.keys()))
    print(
        "Element Total_on_Grid Total_Outflow Sum_Injected Total_model_mass Percent_error"
    )
    for k in list(grid_masses.keys()):
        okey = k + '_Density'
        error = 100 * (outflow_masses[okey] + grid_masses[k] -
                       total_model_ejecta[k]) / total_model_ejecta[k]
        print("%2s     %8.8E %8.8E %8.8E %8.8E %4.4f" %
              (k, grid_masses[k], outflow_masses[okey], grid_masses[k] +
               outflow_masses[okey], total_model_ejecta[k], error))

    return all_stars, model_sn_ejecta, model_wind_ejecta, total_model_ejecta
Esempio n. 6
0
def compute_SNII_error(ds, data, uselog=True):

    pt = data['particle_type']

    select = pt >= 11

    pt = pt[select]
    pm = data['particle_mass'][select].convert_to_units('Msun').value
    bm = data['birth_mass'][select].value
    z = data['metallicity_fraction'][select].value

    # select all particles that could have gone supernova
    select = ((pt == 13) * (bm > 8.0) * (bm < 25.0)) +\
             ((pt == 13) * (z < 2.2E-6) * ((bm > 11.0) * (bm<40.0) + (bm>140.0)*(bm<260.0)))

    pm = pm[select]
    bm = bm[select]
    z = z[select]

    elements = util.species_from_fields(ds.field_list)

    all_stars = generate_model_stars(bm, z, abund=elements)

    total_ejecta = np.zeros(np.size(bm))
    error = np.zeros(np.size(bm))
    wind_error = np.zeros(np.size(bm))
    sn_error = np.zeros(np.size(bm))
    ej_frac = np.zeros(np.size(bm))
    for i, s in enumerate(all_stars):
        s.set_SNII_properties(True)
        wind = s.wind_ejecta_masses()
        sn = s.sn_ejecta_masses

        total_ejecta[i] = wind['m_tot'] + sn['m_tot']
        error[i] = (-1.0 *
                    (bm[i] - pm[i]) + total_ejecta[i]) / (total_ejecta[i])
        ej_frac[i] = (bm[i] - pm[i]) / total_ejecta[i]

        wind_error[i] = (wind['m_tot'] / total_ejecta[i])
        sn_error[i] = (sn['m_tot'] / total_ejecta[i])

    snavg, snstd = np.average(sn_error), np.std(sn_error)
    windavg, windstd = np.average(wind_error), np.std(wind_error)

    # now plot cumulative distribution of positive error (error > 0 = missing mass)
    pos_error = error[error > 0]

    fig, ax = plt.subplots()
    if uselog:
        xdata = np.log10(pos_error)
        bins = np.arange(-4, 1.0, 0.025)
    else:
        xdata = pos_error
        bins = np.linspace(0.0, 1.0, 200)
    hist, bins = np.histogram(np.log10(ej_frac), bins=bins)
    cent = (bins[1:] + bins[:-1]) * 0.5

    ax.plot(cent, np.cumsum(hist) / (1.0 * np.sum(hist)), lw=3, color='black')
    ylim = [0.0, 1.05]
    ax.set_ylim(ylim)

    def _plot_line(x, color, ls, log, label):
        if log:
            if x <= 0:
                return
            x = np.log10(x)

        ax.plot([x, x], ylim, color=color, ls=ls, label=label, lw=2)
        return


#    _plot_line(snavg, 'blue', '-', uselog, 'SN fraction')
#    _plot_line(snavg-snstd, 'blue', '-', uselog, None)
#    _plot_line(snavg+snstd, 'blue', '-', uselog, None)
#    _plot_line(windavg, 'purple', '-', uselog, 'Wind fraction')
#    _plot_line(windavg - windstd, 'purple', '--', uselog, None)
#    _plot_line(windavg + windstd, 'purple', '--', uselog, None)

    ax.set_xlabel('Fraction of Mass Actually Injected')
    ax.set_ylabel('Fraction of SN')
    fig.set_size_inches(8, 8)
    plt.tight_layout()
    plt.minorticks_on()

    fig.savefig('sn_cum_mass_error.png')
    plt.close()
    #
    #
    #   histogram
    #
    #
    fig, ax = plt.subplots()
    if uselog:
        xdata = np.log10(pos_error)
        bins = np.arange(-2, 0.05, 0.025)
    else:
        xdata = pos_error
        bins = np.linspace(0.0, 1.0, 200)

    hist, bins = np.histogram(xdata, bins=bins)
    cent = (bins[1:] + bins[:-1]) * 0.5

    ax.plot(cent, hist, lw=3, color='black')

    energy_error = (np.sum(pos_error)) / (np.size(pos_error) * 1.0)

    ax.plot(
        [np.average(pos_error), np.average(pos_error)], [0, np.max(hist)],
        color='black',
        ls='--',
        lw=3)
    ax.annotate("Energy Error = %0.2f percent" % (100 * energy_error),
                xy=(0.5, 0.9 * np.max(hist)),
                xytext=(0.5, 0.9 * np.max(hist)))
    print(energy_error)
    ax.set_ylim([0, np.max(hist)])
    ax.set_xlabel('Error in Ejected Mass')
    ax.set_ylabel('Counts')
    fig.set_size_inches(8, 8)
    plt.tight_layout()
    plt.minorticks_on()

    fig.savefig('sn_mass_error.png')

    return error, fig, ax
Esempio n. 7
0
def check_wind_ejecta(ds, data):

    pt = data['particle_type']

    # cut out DM
    select = pt >= 11

    pt = pt[select]

    bm = data['birth_mass'][select].value
    pm = data['particle_mass'][select].convert_to_units('Msun').value
    z = data['metallicity_fraction'][select].value

    elements = util.species_from_fields(ds.field_list)

    all_stars = generate_model_stars(
        bm,
        z,
        abund=elements,
        include_popIII=ds.parameters['IndividualStarPopIIIFormation'])

    lifetime = data['dynamical_time'][select].convert_to_units('Myr')
    birth = data['creation_time'][select].convert_to_units('Myr')
    age = ds.current_time.convert_to_units('Myr') - birth

    # total wind ejecta over entire lifetime
    total_wind_ejecta = np.array(
        [x.wind_ejecta_masses()['m_tot'] for x in all_stars])

    # correct for AGB stars that haven't died
    AGB = (bm < 8.0)
    model_wind_ejecta = total_wind_ejecta * 1.0
    model_wind_ejecta[AGB * (pt == 11)] = 0.0

    # adjust wind to correct fraction given lifetime
    select = (bm > 8.0) * (pt == 11)
    factor = age / lifetime
    factor[factor > 1.0] = 1.0
    model_wind_ejecta[select] = model_wind_ejecta[select] * factor[select]

    # load actual injection from simulation
    actual_wind_ejecta = data['wind_mass_ejected'][select].value

    # compute percent error
    model_wind_ejecta = model_wind_ejecta[age > 1]
    actual_wind_ejecta = actual_wind_ejecta[age > 1]
    error = (model_wind_ejecta - actual_wind_ejecta)
    error[model_wind_ejecta > 0] = error[
        model_wind_ejecta > 0] / model_wind_ejecta[model_wind_ejecta > 0]

    error_mass = error[model_wind_ejecta > 0]
    all = 1.0 * np.size(error_mass)
    print(np.size(error_mass[(np.abs(error_mass) < 0.05)]) / all)
    print(np.size(error_mass[(np.abs(error_mass) < 0.10)]) / all)
    print(np.size(error_mass[(np.abs(error_mass) < 0.15)]) / all)
    print(np.size(error_mass[(np.abs(error_mass) < 0.20)]) / all)
    print(np.size(error_mass[(np.abs(error_mass) < 0.25)]) / all)

    #error_mass = error_mass[birth[model_wind_ejecta>0] > 110]
    #error_mass = error_mass[error_mass>0]

    print(np.min(error_mass), np.max(error_mass), np.average(error_mass),
          np.median(error_mass))
    print(error_mass)
    select = (age > 1)
    bm = bm[select]
    pm = pm[select]
    age = age[select]
    lifetime = lifetime[select]
    total_wind_ejecta = total_wind_ejecta[select]
    select = (model_wind_ejecta > 0)
    bm = bm[select]
    pm = pm[select]
    age = age[select]
    lifetime = lifetime[select]
    model_wind_ejecta = model_wind_ejecta[select]
    actual_wind_ejecta = actual_wind_ejecta[select]
    total_wind_ejecta = total_wind_ejecta[select]
    #print("BM   PM   Percent_error    Model_wind    actual_wind    lifetime_wind")
    #for i in np.arange(np.size(error_mass)):
    #    print("%5.5f %3.3f %5.5f %5.5E %5.5E %5.5E"%(bm[i],pm[i],error_mass[i]*100,model_wind_ejecta[i], actual_wind_ejecta[i], total_wind_ejecta[i]))
    #print(np.min(error_mass), np.max(error_mass), np.average(error_mass), np.median(error_mass))

    #    print bm[error > 0.9], pm[error>0.9], pt[error>0.9]
    #    print age[error>0.9]
    #    print actual_wind_ejecta[error>0.9]
    #    print model_wind_ejecta[error>0.9]
    #print actual_wind_ejecta[birth > 110]
    #print model_wind_ejecta[birth > 110]

    return