def load_gnome_tri(filename): """ load an fvcom/gnome netcdf file :param filename: the path to the file to load :returns: an UGRID object with the data from the file """ nc = netCDF4.Dataset(filename) # check if it's the file type we are looking for if nc.getncattr('grid_type').lower() != 'triangular': raise ValueError( 'This does not appear to be a valid triangular grid file:\nIt does not have the "grid_type"="Triangular" global attribute' ) # create an empty UGrid: ug = pyugrid.UGrid() # load the nodes lon = nc.variables['lon'] lat = nc.variables['lat'] num_nodes = lon.shape[0] ug.nodes = np.zeros((num_nodes, 2), dtype=lon.dtype) ug.nodes[:, 0] = lon[:] ug.nodes[:, 1] = lat[:] # load the faces ug.faces = nc.variables['nv'][:].T # load the connectivity array ug.face_face_connectivity = nc.variables['nbe'][:].T # load the center points of the faces ug.face_coordinates = np.zeros((len(ug.faces), 2), dtype=lon.dtype) ug.face_coordinates[:, 0] = nc.variables['lonc'][:] ug.face_coordinates[:, 1] = nc.variables['latc'][:] bounds = nc.variables['bnd'] ug.boundaries = bounds[:, : 2] # ignoring the second two fields -- what are they??? return ug
def tri_vector_field(filename=None, dataset=None): if dataset is None: dataset = nc4.Dataset(filename) nodes = np.ascontiguousarray( np.column_stack((dataset['lon'], dataset['lat']))).astype(np.double) faces = np.ascontiguousarray(np.array(dataset['nv']).T - 1) boundaries = np.ascontiguousarray(np.array(dataset['bnd'])[:, 0:2] - 1) neighbors = np.ascontiguousarray(np.array(dataset['nbe']).T - 1) edges = None grid = pyugrid.UGrid(nodes, faces, edges, boundaries, neighbors) grid.build_edges() u = pyugrid.UVar('u', 'node', dataset['u']) v = pyugrid.UVar('v', 'node', dataset['v']) time = Time(dataset['time']) variables = {'u':u, 'v':v} type = dataset.grid_type return VectorField(grid, time=time, variables=variables, type=type)
def init_grid(filename, grid_topology=None, dataset=None,): gt = grid_topology gf = dataset if gf is None: gf = _get_dataset(filename) grid = None if gt is None: try: grid = pyugrid.UGrid.from_nc_dataset(gf) except (ValueError, NameError): pass try: grid = pysgrid.SGrid.load_grid(gf) except (ValueError, NameError): gt = _gen_topology(filename) if grid is None: nodes = node_lon = node_lat = None if 'nodes' not in gt: if 'node_lon' not in gt and 'node_lat' not in gt: raise ValueError('Nodes must be specified with either the "nodes" or "node_lon" and "node_lat" keys') node_lon = gf[gt['node_lon']] node_lat = gf[gt['node_lat']] else: nodes = gf[gt['nodes']] if 'faces' in gt and gf[gt['faces']]: # UGrid faces = gf[gt['faces']] if faces.shape[0] == 3: faces = np.ascontiguousarray(np.array(faces).T - 1) if nodes is None: nodes = np.column_stack((node_lon, node_lat)) grid = pyugrid.UGrid(nodes=nodes, faces=faces) else: # SGrid center_lon = center_lat = edge1_lon = edge1_lat = edge2_lon = edge2_lat = None if node_lon is None: node_lon = nodes[:, 0] if node_lat is None: node_lat = nodes[:, 1] if 'center_lon' in gt: center_lon = gf[gt['center_lon']] if 'center_lat' in gt: center_lat = gf[gt['center_lat']] if 'edge1_lon' in gt: edge1_lon = gf[gt['edge1_lon']] if 'edge1_lat' in gt: edge1_lat = gf[gt['edge1_lat']] if 'edge2_lon' in gt: edge2_lon = gf[gt['edge2_lon']] if 'edge2_lat' in gt: edge2_lat = gf[gt['edge2_lat']] grid = pysgrid.SGrid(node_lon=node_lon, node_lat=node_lat, center_lon=center_lon, center_lat=center_lat, edge1_lon=edge1_lon, edge1_lat=edge1_lat, edge2_lon=edge2_lon, edge2_lat=edge2_lat) return grid
def load_from_varnames(filename, names_mapping): """ load a UGrid from a netcdf file where the roles are defined by the names of the variables :param filename: the names of the file to load (or opendap url) :param names_mapping: dict that maps the variable names to the UGRid components """ nc = netCDF4.Dataset("small_trigrid_example.nc") # check if it's the file type we are looking for try: name, value = names_mapping['attribute_check'] if nc.getncattr(name).lower() != value: raise ValueError( 'This does not appear to be a valid triangular grid file:\nIt does not have the "grid_type"="Triangular" global attribute' ) except KeyError: pass # create an empty UGrid: ug = pyugrid.UGrid() # load the nodes -- this is required # nodes are usually stored in two different arrays lon = nc.variables[names_mapping['nodes_lon']] lat = nc.variables[names_mapping['nodes_lat']] num_nodes = lon.shape[0] ug.nodes = np.zeros((num_nodes, 2), dtype=lon.dtype) ug.nodes[:, 0] = lon[:] ug.nodes[:, 1] = lat[:] # load the faces faces = nc.variables[names_mapping['faces']] # does it need to be transposed? if faces.shape[0] <= faces.shape[ 1]: # assume there are more than three triangles... # fortran order -- needs to be transposed faces = faces[:].T else: faces = faces[:] # is it one-indexed? if faces.min() == 1: one_indexed = True faces -= 1 ug.faces = faces else: one_indexed = False # load the connectivity array: optional if 'face_face_connectivity' in names_mapping: face_face_connectivity = nc.variables[ names_mapping['face_face_connectivity']] # does it need to be transposed? if face_face_connectivity.shape[0] <= face_face_connectivity.shape[ 1]: # assume there are more than three triangles... # fortran order -- needs to be transposed 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[:] # load the center points of the faces: optional if 'face_coordinates_lon' in names_mapping and 'face_coordinates_lon' 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']][:] ug.face_coordinates[:, 1] = nc.variables[ names_mapping['face_coordinates_lat']][:] print "checking bounds" if 'boundaries' in names_mapping: # optional print "loading boundaries" ## fixme -- this one is weird and non-conforming.... boundaries = nc.variables[names_mapping['boundaries']][:] if one_indexed: boundaries[:, :2] -= 1 ug.boundaries = boundaries[:, : 2] # ignoring the rest of the fields -- they are boundary data -- see below # kludge to handle the gnome tri format's putting boundary data in with the boundary indexes.. if boundaries.shape[ 1] == 4: #this looks like GNOME-style boundary data ## add the boudnary data as uvars pass return ug
def getcommonmesh_remesh(ugrid0, ugrid1, varkws): """ interpolate two UGRID meshes (create with IO_netcdfplot_dg_remesh) and the given variables to common fine "base" mesh. Locally one mesh must be a submesh in the other. """ # compute triangle midpoints on both grids midpointsf0 = np.mean(ugrid0.nodes[ugrid0.faces], axis=1) midpointsf1 = np.mean(ugrid1.nodes[ugrid1.faces], axis=1) # locate which triangles from on grid are in which triangles from the other f1mf0 = ugrid1.locate_faces(midpointsf0) f0mf1 = ugrid0.locate_faces(midpointsf1) # compute areas of triangles to decide, which triangles are common, and which are # sub-triangles in the other grid nodesf0 = ugrid0.nodes[ugrid0.faces] areaf0 = 0.5 * np.abs((nodesf0[:, 0, 0] - nodesf0[:, 2, 0]) * (nodesf0[:, 1, 1] - nodesf0[:, 0, 1]) - (nodesf0[:, 0, 0] - nodesf0[:, 1, 0]) * (nodesf0[:, 2, 1] - nodesf0[:, 0, 1])) nodesf1 = ugrid1.nodes[ugrid1.faces] areaf1 = 0.5 * np.abs((nodesf1[:, 0, 0] - nodesf1[:, 2, 0]) * (nodesf1[:, 1, 1] - nodesf1[:, 0, 1]) - (nodesf1[:, 0, 0] - nodesf1[:, 1, 0]) * (nodesf1[:, 2, 1] - nodesf1[:, 0, 1])) # compute common nodes idxf0same = np.isclose(areaf0, areaf1[f1mf0]) idxn0same = ugrid0.faces[idxf0same].ravel() idxn1same = ugrid1.faces[idxf0same[f0mf1]].ravel() newnodes = ugrid0.nodes[idxn0same] # setup variables vars0 = {} vars1 = {} vars0new = {} vars1new = {} for kw in varkws: vars0[kw] = ugrid0.data[kw].data[0, :] vars1[kw] = ugrid1.data[kw].data[0, :] vars0new[kw] = vars0[kw][idxn0same] vars1new[kw] = vars1[kw][idxn1same] # walk through all triangle in first mesh, which are not other mesh for f0i in np.where(~idxf0same)[0]: face0i = ugrid0.faces[f0i] nodesf0i = ugrid0.nodes[face0i] areaf0i = areaf0[f0i] # find corresponding triangle other mesh and compare areas f1i = f1mf0[f0i] face1i = ugrid1.faces[f1i] areaf1i = areaf1[f1i] if (areaf0i < areaf1i): # if area is smaller, add nodes to new mesh and linearly # interpolate variables to finer mesh nodesf1i = ugrid1.nodes[face1i] newnodes = np.vstack([newnodes, ugrid0.nodes[face0i]]) nodesf0b = xytobary(nodesf0i[:, 0], nodesf0i[:, 1], nodesf1i[:, 0], nodesf1i[:, 1]) for kw in varkws: vars0new[kw] = np.append(vars0new[kw], vars0[kw][face0i]) vars1new[kw] = np.append(vars1new[kw], np.dot(nodesf0b, vars1[kw][face1i])) else: # if are is larger, add nodes from other mesh to new mesh and interpolate # variables from first mesh f1add = np.where(f0mf1 == f0i)[0] nodesf1 = ugrid1.nodes[ugrid1.faces[f1add]] n1add = ugrid1.faces[f1add].ravel() newnodes = np.vstack([newnodes, ugrid1.nodes[n1add]]) nodesf1b = np.swapaxes( xytobary(nodesf1[:, :, 0], nodesf1[:, :, 1], nodesf0i[:, 0], nodesf0i[:, 1]), 0, 1) for kw in varkws: vars0new[kw] = np.append(vars0new[kw], np.dot(nodesf1b, vars0[kw][face0i])) vars1new[kw] = np.append(vars1new[kw], vars1[kw][ugrid1.faces[f1add]]) # create new fine common mesh newfaces = np.reshape(np.arange(newnodes.shape[0]), (newnodes.shape[0] / 3, 3)) ugridnew = pyugrid.UGrid(nodes=newnodes, faces=newfaces, mesh_name=ugrid0.mesh_name) # copy variables to new fine mesh for kw in varkws: uvar0new = copy.deepcopy(ugrid0.data[kw]) uvar0new.data = np.array([vars0new[kw]]) uvar0new.name = kw + '_0' ugridnew.add_data(uvar0new) uvar1new = copy.deepcopy(ugrid1.data[kw]) uvar1new.data = np.array([vars1new[kw]]) uvar1new.name = kw + '_1' ugridnew.add_data(uvar1new) return ugridnew