Ejemplo n.º 1
0
def land_permafrost_top(run):
    """
    Make permafrost metrics.

    Code development Eleanor Burke.

    Arguments:
        run - dictionary containing model run metadata
              (see auto_assess/model_run.py for description)

    Returns:
        metrics - dictionary of metrics names and values
        also produces image files in the current working directory

    """
    metrics = dict()

    # Load the whole monthly soil temperature time-sequence as a single cube.
    # STASH m01s08i225
    period = "monthly"
    soiltemp = load_run_ss(
        run, period, 'soil_temperature')  # has dims(time, depth, lat, long)

    # check soil depths
    expected_soil_depths = [0.05, 0.225, 0.675, 2.0]
    soil_depths = soiltemp.coord('depth')
    if np.array_equal(soil_depths, expected_soil_depths):
        msg = ('Soil has changed levels from usual {}, '
               'following not supported: {}'.format(expected_soil_depths,
                                                    soil_depths))
        raise Exception(msg)

    # load the whole monthly air temperature (STASH m01s03i236)
    airtemp = load_run_ss(run, period, 'air_temperature')

    # get the land fraction mask using whole cube
    landfrac = get_landfr_mask(run)

    # extract northern latitudes
    airtemp = airtemp.extract(iris.Constraint(latitude=lambda cell: cell > 0))
    soiltemp = soiltemp.extract(
        iris.Constraint(latitude=lambda cell: cell > 0))

    # calculate the permafrost area and fraction less than zero
    # permafrost_area returns a dict, which is added to the main metrics dict
    # by metrics.update()
    metrics.update(permafrost_area(soiltemp, airtemp, landfrac, run))

    # calculate the koven temperature metrics
    metrics.update(koven_temp_offsets(soiltemp, airtemp))
    metrics.update(koven_temp_atten(soiltemp, airtemp))

    return metrics
Ejemplo n.º 2
0
def mainfunc(run):
    """Main function in stratospheric assessment code."""
    metrics = dict()

    # Set up to only run for 10 year period (eventually)
    year_cons = dict(from_dt=run['from_monthly'], to_dt=run['to_monthly'])

    # Read zonal mean U (lbproc=192) and add month number to metadata
    ucube = load_run_ss(
        run, 'monthly', 'eastward_wind', lbproc=192, **year_cons)
    # Although input data is a zonal mean, iris does not recognise it as such
    # and just reads it as having a single longitudinal coordinate. This
    # removes longitude as a dimension coordinate and makes it a scalar
    # coordinate in line with how a zonal mean would be described.
    # Is there a better way of doing this?
    ucube_cds = [cdt.standard_name for cdt in ucube.coords()]
    if 'longitude' in ucube_cds:
        ucube = ucube.collapsed('longitude', iris.analysis.MEAN)
    if not ucube.coord('latitude').has_bounds():
        ucube.coord('latitude').guess_bounds()
    # check for month_number
    aux_coord_names = [aux_coord.var_name for aux_coord in ucube.aux_coords]
    if 'month_number' not in aux_coord_names:
        icc.add_month_number(ucube, 'time', name='month_number')

    # Read zonal mean T (lbproc=192) and add clim month and season to metadata
    tcube = load_run_ss(
        run, 'monthly', 'air_temperature', lbproc=192,
        **year_cons)  # m01s30i204
    # Although input data is a zonal mean, iris does not recognise it as such
    # and just reads it as having a single longitudinal coordinate. This
    # removes longitude as a dimension coordinate and makes it a scalar
    # coordinate in line with how a zonal mean would be described.
    # Is there a better way of doing this?
    tcube_cds = [cdt.standard_name for cdt in tcube.coords()]
    if 'longitude' in tcube_cds:
        tcube = tcube.collapsed('longitude', iris.analysis.MEAN)
    if not tcube.coord('latitude').has_bounds():
        tcube.coord('latitude').guess_bounds()
    aux_coord_names = [aux_coord.var_name for aux_coord in tcube.aux_coords]
    if 'month' not in aux_coord_names:
        icc.add_month(tcube, 'time', name='month')
    if 'clim_season' not in aux_coord_names:
        icc.add_season(tcube, 'time', name='clim_season')

    # Read zonal mean q (lbproc=192) and add clim month and season to metadata
    qcube = load_run_ss(
        run, 'monthly', 'specific_humidity', lbproc=192,
        **year_cons)  # m01s30i205
    # Although input data is a zonal mean, iris does not recognise it as such
    # and just reads it as having a single longitudinal coordinate. This
    # removes longitude as a dimension coordinate and makes it a scalar
    # coordinate in line with how a zonal mean would be described.
    # Is there a better way of doing this?
    qcube_cds = [cdt.standard_name for cdt in qcube.coords()]
    if 'longitude' in qcube_cds:
        qcube = qcube.collapsed('longitude', iris.analysis.MEAN)
    if not qcube.coord('latitude').has_bounds():
        qcube.coord('latitude').guess_bounds()
    aux_coord_names = [aux_coord.var_name for aux_coord in qcube.aux_coords]
    if 'month' not in aux_coord_names:
        icc.add_month(qcube, 'time', name='month')
    if 'clim_season' not in aux_coord_names:
        icc.add_season(qcube, 'time', name='clim_season')

    # Calculate PNJ metrics
    pnj_metrics(run, ucube, metrics)

    # Calculate QBO metrics
    qbo_metrics(run, ucube, metrics)

    # Calculate polar temperature metrics
    tpole_metrics(run, tcube, metrics)

    # Calculate equatorial temperature metrics
    teq_metrics(run, tcube, metrics)

    # Calculate tropical temperature metrics
    t_metrics(run, tcube, metrics)

    # Calculate tropical water vapour metric
    q_metrics(run, qcube, metrics)

    # Summary metric
    summary_metric(metrics)

    # Make sure all metrics are of type float
    # Need at the moment to populate metrics files
    for key, value in metrics.items():
        metrics[key] = float(value)

    return metrics
Ejemplo n.º 3
0
def age_of_air(run):
    """Calculate the age of air metrics."""
    # Create metrics dictionary with MDI incase age of air
    # diagnostics not available
    metrics = {
        'RMS error: tropical Age of Air': -10000.,
        'RMS error: NH midlatitude Age of Air': -10000.
    }

    try:
        # Set up to only run for 5 year period
        analysis_start_dt, analysis_end_dt = calculate_analysis_years(run)
        constraint = dict(
            from_dt=analysis_start_dt, to_dt=analysis_end_dt, lbproc=128)
        # Calculate age of air metrics if appropriate diagnostic available
        with warnings.catch_warnings():
            warnings.filterwarnings('ignore', '.*orography.*', UserWarning)
            agecube = load_run_ss(run, 'monthly', 'age_of_stratospheric_air',
                                  **constraint)  # m01s34i150
    except iris.exceptions.ConstraintMismatchError:
        logger.warning('Age of air fields absent.  Skipping this diagnostic.')
    except ValueError:
        logger.warning("Run length < 12 years: Can't assess age of air")
    else:
        # Create time/zonal means of age data
        agecube = agecube.collapsed(['longitude', 'time'], iris.analysis.MEAN)
        # Convert units of data from seconds to years
        agecube.data /= RSECS_PER_360DAY_YEAR
        # Create latitude bounds for area-weighted averaging
        agecube.coord('latitude').guess_bounds()
        # Convert units of height from metres to km
        agecube.coord('level_height').convert_units('km')

        # Calculate area-weighted means for tropics
        trop_cons = iris.Constraint(latitude=lambda lat: -10 <= lat <= 10)
        diag1 = weight_lat_ave(agecube.extract(trop_cons))
        diag1.var_name = 'tropical_age_of_air'

        # Calculate area-weighted means for mid-latitudes
        mlat_cons = iris.Constraint(latitude=lambda lat: 35 <= lat <= 45)
        diag2 = weight_lat_ave(agecube.extract(mlat_cons))
        diag2.var_name = 'midlat_age_of_air'

        # Write age of air data to CWD
        outfile = '{0}_age_of_air_{1}.nc'
        cubelist = iris.cube.CubeList([diag1, diag2])
        iris.save(cubelist, outfile.format(run['runid'], run.period))

        # Calculate metrics
        diag1sf6 = iai.Linear(diag1, [('level_height', ZSF6_KM)])
        diag1co2 = iai.Linear(diag1, [('level_height', ZCO2_KM)])
        diag2sf6 = iai.Linear(diag2, [('level_height', Z2_KM)])
        diag2co2 = iai.Linear(diag2, [('level_height', Z2_KM2)])
        metric1sf6 = np.sqrt(np.mean((diag1sf6.data - AGE_YRS)**2))
        metric1co2 = np.sqrt(np.mean((diag1co2.data - AGE_YRS2)**2))
        metric2sf6 = np.sqrt(np.mean((diag2sf6.data - AGE2_YRS)**2))
        metric2co2 = np.sqrt(np.mean((diag2co2.data - AGE2_YRS2)**2))
        trop_age = (metric1sf6 + metric1co2) / 2.
        midl_age = (metric2sf6 + metric2co2) / 2.

        # Add metrics to dictionary
        metrics['RMS error: tropical Age of Air'] = float(trop_age)
        metrics['RMS error: NH midlatitude Age of Air'] = float(midl_age)

    return metrics