def vbyz(dgl): """Calculate the effect on stratification of differential meridional buoyancy fluxes""" #First ensure that the correct vertical field is present fld_exists = mit.check_field(dgl,'pvz') if not fld_exists: dgl = mit.add_field(dgl,'pvz') zlen = len(dgl[0]['z']) dgl[0]['pvz'] = 0.5*(dgl[0]['z'][0:zlen-1] + dgl[0]['z'][1:zlen]) import eosmit #This routine checks if buoyancy is already loaded before running eos = 'jmd' dgl = eosmit.buoy_dgl(dgl,eos=eos) fld_exists = mit.check_field(dgl,'vbxz') if not fld_exists: dgl = mit.add_field(dgl,'vbyz') dgl[0]['vbyz'] = dgl[0]['v']*mit.ddy(dgl[0]['b'],dgl[0]['y']) return dgl
def ldgl( tims, levs, diag_file, diag_name, search_folders=None, ylims=None, xlims=None, eos="None", normf=False, alpha=2e-4, sbeta=7.4e-4, len_dgl=1, ): """ Mandatory input fields: tims - a list of the times when output is wanted in days e.g. np.arange(0,10,1e-1) Can also be given as an int/float/long that is converted to a list. levs - a list of the model levels where output is wanted e.g. np.arange(0,100) where 0 is the surface level and 100 is the deepest level. Can also be given as an int/float/long that is converted to a list. diag_file - a string that allows unique identification of the output files. For state files (e.g. state.0000000000.t0001.nc) this must be 'st', otherwise can be 'pv', for example, if the output files are called 'pvDiag.0000000000.t001.nc'. diag_name - a list of strings that set the fields that will be read from the model. For ease of use, one letter shortcuts are used and converted to the proper model names in the function 'get_full_diag_name' below e.g. ['u','s'] loads u velocity and salt. Optional input fields: search_folders - a two element list setting the number of the first and last of the mnc_tile_xxxx folders to be read from e.g. [1, 24] (note 1-based indexing for the tile numbers). ylims - a two element list that specifies the lower and upper bounds to load in **kilometres**. Note that closest tile boundary to the limits is found rather than the closest grid point to avoid reading in partial tiles. xlims - as for ylims. eos - string. Needed if buoyancy is wanted. Can be 'lin' for a linear equation of state or 'jmd' for Jackett and McDougall (1995). No default is specified to ensure the user chooses. Procedure Load the desired model output as a structured array. First get the overall model attributes and use this to create the model grid. Then adapt the desired output times (called 'tims') to the actual model output times. If x or y limits have been specified, set the tile limits accordingly. Then pre-allocate the output structured array (called 'dgl'). Load the grid and time output into the output structured array. Then load in the model diagnostic fields into the output structured array. Finally, add any fields that are calculated from other outputs to the output structured array. Glossary "Job" refers to a batch of outputs from breaking a simulation into a series of model runs. If there are 24 tiles and 3 jobs, the output will be in files mnc_tile_0001 to mnc_tile_0072. """ # First make sure that input parameters are lists and convert them if not if isinstance(tims, (int, long, float)): tims = [tims] if isinstance(levs, (int, long, float)): levs = [levs] if isinstance(diag_name, (str)): diag_name = [diag_name] # Find the range of tile output files to examine. This can be specified # as an optional input to improve speed or exclude certain files if search_folders is None: search_folders = [int(sorted(glob.glob("mnc_tile*"))[0][-4:])] search_folders.append(int(sorted(glob.glob("mnc_tile*"))[-1][-4:])) # Get the overall attributes of the domain from a grid file - parameters set initially in SIZE.h nx, ny, sx, sy, px, py = read_grid_atts(search_folders, diag_file) # Define a variable that captures the number of tiles for each job tile_interval = px * py ## Construct the grid - horizontal then vertical. This is done using # the first grid tile only for the doubly-periodic set-up. x, dx, y, dy, depths, f = make_grid_hor(search_folders, diag_file, nx, ny) z, levs = make_grid_vert(search_folders, depths, diag_file, levs) # Now establish at what times the model outputs occur. Have further lists # that record what job each output time occurred in (tjobs), # what file in a folder it corresponds to (tfiles) # and what time point in that file it corresponds to (tpoints). t, tjobs, tfiles, tpoints = find_output_times(search_folders, diag_file, tile_interval) # Convert the index values to integers tjobs = tjobs.astype(int) tfiles = tfiles.astype(int) tpoints = tpoints.astype(int) # Change the input time series (tims) to match the range of values for which # there is model output tims = chop_tims(tims, t) # Align input times (tims) with model times (t). Have further lists that # record the job number, file number and time point in the file these are found at. tims, tjs, fls, pts = align_tims(tims, t, tjobs, tfiles, tpoints) # Re-set range of search tiles to omit those outside the time range. search_folders = np.arange(tjs[0], tjs[-1] + tile_interval) if ylims is not None: # If we want to specify y-limits... # Make the list of files we actually want to extract output # from - these relate to the numbers at the end of the .nc files, # not the random number of the tile directories # 0-based index rl, ru = find_row_range(nx, ny, sx, sy, px, py, x, dx, y, dy, ylims) y = y[rl * sy : ((ru + 1) * sy)] else: # otherwise if no y-limits specified then just take all the rows rl = 0 ru = (ny / sy) - 1 if xlims is not None: # If we want to specify x-limits... # Make the list of files we actually want to extract output # from - these relate to the numbers at the end of the .nc files, # not the random number of the tile directories # 0-based index cl, cu = find_col_range(nx, ny, sx, sy, px, py, x, dx, y, dy, xlims) x = x[cl * sx : ((cu + 1) * sx)] else: # otherwise if no y-limits specified then just take all the rows cl = 0 cu = (nx / sx) - 1 if xlims or ylims is not None: # If we have specified y-limits or x-limits then constrain the list of # output tiles we want to read from in read_diag below. output_folder_list = [] for rws in np.arange(rl, ru + 1): output_folder_list = np.hstack((output_folder_list, px * (rws) + np.arange(cl + 1, cu + 2))) else: output_folder_list = np.arange(1, tile_interval + 1) # A set of handy variables used repeatedly below xlen = len(x) ylen = len(y) zlen = len(z) tlen = len(tims) # Create the shape of the output array dty_info = [ ("tims", np.float32, np.shape(tims)), ("x", np.float32, np.shape(x)), ("y", np.float32, np.shape(y)), ("z", np.float32, np.shape(z)), ("f", np.float32, np.shape(f)), ] # Specify the initial list of grid output fields. out_diags = [] calc_diags = [] model_name = [] # Add the desired diagnostic fields to the pre-allocation array and field list. for dindx, diag in enumerate(diag_name): if diag is "n2" or diag is "pv" or diag is "pv1" or diag is "pv2" or diag is "pv3" or diag is "rib": """Shorten the vertical length for fields that have a first-order #vertical derivative.""" zl = zlen - 1 else: """Else just use the full z-length""" zl = zlen # Add the diagnostic to the pre-allocation array. Use float32 in line # with 32-bit model outputs. dty_info.append((diag_name[dindx], np.float32, [ylen, xlen, zl, tlen])) if ( diag == "rv" or diag == "rvf" or diag == "b" or diag == "n2" or diag == "pv" or diag == "pv1" or diag == "pv2" or diag == "pv3" or diag == "rib" ): calc_diags.append(diag) else: out_diags.append(diag) model_name.append(get_full_diag_name(diag_file, diag)) ## Load the output array dgl with the grid variables dgl = np.zeros((len_dgl,), dtype=dty_info) dgl[0]["tims"][:] = tims dgl[0]["x"][:] = x dgl[0]["y"][:] = y dgl[0]["z"][:] = z dgl[0]["f"][:] = f ## Load all the diagnostics together to avoid large overhead of opening/closing netcdf files dgl = read_diag( search_folders, tile_interval, output_folder_list, cl, rl, tjs, fls, pts, levs, diag_file, out_diags, model_name, dgl, ) if calc_diags: for cld in calc_diags: if cld == "rv": import pvmit dgl = pvmit.rv(dgl, normf) elif cld == "rvf": import pvmit dgl = pvmit.rv(dgl, normf=True) if cld == "b" or cld == "n2" or cld == "rib": import eosmit dgl = eosmit.buoy_dgl(dgl, eos=eos, alpha=alpha, sbeta=sbeta) if cld[0:2] == "n2" or cld[0:2] == "pv": import eosmit dgl = eosmit.buoy_dgl(dgl, eos=eos, alpha=alpha, sbeta=sbeta) if cld == "n2": import pvmit dgl = pvmit.n2(dgl) if cld == "pv1": import pvmit dgl = pvmit.pv1(dgl) if cld == "pv2": import pvmit dgl = pvmit.pv2(dgl) if cld == "pv3": import pvmit dgl = pvmit.pv3(dgl) if cld == "rib": import pvmit dgl = pvmit.rib(dgl) if cld == "pv": import pvmit dgl = pvmit.pv(dgl) return dgl