{ "metadata": { "name": "cell_methods_loading" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Loading cubes when Cell Methods are present \n", "\n", "### Introduction\n", "\n", "Iris can constrain the loading of data to a subset of the entire dataset based on metadata interpreted on the Iris Cube. This includes the ability to constrain based on the cube's cell methods, if present. These cell methods represent operations already applied to the data, describing climatological and diurnal statistics. Available methods include point, sum, mean, maximum, minimum, mid_range, standard_deviation, variance, mode, and median. Along with an associated coordinate, an interval is often defined. An example cell method might be a *time mean of two hours*. Here the method is \"mean\", \"time\" is the coordinate name and an interval of two hours indicates that the time mean is over a two hour interval.\n", "\n", "This worked example shows how to constrain the loading of cubes dependent on whether they have one or more cell methods present." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Writing a constraining function\n", "\n", "The `iris.Constraint` function can be used to constrain cube loading in many different ways. The one that is of interest to us here is the keyword argument `cube_func`, which allows us to specify a function that takes a cube as its only argument and returns either `True` or `False`.\n", "\n", "Below is a function that does precisely that, returning `True` or `False` depending on whether the cube passed has cell methods set or not.\n", "\n", "We will also import Iris, as it's going to be needed later on." ] }, { "cell_type": "code", "collapsed": false, "input": [ "import iris\n", "print('Iris version: {}'.format(iris.__version__))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Iris version: 1.5.1\n" ] } ], "prompt_number": 1 }, { "cell_type": "code", "collapsed": false, "input": [ "def has_cell_methods(cube):\n", " cm = cube.cell_methods\n", " return len(cm) > 0" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `cell_methods` method always returns a tuple, which will be empty if no cell methods are set on the cube. An empty tuple has length zero, giving us a logical test to run against the input cube to determine if any cell methods are set, as performed in the `return` line above." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Simple constraining\n", "\n", "All that remains to do is to use our cell methods constraint function when loading some data. We will use two Iris sample data files to test whether it is working. They are:\n", "\n", "* A1B_north_america.nc (one cube of air temperature that does have cell methods),\n", "* ostia_monthly.nc (one cube of surface_temperature with cell methods), and\n", "* colpex.pp (comprised of two cubes [air potential temperature and air pressure], neither of which have any cell methods).\n", " \n", "If our constraint function above works as expected, we would expect to see the cubes from the first two files loaded fine, but neither of the cubes from the second file.\n", "\n", "Let's test this. First we need to add our function to a constraint that we can use when loading our data:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "cm_constraint = iris.Constraint(cube_func=has_cell_methods)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can test it out on our sample data. Let's start by loading the data into an Iris `cubelist` of the three cubes loaded by our data:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a1b_fname = iris.sample_data_path('A1B_north_america.nc')\n", "colpex_fname = iris.sample_data_path('colpex.pp')\n", "ostia_fname = iris.sample_data_path('ostia_monthly.nc')\n", "\n", "cubelist = iris.load([a1b_fname, colpex_fname, ostia_fname])\n", "for cube in cubelist:\n", " print('{}\\n\\tCell Methods = {}\\n'.format(cube.summary(True), cube.cell_methods))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "air_potential_temperature / (K) (time: 6; model_level_number: 10; grid_latitude: 83; grid_longitude: 83)\n", "\tCell Methods = ()\n", "\n", "air_pressure / (Pa) (time: 6; model_level_number: 10; grid_latitude: 83; grid_longitude: 83)\n", "\tCell Methods = ()\n", "\n", "air_temperature / (K) (time: 240; latitude: 37; longitude: 49)\n", "\tCell Methods = (CellMethod(method=u'mean', coord_names=(u'time',), intervals=(u'6 hour',), comments=()),)\n", "\n", "surface_temperature / (K) (time: 54; latitude: 18; longitude: 432)\n", "\tCell Methods = (CellMethod(method=u'mean', coord_names=(u'month', u'year'), intervals=(), comments=()),)\n", "\n" ] }, { "output_type": "stream", "stream": "stderr", "text": [ "/opt/ukmo/iris/default/linux64/site-packages/iris/fileformats/rules.py:823: UserWarning: Unable to create instance of HybridHeightFactory. The file(s) ['/project/avd/iris/resources/git/iris-sample-data/sample_data/colpex.pp'] don't contain field(s) for 'orography'.\n", " factory=factory_name))\n" ] } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now extract from our cubelist using the constraint we defined above. This will leave only the cubes where cell methods are defined:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print cubelist.extract(cm_constraint)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "0: air_temperature / (K) (time: 240; latitude: 37; longitude: 49)\n", "1: surface_temperature / (K) (time: 54; latitude: 18; longitude: 432)\n" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Good news! Using our constraint to extract from the cubelist has returned only the cube with cell methods defined." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Constraining based on the methods used\n", "\n", "We can go further than what is demonstrated in the example above, as we can also constrain loading based on the specifics of the cell methods used. From the printed cubelist above it is clear that while both cubes with cell methods have the same method (`mean`) deployed, the specifics of that mean change, in terms of both the coordinates affected and the interval defined.\n", "\n", "We can use these differences to select *just one* of the two cubes with cell methods. Let's define a constraint that will only load the first cube in the list immediately above:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "interval_6_hr = iris.coords.CellMethod('mean', coords='time', intervals='6 hour')\n", "constraint_6_hr = iris.Constraint(cube_func=lambda cube: interval_6_hr in cube.cell_methods)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is a two-step process. First we define a cell method based on the definition of the cell methods we want to match to, and then test for its inclusion in the cell methods of a given cube when we reference it in the new constraint defined. Let's test our new constraint on our cubelist:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print cubelist.extract(constraint_6_hr)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "0: air_temperature / (K) (time: 240; latitude: 37; longitude: 49)\n" ] } ], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "So now we can not only extract from a cubelist based on the general presence of cell methods, but also on the presence of a specific, pre-defined cell methods instance." ] } ], "metadata": {} } ] }