Advertisement
Guest User

Untitled

a guest
Sep 29th, 2016
52
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.22 KB | None | 0 0
  1. # same function using variables
  2. _NFACES = 13
  3.  
  4. # these need to be set at some higher point
  5. xdim='i3'
  6. ydim='i2'
  7.  
  8. def _orthogonal_dim(dim):
  9. if dim==xdim:
  10. return ydim
  11. elif dim==ydim:
  12. return xdim
  13. else:
  14. raise ValueError("Invalid dim %s" % dim)
  15.  
  16. def _edge_dim_and_start(edge):
  17. if edge in ['N', 'S']:
  18. dim = ydim
  19. elif edge in ['E', 'W']:
  20. dim = xdim
  21. else:
  22. raise ValueError('%s is not a valid edge' % edge)
  23. if edge in ['S', 'W']:
  24. start = 0
  25. elif edge in ['N', 'E']:
  26. start = -1
  27. return dim, start
  28.  
  29. def exch_get_t_neighbors(var, edge, count=1, facedim='face'):
  30. """Return the neighbor points of a face at cell centers.
  31.  
  32. Paramters
  33. ---------
  34. var : xarray.Variable
  35. Must have a face dimension
  36. edge : {'N','S','E','W}
  37. The edge to fetch
  38. count : int
  39. Number of edge points to fetch
  40. facedim : str
  41. The name of the face dimension
  42.  
  43. Returns
  44. -------
  45. edge : numpy.ndarray
  46. The edge points. (Note NOT an xarray object.)
  47. """
  48.  
  49. face_axis = var.get_axis_num(facedim)
  50. this_edge_dim, _ = _edge_dim_and_start(edge)
  51. this_edge_axis = var.get_axis_num(this_edge_dim)
  52.  
  53. def edge_data(fnum):
  54. link = face_edge_link[fnum][edge]
  55. if link is None:
  56. # TODO: actually return the right data, NaN or similar
  57. return None
  58. else:
  59. other_fnum, other_edge, other_orientation = link
  60.  
  61. # Build up a slice that selects the correct edge region for a given face.
  62. # Start by getting everything
  63. face_slice = [slice(None),] * var.ndim
  64.  
  65. # Specify the face
  66. # (If this is an int rather than slice, the whole axis gets dropped.)
  67. face_slice[face_axis] = slice(other_fnum, other_fnum+1)
  68.  
  69. other_edge_dim, start = _edge_dim_and_start(other_edge)
  70. other_edge_axis = var.get_axis_num(other_edge_dim)
  71. if start==0:
  72. other_edge_slice = slice(None,count)
  73. elif start==-1:
  74. other_edge_slice = slice(-count,None)
  75. face_slice[other_edge_axis] = other_edge_slice
  76.  
  77. # the orthogonal dimension might need to be reoriented
  78. ortho_axis = var.get_axis_num(_orthogonal_dim(other_edge_dim))
  79. ortho_slice = slice(None,None,other_orientation)
  80. face_slice[ortho_axis] = ortho_slice
  81.  
  82. # now get the data
  83. data = var[tuple(face_slice)].data
  84.  
  85. # the axis of the edge on THIS face is
  86. # not necessarily the same as the axis on the OTHER face
  87. if this_edge_axis != other_edge_axis:
  88. # unfortunately dask.Array has no swapaxes method
  89. axes = range(data.ndim)
  90. axes[this_edge_axis] = other_edge_axis
  91. axes[other_edge_axis] = this_edge_axis
  92. data = data.transpose(axes)
  93. return data
  94.  
  95. arrays = [edge_data(fnum) for fnum in range(_NFACES)]
  96. data = xr.core.ops.concatenate(arrays, face_axis)
  97. return data
  98.  
  99. # modeled after xarray/xarray/core/variable.py
  100.  
  101. # specifcy which variables are rollable across a face
  102. # this is valid for 2D (time, lat, lon) or 3D (depth, lat, lon)
  103. _HORIZ_DIMS = {'i2': ('N','S'), 'i3': ('E','W')}
  104. # instead, 4D data would have
  105. #_HORIZ_DIMS = ['i3': ('N','S'), 'i4': ('E','W')]
  106.  
  107. # works on a variable
  108. def _roll_one_dim_face(var, dim, count):
  109. if dim not in _HORIZ_DIMS:
  110. raise KeyError("Can't roll dim '%s' across face. "
  111. "Can only roll dims %s" % (dim, repr(_HORIZ_DIMS)))
  112.  
  113. # set to N, S, E, or W, depending on sign of count
  114. # a positive roll (count>0) shifts everything LEFT=S=W
  115. # a negative roll (count<0) shifts everything RIGHT=N=E
  116. roll_left = count>0
  117. edge = _HORIZ_DIMS[dim][1 if roll_left else 0]
  118. data_neighbor = exch_get_t_neighbors(var, edge, abs(count))
  119.  
  120. axis = var.get_axis_num(dim)
  121.  
  122. count %= var.shape[axis]
  123.  
  124. if roll_left:
  125. indices = slice(None,-count)
  126. else:
  127. indices = slice(-count, None)
  128.  
  129. slices = (slice(None),) * axis + (indices,)
  130.  
  131. data_this_face = var[slices].data
  132. if roll_left:
  133. arrays = [data_neighbor, data_this_face]
  134. else:
  135. arrays = [data_this_face, data_neighbor]
  136. print([a.shape for a in arrays])
  137.  
  138. data = xr.core.ops.concatenate(arrays, axis)
  139.  
  140. if isinstance(data, xr.core.pycompat.dask_array_type):
  141. # chunked data should come out with the same chunks; this makes
  142. # it feasible to combine shifted and unshifted data
  143. # TODO: remove this once dask.array automatically aligns chunks
  144. data = data.rechunk(var.data.chunks)
  145.  
  146. return type(var)(var.dims, data, var._attrs, fastpath=True)
  147.  
  148. def roll_face(result, **shifts):
  149. """
  150. Return a new Variable with rolled data.
  151. Parameters
  152. ----------
  153. **shifts : keyword arguments of the form {dim: offset}
  154. Integer offset to roll along each of the given dimensions.
  155. Positive offsets roll to the right; negative offsets roll to the
  156. left.
  157. Returns
  158. -------
  159. shifted : Variable
  160. Variable with the same dimensions and attributes but rolled data.
  161. """
  162. for dim, count in shifts.items():
  163. result = _roll_one_dim_face(result, dim, count)
  164. return result
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement