Ejemplo n.º 1
0
def gyre_sim_semi_lag(t0, timelength, dt, dx, dy, 
                      f0, B, g, gamma, rho, H, tau0, L, 
                      plot, plot_timestep):
    'Solve SWEs using semi-Lagrangian method on Arakawa-C grid'
    # Set up fields.
    nx = L / dx + 1
    ny = nx

    x = np.linspace(0, L, nx)
    y = np.linspace(0, L, ny)

    X, Y = np.meshgrid(x, y, indexing='ij')

    eta0 = np.zeros_like(X)
    u0 = np.zeros((X.shape[0] + 1, X.shape[1]))
    v0 = np.zeros((X.shape[0], X.shape[1] + 1))

    eta = eta0
    u = u0
    v = v0
    nt = timelength / dt
    times = np.linspace(t0, t0 + timelength, nt + 1)
    dt = times[1] - times[0]
    dx = X[1, 0] - X[0, 0]
    dy = Y[0, 1] - Y[0, 0]

    x = X[:, 0]
    y = Y[0, :]
    x_u = np.linspace(X[0, 0] - dx/2, X[-1, 0] + dx/2, X.shape[0] + 1)
    y_u = np.linspace(Y[0, 0], Y[0, -1], Y.shape[1])
    X_u, Y_u = np.meshgrid(x_u, y_u, indexing='ij')

    x_v = np.linspace(X[0, 0], X[-1, 0], X.shape[0])
    y_v = np.linspace(Y[0, 0] - dy/2, Y[0, -1] + dy/2, Y.shape[1] + 1)
    X_v, Y_v = np.meshgrid(x_v, y_v, indexing='ij')

    print('dx={}, dy={}, dt={}'.format(dx, dy, dt))
    c = calc_c(g, H, dt, dx, dy)
    print('c={}'.format(c))
    if c > 1.0:
        print('Warning, running with c={} (>1.0)'.format(c))
    tau_x = - tau0 * np.cos(np.pi * Y_u / L)
    tau_y = np.zeros_like(Y_v)

    v_u = np.zeros_like(u0)
    u_v = np.zeros_like(v0)

    u_grid = (u[:-1, :] + u[1:, :]) / 2
    v_grid = (v[:, :-1] + v[:, 1:]) / 2
    Es = [energy(eta, u_grid, v_grid, rho, H, g, x, y)]

    u_prev = u.copy()
    v_prev = v.copy()
    for i, t in enumerate(times[1::2]):

        for j in range(2):
	    # Ensure 2nd order accuracy by calc'ing u, v at 1/2 timestep.
	    # Work out u, v, at n+1/2.
	    u0p5 = 1.5 * u - 0.5 * u_prev
	    v0p5 = 1.5 * v - 0.5 * v_prev

	    u_prev = u.copy()
	    v_prev = v.copy()

	    # Calc intermediate x, y.
	    u_grid = (u[:-1, :] + u[1:, :]) / 2
	    v_grid = (v[:, :-1] + v[:, 1:]) / 2
	    Xi = X - u_grid * dt/2
	    Yi = Y - v_grid * dt/2

	    v_u[1:-1, :] = (v[:-1, :-1] + v[1:, :-1] +
			    v[:-1, 1:] + v[1:, 1:]) / 4
	    u_v[:, 1:-1] = (u[:-1, :-1] + u[1:, :-1] +
			    u[:-1, 1:] + u[1:, 1:]) / 4
	    Xi_u = X_u - u * dt/2
	    Yi_u = Y_u - v_u * dt/2

	    Xi_v = X_v - u_v * dt/2
	    Yi_v = Y_v - v * dt/2

	    # Work out interp'd u, v at n+1/2
	    # Interp. handles values outside domain naturally
	    ui0p5 = interp.RectBivariateSpline(x_u, y_u, u0p5).ev(Xi, Yi)
	    vi0p5 = interp.RectBivariateSpline(x_v, y_v, v0p5).ev(Xi, Yi)

	    ui0p5_u = interp.RectBivariateSpline(x_u, y_u, u0p5).ev(Xi_u, Yi_u)
	    vi0p5_u = interp.RectBivariateSpline(x_v, y_v, v0p5).ev(Xi_u, Yi_u)

	    ui0p5_v = interp.RectBivariateSpline(x_u, y_u, u0p5).ev(Xi_v, Yi_v)
	    vi0p5_v = interp.RectBivariateSpline(x_v, y_v, v0p5).ev(Xi_v, Yi_v)

	    # Calc x dep at n
	    Xd = X - ui0p5 * dt
	    Yd = Y - vi0p5 * dt

	    Xd_u = X_u - ui0p5_u * dt
	    Yd_u = Y_u - vi0p5_u * dt

	    Xd_v = X_v - ui0p5_v * dt
	    Yd_v = Y_v - vi0p5_v * dt

	    # Calc u, v, eta at dep points.
	    u_tilde = interp.RectBivariateSpline(x_u, y_u, u).ev(Xd_u, Yd_u)
	    v_tilde = interp.RectBivariateSpline(x_v, y_v, v).ev(Xd_v, Yd_v)
	    eta_tilde = interp.RectBivariateSpline(x, y, eta).ev(Xd, Yd)
	    
	    dudx = (u[1:, :] - u[:-1, :]) / dx
	    dvdy = (v[:, 1:] - v[:, :-1]) / dy
	    dudx_tilde = interp.RectBivariateSpline(x, y, dudx).ev(Xd, Yd)
	    dvdy_tilde = interp.RectBivariateSpline(x, y, dvdy).ev(Xd, Yd)

	    eta = eta_tilde - H * dt * (dudx_tilde + dvdy_tilde)

	    # Update u, v, eta (switching u, v calc.).
            if (i + j) % 2 == 0:
                v_u[1:-1, :] = (v_tilde[:-1, :-1] + v_tilde[1:, :-1] +
				v_tilde[:-1, 1:] + v_tilde[1:, 1:]) / 4
                deta_dx_u = (eta[1:, :] - eta[:-1, :]) / dx

		u[1:-1, :] = (+ u_tilde[1:-1, :]
                              + (f0 + B * Y_u[1:-1, :]) * dt * v_u[1:-1, :] 
                              - g * dt * deta_dx_u
			      - gamma * dt * u_tilde[1:-1, :]
                              + tau_x[1:-1, :] * dt / (rho * H))
            else:
                u_v[:, 1:-1] = (u_tilde[:-1, :-1] + u_tilde[1:, :-1] +
				u_tilde[:-1, 1:] + u_tilde[1:, 1:]) / 4
                deta_dy_v = (eta[:, 1:] - eta[:, :-1]) / dy

		v[:, 1:-1] = (+ v_tilde[:, 1:-1]
                              - (f0 + B * Y_v[:, 1:-1]) * dt * u_v[:, 1:-1] 
                              - g * dt * deta_dy_v
			      - gamma * dt * v_tilde[:, 1:-1]
                              + tau_y[:, 1:-1] * dt / (rho * H))

            # Kinematic BCs: no normal flow.
            u[0, :] = 0
            u[-1, :] = 0
            v[:, 0] = 0
            v[:, -1] = 0

	    u_grid = (u[:-1, :] + u[1:, :]) / 2
	    v_grid = (v[:, :-1] + v[:, 1:]) / 2
	    Es.append(energy(eta, u_grid, v_grid, rho, H, g, x, y))

        if i % 100 == 0:
            print('{}: energy={}'.format(t / 86400, Es[-1]))
            if plot:
                plot_timestep(X, Y, u_grid, v_grid)

    return X, Y, times, eta, u, v, Es
Ejemplo n.º 2
0
def gyre_sim(t0, timelength, dt, dx, dy, 
             f0, B, g, gamma, rho, H, tau0, L, 
             plot, plot_timestep):
    'Solve SWEs using Eulerian method on Arakawa-C grid'
    # Set up fields.
    nx = L / dx + 1
    ny = nx

    x = np.linspace(0, L, nx)
    y = np.linspace(0, L, ny)

    X, Y = np.meshgrid(x, y, indexing='ij')

    eta0 = np.zeros_like(X)
    u0 = np.zeros((X.shape[0] + 1, X.shape[1]))
    v0 = np.zeros((X.shape[0], X.shape[1] + 1))

    eta = eta0
    u = u0
    v = v0
    nt = timelength / dt
    times = np.linspace(t0, t0 + timelength, nt + 1)
    x, y = X[:, 0], Y[0, :]
    dx = X[1, 0] - X[0, 0]
    dy = Y[0, 1] - Y[0, 0]
    print('dx={}, dy={}, dt={}'.format(dx, dy, dt))
    c_x, c_y = np.sqrt(g * H) * dt/dx, np.sqrt(g * H) * dt/dy
    c = np.sqrt(c_x**2 + c_y**2)
    print('c={}'.format(c))
    if c > 1.0:
        print('Warning, running with c={} (>1.0)'.format(c))
    tau_x = - tau0 * np.cos(np.pi * Y / L)
    tau_y = np.zeros_like(Y)

    v_u = np.zeros_like(u0)
    u_v = np.zeros_like(v0)

    u_grid = (u[:-1, :] + u[1:, :]) / 2
    v_grid = (v[:, :-1] + v[:, 1:]) / 2
    Es = [energy(eta, u_grid, v_grid, rho, H, g, x, y)]

    for i, t in enumerate(times[1::2]):
        eta = eta - H * dt * ((u[1:, :] - u[:-1, :]) / dx + 
                              (v[:, 1:] - v[:, :-1]) / dy)
        for j in range(2):
            if (i + j) % 2 == 0:
                v_u[1:-1, :] = (v[:-1, :-1] + v[1:, :-1] +
                                v[:-1, 1:]  + v[1:, 1:]) / 4
                u[1:-1, :] = (+ u[1:-1, :] 
                              + (f0 + B * (Y[:-1, :] + Y[1:, :]) / 2) * dt * v_u[1:-1, :] 
                              - g * dt * (eta[1:, :] - eta[:-1, :]) / dx 
                              - gamma * dt * u[1:-1, :] 
                              + (tau_x[:-1, :] + tau_x[1:, :]) * dt / ( 2 * rho * H))
            else:
                u_v[:, 1:-1] = (u[:-1, :-1] + u[1:, :-1] +
                                u[:-1, 1:]  + u[1:, 1:]) / 4
                v[:, 1:-1] = (+ v[:, 1:-1] 
                              - (f0 + B * (Y[:, :-1] + Y[:, 1:]) / 2) * dt * u_v[:, 1:-1] 
                              - g * dt * (eta[:, 1:] - eta[:, :-1]) / dy 
                              - gamma * dt * v[:, 1:-1] 
                              + (tau_y[:, :-1] + tau_y[:, 1:]) * dt / (2 * rho * H))

            # Kinematic BCs: no normal flow.
            u[0, :] = 0
            u[-1, :] = 0
            v[:, 0] = 0
            v[:, -1] = 0

	    u_grid = (u[:-1, :] + u[1:, :]) / 2
	    v_grid = (v[:, :-1] + v[:, 1:]) / 2
	    Es.append(energy(eta, u_grid, v_grid, rho, H, g, x, y))

        if i % 1000 == 0:
            print('{}: energy={}'.format(t / 86400, Es[-1]))
            if plot:
                plot_timestep(X, Y, u_grid, v_grid)

    return X, Y, times, eta, u, v, Es