Ocean Basin Masks#

import cartopy.crs as ccrs
import cartopy.feature
import matplotlib.path as mpath
from matplotlib.colors import BoundaryNorm
from matplotlib.ticker import MaxNLocator
import matplotlib.colors as mcolors
from mom6_tools.m6plot import xyplot
from mom6_tools.m6toolbox import genBasinMasks 
import regionmask
import datetime
import numpy 
import xarray as xr
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings("ignore")
%matplotlib inline
today = datetime.date.today().strftime("%y%m%d")
print(today)
260306
# The following parameters must be set accordingly
######################################################
# case name - must be changed for each configuration
grid_name = 'tx2_3v3'
# Path to the grid
grd_path = "../mesh/tx2_3v3_grid.nc"
# add your name and email address below
author = 'Gustavo Marques (gmarques@ucar.edu)'
grd = xr.open_dataset(grd_path)
grd
<xarray.Dataset>
Dimensions:  (ny: 480, nx: 540, nxp: 541, nyp: 481)
Dimensions without coordinates: ny, nx, nxp, nyp
Data variables: (12/20)
    tlon     (ny, nx) float64 ...
    tlat     (ny, nx) float64 ...
    ulon     (ny, nxp) float64 ...
    ulat     (ny, nxp) float64 ...
    vlon     (nyp, nx) float64 ...
    vlat     (nyp, nx) float64 ...
    ...       ...
    tarea    (ny, nx) float64 ...
    tmask    (ny, nx) float64 ...
    angle    (ny, nx) float64 ...
    depth    (ny, nx) float64 ...
    ar       (ny, nx) float64 ...
    egs      (ny, nx) float64 ...
Attributes:
    Description:  CESM MOM6 2/3 degree grid
    Author:       Frank, Fred, Gustavo (gmarques@ucar.edu)
    Created:      2026-03-05T14:49:28.971877
    type:         Glogal 2/3 degree grid file

Default basins from mom6-tools#

basin_code = genBasinMasks(grd.tlon.values, grd.tlat.values, grd.depth.values,xda=True).rename('basin_masks')
basin_code
<xarray.DataArray 'basin_masks' (region: 16, yh: 480, xh: 540)>
array([[[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
...
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]],

       [[0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        ...,
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.],
        [0., 0., 0., ..., 0., 0., 0.]]])
Coordinates:
  * region   (region) <U17 'Global' 'PersianGulf' ... 'GulfOfMexico'
Dimensions without coordinates: yh, xh

Check mask for all the regions#

for r in range(len(basin_code.region)):
    xyplot((basin_code[0,:]+basin_code[r,:]*2).values, grd.tlon, grd.tlat,
          title=str(basin_code['region'][r].values))
../_images/1e946efda8b829e2cb4a576ec05b829a935eadd67057237cfe5b0a11b018104d.png ../_images/791921833d079c19831b6457a8ebef1d658cfa53eaf8e0c424e952016a3cdb24.png ../_images/66492b8938e6b66d8b0e63bb09dd96c18544d09e37d791b0ed813d39342ec6fd.png ../_images/541baf4f6e744fd564562dc04bdf3ed8e5f6caf185a01ba0c6c5e84314995c26.png ../_images/10912c7d667571d64bc6f370b7e9a9283fce93b59c98def318f3e2669168afbd.png ../_images/d5db5547ac5af82827ec859375632503485124768d6deaf54f6456448ae465cc.png ../_images/14d6d9e2cf8d18c8acedf8b7ead0efdc6c89b3c99c9c8dbbda1729a0ad5c0a16.png ../_images/23eb38ff732d5306046079c14edde25ae20e16647ac0bf06c33e9ec10dc22c11.png ../_images/9407ac86d8c6e6aff87b2fa790be5adc2003d23a57d541026d8d8544bc66597c.png ../_images/01e6bc4f6a358e5c469a1e1bfbfc343d16e9d942155524dcd57635afc3c30609.png ../_images/a1adb831c2f4852690b551c56ecf44c60055d4ef8c07d810e4ad0e284a91473a.png ../_images/77d6c376982a122e71ba2f03c49efe19a94ef1f25298da06450094846b323251.png ../_images/a928772a56b000d63679ae03ba0a33cfc10f253297d258b87ace431624f34123.png ../_images/af735aaee63f04520c2e58e899fa4ebcb7bfe2456ca1271f36ed45caafc685f9.png ../_images/16be2ba2fb0354c5c553062f1a50969c67418153ae8421840c4a20fb2e5d6907.png ../_images/9d1c2f2d047e1cf65e5a914b13833f5746542be1676cd1a70cdb0b0db6e883cc.png

Plot all masks in a single map#

a= xr.where(basin_code[1]==1, 1, numpy.nan)
val_ls = []
for key, val in mcolors.TABLEAU_COLORS.items():
    val_ls.append(val)
print(val_ls)
['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf']
fig = plt.figure(figsize=(10, 5))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.Robinson())

for r in range(1,len(basin_code.region)):
    mask= xr.where(basin_code[r,:]==1, r, numpy.nan)
    
    
    pc = ax.pcolormesh(grd.qlon, grd.qlat, mask.values, cmap=plt.cm.tab20, 
              transform=ccrs.PlateCarree(),vmin=0, vmax=(len(basin_code.region)+1))

ax.set_title('Region masks')
ax.set_global()
ax.stock_img()
ax.coastlines();
../_images/e21f9892b31549e2088bb3cdbc81c9c2c8c2986f2b358c4bd9e86073f2a63605.png

Load basins from regionmask#

basins = regionmask.defined_regions.natural_earth_v4_1_0.ocean_basins_50
basins.plot(add_ocean=False, add_label=False)
<GeoAxes: >
../_images/b7de6168f3ee47d4e1a9fc47d4c17a839a63f318aca356d122ca77ebcee9fa15.png
from xmip.regionmask import merged_mask
mask = merged_mask(basins,grd.rename({'tlat':'lat', 'tlon':'lon'}))
mask
<xarray.DataArray 'mask' (ny: 480, nx: 540)>
array([[nan, nan, nan, ..., nan, nan, nan],
       [nan, nan, nan, ..., nan, nan, nan],
       [nan, nan, nan, ..., nan, nan, nan],
       ...,
       [nan, nan, nan, ..., nan, nan, nan],
       [nan, nan, nan, ..., nan, nan, nan],
       [nan, nan, nan, ..., nan, nan, nan]])
Dimensions without coordinates: ny, nx
# Find unique values
unique_values = numpy.unique(mask)
unique_values
array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12.,
       nan])

Check mask for all the regions#

for r in unique_values:
    xyplot((mask.where(mask == r)).values, grd.tlon, grd.tlat,
          title='region = {}'.format(str(r)))
../_images/c3b8d40aeb384ae1168d7e77030993835313a5dff6580cf92048d9c1d99b8e6d.png ../_images/cd645b0e29e9905878006c1631253f670d2c9667f426f47cbed0dc7a52cc5946.png ../_images/f8d96a6e34882e6c56dd38b797a18426f0f800153ecb0c2f005895d793a1fd02.png ../_images/e4807cb6b5c4bad5346c471fbec9fc5c5e9b946b45d43dfcc3337f48681140f2.png ../_images/43015352163043f3ce0f7b20e522ebe0160a2caab7748af4f7201f15c1d2513b.png ../_images/727f7c242c8a77c620933ba2239470f16748b5214343d84ca9f6322a6bd3010a.png ../_images/7016f88625d7ca1e4fa3a7ff8401bd72f8b1cf65d975e4129c485d57cc741407.png ../_images/02d2624d3952236a5689fd60b30b9d22450e5138b22404b07fb58b1f2b94f447.png ../_images/3e34458dde0cc0aa9c90b815f1365d80e51863e44cc08c510b706d4c2b3d8df2.png ../_images/1d695c17bdc29c5dfef0d141e2ac79d9a2efb327843de7aec208b17dc277801c.png ../_images/1191b116b31590d5a52c943959b3b36a4ade2327d2f12f8a94581b3d687cc561.png ../_images/6ecca7bd74dc57309aff64e47202c8dc9c54a29223e9e98e4fce534afd6b52f0.png ../_images/d409b26afd26577ca43ac815696dbd94293c72a1f82fad4f620900a30e48d96e.png ../_images/8a79e28b3338675b800a72ec3c589e24e2d5966e88087897d51d15b31453887d.png

Plot all masks in a single map#

mask.plot()
<matplotlib.collections.QuadMesh at 0x145a537a4450>
../_images/899baad129aa6ec0dbefa8f89a782f42b08a30c322e5f99d5ecdbe230b8eca7c.png

Add new basins into basin_code#

Maritime#

# Expand dimensions to match `region` dimension
new_region_mask = xr.where(mask == 4, 1, 0).rename({'ny':'yh', 'nx':'xh'}).fillna(0)

# Assign a new region index (e.g., 14 if original regions are indexed 0-13)
new_region_mask = new_region_mask.expand_dims(dim={"region": [len(basin_code.region)]})  # Change to the appropriate index

# Concatenate with the existing `basin_masks`
basin_code = xr.concat([basin_code, new_region_mask], dim="region")

# Update region name

# Convert region names to a list, modify the last element, and reassign
region_names = basin_code.region.values.tolist()
region_names[-1] = 'Maritime'  # Replace last region name

# Reassign the modified region names to the dataset
basin_code = basin_code.assign_coords(region=("region", region_names))
r = len(basin_code.region)-1
(basin_code[0,:]+basin_code[r,:]*2).values
xyplot((basin_code[0,:]+basin_code[r,:]*2).values, grd.tlon, grd.tlat,
          title=str(basin_code['region'][r].values))
../_images/0cd2aaaffb325a3dcee1e706dcc79fae8345c3383335cbbe84c555da8cbbe837.png

SouthernOcean60S#

# Expand dimensions to match `region` dimension
new_region_mask = xr.where(basin_code.sel(region='SouthernOcean') == 1, 1, 0).where(grd.tlat.rename({'ny':'yh','nx':'xh'})<=-60).fillna(0)

# Assign a new region index (e.g., 14 if original regions are indexed 0-13)
new_region_mask = new_region_mask.expand_dims(dim={"region": [len(basin_code.region)]})  # Change to the appropriate index

# Concatenate with the existing `basin_masks`
basin_code = xr.concat([basin_code, new_region_mask], dim="region")

# Update region name

# Convert region names to a list, modify the last element, and reassign
region_names = basin_code.region.values.tolist()
region_names[-1] = 'SouthernOcean60S'  # Replace last region name

# Reassign the modified region names to the dataset
basin_code = basin_code.assign_coords(region=("region", region_names))
r = len(basin_code.region)-1
(basin_code[0,:]+basin_code[r,:]*2).values
xyplot((basin_code[0,:]+basin_code[r,:]*2).values, grd.tlon, grd.tlat,
          title=str(basin_code['region'][r].values))
../_images/7cea22888a170b7561e7df591c949b6f559b1f956dde790c350a75371eebfa3c.png

Save as netCDF#

# Global attrs
basin_code.attrs['description'] = 'Basin masks for ' + grid_name
basin_code.attrs['author'] = author
basin_code.attrs['date'] = today
basin_code.attrs['infile'] = grd_path
basin_code.attrs['url'] = 'https://github.com/NCAR/tx2_3/basin_masks'
# save
fname = 'basin_masks_{}_{}.nc'.format(grid_name, today)

basin_code.to_netcdf(fname, encoding={'basin_masks': {'_FillValue': None}})