Esempio n. 1
0
 def read_process_data (file_path, var_name, grid, mask_option='3d', gtype='t', lev_option=None, ismr=False, psi=False):
     data = read_netcdf(file_path, var_name)
     if mask_option == '3d':
         data = mask_3d(data, grid, gtype=gtype, time_dependent=True)
     elif mask_option == 'except_ice':
         data = mask_except_ice(data, grid, gtype=gtype, time_dependent=True)
     elif mask_option == 'land':
         data = mask_land(data, grid, gtype=gtype, time_dependent=True)
     elif mask_option == 'land_ice':
         data = mask_land_ice(data, grid, gtype=gtype, time_dependent=True)
     else:
         print 'Error (read_process_data): invalid mask_option ' + mask_option
         sys.exit()
     if lev_option is not None:
         if lev_option == 'top':
             data = select_top(data)
         elif lev_option == 'bottom':
             data = select_bottom(data)
         else:
             print 'Error (read_process_data): invalid lev_option ' + lev_option
             sys.exit()
     if ismr:
         data = convert_ismr(data)
     if psi:
         data = np.sum(data, axis=-3)*1e-6
     return data
Esempio n. 2
0
def plot_topo(var,
              grid,
              vmin=None,
              vmax=None,
              zoom_fris=False,
              xmin=None,
              xmax=None,
              ymin=None,
              ymax=None,
              fig_name=None):

    if not isinstance(grid, Grid):
        # This is the path to the NetCDF grid file, not a Grid object
        # Make a grid object from it
        grid = Grid(grid)

    if var == 'bathy':
        data = abs(mask_land(grid.bathy, grid))
        title = 'Bathymetry (m)'
    elif var == 'zice':
        data = abs(mask_except_zice(grid.zice, grid))
        title = 'Ice shelf draft (m)'
    elif var == 'wct':
        data = abs(mask_land(grid.wct, grid))
        title = 'Water column thickness (m)'

    latlon_plot(data,
                grid,
                vmin=vmin,
                vmax=vmax,
                zoom_fris=zoom_fris,
                xmin=xmin,
                xmax=xmax,
                ymin=ymin,
                ymax=ymax,
                title=title,
                fig_name=fig_name)
Esempio n. 3
0
def interp_grid(data,
                grid,
                gtype_in,
                gtype_out,
                time_dependent=False,
                mask=True,
                mask_shelf=False,
                mask_with_zeros=False,
                periodic=False):

    depth_dependent = is_depth_dependent(data, time_dependent=time_dependent)
    # Make sure we're not trying to mask the ice shelf from a depth-dependent field
    if mask_shelf and depth_dependent:
        print "Error (interp_grid): can't set mask_shelf=True for a depth-dependent field."
        sys.exit()

    if mask and gtype_in in ['u', 'v', 'psi', 'w']:
        # Fill the mask with zeros (okay because no-slip boundary condition)
        data_tmp = np.copy(data)
        data_tmp[data.mask] = 0.0
    else:
        # Tracer land mask is the least restrictive, so it doesn't matter what the masked values are - they will definitely get re-masked at the end.
        data_tmp = data

    # Interpolate
    data_interp = np.empty(data_tmp.shape)
    if gtype_in == 'u' and gtype_out == 't':
        # Midpoints in the x direction
        data_interp[..., :-1] = 0.5 * (data_tmp[..., :-1] + data_tmp[..., 1:])
        # Extend/wrap the easternmost column
        if periodic:
            data_interp[..., -1] = data_interp[..., 0]
        else:
            data_interp[..., -1] = data_tmp[..., -1]
    elif gtype_in == 'v' and gtype_out == 't':
        # Midpoints in the y direction
        data_interp[..., :-1, :] = 0.5 * (data_tmp[..., :-1, :] +
                                          data_tmp[..., 1:, :])
        # Extend the northernmost row
        data_interp[..., -1, :] = data_tmp[..., -1, :]
    elif gtype_in == 't' and gtype_out == 'u':
        # Midpoints in the x direction
        data_interp[..., 1:] = 0.5 * (data_tmp[..., :-1] + data_tmp[..., 1:])
        # Extend/wrap the westernmost column
        if periodic:
            data_interp[..., 0] = data_interp[..., -1]
        else:
            data_interp[..., 0] = data_tmp[..., 0]
    elif gtype_in == 't' and gtype_out == 'v':
        # Midpoints in the y direction
        data_interp[..., 1:, :] = 0.5 * (data_tmp[..., :-1, :] +
                                         data_tmp[..., :-1, :])
        # Extend the southernmost row
        data_interp[..., 0, :] = data_tmp[..., 0, :]
    else:
        print 'Error (interp_grid): interpolation from the ' + gtype_in + '-grid to the ' + gtype_out + '-grid is not yet supported'
        sys.exit()

    if mask:
        # Now apply the mask
        if depth_dependent:
            data_interp = mask_3d(data_interp,
                                  grid,
                                  gtype=gtype_out,
                                  time_dependent=time_dependent)
        else:
            if mask_shelf:
                data_interp = mask_land_ice(data_interp,
                                            grid,
                                            gtype=gtype_out,
                                            time_dependent=time_dependent)
            else:
                data_interp = mask_land(data_interp,
                                        grid,
                                        gtype=gtype_out,
                                        time_dependent=time_dependent)

        if mask_with_zeros:
            # Remove mask and fill with zeros
            data_interp[data_interp.mask] = 0
            data_interp = data_interp.data

    return data_interp
Esempio n. 4
0
def balance_obcs (grid_path, option='balance', obcs_file_w_u=None, obcs_file_e_u=None, obcs_file_s_v=None, obcs_file_n_v=None, d_eta=None, d_t=None, max_deta_dt=0.5, prec=32):

    if option == 'correct' and (d_eta is None or d_t is None):
        print 'Error (balance_obcs): must set d_eta and d_t for option="correct"'
        sys.exit()
    
    print 'Building grid'
    grid = Grid(grid_path)

    # Calculate integrands of area, scaled by hFacC
    # Note that dx and dy are only available on western and southern edges of cells respectively; for the eastern and northern boundary, will just have to use 1 cell in. Not perfect, but this correction wouldn't perfectly conserve anyway.
    # Area of western face = dy*dz*hfac
    dA_w = xy_to_xyz(grid.dy_w, grid)*z_to_xyz(grid.dz, grid)*grid.hfac
    # Area of southern face = dx*dz*hfac
    dA_s = xy_to_xyz(grid.dx_s, grid)*z_to_xyz(grid.dz, grid)*grid.hfac

    # Now extract the area array at each boundary, and wrap up into a list for easy iteration later
    dA_bdry = [dA_w[:,:,0], dA_w[:,:,-1], dA_s[:,0,:], dA_s[:,-1,:]]
    # Some more lists:
    bdry_key = ['W', 'E', 'S', 'N']
    files = [obcs_file_w_u, obcs_file_e_u, obcs_file_s_v, obcs_file_n_v]
    dimensions = ['yzt', 'yzt', 'xzt', 'xzt']
    sign = [1, -1, 1, -1]  # Multiply velocity variable by this to get incoming transport
    # Initialise number of timesteps
    num_time = None

    # Integrate the total area of ocean cells on boundaries
    total_area = 0
    for i in range(len(files)):
        if files[i] is not None:
            print 'Calculating area of ' + bdry_key[i] + ' boundary'
            total_area += np.sum(dA_bdry[i])

    # Calculate the net transport into the domain
    if option in ['balance', 'dampen']:
        # Transport based on OBCS normal velocities
        if option == 'balance':
            net_transport = 0
        elif option == 'dampen':
            net_transport = None
        for i in range(len(files)):
            if files[i] is not None:
                print 'Processing ' + bdry_key[i] + ' boundary from ' + files[i]
                # Read data
                vel = read_binary(files[i], [grid.nx, grid.ny, grid.nz], dimensions[i], prec=prec)
                if num_time is None:
                    # Find number of time indices
                    num_time = vel.shape[0]
                elif num_time != vel.shape[0]:
                    print 'Error (balance_obcs): inconsistent number of time indices between OBCS files'
                    sys.exit()
                if option == 'dampen' and net_transport is None:
                    # Initialise transport per month
                    net_transport = np.zeros(num_time)
                if option == 'balance':
                    # Time-average velocity (this is equivalent to calculating the transport at each month and then time-averaging at the end - it's all just sums)
                    vel = np.mean(vel, axis=0)
                    # Integrate net transport through this boundary into the domain, and add to global sum
                    net_transport += np.sum(sign[i]*vel*dA_bdry[i])
                elif option == 'dampen':
                    # Integrate net transport at each month
                    for t in range(num_time):
                        net_transport[t] += np.sum(sign[i]*vel[t,:]*dA_bdry[i])
    elif option == 'correct':
        # Transport based on simulated changes in sea surface height
        # Need area of sea surface
        dA_sfc = np.sum(grid.dA*np.invert(grid.land_mask).astype(float))
        # Calculate transport in m^3/s
        net_transport = d_eta*dA_sfc/(d_t*sec_per_year)        

    # Inner function to nicely print the net transport to the user
    def print_net_transport (transport):
        if transport < 0:
            direction = 'out of the domain'
        else:
            direction = 'into the domain'
        print 'Net transport is ' + str(abs(transport*1e-6)) + ' Sv ' + direction

    if option == 'dampen':
        for t in range(num_time):
            print 'Month ' + str(t+1)
            print_net_transport(net_transport[t])
    else:
        print_net_transport(net_transport)

    if option == 'dampen':
        # Calculate the acceptable maximum absolute transport
        # First need total area of sea surface (including cavities) in domain
        surface_area = np.sum(mask_land(grid.dA, grid))
        max_transport = max_deta_dt*surface_area/(sec_per_day*30)
        print 'Maximum allowable transport is ' + str(max_transport*1e-6) + ' Sv'
        if np.max(np.abs(net_transport)) <= max_transport:
            print 'OBCS satisfy this; nothing to do'
            return
        # Work out by what factor to dampen the transports
        scale_factor = max_transport/np.max(np.abs(net_transport))
        print 'Will scale transports by ' + str(scale_factor)
        # Calculate corresponding velocity correction at each month
        correction = np.zeros(num_time)
        for t in range(num_time):
            correction[t] = (scale_factor-1)*net_transport[t]/total_area
            print 'Month ' + str(t+1) + ': will apply correction of ' + str(correction[t]) + ' m/s to normal velocity at each boundary'
    else:
        # Calculate single correction in m/s
        correction = -1*net_transport/total_area
        print 'Will apply correction of ' + str(correction) + ' m/s to normal velocity at each boundary'

    # Now apply the correction
    for i in range(len(files)):
        if files[i] is not None:
            print 'Correcting ' + files[i]
            # Read all the data again
            vel = read_binary(files[i], [grid.nx, grid.ny, grid.nz], dimensions[i], prec=prec)
            # Apply the correction
            if option == 'dampen':
                for t in range(num_time):
                    vel[t,:] += sign[i]*correction[t]
            else:
                vel += sign[i]*correction
            # Overwrite the file
            write_binary(vel, files[i], prec=prec)

    if option in ['balance', 'dampen']:
        # Recalculate the transport to make sure it worked
        if option == 'balance':
            net_transport_new = 0
        elif option == 'dampen':
            net_transport_new = np.zeros(num_time)
        for i in range(len(files)):
            if files[i] is not None:
                vel = read_binary(files[i], [grid.nx, grid.ny, grid.nz], dimensions[i], prec=prec)
                if option == 'balance':
                    vel = np.mean(vel, axis=0)
                    net_transport_new += np.sum(sign[i]*vel*dA_bdry[i])
                elif option == 'dampen':
                    for t in range(num_time):
                        net_transport_new[t] += np.sum(sign[i]*vel[t,:]*dA_bdry[i])
        if option == 'balance':
            print_net_transport(net_transport_new)
        elif option == 'dampen':
            for t in range(num_time):
                print 'Month ' + str(t+1)
                print_net_transport(net_transport_new[t])