Example #1
0
    def surfaceForcingDer(self, order, der):
        """Calculate forcing F in equation
        u_t^<order>(der)-( Av u_z^<order> )^(der+1) = F^<order>(der)    at surface z=0
        """
        jmax = self.input.v('grid', 'maxIndex', 'x')
        fmax = self.input.v('grid', 'maxIndex', 'f')

        forcing = np.zeros((jmax + 1, 1, fmax + 1), dtype=complex)

        # forcing from barotropic pressure gradient
        if der == 0:
            forcing += self.input.v('G') * self.input.d('zeta' + str(order),
                                                        range(0, jmax + 1),
                                                        [0],
                                                        range(0, fmax + 1),
                                                        dim='x')

        #  forcing by advection; only include this in the reconstruction if the equation at 'order' contained advection
        if 'adv' in self.input.getKeysOf('u' + str(order)):
            for order1 in range(0, order):
                order2 = order - order1 - 1
                for i in range(0, der + 1):
                    u = self.surf_u_der[:, :, :, order1, i]
                    ux = ny.derivative(
                        self.surf_u_der[:, :, :, order2, der - i], 'x',
                        self.input.slice('grid'))
                    forcing += scipy.misc.comb(
                        der, i) * ny.complexAmplitudeProduct(u, ux, 2)

                    if i == 0:
                        wstr = 'w' + str(order1)
                        w = self.input.v(wstr, range(0, jmax + 1), [0],
                                         range(0, fmax + 1))
                    else:
                        Bu = self.input.v('B', range(
                            0, jmax + 1), [0], range(
                                0, fmax + 1)) * self.surf_u_der[:, :, :,
                                                                order1, i - 1]
                        w = ny.derivative(
                            Bu, 'x', self.input.slice('grid')) / self.input.v(
                                'B', range(0, jmax + 1), [0], range(
                                    0, fmax + 1))
                    uz = self.surf_u_der[:, :, :, order2, der - i + 1]
                    forcing += scipy.misc.comb(
                        der, i) * ny.complexAmplitudeProduct(w, uz, 2)

        # TODO
        #if 'baroc' in self.submodulesToRun:
        #if 'densitydrift' in self.submodulesToRun:

        return forcing
Example #2
0
    def updateSurfaceData(self):
        jmax = self.input.v('grid', 'maxIndex', 'x')
        kmax = self.input.v('grid', 'maxIndex', 'z')
        fmax = self.input.v('grid', 'maxIndex', 'f')
        OMEGA = self.input.v('OMEGA')

        # 1. update velocity and its derivative of previous order
        ustr = 'u' + str(self.currentOrder - 1)
        self.surf_u_der[:, :, :, self.currentOrder - 1,
                        0] = self.input.v(ustr, range(jmax + 1), [0],
                                          range(fmax + 1))
        self.surf_u_der[:, :, :, self.currentOrder - 1,
                        1] = self.input.d(ustr,
                                          range(jmax + 1), [0],
                                          range(fmax + 1),
                                          dim='z')

        # 2. calculate other terms
        for order in range(0, self.currentOrder):
            der = self.currentOrder - order

            # 2a. update surface stress term
            forcing = self.surfaceForcingDer(order, der - 1)
            D = (np.arange(0, fmax + 1) * 1j * OMEGA).reshape(
                (1, 1, fmax + 1)) * np.ones((jmax + 1, 1, 1))
            self.surf_stress[:, :, :, order,
                             der - 1] = D * self.surf_u_der[:, :, :, order,
                                                            der - 1] + forcing

            # 2b. update surface velocity derivative
            sum_nu_u = np.zeros((jmax + 1, 1, fmax + 1), dtype=complex)
            for i in range(1, der + 1):
                if i == 1:
                    Avder = self.input.d('Av',
                                         range(0, jmax + 1), [0],
                                         range(0, fmax + 1),
                                         dim='z')  # first der of Av
                elif i == 2:
                    Av = self.input.d('Av',
                                      range(0, jmax + 1),
                                      range(0, kmax + 1),
                                      range(0, fmax + 1),
                                      dim='zz')
                    Avder = Av[:, [0], :]  # 2nd der of Av
                else:
                    Av = ny.derivative(Av, 'z', self.input.slice('grid'))
                    Avder = Av[:,
                               [0], :]  # every step: take a higher der of Av

                sum_nu_u += scipy.misc.comb(
                    der, i) * ny.complexAmplitudeProduct(
                        Avder, self.surf_u_der[:, :, :, order, der + 1 - i], 2)

            Av = self.input.v('Av', range(0, jmax + 1), [0],
                              range(0, fmax + 1))
            self.surf_u_der[:, :, :, order, der + 1] = -self.Avinv_multiply(
                Av, sum_nu_u - self.surf_stress[:, :, :, order, der - 1])
        return
    def run(self):
        self.logger.info('Running module HinderedSettling')
        d = {}

        ################################################################################################################
        # Load data
        ################################################################################################################
        jmax = self.input.v('grid', 'maxIndex', 'x')
        kmax = self.input.v('grid', 'maxIndex', 'z')
        cgel = self.input.v('cgel')
        mhs = self.input.v('mhs')
        ws0 = self.input.v('ws00')
        wsmin = self.input.v('wsmin')

        c = np.real(
            self.input.v('c0', range(0, jmax + 1), range(
                0, kmax + 1), 0)) + np.real(
                    self.input.v('c2', range(0, jmax + 1), range(0, kmax + 1),
                                 0))  # only subtidal
        phi = np.max(c, axis=1) / cgel

        ################################################################################################################
        # Computations
        ################################################################################################################
        # Richardson & Zaki 1954 formulation
        phi = np.maximum(np.minimum(phi, 1), 0)
        ws = np.maximum(ws0 * (1. - phi)**mhs, wsmin)

        ws_old = self.input.v('ws0', range(0, jmax + 1), 0, 0)
        ws_new = (1 - self.RELAX
                  ) * ws + self.RELAX * ws_old  # Relaxation over the iterands
        dws = ws_new - ws_old

        ################################################################################################################
        # Smoothing of increments in space
        ################################################################################################################
        # smooth by averaging with neighbours twice
        dws[1:-1] = self.local * dws[1:-1] + (1 - self.local) * (
            0.5 * dws[2:] + 0.5 * dws[:-2])
        dws[1:-1] = self.local * dws[1:-1] + (1 - self.local) * (
            0.5 * dws[2:] + 0.5 * dws[:-2])

        # final result and computation of change in this iteration
        ws = ws_old + dws
        ws = ny.savitzky_golay(ws, 7, 1)
        nf = ny.functionTemplates.NumericalFunctionWrapper(
            ws, self.input.slice('grid'))
        nf.addDerivative(
            ny.savitzky_golay(ny.derivative(ws, 'x', self.input), 7, 1), 'x')
        nf.addDerivative(
            ny.savitzky_golay(ny.secondDerivative(ws, 'x', self.input), 7, 1),
            'xx')

        d['ws0'] = nf.function
        self.difference = np.max(np.abs((ws_old - ws) / (ws_old)))
        return d
Example #4
0
    def verticalVelocity(self, u):
        x = self.input.v('grid', 'axis', 'x')
        B = self.input.v('B',
                         x=x).reshape([u.shape[0]] + [1] * (len(u.shape) - 1))
        Bx = self.input.d('B', x=x, dim='x').reshape([u.shape[0]] + [1] *
                                                     (len(u.shape) - 1))
        Hx = self.input.d('H', x=x, dim='x').reshape([u.shape[0]] + [1] *
                                                     (len(u.shape) - 1))
        Bux = Bx / B * u + ny.derivative(u, 'x', self.input.slice('grid'))
        kmax = self.input.v('grid', 'maxIndex', 'z')

        w = -ny.integrate(Bux, 'z', kmax, np.arange(0, kmax + 1),
                          self.input.slice('grid')) - u[:, -1, None,
                                                        Ellipsis] * Hx
        return w
    def availability(self, F, T, G, alpha1, alpha2):
        """Calculates the solution to the bed-evolution equation: the erodibility and availability of sediment

        Parameters:
            F - diffusive coefficient in the availability equation that goes with a_x
            T - coefficient (advective, diffusive and stokes) in the availability equation that goes with a

        Returns:
            a - availability of sediment
            f - erodibility of sediment
        """
        ################################################################################################################
        ## Init
        ################################################################################################################
        jmax = self.input.v('grid', 'maxIndex', 'x')
        B = self.input.v('B', range(0, jmax + 1), 0, 0)
        x = ny.dimensionalAxis(self.input, 'x')[:, 0, 0]
        dx = x[1:] - x[:-1]

        ################################################################################################################
        ## Solution to bed-evolution equation
        ################################################################################################################
        ## analytical solution
        if np.all(G == 0):
            P = np.zeros(jmax+1)
        else:
            P = integrate.cumtrapz(G / (F - 10 ** -6) * np.exp(integrate.cumtrapz(T / F, dx=dx, axis=0, initial=0)), dx=dx, axis=0, initial=0)

        exponent = np.exp(-integrate.cumtrapz(T / F, dx=dx, axis=0, initial=0))

        # Boundary conditions (analytical solution)
            # BC 1: total amount of sediment in the system
        if self.input.v('sedbc') == 'astar':
            astar = self.input.v('astar')
            k = (astar * np.trapz(B, dx=dx, axis=0) / np.trapz(B * exponent, dx=dx, axis=0))

            # BC 2: concentration at the seaward boundary
        elif self.input.v('sedbc') == 'csea':
            csea = self.input.v('csea')
            c000 = alpha1[0]
            k = csea / c000 * (self.input.v('grid', 'low', 'z', 0) - self.input.v('grid', 'high', 'z', 0))

            # BC 3: incorrect boundary description
        else:
            from src.util.diagnostics.KnownError import KnownError
            raise KnownError('incorrect seaward boundary type (sedbc) for sediment module')

        # final solution (analytical)
        f0uncap = (k - P) * exponent

        ## Check if f<1 everywhere,
        # if not compute numerical solution instead with a time-stepping routine that maximises f at 1.
        if all(f0uncap < 1):
            f0 = f0uncap
        else:
            f0, Smod = self.availability_numerical(np.real(T), np.real(F), np.real(f0uncap), k, alpha1, alpha2, G)

        ## compute derivative
        if np.all(G == 0) and all(f0uncap < 1):
            f0x = -T / F * f0uncap  # only use analytical derivative in case with no fluvial source of sediment and f<1; else not reliable.
        else:
            f0x = ny.derivative(f0, 'x', self.input.slice('grid'))

        return f0uncap, f0, f0x
Example #6
0
    def run(self):
        self.logger.info('Running module SalinityFirst')

        # Init
        jmax = self.input.v('grid', 'maxIndex', 'x')
        kmax = self.input.v('grid', 'maxIndex', 'z')
        fmax = self.input.v('grid', 'maxIndex', 'f')
        SIGMASAL = self.input.v('SIGMASAL')
        OMEGA = self.input.v('OMEGA')
        submodulesToRun = self.input.v('submodules')

        sx0 = self.input.d('s0',
                           range(0, jmax + 1),
                           range(0, kmax + 1),
                           range(0, fmax + 1),
                           dim='x')
        u0 = self.input.v('u0', range(0, jmax + 1), range(0, kmax + 1),
                          range(0, fmax + 1))
        s1var = self.input.v('s1var', 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))
        H = self.input.v('H', range(0, jmax + 1))
        B = self.input.v('B', range(0, jmax + 1))
        AKh = self.input.v('Kh', range(0, jmax + 1)) * B * H

        ################################################################################################################
        # Second-order salinity variation as function of first-order salinity closure
        ################################################################################################################
        # build, save and solve the velocity matrices in every water column
        #   LHS
        Kv = self.input.v('salinityMatrix')
        hasMatrix = True
        if Kv is None:
            Kv = self.input.v('Av', range(0, jmax + 1), range(0, kmax + 1),
                              range(0, fmax + 1)) / SIGMASAL
            hasMatrix = False

        #   RHS
        #   Allow for three submodules: advection, diffusion and nostress
        nRHS = len(self.input.getKeysOf('u1')) + 3
        f_index = -1
        f_names = []

        F = np.zeros([jmax + 1, kmax + 1, fmax + 1, nRHS], dtype=complex)
        Fsurf = np.zeros([jmax + 1, 1, fmax + 1, nRHS], dtype=complex)
        Fbed = np.zeros([jmax + 1, 1, fmax + 1, nRHS], dtype=complex)
        if 'advection' in submodulesToRun:
            # advection by u0*sx1
            sx1var = self.input.d('s1var',
                                  range(0, jmax + 1),
                                  range(0, kmax + 1),
                                  range(0, fmax + 1),
                                  dim='x')
            sz1var = self.input.d('s1var',
                                  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))

            f_index += 1
            f_names.append(['advection', 'u0-s1'])
            F[:, :, :, f_index] = -ny.complexAmplitudeProduct(
                u0, sx1var, 2) - ny.complexAmplitudeProduct(w0, sz1var, 2)
            del sx1var, sz1var, w0

            # advection by u1*sx0
            submods = self.input.getKeysOf('u1')
            for mod in submods:
                u1 = self.input.v('u1', mod, range(0, jmax + 1),
                                  range(0, kmax + 1), range(0, fmax + 1))
                f_index += 1
                f_names.append(['advection', 'u1_' + mod + '-s0'])
                F[:, :, :, f_index] = -ny.complexAmplitudeProduct(u1, sx0, 2)
                del u1

        if 'diffusion' in submodulesToRun:
            f_index += 1
            f_names.append(['diffusion', 's0'])
            F[:, :, 0, f_index] = (ny.derivative(AKh * sx0[:, 0, 0], 'x',
                                                 self.input.slice('grid')) /
                                   (B * H)).reshape((jmax + 1, 1)) * np.ones(
                                       (1, kmax + 1))

        if 'nostress' in submodulesToRun:
            D = (np.arange(0, fmax + 1) * 1j * OMEGA).reshape(
                (1, 1, fmax + 1)) * np.ones((jmax + 1, 1, 1))
            Kvsz1z = D * s1var[:, [0], :] + ny.complexAmplitudeProduct(
                u0[:, [0], :], sx0[:, [0], :], 2)

            f_index += 1
            f_names.append(['nostress', 's1-zeta0'])
            Fsurf[:, 0, :, f_index] = -ny.complexAmplitudeProduct(
                Kvsz1z, zeta0, 2).reshape((jmax + 1, fmax + 1))
            del D, Kvsz1z

        sCoef, sForced, szCoef, szForced, salinityMatrix = svarFunction(
            Kv, F, Fsurf, Fbed, self.input, hasMatrix=hasMatrix)
        del Kv

        ################################################################################################################
        # First-order salinity closure
        ################################################################################################################
        ## LHS terms
        #   First-order river discharge
        Q = -self.input.v('Q1', range(0, jmax + 1))

        #   Diffusion coefficient
        us = ny.complexAmplitudeProduct(u0, sCoef,
                                        2)[:, :, 0, 0]  # subtidal part of u*s
        us = ny.integrate(us, 'z', kmax, 0,
                          self.input.slice('grid')).reshape(jmax + 1)
        AK = np.real(AKh) - np.real(B * us)
        del us

        ## RHS terms
        nRHS_clo = nRHS + len(self.input.getKeysOf('u1')) + 3
        f_index_clo = -1
        f_names_clo = []

        F = np.zeros([jmax + 1, nRHS_clo])
        Fopen = np.zeros([1, nRHS_clo])
        Fclosed = np.zeros([1, nRHS_clo])
        if 'advection' in submodulesToRun:
            # advection by u0*s2
            us = ny.complexAmplitudeProduct(u0, sForced, 2)[:, :, [0], :]
            us = ny.integrate(us, 'z', kmax, 0,
                              self.input.slice('grid')).reshape(
                                  jmax + 1, nRHS)
            for i in range(0, nRHS):
                f_index_clo += 1
                f_names_clo.append(['advection', 'u0-s2_' + f_names[i][0]])
                F[:, f_index_clo] = -ny.derivative(np.real(B * us[:, i]), 'x',
                                                   self.input.slice('grid'))

            # advection by u1*s1
            submods = self.input.getKeysOf('u1')
            for mod in submods:
                u1 = self.input.v('u1', mod, range(0, jmax + 1),
                                  range(0, kmax + 1), range(0, fmax + 1))
                us = ny.complexAmplitudeProduct(u1, s1var, 2)[:, :, 0]
                us = ny.integrate(us, 'z', kmax, 0,
                                  self.input.slice('grid')).reshape(jmax + 1)

                f_index_clo += 1
                f_names_clo.append(['advection', 'u1_' + mod + '-s1'])
                F[:, f_index_clo] = -ny.derivative(np.real(B * us), 'x',
                                                   self.input.slice('grid'))
                del u1

            # surface term
            us = ny.complexAmplitudeProduct(u0[:, [0], :], s1var[:, [0], :], 2)
            us = ny.complexAmplitudeProduct(us[:, [0], :], zeta0, 2)[:, 0, 0]

            f_index_clo += 1
            f_names_clo.append(['advection', 'surface'])
            F[:, f_index_clo] = -ny.derivative(np.real(B * us), 'x',
                                               self.input.slice('grid'))
            del us

        if 'diffusion' in submodulesToRun:
            # Bed terms
            Hx = self.input.d('H', range(0, jmax + 1), dim='x')
            sx1var = self.input.d('s1var',
                                  range(0, jmax + 1),
                                  kmax,
                                  0,
                                  dim='x')

            f_index_clo += 1
            f_names_clo.append(['diffusion', 'bedslope'])
            F[:, f_index_clo] = - ny.derivative(np.real(AKh*s1var[:, -1, 0]*Hx), 'x', self.input.slice('grid'))/H \
                                - np.real(AKh/H*sx1var*Hx)

            # Surface term
            f_index_clo += 1
            f_names_clo.append(['diffusion', 'surface'])
            F[:, f_index_clo] = np.real(zeta0[:, 0, 0]) * ny.derivative(
                np.real(AKh * sx0[:, 0, 0]), 'x', self.input.slice('grid')) / H
            del sx1var, Hx

        ## Solve equation
        S1 = np.zeros((jmax + 1, 1, fmax + 1, nRHS_clo))
        Sx1 = np.zeros((jmax + 1, 1, fmax + 1, nRHS_clo))
        S1[:, 0, 0, :], Sx1[:, 0, 0, :] = sclosureFunction((Q, AK), F, Fopen,
                                                           Fclosed, self.input)

        ################################################################################################################
        # Second-order salinity variation
        ################################################################################################################
        s2 = np.zeros((jmax + 1, kmax + 1, fmax + 1, nRHS + 1), dtype=complex)
        sz2 = np.zeros((jmax + 1, kmax + 1, fmax + 1, nRHS + 1), dtype=complex)

        s2[:, :, :, :-1] = sForced
        sz2[:, :, :, :-1] = szForced
        f_names.append(['advection', 'u0-S1'])
        s2[:, :, :, -1] = np.sum(ny.complexAmplitudeProduct(sCoef, Sx1, 2), 3)
        sz2[:, :, :, -1] = np.sum(ny.complexAmplitudeProduct(szCoef, Sx1, 2),
                                  3)

        ################################################################################################################
        # Make final dictionary to return
        ################################################################################################################
        d = {}
        d['salinityMatrix'] = salinityMatrix

        d['s1'] = {}
        d['s2var'] = {}
        for submod in submodulesToRun:
            if submod in zip(*f_names_clo)[0]:
                d['s1'][submod] = {}
            if submod in zip(*f_names)[0]:
                d['s2var'][submod] = {}

        #    if submod in zip(*f_names)[0]:
        for i, mod in enumerate(f_names_clo):
            nf = ny.functionTemplates.NumericalFunctionWrapper(
                S1[:, :, :, i], self.input.slice('grid'))
            nf.addDerivative(Sx1[:, :, :, i], 'x')
            if len(mod) == 1:
                d['s1'][mod[0]] = nf.function
            if len(mod) == 2:
                d['s1'][mod[0]][mod[1]] = nf.function

        for i, mod in enumerate(f_names):
            nf2 = ny.functionTemplates.NumericalFunctionWrapper(
                s2[:, :, :, i], self.input.slice('grid'))
            nf2.addDerivative(sz2[:, :, :, i], 'z')
            if len(mod) == 1:
                d['s2var'][mod[0]] = nf2.function
            if len(mod) == 2:
                d['s2var'][mod[0]][mod[1]] = nf2.function

        return d
Example #7
0
    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]
Example #8
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
Example #9
0
    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
Example #10
0
    def run(self):
        ################################################################################################################
        ## 1. Init
        ################################################################################################################
        # self.timers[0].tic()

        ## prepare output message
        self.logger.info('Running MAW turbulence model')
        denstr = ''
        if self.betac ==0:
            denstr = '- not including density effects'
        self.logger.info('\tMAW rel. difference in Av in last iteration: %s %s' % (self.difference, denstr))

        d = {}

        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')
        rho0 = self.input.v('RHO0')
        uzmin = self.input.v('uzmin')

        Avold = self.input.v('Av', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1))
        Kvold = self.input.v('Kv', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1))
        sfold = self.input.v('Roughness', range(0, jmax+1), 0, 0)
        # self.timers[0].toc()

        ################################################################################################################
        ## 2. KEFitted run
        ################################################################################################################
        # self.timers[1].tic()
        d.update(self.kem.run())
        self.input.merge(d)

        # load data resulting from KEFitted model
        Avmid = self.input.v('Av', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1))
        Kvmid = Avmid/self.input.v('sigma_rho', range(0, jmax+1), range(0, kmax+1), [0])
        sfmid = self.input.v('Roughness', range(0, jmax+1), 0, 0)
        # self.timers[1].toc()

        ################################################################################################################
        ## 3. Density effects
        ################################################################################################################
        if self.betac == 0:     # no density effect included, first let KEFitted spin up
            Av0 = Avmid[:, :, 0]
            Kv0 = Kvmid[:, :, 0]
            sf = sfmid

            Cd = 1.
            MA_av = 1.
            MA_kv = 1.
            Ri = 0.
        else:
            ## Load data
            # self.timers[2].tic()
            cz = self.input.d('c0', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1), dim='z') + self.input.d('c1', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1), dim='z') + self.input.d('c2', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1), dim='z')
            uz = self.input.d('u0', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1), dim='z') + self.input.d('u1', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1), dim='z')
            zeta0 = self.input.v('zeta0', range(0, jmax+1), [0], range(0, fmax+1))
            H = self.input.v('grid', 'low', 'z', range(0, jmax+1)) - self.input.v('grid', 'high', 'z', range(0, jmax+1))
            # self.timers[2].tic()

            ## Convert to time series
            # self.timers[3].tic()
            cz = ny.invfft2(cz, 2, 90)
            uz = ny.invfft2(uz, 2, 90)
            zeta0 = ny.invfft2(zeta0, 2, 90)
            Avmid = ny.invfft2(Avmid, 2, 90)
            Kvmid = ny.invfft2(Kvmid, 2, 90)
            # self.timers[3].toc()
            # self.timers[4].tic()
            uzmin = np.ones(uz.shape)*uzmin

            ## Compute Richardson number
            Ri = -G*self.betac/rho0*cz/(uz**2+uzmin**2)

            Rida = 1./H.reshape((jmax+1, 1, 1))*ny.integrate(Ri.reshape((jmax+1, kmax+1, 1, Ri.shape[-1])), 'z', kmax, 0, self.input.slice('grid')).reshape((jmax+1, 1, Ri.shape[-1]))  # depth-average
            Rida += zeta0*(Ri[:, [0], :]-Rida)/H.reshape((jmax+1, 1, 1))        # depth average continued
            Rida0 = np.maximum(Rida, 0.)                                        # only accept positive Ri
            Ribed = np.maximum(Ri[:, [-1], :], 0.)                              # only accept positive Ri
            Ribedmax = self.input.v('Ribedmax')
            Ribed = np.minimum(Ribed, Ribedmax)                                 # 5-3-2018 limit near-bed Ri

            ## relaxation on Rida
            if hasattr(self, 'Rida'):       # Relaxation of Ri_da using previously saved value
                dRida = self.Rida - Rida0
                Rida = np.max((Rida0, np.min((dRida * (1 - self.RELAX), dRida * (1. + self.RELAX)), axis=0) + Rida0), axis=0)
                Rida = np.min((Rida,   np.max((dRida * (1 - self.RELAX), dRida * (1. + self.RELAX)), axis=0) + Rida0), axis=0)
                self.Rida = Rida
            else:                           # No value saved if the init found an available Ri. Then start with full signal computed here (do not use saved value, as this has been truncated to frequency components)
                Rida = Rida0

            # self.timers[4].toc()

            ## Compute damping functions
            # self.timers[5].tic()
            # Av
            MA_av = (1+10*Rida)**(-0.5)
            dAv = ny.fft(Avmid*MA_av, 2)[:, :, :fmax+1] - Avold
            Av = Avold + (1-self.RELAX)*(self.LOCAL*dAv + .5*(1-self.LOCAL)*dAv[[0]+range(0, jmax), :, :] + .5*(1-self.LOCAL)*dAv[range(1, jmax+1)+[jmax], :, :])
            # Av = Avold + dAv
            Av0 = Av[:, :, 0]

            # Kv
            MA_kv = (1+3.33*Rida)**(-1.5)
            dKv = ny.fft(Kvmid*MA_kv, 2)[:, :, :fmax+1] - Kvold
            Kv = Kvold + (1-self.RELAX)*(self.LOCAL*dKv + .5*(1-self.LOCAL)*dKv[[0]+range(0, jmax), :, :] + .5*(1-self.LOCAL)*dKv[range(1, jmax+1)+[jmax], :, :])
            # Kv = Kvold + dKv
            Kv0 = Kv[:, :, 0]

            # Sf
            Rfmean = np.mean(Ribed[:, 0, :]*(Kvmid*MA_kv)[:, 0, :]/(Avmid*MA_av)[:, 0, :], axis=-1)
            Cd = (1+5.5*Rfmean)**-2.
            damp_sf = Cd
            sf = sfmid*damp_sf
            dsf = sf - sfold
            sf = sfold + (1-self.RELAX)*(self.LOCAL*dsf + .5*(1-self.LOCAL)*dsf[[0]+range(0, jmax)] + .5*(1-self.LOCAL)*dsf[range(1, jmax+1)+[jmax]])
            # self.timers[5].toc()

            # process for output
            MA_av = ny.fft(MA_av, 2)[:, :, :fmax+1]
            MA_kv = ny.fft(MA_kv, 2)[:, :, :fmax+1]
            Ri = ny.fft(Ri, 2)[:, :, :fmax+1]

        ################################################################################################################
        ## Reference level
        ################################################################################################################
        if self.referenceLevel == 'True':
            self.input.merge({'Av': Av0, 'Roughness': sf})
            d['R'] = self.kem.RL.run()['R']

        ################################################################################################################
        ## Compute difference
        ################################################################################################################
        Av0s = ny.savitzky_golay(Av0[:, 0], self.filterlength, 1)
        difference = np.max(abs(Av0s-Avold[:, 0, 0])/abs(Av0s+10**-4))
        self.difference = copy.copy(difference)

        ###############################################################################################################
        # DEBUG plots
        ###############################################################################################################
        # import matplotlib.pyplot as plt
        # import step as st
        # x = ny.dimensionalAxis(self.input.slice('grid'), 'x')[:, 0,0]
        #
        # if self.betac > 0 and np.mod(self.iteration, 3)==0:  # and self.difference>0.15:
        #     st.configure()
        #     plt.figure(1, figsize=(2,2))
        #     plt.subplot(1,2,1)
        #     plt.plot(x/1000., Avold[:, 0, 0], label='old')
        #     plt.plot(x/1000., Av0[:, 0], label='new')
        #     plt.ylim(0, np.maximum(np.max(Av0[:, 0]), np.max(Avold[:, 0, 0])))
        #     plt.legend()
        #
        #     plt.subplot(1,2,2)
        #     plt.plot(x/1000., Avold[:, 0, 0]-Av0[:, 0])
        #     plt.twinx()
        #     plt.plot(x/1000., self.input.v('f', range(0, jmax+1)), color='grey')
        #     plt.ylim(0, 1.)
        #
        #     st.save('plot_'+str(len(x))+'_'+str(self.iteration))
        #
        #     plt.figure(2, figsize=(1, 2))
        #     ws = self.input.v('ws0', range(0, jmax+1), 0, 0)
        #     plt.plot(x/1000., ws)
        #
        #     st.save('ws_'+str(len(x))+'_'+str(self.iteration))


        ################################################################################################################
        ## Prepare Output
        ################################################################################################################
        # self.timers[6].tic()

        x = ny.dimensionalAxis(self.input.slice('grid'),'x')[:, 0,0]
        nf = ny.functionTemplates.NumericalFunctionWrapper(ny.savitzky_golay(Av0[:, 0], self.filterlength, 1).reshape((jmax+1, 1)), self.input.slice('grid'))
        nf.addDerivative(ny.savitzky_golay(ny.derivative(Av0[:, 0], 'x', self.input), self.filterlength, 1).reshape((jmax+1, 1)), 'x')
        nf.addDerivative(ny.savitzky_golay(ny.secondDerivative(Av0[:, 0], 'x', self.input), self.filterlength, 1).reshape((jmax+1, 1)), 'xx')
        d['Av'] = nf.function

        nf2 = ny.functionTemplates.NumericalFunctionWrapper(ny.savitzky_golay(Kv0[:, 0], self.filterlength, 1).reshape((jmax+1, 1)), self.input.slice('grid'))
        nf2.addDerivative(ny.savitzky_golay(ny.derivative(Kv0[:, 0], 'x', self.input), self.filterlength, 1).reshape((jmax+1, 1)), 'x')
        nf2.addDerivative(ny.savitzky_golay(ny.secondDerivative(Kv0[:, 0], 'x', self.input), self.filterlength, 1).reshape((jmax+1, 1)), 'xx')
        d['Kv'] = nf2.function

        d['Roughness'] = sf
        d['skin_friction'] = sfmid
        d['dampingFunctions'] = {}
        d['dampingFunctions']['Roughness'] = Cd
        d['dampingFunctions']['Av'] = MA_av
        d['dampingFunctions']['Kv'] = MA_kv
        d['Ri'] = Ri
        # self.timers[6].toc()

        ## Timers
        # self.timers[0].disp('0 init MAW')
        # self.timers[1].disp('1 KEFitted')
        # self.timers[2].disp('2 load data')
        # self.timers[3].disp('3 invfft')
        # self.timers[4].disp('4 Ri')
        # self.timers[5].disp('5 Compute Av, Kv, sf')
        # self.timers[6].disp('6 Load in dict')

        return d
Example #11
0
    def __operationsNumerical(self, value, *args, **kwargs):
        """Utility of .v().
        Deals with operations, such a derivation and integration on numerical data (scalar, array).
        Returns the value at the specified indices if no operation is prescribed

        Parameters:
            value (scalar or ndarray) - value containing the data
            args (lists, ndarray) - indices for each dimension.
                                    NB. these should already be tailormade (e.g. excess dimensions cut off)
                                    If no args are provided, the data is returned on the original grid.
            kwargs['operation'] (string, optional) - specification of operation
                                            n: negative
                                            d: derivative
                                            dd: second derivative
            kwargs['dim'] (string, int, optional) - axis to take the operation over (if applicable).
                                                    Can be given as dimension number or dimension name.

        Exception:
            KnownError if the data cannot be accessed using the operation

        Returns:
            value with operation executed or raise an exception
        """
        if kwargs.get('operation'):
            if kwargs.get('operation') == 'n':
                if args:
                    value = -value[np.ix_(*args)]
                else:
                    value = -value
            if kwargs.get('operation') == 'd':
                dim = kwargs.get('dim')
                import numbers
                for dir in list(set(
                        sorted(dim))):  # loop over all dimensions once
                    if isinstance(value, numbers.Number
                                  ):  # return 0 for derivative of constant
                        value = 0.
                    else:
                        order = len(
                            [i for i in dim if i == dir]
                        )  # collect the number of occurances of this dimension
                        if order == 1:
                            value = nf.derivative(
                                value,
                                dir,
                                self.slice('grid'),
                                *args,
                                DERMETHOD=kwargs.get('DERMETHOD'))
                        elif order == 2:
                            value = nf.secondDerivative(
                                value, dir, self.slice('grid'), *args)
                        else:
                            raise KnownError(
                                'Numerical derivatives of order %s are not implemented'
                                % str(order))
            ### Depreciated since v2.2 (02-03-2016) [dep01] ###
            if kwargs.get('operation') == 'dd':
                dim = kwargs.get('dim')
                value = nf.secondDerivative(value, dim, self.slice('grid'),
                                            *args)
            ### End ###
        else:
            if args:
                value = value[np.ix_(*args)]
        return value
Example #12
0
    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
Example #13
0
    def run(self):
        self.logger.info('Running module flocculation')
        d = {}
        ################################################################################################################
        # Load data
        ################################################################################################################
        jmax = self.input.v('grid', 'maxIndex', 'x')
        kmax = self.input.v('grid', 'maxIndex', 'z')
        fmax = self.input.v('grid', 'maxIndex', 'f')
        a = 1

        ################################################################################################################
        # Computations
        ################################################################################################################

        # Define constants
        kA = self.input.v('kA')
        kB = self.input.v('kB')
        g = self.input.v('G')  # gravitational accelaration
        mu = self.input.v('mu')  # dynamic viscocity
        rho0 = self.input.v('RHO0')
        rhos = self.input.v('RHOS')
        fs = self.input.v('fs')  #shape facor, if sperical --> pi/6
        G = self.input.v('Gs')  # shear rate
        Dp = self.input.v('Dp')  # primary particle size
        scaleShearRate = self.input.v('scaleShearRate')
        skip_first = self.input.v('skip_first')

        # Calculate shear rate G
        G = np.ones(jmax + 1) * G
        if scaleShearRate == 'True':
            G = self.shearRate(0.5)
        G = G.repeat((kmax + 1) * (fmax + 1)).reshape(jmax + 1, kmax + 1,
                                                      fmax + 1)

        # Calculate impact salinity on kA
        xx = self.input.v('grid', 'axis', 'x') * self.input.v('L')

        fSal = 1
        kAmin = 3 / 2. * kA
        if self.input.v('kASal') == 'True':
            s00 = self.input.v('s0', range(0, len(xx)), 0, 0,
                               dim='x').reshape(len(xx), 1)
            kAmin = 3 / 2. * 0.2908872
            aPar = 4.08532
            cPar = 0.03401

            fSal = (1 + cPar / kAmin *
                    (np.tanh(s00 - aPar) + 1)).reshape(jmax + 1)

        kA = 2 / 3. * kAmin * fSal
        kA = kA.repeat(
            (kmax + 1) * (fmax + 1)).reshape(jmax + 1, kmax + 1, fmax + 1)

        # Compute beta, tau and minimal settling veloccity wsmin
        beta = kA * g * (rhos - rho0) * np.power(
            G, -1. / 2.) / (kB * 18 * mu * rhos * fs)
        tau = (Dp**2 * g**2 *
               (-rho0 + rhos)**2) / (324. * G[:, :, 0]**1.5 * kB * mu**2)
        wsmin = (rhos - rho0) * g * math.pow(Dp, 2.) / (
            18 * mu)  # primary particle size particle, equals beta * kappa

        # Obtain estimated concentration from previous iteration
        c0 = self.input.v('c0', range(0, jmax + 1), range(0, kmax + 1),
                          range(0, fmax + 1))
        c1 = self.input.v('c1', range(0, jmax + 1), range(0, kmax + 1),
                          range(0, fmax + 1))
        c2 = self.input.v('c2', range(0, jmax + 1), range(0, kmax + 1),
                          range(0, fmax + 1))

        # 1. Compute the leading order settling velocity ws0

        ws0 = a * beta * (
            c0 + int(self.input.v('includec2') == 'True') * c2) + wsmin

        if self.input.v('spatial') == 'True':
            ws0[:, :, 2] = 0

        # 2. Compute the first order settling velocity ws1

        if skip_first != 'True':
            # Define constants alpha, Av, delta and kappa
            Av = self.input.v('Av', range(0, jmax + 1), range(0, kmax + 1),
                              range(0, fmax + 1))

            # 2a. compute ws1 contribution which linearly scales to the suspended sediment concentration

            ws1 = beta * c1

            # 2b. compute ws1 contribution which does not linearly scales to the suspended sediment concentration and
            # is due to inertia effects, settling and vertical diffusion.

            # Compute derivative of c00 and c02 which is required by ws1ContributionNonlinearInC()
            dzc00 = ny.derivative(c0, 'z', self.input.slice('grid'))[:, :, 0]
            dzc02 = ny.derivative(c0, 'z', self.input.slice('grid'))[:, :, 2]

            # Compute ws1 contribution which does not linearly scale to the suspended sediment concentration using
            # ws1ContributionNonlinearInC()
            wsAdditional = ws1ContributionNonlinearInC(
                A0=c0[:, :, 0],
                dA0=dzc00[:, :],
                A2=c0[:, :, 2],
                dA2=dzc02[:, :],
                beta=beta[:, :, 0],
                Kv=Av[:, :, 0] / self.input.v('sigma_rho'),
                tau=tau)

            # Add wsAdditional to ws1 which is due to the contribution which linearly scales to the suspended sediment
            # concentration
            ws1[:, :, 0] = ws1[:, :, 0] + wsAdditional[0]

            if self.input.v('spatial') != 'True':
                ws1[:, :, 2] = ws1[:, :, 2] + wsAdditional[1]
            else:
                ws1[:, :, 1:] = 0
        else:
            ws1 = np.zeros((jmax + 1, kmax + 1, fmax + 1), dtype=int)
            c1 = self.input.v('c1', range(0, jmax + 1), range(0, kmax + 1),
                              range(0, fmax + 1))
            print str('skipping first order ws')

        # Smooth settling velocity in longitudinal direction
        if self.input.v('smooth') == 'True':
            ord = 1  # order of smoothing
            xstart = 0  # start smoothing from longitudinal x-axis value.

            # Smooth ws0 over longitudinal x-axis for each depth zi and for f=0:2. Exclude upstream boundary point.
            for zi in range(0, kmax + 1):
                for kj in range(0, 3):
                    ws0[xstart:-1, zi, kj] = ny.savitzky_golay(ws0[xstart:-1,
                                                                   zi, kj],
                                                               window_size=15,
                                                               order=ord)
                    ws1[xstart:-1, zi, kj] = ny.savitzky_golay(ws1[xstart:-1,
                                                                   zi, kj],
                                                               window_size=15,
                                                               order=ord)

        # At the upstream border, remove temporal fluctuations in ws1
        ws1[-1, :, 1] = 0.
        ws1[-1, :, 2] = 0.

        ################################################################################################################
        # Iterative procedure
        ################################################################################################################

        # Check convergence criterion of Picard iterative procedure. If the convergence criterion is reached, stop
        # Picard iterative procedure.
        ws_old = self.input.v('ws0', range(0, jmax + 1), range(0, kmax + 1),
                              range(0, fmax + 1))
        ws1_old = self.input.v('ws1', range(0, jmax + 1), range(0, kmax + 1),
                               range(0, fmax + 1))

        self.difference = np.linalg.norm(
            np.sum(np.abs((ws_old[:, :, 0] - ws0[:, :, 0]) /
                          (ws_old[:, :, 0] + 0.1 * self.input.v('ws00'))),
                   axis=-1), np.inf)
        print self.difference

        # Check for nan values, if nan are present, change 'NanProblem' to True which stops the Picard iterative
        # procedure. To avoid problems in subsequent modules, set ws0 and ws1 to initial values.
        if ~np.all(np.isfinite(ws0)) or ~np.all(np.isfinite(ws0)):
            self.difference = 0
            d['NaNProblem'] = 'True'
            ws0 = ws0 * 0 + self.input.v('ws00')
            ws1 = ws1 * 0
            print 'ws1 or ws0 is not finite, calling stopping_criterion'

        # Check whether timeLimit is reached, if true, stop the Picard iterative procedure or use a different initial
        # value for ws00 and ws10
        if (datetime.now() -
                self.timeInit).seconds > self.input.v('timeLimit'):
            if self.input.v('ws00Skip') == None or self.ws00Try == len(
                    self.input.v('ws00Skip')):
                self.difference = 0  # this will stop the Picard method
                d['picardConverged'] = 'False'
                print 'Picard method did not converge'
            else:
                d['ws0'] = self.input.v('ws00Skip')[self.ws00Try]
                self.timeInit = datetime.now()
                print 'Picard method did not converge: trying next initial ws00 = ' + str(
                    self.input.v('ws00Skip')[self.ws00Try])
                self.ws00Try += 1

        # Save output of flocculation module
        d['ws1'] = 0.2 * ws1 + 0.8 * ws1_old
        d['ws0'] = 0.2 * ws0 + 0.8 * ws_old
        d['picardConverged'] = self.converging

        return d
Example #14
0
    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