Back to home page

MITgcm

 
 

    


File indexing completed on 2021-04-23 05:12:38 UTC

view on githubraw file Latest commit ce0d9af5 on 2021-04-21 19:30:20 UTC
ce0d9af5ea Jeff*0001 # import python modules
                0002 import numpy as np
                0003 import matplotlib.pyplot as plt
                0004 import netCDF4 as nc
                0005 
                0006 
                0007 ###########   load grid data   ########### 
                0008 
                0009 # Load grid variables; names correspond with MITgcm source code.
                0010 # (if using standard binary output instead of netcdf, these are dumped
                0011 # to individual files, e.g. 'RC.data' etc.)
                0012 # Assumes that output in multiple tiles has been concatenated into
                0013 # global files (used script utils/python/MITgcmutils/scripts/gluemncbig)
                0014 # and moved into the top directory;
                0015 # see MITgcm user manual section 4.2.4.1 
                0016 
                0017 # Using a spherical polar grid, all X,Y variables in lon,lat coordinates
                0018 # vertical grid provided in meters, area in m^2
                0019 
                0020 grid = nc.Dataset('grid.nc')
                0021 #  1-D fields
                0022 RC = grid['RC'][:]    # vertical grid, cell center locations
                0023 drF = grid['drF'][:]  # vertical spacing of grid cells (thickness of cells)
                0024 #  2-D fields (y,x)
                0025 XC = grid['XC'][:]    # x-location of gridcell centers
                0026 YC = grid['YC'][:]    # y-location of gridcell centers
                0027 dyG = grid['dyG'][:]  # grid spacing in y-dim (separation between corners)
                0028 rA = grid['rA'][:]    # surface area of gridcells
                0029 #  3-D fields (z,y,x)
                0030 HFacC = grid['HFacC'][:]  # vertical fraction of cell which is ocean
                0031 
                0032 # For convenience, load additional dimensional variables from
                0033 # netcdf files (these variables are NOT included in binary output)
                0034 # These grid variables are also present in netcdf diagnostic data files.
                0035 # 1-D fields
                0036 X = grid['X'][:]      # 1-D version of XC data
                0037 Y = grid['Y'][:]      # 1-D version of YC data
                0038 Xp1 = grid['Xp1'][:]  # x-location of lower left corner
                0039 Yp1 = grid['Yp1'][:]  # y-location of lower left corner
                0040 # Xp1 and Yp1 are effectively 1-D versions of grid variables XG,YG with
                0041 # an extra data value at the eastern and northern ends of the domain.
                0042 # See MITgcm users manual section 2.11 for additional MITgcm grid info
                0043 
                0044 # Number of gridcells in x,y for full domain:
                0045 Nx = X.size
                0046 Ny = Y.size
                0047 # out-of-the-box tutorial configuration is 62x62
                0048 
                0049 
                0050 ###########   load diagnostics   ########### 
                0051 
                0052 # unit for temperature is degrees Celsius, velocity in m/s,
                0053 # surface height in m, heat flux in W/m^2
                0054 # see run output file available_diagnostics.log
                0055    
                0056 # load statistical diagnostic output (set to monthly time-avg output)
                0057 # only one output region is defined: global (the default)
                0058 dynStDiag = nc.Dataset('dynStDiag.nc')
                0059 TRELAX_ave = dynStDiag['TRELAX_ave'][:]      # (time, region, depth); region=0 (global), depth=0 (surf-only)
                0060 THETA_lv_ave = dynStDiag['THETA_lv_ave'][:]  # (time, region, depth); region=0 (global)
                0061 THETA_lv_std = dynStDiag['THETA_lv_std'][:]  # (time, region, depth); region=0 (global)
                0062   
                0063 # load 2-D and 3-D variable diagnostic output, annual mean data
                0064 surfDiag = nc.Dataset('surfDiag.nc')
                0065 TRELAX = surfDiag['TRELAX'][:]  # (time, depth, y, x); depth=0 (surface-only)
                0066 ETAN = surfDiag['ETAN'][:]      # (time, depth, y, x); depth=0 (surface-only)
                0067 dynDiag = nc.Dataset('dynDiag.nc')
                0068 UVEL = dynDiag['UVEL'][:]       # (time, depth, y, x); x dim is Nx+1, includes eastern edge
                0069 VVEL = dynDiag['VVEL'][:]       # (time, depth, y, x); y dim is Ny+1, includes northern edge
                0070 THETA = dynDiag['THETA'][:]     # (time, depth, y, x)
                0071  
                0072 
                0073 ###########   plot diagnostics   ########### 
                0074 
                0075 # figure 4.6 - time series of global mean TRELAX and THETA by level
                0076 #
                0077 # plot THETA at MITgcm k levels 1,5,15 (SST, -305 m, -1705 m)
                0078 klevs = [0, 4, 14]
                0079 
                0080 # MITgcm time unit (dim='T') is seconds, so create new time series
                0081 # for (dynStDiag) monthly time averages and convert into years.
                0082 # Note that the MITgcm time array values correspond to time at the end
                0083 # of the time-avg periods, i.e. subtract 1/24 to plot at mid-month.
                0084 Tmon = dynStDiag['T'][:]/(86400*360) - 1/24 
                0085 # and repeat to create time series for annual mean time output,
                0086 # subtract 0.5 to plot at mid-year.
                0087 Tann = surfDiag['T'][:]/(86400*360) - 0.5
                0088 
                0089 plt.figure(figsize=(16,10))
                0090 # global mean TRELAX
                0091 plt.subplot(221)
                0092 plt.plot(Tmon, TRELAX_ave[:,0,0], 'b', linewidth=4)
                0093 plt.grid('both')
                0094 plt.title('a) Net Heat Flux into Ocean (TRELAX_ave)')
                0095 plt.xlabel('Time (yrs)')
                0096 plt.ylabel('$\mathregular{W/m^2}$')
                0097 plt.xlim(0, np.ceil(Tmon[-1]))
                0098 plt.ylim(-400, 0)
                0099 # Alternatively, a global mean area-weighted TRELAX (annual mean)
                0100 # could be computed as follows, using HfacC[0,:,:], i.e. HfacC in
                0101 # the surface layer, as a land-ocean mask.
                0102 # First, compute total surface area of ocean points:
                0103 total_ocn_area = (rA * HFacC[0,:,:]).sum()
                0104 # numpy is often smart enough to figure out broadcasting,
                0105 # depending on axis position.
                0106 # In next line, note a np.tile command is NOT necessary to span
                0107 # the grid array across the time axis:
                0108 TRELAX_ave_ann = (TRELAX[:,0,:,:] * rA * HFacC[0,:,:]).sum((1,2)) / total_ocn_area
                0109 plt.plot(Tann, TRELAX_ave_ann, 'm--', linewidth=4)
                0110 
                0111 plt.subplot(223)
                0112 plt.plot(Tmon, THETA_lv_ave[:,0,klevs], linewidth=4)
                0113 # To specify colors for specific lines, either change the
                0114 # default a priori, e.g. ax.set_prop_cycle(color=['r','g','c'])
                0115 # or after the fact, e.g. lh[0].set_color('r') etc.
                0116 plt.grid('both')
                0117 plt.title('b) Mean Potential Temp. by Level (THETA_lv_avg)')
                0118 plt.xlabel('Time (yrs)')
                0119 plt.ylabel('$\mathregular{^oC}$')
                0120 plt.xlim(0, np.ceil(Tmon[-1]))
                0121 plt.ylim(0, 30)
                0122 plt.legend(RC[klevs], title='Z (m)')
                0123 
                0124 plt.subplot(224)
                0125 plt.plot(Tmon, THETA_lv_std[:,0,klevs], linewidth=4)
                0126 plt.grid('both')
                0127 plt.title('c) Std. Dev. Potential Temp. by Level (THETA_lv_std)')
                0128 plt.xlabel('Time (years)')
                0129 plt.ylabel('$\mathregular{^oC}$')
                0130 plt.xlim(0, np.ceil(Tmon[-1]))
                0131 plt.ylim(0, 8)
                0132 plt.legend(RC[klevs], title='Z (m)')
                0133 plt.show()
                0134 
                0135 # figure 4.7 - 2-D plot of TRELAX and contours of free surface height
                0136 # (ETAN) at simulation end ( endTime = 3110400000. is t=100 yrs).
                0137 #
                0138 eta_masked = np.ma.MaskedArray(ETAN[-1,0,:,:], HFacC[0,:,:]==0)
                0139 plt.figure(figsize=(10,8)) 
                0140 plt.pcolormesh(Xp1, Yp1, TRELAX[-1,0,:,:], cmap='RdBu_r')
                0141 plt.xlim(0, 60)
                0142 plt.ylim(15, 75)
                0143 plt.colorbar()
                0144 plt.clim(-250, 250)
                0145 plt.contour(X, Y, eta_masked, levels=np.r_[-.6:.7:.1], colors='black')
                0146 plt.title('Free surface height (contours, CI .1 m) and '
                0147           'TRELAX (shading, $\mathregular{W/m^2}$)')
                0148 plt.xlabel('Longitude')
                0149 plt.ylabel('Latitude')
                0150 plt.show()
                0151 # Note we have used routine pcolormesh with Xp1, Yp1, which are the
                0152 # locations of the lower left corners of grid cells
                0153 # (here, length Nx+1,Ny+1 as they include the ending right and upper
                0154 # locations of the grid, respectively).
                0155 # Alternative one could plot shading using contourf with dimensions
                0156 # X and Y, the grid cell center locations.
                0157 # Also note we mask the land values when contouring the free
                0158 # surface height.
                0159 
                0160 # figure 4.8 - barotropic streamfunction, plot at simulation end
                0161 # (w/overlaid labeled contours)
                0162 #
                0163 ubt = (UVEL * drF[:,np.newaxis,np.newaxis]).sum(1)  # depth-integrated u velocity
                0164 # For ubt calculation numpy needs a bit of help with broadcasting
                0165 # the drF vector across [time,y,x] axes
                0166 psi = np.zeros((dynDiag['T'].size, Ny+1, Nx+1))
                0167 psi[:,1:,:] = (-ubt * dyG).cumsum(1) / 1E6  # compute streamfn in Sv (for each yr)
                0168 # Note psi is computed and plotted at the grid cell corners and we
                0169 # compute as dimensioned (Ny,Nx+1); as noted, UVEL contains an extra
                0170 # data point in x, at the eastern edge. cumsum is done in y-direction.
                0171 # We have a wall at southern boundary (i.e. no reentrant flow from
                0172 # north), ergo psi(j=0) is accomplished by declaring psi 
                0173 # to be shape (dynDiag['T'].size,Ny+1,Nx+1). 
                0174 
                0175 plt.figure(figsize=(10,8))
                0176 plt.contourf(Xp1, Yp1, psi[-1], np.arange(-35, 40, 5), cmap='RdYlBu_r')
                0177 plt.colorbar()
                0178 cs = plt.contour(Xp1, Yp1, psi[-1], np.arange(-35, 40, 5), colors='black')
                0179 plt.clabel(cs, fmt = '%.0f')
                0180 plt.xlim(0, 60)
                0181 plt.ylim(15, 75)
                0182 plt.title('Barotropic Streamfunction (Sv)')
                0183 plt.xlabel('Longitude')
                0184 plt.ylabel('Latitude');
                0185 plt.show()
                0186 
                0187 # figure 4.9 - potential temp at depth and xz slice, at simulation end
                0188 #
                0189 # plot THETA at MITgcm k=4 (220 m depth) and j=15 (28.5N)
                0190 klev =  3
                0191 jloc = 14
                0192 
                0193 theta_masked = np.ma.MaskedArray(THETA[-1, klev,:,:], HFacC[klev,:,:]==0)
                0194 plt.figure(figsize=(16,6))
                0195 plt.subplot(121)
                0196 # again we use pcolor for the plan view and provide the
                0197 # corner point locations XG,YG thru Xp1,Yp1
                0198 plt.pcolormesh(Xp1, Yp1, THETA[-1,klev,:,:], cmap='coolwarm')
                0199 plt.clim(0, 30)
                0200 plt.colorbar()
                0201 # but to overlay contours we provide the cell centers
                0202 # and mask out boundary/land cells
                0203 plt.contour(X, Y, theta_masked, np.arange(0,30,2), colors='black')
                0204 plt.title('a) THETA at %g m Depth ($\mathregular{^oC}$)' %RC[klev])
                0205 plt.xlim(0, 60)
                0206 plt.ylim(15, 75)
                0207 plt.xlabel('Longitude')
                0208 plt.ylabel('Latitude')
                0209 
                0210 # For the xz slice, our limited vertical resolution makes for an ugly
                0211 # pcolor plot, we'll shade using contour instead, providing the centers
                0212 # of the vertical grid cells and cell centers in the x-dimension.
                0213 # Also mask out land cells at the boundary, which results in slight
                0214 # white space at domain edges.
                0215 theta_masked = np.ma.MaskedArray(THETA[-1,:,jloc,:], HFacC[:,jloc,:]==0)
                0216 plt.subplot(122)
                0217 plt.contourf(X, RC, theta_masked, np.arange(0,30,.2), cmap='coolwarm')
                0218 plt.colorbar()
                0219 plt.contour(X, RC, theta_masked, np.arange(0,32,2), colors='black')
                0220 plt.title('b) THETA at %gN ($\mathregular{^oC}$)' %YC[jloc,0])
                0221 plt.xlim(0, 60)
                0222 plt.ylim(-1800, 0)
                0223 plt.xlabel('Longitude')
                0224 plt.ylabel('Depth (m)')
                0225 plt.show()
                0226 # One approach to avoiding the white space at boundaries/top/bottom
                0227 # is to copy neighboring tracer values to land cells prior to contouring
                0228 # (and don't mask), and augment a row of z=0 data at the ocean surface
                0229 # and a row at the ocean bottom.
                0230 # (see tutorial Southern Ocean Reentrant Channel for an example)
                0231 # The white space occurs because contour uses data at cell centers, with
                0232 # values masked/undefined beyond the cell centers toward boundaries.
                0233 
                0234 # To instead plot using pcolor, pass location of vertical cell faces RF:
                0235 # RF=grid['RF'][:]
                0236 # plt.pcolormesh(Xp1, RF, THETA[-1,:,jloc,:], cmap='coolwarm')
                0237 
                0238 
                0239 # Note, the gluemncbig steps outlined in tutorial section 4.2.4.1 can be
                0240 # avoided by using the python package "MITgcmutils". Loading the grid
                0241 # and diagnostic output, in place of steps at the beginning of this
                0242 # script, can be accomplished by reading directly from the mnc output
                0243 # directories:
                0244 #
                0245 # from MITgcmutils import mnc
                0246 # grid=mnc.mnc_files('mnc_test_*/grid.t*.nc')
                0247 # XC=grid.variables['XC'][:]
                0248 # ...
                0249 # dynStDiag=mnc.mnc_files('mnc_test_*/dynStDiag.0000000000.t*.nc')
                0250 # TRELAX_ave=dynStDiag.variables['TRELAX_ave'][:]
                0251 # ...
                0252 # surfDiag=mnc.mnc_files('mnc_test_*/surfDiag.0000000000.t*.nc')
                0253 # TRELAX=surfDiag.variables['TRELAX'][:]
                0254 # ...
                0255 # dynDiag=mnc.mnc_files('mnc_test_*/dynDiag.0000000000.t*.nc')
                0256 # THETA=dynDiag.variables['THETA'][:]
                0257 # ...
                0258 
                0259 # An advantage using mnc_files() is that you aren't required to waste
                0260 # disk space assembling glued files. See MITgcm users manual chapter 11
                0261 # for reference information on MITgcmutils. Note mnc_file() will
                0262 # generally NOT work with wildcard mnc_test_* directories from multiple
                0263 # runs are present unless you pass it the specific directories to read,
                0264 # e.g. for a 4-core mpi run output in mnc_test_0009 thru mnc_test_0012:
                0265 # dynStDiag=mnc.mnc_files('mnc_test_{0009..0012}/dynStDiag.0000000000.t*.nc')