Пример #1
0
def test_two_triangles_without_edges(two_triangles_with_depths):
    grid = two_triangles_with_depths
    # This will set the _edges to None, but it will be rebuild
    grid.edges = None

    fname = '2_triangles_without_edges.nc'
    with chdir(test_files):
        grid.save_as_netcdf(fname)
        ug = UGrid.from_ncfile(fname, load_data=True)
        os.remove(fname)

    assert ug.nodes.shape == (4, 2)
    assert ug.nodes.shape == grid.nodes.shape

    # FIXME: Not ideal to pull specific values out, but how else to test?
    assert np.array_equal(ug.nodes[0, :], (0.1, 0.1))
    assert np.array_equal(ug.nodes[-1, :], (3.1, 2.1))
    assert np.array_equal(ug.nodes, grid.nodes)

    assert ug.faces.shape == grid.faces.shape

    # the edges rebuild from faces
    assert ug._edges is None
    ug.build_edges()
    assert ug.edges is not None

    depths = find_depths(ug)
    assert depths.data.shape == (4, )
    assert depths.data[0] == 1
    assert depths.attributes['units'] == 'unknown'
Пример #2
0
def test_with_just_nodes_and_depths(two_triangles):
    expected = two_triangles
    del expected.faces
    del expected.edges

    depth = UVar(
        'depth', 'node', np.array([1.0, 2.0, 3.0, 4.0]), {
            'units': 'm',
            'positive': 'down',
            'standard_name': 'sea_floor_depth_below_geoid'
        })
    expected.add_data(depth)

    fname = '2_triangles_depth.nc'
    with chdir(test_files):
        expected.save_as_netcdf(fname)
        grid = UGrid.from_ncfile(fname, load_data=True)
        os.remove(fname)

    assert grid.faces is None
    assert grid.edges is None
    assert np.array_equal(expected.nodes, grid.nodes)

    assert np.array_equal(expected.data['depth'].data, grid.data['depth'].data)
    assert expected.data['depth'].attributes == grid.data['depth'].attributes
Пример #3
0
def test_without_faces(two_triangles):
    expected = two_triangles
    del expected.faces
    assert expected.faces is None

    fname = '2_triangles.nc'
    with chdir(test_files):
        expected.save_as_netcdf(fname)
        grid = UGrid.from_ncfile(fname)
        os.remove(fname)

    assert grid.faces is None
    assert np.array_equal(expected.faces, grid.faces)
    assert np.array_equal(expected.edges, grid.edges)
Пример #4
0
def test_with_faces(two_triangles):
    """
    Test with faces, edges, but no `face_coordinates` or `edge_coordinates`.

    """

    expected = two_triangles

    fname = '2_triangles.nc'
    with chdir(test_files):
        expected.save_as_netcdf(fname)
        grid = UGrid.from_ncfile(fname)
        os.remove(fname)

    assert np.array_equal(expected.nodes, grid.nodes)
    assert np.array_equal(expected.faces, grid.faces)
    assert np.array_equal(expected.edges, grid.edges)
Пример #5
0
def test_21_triangles(twenty_one_triangles_with_depths):
    grid = twenty_one_triangles_with_depths

    fname = '21_triangles.nc'
    with chdir(test_files):
        grid.save_as_netcdf(fname)
        ug = UGrid.from_ncfile(fname, load_data=True)
        os.remove(fname)

    assert ug.nodes.shape == grid.nodes.shape

    # FIXME: Not ideal to pull specific values out, but how else to test?
    assert np.array_equal(ug.nodes, grid.nodes)

    depths = find_depths(ug)
    assert depths.data.shape == (20, )
    assert depths.data[0] == 1
    assert depths.attributes['units'] == 'unknown'
Пример #6
0
def load_from_varnames(filename, names_mapping, attribute_check=None):
    """
    Load a UGrid from a netcdf file where the roles are defined by the
    names of the variables.

    :param filename: names of the file to load (or OPeNDAP URL).

    :param names_mapping: dict that maps the variable names to UGrid components

    :param attribute_check=None: list of global attributes that are expected
    :type attribute_check: list of tuples to check. Example:
                           [('grid_type','triangular'),] will check if the
                           grid_type attribute is set to "triangular"

    The names_mapping dict has to contain at least: 'nodes_lon', 'nodes_lat'

    Optionally (and mostly required), it can contain: face_face_connectivity',
    'face_coordinates_lon', 'face_coordinates_lat', and 'faces'

    """
    ug = UGrid()
    attribute_check = {} if attribute_check is None else attribute_check

    nc = netCDF4.Dataset(filename)

    # Check for the specified attributes.
    for name, value in attribute_check:
        if nc.getncattr(name).lower() != value:
            raise ValueError('This does not appear to be a valid file:\n'
                             'It does not have the "{}"="{}"'
                             'global attribute set'.format(name, value))

    # Nodes.
    lon = nc.variables[names_mapping['nodes_lon']]
    lat = nc.variables[names_mapping['nodes_lat']]

    num_nodes = lon.size
    ug.nodes = np.zeros((num_nodes, 2), dtype=lon.dtype)
    ug.nodes[:, 0] = lon[:]
    ug.nodes[:, 1] = lat[:]

    # Faces.
    faces = nc.variables[names_mapping['faces']]
    # FIXME: This logic assumes there are more than three triangles.
    if faces.shape[0] <= faces.shape[1]:
        # Fortran order.
        faces = faces[:].T
    else:
        faces = faces[:]

    # One-indexed?
    if faces.min() == 1:
        one_indexed = True
    else:
        one_indexed = False

    if one_indexed:
        faces -= 1
    ug.faces = faces

    # Connectivity (optional).
    if 'face_face_connectivity' in names_mapping:
        face_face_connectivity = nc.variables[names_mapping['face_face_connectivity']]  # noqa
        # FIXME: This logic assumes there are more than three triangles.
        if face_face_connectivity.shape[0] <= face_face_connectivity.shape[1]:
            # Fortran order.
            face_face_connectivity = face_face_connectivity[:].T
        else:
            face_face_connectivity = face_face_connectivity[:]
        if one_indexed:
            face_face_connectivity -= 1
        ug.face_face_connectivity = face_face_connectivity

    # Center (optional).
    if ('face_coordinates_lon' in names_mapping and
       'face_coordinates_lat' in names_mapping):

        ug.face_coordinates = np.zeros((len(ug.faces), 2), dtype=lon.dtype)
        ug.face_coordinates[:, 0] = nc.variables[names_mapping['face_coordinates_lon']][:]  # noqa
        ug.face_coordinates[:, 1] = nc.variables[names_mapping['face_coordinates_lat']][:]  # noqa

    # Boundaries (optional).
    if 'boundaries' in names_mapping:
        # FIXME: this one is weird and non-conforming!
        # Ignoring the second two fields. What are they?
        boundaries = nc.variables[names_mapping['boundaries']][:, :2]
        if one_indexed:
            boundaries -= 1
        ug.boundaries = boundaries

    return ug
Пример #7
0
    def __init__(self, filename, *args, **kwargs):
        self.filename = os.path.expanduser(filename)
        dataset = netCDF4.Dataset(self.filename, mode="r")
        self.dataset = dataset
        meshes = {}
        for meshname in find_mesh_names(self.dataset):
            mesh = UGrid()
            load_grid_from_nc_dataset(dataset, mesh, mesh_name=meshname)
            meshes[meshname] = mesh
        self.meshes = meshes

        # Generate list of excluded variable names.
        exclude_vars = list(meshes.keys())

        for mesh in meshes.values():
            mesh_var = dataset.variables[mesh.mesh_name]
            for attr in mesh_var.ncattrs():
                if attr in _UGRID_LINK_PROPERTIES:
                    exclude_vars.extend(mesh_var.getncattr(attr).split())

        # Identify possible mesh dimensions and make a map of them.
        meshdims_map = {}  # Maps {dimension-name: (mesh, mesh-location)}
        for mesh in meshes.values():
            mesh_var = dataset.variables[mesh.mesh_name]
            if mesh.faces is not None:
                # Work out name of faces dimension and record it.
                if "face_dimension" in mesh_var.ncattrs():
                    faces_dim_name = mesh_var.getncattr("face_dimension")
                else:
                    # Assume default dimension ordering, and get the dim name
                    # from dims of a non-optional connectivity variable.
                    faces_varname = mesh_var.face_node_connectivity
                    faces_var = dataset.variables[faces_varname]
                    faces_dim_name = faces_var.dimensions[0]
                meshdims_map[faces_dim_name] = (mesh, "face")
            if mesh.edges is not None:
                # Work out name of edges dimension and record it.
                if "edge_dimension" in mesh_var.ncattrs():
                    edges_dim_name = mesh_var.getncattr("edge_dimension")
                else:
                    # Assume default dimension ordering, and get the dim name
                    # from dims of a non-optional connectivity variable.
                    edges_varname = mesh_var.edge_node_connectivity
                    edges_var = dataset.variables[edges_varname]
                    edges_dim_name = edges_var.dimensions[0]
                meshdims_map[edges_dim_name] = (mesh, "edge")
            if mesh.nodes is not None:
                # Work out name of nodes dimension and record it.
                # Get it from a non-optional coordinate variable.
                nodes_varname = mesh_var.node_coordinates.split()[0]
                nodes_var = dataset.variables[nodes_varname]
                nodes_dim_name = nodes_var.dimensions[0]
                meshdims_map[nodes_dim_name] = (mesh, "node")
        self.meshdims_map = meshdims_map

        # Initialise the main CF analysis operation, but make it ignore the
        # UGRID-specific variables.
        super().__init__(self.dataset,
                         *args,
                         exclude_var_names=exclude_vars,
                         **kwargs)