Пример #1
0
def models_for_experiments(dic,
                           variable,
                           table,
                           experiments,
                           excluded_models=[],
                           included_models=None):
    """ 
    Provided with DIC a dictionnary of data versions, and a VARIABLE name, returns 
    a list of (model,variant) pairs that have data for VARIABLE and for all EXPERIMENTS 
    (according to DIC), and the same variant index for all EXPERIMENTS for one given model
    (excluding for piControl re. variant)

    There is only one variant returned  per model, as choosen by function `choose_variant()`

    The structure of the dictionnary should be as follow 
    dic[experiment][variable][table][model][realization] = (grid,anything,anything) 
    """

    if included_models == "None":
        included_models = None

    # Store available realizations per model and exp
    variants = dict()
    for exp in experiments:
        for model in dic[exp][variable][table]:
            if included_models is None or model in included_models:
                for real in dic[exp][variable][table][model].keys():
                    #feed_dic(variants,dic[exp][variable][table][model][real],model.encode('ascii'),exp,real)
                    feed_dic(variants, dic[exp][variable][table][model][real],
                             model, exp, real)
    return choose_variant(variants, experiments, excluded_models,
                          included_models)
Пример #2
0
def read_aggregates(ref_period, proj_period, tag, cache_dir):
    """
    This is an ancillary function for `change_figure_with_caching`. See its doc
    """
    d = dict()
    import glob
    files = glob.glob(cache_dir + "/*=*=*=*=*=*=*=%s.nc" % tag)
    for f in files:
        bn = f.split("/")[-1]
        bn = bn.split(".")[0]
        bn = bn.split("=")
        season, variable, exp, field, derive, rperiod, pperiod, _ = bn
        if pperiod == proj_period and rperiod == ref_period:
            dataset = fds(f, period="1850-2100")
            # Need to erase cached value
            cdrop(dataset)
            feed_dic(d, dataset, variable, exp, season, field, derive)
    return d
Пример #3
0
def models_for_experiments_multi_var(dic,
                                     variable_table_pairs,
                                     experiments,
                                     excluded_models=[],
                                     included_models=None):
    """ 
    Same as function `models_for_experiments()` but for a list of (variable,table) pairs
    """

    if included_models == "None":
        included_models = None

    # Store available realizations per model and exp which have data for all variables
    # We use first variable,table pair as pivot
    variable, table = variable_table_pairs[0]
    variants = dict()
    #
    for exp in experiments:
        try:
            a = dic[exp][variable][table]
        except:
            print(exp, variable, table)
            raise ValueError("")
        for model in dic[exp][variable][table]:
            for real in dic[exp][variable][table][model].keys():
                ok = True
                for var, tab in variable_table_pairs[1:]:
                    try:
                        a = dic[exp][var][tab][model][real]
                    except:
                        ok = False
                if ok:
                    feed_dic(variants, dic[exp][variable][table][model][real],
                             model, exp, real)

    return choose_variant(variants, experiments, excluded_models,
                          included_models)
Пример #4
0
def stats_of_basins_changes(model_changes,
                            ref_experiment,
                            scenario,
                            ref_period,
                            variable,
                            table,
                            time_stat,
                            data_versions,
                            slices,
                            stats_list,
                            basins_data,
                            fprint=True,
                            excluded_models=[],
                            included_models=None,
                            must_have_vars=[],
                            relative=True,
                            compute=False,
                            house_keeping=False):
    """
    Feed dic MODEL_CHANGES with change values for TIME_STAT of VARIABLE spatially averaged
    over basins listed in BASINS_DATA["basins"] (which can include "globe" and "land"); this with 
    respect to a REF_PERIOD and for a series of time SLICES in a given SCENARIO; and for the list of 
    models which, according to dict DATA_VERSIONS, provide VARIABLE for both experiments, 
    List INCLUDED_MODELS, if not None, limits models used
    List EXCLUDED_MODELS allows to discard models (even those included in INCLUDED_MODELS
    
    TIME_STAT can be "mean" or "std" and is computed by function `cancillary.mean_or_std`

    Structure of MODEL_CHANGES (which forgets about TABLE) is :
       model_changes[scenario][variable][time_stat][basin][period][model]=change_value
    
    Also returns a dict of ensemble stats of changes across the ensemble of models, for STATS_LIST :
    >>> ens_changes[basin][ensemble_stat][period] = stat_value
    For syntax and semantics of STATS_LIST, see function `cancillary.ensemble_stat()`

    BASINS_DATA is a dict with keys : 

      - basins : list of basin names for those basins to process
      - basins_file : filename for the file coding basins
      - basins_key : a dict of correspondance between basin names and basin numbers in basins_file
      
    Change values are relative changes, except if RELATIVE=False
    """

    lbasins = basins_data["basins"]

    # Compute variables values on ref_period and slices,
    values = dict()
    if fprint:
        print("%6s %s %s %s" % (scenario, variable, table, time_stat), end='')
    pairs = must_have_vars + [(variable, table)]
    models = models_for_experiments_multi_var(data_versions, pairs,
                                              [scenario, ref_experiment],
                                              excluded_models, included_models)
    for model, variant in models:
        if fprint: print(" %s" % (model), end='')
        for period in [ref_period] + slices:
            #if fprint : print "%s"%period[0:3],
            for basin in lbasins:
                if basin == "globe":
                    operator = ccdo_fast
                    args = {"operator": "fldmean"}
                else:
                    operator = basin_average
                    args = {
                        "model": model,
                        "basin": basin,
                        "basins": basins_data,
                        "compute": True
                    }
                value = cvalue(
                    mean_or_std(scenario,
                                ref_experiment,
                                model,
                                variant,
                                "anm",
                                variable,
                                time_stat,
                                table,
                                period,
                                data_versions,
                                operator,
                                args,
                                compute=compute,
                                house_keeping=house_keeping))
                feed_dic(values, value, model, basin, period)
    if fprint: print()

    # Compute relative or absolute changes, and store it with model as last dict key
    model_changes = dict()
    for period in slices:
        for model in values:
            for basin in values[model]:
                pro = values[model][basin][period]
                ref = values[model][basin][ref_period]
                if relative:
                    change = 100 * (pro - ref) / ref
                else:
                    change = pro - ref
                feed_dic(model_changes, change, basin, period, model)

    # Compute stats on models ensemble (inside a scenario)
    ens_changes = dict()
    for period in slices:
        # Next on other variables, per basin
        for basin in model_changes:
            # Access relevant models ensemble
            ens = model_changes[basin][period]
            for ens_stat in stats_list:
                stat_value = ensemble_stat(ens, ens_stat)
                feed_dic(ens_changes, stat_value, basin, ens_stat, period)
    #
    return ens_changes, models
Пример #5
0
 def feed(name, field):
     feed_dic(dic, field, experiment, season, name, derivation_label, model)
Пример #6
0
 def feed(value, key):
     feed_dic(aggregates, value, variable, experiment, season, key,
              derivation_label)
Пример #7
0
def change_fields(
        project,
        variable,
        experiments,
        seasons,
        ref_period,
        projection_period,
        models_to_plot,
        data_versions,
        derivation_label=None,
        relative=False,
        standardized=False,
        print_statistics=False,
        ref_experiment="historical",
        variab_sampling_args={
            "house_keeping": True,
            "compute": True,
            "detrend": True,
            "shift": 100,
            "nyears": 20,
            "number": 20
        },
        common_grid=None,
        table=None,
        deep=None,
        threshold=None,
        low_change_agree_threshold=1.645,
        sign_agree_threshold=0.9):
    """Computes a series of change fields for one
    VARIABLE and a list of EXPERIMENTS, for period PROJECTION_PERIOD
    with respect to REF_EXPERIMENT for REF_PERIOD. Computed fields 
    are e.g. mean change and median relative change. See 'aggregates' below for 
    the list of fields.

    The computation is performed for all seasons listed in arg SEASONS (e.g. ['DJF', 'ANN'])

    The variable may undergo some transformation rather than plain averaging over
    the period(s); such transforations are found in dict `changes.derivations` and must be 
    designated by a label (DERIVATION_LABEL)

    See examples in the scripts of the various figures of AR6/WGI chapter 8 
 
    Also computes variability fields and other related fields (see below) using piControl 
    and some settings for sampling it. See explanations with function `variability.variability_AR5` and 
    `variability.stippling_hatching_masks_AR5`

    MODELS_TO_PLOT is a dictionnary which keys are experiments and values are lists 
    of pairs(model,variant) to include for that experiment. 

    Toggles RELATIVE activate the computation of relative change (in addition to plain 
    change). Key suffix (in keys list below) is then : `_rchange`. 

    Toggles STANDARDIZED activate the computation of change standardized by its 
    interannual variability. Key suffix (in keys list below) is `_schange`. 
    The (multi-decadal) variability is then also standardized the same way.

    Arg THRESHOLD (if not None) is used when relative is True, as a floor value of
    the reference field below which the per-model relative changes are set to missing

    Arg LOW_CHANGE_AGREE_THRESHOLD provides the threshold for
    computing the field of fractional agreement on a low change; its
    default value is the one set for AR6 hatching sheme; it is
    compared, separately for each model, to the ratio of absolute value
    of change by internal multi-decadal variability, for deciding for
    a low change for that model. The fraction of agreement across
    models is returned under key `agree_low` (see below), and mask
    fields defined by AR6 'comprehensive' hatching scheme are returned under key
    `lowchange` (for zones without an agreed significant change) and "conflicts" 
    (for zones with conflicting significant signals)

    The fraction of sign agreement across models is returned under key
    `agreement_fraction_on_sign` (see below)

    The variable is sought in CMIP6 table Amon or Lmon (depending on the 
    variable), except specified otherwise using arg TABLE (e.g. value 'day' is 
    for processing variable 'pr', provided the derivation make sense for daily data)

    Other details of the variable are defined using dict DATA_VERSIONS, which must be a
    dictionnary with this structure (like provided by the notebook in sibling directory 
    data_versions) :

    >>>   data_versions[experiment][variable][table][model][variant]=(grid,version,data_period)

    e.g.

    >>>   data_versions["ssp245"]["pr"]["Amon"]["MPI-ESM1-2-HR"]["r1i1p1f1"]=("gn","v20190710","2015-2100")

    (data-period is used only for piControl)


    **Returns** all results through a pair of dicts of dicts : aggregates and dic
    
    Dict 'aggregates' provides ensemble statistics (e.g. mean or median among
    models), while dict 'dic' returns model specific fields

    Use it as : 

    >>> field=aggregates[variable][experiment][season][key][derivation_label] 

    where key has values : 

        * mean_change   : ensemble mean value of the changes
        * mean_rchange  : ensemble mean value of the relative changes 
        * mean_schange  : ensemble mean value of the interannual variability standardized changes  
        * median_change, median_rchange, median_schange : same as three keys above, but for ensemble median
        * means_rchange : relative change of the ensemble means
        * median_variability : ensemble median of the multi-decadal variability
        * (as defined by AR5) : stippling, hatching : 0/1 masks for the AR5 scheme stippling and hatching
        * (as defined by AR6 simple case) : agreement_fraction_on_sign : fraction of models which agree on sign (highest fraction among the two signs)
        * (as defined by AR6 comprehensive case) : agree_low, conflict, lowchange  : see explanation above with argument LOW_CHANGE_AGREE_THRESHOLD

    >>> field=dic[experiment][season][key][derivation_label][model]
    
    where key has values : reference, projection, change, rchange, schange, nchange, variability
        * variability means : multi-decadal variability
        * nchange means : change standardized by multi-decadal variability

    """
    aggregates = dict()
    dic = dict()
    if standardized and (variab_sampling_args == {}
                         or variab_sampling_args is None):
        raise Exception("Must provide variability sampling arguments when requesting "+\
                        "a variable standardized by inter_annual variability")
    #
    if print_statistics:
        print(
            "Values below are field means, except for last two columns. Last third is median and %. Last three columns are %"
        )
        print(
            "exp.  seas model                 variablity   reference   projection       change|rel/std   :mdn     max     p90"
        )
        print(120 * "-")

    # a commodity function for storing resuts in dic aggregates
    def feed(value, key):
        feed_dic(aggregates, value, variable, experiment, season, key,
                 derivation_label)

    for experiment in experiments:
        #
        if table is None:
            table = table_for_var_and_experiment(variable, experiment)
        #project=project_for_experiment(experiment)
        control_models, models = models_to_plot[experiment]
        do_variability= (variab_sampling_args != {} and variab_sampling_args is not None and \
                        len(control_models) > 0 )
        #
        for season in seasons:
            if not print_statistics: print(experiment, season, end='')
            #
            #
            for model, realization in models:
                change_fields_internal(dic, project, model, realization,
                                       variable, ref_period, projection_period,
                                       ref_experiment, experiment, season,
                                       derivation_label, relative,
                                       standardized, print_statistics,
                                       common_grid, table, data_versions, deep,
                                       variab_sampling_args, threshold)
            #
            if do_variability:
                if print_statistics: print("Variabilities :", end='')
                for model, realization in control_models:
                    variability = variability_field(
                        project, model, realization, variable, season,
                        derivation_label, standardized, variab_sampling_args,
                        common_grid, table, data_versions, deep)
                    feed_dic(dic, variability, experiment, season,
                             "variability", derivation_label, model)
                    if print_statistics:
                        print(
                            "%s % 7.2g / " %
                            (model,
                             cvalue(ccdo_fast(variability,
                                              operator="fldmean"))),
                            end='')
                    #
                    # Compute ratio of change to internal variability for models which allow for
                    # (done on common grid)
                    if model in [m for m, r in models]:
                        change = dic[experiment][season]["change"][
                            derivation_label][model]
                        nchange = ccdo2(change, variability, operator="div")
                        feed_dic(dic, nchange, experiment, season, "nchange",
                                 derivation_label, model)

                if print_statistics: print

            # Compute ensemble statistics
            if print_statistics:
                print("%s medians :" % experiment, end='')
            ensavg = ccdo_ens(cens(
                dic[experiment][season]["change"][derivation_label]),
                              operator='ensmean')
            feed(ensavg, "mean_change")
            ensmdn = ccdo_ens(cens(
                dic[experiment][season]["change"][derivation_label]),
                              operator='enspctl,50')
            feed(ensmdn, "median_change")
            if print_statistics:
                print("change %7.2g" %
                      cvalue(ccdo_fast(ensmdn, operator="fldpctl,50")),
                      end='')
            if relative:
                rmean = ccdo_ens(cens(
                    dic[experiment][season]["rchange"][derivation_label]),
                                 operator='ensmean')
                feed(rmean, "mean_rchange")
                rmedian = ccdo_ens(cens(
                    dic[experiment][season]["rchange"][derivation_label]),
                                   operator='enspctl,50')
                feed(rmedian, "median_rchange")
                # Also compute the relative change of ensemble means
                ref_ensavg = ccdo_ens(
                    cens(dic[experiment][season]["reference_remapped"]
                         [derivation_label]),
                    operator='ensmean')
                proj_ensavg = ccdo_ens(
                    cens(dic[experiment][season]["projection_remapped"]
                         [derivation_label]),
                    operator='ensmean')
                rmeans = ccdo2(ccdo2(proj_ensavg, ref_ensavg, operator="sub"),
                               ref_ensavg,
                               operator="mulc,100 -div")
                feed(rmeans, "means_rchange")
            if print_statistics:
                print("relative %7.2g %%" %
                      cvalue(ccdo_fast(rmedian, operator="fldpctl,50")),
                      end='')
            if standardized:
                smean = ccdo_ens(cens(
                    dic[experiment][season]["schange"][derivation_label]),
                                 operator='ensmean')
                feed(smean, "mean_schange")
                smedian = ccdo_ens(cens(
                    dic[experiment][season]["schange"][derivation_label]),
                                   operator='enspctl,50')
                feed(smedian, "median_schange")
            if print_statistics:
                csync()
                print()
            #
            if standardized:
                agree_field = "schange"
                avg = smean
            else:
                agree_field = "change"
                avg = ensavg
            agreef = agreement_fraction_on_sign(
                cens(dic[experiment][season][agree_field][derivation_label]))
            feed(agreef, "agreement_fraction_on_sign")
            #
            # Compute stippling and hatching fields (a la AR5) for the figure
            #
            if do_variability:
                medvar = ccdo_ens(cens(
                    dic[experiment][season]["variability"][derivation_label]),
                                  operator='enspctl,50')
                feed(medvar, "median_variability")
                #
                s, h = stippling_hatching_masks_AR5(avg, medvar, agreef)
                feed(s, "stippling")
                feed(h, "hatching")
                #
                # Agreement on low change wrt OWN internal variability
                if "nchange" in dic[experiment][season]:
                    agree_low = agreement_fraction_on_lower(
                        cens(dic[experiment][season]["nchange"]
                             [derivation_label]), low_change_agree_threshold)
                    feed(agree_low, "agree_low")
                    (l , c) = lowchange_conflict_masks_AR6(\
                                 agreef,agree_low,
                                 fraction_on_sign=sign_agree_thresold)
                    feed(l, "lowchange")
                    feed(c, "conflict")
                else:
                    print("No common model for ", variable, seasons,
                          experiments)
                    print("models: ", models)
                    print("control_models:", control_models)
            #
            print()
    return aggregates, dic