def second_order_river(self, d): jmax = self.input.v('grid', 'maxIndex', 'x') kmax = self.input.v('grid', 'maxIndex', 'z') fmax = self.input.v('grid', 'maxIndex', 'f') ftot = 2 * fmax + 1 ################################################################################################################ # Forcing terms ################################################################################################################ F = np.zeros([jmax + 1, kmax + 1, ftot, 1], dtype=complex) Fsurf = np.zeros([jmax + 1, 1, ftot, 1], dtype=complex) Fbed = np.zeros([jmax + 1, 1, ftot, 1], dtype=complex) # erosion if self.input.v('u1', 'river') is not None: E = erosion(self.ws, 2, self.input, self.erosion_method, submodule=(None, 'river', None), friction=self.frictionpar) Fbed[:, :, fmax:, 0] = -E ################################################################################################################ # Solve equation ################################################################################################################ cmatrix = self.input.v('cMatrix') if cmatrix is not None: c, cMatrix = cFunction(None, cmatrix, F, Fsurf, Fbed, self.input, hasMatrix=True) else: c, cMatrix = cFunction(self.ws, self.Kv, F, Fsurf, Fbed, self.input, hasMatrix=False) c = c.reshape((jmax + 1, kmax + 1, ftot)) else: c = np.zeros((jmax + 1, kmax + 1, ftot)) d['hatc2'] = {} d['hatc2']['a'] = {} d['hatc2']['a']['erosion'] = {} d['hatc2']['a']['erosion'][ 'river_river'] = ny.eliminateNegativeFourier(c, 2) return d
def component(self, ws, Kv, Kh): jmax = self.input.v('grid', 'maxIndex', 'x') kmax = self.input.v('grid', 'maxIndex', 'z') fmax = self.input.v('grid', 'maxIndex', 'f') z = ny.dimensionalAxis(self.input.slice('grid'), 'z')[:, :, 0] depth = (self.input.v('grid', 'low', 'z', range(0, jmax+1)) - self.input.v('grid', 'high', 'z', range(0, jmax+1))).reshape((jmax+1, 1)) B = self.input.v('B', range(0, jmax+1)) u0 = self.input.v('u0', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1)) w0 = self.input.v('w0', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1)) zeta0 = self.input.v('zeta0', range(0, jmax+1), [0], range(0, fmax+1)) ################################################################################################################ # Leading order ################################################################################################################ Chat = np.zeros((jmax+1, kmax+1, fmax+1), dtype=complex) if ws[0,0] != 0: k = depth*ws[:, [-1]]/Kv[:, [-1]]*(1-np.exp(-ws[:, [-1]]/Kv[:, [-1]]*depth))**-1. else: k = 1 Chat[:, :, 0] = k*np.exp(-ws[:, [-1]]/Kv[:, [-1]]*(z+depth)) # k is such that depth-av Chat = 1. Chatx = ny.derivative(Chat, 'x', self.input.slice('grid')) Chatz = -(ws[:, [-1]]/Kv[:, [-1]]).reshape((jmax+1, 1, 1))*Chat ################################################################################################################ # First order ################################################################################################################ F = np.zeros((jmax+1, kmax+1, 2*fmax+1, 2), dtype=complex) Fsurf = np.zeros((jmax+1, 1, 2*fmax+1, 2), dtype=complex) Fbed = np.zeros((jmax+1, 1, 2*fmax+1, 2), dtype=complex) ## forcing terms # advection F[:, :, fmax:, 0] = -ny.complexAmplitudeProduct(u0, Chatx, 2) - ny.complexAmplitudeProduct(w0, Chatz, 2) F[:, :, fmax:, 1] = -ny.complexAmplitudeProduct(u0, Chat, 2) ## solve Chat1, _ = pFunction(1, ws, Kv, F[:, :, fmax+1], Fsurf[:, :, fmax+1], Fbed[:, :, fmax+1], self.input) Chat1 = ny.eliminateNegativeFourier(Chat1, 2) ################################################################################################################ # Closure ################################################################################################################ # transport T = {} T['adv'] = {} T['adv']['tide'] = np.real(ny.integrate(ny.complexAmplitudeProduct(u0, Chat1[:, :, :, 0], 2), 'z', kmax, 0, self.input.slice('grid'))[:, 0, 0]*B) for key in self.input.getKeysOf('u1'): utemp = self.input.v('u1', key, range(0, jmax+1), range(0, kmax+1), range(0, fmax+1)) try: T['adv'][key] += np.real(ny.integrate(ny.complexAmplitudeProduct(utemp, Chat, 2), 'z', kmax, 0, self.input.slice('grid'))[:, 0, 0]*B) except: T['adv'][key] = np.real(ny.integrate(ny.complexAmplitudeProduct(utemp, Chat, 2), 'z', kmax, 0, self.input.slice('grid'))[:, 0, 0]*B) T['dif'] = - np.real(ny.integrate(ny.complexAmplitudeProduct(Kh, Chatx, 2), 'z', kmax, 0, self.input.slice('grid'))[:, 0, 0]*B) T['noflux'] = np.real(ny.complexAmplitudeProduct(ny.complexAmplitudeProduct(u0[:, [0], :], Chat[:, [0], :], 2), zeta0, 2)[:, 0, 0]*B) F = {} F['adv'] = {} F['adv']['tide'] = np.real(ny.integrate(ny.complexAmplitudeProduct(u0, Chat1[:, :, :, -1], 2), 'z', kmax, 0, self.input.slice('grid'))[:, 0, 0]*B) F['dif'] = - np.real(Kh[:, 0]*depth[:, 0]*B) H1 = np.real(depth[:, 0]*B) return T, F, H1, Chat[:, :, 0]
def run(self): self.logger.info('Running module SedDynamic - first order') d = {} jmax = self.input.v('grid', 'maxIndex', 'x') kmax = self.input.v('grid', 'maxIndex', 'z') fmax = self.input.v('grid', 'maxIndex', 'f') ftot = 2*fmax+1 OMEGA = self.input.v('OMEGA') self.submodulesToRun = ny.toList(self.input.v('submodules')) method = self.input.v('erosion_formulation') frictionpar = self.input.v('friction') # friction parameter used for the erosion, by default the total roughness if frictionpar == None: frictionpar = 'Roughness' ################################################################################################################ # Left hand side ################################################################################################################ Av = self.input.v('Av', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1)) Kv = self.input.v('Kv', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1)) # NB. If Kv is not provided on input, use the module DiffusivityUndamped to compute it. This is a fix for making this module easier to use. if Kv is None: from DiffusivityUndamped import DiffusivityUndamped sr = self.input.v('sigma_rho') if sr is None: # add Prandtl-Schmidt number if it does not exist self.input.addData('sigma_rho', 1.) md = DiffusivityUndamped(self.input) self.input.merge(md.run()) Kv = self.input.v('Kv', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1)) d['Kv'] = Kv ws = self.input.v('ws0', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1)) ################################################################################################################ # Forcing terms ################################################################################################################ if 'sedadv' in self.submodulesToRun and 'sedadv_ax' not in self.submodulesToRun: self.submodulesToRun.append('sedadv_ax') # determine number of submodules nRHS = len(self.submodulesToRun) if 'erosion' in self.submodulesToRun: keysu1 = self.input.getKeysOf('u1') try: keysu1.remove('mixing') # flow due to 'mixing' should not be included in the erosion term except: pass self.submodulesToRun.remove('erosion') #move to the end of the list self.submodulesToRun.append('erosion') nRHS = nRHS - 1 + len(self.input.getKeysOf('u1')) F = np.zeros([jmax+1, kmax+1, ftot, nRHS], dtype=complex) Fsurf = np.zeros([jmax+1, 1, ftot, nRHS], dtype=complex) Fbed = np.zeros([jmax+1, 1, ftot, nRHS], dtype=complex) c0 = self.input.v('hatc0') cx0 = self.input.d('hatc0', dim='x') cz0 = self.input.d('hatc0', dim='z') # 1. Erosion if 'erosion' in self.submodulesToRun: # erosion due to first-order bed shear stress # E = erosion(ws, Av, 1, self.input, method) # 24-04-2017 Obsolete # Fbed[:, :, fmax:, self.submodulesToRun.index('erosion')] = -E # 24-04-2017 Obsolete for submod in keysu1: E = erosion(ws, 1, self.input, method, submodule=(None, submod), friction=frictionpar) Fbed[:, :, fmax:, len(self.submodulesToRun)-1 + keysu1.index(submod)] = -E # 2. Advection if 'sedadv' in self.submodulesToRun: u0 = self.input.v('u0', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1)) w0 = self.input.v('w0', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1)) eta = ny.complexAmplitudeProduct(u0, cx0, 2)+ny.complexAmplitudeProduct(w0, cz0, 2) F[:, :, fmax:, self.submodulesToRun.index('sedadv')] = -eta F[:, :, fmax:, self.submodulesToRun.index('sedadv_ax')] = -ny.complexAmplitudeProduct(u0, c0, 2) # 3. First-order fall velocity if 'fallvel' in self.submodulesToRun: # surface and internal terms ws1 = self.input.v('ws1', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1)) ksi = ny.complexAmplitudeProduct(ws1, c0, 2) ksiz = ny.derivative(ksi, 'z', self.input.slice('grid')) zeta0 = self.input.v('zeta0', range(0, jmax+1), 0, range(0, fmax+1)) F[:, :, fmax:, self.submodulesToRun.index('fallvel')] = ksiz Fsurf[:, 0, fmax:, self.submodulesToRun.index('fallvel')] = -ny.complexAmplitudeProduct(ksiz[:,0,:], zeta0, 1) # adjustment to erosion E = erosion(ws1, 0, self.input, method, friction=frictionpar) Fbed[:, :, fmax:, self.submodulesToRun.index('fallvel')] = -E # 4. First-order eddy diffusivity if 'mixing' in self.submodulesToRun: # surface, bed and internal terms Kv1 = self.input.v('Kv1', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1)) psi = ny.complexAmplitudeProduct(Kv1, cz0, 2) psiz = ny.derivative(psi, 'z', self.input.slice('grid')) F[:, :, fmax:, self.submodulesToRun.index('mixing')] = psiz Fsurf[:, 0, fmax:, self.submodulesToRun.index('mixing')] = -psi[:, 0, :] Fbed[:, 0, fmax:, self.submodulesToRun.index('mixing')] = -psi[:, -1, :] # adjustment to erosion E = erosion(ws, 1, self.input, method, submodule=(None, 'mixing'), friction=frictionpar) Fbed[:, :, fmax:, self.submodulesToRun.index('mixing')] = -E # 5. No-flux surface correction if 'noflux' in self.submodulesToRun: zeta0 = self.input.v('zeta0', range(0, jmax+1), [0], range(0, fmax+1)) D = np.zeros((jmax+1, 1, fmax+1, fmax+1), dtype=complex) D[:, :, range(0, fmax+1), range(0, fmax+1)] = np.arange(0, fmax+1)*1j*OMEGA Dc0 = ny.arraydot(D, c0[:, [0], :]) chi = ny.complexAmplitudeProduct(Dc0, zeta0, 2) Fsurf[:, :, fmax:, self.submodulesToRun.index('noflux')] = -chi ################################################################################################################ # Solve equation ################################################################################################################ cmatrix = self.input.v('cMatrix') if cmatrix is not None: c, cMatrix = cFunction(None, cmatrix, F, Fsurf, Fbed, self.input, hasMatrix = True) else: c, cMatrix = cFunction(ws, Kv, F, Fsurf, Fbed, self.input, hasMatrix = False) c = c.reshape((jmax+1, kmax+1, ftot, nRHS)) c = ny.eliminateNegativeFourier(c, 2) ################################################################################################################ # Prepare output ################################################################################################################ d['hatc1'] = {} d['hatc1']['a'] = {} d['hatc1']['ax'] = {} for i, submod in enumerate(self.submodulesToRun): if submod == 'sedadv_ax': d['hatc1']['ax']['sedadv'] = c[:, :, :, i] elif submod == 'erosion': d['hatc1']['a']['erosion'] = {} for j, subsubmod in enumerate(keysu1): d['hatc1']['a']['erosion'][subsubmod] = c[:, :, :, len(self.submodulesToRun)-1+j] else: d['hatc1']['a'][submod] = c[:, :, :, i] if 'sedadv' not in self.submodulesToRun: d['hatc1']['ax'] = 0 return d
def svarFunction(Kv, F, Fsurf, Fbed, data, hasMatrix=False): """Solve a function Ds - (Kv s_z)_z = -u0_z + F subject to Kv s_z (-H) = Fbed Kv s_z (0) = Fsurf The returned solution has a part 'sCoef' and 'szCoef' for the forcing by u_z and a part 'sForced' and 'szForced' for the forcing by F, Fbed and Fsurf. Args: Kv: (ndarray(jmax+1, kmax+1, fmax+1)) - data on eddy diffusivity or a salinityMatrix as calculated before by this function. F: (ndarray(jmax+1, kmax+1, fmax+1, nRHS)) - interior forcing. nRHS is the number of individual forcing components Fsurf: (ndarray(jmax+1, 1, fmax+1, nRHS)) - surface forcing. nRHS is the number of individual forcing components Fbed: (ndarray(jmax+1, 1, fmax+1, nRHS)) - surface forcing. nRHS is the number of individual forcing components data: (DataContainer) - should at least contain 'grid', 'OMEGA' and 'u0' hasMatrix: (bool) - if True then it is assumed that Kv contains a salinityMatrix as calculated by this function before. The matrix is not computed again, which saves time. Returns: sCoef and szCoef: (ndarray(jmax+1, kmax+1, fmax+1, 1)) the solution s and its vertical derivative for the forcing by u0_z. the final dimension '1' denotes a single forcing component. sForced and szForced: (ndarray(jmax+1, kmax+1, fmax+1, nRHS)) the solution s and its vertical derivative for the other forcings. the solution is separated for each RHS term in F, Fsurf and Fbed. salinityMatrix: matrix used in computation. Can be reused for subsequent calls of this function. """ # Init jmax = data.v('grid', 'maxIndex', 'x') # maximum index of x grid (jmax+1 grid points incl. 0) kmax = data.v('grid', 'maxIndex', 'z') # maximum index of z grid (kmax+1 grid points incl. 0) fmax = data.v('grid', 'maxIndex', 'f') # maximum index of f grid (fmax+1 grid points incl. 0) OMEGA = data.v('OMEGA') uz = data.d('u0', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1), dim='z') u0bed = data.v('u0', range(0, jmax+1), [-1], range(0, fmax+1)) ftot = 2*fmax+1 # Determine bandwidth of eddy viscosity matrix bandwidth = 0 for n in np.arange(fmax, -1, -1): if np.any(abs(Kv[:, :, n]) > 0): bandwidth = max(bandwidth, n) # Init Ctd nRHS = F.shape[-1] salinityMatrix = np.empty([jmax+1, 2*ftot+2*bandwidth+1, ftot*(kmax+1)], dtype=complex) szCoef = np.zeros([jmax+1, kmax+1, fmax+1, 1], dtype=complex) szForced = np.zeros([jmax+1, kmax+1, fmax+1, nRHS], dtype=complex) # build, save and solve the velocity matrices in every water column for j in range(0, jmax+1): # dz vectors dz = (data.v('grid', 'axis', 'z')[0, 1:]-data.v('grid', 'axis', 'z')[0, 0:-1])*data.n('H', j) dz = dz.reshape(dz.shape[0]) dz_down = dz[:kmax-1].reshape(kmax-1, 1, 1) dz_up = dz[1:kmax].reshape(kmax-1, 1, 1) dz_av = 0.5*(dz_down+dz_up) ##### LEFT HAND SIDE ##### if not hasMatrix: # Init A = np.zeros([2*ftot+2*bandwidth+1, ftot*(kmax+1)], dtype=complex) N = np.zeros([kmax+1, 2*bandwidth+1, ftot], dtype=complex) # Build eddy viscosity matrix blocks N[:, bandwidth, :] = Kv[j, :, 0].reshape(kmax+1, 1)*np.ones([1, ftot]) for n in range(1, bandwidth+1): N[:, bandwidth+n, :-n] = 0.5*Kv[j, :, n].reshape(kmax+1, 1)*np.ones([1, ftot]) N[:, bandwidth-n, n:] = 0.5*np.conj(Kv[j, :, n]).reshape(kmax+1, 1)*np.ones([1, ftot]) # Build matrix. Discretisation: central for second derivative, central for first derivative # NB. can use general numerical schemes as dz < 0 a = -N[:-2, :, :]/dz_down b = N[1:kmax, :, :]/dz_up+N[1:kmax, :, :]/dz_down c = -N[2:, :, :]/dz_up b[:, bandwidth, :] += (np.arange(-fmax, ftot-fmax)*1j*OMEGA).reshape((1, ftot))*dz_av.reshape((kmax-1, 1)) a = np.swapaxes(a, 0, 1) b = np.swapaxes(b, 0, 1) c = np.swapaxes(c, 0, 1) # Build matrix A[2*ftot:2*ftot+2*bandwidth+1, :-2*ftot] = a.reshape(a.shape[0], a.shape[1]*a.shape[2]) A[2*fmax+1:2*fmax+2*bandwidth+2, ftot:-ftot] = b.reshape(a.shape[0], a.shape[1]*a.shape[2]) A[0:2*bandwidth+1, 2*ftot:] = c.reshape(a.shape[0], a.shape[1]*a.shape[2]) # Boundary conditions # Surface (k=0) A[2*fmax+1:2*fmax+2*bandwidth+2, :ftot] = N[0, :, :] # Bed (k=kmax) A[2*fmax+1:2*fmax+2*bandwidth+2, -ftot:] = N[-1, :, :] # save matrix salinityMatrix[j, Ellipsis] = A[Ellipsis] bandwidthA = bandwidth+ftot else: A = Kv[j, Ellipsis] # if hasMatrix Av replaces the role of the matrix in this equation bandwidthA = (A.shape[0]-1)/2 ##### RIGHT HAND SIDE ##### # Implicit part of the forcing uz0*dz*Sx umat = np.zeros((kmax+1, ftot), dtype=complex) umat[1:-1, fmax:ftot] = -uz[j, 1:-1, :]*dz_av.reshape((kmax-1, 1)) uRHS_implicit = umat.reshape((ftot*(kmax+1), 1)) # Forcing from other factors uRHS = np.zeros([ftot*(kmax+1), nRHS], dtype=complex) uRHS[fmax:ftot, :] = Fsurf[j, 0, :, :] uRHS[-ftot+fmax:, :] = Fbed[j, 0, :, :] F_full = np.concatenate((np.zeros((jmax+1, kmax+1, fmax, nRHS)), F), 2) uRHS[ftot:-ftot, :] = 0.5*(F_full[j, 2:, :, :]-F_full[j, :-2, :, :]).reshape((kmax-1)*ftot, nRHS) ##### SOLVE ##### sz = solve_banded((bandwidthA, bandwidthA), A, np.concatenate((uRHS_implicit, uRHS), 1), overwrite_ab=True, overwrite_b=True) sz = sz.reshape(kmax+1, ftot, 1+nRHS) szCoef[j, :, :, :] = ny.eliminateNegativeFourier(sz[:, :, :1], 1) szForced[j, :, :, :] = ny.eliminateNegativeFourier(sz[:, :, 1:], 1) del sz, uRHS_implicit, uRHS ##### INTEGRATION CONSTANT ##### SIGMASAL = data.v('SIGMASAL') if hasMatrix: KvBed = data.v('Av', range(0, jmax+1), [kmax-1, kmax], range(0, fmax+1))/SIGMASAL # TODO: shift to turbulence model else: KvBed = Kv[:, [kmax-1, kmax], :] Dinv = np.diag((np.arange(0, fmax+1)*1j*OMEGA)) Dinv[0, 0] = np.inf Dinv[range(0, fmax+1), range(0, fmax+1)] = Dinv[range(0, fmax+1), range(0, fmax+1)]**(-1) z = ny.dimensionalAxis(data.slice('grid'), 'z') dzbed = z[:, [-1], 0] - z[:, [-2], 0] sbedCoef = -ny.complexAmplitudeProduct(KvBed[:, [-2], :], szCoef[:, [-2], :, :], 2)/dzbed.reshape(dzbed.shape+(1, 1)) - u0bed.reshape(u0bed.shape+(1,)) sbedCoef = np.dot(Dinv, sbedCoef) sbedCoef = np.rollaxis(sbedCoef, 0, 3) sbedForced = (Fbed-ny.complexAmplitudeProduct(KvBed[:, [-2], :], szForced[:, [-2], :, :], 2))/dzbed.reshape(dzbed.shape+(1, 1)) + F[:, [-1], :, :] sbedForced = np.dot(Dinv, sbedForced) sbedForced = np.rollaxis(sbedForced, 0, 3) ##### INTEGRATION ##### sCoef = ny.integrate(szCoef, 'z', kmax, np.arange(0, kmax+1), data.slice('grid')) + sbedCoef*np.ones((1, kmax+1, 1, 1)) sForced = ny.integrate(szForced, 'z', kmax, np.arange(0, kmax+1), data.slice('grid')) + sbedForced*np.ones((1, kmax+1, 1, 1)) ##### CLOSURE FOR THE DEPTH-AVERAGED TIME-AVERAGED SALINITY VARIATION ##### H = data.v('H', range(0, jmax+1)).reshape((jmax+1, 1, 1, 1)) sCoef[:, :, [0], :] -= (ny.integrate(sCoef[:, :, [0], :], 'z', kmax, 0, data.slice('grid'))/H)*np.ones((1, kmax+1, 1, 1)) sForced[:, :, [0], :] -= (ny.integrate(sForced[:, :, [0], :], 'z', kmax, 0, data.slice('grid'))/H)*np.ones((1, kmax+1, 1, 1)) if hasMatrix: return sCoef, sForced, szCoef, szForced, Kv else: return sCoef, sForced, szCoef, szForced, salinityMatrix
def run(self): """ Returns: Dictionary with results. At least contains the variables listed as output in the registry """ self.logger.info('Running module HydroFirst') # Init jmax = self.input.v('grid', 'maxIndex', 'x') kmax = self.input.v('grid', 'maxIndex', 'z') fmax = self.input.v('grid', 'maxIndex', 'f') G = self.input.v('G') BETA = self.input.v('BETA') OMEGA = self.input.v('OMEGA') ftot = 2 * fmax + 1 submodulesToRun = self.input.v('submodules') # check if the river term should be compensated for by reference level. Only if river is on, non-zero and there is no leading-order contribution if 'river' in submodulesToRun and self.input.v( 'Q1') != 0 and not np.any( self.input.v('zeta0', 'river', range(0, jmax + 1), 0, 0)): RiverReferenceCompensation = 1 else: RiverReferenceCompensation = 0 ################################################################################################################ # velocity as function of water level ################################################################################################################ ## LHS terms # try to get velocityMatrix from the input. If it is not found, proceed to calculate the matrix again A = self.input.v( 'velocityMatrix' ) # known that this is numeric data, ask without arguments to retrieve full ndarray velocityMatrix = True if A is None: A = self.input.v('Av', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) velocityMatrix = False else: A = A ## RHS terms # Determine number/names of right hand side submodulesVelocityForcing = [ i for i in ['adv', 'nostress', 'baroc', 'mixing', 'river'] if i in submodulesToRun ] #submodulesVelocityConversion = [i for i, mod in enumerate(submodulesToRun) if mod in ['adv', 'nostress', 'baroc', 'mixing']] submodulesVelocityConversion = [ submodulesToRun.index(i) for i in submodulesVelocityForcing ] nRHS = len(submodulesVelocityForcing) F = np.zeros([jmax + 1, kmax + 1, ftot, nRHS], dtype=complex) Fsurf = np.zeros([jmax + 1, 1, ftot, nRHS], dtype=complex) Fbed = np.zeros([jmax + 1, 1, ftot, nRHS], dtype=complex) uFirst = np.zeros([jmax + 1, kmax + 1, ftot, len(submodulesToRun)], dtype=complex) uzFirst = np.zeros([jmax + 1, kmax + 1, ftot, len(submodulesToRun)], dtype=complex) u0 = self.input.v('u0', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) zeta0 = self.input.v('zeta0', range(0, jmax + 1), [0], range(0, fmax + 1)) if RiverReferenceCompensation: # for reference level variation F[:, :, fmax, submodulesVelocityForcing.index('river')] = -G * self.input.d( 'R', range(0, jmax + 1), dim='x').reshape( (jmax + 1, 1)) * np.ones((1, kmax + 1)) if 'adv' in submodulesVelocityForcing: u0x = self.input.d('u0', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1), dim='x') u0z = self.input.d('u0', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1), dim='z') w0 = self.input.v('w0', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) eta = ny.complexAmplitudeProduct( u0, u0x, 2) + ny.complexAmplitudeProduct(w0, u0z, 2) eta = np.concatenate((np.zeros([jmax + 1, kmax + 1, fmax]), eta), 2) F[:, :, :, submodulesVelocityForcing.index('adv')] = -eta if 'nostress' in submodulesVelocityForcing: D = (np.arange(0, fmax + 1) * 1j * OMEGA).reshape( (1, 1, fmax + 1)) * np.ones((jmax + 1, 1, 1)) zeta0x = self.input.d('zeta0', range(0, jmax + 1), [0], range(0, fmax + 1), dim='x') chi = D * u0[:, [0], :] + G * zeta0x chi = ny.complexAmplitudeProduct(chi, zeta0, 2) chi = np.concatenate((np.zeros([jmax + 1, 1, fmax]), chi), 2) Fsurf[:, :, :, submodulesVelocityForcing.index('nostress')] = -chi if 'baroc' in submodulesVelocityForcing: sx = self.input.d('s0', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1), dim='x') Jsx = -ny.integrate( sx, 'z', 0, range(0, kmax + 1), self.input.slice('grid') ) # integral from z to 0 has its boundaries inverted and has a minus sign to compensate Jsx = np.concatenate((np.zeros([jmax + 1, kmax + 1, fmax]), Jsx), 2) F[:, :, :, submodulesVelocityForcing.index('baroc')] = -G * BETA * Jsx if 'mixing' in submodulesVelocityForcing: u0z = self.input.d('u0', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1), dim='z') Av1 = self.input.v('Av1', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) ksi = ny.complexAmplitudeProduct(u0z, Av1, 2) ksiz = ny.derivative(ksi, 1, self.input.slice('grid')) ksi = np.concatenate((np.zeros([jmax + 1, kmax + 1, fmax]), ksi), 2) ksiz = np.concatenate((np.zeros([jmax + 1, kmax + 1, fmax]), ksiz), 2) F[:, :, :, submodulesVelocityForcing.index('mixing')] = ksiz Fsurf[:, :, :, submodulesVelocityForcing.index('mixing')] = -ksi[:, [0], Ellipsis] ## Removed 14-7-2017 YMD: Roughness1*u0 and Av1*u0z should be equal, so this term cancels # if self.input.v('BottomBC') in ['PartialSlip']: # Fbed[:, :, :, submodulesVelocityForcing.index('mixing')] = -ksi[:,[kmax],Ellipsis] # roughness1 = self.input.v('Roughness1', range(0, jmax+1), [0], range(0, fmax+1)) # if roughness1 is not None: # ksi = ny.complexAmplitudeProduct(u0[:, [-1], :], roughness1, 2) # ksi = np.concatenate((np.zeros([jmax+1, 1, fmax]), ksi), 2) # Fbed[:, :, :, submodulesVelocityForcing.index('mixing')] = ksi ## Solve equation uCoef, uFirst[:, :, :, submodulesVelocityConversion], uzCoef, uzFirst[:, :, :, submodulesVelocityConversion], _ = uFunctionMomentumConservative( A, F, Fsurf, Fbed, self. input, hasMatrix =velocityMatrix ) ################################################################################################################ # water level ################################################################################################################ ## LHS terms # try to get zetaMatrix from the input. If it is not found, proceed to calculate the matrix again B = self.input.v( 'zetaMatrix' ) # known that this is numeric data, ask without arguments to retrieve full ndarray zetaMatrix = True if B is None: zetaMatrix = False utemp = uCoef.reshape( uCoef.shape[:2] + (1, ) + uCoef.shape[2:] ) # reshape as the 'f' dimension is not grid conform; move it to a higher dimension JuCoef = ny.integrate(utemp, 'z', kmax, 0, self.input.slice('grid')) JuCoef = JuCoef.reshape(jmax + 1, 1, ftot, ftot) # reshape back to original grid B = -G * JuCoef * self.input.v('B', np.arange( 0, jmax + 1)).reshape(jmax + 1, 1, 1, 1) ## RHS terms # advection, no-stress, baroclinic utemp = uFirst.reshape( uFirst.shape[:2] + (1, ) + uFirst.shape[2:] ) # reshape as the 'f' dimension is not grid conform; move it to a higher dimension JuFirst = ny.integrate(utemp, 'z', kmax, 0, self.input.slice('grid')) JuFirst = JuFirst.reshape( jmax + 1, 1, ftot, uFirst.shape[-1]) # reshape back to original grid # stokes if 'stokes' in submodulesToRun: gamma = ny.complexAmplitudeProduct(u0[:, 0, None, Ellipsis], zeta0, 2) gamma = np.concatenate((np.zeros([jmax + 1, 1, fmax]), gamma), 2) JuFirst[:, :, :, submodulesToRun.index('stokes')] = gamma BJuFirst = JuFirst * self.input.v('B', np.arange(0, jmax + 1)).reshape( jmax + 1, 1, 1, 1) # open BC: tide Fopen = np.zeros([1, 1, ftot, len(submodulesToRun)], dtype=complex) if 'tide' in submodulesToRun: Fopen[0, 0, fmax:, submodulesToRun.index('tide')] = ny.amp_phase_input( self.input.v('A1'), self.input.v('phase1'), (fmax + 1, )) # closed BC: river Fclosed = np.zeros([1, 1, ftot, len(submodulesToRun)], dtype=complex) if 'river' in submodulesToRun: Fclosed[0, 0, fmax, submodulesToRun.index('river')] = -self.input.v('Q1') # closed BC: other terms Fclosed += -JuFirst[jmax, 0, :, :] * self.input.v('B', jmax) ## Solve equation zetaCoef, zetaxCoef, _ = zetaFunctionMassConservative( B, BJuFirst, Fopen, Fclosed, self.input, hasMatrix=zetaMatrix) zetax = ny.eliminateNegativeFourier(zetaxCoef, 2) zeta = ny.eliminateNegativeFourier(zetaCoef, 2) ################################################################################################################ # velocity ################################################################################################################ u = np.empty((jmax + 1, kmax + 1, ftot, len(submodulesToRun)), dtype=uCoef.dtype) uz = np.empty((jmax + 1, kmax + 1, ftot, len(submodulesToRun)), dtype=uCoef.dtype) for j in range(0, jmax + 1): u[j, :, :, :] = np.dot(uCoef[j, :, :, :], -G * zetaxCoef[j, 0, :, :]) uz[j, :, :, :] = np.dot(uzCoef[j, :, :, :], -G * zetaxCoef[j, 0, :, :]) u += uFirst uz += uzFirst u = ny.eliminateNegativeFourier(u, 2) uz = ny.eliminateNegativeFourier(uz, 2) ################################################################################################################ # vertical velocity ################################################################################################################ w = self.verticalVelocity(u) ################################################################################################################ # Make final dictionary to return ################################################################################################################ d = {} d['zeta1'] = {} d['u1'] = {} d['w1'] = {} for i, submod in enumerate(submodulesToRun): nf = ny.functionTemplates.NumericalFunctionWrapper( zeta[:, :, :, i], self.input.slice('grid')) nf.addDerivative(zetax[:, :, :, i], 'x') d['zeta1'][submod] = nf.function nfu = ny.functionTemplates.NumericalFunctionWrapper( u[:, :, :, i], self.input.slice('grid')) nfu.addDerivative(uz[:, :, :, i], 'z') d['u1'][submod] = nfu.function d['w1'][submod] = w[:, :, :, i] return d
def run(self): self.logger.info('Running module SedDynamic - leading order') d = {} jmax = self.input.v('grid', 'maxIndex', 'x') kmax = self.input.v('grid', 'maxIndex', 'z') fmax = self.input.v('grid', 'maxIndex', 'f') ftot = 2 * fmax + 1 self.submodulesToRun = self.input.v('submodules') # H = self.input.v('H', range(0, jmax+1)) method = self.input.v('erosion_formulation') frictionpar = self.input.v( 'friction' ) # friction parameter used for the erosion, by default the total roughness if frictionpar == None: frictionpar = 'Roughness' ################################################################################################################ # Left hand side ################################################################################################################ Av = self.input.v('Av', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) Kv = self.input.v('Kv', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) # NB. If Kv is not provided on input, use the module DiffusivityUndamped to compute it. This is a fix for making this module easier to use. if Kv is None: from DiffusivityUndamped import DiffusivityUndamped sr = self.input.v('sigma_rho') if sr is None: # add Prandtl-Schmidt number if it does not exist self.input.addData('sigma_rho', 1.) md = DiffusivityUndamped(self.input) self.input.merge(md.run()) Kv = self.input.v('Kv', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) d['Kv'] = Kv ws = self.input.v('ws0', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) ################################################################################################################ # Forcing terms ################################################################################################################ F = np.zeros([jmax + 1, kmax + 1, ftot, 1], dtype=complex) Fsurf = np.zeros([jmax + 1, 1, ftot, 1], dtype=complex) Fbed = np.zeros([jmax + 1, 1, ftot, 1], dtype=complex) # erosion E = erosion(ws, 0, self.input, method, friction=frictionpar) Fbed[:, :, fmax:, 0] = -E ################################################################################################################ # Solve equation ################################################################################################################ # Coupled system c, cMatrix = cFunction(ws, Kv, F, Fsurf, Fbed, self.input, hasMatrix=False) c = c.reshape((jmax + 1, kmax + 1, ftot)) hatc0 = ny.eliminateNegativeFourier(c, 2) # Uncoupled system # hatc0 = np.zeros((jmax+1, kmax+1, fmax+1), dtype=complex) # hatc0[:, :, 0] = cFunctionUncoupled(ws, Kv, F, Fsurf, Fbed, self.input, 0).reshape((jmax+1, kmax+1)) # hatc0[:, :, 2] = cFunctionUncoupled(ws, Kv, F, Fsurf, Fbed, self.input, 2).reshape((jmax+1, kmax+1)) # correction at the bed (optional) # cbed00 = E[:, -1, 0]/ws[:, -1, 0] # frac = cbed00/hatc0[:, -1, 0] # hatc0 = hatc0*frac.reshape((jmax+1, 1, 1)) ## analytical solutions # ahatc0 = np.zeros((jmax+1, kmax+1, fmax+1), dtype=complex) # ahatc02 = np.zeros((jmax+1, kmax+1, fmax+1), dtype=complex) # z = ny.dimensionalAxis(self.input.slice('grid'), 'z')[:, :, 0] # ws = ws[:, 0, 0] # Kv = Kv[:, 0, 0] # OMEGA = self.input.v('OMEGA') # H = self.input.v('H', range(0, jmax+1)) # # # M0 # ahatc0[:, :, 0] = (E[:, 0, 0]/ws).reshape((jmax+1, 1))*np.exp(-(ws/Kv).reshape((jmax+1, 1))*(z+H.reshape((jmax+1, 1)))) # # # # M4 # # r1 = -ws/(2.*Kv)+np.sqrt(ws**2+8*1j*OMEGA*Kv)/(2*Kv) # r2 = -ws/(2.*Kv)-np.sqrt(ws**2+8*1j*OMEGA*Kv)/(2*Kv) # k2 = -E[:, 0, 2]*(Kv*(-r1*(ws+Kv*r2)/(ws+Kv*r1)*np.exp(-r1*H) + r2*np.exp(-r2*H)))**-1. # k1 = -k2*(ws+Kv*r2)/(ws+Kv*r1) # ahatc0[:, :, 2] = k1.reshape((jmax+1, 1))*np.exp(r1.reshape((jmax+1, 1))*z) + k2.reshape((jmax+1, 1))*np.exp(r2.reshape((jmax+1, 1))*z) # import step as st # import matplotlib.pyplot as plt # # st.configure() # plt.figure(1, figsize=(1,3)) # plt.subplot(1,3,1) # plt.plot(np.real(ahatc0[0, :, 0]), z[0, :], label='analytical') # plt.plot(np.real(hatc0[0, :, 0]), z[0, :], label='numerical') # plt.xlim(0, np.max(np.maximum(abs(ahatc0[0, :, 0]), abs(hatc0[0, :, 0])))*1.05) # # plt.subplot(1,3,2) # plt.plot(np.abs(ahatc0[0, :, 2]), z[0, :], label='analytical') # # plt.plot(np.abs(ahatc02[0, :, 2]), z[0, :], label='analytical2') # plt.plot(np.abs(hatc0[0, :, 2]), z[0, :], label='numerical') # # plt.xlim(np.min(np.minimum(abs(ahatc0[0, :, 2]), abs(hatc0[0, :, 2])))*1.05, np.max(np.maximum(abs(ahatc0[0, :, 2]), abs(hatc0[0, :, 2])))*1.05) # plt.legend() # # plt.subplot(1,3,3) # plt.plot(np.imag(ahatc0[0, :, 2]), z[0, :], label='analytical') # # plt.plot(np.imag(ahatc02[0, :, 2]), z[0, :], label='analytical2') # plt.plot(np.imag(hatc0[0, :, 2]), z[0, :], label='numerical') # # plt.xlim(np.min(np.minimum(abs(ahatc0[0, :, 2]), abs(hatc0[0, :, 2])))*1.05, np.max(np.maximum(abs(ahatc0[0, :, 2]), abs(hatc0[0, :, 2])))*1.05) # plt.legend() # st.show() d['hatc0'] = {} d['hatc0']['a'] = {} d['hatc0']['a']['erosion'] = hatc0 return d
def leading_order(self, d): jmax = self.input.v('grid', 'maxIndex', 'x') kmax = self.input.v('grid', 'maxIndex', 'z') fmax = self.input.v('grid', 'maxIndex', 'f') ftot = 2 * fmax + 1 ################################################################################################################ # Forcing terms ################################################################################################################ F = np.zeros([jmax + 1, kmax + 1, ftot, 1], dtype=complex) Fsurf = np.zeros([jmax + 1, 1, ftot, 1], dtype=complex) Fbed = np.zeros([jmax + 1, 1, ftot, 1], dtype=complex) # erosion E = erosion(self.ws, 0, self.input, self.erosion_method, friction=self.frictionpar) Fbed[:, :, fmax:, 0] = -E ################################################################################################################ # Solve equation ################################################################################################################ # Coupled system c, cMatrix = cFunction(self.ws, self.Kv, F, Fsurf, Fbed, self.input, hasMatrix=False) c = c.reshape((jmax + 1, kmax + 1, ftot)) hatc0 = ny.eliminateNegativeFourier(c, 2) # Uncoupled system # hatc0 = np.zeros((jmax+1, kmax+1, fmax+1), dtype=complex) # hatc0[:, :, 0] = cFunctionUncoupled(self.ws, self.Kv, F, Fsurf, Fbed, self.input, 0).reshape((jmax+1, kmax+1)) # hatc0[:, :, 2] = cFunctionUncoupled(self.ws, self.Kv, F, Fsurf, Fbed, self.input, 2).reshape((jmax+1, kmax+1)) # correction at the bed (optional) # cbed00 = E[:, -1, 0]/self.ws[:, -1, 0] # frac = cbed00/hatc0[:, -1, 0] # hatc0 = hatc0*frac.reshape((jmax+1, 1, 1)) ## analytical solutions # ahatc0 = np.zeros((jmax+1, kmax+1, fmax+1), dtype=complex) # ahatc02 = np.zeros((jmax+1, kmax+1, fmax+1), dtype=complex) # z = ny.dimensionalAxis(self.input.slice('grid'), 'z')[:, :, 0] # self.ws = self.ws[:, 0, 0] # self.Kv = self.Kv[:, 0, 0] # OMEGA = self.input.v('OMEGA') # H = self.input.v('H', range(0, jmax+1)) # # # M0 # ahatc0[:, :, 0] = (E[:, 0, 0]/self.ws).reshape((jmax+1, 1))*np.exp(-(self.ws/self.Kv).reshape((jmax+1, 1))*(z+H.reshape((jmax+1, 1)))) # # # # M4 # # r1 = -self.ws/(2.*self.Kv)+np.sqrt(self.ws**2+8*1j*OMEGA*self.Kv)/(2*self.Kv) # r2 = -self.ws/(2.*self.Kv)-np.sqrt(self.ws**2+8*1j*OMEGA*self.Kv)/(2*self.Kv) # k2 = -E[:, 0, 2]*(self.Kv*(-r1*(self.ws+self.Kv*r2)/(self.ws+self.Kv*r1)*np.exp(-r1*H) + r2*np.exp(-r2*H)))**-1. # k1 = -k2*(self.ws+self.Kv*r2)/(self.ws+self.Kv*r1) # ahatc0[:, :, 2] = k1.reshape((jmax+1, 1))*np.exp(r1.reshape((jmax+1, 1))*z) + k2.reshape((jmax+1, 1))*np.exp(r2.reshape((jmax+1, 1))*z) # import step as st # import matplotlib.pyplot as plt # # st.configure() # plt.figure(1, figsize=(1,3)) # plt.subplot(1,3,1) # plt.plot(np.real(ahatc0[0, :, 0]), z[0, :], label='analytical') # plt.plot(np.real(hatc0[0, :, 0]), z[0, :], label='numerical') # plt.xlim(0, np.max(np.maximum(abs(ahatc0[0, :, 0]), abs(hatc0[0, :, 0])))*1.05) # # plt.subplot(1,3,2) # plt.plot(np.abs(ahatc0[0, :, 2]), z[0, :], label='analytical') # # plt.plot(np.abs(ahatc02[0, :, 2]), z[0, :], label='analytical2') # plt.plot(np.abs(hatc0[0, :, 2]), z[0, :], label='numerical') # # plt.xlim(np.min(np.minimum(abs(ahatc0[0, :, 2]), abs(hatc0[0, :, 2])))*1.05, np.max(np.maximum(abs(ahatc0[0, :, 2]), abs(hatc0[0, :, 2])))*1.05) # plt.legend() # # plt.subplot(1,3,3) # plt.plot(np.imag(ahatc0[0, :, 2]), z[0, :], label='analytical') # # plt.plot(np.imag(ahatc02[0, :, 2]), z[0, :], label='analytical2') # plt.plot(np.imag(hatc0[0, :, 2]), z[0, :], label='numerical') # # plt.xlim(np.min(np.minimum(abs(ahatc0[0, :, 2]), abs(hatc0[0, :, 2])))*1.05, np.max(np.maximum(abs(ahatc0[0, :, 2]), abs(hatc0[0, :, 2])))*1.05) # plt.legend() # st.show() d['hatc0'] = {} d['hatc0']['a'] = {} d['hatc0']['a']['erosion'] = hatc0 d['cMatrix'] = cMatrix return d
def first_order(self, d): jmax = self.input.v('grid', 'maxIndex', 'x') kmax = self.input.v('grid', 'maxIndex', 'z') fmax = self.input.v('grid', 'maxIndex', 'f') ftot = 2 * fmax + 1 OMEGA = self.input.v('OMEGA') ################################################################################################################ # Forcing terms ################################################################################################################ if 'sedadv' in self.submodulesToRun and 'sedadv_ax' not in self.submodulesToRun: self.submodulesToRun.append('sedadv_ax') # determine number of submodules nRHS = len(self.submodulesToRun) if 'erosion' in self.submodulesToRun: keysu1 = self.input.getKeysOf('u1') try: keysu1.remove( 'mixing' ) # flow due to 'mixing' should not be included in the erosion term except: pass self.submodulesToRun.remove( 'erosion') # move to the end of the list self.submodulesToRun.append('erosion') nRHS = nRHS - 1 + len(self.input.getKeysOf('u1')) F = np.zeros([jmax + 1, kmax + 1, ftot, nRHS], dtype=complex) Fsurf = np.zeros([jmax + 1, 1, ftot, nRHS], dtype=complex) Fbed = np.zeros([jmax + 1, 1, ftot, nRHS], dtype=complex) self.input.merge(d) c0 = self.input.v('hatc0', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) cx0 = self.input.d('hatc0', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1), dim='x') cz0 = self.input.d('hatc0', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1), dim='z') # 1. Erosion if 'erosion' in self.submodulesToRun: # erosion due to first-order bed shear stress # E = erosion(self.ws, Av, 1, self.input, self.erosion_method) # 24-04-2017 Obsolete # Fbed[:, :, fmax:, self.submodulesToRun.index('erosion')] = -E # 24-04-2017 Obsolete for submod in keysu1: E = erosion(self.ws, 1, self.input, self.erosion_method, submodule=(None, submod), friction=self.frictionpar) Fbed[:, :, fmax:, len(self.submodulesToRun) - 1 + keysu1.index(submod)] = -E # 2. Advection if 'sedadv' in self.submodulesToRun: u0 = self.input.v('u0', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) w0 = self.input.v('w0', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) eta = ny.complexAmplitudeProduct( u0, cx0, 2) + ny.complexAmplitudeProduct(w0, cz0, 2) F[:, :, fmax:, self.submodulesToRun.index('sedadv')] = -eta F[:, :, fmax:, self.submodulesToRun. index('sedadv_ax')] = -ny.complexAmplitudeProduct(u0, c0, 2) # 3. First-order fall velocity if 'fallvel' in self.submodulesToRun: # surface and internal terms ws1 = self.input.v('ws1', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) ksi = ny.complexAmplitudeProduct(ws1, c0, 2) ksiz = ny.derivative(ksi, 'z', self.input.slice('grid')) F[:, :, fmax:, self.submodulesToRun.index('fallvel')] = ksiz Fsurf[:, 0, fmax:, self.submodulesToRun.index('fallvel')] = -ksi[:, 0, :] # adjustment to erosion; only if erosion depends on the settling velocity if self.erosion_method == 'Chernetsky': E = erosion(ws1, 0, self.input, self.erosion_method, friction=self.frictionpar) Fbed[:, :, fmax:, self.submodulesToRun.index('fallvel')] = -E # 4. First-order eddy diffusivity if 'mixing' in self.submodulesToRun: # surface, bed and internal terms Kv1 = self.input.v('Kv1', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) psi = ny.complexAmplitudeProduct(Kv1, cz0, 2) psiz = ny.derivative(psi, 'z', self.input.slice('grid')) F[:, :, fmax:, self.submodulesToRun.index('mixing')] = psiz Fsurf[:, 0, fmax:, self.submodulesToRun.index('mixing')] = -psi[:, 0, :] Fbed[:, 0, fmax:, self.submodulesToRun.index('mixing')] = -psi[:, -1, :] # adjustment to erosion E = erosion(self.ws, 1, self.input, self.erosion_method, submodule=(None, 'mixing'), friction=self.frictionpar) Fbed[:, :, fmax:, self.submodulesToRun.index('mixing')] = -E # 5. No-flux surface correction if 'noflux' in self.submodulesToRun: zeta0 = self.input.v('zeta0', range(0, jmax + 1), [0], range(0, fmax + 1)) D = np.zeros((jmax + 1, 1, fmax + 1, fmax + 1), dtype=complex) D[:, :, range(0, fmax + 1), range(0, fmax + 1)] = np.arange(0, fmax + 1) * 1j * OMEGA Dc0 = ny.arraydot(D, c0[:, [0], :]) chi = ny.complexAmplitudeProduct(Dc0, zeta0, 2) Fsurf[:, :, fmax:, self.submodulesToRun.index('noflux')] = -chi ################################################################################################################ # Solve equation ################################################################################################################ cmatrix = self.input.v('cMatrix') if cmatrix is not None: c, cMatrix = cFunction(None, cmatrix, F, Fsurf, Fbed, self.input, hasMatrix=True) else: c, cMatrix = cFunction(self.ws, self.Kv, F, Fsurf, Fbed, self.input, hasMatrix=False) c = c.reshape((jmax + 1, kmax + 1, ftot, nRHS)) c = ny.eliminateNegativeFourier(c, 2) ################################################################################################################ # Prepare output ################################################################################################################ d['hatc1'] = {} d['hatc1']['a'] = {} d['hatc1']['ax'] = {} for i, submod in enumerate(self.submodulesToRun): if submod == 'sedadv_ax': d['hatc1']['ax']['sedadv'] = c[:, :, :, i] elif submod == 'erosion': d['hatc1']['a']['erosion'] = {} for j, subsubmod in enumerate(keysu1): d['hatc1']['a']['erosion'][ subsubmod] = c[:, :, :, len(self.submodulesToRun) - 1 + j] else: d['hatc1']['a'][submod] = c[:, :, :, i] if 'sedadv' not in self.submodulesToRun: d['hatc1']['ax'] = 0 return d
def run(self): self.logger.info('Running module SedDynamic - second order') d = {} jmax = self.input.v('grid', 'maxIndex', 'x') kmax = self.input.v('grid', 'maxIndex', 'z') fmax = self.input.v('grid', 'maxIndex', 'f') ftot = 2 * fmax + 1 self.submodulesToRun = self.input.v('submodules') method = self.input.v('erosion_formulation') frictionpar = self.input.v( 'friction' ) # friction parameter used for the erosion, by default the total roughness if frictionpar == None: frictionpar = 'Roughness' ################################################################################################################ # Left hand side ################################################################################################################ Av = self.input.v('Av', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) Kv = self.input.v('Kv', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) # NB. If Kv is not provided on input, use the module DiffusivityUndamped to compute it. This is a fix for making this module easier to use. if Kv is None: from DiffusivityUndamped import DiffusivityUndamped sr = self.input.v('sigma_rho') if sr is None: # add Prandtl-Schmidt number if it does not exist self.input.addData('sigma_rho', 1.) md = DiffusivityUndamped(self.input) self.input.merge(md.run()) Kv = self.input.v('Kv', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) d['Kv'] = Kv ws = self.input.v('ws0', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) ################################################################################################################ # Forcing terms ################################################################################################################ F = np.zeros([jmax + 1, kmax + 1, ftot, 1], dtype=complex) Fsurf = np.zeros([jmax + 1, 1, ftot, 1], dtype=complex) Fbed = np.zeros([jmax + 1, 1, ftot, 1], dtype=complex) # erosion if self.input.v('u1', 'river') is not None: E = erosion(ws, 2, self.input, method, submodule=(None, 'river', None), friction=frictionpar) Fbed[:, :, fmax:, 0] = -E ################################################################################################################ # Solve equation ################################################################################################################ c, cMatrix = cFunction(ws, Kv, F, Fsurf, Fbed, self.input, hasMatrix=False) c = c.reshape((jmax + 1, kmax + 1, ftot)) else: c = np.zeros((jmax + 1, kmax + 1, ftot)) d['hatc2'] = {} d['hatc2']['a'] = {} d['hatc2']['a']['erosion'] = {} d['hatc2']['a']['erosion'][ 'river_river'] = ny.eliminateNegativeFourier(c, 2) return d
def run(self): """ Returns: Dictionary with results. At least contains the variables listed as output in the registry """ self.logger.info('Running module HydroLead') # Init jmax = self.input.v('grid', 'maxIndex', 'x') kmax = self.input.v('grid', 'maxIndex', 'z') fmax = self.input.v('grid', 'maxIndex', 'f') G = self.input.v('G') ftot = 2 * fmax + 1 submodulesToRun = self.input.v('submodules') # check if the river term should be compensated for by reference level. Only if river is on and non-zero if 'river' in submodulesToRun and self.input.v('Q0') != 0: RiverReferenceCompensation = 1 else: RiverReferenceCompensation = 0 ################################################################################################################ # velocity as function of water level ################################################################################################################ # build, save and solve the velocity matrices in every water column Av = self.input.v('Av', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) F = np.zeros([jmax + 1, kmax + 1, ftot, RiverReferenceCompensation]) Fsurf = np.zeros([jmax + 1, 1, ftot, RiverReferenceCompensation]) Fbed = np.zeros([jmax + 1, 1, ftot, RiverReferenceCompensation]) if RiverReferenceCompensation: # for reference level variation F[:, :, fmax, 0] = -G * self.input.d('R', range(0, jmax + 1), dim='x').reshape( (jmax + 1, 1)) * np.ones((1, kmax + 1)) uCoef, uLead, uzCoef, uzLead, velocityMatrix = uFunctionMomentumConservative( Av, F, Fsurf, Fbed, self.input) ################################################################################################################ # water level ################################################################################################################ ## LHS terms utemp = uCoef.reshape( uCoef.shape[:2] + (1, ) + uCoef.shape[2:] ) # reshape as the 'f' dimension is not grid conform; move it to a higher dimension JuCoef = ny.integrate(utemp, 'z', kmax, 0, self.input.slice('grid')) JuCoef = JuCoef.reshape(jmax + 1, 1, ftot, ftot) # reshape back to original grid BJuCoef = -G * JuCoef * self.input.v('B', np.arange( 0, jmax + 1)).reshape(jmax + 1, 1, 1, 1) # open BC: tide Fopen = np.zeros([1, 1, ftot, len(submodulesToRun)], dtype=complex) if 'tide' in submodulesToRun: Fopen[0, 0, fmax:, submodulesToRun.index('tide')] = ny.amp_phase_input( self.input.v('A0'), self.input.v('phase0'), (fmax + 1, )) # closed BC: river Fclosed = np.zeros([1, 1, ftot, len(submodulesToRun)], dtype=complex) if RiverReferenceCompensation: Fclosed[0, 0, fmax, submodulesToRun.index('river')] = -self.input.v('Q0') ## RHS terms IntForce = np.zeros( [jmax + 1, 1, ftot, len(submodulesToRun)], dtype=complex) if RiverReferenceCompensation: utemp = uLead.reshape( uLead.shape[:2] + (1, ) + uLead.shape[2:] ) # reshape as the 'f' dimension is not grid conform; move it to a higher dimension JuLead = ny.integrate(utemp, 'z', kmax, 0, self.input.slice('grid')) JuLead = JuLead.reshape(jmax + 1, 1, ftot) * self.input.v( 'B', np.arange(0, jmax + 1)).reshape( jmax + 1, 1, 1) # reshape back to original grid IntForce[:, :, :, submodulesToRun.index('river')] = JuLead[:, :, :] Fclosed[0, 0, :, submodulesToRun.index('river')] += -JuLead[jmax, 0, :] ## Solve equation zetaCoef, zetaxCoef, zetaMatrix = zetaFunctionMassConservative( BJuCoef, IntForce, Fopen, Fclosed, self.input) zetax = ny.eliminateNegativeFourier(zetaxCoef, 2) zeta = ny.eliminateNegativeFourier(zetaCoef, 2) ################################################################################################################ # velocity ################################################################################################################ u = np.empty((jmax + 1, kmax + 1, ftot, len(submodulesToRun)), dtype=uCoef.dtype) uz = np.empty((jmax + 1, kmax + 1, ftot, len(submodulesToRun)), dtype=uCoef.dtype) for j in range(0, jmax + 1): u[j, :, :, :] = np.dot(uCoef[j, :, :, :], -G * zetaxCoef[j, 0, :, :]) uz[j, :, :, :] = np.dot(uzCoef[j, :, :, :], -G * zetaxCoef[j, 0, :, :]) if RiverReferenceCompensation: u[:, :, :, submodulesToRun.index('river')] += uLead[:, :, :, 0] uz[:, :, :, submodulesToRun.index('river')] += uzLead[:, :, :, 0] u = ny.eliminateNegativeFourier(u, 2) uz = ny.eliminateNegativeFourier(uz, 2) ################################################################################################################ # vertical velocity ################################################################################################################ w = self.verticalVelocity(u) ################################################################################################################ # Make final dictionary to return ################################################################################################################ d = {} d['velocityMatrix'] = velocityMatrix d['zetaMatrix'] = zetaMatrix d['zeta0'] = {} d['u0'] = {} d['w0'] = {} for i, submod in enumerate(submodulesToRun): nf = ny.functionTemplates.NumericalFunctionWrapper( zeta[:, :, :, i], self.input.slice('grid')) nf.addDerivative(zetax[:, :, :, i], 'x') d['zeta0'][submod] = nf.function nfu = ny.functionTemplates.NumericalFunctionWrapper( u[:, :, :, i], self.input.slice('grid')) nfu.addDerivative(uz[:, :, :, i], 'z') d['u0'][submod] = nfu.function d['w0'][submod] = w[:, :, :, i] return d
def run(self): self.currentOrder = self.input.v('order') if self.currentOrder < 2: return # Init if self.currentOrder == 2: maxOrder = self.input.v('maxOrder') jmax = self.input.v('grid', 'maxIndex', 'x') fmax = self.input.v('grid', 'maxIndex', 'f') OMEGA = self.input.v('OMEGA') G = self.input.v('G') self.submodulesToRun = self.input.v('submodules') # initialise arrays with surface stress and velocity data self.surf_stress = np.nan * np.empty( (jmax + 1, 1, fmax + 1, maxOrder, maxOrder), dtype=complex) # x, z, f, order, derivative self.surf_u_der = np.nan * np.empty( (jmax + 1, 1, fmax + 1, maxOrder, maxOrder + 2), dtype=complex) # x, z, f, order, derivative # update those parts of these arrays that are not updated later # surface stress D = (np.arange(0, fmax + 1) * 1j * OMEGA).reshape( (1, 1, fmax + 1)) * np.ones((jmax + 1, 1, 1)) u0 = self.input.v('u0', range(0, jmax + 1), [0], range(0, fmax + 1)) zeta0x = self.input.d('zeta0', range(0, jmax + 1), [0], range(0, fmax + 1), dim='x') self.surf_stress[:, :, :, 0, 0] = D * u0[:, [0], :] + G * zeta0x # surface der of u self.surf_u_der[:, :, :, 0, 0] = u0 self.surf_u_der[:, :, :, 0, 1] = self.input.d('u0', range(0, jmax + 1), [0], range(0, fmax + 1), dim='z') Av = self.input.v('Av', range(0, jmax + 1), [0], range(0, fmax + 1)) Avz = self.input.d('Av', range(0, jmax + 1), [0], range(0, fmax + 1), dim='z') u0z = self.input.d('u0', range(0, jmax + 1), [0], range(0, fmax + 1), dim='z') self.surf_u_der[:, :, :, 0, 2] = -self.Avinv_multiply( Av, (ny.complexAmplitudeProduct(Avz, u0z, 2) - self.surf_stress[:, :, :, 0, 0])) self.logger.info('Running module HydroHigher - order ' + str(self.currentOrder)) # Init jmax = self.input.v('grid', 'maxIndex', 'x') kmax = self.input.v('grid', 'maxIndex', 'z') fmax = self.input.v('grid', 'maxIndex', 'f') G = self.input.v('G') BETA = self.input.v('BETA') ftot = 2 * fmax + 1 try: maxContributions = int(self.input.v('maxContributions')) except: maxContributions = self.input.v('maxContributions') d = {} # update surf_stress and surf_u_der self.updateSurfaceData() ################################################################################################################ # Velocity in terms of water level gradient ################################################################################################################ ## LHS terms # try to get velocityMatrix from the input. If it is not found, proceed to calculate the matrix again A = self.input.v( 'velocityMatrix' ) # known that this is numeric data, ask without arguments to retrieve full ndarray velocityMatrix = True if A is None: A = self.input.v('Av', range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) velocityMatrix = False ## RHS terms # Determine number/names of right hand side nRHS, nRHSVelocity = self.__numberOfForcings() f_index = -1 f_names = [] # instantiate the forcing components in the equation F = np.zeros([jmax + 1, kmax + 1, ftot, nRHSVelocity], dtype=complex) Fsurf = np.zeros([jmax + 1, 1, ftot, nRHSVelocity], dtype=complex) Fbed = np.zeros([jmax + 1, 1, ftot, nRHSVelocity], dtype=complex) JuFirst = np.zeros([jmax + 1, 1, ftot, nRHS], dtype=complex) uFirst = np.zeros([jmax + 1, kmax + 1, ftot, nRHS], dtype=complex) uzFirst = np.zeros([jmax + 1, kmax + 1, ftot, nRHS], dtype=complex) # determine RHS terms per submodule - first for velocity # 1. Advection if 'adv' in self.submodulesToRun: for order1 in range(0, self.currentOrder): order2 = self.currentOrder - order1 - 1 # labels and submodules u_str1 = 'u' + str(order1) u_keys1 = self.input.getKeysOf(u_str1) u_str2 = 'u' + str(order2) u_keys2 = self.input.getKeysOf(u_str2) w_str = 'w' + str(order1) # retrieve data and make advection forcing for submod1 in u_keys1: for submod2 in u_keys2: u = self.input.v(u_str1, submod1, range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) ux = self.input.d(u_str2, submod2, range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1), dim='x') w = self.input.v(w_str, submod1, range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) uz = self.input.d(u_str2, submod2, range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1), dim='z') eta = ny.complexAmplitudeProduct( u, ux, 2) + ny.complexAmplitudeProduct(w, uz, 2) eta = np.concatenate( (np.zeros([jmax + 1, kmax + 1, fmax]), eta), 2) f_index += 1 f_names.append([ 'adv', submod1 + str(order1) + '-' + submod2 + str(order2) ]) F[:, :, :, f_index] = -eta del eta # 2. No-Stress if 'nostress' in self.submodulesToRun: chi = 0 for m in range(1, self.currentOrder + 1): for k in range(0, self.currentOrder - m + 1): zetapermutations = self.multiindex( m, self.currentOrder - m - k) # a. make the zeta^m product zetasum = 0 for perm in range(0, zetapermutations.shape[0]): zetaname = 'zeta' + str(zetapermutations[perm, 0]) zeta = self.input.v(zetaname, range(0, jmax + 1), [0], range(0, fmax + 1)) for comp in range(1, zetapermutations.shape[1]): zetaname = 'zeta' + str(zetapermutations[perm, comp]) zeta2 = self.input.v(zetaname, range(0, jmax + 1), [0], range(0, fmax + 1)) zeta = ny.complexAmplitudeProduct(zeta, zeta2, 2) zetasum = zetasum + zeta # b. make the (Av*uz)^(m) term (use m-1 as surf_stress contains (Av*uz)_z^(m)) Avuz = self.surf_stress[:, :, :, k, m - 1] # c. add all to chi chi += 1. / np.math.factorial( m) * ny.complexAmplitudeProduct(Avuz, zetasum, 2) chi = np.concatenate((np.zeros([jmax + 1, 1, fmax]), chi), 2) f_index += 1 f_names.append(['nostress', '']) Fsurf[:, :, :, f_index] = -chi del chi # 3. Density-drift # TODO # if 'densitydrift' in self.submodulesToRun: # beta_delta = 0 # for m in range(1, self.currentOrder): # for k in range(0, self.currentOrder-m): # zetapermutations = self.multiindex(m, self.currentOrder-m-k-1) # # a. make the zeta^m product # zetasum = 0 # for perm in range(0, zetapermutations.shape[0]): # zetaname = 'zeta'+str(zetapermutations[perm, 0]) # zeta = self.input.v(zetaname, range(0, jmax+1), [0], range(0, fmax+1)) # for comp in range(1, zetapermutations.shape[1]): # zetaname = 'zeta'+str(zetapermutations[perm, comp]) # zeta2 = self.input.v(zetaname, range(0, jmax+1), [0], range(0, fmax+1)) # zeta = ny.complexAmplitudeProduct(zeta, zeta2, 2) # zetasum = zetasum + zeta # # # b. make the (s_x)^(m) term # sname = 's'+str(k) # sx = self.input.d(sname, range(0, jmax+1), range(0, kmax+1), range(0, fmax+1), dim='x') # sxmdz = self.surfaceDerivative(sx, m-1, self.NUMORDER_SURFACE) # # # c. add all to beta_delta # beta_delta += G*BETA*1./np.math.factorial(m)*ny.complexAmplitudeProduct(sxmdz, zetasum, 2) # # beta_delta = np.concatenate((np.zeros([jmax+1, 1, fmax]), beta_delta), 2) # # f_index += 1 # f_names.append(['densitydrift', '']) # F[:, :, :, f_index] = -beta_delta*np.ones((jmax+1, kmax+1, fmax+1)) # 4. Baroclinic # Only use this when salinity on lower order is available if 'baroc' in self.submodulesToRun: s_str = 's' + str(self.currentOrder - 1) sx = self.input.d(s_str, range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1), dim='x') if sx is not None: Jsx = -G * BETA * ny.integrate( sx, 'z', 0, range(0, kmax + 1), self.input.slice('grid') ) # integral from z to 0 has its boundaries inverted and has a minus sign to compensate Jsx = np.concatenate( (np.zeros([jmax + 1, kmax + 1, fmax]), Jsx), 2) f_index += 1 f_names.append(['baroc', '']) F[:, :, :, f_index] = -Jsx del Jsx, sx # 5. Mixing if 'mixing' in self.submodulesToRun: ksi = np.zeros([jmax + 1, kmax + 1, fmax + 1], dtype=complex) for m in range(1, self.currentOrder + 1): Avm = self.input.v('Av' + str(m), range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1)) if Avm is not None: uz = self.input.d('u' + str(self.currentOrder - m), range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1), dim='z') ksi += ny.complexAmplitudeProduct(Avm, uz, 2) ksi_z = ny.derivative(ksi, 'z', self.input.slice('grid')) ksi = np.concatenate((np.zeros([jmax + 1, kmax + 1, fmax]), ksi), 2) ksi_z = np.concatenate( (np.zeros([jmax + 1, kmax + 1, fmax]), ksi_z), 2) f_index += 1 f_names.append(['mixing', 'general']) F[:, :, :, f_index] = ksi_z Fsurf[:, :, :, f_index] = -ksi[:, [0], :] if self.input.v('BottomBC') in ['PartialSlip']: Fbed[:, :, :, f_index] = -ksi[:, [-1], :] # 5.b higher order no-slip coefficient for m in range(1, self.currentOrder + 1): roughness = self.input.v('Roughness' + str(m), range(0, jmax + 1), [0], range(0, fmax + 1)) if roughness is not None: u_str1 = 'u' + str(self.currentOrder - m) u = self.input.v(u_str1, range(0, jmax + 1), [kmax], range(0, fmax + 1)) ksi = ny.complexAmplitudeProduct(u, roughness, 2) ksi = np.concatenate( (np.zeros([jmax + 1, 1, fmax]), ksi), 2) Fbed[:, :, :, f_index] = ksi # 5.b Mixing-no-stress interaction ksi = np.zeros([jmax + 1, 1, fmax + 1], dtype=complex) for m in range(1, self.currentOrder + 1): for k in range(0, self.currentOrder - m + 1): for i in range(1, self.currentOrder - m - k + 1): zetapermutations = self.multiindex( m, self.currentOrder - m - k - i) # a. make the zeta^m product zetasum = 0 for perm in range(0, zetapermutations.shape[0]): zetaname = 'zeta' + str(zetapermutations[perm, 0]) zeta = self.input.v(zetaname, range(0, jmax + 1), [0], range(0, fmax + 1)) for comp in range(1, zetapermutations.shape[1]): zetaname = 'zeta' + str(zetapermutations[perm, comp]) zeta2 = self.input.v(zetaname, range(0, jmax + 1), [0], range(0, fmax + 1)) zeta = ny.complexAmplitudeProduct( zeta, zeta2, 2) zetasum = zetasum + zeta # b. make the (Av*uz)^(m) term Avuz = 0 for j in range(0, m + 1): if j == 0: Avder = self.input.v('Av' + str(i), range(0, jmax + 1), [0], range(0, fmax + 1)) else: Avder = self.input.d('Av' + str(i), range(0, jmax + 1), [0], range(0, fmax + 1), dim='z' * j) if Avder is not None: Avuz += scipy.misc.comb( m, j) * ny.complexAmplitudeProduct( Avder, self.surf_u_der[:, :, :, k, m - j + 1], 2) # use m-j+1 as we need u_z^(m-j) # c. add all to ksi if not isinstance(Avuz, int): ksi += 1. / np.math.factorial( m) * ny.complexAmplitudeProduct( Avuz, zetasum, 2) ksi = np.concatenate((np.zeros([jmax + 1, 1, fmax]), ksi), 2) f_index += 1 f_names.append(['mixing', 'no-stress']) Fsurf[:, :, :, f_index] = -ksi # 6. Stokes drift return flow # determine RHS terms per submodule - next for water level # Need to place this separate to make sure that stokes term are at the end. # This way they will not be taken into account for velocity equation if 'stokes' in self.submodulesToRun: gamma = 0 for m in range(1, self.currentOrder + 1): for k in range(0, self.currentOrder - m + 1): zetapermutations = self.multiindex( m, self.currentOrder - m - k) # a. make the zeta^m product zetasum = 0 for perm in range(0, zetapermutations.shape[0]): zetaname = 'zeta' + str(zetapermutations[perm, 0]) zeta = self.input.v(zetaname, range(0, jmax + 1), [0], range(0, fmax + 1)) for comp in range(1, zetapermutations.shape[1]): zetaname = 'zeta' + str(zetapermutations[perm, comp]) zeta2 = self.input.v(zetaname, range(0, jmax + 1), [0], range(0, fmax + 1)) zeta = ny.complexAmplitudeProduct(zeta, zeta2, 2) zetasum = zetasum + zeta # b. make the (u)^(m-1) term umz = self.surf_u_der[:, :, :, k, m - 1] # c. add all to chi gamma += 1. / np.math.factorial( m) * ny.complexAmplitudeProduct(umz, zetasum, 2) gamma = np.concatenate((np.zeros([jmax + 1, 1, fmax]), gamma), 2) f_index += 1 f_names.append(['stokes', '']) JuFirst[:, :, :, f_index] = gamma ## Solve equation uCoef, uFirst[:, :, :, : nRHSVelocity], uzCoef, uzFirst[:, :, :, : nRHSVelocity], AMatrix = uFunctionMomentumConservative( A, F, Fsurf, Fbed, self.input, hasMatrix= velocityMatrix) if not velocityMatrix: d['velocityMatrix'] = AMatrix del AMatrix ################################################################################################################ # water level ################################################################################################################ ## LHS terms # try to get zetaMatrix from the input. If it is not found, proceed to calculate the matrix again B = self.input.v( 'zetaMatrix' ) # known that this is numeric data, ask without arguments to retrieve full ndarray zetaMatrix = True if B is None: zetaMatrix = False utemp = uCoef.reshape( uCoef.shape[:2] + (1, ) + uCoef.shape[2:] ) # reshape as the 'f' dimension is not grid conform; move it to a higher dimension JuCoef = ny.integrate(utemp, 'z', kmax, 0, self.input.slice('grid')) JuCoef = JuCoef.reshape(jmax + 1, 1, ftot, ftot) # reshape back to original grid B = -G * JuCoef * self.input.v('B', np.arange( 0, jmax + 1)).reshape(jmax + 1, 1, 1, 1) ## RHS terms # advection, no-stress, baroclinic utemp = uFirst.reshape( uFirst.shape[:2] + (1, ) + uFirst.shape[2:] ) # reshape as the 'f' dimension is not grid conform; move it to a higher dimension JTemp = ny.integrate(utemp, 'z', kmax, 0, self.input.slice('grid')) JuFirst += JTemp.reshape( jmax + 1, 1, ftot, uFirst.shape[-1]) # reshape back to original grid BJuFirst = JuFirst * self.input.v('B', np.arange(0, jmax + 1)).reshape( jmax + 1, 1, 1, 1) # no open BC forcing & all terms in closed BC Fopen = np.zeros([1, 1, ftot, nRHS], dtype=complex) Fclosed = np.zeros([1, 1, ftot, nRHS], dtype=complex) Fclosed += -JuFirst[jmax, 0, :, :] * self.input.v('B', jmax) ## Solve equation zetaCoef, zetaxCoef, BMatrix = zetaFunctionMassConservative( B, BJuFirst, Fopen, Fclosed, self.input, hasMatrix=zetaMatrix) if not zetaMatrix: d['zetaMatrix'] = BMatrix del BMatrix zetax = ny.eliminateNegativeFourier(zetaxCoef, 2) zeta = ny.eliminateNegativeFourier(zetaCoef, 2) ################################################################################################################ # velocity ################################################################################################################ u = np.empty((jmax + 1, kmax + 1, ftot, nRHS), dtype=uCoef.dtype) for j in range(0, jmax + 1): u[j, :, :, :] = np.dot(uCoef[j, :, :, :], -G * zetaxCoef[j, 0, :, :]) u += uFirst u = ny.eliminateNegativeFourier(u, 2) ################################################################################################################ # Reduce number of components ################################################################################################################ # Select components by their velocity magnitude. # This is measured as the 1-norm over z and f and the 2-norm over x if maxContributions != 'all': for submod in self.submodulesToRun: f_names_numbers = zip( f_names, range(0, len(f_names)) ) # combine forcing names and its position in the 4th dimension of u and zeta f_submod = [ f_names_numbers[i] for i in range(0, len(f_names)) if f_names[i][0] == submod ] # take only the forcing component of a particular submodule # determine norm and sort the list if f_submod: unorm = [ np.linalg.norm( np.linalg.norm(u[:, :, :, i], 1, (1, 2)), 2, 0) for i in zip(*f_submod)[1] ] sorted_fnames = [ list(l) for l in zip(*sorted(zip(unorm, f_submod), key=lambda nrm: nrm[0])) ] # sorted list with entries (unorm, (forcing name, forcing position)) with smallest norm first else: unorm = [] sorted_fnames = [] # determine the contributions to be aggregated (redundant positions) redundant_positions = [ sorted_fnames[1][i][1] for i in range(0, len(unorm) - maxContributions) ] if len(redundant_positions) >= 1: # replace first redundant element by sum and label 'other' first_red_pos = redundant_positions[0] u[:, :, :, first_red_pos] = np.sum(u[:, :, :, redundant_positions], 3) zeta[:, :, :, first_red_pos] = np.sum( zeta[:, :, :, redundant_positions], 3) f_names[first_red_pos][1] = 'other' # remove other redundant positions u = np.delete(u, redundant_positions[1:], 3) zeta = np.delete(zeta, redundant_positions[1:], 3) [ f_names.pop(i) for i in sorted(redundant_positions[1:], reverse=True) ] ################################################################################################################ # vertical velocity ################################################################################################################ w = self.verticalVelocity(u) ################################################################################################################ # Make final dictionary to return ################################################################################################################ d['zeta' + str(self.currentOrder)] = {} d['u' + str(self.currentOrder)] = {} d['w' + str(self.currentOrder)] = {} for submod in self.submodulesToRun: if submod in zip(*f_names)[0]: d['zeta' + str(self.currentOrder)][submod] = {} d['u' + str(self.currentOrder)][submod] = {} d['w' + str(self.currentOrder)][submod] = {} for i, submod in enumerate(f_names): nf = ny.functionTemplates.NumericalFunctionWrapper( zeta[:, :, :, i], self.input.slice('grid')) nf.addDerivative(zetax[:, :, :, i], 'x') if submod == 'baroc': d['zeta' + str(self.currentOrder)][submod[0]] = nf.function d['u' + str(self.currentOrder)][submod[0]] = u[:, :, :, i] d['w' + str(self.currentOrder)][submod[0]] = w[:, :, :, i] else: d['zeta' + str(self.currentOrder)][submod[0]][submod[1]] = nf.function d['u' + str(self.currentOrder)][submod[0]][submod[1]] = u[:, :, :, i] d['w' + str(self.currentOrder)][submod[0]][submod[1]] = w[:, :, :, i] d['surfder'] = self.surf_u_der d['surfstress'] = self.surf_stress return d