def normal_current(self, U, V): """Sample normal component of velocity field""" # Interpolerer foreløpig langs s-flater # Offset for interpolation from U and V grid deltaU = -0.5 + self.grid.i0 - self.grid.i0_u deltaV = -0.5 + self.grid.j0 - self.grid.j0_v Usec = np.zeros((self.N, self.nseg)) Vsec = np.zeros((self.N, self.nseg)) for k in range(self.N): Usec[k, :] = sample2D(U[k, :, :], self.Xm+deltaU, self.Ym) Vsec[k, :] = sample2D(V[k, :, :], self.Xm, self.Ym+deltaV) return self.nx*Usec + self.ny*Vsec
def test_masked(self): """Interpolates correctly in the presence of mask""" A = np.array([[1, 1, 1, 1], # j=0 [0, 1, 1, 1], # j=1 [0, 1, 0, 0], # j=2 [1, 1, 0, 0]]) # j=3 M = A # sea point outside halo x, y = 1.8, 0.8 self.assertEqual(sample2D(A, x, y), 1) self.assertEqual(sample2D(A, x, y, mask=M), 1) # sea point in halo x, y = 1.8, 1.3 self.assertAlmostEqual(sample2D(A, x, y), 1-0.8*0.3) self.assertEqual(sample2D(A, x, y, mask=M), 1) # land point in halo x, y = 1.8, 1.8 b_unmask = sample2D(A, x, y, undef_value=np.nan) self.assertAlmostEqual(b_unmask, 1-0.8*0.8) b_mask = sample2D(A, x, y, mask=M, undef_value=np.nan) self.assertEqual(b_mask, 1) # land point outside halo x, y = 2.8, 2.4 b_unmask = sample2D(A, x, y, undef_value=np.nan) self.assertEqual(b_unmask, 0) b_mask = sample2D(A, x, y, mask=M, undef_value=np.nan) self.assertTrue(np.isnan(b_mask))
def __init__(self, grid, X, Y): self.grid = grid # Vertices, in subgrid coordinates self.X = X - grid.i0 self.Y = Y - grid.j0 # Nodes self.Xm = 0.5*(self.X[:-1] + self.X[1:]) self.Ym = 0.5*(self.Y[:-1] + self.Y[1:]) # Section size self.nseg = len(self.Xm) # Number of segments = Number of nodes self.N = len(self.grid.Cs_r) # Compatible with both SGrid and grdClass try: self.h = sample2D(self.grid.h, self.Xm, self.Ym, mask=self.grid.mask_rho, undef_value=0.0) except AttributeError: self.h = sample2D(self.grid.depth, self.Xm, self.Ym) pm = sample2D(self.grid.pm, self.Xm, self.Ym) pn = sample2D(self.grid.pn, self.Xm, self.Ym) # Unit normal vector (nx, ny) # Sjekk om dette er korrekt hvis pm og pn er ulike dX = (X[1:]-X[:-1]) / pm dY = (Y[1:]-Y[:-1]) / pn # Length of segments # Kan kanskje forbedres med sfærisk avstand self.dS = np.sqrt(dX*dX+dY*dY) # Cumulative distance (at vertices)s self.S = np.concatenate(([0], np.add.accumulate(self.dS))) nx, ny = dY, -dX norm = np.sqrt(nx*nx + ny*ny) self.nx, self.ny = nx/norm, ny/norm # Vertical structure self.z_r = sdepth(self.h, self.grid.hc, self.grid.Cs_r, stagger='rho', Vtransform=self.grid.Vtransform) self.z_w = sdepth(self.h, self.grid.hc, self.grid.Cs_w, stagger='w', Vtransform=self.grid.Vtransform) self.dZ = self.z_w[1:, :]-self.z_w[:-1, :] self.Area = self.dZ * self.dS
def test_outside(self): """Handle outside values correctly""" imax, jmax = 10, 7 A = np.zeros((jmax, imax)) x, y = 9.2, 4 self.assertRaises(ValueError, sample2D, A, x, y) b = sample2D(A, x, y, outside_value=np.nan) self.assertTrue(np.isnan(b))
def test_nodes(self): """Exact at nodes""" f = lambda x, y : x**2 + y**2 imax, jmax = 10, 7 JJ, II = np.meshgrid(np.arange(jmax), np.arange(imax)) A = f(JJ, II) i, j = 4, 3 B = sample2D(A, i, j) self.assertEqual(B, A[j,i])
def sample3D(self, F): """Sample a 3D field in rho-points with shape (N,Mp,Lp)""" # Not masked ?? Fsec = np.zeros((self.N, self.L)) for k in range(self.N): Fsec[k, :] = sample2D(F[k, :, :], self.X, self.Y, mask=self.grid.mask_rho) return Fsec
def test_bilinear(self): """Exact for bilinear function""" f = lambda x, y: 3.0 + 2*x + 1.4*y + 0.2*x*y imax, jmax = 10, 7 JJ, II = np.meshgrid(np.arange(jmax), np.arange(imax)) A = f(JJ, II) X, Y = 5.2, 4.1 Z = f(X, Y) B = sample2D(A, X, Y) self.assertEqual(B, Z)
def __init__(self, grid, X, Y): self.grid = grid # Vertices, in subgrid coordinates self.X = X self.Y = Y # Section size self.L = len(self.X) # Number of nodes self.N = len(self.grid.Cs_r) # Topography self.h = sample2D(self.grid.h, self.X, self.Y, mask=self.grid.mask_rho, undef_value=1.0) # Metric pm = sample2D(self.grid.pm, self.X, self.Y) pn = sample2D(self.grid.pn, self.X, self.Y) dX = 2 * (X[1:]-X[:-1]) / (pm[:-1] + pm[1:]) # unit = meter dY = 2 * (Y[1:]-Y[:-1]) / (pn[:-1] + pn[1:]) # Assume spacing is close enough to approximate distance self.dS = np.sqrt(dX*dX+dY*dY) # Cumulative distance self.S = np.concatenate(([0], np.add.accumulate(self.dS))) # Weights for trapez integration (linear interpolation) self.W = 0.5*np.concatenate(([self.dS[0]], self.dS[:-1] + self.dS[1:], [self.dS[-1]])) # nx, ny = dY, -dX # norm = np.sqrt(nx*nx + ny*ny) # self.nx, self.ny = nx/norm, ny/norm # Vertical structure self.z_r = sdepth(self.h, self.grid.hc, self.grid.Cs_r, stagger='rho', Vtransform=self.grid.Vtransform) self.z_w = sdepth(self.h, self.grid.hc, self.grid.Cs_w, stagger='w', Vtransform=self.grid.Vtransform) self.dZ = self.z_w[1:, :]-self.z_w[:-1, :] self.Area = self.dZ * self.W
def sample3D(self, F): """Sample a 3D field in rho-points with shape (N,Mp,Lp)""" # Interpolerer foreløpig langs s-flater # Sikkert OK for plotting, Godt nok for flux-beregning? Fsec = np.zeros((self.grid.N, self.nseg)) for k in range(self.grid.N): Fsec[k, :] = sample2D(F[k, :, :], self.Xm, self.Ym, mask=self.grid.mask_rho) Fsec = np.ma.masked_where(self.extend_vertically(self.h) == 0, Fsec) return Fsec
def test_arguments(self): # Make a grid for testing imax, jmax = 10, 7 A = np.zeros((jmax, imax)) # Scalars X, Y = 2.7, 3.5 self.assertTrue(np.isscalar(sample2D(A, X, Y))) # Conformal arrays X = np.array([1,2]) Y = np.array([3,4]) B = sample2D(A, X, Y) self.assertEqual(B.shape, (2,)) # Conformal arrays 2 X = np.arange(6).reshape(2,3) Y = np.array([1,2]).reshape(2,1) B = sample2D(A, X, Y) self.assertEqual(B.shape, (2,3)) # Scalar and array X = 4 Y = np.array([1,2]) B = sample2D(A, X, Y) self.assertEqual(B.shape, (2,)) # Nonconformal arrays X = np.arange(6).reshape(2,3) Y = np.array([1,2]) self.assertRaises(ValueError, sample2D, A, X, Y) # 1D sequences such as lists X = [1.1, 2.2, 3.3] Y = [3.5] B = sample2D(A, X, Y) self.assertEqual(B.shape, (3,))
def sample2D(self, F): return sample2D(F, self.Xm, self.Ym)
def sample2D(self, F): """Sample a horizontal field at rho poins with shape (Mp, Lp)""" return sample2D(F, self.X, self.Y, mask=self.grid.mask_rho)
def xy2ll(self, x, y): return (sample2D(self.lon_rho, x-self.i0, y-self.j0), sample2D(self.lat_rho, x-self.i0, y-self.j0))
def test_boundary(self): """Works correctly close to boundary""" imax, jmax = 10, 7 A = np.ones((jmax, imax)) x, y = 0.2, 5.9 self.assertEqual(sample2D(A, x, y), 1)