Source code for compass.landice.extrapolate

import sys

import numpy as np
from netCDF4 import Dataset


[docs] def extrapolate_variable(nc_file, var_name, extrap_method, set_value=None): """ Function to extrapolate variable values into undefined regions Parameters ---------- nc_file : str the mpas file to modify var_name : str the mpas variable to extrapolate extrap_method : str idw, min, or value method of extrapolation set_value : float value to set variable to outside keepCellMask when using -v value """ dataset = Dataset(nc_file, 'r+') varValue = dataset.variables[var_name][0, :] # Extrapolation nCells = len(dataset.dimensions['nCells']) if 'thickness' in dataset.variables.keys(): thickness = dataset.variables['thickness'][0, :] bed = dataset.variables["bedTopography"][0, :] cellsOnCell = dataset.variables['cellsOnCell'][:] nEdgesOnCell = dataset.variables['nEdgesOnCell'][:] xCell = dataset.variables["yCell"][:] yCell = dataset.variables["xCell"][:] # Define region of good data to extrapolate from. # Different methods for different variables if var_name in ["effectivePressure", "beta", "muFriction"]: groundedMask = (thickness > (-1028.0 / 910.0 * bed)) keepCellMask = np.copy(groundedMask) extrap_method == "min" # grow mask by one cell oceanward of GL for iCell in range(nCells): for n in range(nEdgesOnCell[iCell]): jCell = cellsOnCell[iCell, n] - 1 if (groundedMask[jCell] == 1): keepCellMask[iCell] = 1 continue # ensure zero muFriction does not get extrapolated keepCellMask *= (varValue > 0) elif var_name in ["floatingBasalMassBal"]: floatingMask = (thickness <= (-1028.0 / 910.0 * bed)) keepCellMask = floatingMask * (varValue != 0.0) extrap_method == "idw" else: keepCellMask = (thickness > 0.0) # make a copy to edit that will be used later keepCellMaskNew = np.copy(keepCellMask) # recursive extrapolation steps: # 1) find cell A with mask = 0 # 2) find how many surrounding cells have nonzero mask, and their # indices (this will give us the cells from upstream) # 3) use the values for nonzero mask upstream cells to extrapolate # the value for cell A # 4) change the mask for A from 0 to 1 # 5) Update mask # 6) go to step 1) print("Start {} extrapolation using {} method".format(var_name, extrap_method)) if extrap_method == 'value': varValue[np.where(np.logical_not(keepCellMask))] = float(set_value) else: while np.count_nonzero(keepCellMask) != nCells: keepCellMask = np.copy(keepCellMaskNew) searchCells = np.where(keepCellMask == 0)[0] varValueOld = np.copy(varValue) for iCell in searchCells: neighborcellID = cellsOnCell[iCell, :nEdgesOnCell[iCell]] - 1 # Important: ignore the phantom "neighbors" that are off # the edge of the mesh (0 values in cellsOnCell) neighborcellID = neighborcellID[neighborcellID >= 0] mask_for_idx = keepCellMask[neighborcellID] # active cellmask mask_nonzero_idx, = np.nonzero(mask_for_idx) # id for nonzero beta cells nonzero_id = neighborcellID[mask_nonzero_idx] nonzero_num = np.count_nonzero(mask_for_idx) assert len(nonzero_id) == nonzero_num if nonzero_num > 0: x_i = xCell[iCell] y_i = yCell[iCell] x_adj = xCell[nonzero_id] y_adj = yCell[nonzero_id] var_adj = varValueOld[nonzero_id] if extrap_method == 'idw': ds = np.sqrt((x_i - x_adj)**2 + (y_i - y_adj)**2) assert np.count_nonzero(ds) == len(ds) var_interp = 1.0 / sum(1.0 / ds) * \ sum(1.0 / ds * var_adj) varValue[iCell] = var_interp elif extrap_method == 'min': varValue[iCell] = np.min(var_adj) else: sys.exit("ERROR: invalid extrapolation scheme! " "Set option m as idw or min!") keepCellMaskNew[iCell] = 1 # print ("{0:8d} cells left for extrapolation in total {1:8d} " # "cells".format(nCells-np.count_nonzero(keepCellMask), nCells)) # Put updated array back into file dataset.variables[var_name][0, :] = varValue dataset.close()