예제 #1
0
def SPIbiannual(incube, season, ncfile):
    """
    Calculate biannual SPI with a rolling window for given months.
    The SPI is the anomaly with respect to the chosen scenario baseline period.
    period - climatological_mean / climatological_std

    :param incube: precipitation cube from CMIP5 raw data
    :param season: string indicating season, read by _getSeasConstr() to get season contraint
    :param ncfile: full string for output netcdf file
    :return: single model netcdf file
    """

    print 'Calculating biannual SPI for ' + str(season)
    fdict = atlas_utils.split_filename_path(ncfile)

    if 'month_number' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_month_number(incube, 'time', name='month_number')
    if 'year' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_year(incube, 'time', name='year')

    slicer = _getSeasConstr(season)
    incube = incube.extract(slicer)

    _calcUnit(incube, ncfile)
    incube.data = np.ma.masked_invalid(incube.data)
    c_monthly = atlas_utils.time_slicer(incube, fdict['scenario'])  # shorten time period
    c_monthly = c_monthly.aggregated_by(['year'], iris.analysis.MEAN)

    # This is the monthly climatology (mean and std deviation)
    std = c_monthly.collapsed('year', iris.analysis.STD_DEV)
    mean = c_monthly.collapsed('year', iris.analysis.MEAN)

    c_biannual = c_monthly.rolling_window(['year'], iris.analysis.MEAN, 2)

    # We need to change the shape of the monthly climatologies to match the shape of the timeseries (in the cube c_monthly)
    mean = ma.masked_invalid(mean.data)
    std = ma.masked_invalid(std.data)

    clim_mean_data = np.repeat(mean.reshape(1, mean.shape[0], mean.shape[1]), c_biannual.shape[0],
                               axis=0)  # np.tile(mean.data, (c_monthly.shape[0] / mean.shape[0], 1, 1))
    clim_std_data = np.repeat(std.reshape(1, std.shape[0], std.shape[1]), c_biannual.shape[0],
                              axis=0)  # np.tile(std.data, (c_monthly.shape[0] / std.shape[0], 1, 1))

    clim_mean_cube = c_biannual.copy(clim_mean_data)
    clim_std_cube = c_biannual.copy(clim_std_data)

    spi = (c_biannual - clim_mean_cube) / clim_std_cube
    spi.data = ma.masked_invalid(spi.data)

    tseries = spi.collapsed(['longitude', 'latitude'], iris.analysis.MEDIAN)
    c2d = spi.collapsed('year', iris.analysis.MEDIAN)

    nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])

    iris.save(tseries, ncfile)
    iris.save(c2d, nc2d)
예제 #2
0
def _annualnbDay(incube, season, ncfile, threshold=None):
    '''
    Calculate number of days per year with higher value than threshold.
    Choose threshold as needed e.g. 30mm for extreme and 1mm for rainy day.

    :param incube: cube from CMIP5 raw data
    :param season: string indicating season, read by _getSeasConstr() to get season contraint
    :param ncfile: full string for output netcdf file
    :return: single model netcdf file
    '''
    if not threshold:
        print 'No threshold given, stopping calculation'
        return

    print ncfile
    print "Calculating number of days with variable above " + str(threshold)
    fdict = atlas_utils.split_filename_path(ncfile)

    if 'month_number' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_month_number(incube,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_year(incube, 'time', name='year')

    slicer = _getSeasConstr(season)
    incube = incube.extract(slicer)
    incube.coord('latitude').guess_bounds()
    incube.coord('longitude').guess_bounds()
    if "_pr_" in ncfile:
        incube.convert_units('kg m-2 day-1')

    if ("_tas_" in ncfile) or ('_tasmax_' in ncfile) or ('_tasmin_' in ncfile):
        incube.convert_units('Celsius')

    bigger = incube.aggregated_by('year',
                                  iris.analysis.COUNT,
                                  function=lambda values: values >= threshold)
    bigger.units = incube.units
    bigger.data = bigger.data.astype(float)

    tseries = bigger.collapsed(['longitude', 'latitude'], iris.analysis.MEDIAN)

    bigger2d = atlas_utils.time_slicer(bigger, fdict['scenario'])
    c2d = bigger2d.collapsed('year', iris.analysis.MEDIAN)

    trend2d = trend(bigger, season, ncfile)

    nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])
    nctrend2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[2])

    pdb.set_trace()
    iris.save(tseries, ncfile)
    iris.save(c2d, nc2d)
    iris.save(trend2d, nctrend2d)
예제 #3
0
def monthlyClimatologicalMean(incube, season, ncfile):
    '''
    Calculates the climatological monthly means over the time period

    TODO: allow lower threshold to compute mean based on e.g. RAINY days rather than all days

    :param incube: single variable cube from CMIP5 raw data
    :param season: string indicating season, read by _getSeasConstr() to get season constraint
    :param ncfile: full string for output netcdf file
    :return: single model netcdf file
    '''

    print ncfile
    print 'Calculating climatological monthly mean'
    fdict = atlas_utils.split_filename_path(ncfile)

    if 'month_number' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_month_number(incube,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_year(incube, 'time', name='year')

    #    slicer = _getSeasConstr(season)
    #    cubein = incube.extract(slicer)

    if "_pr_" in ncfile:
        incube.convert_units('kg m-2 day-1')

    if ("_tas_" in ncfile) or ('_tasmax_' in ncfile) or ('_tasmin_' in ncfile):
        incube.convert_units('Celsius')

    tcalc = incube.aggregated_by(['month_number', 'year'],
                                 iris.analysis.MEAN)  # prepare trend calc
    tcalc.units = incube.units
    trend2d = trend(tcalc, season, ncfile)

    incube = atlas_utils.time_slicer(
        incube, fdict['scenario'])  # time slicing for 2d and time series
    calc = incube.aggregated_by('month_number', iris.analysis.MEAN)
    tseries = calc.collapsed(['longitude', 'latitude'], iris.analysis.MEDIAN)
    c2d = calc.collapsed('year', iris.analysis.MEDIAN)

    nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])
    nctrend2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[2])

    # monthly time series, 12 entries
    iris.save(tseries, ncfile)
    # this is simply an average of all 12 entries on a map..nothing to do with monthly Clim
    iris.save(c2d, nc2d)
    # this gives a single map showing the annual (rather than trend specific months) trend
    # since the trend function aggregates seperate months
    iris.save(trend2d, nctrend2d)
예제 #4
0
def _xDaySumAnnualMax(incube, season, ncfile, nb_days=None):
    """
    :param incube: cube from CMIP5 raw data
    :param season: string indicating season, read by _getSeasConstr() to get season contraint
    :param ncfile: full string for output netcdf file
    :param nb_days: number of days over which to sum up the variable
    :return: single model netcdf file
    """

    if not nb_days:
        print 'Number of days for aggregation not given, stopping calculation'
        return

    print ncfile
    print "Aggregating variable for " + str(nb_days) + "-day moving windows."
    fdict = atlas_utils.split_filename_path(ncfile)

    if 'month_number' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_month_number(incube,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_year(incube, 'time', name='year')

    slicer = _getSeasConstr(season)
    incube = incube.extract(slicer)

    if ("tas_" in ncfile) or ("tasmax_" in ncfile) or ("tasmin_" in ncfile):
        print(
            'This aggregation makes no sense for temperature. Stopping calculation'
        )
        return

    _calcUnit(incube, ncfile)
    incube.data = np.ma.masked_invalid(incube.data)

    calc = incube.rolling_window('time', iris.analysis.SUM, nb_days)
    calc.data = np.ma.masked_invalid(calc.data)
    calc = calc.aggregated_by(['year'], iris.analysis.MAX)

    tseries = calc.collapsed(['longitude', 'latitude'], iris.analysis.MEDIAN)

    calc2d = atlas_utils.time_slicer(calc, fdict['scenario'])

    c2d = calc2d.collapsed('year', iris.analysis.MEDIAN)
    trend2d = trend(calc, season, ncfile)

    nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])
    nctrend2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[2])

    iris.save(tseries, ncfile)  # monthly time series, 12 entries
    iris.save(c2d, nc2d)
    iris.save(trend2d, nctrend2d)
예제 #5
0
def _annualMeanThresh(incube, season, ncfile, lower_threshold=None):
    '''
    Calculates the annual mean over the time period

    TODO: allow lower threshold to compute mean based on e.g. RAINY days rather than all days

    :param incube: single variable cube from CMIP5 raw data
    :param season: string indicating season, read by _getSeasConstr() to get season contraint
    :param ncfile: full string for output netcdf file
    :return: single model netcdf file
    '''

    print ncfile
    print 'Calculating annual mean for ' + season
    fdict = atlas_utils.split_filename_path(ncfile)

    slicer = _getSeasConstr(season)

    if 'month_number' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_month_number(incube,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_year(incube, 'time', name='year')

    incube = incube.extract(slicer)

    _calcUnit(incube, ncfile)

    csum = incube.aggregated_by(['year'], iris.analysis.SUM)
    ccount = incube.aggregated_by(
        ['year'],
        iris.analysis.COUNT,
        function=lambda values: values >= lower_threshold)
    ccount.data = np.array(ccount.data, dtype=float)
    ccount.data[ccount.data == 0] = np.nan
    ccount.data = np.ma.masked_invalid(ccount.data)
    calc = csum / ccount
    calc.units = incube.units
    calc.long_name = incube.long_name
    calc.data = np.ma.masked_invalid(calc.data)
    tseries = calc.collapsed(['longitude', 'latitude'], iris.analysis.MEDIAN)

    calc2d = atlas_utils.time_slicer(calc, fdict['scenario'])
    c2d = calc2d.collapsed('year', iris.analysis.MEDIAN)
    trend2d = trend(calc, season, ncfile)

    nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])
    nctrend2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[2])

    iris.save(tseries, ncfile)  # yearly time series
    iris.save(c2d, nc2d)
    iris.save(trend2d, nctrend2d)
예제 #6
0
def lineplot_scenarios(incubes, outpath, region):
    """
    Line plot showing how the metric evolves over the years for all models and all scenarios combined
   :param incubes: wildcard path to all tseries multi-model cubes
   :param outpath: the path where the plot is saved
   :param region: the region dictionary as defined in constants
   :return: plot
   """
    ano_list = glob.glob(incubes + '_tseries.nc')
    ano_list = atlas_utils.order(ano_list)[::-1]

    f = plt.figure(figsize=(8, 5), dpi=300)
    ax = f.add_subplot(111)

    colors = ['gray', 'gold', 'green', 'mediumblue'][::-1]
    tag = cnst.SCENARIO[::-1]
    scenarios = []

    for ano, co, ta in zip(ano_list, colors, tag):

        fdict = atlas_utils.split_filename_path(ano)
        scen = fdict['scenario']
        metric = fdict['metric']
        variable = fdict['variable']
        season = fdict['season']
        bc = fdict['bc_res']
        scenarios.append(scen)

        cube = iris.load_cube(ano)
        time = cube.coord('year').points
        cube = cube.data

        ax.plot(time[0], 0, color=co, label=ta)
        for nb in range(cube.shape[0]):
            ax.plot(time, cube[nb, :], color=co, alpha=0.5, lw=0.75)

    bottom, top = ax.get_ylim()
    plt.vlines(2005, bottom, top, linestyle='--', linewidth=1.5, zorder=10)
    plt.ylabel(lblr.getYlab(metric, variable, anom=""))
    plt.title(lblr.getTitle(metric,
                            variable,
                            season,
                            scenarios,
                            bc,
                            region[1],
                            anom=''),
              fontsize=10)
    plt.legend()
    plt.savefig(outpath + os.sep + fdict['metric'] + '_' + fdict['variable'] +
                '_' + fdict['bc_res'] + '_' + fdict['season'] + '_' +
                region[0] + '_lineplot_allscen_' + '.png')
    plt.close(f)
예제 #7
0
def annualMax(cubein, season, ncfile):
    '''
    Calculates the annual maximum of a variable.

    :param incube: single variable cube from CMIP5 raw data
    :param season: string indicating season, read by _getSeasConstr() to get season contraint
    :param ncfile: full string for output netcdf file
    :return: single model netcdf file
    '''

    print ncfile
    print 'Calculating annual maximum'
    fdict = atlas_utils.split_filename_path(ncfile)

    if 'month_number' not in [coord.name() for coord in cubein.coords()]:
        iris.coord_categorisation.add_month_number(cubein,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in cubein.coords()]:
        iris.coord_categorisation.add_year(cubein, 'time', name='year')

    slicer = _getSeasConstr(season)
    cubein = cubein.extract(slicer)

    if "_pr_" in ncfile:
        try:
            cubein.convert_units('kg m-2 day-1')
        except:
            return

    if ("_tas_" in ncfile) or ('_tasmax_' in ncfile) or ('_tasmin_' in ncfile):
        try:
            cubein.convert_units('Celsius')
        except:
            return

    calc = cubein.aggregated_by(['year'], iris.analysis.MAX)
    tseries = calc.collapsed(['longitude', 'latitude'], iris.analysis.MEDIAN)

    calc2d = atlas_utils.time_slicer(calc, fdict['scenario'])
    c2d = calc2d.collapsed('year', iris.analysis.MEDIAN)
    trend2d = trend(calc, season, ncfile)

    nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])
    nctrend2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[2])

    iris.save(tseries, ncfile)
    iris.save(c2d, nc2d)
    iris.save(trend2d, nctrend2d)
예제 #8
0
def monthlyClimatologicalMean(incube, season, ncfile):
    '''
    Calculates the climatological monthly means over the time period

    TODO: allow lower threshold to compute mean based on e.g. RAINY days rather than all days

    :param incube: single variable cube from CMIP5 raw data
    :param season: string indicating season, read by _getSeasConstr() to get season constraint
    :param ncfile: full string for output netcdf file
    :return: single model netcdf file
    '''

    print ncfile
    print 'Calculating climatological monthly mean'
    fdict = atlas_utils.split_filename_path(ncfile)

    if 'month_number' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_month_number(incube,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_year(incube, 'time', name='year')

    #    slicer = _getSeasConstr(season)
    #    cubein = incube.extract(slicer)

    _calcUnit(incube, ncfile)
    incube.data = np.ma.masked_invalid(incube.data)

    tcalc = incube.aggregated_by(['month_number', 'year'],
                                 iris.analysis.MEAN)  # prepare trend calc
    tcalc.units = incube.units
    #trend2d = trend(tcalc, season, ncfile)

    incube = atlas_utils.time_slicer(
        incube, fdict['scenario'])  # time slicing for 2d and time series
    calc = incube.aggregated_by('month_number', iris.analysis.MEAN)
    tseries = calc.collapsed(['longitude', 'latitude'], iris.analysis.MEDIAN)
    #c2d = calc.collapsed('year', iris.analysis.MEDIAN)

    #nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])
    #nctrend2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[2])

    # monthly time series, 12 entries
    iris.save(tseries, ncfile)
예제 #9
0
def annualMin(incube, season, ncfile):
    '''
    Calculates the annual minimum of the variable.

    :param incube: single variable cube from CMIP5 raw data
    :param season: string indicating season, read by _getSeasConstr() to get season contraint
    :param ncfile: full string for output netcdf file
    :return: single model netcdf file
    '''

    print ncfile
    print 'Calculating annual minimum'
    fdict = atlas_utils.split_filename_path(ncfile)

    if 'month_number' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_month_number(incube,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_year(incube, 'time', name='year')

    slicer = _getSeasConstr(season)
    incube = incube.extract(slicer)

    _calcUnit(incube, ncfile)
    incube.data = np.ma.masked_invalid(incube.data)

    calc = incube.aggregated_by(['year'], iris.analysis.MIN)
    tseries = calc.collapsed(['longitude', 'latitude'], iris.analysis.MEDIAN)

    calc2d = atlas_utils.time_slicer(calc, fdict['scenario'])
    c2d = calc2d.collapsed('year', iris.analysis.MEDIAN)
    trend2d = trend(calc, season, ncfile)

    nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])
    nctrend2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[2])

    iris.save(tseries, ncfile)
    iris.save(c2d, nc2d)
    iris.save(trend2d, nctrend2d)
예제 #10
0
def annualTotalRain(incube, season, ncfile):
    '''
    Calculates the total rain over the time period

    :param incube: precipitation cube from CMIP5 raw data
    :param season: string indicating season, read by _getSeasConstr() to get season contraint
    :param ncfile: full string for output netcdf file
    :return: single model netcdf file
    '''

    print ncfile
    print 'Calculating total rain'
    fdict = atlas_utils.split_filename_path(ncfile)

    slicer = _getSeasConstr(season)
    if 'month_number' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_month_number(incube,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_year(incube, 'time', name='year')

    incube = incube.extract(slicer)
    incube.convert_units('kg m-2 day-1')

    calc = incube.aggregated_by(['year'], iris.analysis.SUM)
    tseries = calc.collapsed(['longitude', 'latitude'], iris.analysis.MEDIAN)

    calc2d = atlas_utils.time_slicer(calc, fdict['scenario'])
    c2d = calc2d.collapsed('year', iris.analysis.MEDIAN)
    trend2d = trend(calc, season, ncfile)

    nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])
    nctrend2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[2])

    iris.save(tseries, ncfile)
    iris.save(c2d, nc2d)
    iris.save(trend2d, nctrend2d)
예제 #11
0
def map_percentile_single(incubes, outpath, region, anomaly=False):
    """
    Produces maps for individual scenarios of the 10th and 90th percentile of the model ensemble.
    :param incubes: single 2d file of a multi-model metric cube
    :param outpath: the path where the plot is saved
    :param region: the region dictionary as defined in constants
    :param anomaly: boolean, switch for anomaly calculation
    :return: plot
    """

    fname = incubes + '_2d.nc'
    fdict = atlas_utils.split_filename_path(fname)

    if fdict['aggregation'] not in cnst.METRIC_AGGS[fdict['metric']]:
        return

    ano = glob.glob(incubes + '_2d.nc')

    if len(ano) != 1:
        sys.exit('Found none or too many files, need one file')
    ano = ano[0]

    scen = fdict['scenario']
    metric = fdict['metric']
    variable = fdict['variable']
    season = fdict['season']
    bc = fdict['bc_res']

    if (anomaly == True) & (scen == 'historical'):
        return

    wfdei_file = cnst.METRIC_DATADIR + os.sep + 'WFDEI' + os.sep + metric + '_' + variable + '_WFDEI_historical_' + season + '*_2d.nc'
    wfdei = glob.glob(wfdei_file)
    if len(wfdei) != 1:
        print(wfdei)
        print('No or too many wfdei files. Please check')
        pdb.set_trace()

    cube = iris.load_cube(ano)
    wcube = iris.load_cube(wfdei)

    if anomaly:

        ano_hist = ano.replace(fdict['scenario'], 'historical')
        hist = iris.load_cube(ano_hist)

        data = atlas_utils.anomalies(hist, cube, percentage=False)
        data_perc = atlas_utils.anomalies(hist, cube, percentage=True)

        data_perc = data_perc.collapsed('model_name',
                                        iris.analysis.PERCENTILE,
                                        percent=[10, 90])
        data = data.collapsed('model_name',
                              iris.analysis.PERCENTILE,
                              percent=[10, 90])

        if np.nanmax(data.data) - np.nanmin(data.data) > np.nanmax(data.data):
            levels = (atlas_utils.datalevels_ano(
                np.append(data[0].data, data[1].data)),
                      atlas_utils.datalevels_ano(
                          np.append(data[0].data, data[1].data)))
            cmap = 'RdBu_r' if 'tas' in variable else 'RdBu'
        else:
            levels = (atlas_utils.datalevels(
                np.append(data[0].data, data[1].data)),
                      atlas_utils.datalevels(
                          np.append(data[0].data, data[1].data)))
            cmap = 'Reds' if 'tas' in variable else 'Blues'

        if np.nanmax(data_perc.data) - np.nanmin(data_perc.data) > np.nanmax(
                data_perc.data):
            plevels = (atlas_utils.datalevels_ano(
                np.append(data_perc[0].data, data_perc[1].data)),
                       atlas_utils.datalevels_ano(
                           np.append(data_perc[0].data, data_perc[1].data)))

        else:
            plevels = (atlas_utils.datalevels(
                np.append(data_perc[0].data, data_perc[1].data)),
                       atlas_utils.datalevels(
                           np.append(data_perc[0].data, data_perc[1].data)))

        plot_dic1 = {
            'data': data,
            'ftag': scen + 'Anomaly',
            'cblabel': 'anomaly',
            'levels': levels,
            'cmap': cmap
        }

        if not 'tas' in variable:
            plot_dic2 = {
                'data': data_perc,
                'ftag': scen +
                'PercentageAnomaly',  # if cnst.LANGUAGE == 'ENGLISH' else '
                'cblabel': 'percentageAnomaly',
                'levels': plevels,
                'cmap': cmap
            }

            toplot = [plot_dic1, plot_dic2]

        else:
            toplot = [plot_dic1]

    else:

        data = cube
        data = data.collapsed('model_name',
                              iris.analysis.PERCENTILE,
                              percent=[10, 90])

        plot_dic1 = {
            'data':
            data,
            'ftag':
            scen,
            'cblabel':
            '',
            'levels':
            (atlas_utils.datalevels(np.append(data[0].data, data[1].data)),
             atlas_utils.datalevels(np.append(data[0].data, data[1].data))),
            'cmap':
            'viridis'
        }

        toplot = [plot_dic1]

    map = False
    map1 = False
    map2 = False

    for p in toplot:
        f = plt.figure(figsize=lblr.getFigSize(region[0], 'map'), dpi=300)
        siz = 6
        lon = data.coord('longitude').points
        lat = data.coord('latitude').points

        if not np.nansum(wcube.data):
            ax = f.add_subplot(311)
            ax.text(0.5, 0.5, 'Zero values', ha='center')
        else:
            try:
                ax = f.add_subplot(311, projection=ccrs.PlateCarree())
                dataw = np.ma.array(wcube.data, mask=wcube.data == np.nan)
                ax.set_autoscale_on('False')
                map = ax.contourf(lon,
                                  lat,
                                  dataw,
                                  transform=ccrs.PlateCarree(),
                                  cmap='viridis',
                                  vmin=np.nanmin(dataw),
                                  vmax=np.nanmax(dataw),
                                  extend='both')
                ax.set_ylim(np.min(lat), np.max(lat))
                ax.set_xlim(np.min(lon), np.max(lon))
            except ValueError:
                ax = f.add_subplot(311)
                ax.text(0.5, 0.5, 'Zero values', ha='center')

            if map:
                ax.coastlines()
                # Gridlines
                siz = 6
                xl = ax.gridlines(draw_labels=True)
                xl.xlabels_top = False
                xl.ylabels_right = False
                xl.xformatter = LONGITUDE_FORMATTER
                xl.yformatter = LATITUDE_FORMATTER
                xl.xlabel_style = {'size': siz, 'color': 'k'}
                xl.ylabel_style = {'size': siz, 'color': 'k'}
                # Countries
                ax.add_feature(cartopy.feature.BORDERS, linestyle='--')
                cb = plt.colorbar(map, format='%1.1f')
                cb.set_label(lblr.getYlab(metric, variable))

        if cnst.LANGUAGE == 'ENGLISH':
            ax.set_title('WFDEI historical')
        else:
            ax.set_title('WFDEI historique')

        if not np.nansum(p['data'][1].data):
            ax1 = f.add_subplot(312)
            ax1.text(0.5, 0.5, 'Zero values', ha='center')
        else:
            try:
                ax1 = f.add_subplot(312, projection=ccrs.PlateCarree())
                data1 = np.ma.array(p['data'][1].data,
                                    mask=p['data'][1].data == np.nan)
                ax1.set_autoscale_on('False')
                # plt.gca().patch.set_color('.25')
                map1 = ax1.contourf(lon,
                                    lat,
                                    data1,
                                    transform=ccrs.PlateCarree(),
                                    cmap=p['cmap'],
                                    levels=p['levels'][1],
                                    extend='both')
                ax1.set_ylim(np.min(lat), np.max(lat))
                ax1.set_xlim(np.min(lon), np.max(lon))
            except ValueError:
                ax1 = f.add_subplot(312)
                ax1.text(0.5, 0.5, 'Zero values', ha='center')

            if map1:
                ax1.coastlines()
                # Gridlines
                siz = 6
                xl = ax1.gridlines(draw_labels=True)
                xl.xlabels_top = False
                xl.ylabels_right = False
                xl.xformatter = LONGITUDE_FORMATTER
                xl.yformatter = LATITUDE_FORMATTER
                xl.xlabel_style = {'size': siz, 'color': 'k'}
                xl.ylabel_style = {'size': siz, 'color': 'k'}
                # Countries
                ax1.add_feature(cartopy.feature.BORDERS, linestyle='--')
                cb = plt.colorbar(map1, format='%1.1f')
                # cb.set_label('10th percentile ' + p['cblabel'])
                cb.set_label(lblr.getYlab(metric, variable, anom=p['cblabel']))

        if cnst.LANGUAGE == 'ENGLISH':
            ax1.set_title('Future 90th percentile')
        else:
            ax1.set_title('90e percentile (futur)')

        if not np.nansum(p['data'][0].data):
            ax2 = f.add_subplot(313)
            ax2.text(0.5, 0.5, 'Zero values', ha='center')
        else:
            try:
                ax2 = f.add_subplot(313, projection=ccrs.PlateCarree())
                data2 = np.ma.array(p['data'][0].data,
                                    mask=p['data'][0].data == np.nan)
                ax2.set_autoscale_on('False')
                map2 = ax2.contourf(lon,
                                    lat,
                                    data2,
                                    transform=ccrs.PlateCarree(),
                                    cmap=p['cmap'],
                                    levels=p['levels'][0],
                                    extend='both')
                ax2.set_ylim(np.min(lat), np.max(lat))
                ax2.set_xlim(np.min(lon), np.max(lon))
            except ValueError:
                ax2 = f.add_subplot(313)
                ax2.text(0.5, 0.5, 'Zero values', ha='center')

            if map2:
                ax2.coastlines()
                # Gridlines
                xl = ax2.gridlines(draw_labels=True, )
                xl.xlabels_top = False
                xl.ylabels_right = False
                xl.xformatter = LONGITUDE_FORMATTER
                xl.yformatter = LATITUDE_FORMATTER
                xl.xlabel_style = {'size': siz, 'color': 'k'}
                xl.ylabel_style = {'size': siz, 'color': 'k'}
                # Countries
                ax2.add_feature(cartopy.feature.BORDERS, linestyle='--')
                cb = plt.colorbar(map2, format='%1.1f')
                cb.set_label(lblr.getYlab(metric, variable, anom=p['cblabel']))

        if cnst.LANGUAGE == 'ENGLISH':
            ax2.set_title('Future 10th percentile')
        else:
            ax2.set_title('10e percentile (futur)')

        f.suptitle(lblr.getTitle(metric,
                                 variable,
                                 season,
                                 scen,
                                 bc,
                                 region[1],
                                 anom=p['cblabel']),
                   fontsize=10)
        plt.tight_layout(rect=[0, 0.01, 1, 0.95])

        if (region[0] == 'BF') | (region[0] == 'SG'):
            plt.tight_layout(rect=[0, 0.01, 1, 0.95])
            f.subplots_adjust(right=0.8, left=0.2)
        else:
            plt.tight_layout(rect=[0, 0.01, 1, 0.95])
            f.subplots_adjust(left=0.05, right=1)
        plt.savefig(outpath + os.sep + fdict['metric'] + '_' +
                    fdict['variable'] + '_' + fdict['bc_res'] + '_' +
                    fdict['season'] + '_' + region[0] + '_mapPerc_' +
                    p['ftag'] + '.png')

        plt.close(f)
예제 #12
0
def nbModels_histogram_scenarios(incubes, outpath, region, anomaly=False):
    """
       Histogram plot showing the number of models within different ranges of the metric (anomaly) value for ALL scenarios
      :param incubes: wildcard path to all tseries multi-model cubes
      :param outpath: the path where the plot is saved
      :param region: the region dictionary as defined in constants
      :param anomaly: boolean, switch for anomaly calculation
      :return: plot
      """

    fname = incubes + '_tseries.nc'
    fdict = atlas_utils.split_filename_path(fname)

    if fdict['aggregation'] not in cnst.METRIC_AGGS[fdict['metric']]:
        return

    ano_list = glob.glob(fname)
    ano_list = atlas_utils.order(ano_list)

    ldata = []
    scen = []
    perc = []

    for ano in ano_list:

        toplot = None

        fdict = atlas_utils.split_filename_path(ano)
        scenario = fdict['scenario']
        metric = fdict['metric']
        variable = fdict['variable']
        season = fdict['season']
        bc = fdict['bc_res']

        if (anomaly == True) & (fdict['scenario'] == 'historical'):
            continue

        vname = cnst.VARNAMES[fdict['variable']]
        cube = iris.load_cube(ano)
        cube = atlas_utils.time_slicer(cube, fdict['scenario'])

        cube = cube.collapsed('year', iris.analysis.MEDIAN)

        if anomaly:
            ano_hist = ano.replace(fdict['scenario'], 'historical')
            hist = iris.load_cube(ano_hist)
            hist = atlas_utils.time_slicer(hist, 'historical')
            hist = hist.collapsed('year', iris.analysis.MEDIAN)

            data = atlas_utils.anomalies(hist, cube, percentage=False)
            data_perc = atlas_utils.anomalies(hist, cube, percentage=True)

            data = data.data
            data_perc = data_perc.data

            hhisto, bi = np.histogram(data,
                                      bins=np.linspace(data.min(), data.max(),
                                                       10))
            try:
                hhistop, bip = np.histogram(data_perc,
                                            bins=np.linspace(
                                                data_perc.min(),
                                                data_perc.max(), 10))
            except:
                continue

            an = 'anomaly'
            ylabel = lblr.getYlab(metric, variable, anom="anomaly")

            an_p = 'percentageAnomaly'
            ylabel_p = lblr.getYlab(metric, variable, anom="percentageAnomaly")

            ldata.append((hhisto, bi))
            perc.append((hhistop, bip))

        else:
            cube = cube.data
            hhisto, bi = np.histogram(cube,
                                      bins=np.linspace(cube.min(), cube.max(),
                                                       10))
            ldata.append((hhisto, bi))
            ylabel = lblr.getYlab(metric, variable, anom="")
            an = 'scenarios'

        scen.append(fdict['scenario'])

        plot_dic1 = {
            'data': ldata,
            'ftag': an,
            'ylabel': ylabel,
        }

        toplot = [plot_dic1]

        if anomaly and not 'tas' in variable:
            plot_dic2 = {
                'data': perc,
                'ftag': an_p,
                'ylabel': ylabel_p,
            }

            toplot = [plot_dic1, plot_dic2]

    if toplot:
        # This will only fail if both the historical and future are zero
        for p in toplot:

            if len(p['data']) < 4:
                xp = len(p['data'])
                yp = 1
                xx = 8
                yy = 6
            else:
                xp = 2
                yp = 2
                xx = 9
                yy = 5

            f = plt.figure(figsize=(xx, yy))

            for id in range(len(p['data'])):
                ax = f.add_subplot(xp, yp, id + 1)

                bin = p['data'][id][1]
                ax.bar(bin[0:-1] + ((bin[1::] - bin[0:-1]) / 2),
                       p['data'][id][0],
                       edgecolor='black',
                       width=(bin[1::] - bin[0:-1]),
                       align='edge',
                       color='darkseagreen')

                ax.set_xlabel(p['ylabel'])
                if cnst.LANGUAGE == 'ENGLISH':
                    ax.set_ylabel('Number of models')
                else:
                    ax.set_ylabel(u'Nombre de modèles')

                ax.set_title(lblr.getTitle(metric,
                                           variable,
                                           season,
                                           scenario,
                                           bc,
                                           region[1],
                                           anom=p['ftag']),
                             fontsize=10)

            plt.tight_layout()

            plt.savefig(outpath + os.sep + fdict['metric'] + '_' +
                        fdict['variable'] + '_' + fdict['bc_res'] + '_' +
                        fdict['season'] + '_' + region[0] +
                        '_MultiNbModelHistogram_' + p['ftag'] + '.png')

            plt.close(f)
예제 #13
0
def barplot_scenarios(incubes, outpath, region, anomaly=False):
    """
       Barplot showing the average of the (anomaly) metric over the climatological period for all
       individual models and scenarios.
       :param incubes: wildcard path to all tseries multi-model cubes
       :param outpath: the path where the plot is saved
       :param region: the region dictionary as defined in constants
       :param anomaly: boolean, switch for anomaly calculation
       :return: plot
       """

    fname = incubes + '_tseries.nc'
    fdict = atlas_utils.split_filename_path(fname)

    if fdict['aggregation'] not in cnst.METRIC_AGGS[fdict['metric']]:
        return

    # This creates a list of '*allModels_tseries.nc' files, one element for each scenario
    ano_list = glob.glob(fname)
    ano_list = atlas_utils.order(ano_list)

    ldata = []
    scen = []
    perc = []
    lmodels = []
    for ano in ano_list:

        fdict = atlas_utils.split_filename_path(ano)
        scenario = fdict['scenario']
        metric = fdict['metric']
        variable = fdict['variable']
        season = fdict['season']
        bc = fdict['bc_res']

        if (anomaly == True) & (fdict['scenario'] == 'historical'):
            continue

        cube = iris.load_cube(ano)
        cube = atlas_utils.time_slicer(cube, fdict['scenario'])
        cube = cube.collapsed('year', iris.analysis.MEDIAN)
        lmodels.append(np.ndarray.tolist(cube.coord('model_name').points))

        if anomaly:
            ano_hist = ano.replace(fdict['scenario'], 'historical')
            hist = iris.load_cube(ano_hist)
            hist = atlas_utils.time_slicer(hist, 'historical')
            hist = hist.collapsed('year', iris.analysis.MEDIAN)

            data = atlas_utils.anomalies(hist, cube, percentage=False)
            data_perc = atlas_utils.anomalies(hist, cube, percentage=True)

            an = 'anomaly'
            ylabel = lblr.getYlab(metric, variable, anom="anomaly")

            an_p = 'percentageAnomaly'
            ylabel_p = lblr.getYlab(metric, variable, anom="percentageAnomaly")
            dat_perc = np.ndarray.tolist(data_perc.data)
            perc.append(dat_perc)

        else:
            data = cube
            an = 'scenarios'
            ylabel = lblr.getYlab(metric, variable, anom="")

        dat = data.data
        dat = np.ndarray.tolist(dat)
        ldata.append(dat)

        scen.append(scenario)

    plot_dic1 = {
        'data': ldata,
        'xlabel': scen,
        'ftag': an,
        'ylabel': ylabel,
        'models': lmodels
    }

    toplot = [plot_dic1]

    if anomaly and not 'tas' in variable:
        plot_dic2 = {
            'data': perc,
            'xlabel': scen,
            'ftag': an_p,
            'ylabel': ylabel_p,
            'models': lmodels
        }

        toplot = [plot_dic1, plot_dic2]

    for p in toplot:

        if len(p['data']) < 4:
            xp = len(p['data'])
            yp = 1
            xx = 8
            yy = 7
        else:
            xp = 2
            yp = 2
            xx = 13
            yy = 8

        f = plt.figure(figsize=(xx, yy))

        for id in range(len(p['data'])):
            ax = f.add_subplot(xp, yp, id + 1)

            b = plt.bar(range(len(p['models'][id])),
                        p['data'][id],
                        align='edge',
                        label=p['models'][id],
                        color='darkseagreen')

            # plt.subplots_adjust(bottom=0.8)
            xticks_pos = [
                0.65 * patch.get_width() + patch.get_xy()[0] for patch in b
            ]

            plt.xticks(xticks_pos, p['models'][id], ha='right', rotation=45)

            plt.ylabel(p['ylabel'])
            plt.title(p['xlabel'][id])

        plt.tight_layout(h_pad=0.2, rect=(0, 0, 1, 0.92))
        plt.suptitle(lblr.getTitle(metric,
                                   variable,
                                   season,
                                   scen,
                                   bc,
                                   region[1],
                                   anom=p['ftag']),
                     fontsize=10)

        plt.savefig(outpath + os.sep + fdict['metric'] + '_' +
                    fdict['variable'] + '_' + fdict['bc_res'] + '_' +
                    fdict['season'] + '_' + region[0] + '_allModelHisto_' +
                    p['ftag'] + '.png')

        plt.close(f)
예제 #14
0
def nbModels_histogram_single(incubes, outpath, region, anomaly=False):
    """
    Histogram plot showing the number of models within different ranges of the metric (anomaly) value for a single scenario
   :param incubes: wildcard path to all tseries multi-model cubes
   :param outpath: the path where the plot is saved
   :param region: the region dictionary as defined in constants
   :param anomaly: boolean, switch for anomaly calculation
   :return: plot
   """

    fname = incubes + '_tseries.nc'
    fdict = atlas_utils.split_filename_path(fname)

    if fdict['aggregation'] not in cnst.METRIC_AGGS[fdict['metric']]:
        return

    ano = glob.glob(fname)
    if len(ano) != 1:
        print incubes
        pdb.set_trace()
        sys.exit('Found too many or no files, need one file')
    ano = ano[0]

    fdict = atlas_utils.split_filename_path(ano)
    scen = fdict['scenario']
    metric = fdict['metric']
    variable = fdict['variable']
    season = fdict['season']
    bc = fdict['bc_res']

    if (anomaly == True) & (scen == 'historical'):
        return

    cube = iris.load_cube(ano)
    cube = atlas_utils.time_slicer(cube, fdict['scenario'])
    cube.data = np.ma.masked_invalid(cube.data)

    cube = cube.collapsed('year', iris.analysis.MEDIAN)

    if anomaly:
        ano_hist = ano.replace(fdict['scenario'], 'historical')
        hist = iris.load_cube(ano_hist)
        hist = atlas_utils.time_slicer(hist, 'historical')
        hist.data = np.ma.masked_invalid(hist.data)
        hist = hist.collapsed('year', iris.analysis.MEDIAN)

        data = atlas_utils.anomalies(hist, cube, percentage=False)

        data_perc = atlas_utils.anomalies(hist, cube, percentage=True)

        data = np.ma.masked_invalid(data.data)
        data_perc = np.ma.masked_invalid(data_perc.data)

        if np.nansum(data) and np.ma.count(data):
            if np.nanmax(data) - np.nanmin(data) > np.nanmax(data):
                levels = atlas_utils.binlevels(data)
            else:
                levels = np.linspace(np.nanmin(data), np.nanmax(data), 14)
        else:
            levels = np.arange(-1, 1, 10)
            data = np.zeros_like(data)

        if np.nansum(data_perc) and np.ma.count(data):
            if np.nanmax(data_perc) - np.nanmin(data_perc) > np.nanmax(
                    data_perc):
                plevels = atlas_utils.binlevels(data_perc)
            else:
                plevels = np.linspace(np.nanmin(data_perc),
                                      np.nanmax(data_perc), 14)
        else:
            plevels = np.arange(-1, 1, 10)
            data_perc = np.zeros_like(data_perc)

        try:
            histo, h = np.histogram(data[np.isfinite(data)], bins=levels)
        except ValueError:
            pdb.set_trace()

        try:
            histop, hp = np.histogram(data_perc[np.isfinite(data_perc)],
                                      bins=plevels)
        except ValueError:
            pdb.set_trace()

        plot_dic1 = {
            'data': histo,
            'ftag': scen + 'Anomaly',
            'ylabel': lblr.getYlab(metric, variable, anom="anomaly"),
            'bins': h
        }

        if not 'tas' in variable:
            plot_dic2 = {
                'data': histop,
                'ftag': scen + 'PercentageAnomaly',
                'ylabel': lblr.getYlab(metric,
                                       variable,
                                       anom="percentageAnomaly"),
                'bins': hp
            }

            toplot = [plot_dic1, plot_dic2]

        else:
            toplot = [plot_dic1]

    else:
        cube = cube.data
        if np.nanmax(cube) - np.nanmin(cube) > np.nanmax(cube):
            levels = atlas_utils.binlevels(cube)
        else:
            levels = np.linspace(cube.min(), cube.max(), 10)

        histo, h = np.histogram(cube, bins=levels)
        plot_dic1 = {
            'data': histo,
            'ftag': scen,
            'ylabel': lblr.getYlab(metric, variable, anom=""),
            'bins': h
        }
        toplot = [plot_dic1]

    for p in toplot:
        f = plt.figure(figsize=lblr.getFigSize(None, 'nbModelHistogram'))
        ax = f.add_subplot(111)
        bin = p['bins']
        middle = bin[0:-1] + ((bin[1::] - bin[0:-1]) / 2)
        barlist = ax.bar(bin[0:-1] + ((bin[1::] - bin[0:-1]) / 2),
                         p['data'],
                         edgecolor='black',
                         width=(bin[1::] - bin[0:-1]),
                         color='lightblue')

        dummy = np.array(barlist)
        for d in dummy[middle < 0]:
            d.set_color('lightslategray')
            d.set_edgecolor('black')
        try:
            ax.set_xlim(
                np.floor(
                    np.nanmin((bin[0:-1])[(p['data']) > 0]) -
                    (bin[1] - bin[0])),
                np.ceil(
                    np.nanmax((bin[1::])[(p['data']) > 0]) +
                    (bin[-1] - bin[-2])))
        except ValueError:
            pass
        ax.set_xlabel(p['ylabel'])
        if cnst.LANGUAGE == 'ENGLISH':
            ax.set_ylabel('Number of models')
        else:
            ax.set_ylabel(u'Nombre de modèles')

        if not np.nansum(p['data']):
            ax.text(0.5, 0.5, 'Zero values', zorder=10)
            print metric, 'set text'
        ax.set_title(lblr.getTitle(metric,
                                   variable,
                                   season,
                                   scen,
                                   bc,
                                   region[1],
                                   anom=p['ftag']),
                     fontsize=11)
        plt.savefig(outpath + os.sep + fdict['metric'] + '_' +
                    fdict['variable'] + '_' + fdict['bc_res'] + '_' +
                    fdict['season'] + '_' + region[0] + '_nbModelHistogram_' +
                    p['ftag'] + '.png')
        plt.close(f)
예제 #15
0
def boxplot_scenarios(incubes, outpath, region, anomaly=False):
    """
       Produces a boxplot with a box for each scenario, indicating the model spread.
       :param incubes: wildcard path to all tseries multi-model cubes
       :param outpath: the path where the plot is saved
       :param region: the region dictionary as defined in constants
       :param anomaly: boolean, switch for anomaly calculation
       :return: plot
       """

    fname = incubes + '_tseries.nc'
    fdict = atlas_utils.split_filename_path(fname)

    if fdict['aggregation'] not in cnst.METRIC_AGGS[fdict['metric']]:
        return

    ano_list = glob.glob(fname)
    ano_list = atlas_utils.order(ano_list)

    ldata = []
    scen = []
    perc = []

    for ano in ano_list:
        print ano
        fdict = atlas_utils.split_filename_path(ano)
        metric = fdict['metric']
        variable = fdict['variable']
        season = fdict['season']
        scenario = fdict['scenario']
        bc = fdict['bc_res']

        if (anomaly == True) & (fdict['scenario'] == 'historical'):
            continue

        cube = iris.load_cube(ano)
        cube = atlas_utils.time_slicer(cube, fdict['scenario'])
        cube = cube.collapsed('year', iris.analysis.MEDIAN)

        if anomaly:
            ano_hist = ano.replace(fdict['scenario'], 'historical')
            hist = iris.load_cube(ano_hist)
            hist = atlas_utils.time_slicer(hist, 'historical')
            hist = hist.collapsed('year', iris.analysis.MEDIAN)

            data = atlas_utils.anomalies(hist, cube, percentage=False)

            data_perc = atlas_utils.anomalies(hist, cube, percentage=True)

            an = 'anomaly'
            ylabel = lblr.getYlab(metric, variable, anom='absolute')

            an_p = 'percentageAnomaly'
            ylabel_p = lblr.getYlab(metric, variable, anom='percentage')
            dat_perc = np.ndarray.tolist(data_perc.data)
            perc.append(dat_perc)

        else:
            data = cube
            an = 'scenarios'
            ylabel = lblr.getYlab(metric, variable, anom=None)

        dat = data.data
        dat = np.ndarray.tolist(dat)
        ldata.append(dat)

        scen.append(fdict['scenario'])

    plot_dic1 = {'data': ldata, 'xlabel': scen, 'ftag': an, 'ylabel': ylabel}

    toplot = [plot_dic1]

    if anomaly and not 'tas' in variable:
        plot_dic2 = {
            'data': perc,
            'xlabel': scen,
            'ftag': an_p,
            'ylabel': ylabel_p
        }

        toplot = [plot_dic1, plot_dic2]

    for p in toplot:

        f = plt.figure(figsize=(8, 7))

        try:
            bp = plt.boxplot(p['data'],
                             labels=p['xlabel'],
                             sym='',
                             patch_artist=True,
                             notch=False,
                             zorder=9,
                             whis=[10, 90])
        except ValueError:
            print('Boxplot data has a problem, please check. Cannot continue')
            pdb.set_trace()

        plt.title(lblr.getTitle(metric,
                                variable,
                                season,
                                scenario,
                                bc,
                                region[1],
                                anom=p['ftag']),
                  fontsize=10)

        if cnst.LANGUAGE == 'ENGLISH':
            plt.xlabel('Scenario')
            plt.ylabel(p['ylabel'])
        else:
            plt.xlabel(u'Scénario')
            plt.ylabel(p['ylabel'])

        for median, box, lab in zip(bp['medians'], bp['boxes'], p['xlabel']):
            box.set(facecolor='none')
            median.set(linewidth=0)  #, color='steelblue')

        for id, d in enumerate(p['data']):
            try:
                plt.scatter([id + 1] * len(d),
                            d,
                            marker='_',
                            color='firebrick',
                            s=60,
                            zorder=9)
            except:
                pdb.set_trace()

        if np.nanmax(d) - np.nanmin(d) > np.nanmax(d):
            plt.hlines(0, 0, len(d), linestyle='dashed', color='grey')

        plt.savefig(outpath + os.sep + fdict['metric'] + '_' +
                    fdict['variable'] + '_' + fdict['bc_res'] + '_' +
                    fdict['season'] + '_' + region[0] + '_allModelBoxplot_' +
                    p['ftag'] + '.png')

        plt.close(f)
예제 #16
0
def boxplotMonthlyClim(incubes, outpath, region, anomaly=False):
    """
       Produces a boxplot with a box for each scenario, indicating the model spread.
       :param incubes: wildcard path to all tseries multi-model cubes
       :param outpath: the path where the plot is saved
       :param region: the region dictionary as defined in constants
       :param anomaly: boolean, switch for anomaly calculation
       :return: plot
       """

    fname = incubes + '_tseries.nc'
    fdict = atlas_utils.split_filename_path(fname)

    if fdict['aggregation'] not in cnst.METRIC_AGGS[fdict['metric']]:
        return

    ano = glob.glob(fname)
    if len(ano) != 1:
        print incubes
        pdb.set_trace()
        sys.exit('Found too many or no files, need one file')
    ano = ano[0]

    fdict = atlas_utils.split_filename_path(ano)
    scen = fdict['scenario']
    metric = fdict['metric']
    variable = fdict['variable']
    season = fdict['season']
    bc = fdict['bc_res']

    if (anomaly == True) & (scen == 'historical'):
        return

    cube = iris.load_cube(ano)
    cube.remove_coord('year')
    cube.remove_coord('time')

    if anomaly:
        ano_hist = ano.replace(fdict['scenario'], 'historical')
        hist = iris.load_cube(ano_hist)
        hist.remove_coord('year')
        hist.remove_coord('time')

        data = atlas_utils.anomalies(hist, cube, percentage=False)
        data_perc = atlas_utils.anomalies(hist, cube, percentage=True)

        data = data.data
        data_perc = data_perc.data

        plot_dic1 = {
            'data': data,
            'ftag': scen + 'Anomaly',
            'ylabel': lblr.getYlab(metric, variable, anom="anomaly"),
        }

        if not 'tas' in variable:
            plot_dic2 = {
                'data': data_perc,
                'ftag': scen + 'PercentageAnomaly',
                'ylabel': lblr.getYlab(metric,
                                       variable,
                                       anom="percentageAnomaly"),
            }

            toplot = [plot_dic1, plot_dic2]

        else:
            toplot = [plot_dic1]

    else:
        cube = cube.data
        plot_dic1 = {
            'data': cube,
            'ftag': scen,
            'ylabel': lblr.getYlab(metric, variable, anom=""),
        }
        toplot = [plot_dic1]

    for p in toplot:

        f = plt.figure(figsize=(8, 7))

        # do_jitter(p['data'], f.gca())
        data = np.transpose(p['data'])
        try:
            bp = plt.boxplot(p['data'],
                             sym='',
                             patch_artist=True,
                             notch=False,
                             zorder=9,
                             whis=[10, 90])
        except ValueError:
            print('Boxplot data has a problem, please check. Cannot continue')
            pdb.set_trace()
        plt.title(lblr.getTitle(metric,
                                variable,
                                season,
                                scen,
                                bc,
                                region[1],
                                anom=p['ftag']),
                  fontsize=10)  # (region[1])
        if cnst.LANGUAGE == 'ENGLISH':
            plt.xlabel('Month')
            plt.ylabel(p['ylabel'])
        else:
            plt.xlabel('Mois')
            plt.ylabel(p['ylabel'])

        for median, box in zip(bp['medians'], bp['boxes']):
            box.set(facecolor='none')
            median.set(linewidth=0)  #, color='steelblue')

        for id, d in enumerate(data):
            try:
                plt.scatter([id + 1] * len(d),
                            d,
                            marker='_',
                            color='firebrick',
                            s=60,
                            zorder=9)
            except:
                pdb.set_trace()

        if np.nanmax(d) - np.nanmin(d) > np.nanmax(d):
            plt.hlines(0, 0, len(d), linestyle='dashed', color='grey')

        plt.savefig(outpath + os.sep + fdict['metric'] + '_' +
                    fdict['variable'] + '_' + fdict['bc_res'] + '_' +
                    fdict['season'] + '_' + region[0] + '_allModelMonthClim_' +
                    p['ftag'] + '.png')

        plt.close(f)
예제 #17
0
def modelRank_scatter_single(incubes, outpath, region, anomaly=False):
    """
    Scatter plot showing the model ranks for a metric (anomaly) for a single scenario
   :param incubes: wildcard path to all tseries multi-model cubes
   :param outpath: the path where the plot is saved
   :param region: the region dictionary as defined in constants
   :param anomaly: boolean, switch for anomaly calculation
   :return: plot
   """

    fname = incubes + '_tseries.nc'
    fdict = atlas_utils.split_filename_path(fname)

    if fdict['aggregation'] not in cnst.METRIC_AGGS[fdict['metric']]:
        return

    ano = glob.glob(fname)
    if len(ano) != 1:
        sys.exit('Found too many files, need one file')
    ano = ano[0]

    fdict = atlas_utils.split_filename_path(ano)
    scen = fdict['scenario']
    metric = fdict['metric']
    variable = fdict['variable']
    season = fdict['season']
    bc = fdict['bc_res']

    if (anomaly == True) & (scen == 'historical'):
        return

    cube = iris.load_cube(ano)
    cube = atlas_utils.time_slicer(cube, fdict['scenario'])
    cube = cube.collapsed('year', iris.analysis.MEDIAN)

    if anomaly:
        ano_hist = ano.replace(fdict['scenario'], 'historical')
        hist = iris.load_cube(ano_hist)
        hist = atlas_utils.time_slicer(hist, 'historical')
        hist = hist.collapsed('year', iris.analysis.MEDIAN)

        data = atlas_utils.anomalies(hist, cube, percentage=False)
        data_perc = atlas_utils.anomalies(hist, cube, percentage=True)

        data = np.ndarray.tolist(data.data)
        data.sort()
        data_perc = np.ndarray.tolist(data_perc.data)
        data_perc.sort()

        plot_dic1 = {
            'data': data,
            'ftag': scen + 'Anomaly',
            'ylabel': lblr.getYlab(metric, variable, anom="anomaly"),
            # vname + ' anomaly: ' + fdict['metric'],
            'minmax': atlas_utils.data_minmax(data)
        }

        if not 'tas' in variable:
            plot_dic2 = {
                'data': data_perc,
                'ftag': scen + 'PercentageAnomaly',
                'ylabel': lblr.getYlab(metric,
                                       variable,
                                       anom="percentageAnomaly"),
                # vname + ' anomaly percentage: ' + fdict['metric'],
                'minmax': atlas_utils.data_minmax(data_perc)
            }
            toplot = [plot_dic1, plot_dic2]
        else:
            toplot = [plot_dic1]

    else:
        cube = cube.data
        cube = np.ndarray.tolist(cube)
        cube.sort()

        plot_dic1 = {
            'data': cube,
            'ftag': scen,
            'ylabel': lblr.getYlab(metric, variable, anom=""),
            'minmax': atlas_utils.data_minmax(cube)
        }

        toplot = [plot_dic1]

    for p in toplot:

        cms = 'seismic' if 'tas' in variable else 'seismic_r'
        cm = plt.get_cmap(cms)

        f = plt.figure(figsize=(8.5, 6))

        if np.nanmax(p['data']) - np.nanmin(p['data']) > np.nanmax(p['data']):
            plt.hlines(0, 0, len(p['data']), linestyle='dashed', color='grey')

        for i in range(0, len(p['data'])):
            plt.scatter(i,
                        p['data'][i],
                        c=p['data'][i],
                        vmin=p['minmax'][0],
                        vmax=p['minmax'][1],
                        cmap=cm,
                        edgecolors='k',
                        s=50,
                        zorder=10)

        plt.ylabel(p['ylabel'])
        if cnst.LANGUAGE == 'ENGLISH':
            plt.xlabel("Model Rank")
        else:
            plt.xlabel(u"Classement de modèles")

        plt.title(lblr.getTitle(metric,
                                variable,
                                season,
                                scen,
                                bc,
                                region[1],
                                anom=p['ftag']),
                  fontsize=11)
        plt.tick_params(axis='x', which='both', bottom='off', top='off')

        plt.savefig(outpath + os.sep + fdict['metric'] + '_' +
                    fdict['variable'] + '_' + fdict['bc_res'] + '_' +
                    fdict['season'] + '_' + region[0] + '_allModelRank_' +
                    p['ftag'] + '.png',
                    dpi=400)

        plt.close(f)
예제 #18
0
def trend(cubein, season, ncfile):
    '''
    Calculates the annual trend either for 1950-2000 or for 2010-2060
    Can calculate the trend for one period, or (if 'month_number' is a coordinate name), it will calculate the trend for each month
    
    :param incube: timeseries of a metric either for 1 period (e.g. JAS), or for all months of the year
    :param season: season name as recognised by the function _getSeasConstr
    :param ncfile: full string for output netcdf file
    returns: trend for a single model netcdf 

    TODO: Review code & check that behaviour for multiple months is as expected
    '''

    fdict = atlas_utils.split_filename_path(ncfile)

    if 'month_number' not in [coord.name() for coord in cubein.coords()]:
        iris.coord_categorisation.add_month_number(cubein,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in cubein.coords()]:
        iris.coord_categorisation.add_year(cubein, 'time', name='year')

    incube = atlas_utils.time_slicer(cubein, fdict['scenario'])

    # Make sure there aren't any invalid grid cells in the data
    incube.data = ma.masked_invalid(incube.data)

    # Are we quantifying the trend for each month of the year ('ann') or just for one period (e.g. JAS)?
    if "pr_" in ncfile and not "SPIxMonthly" in ncfile:
        incube_y = incube.aggregated_by(['year'], iris.analysis.SUM)
        incube_y.convert_units('kg m-2 month-1')

    if ("tas_" in ncfile) or ('tasmax_' in ncfile) or ('tasmin_' in ncfile):
        incube_y = incube.aggregated_by(['year'], iris.analysis.MEAN)
        try:
            incube_y.convert_units('Celsius')
        except ValueError:
            if np.mean(incube_y.data) > 100:
                incube_y.units = cf_units.Unit('K')
            else:
                incube_y.units = cf_units.Unit('Celsius')
    else:
        incube_y = incube.aggregated_by(['year'], iris.analysis.MEAN)

    month_numbers = np.unique(incube_y.coord('month_number').points)

    if len(month_numbers) > 1:

        if "pr_" in ncfile:
            incube_ym = incube.aggregated_by(['year', 'month_number'],
                                             iris.analysis.SUM)
            incube_ym.convert_units('kg m-2 month-1')

        if ("tas_" in ncfile) or ("tasmax_" in ncfile) or ("tasmin_"
                                                           in ncfile):
            incube_ym = incube.aggregated_by(['year', 'month_number'],
                                             iris.analysis.MEAN)
            incube_ym.convert_units('Celsius')

        slopedata1mon = np.zeros(incube_ym[0].shape).reshape(
            (1, incube_ym[0].shape[0], incube_ym[0].shape[1]))
        slopedata = np.repeat(slopedata1mon, 12, axis=0)
        moncoord = iris.coords.DimCoord(points=np.arange(1, 13),
                                        long_name='month_number',
                                        units='1')
        slope = iris.cube.Cube(slopedata,
                               long_name='Trend',
                               units=incube_ym.units,
                               dim_coords_and_dims=[
                                   (moncoord, 0),
                                   (incube.coord('latitude'), 1),
                                   (incube.coord('longitude'), 2)
                               ])
        for mon in month_numbers:
            # print mon
            slicer = iris.Constraint(month_number=lambda cell: cell == mon)
            incube1mon = incube_ym.extract(slicer)
            for x in np.arange(len(incube.coord('longitude').points)):
                for y in np.arange(len(incube.coord('latitude').points)):
                    if np.all(incube1mon.data[:, y, x].mask):
                        slope.data[mon - 1, y, x] = ma.masked
                    else:
                        # Outputs: slope, intercept, r-value, pvalue, std_err
                        # for py34: reg.slope
                        reg = stats.linregress(np.arange(incube1mon.shape[0]),
                                               incube1mon.data[:, y, x])
                        slope.data[mon - 1, y, x] = reg[0]

    else:
        # No need to loop through months in this case
        slopedata = np.zeros(incube_y[0].shape)
        slope = iris.cube.Cube(slopedata,
                               long_name='Trend',
                               units=incube_y.units,
                               dim_coords_and_dims=[
                                   (incube.coord('latitude'), 0),
                                   (incube.coord('longitude'), 1)
                               ])
        for x in np.arange(len(incube.coord('longitude').points)):
            for y in np.arange(len(incube.coord('latitude').points)):
                if np.all(incube_y.data[:, y, x].mask):
                    slope.data[y, x] = ma.masked
                else:
                    # Outputs: slope, intercept, r-value, pvalue, std_err
                    # for py34: reg.slope
                    reg = stats.linregress(np.arange(incube_y.shape[0]),
                                           incube_y.data[:, y, x])
                    slope.data[y, x] = reg[0]

    return (slope)
예제 #19
0
def onsetMarteau(incube, season, ncfile):
    """
    Calculate Marteau monsoon onset. Season is fixed to onset period

    :param incube: precipitation cube from CMIP5 raw data
    :param ncfile: full string for output netcdf file
    :return: single model netcdf file
    """

    season = 'mjjas'
    fdict = atlas_utils.split_filename_path(ncfile)

    if 'month_number' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_month_number(incube,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_year(incube, 'time', name='year')
    if 'day_of_year' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_day_of_year(incube,
                                                  'time',
                                                  name='day_of_year')

    slicer = _getSeasConstr(season)
    cubein = incube.extract(slicer)

    cube2plot = cubein
    _calcUnit(cube2plot, ncfile)
    yrs = cube2plot.aggregated_by('year', iris.analysis.MEAN)

    empty = yrs.data
    years = yrs.coord('year').points
    dates = []
    tester = 14
    onsets = np.zeros((empty.shape[0], empty.shape[1], empty.shape[2]), float)

    for yr in years:
        yrslice = iris.Constraint(year=lambda cell: cell == yr)
        holdr = cubein.extract(yrslice)
        strt_date = holdr.coord('day_of_year').points[0]
        holdr = holdr.data
        for x in range(0, holdr.shape[2]):
            for y in range(0, holdr.shape[1]):
                latmean = 0
                cnt0 = 0
                A = 0
                B = 0
                C = 0
                for t in xrange(0, holdr.shape[0] - tester - 6):
                    if holdr[t, y, x] > 1.0:
                        A4 = 1
                    else:
                        A4 = 0
                    if holdr[t + 1, y, x] + holdr[t, y, x] > 20.0:
                        A1 = 1
                    else:
                        A1 = 0
                    A2 = 1
                    t2 = 2
                    while t2 < tester - 6:
                        drytest = holdr[t + t2, y, x] + holdr[
                            t + t2 + 1, y,
                            x] + holdr[t + t2 + 2, y, x] + holdr[
                                t + t2 + 3, y,
                                x] + holdr[t + t2 + 4, y, x] + holdr[
                                    t + t2 + 5, y, x] + holdr[t + t2 + 6, y, x]
                        if drytest < 5.0:
                            A2 = 0
                            break
                        else:
                            t2 = t2 + 1
                    A3 = A4 + A2 + A1
                    if A3 == 3:
                        latmean = t + strt_date

                        onsets[yr - years[0], y, x] = latmean

                        break
                    else:
                        continue
                    break
                if latmean == 0:
                    onsets[yr - years[0], y, x] = np.nan

    yrs.data = ma.masked_invalid(onsets)
    tseries = yrs.collapsed(['longitude', 'latitude'], iris.analysis.MEDIAN)

    yrs2d = atlas_utils.time_slicer(yrs, fdict['scenario'])
    c2d = yrs2d.collapsed('year', iris.analysis.MEDIAN)
    trend2d = trend(yrs, season, ncfile)

    nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])
    nctrend2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[2])

    iris.save(tseries, ncfile)
    iris.save(c2d, nc2d)
    iris.save(trend2d, nctrend2d)
예제 #20
0
def SPIxMonthly(incube, season, ncfile):
    """
    Calculate SPI for given months up to one year.
    The SPI is the anomaly with respect to the chosen scenario baseline period.
    period - climatological_mean / climatological_std

    :param incube: precipitation cube from CMIP5 raw data
    :param season: string indicating season, read by _getSeasConstr() to get season contraint
    :param ncfile: full string for output netcdf file
    :return: single model netcdf file
    """

    print 'Calculating SPI for ' + str(season)
    fdict = atlas_utils.split_filename_path(ncfile)

    if 'month_number' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_month_number(incube,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_year(incube, 'time', name='year')

    slicer = _getSeasConstr(season)

    incube = incube.extract(slicer)

    incube.convert_units('kg m-2 day-1')
    c_monthly = atlas_utils.time_slicer(
        incube, fdict['scenario'])  # shorten time period
    c_monthly = c_monthly.aggregated_by(['year'], iris.analysis.MEAN)

    # This is the monthly climatology (mean and std deviation)
    std = c_monthly.collapsed('year', iris.analysis.STD_DEV)
    mean = c_monthly.collapsed('year', iris.analysis.MEAN)

    # We need to change the shape of the monthly climatologies to match the shape of the timeseries (in the cube c_monthly)
    mean = mean.data
    std = std.data

    clim_mean_data = np.repeat(
        mean.reshape(1, mean.shape[0], mean.shape[1]),
        c_monthly.shape[0],
        axis=0
    )  # np.tile(mean.data, (c_monthly.shape[0] / mean.shape[0], 1, 1))
    clim_std_data = np.repeat(
        std.reshape(1, std.shape[0], std.shape[1]), c_monthly.shape[0],
        axis=0)  # np.tile(std.data, (c_monthly.shape[0] / std.shape[0], 1, 1))

    clim_mean_cube = c_monthly.copy(clim_mean_data)
    clim_std_cube = c_monthly.copy(clim_std_data)

    spi = (c_monthly - clim_mean_cube) / clim_std_cube

    #iris.save(spi, ncfile)  #SPI is 3d cube at the moment. Not sure what we want to plot!

    tseries = spi.collapsed(['longitude', 'latitude'], iris.analysis.MEDIAN)

    calc2d = atlas_utils.time_slicer(spi, fdict['scenario'])
    c2d = calc2d.collapsed('year', iris.analysis.MEDIAN)
    trend2d = trend(spi, season, ncfile)

    nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])
    nctrend2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[2])

    iris.save(tseries, ncfile)  # monthly time series, 12 entries
    iris.save(c2d, nc2d)
    iris.save(trend2d, nctrend2d)
예제 #21
0
def pet(cubein, season, ncfile):
    '''
    Calculates the potential evapotranspiration on a daily timestep, and aggregates over a time period 

    :param incube: precipitation cube from CMIP5 raw data. Note that this is used as a template to retrieve the other variables required
    :param season: string indicating season, read by _getSeasConstr() to get season contraint
    :param ncfile: full string for output netcdf file
    :return: single model netcdf file
    '''

    print 'Calculating Potential Evapotranspiration'

    # Retrieve all data first
    tasmin = cubein[0]
    tasmax = cubein[1]
    rsds = cubein[2]

    tasmin.data = ma.masked_invalid(tasmin.data)
    tasmax.data = ma.masked_invalid(tasmax.data)
    rsds.data = ma.masked_invalid(rsds.data)

    # Get details
    fdict = atlas_utils.split_filename_path(ncfile)

    # NB: Had to do it this way because iris didn't like power function
    try:
        tas_dif = tasmax - tasmin
    except ValueError:
        print 'Cubes not of same length (timestep?), returning'
        return

    tas_dif.data = tas_dif.data**0.5

    # NB: SW incoming radiation (in W m-2) needs to be converted to MJ m-2 and then mm day-1 equivalent using the following:
    # 1 W m-2 = 0.0864 MJ m-2 day-1
    # The value of 0.408 is the inverse of the latent heat flux of vaporization at 20C, changing the extraterrestrial radiation units from MJ m-2 day-1 into mm day-1 of evaporation equivalent (Allen et al., 1998)
    # pet = 0.0023 * ((tasmax+tasmin)/2 + 17.8) * (tasmax-tasmin)**0.5 * rsds

    try:
        pet = 0.0023 * (
            (tasmax + tasmin) / 2 + 17.8) * tas_dif * (rsds * 0.0864 * 0.408)
    except ValueError:
        # TODO: Work out why some models fail this test (e.g. bcc-csm1-1, HadGEM2-AO, CMCC-CM)
        print 'There was a value error for ' + ncfile
        return

    #Now aggregate to the season and according to the aggregation types

    slicer = _getSeasConstr(season)

    if 'month_number' not in [coord.name() for coord in pet.coords()]:
        iris.coord_categorisation.add_month_number(pet,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in pet.coords()]:
        iris.coord_categorisation.add_year(pet, 'time', name='year')

    pet = pet.extract(slicer)
    pet.units = cf_units.Unit(
        'mm day-1'
    )  # Over-rides units because temp and radiation values are used to give an approximation of potential evapotranspiration in mm per day
    pet.data = ma.masked_invalid(pet.data)

    calc = pet.aggregated_by(['year'], iris.analysis.MEAN)
    tseries = calc.collapsed(['longitude', 'latitude'], iris.analysis.MEDIAN)

    calc2d = atlas_utils.time_slicer(calc, fdict['scenario'])
    c2d = calc2d.collapsed('year', iris.analysis.MEDIAN)
    trend2d = trend(calc, season, ncfile)

    nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])
    nctrend2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[2])

    iris.save(tseries, ncfile)
    iris.save(c2d, nc2d)
    iris.save(trend2d, nctrend2d)
예제 #22
0
def _countSpells(incube,
                 season,
                 ncfile,
                 spell_length=None,
                 lower_threshold=None,
                 upper_threshold=None):
    """
    Calculates the number of periods of a spell of length 'spell length' above or equal
    'lower threshold' or below 'upper threshold'.

    :param incube: single variable cube from CMIP5 raw data
    :param season: string indicating season, read by _getSeasConstr() to get season contraint
    :param ncfile: full string for output netcdf file
    :param spell_length: length
    :param lower_threshold:
    :param upper_threshold:
    :return: single model netcdf file
    """
    def count_func(data, threshold, axis, spell_length):
        #        print(data.shape)
        #        print(axis)
        if axis < 0:
            # just cope with negative axis numbers
            axis += data.ndim
        # print(axis)
        # Threshold the data to find the 'significant' points.
        if lower_threshold:
            data_hits = data >= threshold

        if upper_threshold:
            data_hits = data < threshold

        # Make an array with data values "windowed" along the time axis.
        hit_windows = iris.util.rolling_window(
            data_hits, window=spell_length,
            axis=axis)  # rolling window along time axis

        # Find the windows "full of True-s" (along the added 'window axis').
        full_windows = np.all(hit_windows, axis=axis + 1)
        # Count points fulfilling the condition (along the time axis).
        spell_point_counts = np.nansum(full_windows, axis=axis, dtype=int)
        return spell_point_counts

    if not spell_length:
        print "No spell length given, please provide. Stopping calculation"
        return

    if (upper_threshold and lower_threshold):
        print "Upper and lower threshold given. Please provide exactly one (upper or lower) threshold. Stopping calculation"
        return

    if not (upper_threshold or lower_threshold):
        print "No threshold given. Please provide one (upper or lower) threshold. Stopping calculation"
        return

    fdict = atlas_utils.split_filename_path(ncfile)

    if upper_threshold:
        threshold = upper_threshold
    else:
        threshold = lower_threshold

    print ncfile
    print "Calculating number of spells equal or longer than " + str(
        spell_length) + ' days.'

    if 'month_number' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_month_number(incube,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_year(incube, 'time', name='year')

    slicer = _getSeasConstr(season)
    incube = incube.extract(slicer)
    incube.coord('latitude').guess_bounds()
    incube.coord('longitude').guess_bounds()

    _calcUnit(incube, ncfile)
    incube.data = ma.masked_invalid(incube.data)

    # Start spell calculation
    # Make an aggregator from days count
    SPELL_COUNT = iris.analysis.Aggregator('spell_count',
                                           count_func,
                                           units_func=lambda units: 1)
    # Calculate the statistic
    calc = incube.aggregated_by(['year'],
                                SPELL_COUNT,
                                threshold=threshold,
                                spell_length=spell_length)
    calc.units = incube.units
    calc.data = np.array(calc.data, dtype=float)
    calc.data = ma.masked_invalid(calc.data)

    tseries = calc.collapsed(['longitude', 'latitude'], iris.analysis.MEDIAN)

    calc2d = atlas_utils.time_slicer(calc, fdict['scenario'])
    c2d = calc2d.collapsed('year', iris.analysis.MEDIAN)
    trend2d = trend(calc, season, ncfile)

    nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])
    nctrend2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[2])

    iris.save(tseries, ncfile)  # full time period
    iris.save(c2d, nc2d)  # sliced time period
    iris.save(trend2d, nctrend2d)  # values for trend period
예제 #23
0
def _annualnbDayPerc(incube,
                     season,
                     ncfile,
                     upper_threshold=None,
                     lower_threshold=None):
    '''
    Calculate percentage of days per year with higher value than threshold.
    Choose thresholds as needed e.g. 30mm for extreme and 1mm for rainy day.

    :param incube: precipitation cube from CMIP5 raw data
    :param season: string indicating season, read by _getSeasConstr() to get season contraint
    :param ncfile: full string for output netcdf file
    :param upper_threshold: threshold (>=) defining the value to be exceeded (e.g. extreme value or rainy day value
    :param lower_threshold: threshold (>=) defining the minimum value of valid pixels (eg. 0 or 0.1 or 1)
    :return: single model netcdf file
    '''
    if not upper_threshold:
        print "No threshold given, please provide upper threshold, stopping calculation"
        return

    print ncfile
    print "Calculating percentage of days with variable above " + str(
        upper_threshold)
    fdict = atlas_utils.split_filename_path(ncfile)

    if 'month_number' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_month_number(incube,
                                                   'time',
                                                   name='month_number')
    if 'year' not in [coord.name() for coord in incube.coords()]:
        iris.coord_categorisation.add_year(incube, 'time', name='year')

    slicer = _getSeasConstr(season)
    incube = incube.extract(slicer)
    incube.coord('latitude').guess_bounds()
    incube.coord('longitude').guess_bounds()

    _calcUnit(incube, ncfile)

    bigger = incube.aggregated_by(
        'year',
        iris.analysis.COUNT,
        function=lambda values: values >= upper_threshold)
    monthcount = incube.aggregated_by(
        'year',
        iris.analysis.COUNT,
        function=lambda values: values >= lower_threshold)
    bigger.data = np.ma.masked_invalid(bigger.data.astype(float))
    monthcount.data = monthcount.data.astype(float)
    monthcount[monthcount == 0] = np.nan
    monthcount.data = np.ma.masked_invalid(monthcount.data)

    trend_data = bigger / monthcount * 100

    trend_data.units = incube.units
    trend2d = trend(trend_data, season, ncfile)

    bigger_tseries = bigger.collapsed(['longitude', 'latitude'],
                                      iris.analysis.SUM)

    bigger2d = atlas_utils.time_slicer(bigger, fdict['scenario'])
    bigger_c2d = bigger2d.collapsed('year', iris.analysis.SUM)

    monthcount_tseries = monthcount.collapsed(['longitude', 'latitude'],
                                              iris.analysis.SUM)
    monthcount_tseries[monthcount_tseries == 0] = np.nan
    monthcount_tseries.data = np.ma.masked_invalid(monthcount_tseries.data)

    monthcount2d = atlas_utils.time_slicer(monthcount, fdict['scenario'])
    monthcount_c2d = monthcount2d.collapsed('year', iris.analysis.SUM)
    monthcount_c2d[monthcount_c2d == 0] = np.nan
    monthcount_c2d.data = np.ma.masked_invalid(monthcount_c2d.data)

    tseries = (bigger_tseries / monthcount_tseries) * 100
    c2d = (bigger_c2d / monthcount_c2d) * 100

    nc2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[1])
    nctrend2d = ncfile.replace(cnst.AGGREGATION[0], cnst.AGGREGATION[2])
    iris.save(tseries, ncfile)
    iris.save(c2d, nc2d)
    iris.save(trend2d, nctrend2d)