コード例 #1
0
def main(wd=None, CODE_wd=None):
    """
    Driver for analysis of LOx via KPP in GEOS-Chem

    Notes
    -----
     - comment/uncommet functions as required
    """
    # Manually let locations of Ox loss here
    root = '/users/ts551/scratch/GC/'
    CODE_wd = root + '/Code/Code.v11-02_Cl_v3_0/'
    wd = root + 'rundirs/GC_v11_2d_plus_Clv3/geosfp_4x5_tropchem_Cl.v3_0.1year.2016.tagged/'
    Mechanism = 'Tropchem'
    # Get all the necessary data as as a dictionary object
    Ox_loss_dict = AC.get_Ox_loss_dicts(wd=wd,
                                        CODE_wd=CODE_wd,
                                        Mechanism=Mechanism)
    # Plot vertical odd oxygen (Ox) loss via route (chemical family)
    plot_vertical_fam_loss_by_route(Ox_loss_dict=Ox_loss_dict,
                                    Mechanism=Mechanism)
    # Analyse odd oxygen (Ox) loss budget via route (chemical family)
    calc_fam_loss_by_route(Ox_loss_dict=Ox_loss_dict, Mechanism=Mechanism)
コード例 #2
0
def plot_vertical_fam_loss_by_route(fam='LOx',
                                    ref_spec='O3',
                                    wd=None,
                                    Mechanism='Halogens',
                                    rm_strat=False,
                                    weight_by_molecs=True,
                                    CODE_wd=None,
                                    full_vertical_grid=True,
                                    dpi=320,
                                    suffix='',
                                    save_plot=True,
                                    show_plot=False,
                                    limit_plotted_alititude=True,
                                    lw=16,
                                    Ox_loss_dict=None,
                                    fontsize=10,
                                    cmap=plt.cm.jet,
                                    verbose=True,
                                    debug=False):
    """
    Plot vertical odd oxygen (Ox) loss via route (chemical family)

    Parameters
    -------
    fam (str): tagged family to track (already compiled in KPP mechanism)
    ref_spec (str): reference species to normalise to
    wd (str): working directory ("wd") of model output
    CODE_wd (str): root of code directory containing the tagged KPP mechanism
    Mechanism (str): name of the KPP mechanism (and folder) of model output
    weight_by_molecs (bool): weight grid boxes by number of molecules
    rm_strat (bool): (fractionally) replace values in statosphere with zeros
    debug, verbose (bool): switches to turn on/set verbosity of output to screen
    full_vertical_grid (bool): use the full vertical grid for analysis
    limit_plotted_alititude (bool): limit the plotted vertical extend to troposphere
    suffix (str): suffix in filename for saved plot
    dpi (int): resolution to use for saved image (dots per square inch)
    Ox_loss_dict (dict), dictionary of Ox loss variables/data (from get_Ox_loss_dicts)

    Returns
    -------
    (None)

    Notes
    -----
     - AC_tools includes equivlent functions for smvgear mechanisms
    """
    # - Local variables/ Plot extraction / Settings
    if isinstance(Ox_loss_dict, type(None)):
        Ox_loss_dict = AC.get_Ox_loss_dicts(
            wd=wd,
            CODE_wd=CODE_wd,
            fam=fam,
            ref_spec=ref_spec,
            Mechanism=Mechanism,
            rm_strat=rm_strat,
            weight_by_molecs=weight_by_molecs,
            full_vertical_grid=full_vertical_grid,
        )
    # extract variables from data/variable dictionary
    sorted_fam_names = Ox_loss_dict['sorted_fam_names']
    fam_dict = Ox_loss_dict['fam_dict']
    ars = Ox_loss_dict['ars']
    RR_dict_fam_stioch = Ox_loss_dict['RR_dict_fam_stioch']
    RR_dict = Ox_loss_dict['RR_dict']
    tags2_rxn_num = Ox_loss_dict['tags2_rxn_num']
    tags = Ox_loss_dict['tags']
    tags_dict = Ox_loss_dict['tags_dict']
    Data_rc = Ox_loss_dict['Data_rc']
    # Combine to a single array
    arr = np.array(ars)
    if debug:
        print((arr.shape))
    # - Process data for plotting
    fam_tag = [fam_dict[i] for i in tags]
    fam_ars = []
    for fam_ in sorted_fam_names:
        # Get indices for routes of family
        fam_ind = [n for n, i in enumerate(fam_tag) if (i == fam_)]
        if debug:
            print((fam_ind, len(fam_ind)))
        # Select these ...
        fam_ars += [arr[fam_ind, ...]]
    # Recombine and sum by family...
    if debug:
        print(([i.shape for i in fam_ars], len(fam_ars)))
    arr = np.array([i.sum(axis=0) for i in fam_ars])
    if debug:
        print((arr.shape))
    # - Plot up as a stack-plot...
    # Normalise to total and conver to % (*100)
    arr = (arr / arr.sum(axis=0)) * 100
    # Add zeros array to beginning (for stack/area plot )
    arr_ = np.vstack((np.zeros((1, arr.shape[-1])), arr))
    # Setup figure
    fig, ax = plt.subplots(figsize=(9, 6),
                           dpi=dpi,
                           facecolor='w',
                           edgecolor='w')
    # Plot by family
    for n, label in enumerate(sorted_fam_names):
        # Print out some summary stats
        if verbose:
            print(n,
                  label,
                  arr[:n, 0].sum(axis=0),
                  arr[:n + 1, 0].sum(axis=0),
                  end=' ')
            print(arr[:n, :].sum(), arr[:n + 1, :].sum())
            print([i.shape for i in (Data_rc['alt'], arr)])
        # Fill between X
        plt.fill_betweenx(Data_rc['alt'],
                          arr[:n, :].sum(axis=0),
                          arr[:n + 1, :].sum(axis=0),
                          color=cmap(1. * n / len(sorted_fam_names)))
        # Plot the line too
        plt.plot(
            arr[:n, :].sum(axis=0),
            Data_rc['alt'],
            label=label,
            color=cmap(1. * n / len(sorted_fam_names)),
            alpha=0,
            lw=lw,
        )
    # Beautify the plot
    plt.xlim(0, 100)
    xlabel = '% of total O$_{\\rm x}$ loss'
    plt.xlabel(xlabel, fontsize=fontsize * .75)
    plt.yticks(fontsize=fontsize * .75)
    plt.xticks(fontsize=fontsize * .75)
    plt.ylabel('Altitude (km)', fontsize=fontsize * .75)
    leg = plt.legend(loc='upper center', fontsize=fontsize)
    # Update lengnd line sizes ( + update line sizes)
    for legobj in leg.legendHandles:
        legobj.set_linewidth(lw / 2)
        legobj.set_alpha(1)
    plt.ylim(Data_rc['alt'][0], Data_rc['alt'][-1])
    # Limit plot y axis to 12km?
    if limit_plotted_alititude:
        plt.ylim(Data_rc['alt'][0], 12)
    # Show plot or save?
    if save_plot:
        filename = 'Ox_loss_plot_by_vertical_{}_{}'.format(Mechanism, suffix)
        plt.savefig(filename, dpi=dpi)
    if show_plot:
        plt.show()
コード例 #3
0
def calc_fam_loss_by_route(wd=None,
                           fam='LOx',
                           ref_spec='O3',
                           rm_strat=True,
                           Mechanism='Halogens',
                           Ox_loss_dict=None,
                           weight_by_molecs=False,
                           full_vertical_grid=False,
                           CODE_wd=None,
                           verbose=True,
                           debug=False):
    """
    Build an Ox budget table like table 4 in Sherwen et al 2016b

    Parameters
    -------
    fam (str): tagged family to track (already compiled in KPP mechanism)
    ref_spec (str): reference species to normalise to
    wd (str): working directory ("wd") of model output
    CODE_wd (str): root of code directory containing the tagged KPP mechanism
    rm_strat (bool): (fractionally) replace values in statosphere with zeros
    Ox_loss_dict (dict), dictionary of Ox loss variables/data (from get_Ox_loss_dicts)
    Mechanism (str): name of the KPP mechanism (and folder) of model output
    weight_by_molecs (bool): weight grid boxes by number of molecules
    full_vertical_grid (bool): use the full vertical grid for analysis
    debug, verbose (bool): switches to turn on/set verbosity of output to screen

    Returns
    -------
    (None)

    Notes
    -----
     - AC_tools includes equivlent functions for smvgear mechanisms
    """
    # - Local variables/ Plot extraction / Settings
    if isinstance(Ox_loss_dict, type(None)):
        Ox_loss_dict = AC.get_Ox_loss_dicts(
            wd=wd,
            CODE_wd=CODE_wd,
            fam=fam,
            ref_spec=ref_spec,
            Mechanism=Mechanism,
            rm_strat=rm_strat,
            weight_by_molecs=weight_by_molecs,
            full_vertical_grid=full_vertical_grid,
        )
    # Extract variables from data/variable dictionary
    fam_dict = Ox_loss_dict['fam_dict']
    ars = Ox_loss_dict['ars']
    RR_dict_fam_stioch = Ox_loss_dict['RR_dict_fam_stioch']
    RR_dict = Ox_loss_dict['RR_dict']
    tags2_rxn_num = Ox_loss_dict['tags2_rxn_num']
    tags = Ox_loss_dict['tags']
    tags_dict = Ox_loss_dict['tags_dict']
    halogen_fams = Ox_loss_dict['halogen_fams']
    # --- Do analysis on model output
    # Sum the total mass fluxes for each reaction
    ars = [i.sum() for i in ars]
    # Sum all the Ox loss routes
    total = np.array(ars).sum()
    # Create a dictionary of values of interest
    dict_ = {
        'Total flux': [i.sum(axis=0) for i in ars],
        'Total of flux (%)': [i.sum(axis=0) / total * 100 for i in ars],
        'Family': [fam_dict[i] for i in tags],
        'rxn #': [tags2_rxn_num[i] for i in tags],
        'rxn str': [RR_dict[tags2_rxn_num[i]] for i in tags],
        'stoich': [RR_dict_fam_stioch[tags2_rxn_num[i]] for i in tags],
        'tags': tags,
    }
    # Create pandas dataframe
    df = pd.DataFrame(dict_)
    # Sort the data and have a look...
    df = df.sort_values('Total flux', ascending=False)
    if debug:
        print(df.head())
    # Sort values again and save...
    df = df.sort_values(['Family', 'Total flux'], ascending=False)
    if debug:
        print(df.head())
    df.to_csv('Ox_loss_budget_by_rxn_for_{}_mechanism.csv'.format(Mechanism))
    # Now select the most important routes
    grp = df[['Family', 'Total flux']].groupby('Family')
    total = grp.sum().sum()
    # Print the contribution by family to screen
    print((grp.sum() / total * 100))
    # Print the contribution of all the halogen routes
    hal_LOx = (grp.sum().T[halogen_fams].sum().sum() / total * 100).values[0]
    if verbose:
        print(('Total contribution of halogens is: {:.2f} %'.format(hal_LOx)))
    # Add Halogen total and general total to DataFrame
    dfFam = grp.sum().T
    dfFam['Total'] = dfFam.sum().sum()
    dfFam['Halogens'] = dfFam[halogen_fams].sum().sum()
    # Update units to Tg O3
    dfFam = dfFam.T / 1E12
    # return dictionaries of LOx by reaction or by family (in Tg O3)
    if rtn_by_rxn:
        return df / 1E12
    if rtn_by_fam:
        return dfFam