Exemple #1
0
 def test_unicode_history(self):
     unicode_str = unichr(40960) + u'wxyz' + unichr(1972)
     cube = iris.tests.stock.simple_1d()
     cube.add_history(unicode_str)
     self.assertString(str(cube), ('cdm', 'str_repr',
                                   'unicode_history.__str__.txt'))
     self.assertString(unicode(cube), ('cdm', 'str_repr',
                                       'unicode_history.__unicode__.txt'))
Exemple #2
0
def curl(i_cube, j_cube, k_cube=None, ignore=None, update_history=True):
    r'''
    Calculate the 3d curl of the given vector of cubes.

    Args:
    
    * i_cube
        The i cube of the vector to operate on
    * j_cube
        The j cube of the vector to operate on
        
    Kwargs:
    
    * k_cube
        The k cube of the vector to operate on        

    Return (i_cmpt_curl_cube, j_cmpt_curl_cube, k_cmpt_curl_cube)
    
    The calculation of curl is dependent on the type of :func:`iris.coord_systems.CoordSystem` in the cube:
    
        Cartesian curl
        
            The Cartesian curl is defined as:
        
            .. math::
            
                \nabla\times \vec u = (\frac{\delta w}{\delta y} - \frac{\delta v}{\delta z}) \vec a_i - (\frac{\delta w}{\delta x} - \frac{\delta u}{\delta z})\vec a_j + (\frac{\delta v}{\delta x} - \frac{\delta u}{\delta y})\vec a_k
        
        Spherical curl
            
            When spherical calculus is used, i_cube is the phi vector component (e.g. eastward), j_cube is the theta component 
            (e.g. northward) and k_cube is the radial component.
    
            The spherical curl is defined as:
        
            .. math::
                
                \nabla\times \vec A = \frac{1}{r cos \theta}(\frac{\delta}{\delta \theta}(\vec A_\phi cos \theta) - \frac{\delta \vec A_\theta}{\delta \phi}) \vec r + \frac{1}{r}(\frac{1}{cos \theta} \frac{\delta \vec A_r}{\delta \phi} - \frac{\delta}{\delta r} (r \vec A_\phi))\vec \theta + \frac{1}{r}(\frac{\delta}{\delta r}(r \vec A_\theta) - \frac{\delta \vec A_r}{\delta \theta}) \vec \phi
    
            where phi is longitude, theta is latitude.

    '''
    if ignore is not None:
        ignore = None
        warnings.warn('The ignore keyword to iris.analysis.calculus.curl is deprecated, ignoring is now done automatically.')
    
    # Get the vector quantity names (i.e. ['easterly', 'northerly', 'vertical'])
    vector_quantity_names, phenomenon_name = spatial_vectors_with_phenom_name(i_cube, j_cube, k_cube)
    
    cubes = filter(None, [i_cube, j_cube, k_cube])
    
    # get the names of all coords binned into useful comparison groups
    coord_comparison = iris.analysis.coord_comparison(*cubes)
    
    bad_coords = coord_comparison['ungroupable_and_dimensioned']
    if bad_coords:
        raise ValueError("Coordinates found in one cube that describe a data dimension which weren't in the other "
                         "cube (%s), try removing this coordinate."  % ', '.join([group.name() for group in bad_coords]))
    
    bad_coords = coord_comparison['resamplable']
    if bad_coords:
        raise ValueError('Some coordinates are different (%s), consider resampling.' % ', '.join([group.name() for group in bad_coords]))
    
    ignore_string = ''
    if coord_comparison['ignorable']:
        ignore_string = ' (ignoring %s)' % ', '.join([group.name() for group in bad_coords])

    # Get the dim_coord, or None if none exist, for the xyz dimensions
    x_coord = i_cube.coord(axis='X') 
    y_coord = i_cube.coord(axis='Y')
    z_coord = i_cube.coord(axis='Z')
    
    y_dim = i_cube.coord_dims(y_coord)[0]
   
    horiz_cs = i_cube.coord_system('CoordSystem')
        
    # Planar (non spherical) coords?
    ellipsoidal = isinstance(horiz_cs, (iris.coord_systems.GeogCS, iris.coord_systems.RotatedGeogCS))
    if not ellipsoidal:
        
        # TODO Implement some mechanism for conforming to a common grid
        dj_dx = _curl_differentiate(j_cube, x_coord)
        prototype_diff = dj_dx
                
        # i curl component (dk_dy - dj_dz)
        dk_dy = _curl_differentiate(k_cube, y_coord)
        dk_dy = _curl_regrid(dk_dy, prototype_diff)
        dj_dz = _curl_differentiate(j_cube, z_coord)
        dj_dz = _curl_regrid(dj_dz, prototype_diff)
        
        # TODO Implement resampling in the vertical (which regridding does not support).
        if dj_dz is not None and dj_dz.data.shape != prototype_diff.data.shape:
            dj_dz = _curl_change_z(dj_dz, z_coord, prototype_diff)

        i_cmpt = _curl_subtract(dk_dy, dj_dz)
        dj_dz = dk_dy = None
        
        # j curl component (di_dz - dk_dx)
        di_dz = _curl_differentiate(i_cube, z_coord)
        di_dz = _curl_regrid(di_dz, prototype_diff)
        
        # TODO Implement resampling in the vertical (which regridding does not support).
        if di_dz is not None and di_dz.data.shape != prototype_diff.data.shape:
            di_dz = _curl_change_z(di_dz, z_coord, prototype_diff)

        dk_dx = _curl_differentiate(k_cube, x_coord)
        dk_dx = _curl_regrid(dk_dx, prototype_diff)
        j_cmpt = _curl_subtract(di_dz, dk_dx)
        di_dz = dk_dx = None
        
        # k curl component ( dj_dx - di_dy)
        di_dy = _curl_differentiate(i_cube, y_coord)
        di_dy = _curl_regrid(di_dy, prototype_diff)
        # Since prototype_diff == dj_dx we don't need to recalculate dj_dx
#        dj_dx = _curl_differentiate(j_cube, x_coord)
#        dj_dx = _curl_regrid(dj_dx, prototype_diff)
        k_cmpt = _curl_subtract(dj_dx, di_dy)
        di_dy = dj_dx = None
        
        result = [i_cmpt, j_cmpt, k_cmpt]
    
    # Spherical coords (GeogCS or RotatedGeogCS).
    else:
        # A_\phi = i ; A_\theta = j ; A_\r = k
        # theta = lat ; phi = long ;
        # r_cmpt = 1/ ( r * cos(lat) ) * ( d/dtheta ( i_cube * sin( lat ) ) - d_j_cube_dphi )
        # phi_cmpt = 1/r * ( d/dr (r * j_cube) - d_k_cube_dtheta)
        # theta_cmpt = 1/r * ( 1/cos(lat) * d_k_cube_dphi - d/dr (r * i_cube)
        if y_coord.name() != 'latitude' or x_coord.name() != 'longitude':
            raise ValueError('Expecting latitude as the y coord and longitude as the x coord for spherical curl.')

        # Get the radius of the earth - and check for sphericity
        ellipsoid = horiz_cs
        if isinstance(horiz_cs, iris.coord_systems.RotatedGeogCS):
            ellipsoid = horiz_cs.ellipsoid
        if ellipsoid:
            # TODO: Add a test for this
            r = ellipsoid.semi_major_axis
            r_unit = iris.unit.Unit("m")
            spherical = (ellipsoid.inverse_flattening == 0.0)
        else:
            r = iris.analysis.cartography.DEFAULT_SPHERICAL_EARTH_RADIUS
            r_unit = iris.analysis.cartography.DEFAULT_SPHERICAL_EARTH_RADIUS_UNIT
            spherical = True
            
        if not spherical:
            raise ValueError("Cannot take the curl over a non-spherical ellipsoid.")
        
        lon_coord = x_coord.copy()
        lat_coord = y_coord.copy()
        lon_coord.convert_units('radians')
        lat_coord.convert_units('radians')
        lat_cos_coord = _coord_cos(lat_coord)

        # TODO Implement some mechanism for conforming to a common grid
        temp = iris.analysis.maths.multiply(i_cube, lat_cos_coord, y_dim)
        dicos_dtheta = _curl_differentiate(temp, lat_coord)
        prototype_diff = dicos_dtheta
        
        # r curl component:  1/ ( r * cos(lat) ) * ( dicos_dtheta - d_j_cube_dphi )
        # Since prototype_diff == dicos_dtheta we don't need to recalculate dicos_dtheta
        d_j_cube_dphi = _curl_differentiate(j_cube, lon_coord)
        d_j_cube_dphi = _curl_regrid(d_j_cube_dphi, prototype_diff)
        new_lat_coord = d_j_cube_dphi.coord(name='latitude')
        new_lat_cos_coord = _coord_cos(new_lat_coord)
        lat_dim = d_j_cube_dphi.coord_dims(new_lat_coord)[0]
        r_cmpt = iris.analysis.maths.divide(_curl_subtract(dicos_dtheta, d_j_cube_dphi), r * new_lat_cos_coord, dim=lat_dim)
        r_cmpt.units = r_cmpt.units / r_unit
        d_j_cube_dphi = dicos_dtheta = None
        
        # phi curl component: 1/r * ( drj_dr - d_k_cube_dtheta)
        drj_dr = _curl_differentiate(r * j_cube, z_coord)
        if drj_dr is not None:
            drj_dr.units = drj_dr.units * r_unit
        drj_dr = _curl_regrid(drj_dr, prototype_diff)
        d_k_cube_dtheta = _curl_differentiate(k_cube, lat_coord)
        d_k_cube_dtheta = _curl_regrid(d_k_cube_dtheta, prototype_diff)
        if drj_dr is None and d_k_cube_dtheta is None:
            phi_cmpt = None
        else:
            phi_cmpt = 1/r * _curl_subtract(drj_dr, d_k_cube_dtheta)
            phi_cmpt.units = phi_cmpt.units / r_unit

        drj_dr = d_k_cube_dtheta = None

        # theta curl component: 1/r * ( 1/cos(lat) * d_k_cube_dphi - dri_dr )
        d_k_cube_dphi = _curl_differentiate(k_cube, lon_coord)
        d_k_cube_dphi = _curl_regrid(d_k_cube_dphi, prototype_diff)
        if d_k_cube_dphi is not None:
            d_k_cube_dphi = iris.analysis.maths.divide(d_k_cube_dphi, lat_cos_coord)
        dri_dr = _curl_differentiate(r * i_cube, z_coord)
        if dri_dr is not None:
            dri_dr.units = dri_dr.units * r_unit
        dri_dr = _curl_regrid(dri_dr, prototype_diff)
        if d_k_cube_dphi is None and dri_dr is None:
            theta_cmpt = None
        else:
            theta_cmpt = 1/r * _curl_subtract(d_k_cube_dphi, dri_dr)
            theta_cmpt.units = theta_cmpt.units / r_unit
        d_k_cube_dphi = dri_dr = None
        
        result = [phi_cmpt, theta_cmpt, r_cmpt]

    for direction, cube in zip(vector_quantity_names, result):
        if cube is not None:
            cube.rename('%s curl of %s' % (direction, phenomenon_name))
        
            if update_history:
                # Add history in place
                if k_cube is None:
                    cube.add_history('%s cmpt of the curl of %s and %s%s' % \
                                     (direction, i_cube.name(), j_cube.name(), ignore_string))
                else:
                    cube.add_history('%s cmpt of the curl of %s, %s and %s%s' % \
                                     (direction, i_cube.name(), j_cube.name(), k_cube.name(), ignore_string))
        
    return result
Exemple #3
0
def curl(i_cube, j_cube, k_cube=None, ignore=None, update_history=True):
    r'''
    Calculate the 3d curl of the given vector of cubes.

    Args:
    
    * i_cube
        The i cube of the vector to operate on
    * j_cube
        The j cube of the vector to operate on
        
    Kwargs:
    
    * k_cube
        The k cube of the vector to operate on        

    Return (i_cmpt_curl_cube, j_cmpt_curl_cube, k_cmpt_curl_cube)
    
    The calculation of curl is dependent on the type of :func:`iris.coord_systems.CoordSystem` in the cube:
    
        Cartesian curl
        
            The Cartesian curl is defined as:
        
            .. math::
            
                \nabla\times \vec u = (\frac{\delta w}{\delta y} - \frac{\delta v}{\delta z}) \vec a_i - (\frac{\delta w}{\delta x} - \frac{\delta u}{\delta z})\vec a_j + (\frac{\delta v}{\delta x} - \frac{\delta u}{\delta y})\vec a_k
        
        Spherical curl
            
            When spherical calculus is used, i_cube is the phi vector component (e.g. eastward), j_cube is the theta component 
            (e.g. northward) and k_cube is the radial component.
    
            The spherical curl is defined as:
        
            .. math::
                
                \nabla\times \vec A = \frac{1}{r cos \theta}(\frac{\delta}{\delta \theta}(\vec A_\phi cos \theta) - \frac{\delta \vec A_\theta}{\delta \phi}) \vec r + \frac{1}{r}(\frac{1}{cos \theta} \frac{\delta \vec A_r}{\delta \phi} - \frac{\delta}{\delta r} (r \vec A_\phi))\vec \theta + \frac{1}{r}(\frac{\delta}{\delta r}(r \vec A_\theta) - \frac{\delta \vec A_r}{\delta \theta}) \vec \phi
    
            where phi is longitude, theta is latitude.

    '''
    if ignore is not None:
        ignore = None
        warnings.warn(
            'The ignore keyword to iris.analysis.calculus.curl is deprecated, ignoring is now done automatically.'
        )

    # Get the vector quantity names (i.e. ['easterly', 'northerly', 'vertical'])
    vector_quantity_names, phenomenon_name = spatial_vectors_with_phenom_name(
        i_cube, j_cube, k_cube)

    cubes = filter(None, [i_cube, j_cube, k_cube])

    # get the names of all coords binned into useful comparison groups
    coord_comparison = iris.analysis.coord_comparison(*cubes)

    bad_coords = coord_comparison['ungroupable_and_dimensioned']
    if bad_coords:
        raise ValueError(
            "Coordinates found in one cube that describe a data dimension which weren't in the other "
            "cube (%s), try removing this coordinate." %
            ', '.join([group.name() for group in bad_coords]))

    bad_coords = coord_comparison['resamplable']
    if bad_coords:
        raise ValueError(
            'Some coordinates are different (%s), consider resampling.' %
            ', '.join([group.name() for group in bad_coords]))

    ignore_string = ''
    if coord_comparison['ignorable']:
        ignore_string = ' (ignoring %s)' % ', '.join(
            [group.name() for group in bad_coords])

    # Get the dim_coord, or None if none exist, for the xyz dimensions
    x_coord = i_cube.coord(axis='X')
    y_coord = i_cube.coord(axis='Y')
    z_coord = i_cube.coord(axis='Z')

    y_dim = i_cube.coord_dims(y_coord)[0]

    horiz_cs = i_cube.coord_system('CoordSystem')

    # Planar (non spherical) coords?
    ellipsoidal = isinstance(
        horiz_cs,
        (iris.coord_systems.GeogCS, iris.coord_systems.RotatedGeogCS))
    if not ellipsoidal:

        # TODO Implement some mechanism for conforming to a common grid
        dj_dx = _curl_differentiate(j_cube, x_coord)
        prototype_diff = dj_dx

        # i curl component (dk_dy - dj_dz)
        dk_dy = _curl_differentiate(k_cube, y_coord)
        dk_dy = _curl_regrid(dk_dy, prototype_diff)
        dj_dz = _curl_differentiate(j_cube, z_coord)
        dj_dz = _curl_regrid(dj_dz, prototype_diff)

        # TODO Implement resampling in the vertical (which regridding does not support).
        if dj_dz is not None and dj_dz.data.shape != prototype_diff.data.shape:
            dj_dz = _curl_change_z(dj_dz, z_coord, prototype_diff)

        i_cmpt = _curl_subtract(dk_dy, dj_dz)
        dj_dz = dk_dy = None

        # j curl component (di_dz - dk_dx)
        di_dz = _curl_differentiate(i_cube, z_coord)
        di_dz = _curl_regrid(di_dz, prototype_diff)

        # TODO Implement resampling in the vertical (which regridding does not support).
        if di_dz is not None and di_dz.data.shape != prototype_diff.data.shape:
            di_dz = _curl_change_z(di_dz, z_coord, prototype_diff)

        dk_dx = _curl_differentiate(k_cube, x_coord)
        dk_dx = _curl_regrid(dk_dx, prototype_diff)
        j_cmpt = _curl_subtract(di_dz, dk_dx)
        di_dz = dk_dx = None

        # k curl component ( dj_dx - di_dy)
        di_dy = _curl_differentiate(i_cube, y_coord)
        di_dy = _curl_regrid(di_dy, prototype_diff)
        # Since prototype_diff == dj_dx we don't need to recalculate dj_dx
        #        dj_dx = _curl_differentiate(j_cube, x_coord)
        #        dj_dx = _curl_regrid(dj_dx, prototype_diff)
        k_cmpt = _curl_subtract(dj_dx, di_dy)
        di_dy = dj_dx = None

        result = [i_cmpt, j_cmpt, k_cmpt]

    # Spherical coords (GeogCS or RotatedGeogCS).
    else:
        # A_\phi = i ; A_\theta = j ; A_\r = k
        # theta = lat ; phi = long ;
        # r_cmpt = 1/ ( r * cos(lat) ) * ( d/dtheta ( i_cube * sin( lat ) ) - d_j_cube_dphi )
        # phi_cmpt = 1/r * ( d/dr (r * j_cube) - d_k_cube_dtheta)
        # theta_cmpt = 1/r * ( 1/cos(lat) * d_k_cube_dphi - d/dr (r * i_cube)
        if y_coord.name() != 'latitude' or x_coord.name() != 'longitude':
            raise ValueError(
                'Expecting latitude as the y coord and longitude as the x coord for spherical curl.'
            )

        # Get the radius of the earth - and check for sphericity
        ellipsoid = horiz_cs
        if isinstance(horiz_cs, iris.coord_systems.RotatedGeogCS):
            ellipsoid = horiz_cs.ellipsoid
        if ellipsoid:
            # TODO: Add a test for this
            r = ellipsoid.semi_major_axis
            r_unit = iris.unit.Unit("m")
            spherical = (ellipsoid.inverse_flattening == 0.0)
        else:
            r = iris.analysis.cartography.DEFAULT_SPHERICAL_EARTH_RADIUS
            r_unit = iris.analysis.cartography.DEFAULT_SPHERICAL_EARTH_RADIUS_UNIT
            spherical = True

        if not spherical:
            raise ValueError(
                "Cannot take the curl over a non-spherical ellipsoid.")

        lon_coord = x_coord.copy()
        lat_coord = y_coord.copy()
        lon_coord.convert_units('radians')
        lat_coord.convert_units('radians')
        lat_cos_coord = _coord_cos(lat_coord)

        # TODO Implement some mechanism for conforming to a common grid
        temp = iris.analysis.maths.multiply(i_cube, lat_cos_coord, y_dim)
        dicos_dtheta = _curl_differentiate(temp, lat_coord)
        prototype_diff = dicos_dtheta

        # r curl component:  1/ ( r * cos(lat) ) * ( dicos_dtheta - d_j_cube_dphi )
        # Since prototype_diff == dicos_dtheta we don't need to recalculate dicos_dtheta
        d_j_cube_dphi = _curl_differentiate(j_cube, lon_coord)
        d_j_cube_dphi = _curl_regrid(d_j_cube_dphi, prototype_diff)
        new_lat_coord = d_j_cube_dphi.coord(name='latitude')
        new_lat_cos_coord = _coord_cos(new_lat_coord)
        lat_dim = d_j_cube_dphi.coord_dims(new_lat_coord)[0]
        r_cmpt = iris.analysis.maths.divide(_curl_subtract(
            dicos_dtheta, d_j_cube_dphi),
                                            r * new_lat_cos_coord,
                                            dim=lat_dim)
        r_cmpt.units = r_cmpt.units / r_unit
        d_j_cube_dphi = dicos_dtheta = None

        # phi curl component: 1/r * ( drj_dr - d_k_cube_dtheta)
        drj_dr = _curl_differentiate(r * j_cube, z_coord)
        if drj_dr is not None:
            drj_dr.units = drj_dr.units * r_unit
        drj_dr = _curl_regrid(drj_dr, prototype_diff)
        d_k_cube_dtheta = _curl_differentiate(k_cube, lat_coord)
        d_k_cube_dtheta = _curl_regrid(d_k_cube_dtheta, prototype_diff)
        if drj_dr is None and d_k_cube_dtheta is None:
            phi_cmpt = None
        else:
            phi_cmpt = 1 / r * _curl_subtract(drj_dr, d_k_cube_dtheta)
            phi_cmpt.units = phi_cmpt.units / r_unit

        drj_dr = d_k_cube_dtheta = None

        # theta curl component: 1/r * ( 1/cos(lat) * d_k_cube_dphi - dri_dr )
        d_k_cube_dphi = _curl_differentiate(k_cube, lon_coord)
        d_k_cube_dphi = _curl_regrid(d_k_cube_dphi, prototype_diff)
        if d_k_cube_dphi is not None:
            d_k_cube_dphi = iris.analysis.maths.divide(d_k_cube_dphi,
                                                       lat_cos_coord)
        dri_dr = _curl_differentiate(r * i_cube, z_coord)
        if dri_dr is not None:
            dri_dr.units = dri_dr.units * r_unit
        dri_dr = _curl_regrid(dri_dr, prototype_diff)
        if d_k_cube_dphi is None and dri_dr is None:
            theta_cmpt = None
        else:
            theta_cmpt = 1 / r * _curl_subtract(d_k_cube_dphi, dri_dr)
            theta_cmpt.units = theta_cmpt.units / r_unit
        d_k_cube_dphi = dri_dr = None

        result = [phi_cmpt, theta_cmpt, r_cmpt]

    for direction, cube in zip(vector_quantity_names, result):
        if cube is not None:
            cube.rename('%s curl of %s' % (direction, phenomenon_name))

            if update_history:
                # Add history in place
                if k_cube is None:
                    cube.add_history('%s cmpt of the curl of %s and %s%s' % \
                                     (direction, i_cube.name(), j_cube.name(), ignore_string))
                else:
                    cube.add_history('%s cmpt of the curl of %s, %s and %s%s' % \
                                     (direction, i_cube.name(), j_cube.name(), k_cube.name(), ignore_string))

    return result