Tutorials¶
Hello World¶
import esmpy # This call enables debug logging # esmpy = esmpy.Manager(debug=True) print ("Hello ESMPy World from PET (processor) {0}!".format(esmpy.local_pet()))
Regridding Helper Functions¶
The following code snippets demonstrate how to build all of the pieces
necessary to regrid data between Fields
built on
Grids
, Meshes
and LocStreams
.
LocStream Create¶
def create_locstream_spherical_16(coord_sys=esmpy.CoordSys.SPH_DEG, domask=False):
"""
:param coord_sys: the coordinate system of the LocStream
:param domask: a boolean to tell whether or not to add a mask
:return: LocStream
"""
if esmpy.pet_count() != 1:
raise ValueError("processor count must be 1 to use this function")
locstream = esmpy.LocStream(16, coord_sys=coord_sys)
deg_rad = pi
if coord_sys == esmpy.CoordSys.SPH_DEG:
deg_rad = 180
locstream["ESMF:Lon"] = [0.2*deg_rad, 0.5*deg_rad, 1.5*deg_rad, 1.8*deg_rad, 0.2*deg_rad, 0.5*deg_rad, 1.5*deg_rad, 1.8*deg_rad, 0.2*deg_rad, 0.5*deg_rad, 1.5*deg_rad, 1.8*deg_rad, 0.2*deg_rad, 0.5*deg_rad, 1.5*deg_rad, 1.8*deg_rad]
locstream["ESMF:Lat"] = [-0.4*deg_rad, -0.4*deg_rad, -0.4*deg_rad, -0.4*deg_rad, -0.25*deg_rad, -0.25*deg_rad, -0.25*deg_rad, -0.25*deg_rad, 0.25*deg_rad, 0.25*deg_rad, 0.25*deg_rad, 0.25*deg_rad, 0.4*deg_rad, 0.4*deg_rad, 0.4*deg_rad, 0.4*deg_rad]
if domask:
locstream["ESMF:Mask"] = np.array([1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], dtype=np.int32)
return locstream
LocStream Create Parallel¶
def create_locstream_spherical_16_parallel(coord_sys=esmpy.CoordSys.SPH_DEG, domask=False):
"""
:param coord_sys: the coordinate system of the LocStream
:param domask: a boolean to tell whether or not to add a mask
:return: LocStream
"""
if esmpy.pet_count() != 4:
raise ValueError("processor count must be 4 to use this function")
deg_rad = pi
if coord_sys == esmpy.CoordSys.SPH_DEG:
deg_rad = 180.0
locstream = None
if esmpy.local_pet() == 0:
locstream = esmpy.LocStream(4, coord_sys=coord_sys)
locstream["ESMF:Lon"] = [0.2*deg_rad, 0.5*deg_rad, 0.2*deg_rad, 0.5*deg_rad]
locstream["ESMF:Lat"] = [-0.4*deg_rad, -0.4*deg_rad, -0.25*deg_rad, -0.25*deg_rad]
if domask:
locstream["ESMF:Mask"] = np.array([1, 0, 1, 1], dtype=np.int32)
elif esmpy.local_pet() == 1:
locstream = esmpy.LocStream(4, coord_sys=coord_sys)
locstream["ESMF:Lon"] = [1.5*deg_rad, 1.8*deg_rad, 1.5*deg_rad, 1.8*deg_rad]
locstream["ESMF:Lat"] = [-0.4*deg_rad, -0.4*deg_rad, -0.25*deg_rad, -0.25*deg_rad]
if domask:
locstream["ESMF:Mask"] = np.array([0, 1, 1, 1], dtype=np.int32)
elif esmpy.local_pet() == 2:
locstream = esmpy.LocStream(4, coord_sys=coord_sys)
locstream["ESMF:Lon"] = [0.2*deg_rad, 0.5*deg_rad, 0.2*deg_rad, 0.5*deg_rad]
locstream["ESMF:Lat"] = [0.25*deg_rad, 0.25*deg_rad, 0.4*deg_rad, 0.4*deg_rad]
if domask:
locstream["ESMF:Mask"] = np.array([1, 1, 1, 1], dtype=np.int32)
elif esmpy.local_pet() == 3:
locstream = esmpy.LocStream(4, coord_sys=coord_sys)
locstream["ESMF:Lon"] = [1.5*deg_rad, 1.8*deg_rad, 1.5*deg_rad, 1.8*deg_rad]
locstream["ESMF:Lat"] = [0.25*deg_rad, 0.25*deg_rad, 0.4*deg_rad, 0.4*deg_rad]
if domask:
locstream["ESMF:Mask"] = np.array([1, 1, 1, 1], dtype=np.int32)
return locstream
Create a 2D Grid¶
def grid_create_from_coordinates(xcoords, ycoords, xcorners=False, ycorners=False, corners=False, domask=False, doarea=False, ctk=esmpy.TypeKind.R8): """ Create a 2 dimensional Grid using the bounds of the x and y coordiantes. :param xcoords: The 1st dimension or 'x' coordinates at cell centers, as a Python list or numpy Array :param ycoords: The 2nd dimension or 'y' coordinates at cell centers, as a Python list or numpy Array :param xcorners: The 1st dimension or 'x' coordinates at cell corners, as a Python list or numpy Array :param ycorners: The 2nd dimension or 'y' coordinates at cell corners, as a Python list or numpy Array :param domask: boolean to determine whether to set an arbitrary mask or not :param doarea: boolean to determine whether to set an arbitrary area values or not :param ctk: the coordinate typekind :return: grid """ [x, y] = [0, 1] # create a grid given the number of grid cells in each dimension, the center stagger location is allocated, the # Cartesian coordinate system and type of the coordinates are specified max_index = np.array([len(xcoords), len(ycoords)]) grid = esmpy.Grid(max_index, staggerloc=[esmpy.StaggerLoc.CENTER], coord_sys=esmpy.CoordSys.CART, coord_typekind=ctk) # set the grid coordinates using numpy arrays, parallel case is handled using grid bounds gridXCenter = grid.get_coords(x) x_par = xcoords[grid.lower_bounds[esmpy.StaggerLoc.CENTER][x]:grid.upper_bounds[esmpy.StaggerLoc.CENTER][x]] gridXCenter[...] = x_par.reshape((x_par.size, 1)) gridYCenter = grid.get_coords(y) y_par = ycoords[grid.lower_bounds[esmpy.StaggerLoc.CENTER][y]:grid.upper_bounds[esmpy.StaggerLoc.CENTER][y]] gridYCenter[...] = y_par.reshape((1, y_par.size)) # create grid corners in a slightly different manner to account for the bounds format common in CF-like files if corners: grid.add_coords([esmpy.StaggerLoc.CORNER]) lbx = grid.lower_bounds[esmpy.StaggerLoc.CORNER][x] ubx = grid.upper_bounds[esmpy.StaggerLoc.CORNER][x] lby = grid.lower_bounds[esmpy.StaggerLoc.CORNER][y] uby = grid.upper_bounds[esmpy.StaggerLoc.CORNER][y] gridXCorner = grid.get_coords(x, staggerloc=esmpy.StaggerLoc.CORNER) for i0 in range(ubx - lbx - 1): gridXCorner[i0, :] = xcorners[i0+lbx, 0] gridXCorner[i0 + 1, :] = xcorners[i0+lbx, 1] gridYCorner = grid.get_coords(y, staggerloc=esmpy.StaggerLoc.CORNER) for i1 in range(uby - lby - 1): gridYCorner[:, i1] = ycorners[i1+lby, 0] gridYCorner[:, i1 + 1] = ycorners[i1+lby, 1] # add an arbitrary mask if domask: mask = grid.add_item(esmpy.GridItem.MASK) mask[:] = 1 mask[np.where((1.75 <= gridXCenter) & (gridXCenter < 2.25) & (1.75 <= gridYCenter) & (gridYCenter < 2.25))] = 0 # add arbitrary areas values if doarea: area = grid.add_item(esmpy.GridItem.AREA) area[:] = 5.0 return grid
Create a 3D Grid¶
def grid_create_from_coordinates_3d(xcoords, ycoords, zcoords, xcorners=False, ycorners=False, zcorners=False, corners=False, domask=False, doarea=False): """ Create a 3 dimensional Grid using the xcoordinates, ycoordinates and zcoordinates. :param xcoords: The 1st dimension or 'x' coordinates at cell centers, as a Python list or numpy Array :param ycoords: The 2nd dimension or 'y' coordinates at cell centers, as a Python list or numpy Array :param zcoords: The 3rd dimension or 'z' coordinates at cell centers, as a Python list or numpy Array :param xcorners: The 1st dimension or 'x' coordinates at cell corners, as a Python list or numpy Array :param ycorners: The 2nd dimension or 'y' coordinates at cell corners, as a Python list or numpy Array :param zcorners: The 3rd dimension or 'z' coordinates at cell corners, as a Python list or numpy Array :param corners: boolean to determine whether or not to add corner coordinates to this grid :param domask: boolean to determine whether to set an arbitrary mask or not :param doarea: boolean to determine whether to set an arbitrary area values or not :return: grid """ [x, y, z] = [0, 1, 2] # create a grid given the number of grid cells in each dimension, the center stagger location is allocated and the # Cartesian coordinate system is specified max_index = np.array([len(xcoords), len(ycoords), len(zcoords)]) grid = esmpy.Grid(max_index, staggerloc=[esmpy.StaggerLoc.CENTER_VCENTER], coord_sys=esmpy.CoordSys.CART) # set the grid coordinates using numpy arrays, parallel case is handled using grid bounds gridXCenter = grid.get_coords(x) x_par = xcoords[grid.lower_bounds[esmpy.StaggerLoc.CENTER_VCENTER][x]:grid.upper_bounds[esmpy.StaggerLoc.CENTER_VCENTER][x]] gridXCenter[...] = x_par.reshape(x_par.size, 1, 1) gridYCenter = grid.get_coords(y) y_par = ycoords[grid.lower_bounds[esmpy.StaggerLoc.CENTER_VCENTER][y]:grid.upper_bounds[esmpy.StaggerLoc.CENTER_VCENTER][y]] gridYCenter[...] = y_par.reshape(1, y_par.size, 1) gridZCenter = grid.get_coords(z) z_par = zcoords[grid.lower_bounds[esmpy.StaggerLoc.CENTER_VCENTER][z]:grid.upper_bounds[esmpy.StaggerLoc.CENTER_VCENTER][z]] gridZCenter[...] = z_par.reshape(1, 1, z_par.size) # create grid corners in a slightly different manner to account for the bounds format common in CF-like files if corners: grid.add_coords([esmpy.StaggerLoc.CORNER_VFACE]) lbx = grid.lower_bounds[esmpy.StaggerLoc.CORNER_VFACE][x] ubx = grid.upper_bounds[esmpy.StaggerLoc.CORNER_VFACE][x] lby = grid.lower_bounds[esmpy.StaggerLoc.CORNER_VFACE][y] uby = grid.upper_bounds[esmpy.StaggerLoc.CORNER_VFACE][y] lbz = grid.lower_bounds[esmpy.StaggerLoc.CORNER_VFACE][z] ubz = grid.upper_bounds[esmpy.StaggerLoc.CORNER_VFACE][z] gridXCorner = grid.get_coords(x, staggerloc=esmpy.StaggerLoc.CORNER_VFACE) for i0 in range(ubx - lbx - 1): gridXCorner[i0, :, :] = xcorners[i0+lbx, 0] gridXCorner[i0 + 1, :, :] = xcorners[i0+lbx, 1] gridYCorner = grid.get_coords(y, staggerloc=esmpy.StaggerLoc.CORNER_VFACE) for i1 in range(uby - lby - 1): gridYCorner[:, i1, :] = ycorners[i1+lby, 0] gridYCorner[:, i1 + 1, :] = ycorners[i1+lby, 1] gridZCorner = grid.get_coords(z, staggerloc=esmpy.StaggerLoc.CORNER_VFACE) for i2 in range(ubz - lbz - 1): gridZCorner[:, :, i2] = zcorners[i2+lbz, 0] gridZCorner[:, :, i2 + 1] = zcorners[i2+lbz, 1] # add an arbitrary mask if domask: mask = grid.add_item(esmpy.GridItem.MASK) mask[:] = 1 mask[np.where((1.75 <= gridXCenter) & (gridXCenter < 2.25) & (1.75 <= gridYCenter) & (gridYCenter < 2.25) & (1.75 <= gridZCenter) & (gridZCenter < 2.25))] = 0 # add arbitrary areas values if doarea: area = grid.add_item(esmpy.GridItem.AREA) area[:] = 5.0 return grid
Create a Periodic Grid¶
def grid_create_from_coordinates_periodic(longitudes, latitudes, lon_corners=False, lat_corners=False, corners=False, domask=False): """ Create a 2 dimensional periodic Grid using the 'longitudes' and 'latitudes'. :param longitudes: longitude coordinate values at cell centers :param latitudes: latitude coordinate values at cell centers :param lon_corners: longitude coordinate values at cell corners :param lat_corners: latitude coordinate values at cell corners :param corners: boolean to determine whether or not to add corner coordinates to this grid :param domask: boolean to determine whether to set an arbitrary mask or not :return: grid """ [lon, lat] = [0, 1] # create a grid given the number of grid cells in each dimension the center stagger location is allocated max_index = np.array([len(longitudes), len(latitudes)]) grid = esmpy.Grid(max_index, num_peri_dims=1, staggerloc=[esmpy.StaggerLoc.CENTER]) # set the grid coordinates using numpy arrays, parallel case is handled using grid bounds gridXCenter = grid.get_coords(lon) lon_par = longitudes[grid.lower_bounds[esmpy.StaggerLoc.CENTER][lon]:grid.upper_bounds[esmpy.StaggerLoc.CENTER][lon]] gridXCenter[...] = lon_par.reshape((lon_par.size, 1)) gridYCenter = grid.get_coords(lat) lat_par = latitudes[grid.lower_bounds[esmpy.StaggerLoc.CENTER][lat]:grid.upper_bounds[esmpy.StaggerLoc.CENTER][lat]] gridYCenter[...] = lat_par.reshape((1, lat_par.size)) # create grid corners in a slightly different manner to account for the bounds format common in CF-like files if corners: grid.add_coords([esmpy.StaggerLoc.CORNER]) lbx = grid.lower_bounds[esmpy.StaggerLoc.CORNER][lon] ubx = grid.upper_bounds[esmpy.StaggerLoc.CORNER][lon] lby = grid.lower_bounds[esmpy.StaggerLoc.CORNER][lat] uby = grid.upper_bounds[esmpy.StaggerLoc.CORNER][lat] gridXCorner = grid.get_coords(lon, staggerloc=esmpy.StaggerLoc.CORNER) for i0 in range(ubx - lbx - 1): gridXCorner[i0, :] = lon_corners[i0+lbx, 0] gridXCorner[i0 + 1, :] = lon_corners[i0+lbx, 1] gridYCorner = grid.get_coords(lat, staggerloc=esmpy.StaggerLoc.CORNER) for i1 in range(uby - lby - 1): gridYCorner[:, i1] = lat_corners[i1+lby, 0] gridYCorner[:, i1 + 1] = lat_corners[i1+lby, 1] # add an arbitrary mask if domask: mask = grid.add_item(esmpy.GridItem.MASK) mask[:] = 1 mask[np.where((1.75 <= gridXCenter) & (gridXCenter < 2.25) & (1.75 <= gridYCenter) & (gridYCenter < 2.25))] = 0 return grid
Create a 5 Element Mesh¶
def mesh_create_5(): """ PRECONDITIONS: None POSTCONDITIONS: A 5 element Mesh has been created. RETURN VALUES: \n Mesh :: mesh \n 4.0 31 ------ 32 ------ 33 | | 22 / | | 21 | / | | | / 23 | 2.0 21 ------ 22 ------ 23 | | | | 11 | 12 | | | | 0.0 11 ------ 12 ------ 13 0.0 2.0 4.0 Node Ids at corners Element Ids in centers Note: This mesh is not parallel, it can only be used in serial """ # Two parametric dimensions, and two spatial dimensions mesh = esmpy.Mesh(parametric_dim=2, spatial_dim=2) num_node = 9 num_elem = 5 nodeId = np.array([11,12,13,21,22,23,31,32,33]) nodeCoord = np.array([0.0,0.0, # node 11 2.0,0.0, # node 12 4.0,0.0, # node 13 0.0,2.0, # node 21 2.0,2.0, # node 22 4.0,2.0, # node 23 0.0,4.0, # node 31 2.0,4.0, # node 32 4.0,4.0]) # node 33 nodeOwner = np.zeros(num_node) elemId = np.array([11,12,21,22,23]) elemType=np.array([esmpy.MeshElemType.QUAD, esmpy.MeshElemType.QUAD, esmpy.MeshElemType.QUAD, esmpy.MeshElemType.TRI, esmpy.MeshElemType.TRI]) elemConn=np.array([0,1,4,3, # element 11 1,2,5,4, # element 12 3,4,7,6, # element 21 4,8,7, # element 22 4,5,8]) # element 23 elemCoord = np.array([1.0, 1.0, 3.0, 1.0, 1.0, 3.0, 2.5, 3.5, 3.5, 2.5]) mesh.add_nodes(num_node,nodeId,nodeCoord,nodeOwner) mesh.add_elements(num_elem,elemId,elemType,elemConn, element_coords=elemCoord) return mesh, nodeCoord, nodeOwner, elemType, elemConn, elemCoord
Create a Field¶
def create_field(gml, name): ''' PRECONDITIONS: An Grid, Mesh or LocStream has been created, and 'name' is a string that will be used to initialize the name of a new Field.\n POSTCONDITIONS: A Field has been created.\n RETURN VALUES: \n Field :: field \n ''' field = Field(gml, name=name) return field
Initialize an Analytic Field¶
def initialize_field_grid_periodic(field): """ PRECONDITIONS: A Field has been created as 'field' with a 'grid' where coordinates have been set on both the center and corner stagger locations. \n POSTCONDITIONS: The 'field' has been initialized to an analytic field.\n RETURN VALUES: \n Field :: field \n """ DEG2RAD = 3.141592653589793/180.0 # get the coordinate pointers and set the coordinates [x,y] = [0, 1] gridXCoord = field.grid.get_coords(x, esmpy.StaggerLoc.CENTER) gridYCoord = field.grid.get_coords(y, esmpy.StaggerLoc.CENTER) field.data[:] = 2.0 + np.cos(DEG2RAD*gridXCoord)**2 * \ np.cos(2.0*DEG2RAD*(90.0 - gridYCoord)) return field
Run ESMPy Regridding¶
def run_regridding(srcfield, dstfield, srcfracfield, dstfracfield): # This is for documentation. Do not modify. ''' PRECONDITIONS: Two Fields have been created and a regridding operation is desired from 'srcfield' to 'dstfield'. The 'srcfracfield' and 'dstfractfield' are Fields created to hold the fractions of the source and destination fields which contribute to conservative regridding.\n POSTCONDITIONS: A regridding operation has set the data on 'dstfield', 'srcfracfield', and 'dstfracfield'.\n RETURN VALUES: \n Field :: dstfield \n Field :: srcfracfield \n Field :: dstfracfield \n ''' # call the regridding functions regridSrc2Dst = esmpy.Regrid(srcfield, dstfield, regrid_method=esmpy.RegridMethod.CONSERVE, unmapped_action=esmpy.UnmappedAction.ERROR, src_frac_field=srcfracfield, dst_frac_field=dstfracfield) dstfield = regridSrc2Dst(srcfield, dstfield) return dstfield, srcfracfield, dstfracfield
Compute Field Mass¶
def compute_mass_grid(valuefield, dofrac=False, fracfield=None, uninitval=422397696.): """ PRECONDITIONS: 'fracfield' contains the fractions of each cell which contributed to a regridding operation involving 'valuefield. 'dofrac' is a boolean value that gives the option to not use the 'fracfield'.\n POSTCONDITIONS: The mass of the data field is computed.\n RETURN VALUES: float :: mass \n """ mass = 0.0 areafield = esmpy.Field(valuefield.grid, name='areafield') areafield.get_area() ind = np.where(valuefield.data != uninitval) if dofrac: mass = np.sum(areafield.data[ind] * valuefield.data[ind] * fracfield.data[ind]) else: mass = np.sum(areafield.data[ind] * valuefield.data[ind]) return mass
Regridding¶
The following stand alone scripts demonstrate how to use regridding between
Fields
built on
Grids
, Meshes
and LocStreams
. These scripts
can be run in serial or parallel with no modification.
Grid, Mesh and Field Created from File¶
# This example demonstrates how to create ESMPy Grid, Mesh and Field objects # from file and use them for regridding. import os import esmpy from esmpy.util.cache_data import DATA_DIR from esmpy.util.exceptions import DataMissing # The data files can be retrieved from the ESMF data repository by uncommenting the # following block of code: # # from esmpy.util.cache_data import cache_data_file # cache_data_file(os.path.join(DATA_DIR, "so_Omon_GISS-E2.nc")) # cache_data_file(os.path.join(DATA_DIR, "mpas_uniform_10242_dual_counterclockwise.nc")) # This call enables debug logging # esmpy.Manager(debug=True) datafile = os.path.join(DATA_DIR, "so_Omon_GISS-E2.nc") if not os.path.exists(datafile): raise DataMissing("Data not available, try 'make download'.") meshfile = os.path.join(DATA_DIR, "mpas_uniform_10242_dual_counterclockwise.nc") if not os.path.exists(meshfile): raise DataMissing("Data not available, try 'make download'.") # Create a global grid from a GRIDSPEC formatted file grid = esmpy.Grid(filename=os.path.join(DATA_DIR, datafile), filetype=esmpy.FileFormat.GRIDSPEC) # Create a field on the centers of the grid, with extra dimensions srcfield = esmpy.Field(grid, staggerloc=esmpy.StaggerLoc.CENTER, ndbounds=[33, 2]) # Read the field data from file srcfield.read(filename=os.path.join(DATA_DIR, datafile), variable="so", timeslice=2) # Create an ESMF formatted unstructured mesh with clockwise cells removed mesh = esmpy.Mesh(filename=os.path.join(DATA_DIR, meshfile), filetype=esmpy.FileFormat.ESMFMESH) # Create a field on the nodes of the mesh dstfield = esmpy.Field(mesh, meshloc=esmpy.MeshLoc.NODE, ndbounds=[33, 2]) dstfield.data[:] = 1e20 # compute the weight matrix for regridding regrid = esmpy.Regrid(srcfield, dstfield, regrid_method=esmpy.RegridMethod.BILINEAR, unmapped_action=esmpy.UnmappedAction.IGNORE) # calculate the regridding from source to destination field dstfield = regrid(srcfield, dstfield) if esmpy.local_pet() == 0: print ("Fields created from file regridded successfully :)")
Read and Write a Weight File¶
# This example demonstrates how to regrid between a Grid and a Mesh. import esmpy import numpy import os import esmpy.util.helpers as helpers import esmpy.api.constants as constants # This call enables debug logging mg = esmpy.Manager(debug=True) # ESMPy uses Fortran style dimension ordering (as of November 2017) [lat,lon] = [1,0] # Create the source grid from memory with periodic dimension specified. lons = numpy.arange(5, 350.1, 10) lats = numpy.arange(-85, 85.1, 10) srcgrid = esmpy.Grid(numpy.array([lons.size, lats.size]), coord_sys=esmpy.CoordSys.SPH_DEG, staggerloc=esmpy.StaggerLoc.CENTER, num_peri_dims=1, periodic_dim=0, pole_dim=1) # Get and set the source grid coordinates. srcGridCoordLon = srcgrid.get_coords(lon) srcGridCoordLat = srcgrid.get_coords(lat) slons_par = lons[srcgrid.lower_bounds[esmpy.StaggerLoc.CENTER][0]:srcgrid.upper_bounds[esmpy.StaggerLoc.CENTER][0]] slats_par = lats[srcgrid.lower_bounds[esmpy.StaggerLoc.CENTER][1]:srcgrid.upper_bounds[esmpy.StaggerLoc.CENTER][1]] # make sure to use indexing='ij' as ESMPy backend uses matrix indexing (not Cartesian) lonm, latm = numpy.meshgrid(slons_par, slats_par, indexing='ij') srcGridCoordLon[:] = lonm srcGridCoordLat[:] = latm # Create the dest grid from memory with periodic dimension specified. lons = numpy.arange(2.5, 357.6, 5) lats = numpy.arange(-87.5, 87.6, 5) dstgrid = esmpy.Grid(numpy.array([lons.size, lats.size]), coord_sys=esmpy.CoordSys.SPH_DEG, staggerloc=esmpy.StaggerLoc.CENTER, num_peri_dims=1, periodic_dim=1, pole_dim=0) # Get and set the source grid coordinates. dstGridCoordLat = dstgrid.get_coords(lat) dstGridCoordLon = dstgrid.get_coords(lon) dlons_par = lons[dstgrid.lower_bounds[esmpy.StaggerLoc.CENTER][0]:dstgrid.upper_bounds[esmpy.StaggerLoc.CENTER][0]] dlats_par = lats[dstgrid.lower_bounds[esmpy.StaggerLoc.CENTER][1]:dstgrid.upper_bounds[esmpy.StaggerLoc.CENTER][1]] # make sure to use indexing='ij' as ESMPy backend uses matrix indexing (not Cartesian) lonm, latm = numpy.meshgrid(dlons_par, dlats_par, indexing='ij') dstGridCoordLon[:] = lonm dstGridCoordLat[:] = latm # Create a field on the centers of the source grid with the mask applied. srcfield = esmpy.Field(srcgrid, name="srcfield", staggerloc=esmpy.StaggerLoc.CENTER) # Create a field on the centers of the source grid with the mask applied. dstfield = esmpy.Field(dstgrid, name="dstfield", staggerloc=esmpy.StaggerLoc.CENTER) xctfield = esmpy.Field(dstgrid, name="xctfield", staggerloc=esmpy.StaggerLoc.CENTER) gridLon = srcfield.grid.get_coords(lon, esmpy.StaggerLoc.CENTER) gridLat = srcfield.grid.get_coords(lat, esmpy.StaggerLoc.CENTER) # wave = lambda x,k: numpy.sin(x*k*numpy.pi/180.0) # srcfield.data[...] = numpy.outer(wave(slons_par,3), wave(slats_par,3)) + 2 srcfield.data[:,:] = 2.0 + numpy.cos(numpy.radians(srcGridCoordLat)[...])**2 * \ numpy.cos(2.0*numpy.radians(srcGridCoordLon)[...]) # wave = lambda x,k: numpy.sin(x*k*numpy.pi/180.0) # xctfield.data[...] = numpy.outer(wave(dlons_par,3), wave(dlats_par,3)) + 2 xctfield.data[:,:] = 2.0 + numpy.cos(numpy.radians(dstGridCoordLat)[...])**2 * \ numpy.cos(2.0*numpy.radians(dstGridCoordLon)[...]) dstfield.data[:] = 1e20 # write regridding weights to file filename = "esmpy_example_weight_file.nc" if esmpy.local_pet() == 0: if os.path.isfile( os.path.join(os.getcwd(), filename)): os.remove(os.path.join(os.getcwd(), filename)) mg.barrier() regrid = esmpy.Regrid(srcfield, dstfield, filename=filename, regrid_method=esmpy.RegridMethod.BILINEAR, unmapped_action=esmpy.UnmappedAction.IGNORE) # # create a regrid object from file regrid = esmpy.RegridFromFile(srcfield, dstfield, filename) # calculate the regridding from source to destination field dstfield = regrid(srcfield, dstfield) # compute the mean relative error num_nodes = numpy.prod(xctfield.data.shape[:]) relerr = 0 meanrelerr = 0 if num_nodes != 0: relerr = numpy.sum(numpy.abs(dstfield.data - xctfield.data) / numpy.abs(xctfield.data)) meanrelerr = relerr / num_nodes # handle the parallel case if esmpy.pet_count() > 1: relerr = helpers.reduce_val(relerr, op=constants.Reduce.SUM) num_nodes = helpers.reduce_val(num_nodes, op=constants.Reduce.SUM) # output the results from one processor only if esmpy.local_pet() == 0: meanrelerr = relerr / num_nodes print ("ESMPy Grid Mesh Regridding Example") print (" interpolation mean relative error = {0}".format(meanrelerr)) if os.path.isfile(os.path.join(os.getcwd(), filename)): os.remove(os.path.join(os.getcwd(), filename)) # set to 1 to output results # if esmpy.pet_count() == 0: # import matplotlib.pyplot as plt # fig = plt.figure(1, (15, 6)) # fig.suptitle('ESMPy Periodic Grids', fontsize=14, fontweight='bold') # # ax = fig.add_subplot(1, 2, 1) # im = ax.imshow(srcfield.data, vmin=1, vmax=3, cmap='gist_ncar', aspect='auto', # extent=[min(slons_par), max(slons_par), min(slats_par), max(slats_par)]) # ax.set_xbound(lower=min(slons_par), upper=max(slons_par)) # ax.set_ybound(lower=min(slats_par), upper=max(slats_par)) # ax.set_xlabel("Longitude") # ax.set_ylabel("Latitude") # ax.set_title("Source Data") # # ax = fig.add_subplot(1, 2, 2) # im = ax.imshow(dstfield.data, vmin=1, vmax=3, cmap='gist_ncar', aspect='auto', # extent=[min(dlons_par), max(dlons_par), min(dlats_par), max(dlats_par)]) # ax.set_xlabel("Longitude") # ax.set_ylabel("Latitude") # ax.set_title("Regrid Solution") # # fig.subplots_adjust(right=0.8) # cbar_ax = fig.add_axes([0.9, 0.1, 0.01, 0.8]) # fig.colorbar(im, cax=cbar_ax) # # plt.show()
Grid to LocStream¶
# This example demonstrates how to regrid between a Grid and a LocStream. import esmpy import numpy import os import esmpy.util.helpers as helpers import esmpy.api.constants as constants from esmpy.util.cache_data import DATA_DIR from esmpy.util.exceptions import DataMissing # The data files can be retrieved from the ESMF data repository by uncommenting the # following block of code: # # from esmpy.util.cache_data import cache_data_file # cache_data_file(os.path.join(DATA_DIR, "ll1deg_grid.nc")) # This call enables debug logging esmpy.Manager(debug=True) grid1 = os.path.join(DATA_DIR, "ll1deg_grid.nc") if not os.path.exists(grid1): raise DataMissing("Data not available, try 'make download'.") from esmpy.util.locstream_utilities import create_locstream_spherical_16, create_locstream_spherical_16_parallel coord_sys=esmpy.CoordSys.SPH_DEG domask=True if esmpy.pet_count() == 1: locstream = create_locstream_spherical_16(coord_sys=coord_sys, domask=domask) else: locstream = create_locstream_spherical_16_parallel(coord_sys=coord_sys, domask=domask) grid = esmpy.Grid(filename=grid1, filetype=esmpy.FileFormat.SCRIP) # create a field srcfield = esmpy.Field(grid, name='srcfield') dstfield = esmpy.Field(locstream, name='dstfield') xctfield = esmpy.Field(locstream, name='xctfield') # initialize the fields [x, y] = [0, 1] deg2rad = 3.14159/180 gridXCoord = srcfield.grid.get_coords(x) gridYCoord = srcfield.grid.get_coords(y) srcfield.data[...] = 10.0 + numpy.cos(gridXCoord * deg2rad) ** 2 + numpy.cos(2 * gridYCoord * deg2rad) gridXCoord = locstream["ESMF:Lon"] gridYCoord = locstream["ESMF:Lat"] if coord_sys == esmpy.CoordSys.SPH_DEG: xctfield.data[...] = 10.0 + numpy.cos(gridXCoord * deg2rad) ** 2 + numpy.cos(2 * gridYCoord * deg2rad) elif coord_sys == esmpy.CoordSys.SPH_RAD: xctfield.data[...] = 10.0 + numpy.cos(gridXCoord) ** 2 + numpy.cos(2 * gridYCoord) else: raise ValueError("coordsys value does not work in this example") dstfield.data[...] = 1e20 # create an object to regrid data from the source to the destination field dst_mask_values=None if domask: dst_mask_values=numpy.array([0]) regrid = esmpy.Regrid(srcfield, dstfield, regrid_method=esmpy.RegridMethod.BILINEAR, unmapped_action=esmpy.UnmappedAction.ERROR, dst_mask_values=dst_mask_values) # do the regridding from source to destination field dstfield = regrid(srcfield, dstfield, zero_region=esmpy.Region.SELECT) # compute the mean relative error num_nodes = numpy.prod(xctfield.data.shape[:]) relerr = 0 meanrelerr = 0 dstfield = numpy.ravel(dstfield.data) xctfield = numpy.ravel(xctfield.data) if num_nodes != 0: ind = numpy.where((dstfield != 1e20) & (xctfield != 0))[0] relerr = numpy.sum(numpy.abs(dstfield[ind] - xctfield[ind]) / numpy.abs(xctfield[ind])) meanrelerr = relerr / num_nodes # handle the parallel case if esmpy.pet_count() > 1: relerr = helpers.reduce_val(relerr, op=constants.Reduce.SUM) num_nodes = helpers.reduce_val(num_nodes, op=constants.Reduce.SUM) # output the results from one processor only if esmpy.local_pet() == 0: meanrelerr = relerr / num_nodes print ("ESMPy Grid LocStream Regridding Example") print (" interpolation mean relative error = {0}".format(meanrelerr)) assert (meanrelerr < 5e-6)
Mesh to LocStream¶
# This example demonstrates how to regrid between a mesh and a locstream. import esmpy import numpy import esmpy.util.helpers as helpers import esmpy.api.constants as constants # This call enables debug logging # esmpy.Manager(debug=True) from esmpy.util.mesh_utilities import mesh_create_5, mesh_create_5_parallel from esmpy.util.locstream_utilities import create_locstream_16, create_locstream_16_parallel if esmpy.pet_count() == 1: mesh, _, _, _, _, _ = mesh_create_5() locstream = create_locstream_16() else: mesh, _, _, _, _ = mesh_create_5_parallel() locstream = create_locstream_16_parallel() # create a field srcfield = esmpy.Field(mesh, name='srcfield')#, meshloc=esmpy.MeshLoc.ELEMENT) # create a field on the locstream dstfield = esmpy.Field(locstream, name='dstfield') xctfield = esmpy.Field(locstream, name='xctfield') # initialize the fields [x, y] = [0, 1] deg2rad = 3.14159/180 gridXCoord = srcfield.grid.get_coords(x) gridYCoord = srcfield.grid.get_coords(y) srcfield.data[...] = 10.0 + (gridXCoord * deg2rad) ** 2 + (gridYCoord * deg2rad) ** 2 gridXCoord = locstream["ESMF:X"] gridYCoord = locstream["ESMF:Y"] xctfield.data[...] = 10.0 + (gridXCoord * deg2rad) ** 2 + (gridYCoord * deg2rad) ** 2 dstfield.data[...] = 1e20 # create an object to regrid data from the source to the destination field # TODO: this example seems to fail occasionally with UnmappedAction.ERROR, probably due to a tolerance issue - ask Bob regrid = esmpy.Regrid(srcfield=srcfield, dstfield=dstfield, regrid_method=esmpy.RegridMethod.BILINEAR, unmapped_action=esmpy.UnmappedAction.IGNORE) # do the regridding from source to destination field dstfield = regrid(srcfield, dstfield) # compute the mean relative error num_nodes = numpy.prod(xctfield.data.shape[:]) relerr = 0 meanrelerr = 0 if num_nodes != 0: ind = numpy.where((dstfield.data != 1e20) & (xctfield.data != 0))[0] relerr = numpy.sum(numpy.abs(dstfield.data[ind] - xctfield.data[ind]) / numpy.abs(xctfield.data[ind])) meanrelerr = relerr / num_nodes # handle the parallel case if esmpy.pet_count() > 1: relerr = helpers.reduce_val(relerr, op=constants.Reduce.SUM) num_nodes = helpers.reduce_val(num_nodes, op=constants.Reduce.SUM) # output the results from one processor only if esmpy.local_pet() == 0: meanrelerr = relerr / num_nodes print ("ESMPy Grid Mesh Regridding Example") print (" interpolation mean relative error = {0}".format(meanrelerr)) assert (meanrelerr < 3e-5)
LocStream to Grid¶
# This example demonstrates how to regrid between a LocStream and a Grid. import esmpy import numpy import os import esmpy.util.helpers as helpers import esmpy.api.constants as constants from esmpy.util.cache_data import DATA_DIR from esmpy.util.exceptions import DataMissing # The data files can be retrieved from the ESMF data repository by uncommenting the # following block of code: # # from esmpy.util.cache_data import cache_data_file # cache_data_file(os.path.join(DATA_DIR, "ll1deg_grid.nc")) # This call enables debug logging esmpy.Manager(debug=True) grid1 = os.path.join(DATA_DIR, "ll1deg_grid.nc") if not os.path.exists(grid1): raise DataMissing("Data not available, try 'make download'.") grid = esmpy.Grid(filename=grid1, filetype=esmpy.FileFormat.SCRIP) from esmpy.util.locstream_utilities import create_locstream_spherical_16, create_locstream_spherical_16_parallel coord_sys=esmpy.CoordSys.SPH_DEG domask=True if esmpy.pet_count() == 1: locstream = create_locstream_spherical_16(coord_sys=coord_sys, domask=domask) else: locstream = create_locstream_spherical_16_parallel(coord_sys=coord_sys, domask=domask) # create a field srcfield = esmpy.Field(locstream, name='srcfield') dstfield = esmpy.Field(grid, name='dstfield') xctfield = esmpy.Field(grid, name='xctfield') # initialize the fields [x, y] = [0, 1] deg2rad = 3.14159/180 gridXCoord = locstream["ESMF:Lon"] gridYCoord = locstream["ESMF:Lat"] if coord_sys == esmpy.CoordSys.SPH_DEG: srcfield.data[...] = 10.0 + numpy.cos(gridXCoord * deg2rad) ** 2 + numpy.cos(2 * gridYCoord * deg2rad) elif coord_sys == esmpy.CoordSys.SPH_RAD: srcfield.data[...] = 10.0 + numpy.cos(gridXCoord) ** 2 + numpy.cos(2 * gridYCoord) else: raise ValueError("coordsys value does not apply in this example") gridXCoord = xctfield.grid.get_coords(x) gridYCoord = xctfield.grid.get_coords(y) xctfield.data[...] = 10.0 + numpy.cos(gridXCoord * deg2rad) ** 2 + numpy.cos(2 * gridYCoord * deg2rad) dstfield.data[...] = 1e20 # create an object to regrid data from the source to the destination field mask_values=None if domask: mask_values=numpy.array([0]) regrid = esmpy.Regrid(srcfield, dstfield, regrid_method=esmpy.RegridMethod.NEAREST_DTOS, unmapped_action=esmpy.UnmappedAction.ERROR, src_mask_values=mask_values) # do the regridding from source to destination field dstfield = regrid(srcfield, dstfield, zero_region=esmpy.Region.SELECT) # compute the mean relative error from operator import mul num_nodes = numpy.prod(xctfield.data.shape[:]) relerr = 0 meanrelerr = 0 dstfield = numpy.ravel(dstfield.data) xctfield = numpy.ravel(xctfield.data) if num_nodes != 0: ind = numpy.where((dstfield != 1e20) & (xctfield != 0))[0] relerr = numpy.sum(numpy.abs(dstfield[ind] - xctfield[ind]) / numpy.abs(xctfield[ind])) meanrelerr = relerr / num_nodes # handle the parallel case if esmpy.pet_count() > 1: relerr = helpers.reduce_val(relerr, op=constants.Reduce.SUM) num_nodes = helpers.reduce_val(num_nodes, op=constants.Reduce.SUM) # output the results from one processor only if esmpy.local_pet() == 0: meanrelerr = relerr / num_nodes print ("ESMPy LocStream Grid Regridding Example") print (" interpolation mean relative error = {0}".format(meanrelerr)) assert (meanrelerr < 4e-7)
Using MPI.Spawn() from a Serial Python Driver¶
# This example demonstrates how to call ESMPy regridding as a parallel # subprocess spawned using mpi4py from a serial Python driver. # # NOTE: MPI.COMM_WORLD.Spawn does not seem to work for mpi4py installations # installations built with mpich, however openmpi does work (July 2016). # import numpy from mpi4py import MPI import sys, os from esmpy.util.cache_data import DATA_DIR from esmpy.util.exceptions import DataMissing from functools import reduce # The data files can be retrieved from the ESMF data repository by uncommenting the # following block of code: # # from esmpy.util.cache_data import cache_data_file # cache_data_file(os.path.join(DATA_DIR, "ll1deg_grid.nc")) # cache_data_file(os.path.join(DATA_DIR, "mpas_uniform_10242_dual_counterclockwise.nc")) def regrid(): try: import esmpy except: raise ImportError("ESMF is not available on this machine") grid1 = os.path.join(DATA_DIR, "ll1deg_grid.nc") if not os.path.exists(grid1): raise DataMissing("Data not available, try 'make download'.") grid2 = os.path.join(DATA_DIR, "mpas_uniform_10242_dual_counterclockwise.nc") if not os.path.exists(grid2): raise DataMissing("Data not available, try 'make download'.") # Create a uniform global latlon grid from a SCRIP formatted file grid = esmpy.Grid(filename=grid1, filetype=esmpy.FileFormat.SCRIP) # NOTE: corners are needed for conservative regridding # grid = esmpy.Grid(filename=grid1, filetype=esmpy.FileFormat.SCRIP, # add_corner_stagger=True) # create a field on the center stagger locations of the source grid srcfield = esmpy.Field(grid, name='srcfield', staggerloc=esmpy.StaggerLoc.CENTER) # create an ESMF formatted unstructured mesh with clockwise cells removed mesh = esmpy.Mesh(filename=grid2, filetype=esmpy.FileFormat.ESMFMESH) # create a field on the nodes of the destination mesh dstfield = esmpy.Field(mesh, name='dstfield', meshloc=esmpy.MeshLoc.NODE) xctfield = esmpy.Field(mesh, name='xctfield', meshloc=esmpy.MeshLoc.NODE) # NOTE: Field must be built on elements of Mesh for conservative regridding # dstfield = esmpy.Field(mesh, name='dstfield', meshloc=esmpy.MeshLoc.ELEMENT) # xctfield = esmpy.Field(mesh, name='xctfield', meshloc=esmpy.MeshLoc.ELEMENT) # initialize the fields [lon, lat] = [0, 1] deg2rad = 3.14159 / 180 gridXCoord = srcfield.grid.get_coords(lon, esmpy.StaggerLoc.CENTER) gridYCoord = srcfield.grid.get_coords(lat, esmpy.StaggerLoc.CENTER) srcfield.data[...] = 10.0 + (gridXCoord * deg2rad) ** 2 + ( gridYCoord * deg2rad) ** 2 gridXCoord = xctfield.grid.get_coords(lon, esmpy.StaggerLoc.CENTER) gridYCoord = xctfield.grid.get_coords(lat, esmpy.StaggerLoc.CENTER) xctfield.data[...] = 10.0 + (gridXCoord * deg2rad) ** 2 + ( gridYCoord * deg2rad) ** 2 dstfield.data[...] = 1e20 # create an object to regrid data from the source to the destination field regrid = esmpy.Regrid(srcfield, dstfield, regrid_method=esmpy.RegridMethod.BILINEAR, unmapped_action=esmpy.UnmappedAction.ERROR) # do the regridding from source to destination field dstfield = regrid(srcfield, dstfield) return dstfield, xctfield def compute_error(dstfield, xctfield): # compute the mean relative error from operator import mul num_nodes = reduce(mul, xctfield.shape) relerr = 0 meanrelerr = 0 if num_nodes != 0: ind = numpy.where((dstfield != 1e20) & (xctfield != 0))[0] relerr = numpy.sum( numpy.abs(dstfield[ind] - xctfield[ind]) / numpy.abs( xctfield[ind])) meanrelerr = relerr / num_nodes meanrelerr = relerr / num_nodes print("ESMPy regridding as a spawned MPI process:") print(" interpolation mean relative error = {0}".format(meanrelerr)) ########################################### MAIN ############################# start_worker = 'worker' usage = 'Program should be started without arguments' pet_count = 4 # Parent if len(sys.argv) == 1: # Spawn workers comm = MPI.COMM_WORLD.Spawn( sys.executable, args=[sys.argv[0], start_worker], maxprocs=pet_count) # gather output fields from workers dstfield = None dstfield = comm.gather(dstfield, root=MPI.ROOT) dstfield = numpy.concatenate([dstfield[i] for i in range(pet_count)]) xctfield = None xctfield = comm.gather(xctfield, root=MPI.ROOT) xctfield = numpy.concatenate([xctfield[i] for i in range(pet_count)]) # plot results compute_error(dstfield, xctfield) # Shutdown comm.Disconnect() # Worker elif sys.argv[1] == start_worker: # Connect to parent try: comm = MPI.Comm.Get_parent() rank = comm.Get_rank() except: raise ValueError('Could not connect to parent - ' + usage) try: # call ESMPy regridding dstfield, xctfield = regrid() # send output to parent comm.gather(sendobj=dstfield.data, root=0) comm.gather(sendobj=xctfield.data, root=0) except: comm.Disconnect() # Shutdown comm.Disconnect() # Catch else: raise ValueError(usage)