Esempio n. 1
0
def circumpolar_cice_plot(file_path,
                          var_name,
                          tstep,
                          colour_bounds=None,
                          save=False,
                          fig_name=None):

    deg2rad = pi / 180
    month_names = [
        'January', 'February', 'March', 'April', 'May', 'June', 'July',
        'August', 'September', 'October', 'November', 'December'
    ]

    # Read the variable
    id = Dataset(file_path, 'r')
    data_tmp = id.variables[var_name][tstep - 1, :-15, :]
    if var_name == 'aice':
        units = 'fraction'
    else:
        units = id.variables[var_name].units

    # Check for vector variables that need to be rotated
    if var_name in [
            'uvel', 'vvel', 'uatm', 'vatm', 'uocn', 'vocn', 'strairx',
            'strairy', 'strtltx', 'strtlty', 'strcorx', 'strcory', 'strocnx',
            'strocny', 'strintx', 'strinty'
    ]:
        angle = id.variables['ANGLE'][:-15, :]
        if var_name in [
                'uvel', 'uatm', 'uocn', 'strairx', 'strtltx', 'strcorx',
                'strocnx', 'strintx'
        ]:
            # u-variable
            u_data = data_tmp[:, :]
            if var_name[0] == 'u':
                v_data = id.variables[var_name.replace('u', 'v')][tstep -
                                                                  1, :-15, :]
            else:
                v_data = id.variables[var_name.replace('x', 'y')][tstep -
                                                                  1, :-15, :]
            u_data_lonlat, v_data_lonlat = rotate_vector_cice(
                u_data, v_data, angle)
            data_tmp = u_data_lonlat
        elif var_name in [
                'vvel', 'vatm', 'vocn', 'strairy', 'strtlty', 'strcory',
                'strocny', 'strinty'
        ]:
            # v-variable
            v_data = data_tmp[:, :]
            if var_name[0] == 'v':
                u_data = id.variables[var_name.replace('v', 'u',
                                                       1)][tstep - 1, :-15, :]
            else:
                u_data = id.variables[var_name.replace('y', 'x')][tstep -
                                                                  1, :-15, :]
            u_data_lonlat, v_data_lonlat = rotate_vector_cice(
                u_data, v_data, angle)
            data_tmp = v_data_lonlat

    # Figure out which grid we're on
    grid_string = id.variables[var_name].coordinates
    if grid_string.startswith('ULON'):
        grid_name = 'u'
        lon_name = 'ULON'
        lat_name = 'ULAT'
    elif grid_string.startswith('TLON'):
        grid_name = 't'
        lon_name = 'TLON'
        lat_name = 'TLAT'
    else:
        print 'Grid type ' + grid_string + ' not supported'
        id.close()
        return

    # Read the correct lat and lon for this grid
    lon_tmp = id.variables[lon_name][:-15, :]
    lat_tmp = id.variables[lat_name][:-15, :]
    time_id = id.variables['time']
    time = num2date(time_id[tstep - 1],
                    units=time_id.units,
                    calendar=time_id.calendar.lower())
    id.close()

    # Wrap the periodic boundary by 1 cell
    lon = ma.empty([size(lon_tmp, 0), size(lon_tmp, 1) + 1])
    lat = ma.empty([size(lat_tmp, 0), size(lat_tmp, 1) + 1])
    data = ma.empty([size(data_tmp, 0), size(data_tmp, 1) + 1])
    lon[:, :-1] = lon_tmp
    lon[:, -1] = lon_tmp[:, 0]
    lat[:, :-1] = lat_tmp
    lat[:, -1] = lat_tmp[:, 0]
    data[:, :-1] = data_tmp
    data[:, -1] = data_tmp[:, 0]

    # Convert to spherical coordinates
    x = -(lat + 90) * cos(lon * deg2rad + pi / 2)
    y = (lat + 90) * sin(lon * deg2rad + pi / 2)

    if colour_bounds is not None:
        # User has set bounds on colour scale
        lev = linspace(colour_bounds[0], colour_bounds[1], num=40)
        if colour_bounds[0] == -colour_bounds[1]:
            # Bounds are centered on zero, so choose a blue-to-red colourmap
            # centered on yellow
            colour_map = 'RdYlBu_r'
        else:
            colour_map = 'jet'
    else:
        # Determine bounds automatically
        if var_name in [
                'uvel', 'vvel', 'uatm', 'vatm', 'uocn', 'vocn', 'fresh_ai',
                'fsalt_ai', 'fhocn_ai', 'strairx', 'strairy', 'strtltx',
                'strtlty', 'strcorx', 'strcory', 'strocnx', 'strocny',
                'strintx', 'strinty'
        ]:
            # Center levels on 0 for certain variables, with a blue-to-red
            # colourmap
            max_val = amax(abs(data))
            lev = linspace(-max_val, max_val, num=40)
            colour_map = 'RdYlBu_r'
        else:
            lev = linspace(amin(data), amax(data), num=40)
            colour_map = 'jet'

    # Plot
    fig = figure(figsize=(16, 12))
    fig.add_subplot(1, 1, 1, aspect='equal')
    contourf(x, y, data, lev, cmap=colour_map, extend='both')
    cbar = colorbar()
    cbar.ax.tick_params(labelsize=20)
    title(var_name + ' (' + units + ')\n' + str(time.day) + ' ' +
          month_names[time.month - 1] + ' ' + str(time.year),
          fontsize=24)
    #title(var_name+' ('+units+')', fontsize=30)
    axis('off')

    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
Esempio n. 2
0
def common_grid(roms_file, cice_file, out_file):

    # Resolution of common grid (degrees, same for lat and lon)
    res = 0.25
    # Northern boundary to interpolate to
    nbdry = -50
    # Radius of the Earth in metres
    r = 6.371e6
    # Degrees to radians conversion factor
    deg2rad = pi / 180.0
    N = 31

    print 'Calculating grids'

    # Make the latitude and longitude arrays for the common grid
    lon_common = arange(-180, 180 + res, res)
    lat_common = arange(-90, nbdry + res, res)
    # Get a 2D version of each to calculate dx and dy in metres
    lon_2d, lat_2d = meshgrid(lon_common, lat_common)
    # dx = r*cos(lat)*dlon where lat and dlon (i.e. res) are in radians
    dx = r * cos(lat_2d * deg2rad) * res * deg2rad
    # dy = r*dlat where dlat (i.e. res) is in radians
    # This is constant so reshape to an array of the right dimensions
    dy = zeros(shape(dx)) + r * res * deg2rad

    # Read the ROMS grid
    id = Dataset(roms_file, 'r')
    # We only need lat and lon on the rho grid
    lon_rho = id.variables['lon_rho'][:, :]
    lat_rho = id.variables['lat_rho'][:, :]
    # Get shape of u and v grids
    u_shape = id.variables['lon_u'].shape
    v_shape = id.variables['lon_v'].shape
    # Read land mask
    mask_roms = id.variables['mask_rho'][:, :]
    # Mask out ice shelves too
    zice = id.variables['zice'][:, :]
    mask_roms[zice != 0] = 0.0
    # Read angle (for rotation of vector components)
    angle_roms = id.variables['angle'][:, :]
    # Get time as an array of Date objects
    time_id = id.variables['ocean_time']
    time = num2date(time_id[:],
                    units=time_id.units,
                    calendar=time_id.calendar.lower())
    id.close()

    # Read the CICE grid
    id = Dataset(cice_file, 'r')
    # We only need lat and lon on the velocity grid
    lon_cice = id.variables['ULON'][:, :]
    lat_cice = id.variables['ULAT'][:, :]
    # Read angle (for rotation of vector components)
    angle_cice = id.variables['ANGLE'][:, :]
    id.close()

    # Make sure longitude is between -180 and 180
    index = lon_rho > 180
    lon_rho[index] = lon_rho[index] - 360
    index = lon_cice > 180
    lon_cice[index] = lon_cice[index] - 360

    print 'Counting months'
    # Assume we start at the beginning of a year
    # Figure out how many complete years have happened since then
    num_full_years = time[-1].year - time[0].year
    if time[-1].month == 12 and time[-1].day in range(29, 31 + 1):
        # We happen to end at the very end of a year
        num_full_years += 1
    else:
        # Count the complete months that have happened this year
        num_extra_months = time[-1].month - 1
        # Don't bother with the hassle of considering cases where we end at
        # the very end of a month. Just ignore the month.
    num_months = 12 * num_full_years + num_extra_months

    print 'Interpolating land mask to new grid'
    mask_common = interp_roms2common(lon_common, lat_common, lon_rho, lat_rho,
                                     mask_roms)
    mask_common[isnan(mask_common)] = 0
    # Cut it off at 1
    mask_common[mask_common < 0.5] = 0
    mask_common[mask_common >= 0.5] = 1

    #    print 'Setting up ' + out_file
    #    id = Dataset(out_file, 'w')
    #    id.createDimension('longitude', size(lon_common))
    #    id.createDimension('latitude', size(lat_common))
    #    id.createDimension('time', None)
    #    id.createVariable('longitude', 'f8', ('longitude'))
    #    id.variables['longitude'].units = 'degrees'
    #    id.variables['longitude'][:] = lon_common
    #    id.createVariable('latitude', 'f8', ('latitude'))
    #    id.variables['latitude'].units = 'degrees'
    #    id.variables['latitude'][:] = lat_common
    #    id.createVariable('time', 'f8', ('time'))
    #    id.variables['time'].units = 'months'
    #    id.createVariable('mask', 'f8', ('latitude', 'longitude'))
    #    id.variables['mask'].units = '1'
    #    id.variables['mask'][:,:] = mask_common
    #    id.createVariable('sst', 'f8', ('time', 'latitude', 'longitude'))
    #    id.variables['sst'].long_name = 'sea surface temperature'
    #    id.variables['sst'].units = 'C'
    #    id.createVariable('sss', 'f8', ('time', 'latitude', 'longitude'))
    #    id.variables['sss'].long_name = 'sea surface salinity'
    #    id.variables['sss'].units = 'psu'
    #    id.createVariable('shflux', 'f8', ('time', 'latitude', 'longitude'))
    #    id.variables['shflux'].long_name = 'surface heat flux into ocean'
    #    id.variables['shflux'].units = 'W/m^2'
    #    id.createVariable('ssflux', 'f8', ('time', 'latitude', 'longitude'))
    #    id.variables['ssflux'].long_name = 'surface virtual salinity flux into ocean'
    #    id.variables['ssflux'].units = 'psu m/s'
    #    id.createVariable('aice', 'f8', ('time', 'latitude', 'longitude'))
    #    id.variables['aice'].long_name = 'sea ice concentration'
    #    id.variables['aice'].units = '1'
    #    id.createVariable('hice', 'f8', ('time', 'latitude', 'longitude'))
    #    id.variables['hice'].long_name = 'sea ice thickness'
    #    id.variables['hice'].units = 'm'
    #    id.createVariable('uocn', 'f8', ('time', 'latitude', 'longitude'))
    #    id.variables['uocn'].long_name = 'ocean surface velocity eastward'
    #    id.variables['uocn'].units = 'm/s'
    #    id.createVariable('vocn', 'f8', ('time', 'latitude', 'longitude'))
    #    id.variables['vocn'].long_name = 'ocean surface velocity northward'
    #    id.variables['vocn'].units = 'm/s'
    #    id.createVariable('uice', 'f8', ('time', 'latitude', 'longitude'))
    #    id.variables['uice'].long_name = 'sea ice velocity eastward'
    #    id.variables['uice'].units = 'm/s'
    #    id.createVariable('vice', 'f8', ('time', 'latitude', 'longitude'))
    #    id.variables['vice'].long_name = 'sea ice velocity northward'
    #    id.variables['vice'].units = 'm/s'
    #    id.createVariable('sustr', 'f8', ('time', 'latitude', 'longitude'))
    #    id.variables['sustr'].long_name = 'zonal surface stress'
    #    id.variables['sustr'].units = 'N/m^2'
    #    id.createVariable('svstr', 'f8', ('time', 'latitude', 'longitude'))
    #    id.variables['svstr'].long_name = 'meridional surface stress'
    #    id.variables['svstr'].units = 'N/m^2'
    #    id.createVariable('curl_str', 'f8', ('time', 'latitude', 'longitude'))
    #    id.variables['curl_str'].long_name = 'curl of surface stress'
    #    id.variables['curl_str'].units = 'N/m^3'
    #    id.close()

    # Loop over months
    for month in range(18, num_months):
        print 'Processing month ' + str(month + 1) + ' of ' + str(num_months)
        id = Dataset(out_file, 'a')
        # Write time value for this month
        id.variables['time'][month] = month + 1

        print '...sea surface temperature'
        # Get monthly average of 3D variable
        temp_roms = monthly_avg_roms(
            roms_file,
            'temp',
            [N, size(lon_rho, 0), size(lon_rho, 1)],
            month % 12,
            instance=month / 12 + 1)
        # Select surface layer
        sst_roms = temp_roms[-1, :, :]
        # Interpolate to common grid
        sst_common = interp_roms2common(lon_common, lat_common, lon_rho,
                                        lat_rho, sst_roms)
        # Apply land mask
        sst = ma.masked_where(mask_common == 0, sst_common)
        # Write to file
        id.variables['sst'][month, :, :] = sst

        print '...sea surface salinity'
        # Get monthly average of 3D variable
        salt_roms = monthly_avg_roms(
            roms_file,
            'salt',
            [N, size(lon_rho, 0), size(lon_rho, 1)],
            month % 12,
            instance=month / 12 + 1)
        # Select surface layer
        sss_roms = salt_roms[-1, :, :]
        # Interpolate to common grid
        sss_common = interp_roms2common(lon_common, lat_common, lon_rho,
                                        lat_rho, sss_roms)
        # Apply land mask
        sss = ma.masked_where(mask_common == 0, sss_common)
        # Write to file
        id.variables['sss'][month, :, :] = sss

        print '...surface heat flux'
        # Get monthly average
        shflux_roms = monthly_avg_roms(roms_file,
                                       'shflux',
                                       shape(lon_rho),
                                       month % 12,
                                       instance=month / 12 + 1)
        # Interpolate to common grid
        shflux_common = interp_roms2common(lon_common, lat_common, lon_rho,
                                           lat_rho, shflux_roms)
        # Apply land mask
        shflux = ma.masked_where(mask_common == 0, shflux_common)
        # Write to file
        id.variables['shflux'][month, :, :] = shflux

        print '...surface salt flux'
        # Get monthly average
        ssflux_roms = monthly_avg_roms(roms_file,
                                       'ssflux',
                                       shape(lon_rho),
                                       month % 12,
                                       instance=month / 12 + 1)
        # Interpolate to common grid
        ssflux_common = interp_roms2common(lon_common, lat_common, lon_rho,
                                           lat_rho, ssflux_roms)
        # Apply land mask
        ssflux = ma.masked_where(mask_common == 0, ssflux_common)
        # Write to file
        id.variables['ssflux'][month, :, :] = ssflux

        print '...sea ice concentration'
        # Get monthly average (use CICE file)
        aice_cice = monthly_avg_cice(cice_file,
                                     'aice',
                                     shape(lon_cice),
                                     month % 12,
                                     instance=month / 12 + 1)
        # Interpolate to common grid (note CICE grid not ROMS)
        aice_common = interp_roms2common(lon_common, lat_common, lon_cice,
                                         lat_cice, aice_cice)
        # Apply land mask
        aice = ma.masked_where(mask_common == 0, aice_common)
        # Write to file
        id.variables['aice'][month, :, :] = aice

        print '...sea ice thickness'
        # Get monthly average (use CICE file)
        hice_cice = monthly_avg_cice(cice_file,
                                     'hi',
                                     shape(lon_cice),
                                     month % 12,
                                     instance=month / 12 + 1)
        # Interpolate to common grid (note CICE grid not ROMS)
        hice_common = interp_roms2common(lon_common, lat_common, lon_cice,
                                         lat_cice, hice_cice)
        # Apply land mask
        hice = ma.masked_where(mask_common == 0, hice_common)
        # Write to file
        id.variables['hice'][month, :, :] = hice

        print '...surface ocean velocity vector'
        # Surface ocean velocity
        # Get monthly averages of both 3D vector components
        uocn_3d_tmp = monthly_avg_roms(roms_file,
                                       'u', [N, u_shape[0], u_shape[1]],
                                       month % 12,
                                       instance=month / 12 + 1)
        vocn_3d_tmp = monthly_avg_roms(roms_file,
                                       'v', [N, v_shape[0], v_shape[1]],
                                       month % 12,
                                       instance=month / 12 + 1)
        # Select surface layer
        uocn_tmp = uocn_3d_tmp[-1, :, :]
        vocn_tmp = vocn_3d_tmp[-1, :, :]
        # Rotate to lon-lat space (note they are on the rho grid now)
        uocn_roms, vocn_roms = rotate_vector_roms(uocn_tmp, vocn_tmp,
                                                  angle_roms)
        # Interpolate to common grid
        uocn_common = interp_roms2common(lon_common, lat_common, lon_rho,
                                         lat_rho, uocn_roms)
        vocn_common = interp_roms2common(lon_common, lat_common, lon_rho,
                                         lat_rho, vocn_roms)
        # Apply land mask
        uocn = ma.masked_where(mask_common == 0, uocn_common)
        vocn = ma.masked_where(mask_common == 0, vocn_common)
        # Write to file
        id.variables['uocn'][month, :, :] = uocn
        id.variables['vocn'][month, :, :] = vocn

        print '...sea ice velocity vector'
        # Sea ice velocity (CICE variable not ROMS)
        # Get monthly averages of both vector components
        uice_tmp = monthly_avg_cice(cice_file,
                                    'uvel',
                                    shape(lon_cice),
                                    month % 12,
                                    instance=month / 12 + 1)
        vice_tmp = monthly_avg_cice(cice_file,
                                    'vvel',
                                    shape(lon_cice),
                                    month % 12,
                                    instance=month / 12 + 1)
        # Rotate to lon-lat space
        uice_cice, vice_cice = rotate_vector_cice(uice_tmp, vice_tmp,
                                                  angle_cice)
        # Interpolate to common grid (note CICE grid not ROMS)
        uice_common = interp_roms2common(lon_common, lat_common, lon_cice,
                                         lat_cice, uice_cice)
        vice_common = interp_roms2common(lon_common, lat_common, lon_cice,
                                         lat_cice, vice_cice)
        # Apply land mask
        uice = ma.masked_where(mask_common == 0, uice_common)
        vice = ma.masked_where(mask_common == 0, vice_common)
        # Write to file
        id.variables['uice'][month, :, :] = uice
        id.variables['vice'][month, :, :] = vice

        print '...surface stress vector'
        # Surface stresses
        # Get monthly averages of both vector components
        sustr_tmp = monthly_avg_roms(roms_file,
                                     'sustr',
                                     u_shape,
                                     month % 12,
                                     instance=month / 12 + 1)
        svstr_tmp = monthly_avg_roms(roms_file,
                                     'svstr',
                                     v_shape,
                                     month % 12,
                                     instance=month / 12 + 1)
        # Rotate to lon-lat space (note they are on the rho grid now)
        sustr_roms, svstr_roms = rotate_vector_roms(sustr_tmp, svstr_tmp,
                                                    angle_roms)
        # Interpolate to common grid
        sustr_common = interp_roms2common(lon_common, lat_common, lon_rho,
                                          lat_rho, sustr_roms)
        svstr_common = interp_roms2common(lon_common, lat_common, lon_rho,
                                          lat_rho, svstr_roms)
        # Apply land mask
        sustr = ma.masked_where(mask_common == 0, sustr_common)
        svstr = ma.masked_where(mask_common == 0, svstr_common)
        # Write to file
        id.variables['sustr'][month, :, :] = sustr
        id.variables['svstr'][month, :, :] = svstr

        print '...curl of surface stress vector'
        # Curl of surface stress = d/dx (svstr) - d/dy (sustr)
        # First calculate the two derivatives
        dsvstr_dx = ma.empty(shape(svstr_common))
        # Forward difference approximation
        dsvstr_dx[:, :-1] = (svstr_common[:, 1:] -
                             svstr_common[:, :-1]) / dx[:, :-1]
        # Backward difference for the last row
        dsvstr_dx[:,
                  -1] = (svstr_common[:, -1] - svstr_common[:, -2]) / dx[:, -1]
        dsustr_dy = ma.empty(shape(sustr_common))
        dsustr_dy[:-1, :] = (sustr_common[1:, :] -
                             sustr_common[:-1, :]) / dy[:-1, :]
        dsustr_dy[-1, :] = (sustr_common[-1, :] -
                            sustr_common[-2, :]) / dy[-1, :]
        curl_str = dsvstr_dx - dsustr_dy
        curl_str = ma.masked_where(mask_common == 0, curl_str)
        # Write to file
        id.variables['curl_str'][month, :, :] = curl_str

        id.close()

    print 'Finished'
Esempio n. 3
0
def compare_nic_seasonal(cice_file,
                         var_name,
                         colour_bounds=None,
                         save=False,
                         fig_name=None):

    # Piece together the paths to Nic's monthly averaged output on raijin
    nic_dir_head = '/g/data/gh5/access_om_025-CORE_NYF/output'
    output_number = 137
    nic_dir_tail = '/ice/HISTORY/'
    nic_file_head = 'iceh.0'
    nic_year_number = 133
    # Maximum j-index to read in Nic's output
    max_j = 300

    # Look at the variable in my output
    id = Dataset(cice_file, 'r')
    # Save units
    units = id.variables[var_name].units
    # Check if this is a vector we need to rotate to lon-lat space
    if var_name in [
            'uvel', 'vvel', 'strairx', 'strairy', 'strocnx', 'strocny'
    ]:
        rotate = True
        # Read the angle of grid rotation
        angle = id.variables['ANGLE'][:, :]
        # Figure out whether this is an x or y component, and what the name of
        # the other component is
        if var_name == 'uvel':
            cmp_flag = 'x'
            other_name = 'vvel'
        elif var_name == 'vvel':
            cmp_flag = 'y'
            other_name = 'uvel'
        elif var_name in ['strairx', 'strocnx']:
            cmp_flag = 'x'
            other_name = var_name.replace('x', 'y')
        elif var_name in ['strairy', 'strocny']:
            cmp_flag = 'y'
            other_name = var_name.replace('x', 'y')
    else:
        rotate = False
    # Read the correct grid (tracer or velocity)
    grid_string = id.variables[var_name].coordinates
    if grid_string.startswith('ULON'):
        lon_name = 'ULON'
        lat_name = 'ULAT'
    else:
        lon_name = 'TLON'
        lat_name = 'TLAT'
    id.close()

    # Number of days in each month (this is just for Nic's output)
    # Note Nic doesn't run with leap years
    ndays_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    # Season names for titles
    season_names = ['DJF', 'MAM', 'JJA', 'SON']
    # Degrees to radians conversion
    deg2rad = pi / 180.0

    # Read my CICE grid
    id = Dataset(cice_file, 'r')
    cice_lon_tmp = id.variables[lon_name][:-15, :]
    cice_lat_tmp = id.variables[lat_name][:-15, :]
    num_lon = id.variables['TLON'].shape[1]
    num_lat = id.variables['TLAT'].shape[0]
    id.close()
    # Wrap the periodic boundary by 1 cell
    cice_lon = ma.empty([size(cice_lon_tmp, 0), size(cice_lon_tmp, 1) + 1])
    cice_lat = ma.empty([size(cice_lat_tmp, 0), size(cice_lat_tmp, 1) + 1])
    cice_lon[:, :-1] = cice_lon_tmp
    cice_lon[:, -1] = cice_lon_tmp[:, 0]
    cice_lat[:, :-1] = cice_lat_tmp
    cice_lat[:, -1] = cice_lat_tmp[:, 0]

    # Get seasonal averages of CICE data
    if rotate:
        # Average both components of the vector
        this_cmp = seasonal_avg_cice(cice_file, var_name, [num_lat, num_lon])
        other_cmp = seasonal_avg_cice(cice_file, other_name,
                                      [num_lat, num_lon])
        # Rotate to lon-lat space
        if cmp_flag == 'x':
            cice_data_tmp = ma.empty(shape(this_cmp))
            for season in range(4):
                tmp1, tmp2 = rotate_vector_cice(this_cmp[season, :, :],
                                                other_cmp[season, :, :], angle)
                cice_data_tmp[season, :, :] = tmp1
        elif cmp_flag == 'y':
            cice_data_tmp = ma.empty(shape(this_cmp))
            for season in range(4):
                tmp1, tmp2 = rotate_vector_cice(other_cmp[season, :, :],
                                                this_cmp[season, :, :], angle)
                cice_data_tmp[season, :, :] = tmp2
    else:
        cice_data_tmp = seasonal_avg_cice(cice_file, var_name,
                                          [num_lat, num_lon])

    # Chop off northern boundary
    cice_data_tmp = cice_data_tmp[:, :-15, :]
    # Wrap the periodic boundary
    cice_data = ma.empty([
        size(cice_data_tmp, 0),
        size(cice_data_tmp, 1),
        size(cice_data_tmp, 2) + 1
    ])
    cice_data[:, :, :-1] = cice_data_tmp
    cice_data[:, :, -1] = cice_data_tmp[:, :, 0]

    # Conversions to account for different thermodynamics schemes
    if var_name in ['frazil', 'snoice']:
        cice_data /= 3.6

    # Read Nic's grid from the January file
    id = Dataset(
        nic_dir_head + str(output_number) + nic_dir_tail + nic_file_head +
        str(nic_year_number) + '-01.nc', 'r')
    nic_lon = id.variables[lon_name][:max_j, :]
    nic_lat = id.variables[lat_name][:max_j, :]
    id.close()

    # Get seasonal averages of Nic's output
    nic_data = ma.empty([4, size(nic_lon, 0), size(nic_lon, 1)])
    nic_data[:, :, :] = 0.0
    # Loop over seasons
    for season in range(4):
        # Figure out what months we care about for this season
        if season == 0:
            months = [12, 1, 2]
        elif season == 1:
            months = [3, 4, 5]
        elif season == 2:
            months = [6, 7, 8]
        elif season == 3:
            months = [9, 10, 11]
        # Days in season so far
        season_days = 0
        # Loop over months
        for month in months:
            if month == 12:
                # Read December from the previous year
                filename = nic_dir_head + str(
                    output_number - 1) + nic_dir_tail + nic_file_head + str(
                        nic_year_number - 1) + '-' + str(month) + '.nc'
            else:
                if month < 10:
                    filename = nic_dir_head + str(
                        output_number) + nic_dir_tail + nic_file_head + str(
                            nic_year_number) + '-0' + str(month) + '.nc'
                else:
                    filename = nic_dir_head + str(
                        output_number) + nic_dir_tail + nic_file_head + str(
                            nic_year_number) + '-' + str(month) + '.nc'
            id = Dataset(filename, 'r')
            # Integrate over time
            nic_data[season, :, :] += id.variables[var_name][
                0, :max_j, :] * ndays_month[month - 1]
            season_days += ndays_month[month - 1]
        # Convert from integral to average
        nic_data[season, :, :] /= season_days

    # Convert both grids to spherical coordinates
    cice_x = -(cice_lat + 90) * cos(cice_lon * deg2rad + pi / 2)
    cice_y = (cice_lat + 90) * sin(cice_lon * deg2rad + pi / 2)
    nic_x = -(nic_lat + 90) * cos(nic_lon * deg2rad + pi / 2)
    nic_y = (nic_lat + 90) * sin(nic_lon * deg2rad + pi / 2)

    # Boundaries on plots
    bdry1 = -35
    bdry2 = 39
    bdry3 = -35
    bdry4 = 39

    if colour_bounds is not None:
        # User-defined colour bounds
        lev = linspace(colour_bounds[0], colour_bounds[1], num=50)
        if colour_bounds[0] == -colour_bounds[1]:
            # Centered on zero; use red-yellow-blue colourmap
            colour_map = 'RdYlBu_r'
        else:
            # Not centered on zero; go for a rainbow
            colour_map = 'jet'
    else:
        # Automatic colour bounds based on min/max of the data
        if var_name in [
                'uvel', 'vvel', 'strairx', 'strairy', 'strocnx', 'strocny'
        ]:
            # Center on zero and use red-yellow-blue colourmap
            max_val = max(amax(abs(nic_data)), amax(abs(cice_data)))
            lev = linspace(-max_val, max_val, num=50)
            colour_map = 'RdYlBu_r'
        else:
            # Not centered on zero; go for a rainbow
            min_val = min(amin(nic_data), amin(cice_data))
            max_val = max(amax(nic_data), amax(cice_data))
            lev = linspace(min_val, max_val, num=50)
            colour_map = 'jet'

    # Make the figure
    fig = figure(figsize=(20, 9))
    # Loop over seasons
    for season in range(4):
        # Nic's output
        ax = fig.add_subplot(2, 4, season + 1, aspect='equal')
        contourf(nic_x,
                 nic_y,
                 nic_data[season, :, :],
                 lev,
                 cmap=colour_map,
                 extend='both')
        if season == 0:
            text(-39, 0, 'Nic', fontsize=24, ha='right')
        title(season_names[season], fontsize=24)
        xlim([bdry1, bdry2])
        ylim([bdry3, bdry4])
        axis('off')
        # My output
        ax = fig.add_subplot(2, 4, season + 5, aspect='equal')
        img = contourf(cice_x,
                       cice_y,
                       cice_data[season, :, :],
                       lev,
                       cmap=colour_map,
                       extend='both')
        if season == 0:
            text(-39, 0, 'Me', fontsize=24, ha='right')
        xlim([bdry1, bdry2])
        ylim([bdry3, bdry4])
        axis('off')
    # Add colourbar on the bottom
    cbaxes = fig.add_axes([0.25, 0.04, 0.5, 0.02])
    cbar = colorbar(img, orientation='horizontal', cax=cbaxes)
    cbar.ax.tick_params(labelsize=16)
    # Main title with variable name and units
    suptitle(var_name + ' (' + units + ')', fontsize=30)
    subplots_adjust(wspace=0.025, hspace=0.025)

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
def circumpolar_cice_plot (file_path, var_name, tstep, colour_bounds=None, save=False, fig_name=None):

    deg2rad = pi/180

    # Read the variable
    id = Dataset(file_path, 'r')
    data_tmp = id.variables[var_name][tstep-1,:-15,:]
    if var_name == 'aice':
        units = 'fraction'
    else:
        units = id.variables[var_name].units

    # Check for vector variables that need to be rotated
    if var_name in ['uvel', 'vvel', 'uatm', 'vatm', 'uocn', 'vocn', 'strairx', 'strairy', 'strtltx', 'strtlty', 'strcorx', 'strcory', 'strocnx', 'strocny', 'strintx', 'strinty']:
        angle = id.variables['ANGLET'][:-15,:]
        if var_name in ['uvel', 'uatm', 'uocn', 'strairx', 'strtltx', 'strcorx', 'strocnx', 'strintx']:
            # u-variable
            u_data = data_tmp[:,:]
            if var_name[0] == 'u':
                v_data = id.variables[var_name.replace('u','v')][tstep-1,:-15,:]
            else:
                v_data = id.variables[var_name.replace('x','y')][tstep-1,:-15,:]
            u_data_lonlat, v_data_lonlat = rotate_vector_cice(u_data, v_data, angle)
            data_tmp = u_data_lonlat
        elif var_name in ['vvel', 'vatm', 'vocn', 'strairy', 'strtlty', 'strcory', 'strocny', 'strinty']:
            # v-variable
            v_data = data_tmp[:,:]
            if var_name[0] == 'v':
                u_data = id.variables[var_name.replace('v','u',1)][tstep-1,:-15,:]
            else:
                u_data = id.variables[var_name.replace('y','x')][tstep-1,:-15,:]
            u_data_lonlat, v_data_lonlat = rotate_vector_cice(u_data, v_data, angle)
            data_tmp = v_data_lonlat

    # Figure out which grid we're on
    grid_string = id.variables[var_name].coordinates
    if grid_string.startswith('ULON'):
        grid_name = 'u'
        lon_name = 'ULON'
        lat_name = 'ULAT'
    elif grid_string.startswith('TLON'):
        grid_name = 't'
        lon_name = 'TLON'
        lat_name = 'TLAT'
    else:
        print 'Grid type ' + grid_string + ' not supported'
        id.close()
        return

    # Read the correct lat and lon for this grid
    lon_tmp = id.variables[lon_name][:-15,:]
    lat_tmp = id.variables[lat_name][:-15,:]
    id.close()

    # Wrap the periodic boundary by 1 cell
    lon = ma.empty([size(lon_tmp,0), size(lon_tmp,1)+1])
    lat = ma.empty([size(lat_tmp,0), size(lat_tmp,1)+1])
    data = ma.empty([size(data_tmp,0), size(data_tmp,1)+1])
    lon[:,:-1] = lon_tmp
    lon[:,-1] = lon_tmp[:,0]
    lat[:,:-1] = lat_tmp
    lat[:,-1] = lat_tmp[:,0]
    data[:,:-1] = data_tmp
    data[:,-1] = data_tmp[:,0]

    # Convert to spherical coordinates
    x = -(lat+90)*cos(lon*deg2rad+pi/2)
    y = (lat+90)*sin(lon*deg2rad+pi/2)

    if colour_bounds is not None:
        # User has set bounds on colour scale
        lev = linspace(colour_bounds[0], colour_bounds[1], num=40)
        if colour_bounds[0] == -colour_bounds[1]:
            # Bounds are centered on zero, so choose a blue-to-red colourmap
            # centered on yellow
            colour_map = 'RdYlBu_r'
        else:
            colour_map = 'jet'
    else:
        # Determine bounds automatically
        if var_name in ['uvel', 'vvel', 'uatm', 'vatm', 'uocn', 'vocn', 'fresh_ai', 'fsalt_ai', 'fhocn_ai', 'strairx', 'strairy', 'strtltx', 'strtlty', 'strcorx', 'strcory', 'strocnx', 'strocny', 'strintx', 'strinty']:
            # Center levels on 0 for certain variables, with a blue-to-red
            # colourmap
            max_val = amax(abs(data))
            lev = linspace(-max_val, max_val, num=40)
            colour_map = 'RdYlBu_r'
        else:
            lev = linspace(amin(data), amax(data), num=40)
            colour_map = 'jet'

    # Plot
    fig = figure(figsize=(16,12))
    fig.add_subplot(1,1,1, aspect='equal')
    contourf(x, y, data, lev, cmap=colour_map, extend='both')
    cbar = colorbar()
    cbar.ax.tick_params(labelsize=20)
    title(var_name+' ('+units+')', fontsize=30)
    axis('off')

    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
Esempio n. 5
0
def cice_vectorplot (file_path, tstep, xname, yname, cmax=None, save=False, fig_name=None):

    # Radius of the Earth in metres
    r = 6.371e6
    # Degrees to radians conversion factor
    deg2rad = pi/180
    # Side length of blocks to average vectors over (can't plot vector at
    # every single point or the plot will be way too crowded)
    block = 15

    # Read grid (including rotation angle) and vector components
    id = Dataset(file_path, 'r')
    lon_tmp = id.variables['ULON'][:-15,:]
    lat_tmp = id.variables['ULAT'][:-15,:]
    angle_tmp = id.variables['ANGLET'][:-15,:]
    u_xy_tmp = id.variables[xname][tstep-1,:-15,:]
    v_xy_tmp = id.variables[yname][tstep-1,:-15,:]
    id.close()

    # Wrap periodic boundary by 1 cell
    lon = ma.empty([size(lon_tmp,0), size(lon_tmp,1)+1])
    lat = ma.empty([size(lat_tmp,0), size(lat_tmp,1)+1])
    angle = ma.empty([size(angle_tmp,0), size(angle_tmp,1)+1])
    u_xy = ma.empty([size(u_xy_tmp,0), size(u_xy_tmp,1)+1])
    v_xy = ma.empty([size(v_xy_tmp,0), size(v_xy_tmp,1)+1])
    lon[:,:-1] = lon_tmp
    lon[:,-1] = lon_tmp[:,0]
    lat[:,:-1] = lat_tmp
    lat[:,-1] = lat_tmp[:,0]
    angle[:,:-1] = angle_tmp
    angle[:,-1] = angle_tmp[:,0]
    u_xy[:,:-1] = u_xy_tmp
    u_xy[:,-1] = u_xy_tmp[:,0]
    v_xy[:,:-1] = v_xy_tmp
    v_xy[:,-1] = v_xy_tmp[:,0]

    # Rotate from local x-y space to lon-lat space
    u, v = rotate_vector_cice(u_xy, v_xy, angle)
    # Calculate magnitude for the background filled contour plot
    speed = sqrt(u**2 + v**2)

    # Calculate X and Y coordinates for plotting circumpolar projection
    X = -(lat+90)*cos(lon*deg2rad+pi/2)
    Y = (lat+90)*sin(lon*deg2rad+pi/2)

    # Calculate vector components in spherical coordinate space
    # (just differentiate and rearrange spherical coordinate transformation)
    dlon_dt = u/(r*cos(lat*deg2rad)*deg2rad)
    dlat_dt = v/(r*deg2rad)
    dX_dt = -dlat_dt*cos(lon*deg2rad+pi/2) + (lat+90)*sin(lon*deg2rad+pi/2)*dlon_dt*deg2rad
    dY_dt = dlat_dt*sin(lon*deg2rad+pi/2) + (lat+90)*cos(lon*deg2rad+pi/2)*dlon_dt*deg2rad

    # Average X, Y, dX_dt, and dY_dt over block x block intervals
    # Calculate number of blocks
    size0 = int(ceil(size(X,0)/float(block)))
    size1 = int(ceil((size(X,1)-1)/float(block)))
    # Set up arrays for averaged fields
    X_block = ma.empty([size0, size1])
    Y_block = ma.empty([size0, size1])
    dX_dt_block = ma.empty([size0, size1])
    dY_dt_block = ma.empty([size0, size1])
    # Set up arrays containing boundary indices
    posn0 = range(0, size(X,0), block)
    posn0.append(size(X,0))
    posn1 = range(0, size(X,1), block)
    posn1.append(size(X,1))
    # Double loop to average each block (can't find a more efficient way to do
    # this)
    for j in range(size0):
        for i in range(size1):
            start0 = posn0[j]
            end0 = posn0[j+1]
            start1 = posn1[i]
            end1 = posn1[i+1]
            X_block[j,i] = mean(X[start0:end0, start1:end1])
            Y_block[j,i] = mean(Y[start0:end0, start1:end1])
            dX_dt_block[j,i] = mean(dX_dt[start0:end0, start1:end1])
            dY_dt_block[j,i] = mean(dY_dt[start0:end0, start1:end1])

    # Set up colour scale levels
    if cmax is None:
        lev = linspace(0, amax(speed), num=50)
    else:
        lev = linspace(0, cmax, num=50)

    # Make the plot
    fig = figure(figsize=(16,12))
    fig.add_subplot(1,1,1, aspect='equal')
    # Contour speed values at every point
    # Use pastel colour map so overlaid vectors will show up
    contourf(X, Y, speed, lev, cmap='Paired', extend='both')
    cbar = colorbar()
    cbar.ax.tick_params(labelsize=20)
    # Add vectors for each block
    quiver(X_block, Y_block, dX_dt_block, dY_dt_block, color='black')
    title(xname + ', ' + yname, fontsize=30)
    axis('off')

    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
Esempio n. 6
0
def ice_drift_seasonal(cice_file, save=False, fig_name=None):

    # Starting and ending months (1-based) for each season
    start_month = [2, 5, 8, 11]
    end_month = [4, 7, 10, 1]
    # Starting and ending days of the month (1-based) for each season
    start_day = [1, 1, 1, 1]
    end_day = [30, 31, 31, 31]
    # Number of days in each season
    # Assume no leap years, we'll fix this later if needed
    ndays_season = [89, 92, 92, 92]
    # Season names for titles
    season_names = ['FMA', 'MMJ', 'ASO', 'NDJ']
    # Order of figures (clockwise)
    figure_order = [1, 2, 4, 3]
    # Degrees to radians conversion
    deg2rad = pi / 180.0
    # Side length of blocks to average vectors over (can't plot vector at
    # every single point or the plot will be way too crowded)
    block = 15

    # Read CICE grid (including angle) and time values
    id = Dataset(cice_file, 'r')
    lon_tmp = id.variables['TLON'][:-15, :]
    lat_tmp = id.variables['TLAT'][:-15, :]
    angle_tmp = id.variables['ANGLE'][:-15, :]
    # Wrap the periodic boundary by 1 cell
    lon = ma.empty([size(lon_tmp, 0), size(lon_tmp, 1) + 1])
    lat = ma.empty([size(lat_tmp, 0), size(lat_tmp, 1) + 1])
    angle = ma.empty([size(angle_tmp, 0), size(angle_tmp, 1) + 1])
    lon[:, :-1] = lon_tmp
    lon[:, -1] = lon_tmp[:, 0]
    lat[:, :-1] = lat_tmp
    lat[:, -1] = lat_tmp[:, 0]
    angle[:, :-1] = angle_tmp
    angle[:, -1] = angle_tmp[:, 0]
    time_id = id.variables['time']
    # Get the year, month, and day (all 1-based) for each output step
    # These are 5-day averages marked with the next day's date.
    time = num2date(time_id[:],
                    units=time_id.units,
                    calendar=time_id.calendar.lower())

    # Loop backwards through time indices to find the last one we care about
    # (which contains 31 Jan in its averaging period)
    end_t = -1  # Missing value flag
    for t in range(size(time) - 1, -1, -1):
        if time[t].month == start_month[0] and time[t].day in range(
                start_day[0], start_day[0] + 5):
            end_t = t
            break
    # Make sure we actually found it
    if end_t == -1:
        print 'Error: ' + cice_file + ' does not contain a complete Feb-Jan period'
        return

    # Continue looping backwards to find the first time index we care about
    # (which contains 1 Feb the previous year in its averaging period)
    start_t = -1  # Missing value flag
    for t in range(end_t - 60, -1, -1):
        if time[t].month == start_month[0] and time[t].day in range(
                start_day[0] + 1, start_day[0] + 6):
            start_t = t
            break
    # Make sure we actually found it
    if start_t == -1:
        print 'Error: ' + cice_file + ' does not contain a complete Feb-Jan period'
        return

    # Check for leap years
    leap_year = False
    if mod(time[start_t].year, 4) == 0:
        # Years divisible by 4 are leap years
        leap_year = True
        if mod(time[start_t].year, 100) == 0:
            # Unless they're also divisible by 100, in which case they aren't
            # leap years
            leap_year = False
            if mod(time[start_t].year, 400) == 0:
                # Unless they're also divisible by 400, in which case they are
                # leap years after all
                leap_year = True
    if leap_year:
        # Update last day in February
        ndays_season[0] += 1

    # Initialise seasonal averages of CICE output
    aice_tmp = ma.empty([4, size(lon_tmp, 0), size(lon_tmp, 1)])
    aice_tmp[:, :, :] = 0.0
    uxy_tmp = ma.empty([4, size(lon_tmp, 0), size(lon_tmp, 1)])
    uxy_tmp[:, :, :] = 0.0
    vxy_tmp = ma.empty([4, size(lon_tmp, 0), size(lon_tmp, 1)])
    vxy_tmp[:, :, :] = 0.0
    # Process one season at a time
    for season in range(4):
        season_days = 0  # Number of days in season; this will be incremented
        next_season = mod(season + 1, 4)

        # Find starting timestep
        start_t_season = -1
        for t in range(start_t, end_t + 1):
            if time[t].month == start_month[season] and time[t].day in range(
                    start_day[season] + 1, start_day[season] + 6):
                start_t_season = t
                break
        # Make sure we actually found it
        if start_t_season == -1:
            print 'Error: could not find starting timestep for season ' + season_names[
                season]
            return

        # Find ending timestep
        end_t_season = -1
        for t in range(start_t_season + 1, end_t + 1):
            if time[t].month == start_month[
                    next_season] and time[t].day in range(
                        start_day[next_season], start_day[next_season] + 5):
                end_t_season = t
                break
        # Make sure we actually found it
        if end_t_season == -1:
            print 'Error: could not find ending timestep for season ' + season_names[
                season]
            return

        # Figure out how many of the 5 days averaged in start_t_season are
        # actually within this season
        if time[start_t_season].month == start_month[season] and time[
                start_t_season].day == start_day[season] + 5:
            # Starting day is in position 1 of 5; we care about all of them
            start_days = 5
        elif time[start_t_season].month == start_month[season] and time[
                start_t_season].day == start_day[season] + 4:
            # Starting day is in position 2 of 5; we care about the last 4
            start_days = 4
        elif time[start_t_season].month == start_month[season] and time[
                start_t_season].day == start_day[season] + 3:
            # Starting day is in position 3 of 5; we care about the last 3
            start_days = 3
        elif time[start_t_season].month == start_month[season] and time[
                start_t_season].day == start_day[season] + 2:
            # Starting day is in position 4 of 5; we care about the last 2
            start_days = 2
        elif time[start_t_season].month == start_month[season] and time[
                start_t_season].day == start_day[season] + 1:
            # Starting day is in position 5 of 5; we care about the last 1
            start_days = 1
        else:
            print 'Error for season ' + season_names[
                season] + ': starting index is month ' + str(
                    time[start_t_season].month) + ', day ' + str(
                        time[start_t_season].day)
            return

        # Start accumulating data weighted by days
        aice_tmp[season, :, :] += id.variables['aice'][
            start_t_season, :-15, :] * start_days
        uxy_tmp[season, :, :] += id.variables['uvel'][
            start_t_season, :-15, :] * start_days
        vxy_tmp[season, :, :] += id.variables['vvel'][
            start_t_season, :-15, :] * start_days
        season_days += start_days

        # Between start_t_season and end_t_season, we want all the days
        for t in range(start_t_season + 1, end_t_season):
            aice_tmp[season, :, :] += id.variables['aice'][t, :-15, :] * 5
            uxy_tmp[season, :, :] += id.variables['uvel'][t, :-15, :] * 5
            vxy_tmp[season, :, :] += id.variables['vvel'][t, :-15, :] * 5
            season_days += 5

        # Figure out how many of the 5 days averaged in end_t_season are
        # actually within this season
        if time[end_t_season].month == start_month[next_season] and time[
                end_t_season].day == start_day[next_season] + 4:
            # Ending day is in position 1 of 5; we care about the first 1
            end_days = 1
        elif time[end_t_season].month == start_month[next_season] and time[
                end_t_season].day == start_day[next_season] + 3:
            # Ending day is in position 2 of 5; we care about the first 2
            end_days = 2
        elif time[end_t_season].month == start_month[next_season] and time[
                end_t_season].day == start_day[next_season] + 2:
            # Ending day is in position 3 of 5; we care about the first 3
            end_days = 3
        elif time[end_t_season].month == start_month[next_season] and time[
                end_t_season].day == start_day[next_season] + 1:
            # Ending day is in position 4 of 5; we care about the first 4
            end_days = 4
        elif time[end_t_season].month == start_month[next_season] and time[
                end_t_season].day == start_day[next_season]:
            # Ending day is in position 5 of 5; we care about all 5
            end_days = 5
        else:
            print 'Error for season ' + season_names[
                season] + ': ending index is month ' + str(
                    time[end_t_season].month) + ', day ' + str(
                        time[end_t_season].day)
            return

        aice_tmp[season, :, :] += id.variables['aice'][
            end_t_season, :-15, :] * end_days
        uxy_tmp[season, :, :] += id.variables['uvel'][
            end_t_season, :-15, :] * end_days
        vxy_tmp[season, :, :] += id.variables['vvel'][
            end_t_season, :-15, :] * end_days
        season_days += end_days

        # Check that we got the correct number of days
        if season_days != ndays_season[season]:
            print 'Error: found ' + str(
                season_days) + ' days instead of ' + str(ndays_season[season])
            return

        # Finished accumulating data, now convert from sum to average
        aice_tmp[season, :, :] /= season_days
        uxy_tmp[season, :, :] /= season_days
        vxy_tmp[season, :, :] /= season_days

    # Finished reading all CICE data
    id.close()

    # Wrap the periodic boundary
    aice = ma.empty(
        [size(aice_tmp, 0),
         size(aice_tmp, 1),
         size(aice_tmp, 2) + 1])
    aice[:, :, :-1] = aice_tmp
    aice[:, :, -1] = aice_tmp[:, :, 0]
    u_xy = ma.empty([size(uxy_tmp, 0), size(uxy_tmp, 1), size(uxy_tmp, 2) + 1])
    u_xy[:, :, :-1] = uxy_tmp
    u_xy[:, :, -1] = uxy_tmp[:, :, 0]
    v_xy = ma.empty([size(vxy_tmp, 0), size(vxy_tmp, 1), size(vxy_tmp, 2) + 1])
    v_xy[:, :, :-1] = vxy_tmp
    v_xy[:, :, -1] = vxy_tmp[:, :, 0]

    # Rotate from local x-y space to lon-lat space
    u, v = rotate_vector_cice(u_xy, v_xy, angle)
    # Calculate speed
    speed = sqrt(u**2 + v**2)
    # Convert velocity to polar coordinates, rotate to account for longitude in
    # circumpolar projection, and convert back to vector components
    theta = arctan2(v, u)
    theta_circ = theta - lon * deg2rad
    u_circ = speed * cos(theta_circ)
    v_circ = speed * sin(theta_circ)

    # Calculate x and y coordinates for plotting circumpolar projection
    x = -(lat + 90) * cos(lon * deg2rad + pi / 2)
    y = (lat + 90) * sin(lon * deg2rad + pi / 2)

    # Average x, y, u_circ, and v_circ over block x block intervals
    # Calculate number of blocks
    size0 = int(ceil(size(x, 0) / float(block)))
    size1 = int(ceil((size(x, 1) - 1) / float(block)))
    # Set up arrays for averaged fields
    x_block = ma.empty([size0, size1])
    y_block = ma.empty([size0, size1])
    u_circ_block = ma.empty([4, size0, size1])
    v_circ_block = ma.empty([4, size0, size1])
    # Loop over seasons
    for season in range(4):
        # Set up arrays containing boundary indices
        posn0 = range(0, size(x, 0), block)
        posn0.append(size(x, 0))
        posn1 = range(0, size(x, 1), block)
        posn1.append(size(x, 1))
        # Double loop to average each block (can't find a more efficient way to
        # do this)
        for j in range(size0):
            for i in range(size1):
                start0 = posn0[j]
                end0 = posn0[j + 1]
                start1 = posn1[i]
                end1 = posn1[i + 1]
                if season == 0:
                    # x_block and y_block are season-independent so just do them
                    # for the first season
                    x_block[j, i] = mean(x[start0:end0, start1:end1])
                    y_block[j, i] = mean(y[start0:end0, start1:end1])
                u_circ_block[season, j, i] = mean(u_circ[season, start0:end0,
                                                         start1:end1])
                v_circ_block[season, j, i] = mean(v_circ[season, start0:end0,
                                                         start1:end1])

    # Set up colour levels for aice
    lev = linspace(0, 1, num=50)
    # Set boundaries for each side of plot
    bdry1 = -35
    bdry2 = 35
    bdry3 = -33
    bdry4 = 37

    # Make the plot
    fig = figure(figsize=(16, 12))
    # Loop over seasons
    for season in range(4):
        ax = fig.add_subplot(2, 2, figure_order[season], aspect='equal')
        # Contour concentration
        img = contourf(x, y, aice[season, :, :], lev, cmap='jet')
        # Add velocity vectors
        q = quiver(x_block,
                   y_block,
                   u_circ_block[season, :, :],
                   v_circ_block[season, :, :],
                   color='black')
        # Configure plot
        xlim([bdry1, bdry2])
        ylim([bdry3, bdry4])
        axis('off')
        title(season_names[season], fontsize=24)
        if season == 0:
            # Add colourbar
            cbaxes = fig.add_axes([0.07, 0.6, 0.02, 0.3])
            cbar = colorbar(img, ticks=arange(0, 1 + 0.25, 0.25), cax=cbaxes)
            cbar.ax.tick_params(labelsize=16)
        if season == 3:
            # Add 20 cm/s reference vector
            quiverkey(q,
                      0.07,
                      0.3,
                      0.2,
                      '20 cm/s',
                      coordinates='figure',
                      fontproperties={'size': 16})
    # Add main title
    suptitle('Sea ice concentration (1) and velocity (m/s)', fontsize=30)
    # Make plots closer together
    subplots_adjust(wspace=0.025, hspace=0.1)

    # Finished
    if save:
        fig.savefig(fig_name)
    else:
        fig.show()
Esempio n. 7
0
def cice_vectorplot(file_path,
                    tstep,
                    xname,
                    yname,
                    cmax=None,
                    save=False,
                    fig_name=None):

    # Radius of the Earth in metres
    r = 6.371e6
    # Degrees to radians conversion factor
    deg2rad = pi / 180
    # Side length of blocks to average vectors over (can't plot vector at
    # every single point or the plot will be way too crowded)
    block = 15

    # Read grid (including rotation angle) and vector components
    id = Dataset(file_path, 'r')
    lon_tmp = id.variables['ULON'][:-15, :]
    lat_tmp = id.variables['ULAT'][:-15, :]
    angle_tmp = id.variables['ANGLE'][:-15, :]
    u_xy_tmp = id.variables[xname][tstep - 1, :-15, :]
    v_xy_tmp = id.variables[yname][tstep - 1, :-15, :]
    id.close()

    # Wrap periodic boundary by 1 cell
    lon = ma.empty([size(lon_tmp, 0), size(lon_tmp, 1) + 1])
    lat = ma.empty([size(lat_tmp, 0), size(lat_tmp, 1) + 1])
    angle = ma.empty([size(angle_tmp, 0), size(angle_tmp, 1) + 1])
    u_xy = ma.empty([size(u_xy_tmp, 0), size(u_xy_tmp, 1) + 1])
    v_xy = ma.empty([size(v_xy_tmp, 0), size(v_xy_tmp, 1) + 1])
    lon[:, :-1] = lon_tmp
    lon[:, -1] = lon_tmp[:, 0]
    lat[:, :-1] = lat_tmp
    lat[:, -1] = lat_tmp[:, 0]
    angle[:, :-1] = angle_tmp
    angle[:, -1] = angle_tmp[:, 0]
    u_xy[:, :-1] = u_xy_tmp
    u_xy[:, -1] = u_xy_tmp[:, 0]
    v_xy[:, :-1] = v_xy_tmp
    v_xy[:, -1] = v_xy_tmp[:, 0]

    # Rotate from local x-y space to lon-lat space
    u, v = rotate_vector_cice(u_xy, v_xy, angle)
    # Calculate magnitude of vector
    speed = sqrt(u**2 + v**2)
    # Convert vector to polar coordinates, rotate to account for longitude in
    # circumpolar projection, and convert back to vector components
    theta = arctan2(v, u)
    theta_circ = theta - lon * deg2rad
    u_circ = speed * cos(theta_circ)
    v_circ = speed * sin(theta_circ)

    # Calculate x and y coordinates for plotting circumpolar projection
    x = -(lat + 90) * cos(lon * deg2rad + pi / 2)
    y = (lat + 90) * sin(lon * deg2rad + pi / 2)

    # Average x, y, u_circ, and v_circ over block x block intervals
    # Calculate number of blocks
    size0 = int(ceil(size(x, 0) / float(block)))
    size1 = int(ceil((size(x, 1) - 1) / float(block)))
    # Set up arrays for averaged fields
    x_block = ma.empty([size0, size1])
    y_block = ma.empty([size0, size1])
    u_circ_block = ma.empty([size0, size1])
    v_circ_block = ma.empty([size0, size1])
    # Set up arrays containing boundary indices
    posn0 = range(0, size(x, 0), block)
    posn0.append(size(x, 0))
    posn1 = range(0, size(x, 1), block)
    posn1.append(size(x, 1))
    # Double loop to average each block (can't find a more efficient way to do
    # this)
    for j in range(size0):
        for i in range(size1):
            start0 = posn0[j]
            end0 = posn0[j + 1]
            start1 = posn1[i]
            end1 = posn1[i + 1]
            x_block[j, i] = mean(x[start0:end0, start1:end1])
            y_block[j, i] = mean(y[start0:end0, start1:end1])
            u_circ_block[j, i] = mean(u_circ[start0:end0, start1:end1])
            v_circ_block[j, i] = mean(v_circ[start0:end0, start1:end1])

    # Set up colour scale levels
    if cmax is None:
        lev = linspace(0, amax(speed), num=50)
    else:
        lev = linspace(0, cmax, num=50)

    # Make the plot
    fig = figure(figsize=(16, 12))
    fig.add_subplot(1, 1, 1, aspect='equal')
    # Contour speed values at every point
    # Use pastel colour map so overlaid vectors will show up
    contourf(x, y, speed, lev, cmap='Paired', extend='both')
    cbar = colorbar()
    cbar.ax.tick_params(labelsize=20)
    # Add vectors for each block
    quiver(x_block, y_block, u_circ_block, v_circ_block, color='black')
    title(xname + ', ' + yname, fontsize=30)
    axis('off')

    if save:
        fig.savefig(fig_name)
    else:
        fig.show()