Ejemplo n.º 1
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
Ejemplo n.º 2
0
def svarFunction(Kv, F, Fsurf, Fbed, data, hasMatrix=False):
    """Solve a function
    Ds - (Kv s_z)_z = -u0_z + F
    subject to
        Kv s_z (-H) = Fbed
        Kv s_z (0) = Fsurf

    The returned solution has a part 'sCoef' and 'szCoef' for the forcing by u_z and a part 'sForced' and 'szForced' for the
    forcing by F, Fbed and Fsurf.

    Args:
        Kv: (ndarray(jmax+1, kmax+1, fmax+1)) - data on eddy diffusivity
            or a salinityMatrix as calculated before by this function.
        F: (ndarray(jmax+1, kmax+1, fmax+1, nRHS)) - interior forcing. nRHS is the number of individual forcing components
        Fsurf: (ndarray(jmax+1, 1, fmax+1, nRHS)) - surface forcing. nRHS is the number of individual forcing components
        Fbed: (ndarray(jmax+1, 1, fmax+1, nRHS)) - surface forcing. nRHS is the number of individual forcing components
        data: (DataContainer) - should at least contain 'grid', 'OMEGA' and 'u0'
        hasMatrix: (bool) - if True then it is assumed that Kv contains a salinityMatrix as calculated by this function before.
                            The matrix is not computed again, which saves time.

    Returns:
        sCoef and szCoef: (ndarray(jmax+1, kmax+1, fmax+1, 1)) the solution s and its vertical derivative for the forcing by u0_z.
                            the final dimension '1' denotes a single forcing component.
        sForced and szForced: (ndarray(jmax+1, kmax+1, fmax+1, nRHS)) the solution s and its vertical derivative for the other forcings.
                            the solution is separated for each RHS term in F, Fsurf and Fbed.
        salinityMatrix: matrix used in computation. Can be reused for subsequent calls of this function.
    """
    # Init
    jmax = data.v('grid', 'maxIndex', 'x')  # maximum index of x grid (jmax+1 grid points incl. 0)
    kmax = data.v('grid', 'maxIndex', 'z')  # maximum index of z grid (kmax+1 grid points incl. 0)
    fmax = data.v('grid', 'maxIndex', 'f')  # maximum index of f grid (fmax+1 grid points incl. 0)
    OMEGA = data.v('OMEGA')
    uz = data.d('u0', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1), dim='z')
    u0bed = data.v('u0', range(0, jmax+1), [-1], range(0, fmax+1))
    ftot = 2*fmax+1

    # Determine bandwidth of eddy viscosity matrix
    bandwidth = 0
    for n in np.arange(fmax, -1, -1):
        if np.any(abs(Kv[:, :, n]) > 0):
            bandwidth = max(bandwidth, n)

    # Init Ctd
    nRHS = F.shape[-1]
    salinityMatrix = np.empty([jmax+1, 2*ftot+2*bandwidth+1, ftot*(kmax+1)], dtype=complex)
    szCoef = np.zeros([jmax+1, kmax+1, fmax+1, 1], dtype=complex)
    szForced = np.zeros([jmax+1, kmax+1, fmax+1, nRHS], dtype=complex)

    # build, save and solve the velocity matrices in every water column
    for j in range(0, jmax+1):
        # dz vectors
        dz = (data.v('grid', 'axis', 'z')[0, 1:]-data.v('grid', 'axis', 'z')[0, 0:-1])*data.n('H', j)
        dz = dz.reshape(dz.shape[0])
        dz_down = dz[:kmax-1].reshape(kmax-1, 1, 1)
        dz_up = dz[1:kmax].reshape(kmax-1, 1, 1)
        dz_av = 0.5*(dz_down+dz_up)

        ##### LEFT HAND SIDE #####
        if not hasMatrix:
            # Init
            A = np.zeros([2*ftot+2*bandwidth+1, ftot*(kmax+1)], dtype=complex)
            N = np.zeros([kmax+1, 2*bandwidth+1, ftot], dtype=complex)

            # Build eddy viscosity matrix blocks
            N[:, bandwidth, :] = Kv[j, :, 0].reshape(kmax+1, 1)*np.ones([1, ftot])
            for n in range(1, bandwidth+1):
                N[:, bandwidth+n, :-n] = 0.5*Kv[j, :, n].reshape(kmax+1, 1)*np.ones([1, ftot])
                N[:, bandwidth-n, n:] = 0.5*np.conj(Kv[j, :, n]).reshape(kmax+1, 1)*np.ones([1, ftot])

            # Build matrix. Discretisation: central for second derivative, central for first derivative
            #  NB. can use general numerical schemes as dz < 0
            a = -N[:-2, :, :]/dz_down
            b = N[1:kmax, :, :]/dz_up+N[1:kmax, :, :]/dz_down
            c = -N[2:, :, :]/dz_up
            b[:, bandwidth, :] += (np.arange(-fmax, ftot-fmax)*1j*OMEGA).reshape((1, ftot))*dz_av.reshape((kmax-1, 1))

            a = np.swapaxes(a, 0, 1)
            b = np.swapaxes(b, 0, 1)
            c = np.swapaxes(c, 0, 1)

            # Build matrix
            A[2*ftot:2*ftot+2*bandwidth+1, :-2*ftot] = a.reshape(a.shape[0], a.shape[1]*a.shape[2])
            A[2*fmax+1:2*fmax+2*bandwidth+2, ftot:-ftot] = b.reshape(a.shape[0], a.shape[1]*a.shape[2])
            A[0:2*bandwidth+1, 2*ftot:] = c.reshape(a.shape[0], a.shape[1]*a.shape[2])

            # Boundary conditions
            #   Surface (k=0)
            A[2*fmax+1:2*fmax+2*bandwidth+2, :ftot] = N[0, :, :]

            #   Bed (k=kmax)
            A[2*fmax+1:2*fmax+2*bandwidth+2, -ftot:] = N[-1, :, :]

            # save matrix
            salinityMatrix[j, Ellipsis] = A[Ellipsis]
            bandwidthA = bandwidth+ftot
        else:
            A = Kv[j, Ellipsis]     # if hasMatrix Av replaces the role of the matrix in this equation
            bandwidthA = (A.shape[0]-1)/2


        ##### RIGHT HAND SIDE #####
        #   Implicit part of the forcing uz0*dz*Sx
        umat = np.zeros((kmax+1, ftot), dtype=complex)
        umat[1:-1, fmax:ftot] = -uz[j, 1:-1, :]*dz_av.reshape((kmax-1, 1))
        uRHS_implicit = umat.reshape((ftot*(kmax+1), 1))

        #   Forcing from other factors
        uRHS = np.zeros([ftot*(kmax+1), nRHS], dtype=complex)
        uRHS[fmax:ftot, :] = Fsurf[j, 0, :, :]
        uRHS[-ftot+fmax:, :] = Fbed[j, 0, :, :]
        F_full = np.concatenate((np.zeros((jmax+1, kmax+1, fmax, nRHS)), F), 2)
        uRHS[ftot:-ftot, :] = 0.5*(F_full[j, 2:, :, :]-F_full[j, :-2, :, :]).reshape((kmax-1)*ftot, nRHS)

        ##### SOLVE #####
        sz = solve_banded((bandwidthA, bandwidthA), A, np.concatenate((uRHS_implicit, uRHS), 1), overwrite_ab=True, overwrite_b=True)
        sz = sz.reshape(kmax+1, ftot, 1+nRHS)
        szCoef[j, :, :, :] = ny.eliminateNegativeFourier(sz[:, :, :1], 1)
        szForced[j, :, :, :] = ny.eliminateNegativeFourier(sz[:, :, 1:], 1)
        del sz, uRHS_implicit, uRHS

    ##### INTEGRATION CONSTANT #####
    SIGMASAL = data.v('SIGMASAL')
    if hasMatrix:
        KvBed = data.v('Av', range(0, jmax+1), [kmax-1, kmax], range(0, fmax+1))/SIGMASAL # TODO: shift to turbulence model
    else:
        KvBed = Kv[:, [kmax-1, kmax], :]

    Dinv = np.diag((np.arange(0, fmax+1)*1j*OMEGA))
    Dinv[0, 0] = np.inf
    Dinv[range(0, fmax+1), range(0, fmax+1)] = Dinv[range(0, fmax+1), range(0, fmax+1)]**(-1)
    z = ny.dimensionalAxis(data.slice('grid'), 'z')
    dzbed = z[:, [-1], 0] - z[:, [-2], 0]
    sbedCoef = -ny.complexAmplitudeProduct(KvBed[:, [-2], :], szCoef[:, [-2], :, :], 2)/dzbed.reshape(dzbed.shape+(1, 1)) - u0bed.reshape(u0bed.shape+(1,))
    sbedCoef = np.dot(Dinv, sbedCoef)
    sbedCoef = np.rollaxis(sbedCoef, 0, 3)
    sbedForced = (Fbed-ny.complexAmplitudeProduct(KvBed[:, [-2], :], szForced[:, [-2], :, :], 2))/dzbed.reshape(dzbed.shape+(1, 1)) + F[:, [-1], :, :]
    sbedForced = np.dot(Dinv, sbedForced)
    sbedForced = np.rollaxis(sbedForced, 0, 3)

    ##### INTEGRATION #####
    sCoef = ny.integrate(szCoef, 'z', kmax, np.arange(0, kmax+1), data.slice('grid')) + sbedCoef*np.ones((1, kmax+1, 1, 1))
    sForced = ny.integrate(szForced, 'z', kmax, np.arange(0, kmax+1), data.slice('grid')) + sbedForced*np.ones((1, kmax+1, 1, 1))

    ##### CLOSURE FOR THE DEPTH-AVERAGED TIME-AVERAGED SALINITY VARIATION #####
    H = data.v('H', range(0, jmax+1)).reshape((jmax+1, 1, 1, 1))
    sCoef[:, :, [0], :] -= (ny.integrate(sCoef[:, :, [0], :], 'z', kmax, 0, data.slice('grid'))/H)*np.ones((1, kmax+1, 1, 1))
    sForced[:, :, [0], :] -= (ny.integrate(sForced[:, :, [0], :], 'z', kmax, 0, data.slice('grid'))/H)*np.ones((1, kmax+1, 1, 1))

    if hasMatrix:
        return sCoef, sForced, szCoef, szForced, Kv
    else:
        return sCoef, sForced, szCoef, szForced, salinityMatrix
Ejemplo n.º 3
0
    A = np.zeros((jmax + 1, jmax + 1))
    ##### LEFT-HAND SIDE #####
    x = ny.dimensionalAxis(data.slice('grid'), 'x')[:, 0, 0]
    dx = x[1:] - x[:-1]
    A[range(0, jmax), range(0, jmax)] = +AK[:-1] / dx  # main diagonal
    A[range(0, jmax),
      range(1, jmax + 1)] = Q[:-1] - AK[1:] / dx  # upper diagonal

    # BC closed end
    A[-1, -1] = -AK[-1]
    A[-1, 0] = AK[0]

    ##### RIGHT-HAND SIDE #####
    sRHS = np.zeros((jmax + 1, nRHS))
    sRHS[:-1, :] = F[:-1, :]
    sRHS[-1, :] = Q[0] * Fopen - Q[-1] * Fclosed + ny.integrate(
        F, 'x', 0, jmax, data.slice('grid'))

    ##### SOLVE #####
    Sx = np.zeros((jmax + 1, 1, 1, nRHS))
    Sx[:, 0, 0, :] = np.linalg.solve(A, sRHS)

    ##### INTEGRATE ######
    # integrate from back to front to make sure that the landward BC is guaranteed
    S = ny.integrate(Sx, 'x', jmax, range(0, jmax + 1),
                     data.slice('grid')) + Fclosed

    ##### CORRECTION ######
    # Integration errors may cause the solution to not satisfy the boundary conditions.
    # By the definition of integration here, the landward boundary condition is satisfied, but the seaward condition is not
    # Apply a correction that scales the salinity profile
    #for i in range(0, nRHS):
Ejemplo n.º 4
0
    def growthrate(self, Ceco, init=False):
        """
        Function largely copied from growth function above, returns the growth rate mu for output purposes
        (IN FUTURE FIND BETTER WAY TO STRUCTURE THIS)
        """
        jmax = self.input.v('grid', 'maxIndex', 'x')
        kmax = self.input.v('grid', 'maxIndex', 'z')

        kp = self.input.v('kp')
        E0 = self.input.v('E0')
        HI = self.input.v('HI')
        mu = {}

        T = 49 * 25.655 * 3600  # approximate
        t = np.linspace(0, T, 1000)

        # Growth rate (Eppley, 1972)
        Temp = self.input.v('Temp', range(0, jmax + 1), [0], [0])
        mu0 = self.input.v('mu00', range(0, jmax + 1), [0], [0])
        mu_Eppley = .851 * 1.066**Temp
        mumax = self.input.v('mu00') * np.log(
            2
        ) * mu_Eppley  # need log(2) as Eppley's number is in doublings/day (not in 1/day)
        mu['mumax'] = mumax

        # Limitations:
        N = Ceco['nitrogen'][:, 0]  # Nitrogen. Assume well-mixed
        Phos = Ceco['phosphorous'][:, 0]  # Phosphorous. Assume well-mixed
        Pprim = -ny.primitive(
            np.real(Ceco['phytoplankton']), 'z', 0, kmax,
            self.input.slice('grid'))  # primitive counted from surface

        z = ny.dimensionalAxis(self.input.slice('grid'), 'z')[:, :, 0]

        # Light - background
        kbg = self.input.v('kbg')
        kbg = kbg * z.reshape((jmax + 1, kmax + 1, 1, 1))

        # Light - sediment
        kc = self.input.v('kc')
        c00 = np.real(
            self.input.v('c0', range(0, jmax + 1), range(0, kmax + 1), [0],
                         [0]))
        c00int = ny.integrate(c00, 'z', 0, range(0, kmax + 1),
                              self.input.slice('grid'))
        c04 = np.real(
            self.input.v('c0', range(0, jmax + 1), range(0, kmax + 1), [2],
                         [0]))
        c04int = ny.integrate(c04, 'z', 0, range(0, kmax + 1),
                              self.input.slice('grid'))
        OMEGA = self.input.v('OMEGA')
        cint = c00int + c04int * np.cos(2 * OMEGA * t.reshape(
            (1, 1, 1, len(t))))

        kc = (kc * cint)

        # Light - daily cycle
        omega_E = self.input.v('omega_E')  # in 1/hr
        dE = np.maximum(np.sin(t * omega_E), 0).reshape((1, 1, 1, len(t)))

        # Light - self-shading
        kself = -kp * np.cumsum(Pprim, axis=1).reshape(
            (jmax + 1, kmax + 1, 1, 1))

        # Light - total and decomposition
        #   night
        dayinds = np.where(dE[0, 0, 0, :] > 0)[0]
        tau_night = np.float(len(dayinds)) / np.float(len(t))

        #   day
        k = kbg + kc + kself
        alpha_day = np.exp(k[:, :, :, dayinds])
        E_day = E0 * dE[:, :, :, dayinds] * alpha_day
        dE_day = dE[:, :, :, dayinds]
        FE_day = E_day / np.sqrt(HI**2 + E_day**2)
        FE = {}
        FE['daily'] = (1. - dE_day) / (1 - E_day / E0) * FE_day
        FE['background'] = dE_day * (1. - alpha_day) / (1 - E_day / E0) * (
            1 - np.exp(kbg)) / (3. + 1e-4 - np.exp(kbg) - np.exp(
                kc[:, :, :, dayinds]) - np.exp(kself)) * FE_day
        FE['sediment'] = dE_day * (1. - alpha_day) / (1 - E_day / E0) * (
            1 - np.exp(kc[:, :, :, dayinds])) / (3. + 1e-4 - np.exp(kbg) -
                                                 np.exp(kc[:, :, :, dayinds]) -
                                                 np.exp(kself)) * FE_day
        FE['self-shading'] = dE_day * (1. - alpha_day) / (1 - E_day / E0) * (
            1 - np.exp(kself)) / (3. + 1e-4 - np.exp(kbg) - np.exp(
                kc[:, :, :, dayinds]) - np.exp(kself)) * FE_day
        # mu['FE']['daily']       = (1.-dE_day)/(4.-dE_day-np.exp(kbg)-np.exp(kc[:, :,:, dayinds])-np.exp(kself))*FE_day
        # mu['FE']['background']  = (1.-np.exp(kbg))/(4.-dE_day-np.exp(kbg)-np.exp(kc[:, :,:, dayinds])-np.exp(kself))*FE_day
        # mu['FE']['sediment']    = (1.-np.exp(kc[:, :,:, dayinds]))/(4.-dE_day-np.exp(kbg)-np.exp(kc[:, :,:, dayinds])-np.exp(kself))*FE_day
        # mu['FE']['self-shading']= (1.-np.exp(kself))/(4.-dE_day-np.exp(kbg)-np.exp(kc[:, :,:, dayinds])-np.exp(kself))*FE_day

        # N
        HN = self.input.v('HN')
        FN = (N / (HN + N)).reshape((jmax + 1, 1, 1, 1))

        # Phos
        HP = self.input.v('HP')
        FP = (Phos / (HP + Phos)).reshape((jmax + 1, 1, 1, 1))

        mu = mumax * tau_night * np.mean(
            np.minimum(np.minimum(FN, FP), FE_day), axis=-1)
        return mu, tau_night, mumax, FN, FP, FE
Ejemplo n.º 5
0
    def PgrowthNE(self, Ch, Chprim, Chint, X, init=False):
        # Init
        jmax = self.input.v('grid', 'maxIndex', 'x')
        kmax = self.input.v('grid', 'maxIndex', 'z')

        kp = self.input.v('kp')
        E0 = self.input.v('E0')
        HI = self.input.v('HI')

        T = 8 * 25.655 * 3600  # approximate
        t = np.linspace(0, T, 100)
        # T = 49*25.655*3600      # approximate
        # t = np.linspace(0, T, 5000)

        # Growth rate (Eppley, 1972)
        Temp = self.input.v('Temp', range(0, jmax + 1), [0])
        mu0 = self.input.v('mu00', range(0, jmax + 1), [0])
        mu_Eppley = .851 * 1.066**Temp
        mumax = mu0 * np.log(
            2
        ) * mu_Eppley  # need log(2) as Eppley's number is in doublings/day (not in 1/day)

        # Limitations:
        N = Ch[:, 0, 1] * X[:, 1]
        Phos = Ch[:, 0, 2] * X[:, 2]
        Ph = Ch[:, :, 0]
        Phprim = Chprim[:, :, 0]

        if init:
            self.G_Pgrowth = {}
            z = ny.dimensionalAxis(self.input.slice('grid'), 'z')[:, :, 0]

            # Light - background
            kbg = self.input.v('kbg')
            self.kbg = kbg * z.reshape((jmax + 1, kmax + 1, 1))

            # Light - sediment
            kc = self.input.v('kc')
            c00 = np.real(
                self.input.v('c0', range(0, jmax + 1), range(0, kmax + 1),
                             [0]))
            c00int = ny.integrate(c00, 'z', 0, range(0, kmax + 1),
                                  self.input.slice('grid'))
            c04 = np.real(
                self.input.v('c0', range(0, jmax + 1), range(0, kmax + 1),
                             [2]))
            c04int = ny.integrate(c04, 'z', 0, range(0, kmax + 1),
                                  self.input.slice('grid'))
            OMEGA = self.input.v('OMEGA')
            cint = c00int + c04int * np.cos(2 * OMEGA * t.reshape(
                (1, 1, len(t))))

            self.kc = (kc * cint)

            # Light - daily cycle
            omega_E = self.input.v('omega_E')  # in 1/hr
            self.E = np.maximum(E0 * np.sin(t / 3600. * omega_E - 1.6),
                                0).reshape((1, 1, len(t)))

        if init or kp > 0:
            # Light - self-shading
            self.kself = -kp * np.cumsum(Phprim * X[:, [0]], axis=1).reshape(
                (jmax + 1, kmax + 1, 1))

        # Light - total
        k = self.kbg + self.kc + self.kself
        E = self.E * np.exp(k)
        FE = E / np.sqrt(HI**2 + E**2)

        # N
        HN = self.input.v('HN')
        FN = (N / (HN + N)).reshape((jmax + 1, 1, 1))

        # Phos
        HP = self.input.v('HP')
        FP = (Phos / (HP + Phos)).reshape((jmax + 1, 1, 1))

        mu = mumax * np.mean(np.minimum(np.minimum(FN, FP), FE), axis=2)
        # mu = mumax*np.minimum(np.minimum(np.mean(FN, axis=2), np.mean(FP, axis=2)), np.mean(FE, axis=2))

        muint = ny.integrate(mu * Ph, 'z', kmax, 0,
                             self.input.slice('grid'))[:, 0]
        return {'growth': self.B * muint * X[:, 0]}
Ejemplo n.º 6
0
def zetaFunctionMassConservative(M,
                                 F,
                                 Fopen,
                                 Fclosed,
                                 data,
                                 source=None,
                                 hasMatrix=False):
    # Init
    jmax = data.v('grid', 'maxIndex', 'x')
    fmax = data.v('grid', 'maxIndex', 'f')
    OMEGA = data.v('OMEGA')
    ftot = 2 * fmax + 1

    x = data.v('grid', 'axis', 'x')
    dx = (x[1:] - x[:-1]) * data.v('L')

    B = data.v('B', x=x[:-1] + .5 *
               (x[1:] - x[:-1]))  # widths between two grid points

    ##### LEFT HAND SIDE #####
    if not hasMatrix:
        # determine bandwith
        bandwidth = 0
        for n in np.arange(ftot - 1, -1, -1):
            for m in np.arange(ftot - 1, -1, -1):
                if any(abs(M[:, 0, n, m]) > 0):
                    bandwidth = max(bandwidth, n - m, -n + m)

        # init
        A = np.zeros([2 * ftot + 2 * bandwidth + 1, ftot * (jmax + 1)],
                     dtype=complex)
        Mdiag = np.zeros([jmax + 1, 2 * bandwidth + 1, ftot], dtype=complex)
        Mdiag[:, bandwidth, :] = np.diagonal(M[:, 0, :, :], 0, 1, 2)
        for n in range(1, bandwidth + 1):
            Mdiag[:, bandwidth + n, :-n] = np.diagonal(M[:, 0, :, :], -n, 1, 2)
            Mdiag[:, bandwidth - n, n:] = np.diagonal(M[:, 0, :, :], n, 1, 2)

        # dx vectors
        Bdx_down = (dx[:jmax - 1] * B[:jmax - 1]).reshape(jmax - 1, 1, 1)
        Bdx_up = (dx[1:jmax] * B[1:jmax]).reshape(jmax - 1, 1, 1)
        dx_av = 0.5 * (dx[1:jmax] + dx[:jmax - 1]).reshape(jmax - 1, 1)

        # Build matrix
        a = Mdiag[:-2, :, :] / Bdx_down
        b = -Mdiag[1:-1, :, :] / Bdx_down - Mdiag[1:-1, :, :] / Bdx_up
        c = Mdiag[2:, :, :] / Bdx_up
        b[:, bandwidth, :] += (np.arange(-fmax, ftot - fmax) * 1j *
                               OMEGA).reshape(1, ftot) * dx_av

        a = np.swapaxes(a, 0, 1)
        b = np.swapaxes(b, 0, 1)
        c = np.swapaxes(c, 0, 1)

        A[2 * ftot:2 * ftot + 2 * bandwidth + 1, :-2 * ftot] += a.reshape(
            a.shape[0], a.shape[1] * a.shape[2])
        A[2 * fmax + 1:2 * fmax + 2 * bandwidth + 2,
          ftot:-ftot] += b.reshape(a.shape[0], a.shape[1] * a.shape[2])
        A[:2 * bandwidth + 1, 2 * ftot:] += c.reshape(a.shape[0],
                                                      a.shape[1] * a.shape[2])

        # Boundary conditions
        #   Sea (j=0)
        b = -Mdiag[0, :, :] / (dx[0] * B[0])
        b[bandwidth, :] += 0.5 * np.arange(-fmax,
                                           ftot - fmax) * 1j * OMEGA * dx[0]
        c = Mdiag[1, :, :] / (dx[0] * B[0])

        A[2 * fmax + 1:2 * fmax + 2 * bandwidth + 2, :ftot] += b
        A[:2 * bandwidth + 1, ftot:2 * ftot] += c

        #   Weir (j=jmax)
        A[2 * fmax + 1:2 * fmax + 2 * bandwidth + 2, -ftot:] += Mdiag[-1, :, :]
        bandwidth = bandwidth + ftot
    else:
        A = M
        bandwidth = (A.shape[0] - 1) / 2

    ##### RIGHT HAND SIDE #####
    nRHS = F.shape[-1]
    zRHS = np.zeros([ftot * (jmax + 1), nRHS], dtype=complex)
    for i in range(0, nRHS):
        # forcing on open boundary
        zRHS[:ftot,
             i] = -np.arange(-fmax, fmax + 1) * 1j * OMEGA * Fopen[0, 0, :, i]

        # forcing on closed boundary
        zRHS[-ftot:, i] = Fclosed[0, 0, :, i]

        # internal forcing
        bdx_up = (dx[1:] * B[1:]).reshape(jmax - 1, 1)
        bdx_down = (dx[:-1] * B[:-1]).reshape(jmax - 1, 1)
        bdx0 = dx[0] * B[0]
        zRHS[ftot:-ftot,
             i] = -((F[2:, 0, :, i] - F[1:-1, 0, :, i]) / bdx_up -
                    (F[1:-1, 0, :, i] - F[:-2, 0, :, i]) / bdx_down).reshape(
                        (jmax - 1) * ftot)
        if source is not None:
            zRHS[ftot:-ftot, i] += (
                0.5 * (source[1:-1, 0, :, i] + source[2:, 0, :, i]) - 0.5 *
                (source[1:-1, 0, :, i] + source[:-2, 0, :, i])).reshape(
                    (jmax - 1) * ftot)
        zRHS[:ftot, i] += -(F[1, 0, :, i] - F[0, 0, :, i]) / bdx0

    ##### SOLVE #####
    zetax = solve_banded((bandwidth, bandwidth),
                         A,
                         zRHS,
                         overwrite_ab=False,
                         overwrite_b=True)
    zetax = zetax.reshape(jmax + 1, 1, ftot, nRHS)

    # integrate to zeta
    zeta = integrate(zetax.reshape((jmax + 1, 1, 1, ftot, nRHS)),
                     'x',
                     0,
                     np.arange(0, jmax + 1),
                     data.slice('grid'),
                     INTMETHOD='INTERPOLSIMPSON')
    zeta = zeta.reshape((jmax + 1, 1, ftot, nRHS))

    zetaOpenBoundary = Fopen[0, None, 0, None, :, :] * np.ones(
        [jmax + 1, 1, ftot, nRHS], dtype=complex)
    zeta += zetaOpenBoundary

    return zeta, zetax, A
Ejemplo n.º 7
0
    def run(self):
        """

        Returns:
            Dictionary with results. At least contains the variables listed as output in the registry
        """
        self.logger.info('Running module HydroLead')

        # Init
        jmax = self.input.v('grid', 'maxIndex', 'x')
        kmax = self.input.v('grid', 'maxIndex', 'z')
        fmax = self.input.v('grid', 'maxIndex', 'f')
        G = self.input.v('G')
        ftot = 2 * fmax + 1
        submodulesToRun = self.input.v('submodules')

        # check if the river term should be compensated for by reference level. Only if river is on and non-zero
        if 'river' in submodulesToRun and self.input.v('Q0') != 0:
            RiverReferenceCompensation = 1
        else:
            RiverReferenceCompensation = 0

        ################################################################################################################
        # velocity as function of water level
        ################################################################################################################
        # build, save and solve the velocity matrices in every water column
        Av = self.input.v('Av', range(0, jmax + 1), range(0, kmax + 1),
                          range(0, fmax + 1))
        F = np.zeros([jmax + 1, kmax + 1, ftot, RiverReferenceCompensation])
        Fsurf = np.zeros([jmax + 1, 1, ftot, RiverReferenceCompensation])
        Fbed = np.zeros([jmax + 1, 1, ftot, RiverReferenceCompensation])

        if RiverReferenceCompensation:  # for reference level variation
            F[:, :, fmax,
              0] = -G * self.input.d('R', range(0, jmax + 1), dim='x').reshape(
                  (jmax + 1, 1)) * np.ones((1, kmax + 1))

        uCoef, uLead, uzCoef, uzLead, velocityMatrix = uFunctionMomentumConservative(
            Av, F, Fsurf, Fbed, self.input)

        ################################################################################################################
        # water level
        ################################################################################################################
        ## LHS terms
        utemp = uCoef.reshape(
            uCoef.shape[:2] + (1, ) + uCoef.shape[2:]
        )  # reshape as the 'f' dimension is not grid conform; move it to a higher dimension
        JuCoef = ny.integrate(utemp, 'z', kmax, 0, self.input.slice('grid'))
        JuCoef = JuCoef.reshape(jmax + 1, 1, ftot,
                                ftot)  # reshape back to original grid
        BJuCoef = -G * JuCoef * self.input.v('B', np.arange(
            0, jmax + 1)).reshape(jmax + 1, 1, 1, 1)

        #   open BC: tide
        Fopen = np.zeros([1, 1, ftot, len(submodulesToRun)], dtype=complex)
        if 'tide' in submodulesToRun:
            Fopen[0, 0, fmax:,
                  submodulesToRun.index('tide')] = ny.amp_phase_input(
                      self.input.v('A0'), self.input.v('phase0'), (fmax + 1, ))

        #   closed BC: river
        Fclosed = np.zeros([1, 1, ftot, len(submodulesToRun)], dtype=complex)
        if RiverReferenceCompensation:
            Fclosed[0, 0, fmax,
                    submodulesToRun.index('river')] = -self.input.v('Q0')

        ## RHS terms
        IntForce = np.zeros(
            [jmax + 1, 1, ftot, len(submodulesToRun)], dtype=complex)
        if RiverReferenceCompensation:
            utemp = uLead.reshape(
                uLead.shape[:2] + (1, ) + uLead.shape[2:]
            )  # reshape as the 'f' dimension is not grid conform; move it to a higher dimension
            JuLead = ny.integrate(utemp, 'z', kmax, 0,
                                  self.input.slice('grid'))
            JuLead = JuLead.reshape(jmax + 1, 1, ftot) * self.input.v(
                'B', np.arange(0, jmax + 1)).reshape(
                    jmax + 1, 1, 1)  # reshape back to original grid
            IntForce[:, :, :, submodulesToRun.index('river')] = JuLead[:, :, :]
            Fclosed[0, 0, :,
                    submodulesToRun.index('river')] += -JuLead[jmax, 0, :]

        ## Solve equation
        zetaCoef, zetaxCoef, zetaMatrix = zetaFunctionMassConservative(
            BJuCoef, IntForce, Fopen, Fclosed, self.input)
        zetax = ny.eliminateNegativeFourier(zetaxCoef, 2)
        zeta = ny.eliminateNegativeFourier(zetaCoef, 2)

        ################################################################################################################
        # velocity
        ################################################################################################################
        u = np.empty((jmax + 1, kmax + 1, ftot, len(submodulesToRun)),
                     dtype=uCoef.dtype)
        uz = np.empty((jmax + 1, kmax + 1, ftot, len(submodulesToRun)),
                      dtype=uCoef.dtype)
        for j in range(0, jmax + 1):
            u[j, :, :, :] = np.dot(uCoef[j, :, :, :],
                                   -G * zetaxCoef[j, 0, :, :])
            uz[j, :, :, :] = np.dot(uzCoef[j, :, :, :],
                                    -G * zetaxCoef[j, 0, :, :])
        if RiverReferenceCompensation:
            u[:, :, :, submodulesToRun.index('river')] += uLead[:, :, :, 0]
            uz[:, :, :, submodulesToRun.index('river')] += uzLead[:, :, :, 0]
        u = ny.eliminateNegativeFourier(u, 2)
        uz = ny.eliminateNegativeFourier(uz, 2)
        ################################################################################################################
        # vertical velocity
        ################################################################################################################
        w = self.verticalVelocity(u)

        ################################################################################################################
        # Make final dictionary to return
        ################################################################################################################
        d = {}
        d['velocityMatrix'] = velocityMatrix
        d['zetaMatrix'] = zetaMatrix
        d['zeta0'] = {}
        d['u0'] = {}
        d['w0'] = {}
        for i, submod in enumerate(submodulesToRun):
            nf = ny.functionTemplates.NumericalFunctionWrapper(
                zeta[:, :, :, i], self.input.slice('grid'))
            nf.addDerivative(zetax[:, :, :, i], 'x')
            d['zeta0'][submod] = nf.function

            nfu = ny.functionTemplates.NumericalFunctionWrapper(
                u[:, :, :, i], self.input.slice('grid'))
            nfu.addDerivative(uz[:, :, :, i], 'z')
            d['u0'][submod] = nfu.function
            d['w0'][submod] = w[:, :, :, i]

        return d
Ejemplo n.º 8
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
Ejemplo n.º 9
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
Ejemplo n.º 10
0
    def run(self):
        self.logger.info('Running module SalinityLead')

        # 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')

        ################################################################################################################
        # First-order salinity variation as function of leading-order salinity closure
        ################################################################################################################
        # build, save and solve the velocity matrices in every water column
        Kv = self.input.v('Av', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1))/SIGMASAL
        F = np.zeros([jmax+1, kmax+1, fmax+1, 0])
        Fsurf = np.zeros([jmax+1, 1, fmax+1, 0])
        Fbed = np.zeros([jmax+1, 1, fmax+1, 0])

        sCoef, _, szCoef, _, salinityMatrix = svarFunction(Kv, F, Fsurf, Fbed, self.input)

        ################################################################################################################
        # Leading-order salinity closure
        ################################################################################################################
        ## LHS terms
        #   First-order river discharge
        Q = -self.input.v('Q1', range(0, jmax+1))
        #   First-order river discharge or zero if not available
        # u1riv = self.input.v('u1', 'river', range(0, jmax+1), range(0, kmax+1))
        # B = self.input.v('B', range(0, jmax+1))
        # if u1riv is None:
        #     Q = np.zeros((jmax+1))
        #     self.logger.warning('No first-order river discharge found in module SalinityLead')
        # else:
        #     Q = ny.integrate(u1riv, 'z', kmax, 0, self.input.slice('grid'))
        #     Q = Q*B
        # del u1riv

        #   Diffusion coefficient
        #   part 1) diffusive transport
        H = self.input.v('H', range(0, jmax+1))
        B = self.input.v('B', range(0, jmax+1))
        Kh = self.input.v('Kh', range(0, jmax+1))
        AK = np.real(H*B*Kh)

        #   part 2) advective transport
        u0 = self.input.v('u0', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1))
        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(B*us)

        del us, u0, H, B

        ## RHS terms
        F = np.zeros([jmax+1, 1])   # dimensions (jmax+1, NumberOfForcings)

        #   open BC: effect of the sea
        Fopen = np.zeros([1, 1])
        Fopen[0, 0] = self.input.v('ssea')

        # closed BC: always zero. This is by assumption that the salinity vanishes for x=L
        Fclosed = np.zeros([1, 1])

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

        ################################################################################################################
        # First-order salinity variation
        ################################################################################################################
        s1 = ny.complexAmplitudeProduct(sCoef, Sx0, 2)
        sz1 = ny.complexAmplitudeProduct(szCoef, Sx0, 2)

        ################################################################################################################
        # Make final dictionary to return
        ################################################################################################################
        d = {}
        d['salinityMatrix'] = salinityMatrix
        nf = ny.functionTemplates.NumericalFunctionWrapper(S0[:, :, :, 0], self.input.slice('grid'))
        nf.addDerivative(Sx0[:, :, :, 0], 'x')
        d['s0'] = nf.function

        nf2 = ny.functionTemplates.NumericalFunctionWrapper(s1[:, :, :, 0], self.input.slice('grid'))
        nf2.addDerivative(sz1[:, :, :, 0], 'z')
        d['s1var'] = nf2.function
        return d
Ejemplo n.º 11
0
    def run(self):
        ################################################################################################################
        ## Get data
        ################################################################################################################
        # grid sizes
        fmax = self.input.v('grid', 'maxIndex', 'f')
        kmax = self.input.v('grid', 'maxIndex', 'z')
        jmax = self.input.v('grid', 'maxIndex', 'x')

        # grid axes, dimensionless and with dimension
        x = self.input.v('grid', 'axis',
                         'x')  # dimensionless x axis between 0 and 1 (jmax+1)
        z = self.input.v('grid', 'axis', 'z',
                         0)  # dimensionless z axis between 0 and 1 (kmax+1)
        x_km = ny.dimensionalAxis(self.input.slice('grid'), 'x', x=x, z=0,
                                  f=0)  # x axis in m between 0 and L (jmax+1)

        L = self.input.v('grid', 'high', 'x')  # length in m (1)
        B = self.input.v('B', x=x, z=[0], f=[0])  # width (jmax+1, 1, 1)

        # variables
        Av = self.input.v('Av', x=x, z=0.5,
                          f=range(0,
                                  fmax + 1))  # Eddy viscosity (jmax+1, fmax+1)
        Roughness = self.input.v('Roughness', x=x, z=0, f=range(
            0, fmax + 1))  # Partial slip coefficient (jmax+1, fmax+1)

        zeta = self.input.v('zeta0', x=x, z=0, f=range(
            0, fmax + 1)) + self.input.v(
                'zeta1', x=x, z=0, f=range(
                    0, fmax + 1))  # water level (jmax+1, fmax+1)
        u = self.input.v('u0', x=x, z=z, f=range(0, fmax + 1)) + self.input.v(
            'u1', x=x, z=z, f=range(
                0, fmax + 1))  # horizontal velocity (jmax+1, kmax+1, fmax+1)
        c = self.input.v('c0', x=x, z=z, f=range(0, fmax + 1)) + self.input.v(
            'c1', x=x, z=z, f=range(0, fmax + 1)) + self.input.v(
                'c2', x=x, z=z, f=range(
                    0, fmax + 1))  # concentration (jmax+1, kmax+1, fmax+1)

        StotalB = ny.integrate(
            ny.integrate(B * c, 'z', kmax, 0, self.input.slice('grid')), 'x',
            0, jmax, self.input.slice('grid'))  # compute total sediment stock
        print 'Total sediment stock in domain (mln kg): ' + str(
            np.real(StotalB[0, 0, 0]) / 1.e6)

        # use data from measurements
        measurementset = self.input.v('measurementset')
        x_waterlevel = self.input.v(measurementset, 'x_waterlevel')
        x_velocity = self.input.v(measurementset, 'x_velocity')
        zeta_meas = self.input.v(measurementset,
                                 'zeta',
                                 x=x_waterlevel / L,
                                 z=0,
                                 f=range(0, 3))
        ucomp_meas = self.input.v(measurementset,
                                  'u_comp',
                                  x=x_velocity / L,
                                  z=0,
                                  f=range(0, 3))

        ################################################################################################################
        ## Plot
        ################################################################################################################
        st.configure()

        # Figure 1 - Water level amplitude
        plt.figure(1, figsize=(1, 2))
        plt.subplot2grid((1, 8), (0, 0), colspan=7)
        for n in range(0, 3):
            if n == 0:
                p = plt.plot(x_km / 1000.,
                             abs(zeta[:, n] +
                                 self.input.v('R', range(0, jmax + 1))),
                             label='$M_' + str(2 * n) + '$')
            else:
                p = plt.plot(x_km / 1000.,
                             abs(zeta[:, n]),
                             label='$M_' + str(2 * n) + '$')
            plt.plot(x_waterlevel / 1000.,
                     abs(zeta_meas[:, n]),
                     'o',
                     color=p[0].get_color())
        plt.ylabel('$|\hat{\zeta}|$ $(m)$')
        plt.xlabel('x (km)')
        plt.legend(bbox_to_anchor=(1.15, 1.05))
        plt.xlim(np.min(x_km / 1000.), np.max(x_km / 1000.))
        plt.title('Water level amplitude')

        # Figure 2 - Water level phase
        plt.figure(2, figsize=(1, 2))
        plt.subplot2grid((1, 8), (0, 0), colspan=7)
        for n in range(0, 3):
            p = plt.plot(x_km / 1000.,
                         -np.angle(zeta[:, n]) * 180 / np.pi,
                         label='$M_' + str(2 * n) + '$')
            if n == 1 or n == 2:
                plt.plot(x_waterlevel / 1000.,
                         -np.angle(zeta_meas[:, n]) * 180 / np.pi,
                         'o',
                         color=p[0].get_color())
        plt.ylabel('$\phi(\hat{\zeta})$ $(deg)$')
        plt.xlabel('x (km)')
        plt.ylim(-180, 180)
        plt.legend(bbox_to_anchor=(1.15, 1.05))
        plt.xlim(np.min(x_km / 1000.), np.max(x_km / 1000.))
        plt.title('Water level phase')

        # Figure 3 - Velocity amplitude
        plt.figure(3, figsize=(1, 2))
        plt.subplot2grid((1, 8), (0, 0), colspan=7)
        # velocity components
        for n in range(0, 3):
            p = plt.plot(x_km / 1000.,
                         abs(u[:, 0, n]),
                         label='$M_' + str(2 * n) + '$')
            plt.plot(x_velocity / 1000.,
                     abs(ucomp_meas[:, n]),
                     'o',
                     color=p[0].get_color())
        plt.ylabel('$|\hat{u}|$ $(m/s)$')
        plt.xlabel('x (km)')
        plt.title('Surface velocity amplitude')
        plt.xlim(np.min(x_km / 1000.), np.max(x_km / 1000.))
        plt.legend(bbox_to_anchor=(1.15, 1.05))

        # Figure 4 - Roughness, Eddy viscosity
        plt.figure(4, figsize=(1, 2))
        plt.subplot(1, 2, 1)
        for n in range(0, fmax + 1):
            plt.plot(x_km / 1000, abs(Av[:, n]))
        plt.ylabel(r'$|\hat{A}_{\nu}|$ $(m^2/s)$')
        plt.xlabel('x (km)')

        plt.subplot(1, 2, 2)
        for n in range(0, fmax + 1):
            plt.plot(x_km / 1000,
                     abs(Roughness[:, n]),
                     label='$M_' + str(2 * n) + '$')
        plt.ylabel(r'$|\hat{s}_{f}|$ $(m/s)$')
        plt.xlabel('x (km)')

        # Figure 5 - surface concentration
        plt.figure(5, figsize=(1, 2))
        for n in range(0, fmax + 1):
            p = plt.plot(x_km / 1000., abs(c[:, 0, n]))
        plt.xlabel('x (km)')
        plt.ylabel('|c| $(kg/m^3)$')
        plt.title('Surface sediment concentration')

        # Figure 6 - availability
        plt.figure(11, figsize=(1, 1))
        a = self.input.v('a', range(0, jmax + 1), 0, 0)
        if self.input.v('a') is not None:
            plt.plot(x_km / 1000., a)
            plt.legend()
            plt.xlabel('x (km)')
            plt.ylabel('a')
            plt.title('sediment availability')

        st.show()

        return {}
Ejemplo n.º 12
0
    def run(self):
        self.logger.info('Running module StaticAvailability')

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

        c0 = self.input.v('hatc0', 'a', range(0, jmax + 1), range(0, kmax + 1),
                          range(0, fmax + 1))
        c1_a0 = self.input.v('hatc1', 'a', range(0, jmax + 1),
                             range(0, kmax + 1), range(0, fmax + 1))
        c1_a0x = self.input.v('hatc1', 'ax', range(0, jmax + 1),
                              range(0, kmax + 1), range(0, fmax + 1))
        if isinstance(c1_a0x, bool):
            c1_a0x = np.zeros((jmax + 1, kmax + 1, fmax + 1))

        d = {}

        c0_int = ny.integrate(c0, 'z', kmax, 0, self.input.slice('grid'))
        B = self.input.v('B', range(0, jmax + 1), [0], [0])
        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))
        Kh = self.input.v('Kh', range(0, jmax + 1), [0], [0])

        ################################################################################################################
        ## Second order closure
        ################################################################################################################
        u1 = self.input.v('u1', range(0, jmax + 1), range(0, kmax + 1),
                          range(0, fmax + 1))

        d['T'] = {}
        d['F'] = {}
        T0 = 0
        F0 = 0

        ## Transport T  ############################################################################################
        ## T.1. - u0*c1_a0
        # Total
        c1a_f0 = c1_a0
        T0 += ny.integrate(ny.complexAmplitudeProduct(u0, c1a_f0, 2), 'z',
                           kmax, 0, self.input.slice('grid'))

        # Decomposition
        for submod in self.input.getKeysOf('hatc1', 'a'):
            if submod == 'erosion':
                for subsubmod in self.input.getKeysOf('hatc1', 'a', 'erosion'):
                    c1_a0_comp = self.input.v('hatc1', 'a', submod, subsubmod,
                                              range(0, jmax + 1),
                                              range(0, kmax + 1),
                                              range(0, fmax + 1))
                    c1a_f0_comp_res = c1_a0_comp
                    d['T'] = self.dictExpand(
                        d['T'], subsubmod,
                        ['TM' + str(2 * n) for n in range(0, fmax + 1)
                         ])  # add submod index to dict if not already
                    # transport with residual availability
                    for n in range(0, fmax + 1):
                        tmp = np.zeros(c1a_f0_comp_res.shape, dtype=complex)
                        tmp[:, :, n] = c1a_f0_comp_res[:, :, n]
                        tmp = ny.integrate(
                            ny.complexAmplitudeProduct(u0, tmp, 2), 'z', kmax,
                            0, self.input.slice('grid'))[:, 0, 0]
                        if any(abs(tmp)) > 10**-14:
                            d['T'][subsubmod]['TM' + str(2 * n)] += tmp
            else:
                c1_a0_comp = self.input.v('hatc1', 'a', submod,
                                          range(0,
                                                jmax + 1), range(0, kmax + 1),
                                          range(0, fmax + 1))
                c1a_f0_comp_res = c1_a0_comp
                d['T'] = self.dictExpand(
                    d['T'], submod,
                    ['TM' + str(2 * n) for n in range(0, fmax + 1)
                     ])  # add submod index to dict if not already
                # transport with residual availability
                for n in range(0, fmax + 1):
                    tmp = np.zeros(c1a_f0_comp_res.shape, dtype=complex)
                    tmp[:, :, n] = c1a_f0_comp_res[:, :, n]
                    tmp = ny.integrate(ny.complexAmplitudeProduct(u0, tmp, 2),
                                       'z', kmax, 0,
                                       self.input.slice('grid'))[:, 0, 0]
                    if any(abs(tmp)) > 10**-14:
                        d['T'][submod]['TM' + str(2 * n)] += tmp

        ## T.2. - u1*c0
        # Total
        T0 += ny.integrate(ny.complexAmplitudeProduct(u1, c0, 2), 'z', kmax, 0,
                           self.input.slice('grid'))

        # Decomposition
        for submod in self.input.getKeysOf('u1'):
            u1_comp = self.input.v('u1', submod, range(0, jmax + 1),
                                   range(0, kmax + 1), range(0, fmax + 1))
            d['T'] = self.dictExpand(
                d['T'], submod,
                ['TM' + str(2 * n) for n in range(0, fmax + 1)
                 ])  # add submod index to dict if not already
            # transport with residual availability
            for n in range(0, fmax + 1):
                tmp = np.zeros(u1_comp.shape, dtype=complex)
                tmp[:, :, n] = u1_comp[:, :, n]
                if submod == 'stokes':
                    tmp = ny.integrate(ny.complexAmplitudeProduct(tmp, c0, 2),
                                       'z', kmax, 0,
                                       self.input.slice('grid'))[:, 0, 0]
                    if any(abs(tmp)) > 10**-14:
                        d['T'][submod] = self.dictExpand(
                            d['T'][submod], 'TM' + str(2 * n),
                            ['return', 'drift'])
                        d['T'][submod]['TM0']['return'] += tmp
                else:
                    tmp = ny.integrate(ny.complexAmplitudeProduct(tmp, c0, 2),
                                       'z', kmax, 0,
                                       self.input.slice('grid'))[:, 0, 0]
                    if any(abs(tmp)) > 10**-14:
                        d['T'][submod]['TM' + str(2 * n)] += tmp

        ## T.5. - u0*c0*zeta0
        # Total
        T0 += ny.complexAmplitudeProduct(
            ny.complexAmplitudeProduct(u0[:, [0], :], c0[:, [0], :], 2), zeta0,
            2)

        # Decomposition
        uzeta = ny.complexAmplitudeProduct(u0[:, [0], :], zeta0, 2)
        d['T'] = self.dictExpand(
            d['T'], 'stokes', ['TM' + str(2 * n) for n in range(0, fmax + 1)])
        # transport with residual availability
        for n in range(0, fmax + 1):
            tmp = np.zeros(c0[:, [0], :].shape, dtype=complex)
            tmp[:, :, n] = c0[:, [0], n]
            tmp = ny.complexAmplitudeProduct(uzeta, tmp, 2)[:, 0, 0]
            if any(abs(tmp)) > 10**-14:
                d['T']['stokes']['TM' + str(2 * n)]['drift'] += tmp

        ## T.6. - u1riv*c2rivriv
        c2 = self.input.v('hatc2', 'a', 'erosion', 'river_river',
                          range(0, jmax + 1), range(0, kmax + 1),
                          range(0, fmax + 1))
        u1riv = self.input.v('u1', 'river', range(0, jmax + 1),
                             range(0, kmax + 1), range(0, fmax + 1))
        if u1riv is not None:
            d['T'] = self.dictExpand(
                d['T'], 'river_river',
                'TM0')  # add submod index to dict if not already
            tmp = ny.integrate(ny.complexAmplitudeProduct(u1riv, c2, 2), 'z',
                               kmax, 0, self.input.slice('grid'))
            if any(abs(tmp[:, 0, 0])) > 10**-14:
                d['T']['river_river']['TM0'] = tmp[:, 0, 0]

            T0 += tmp

        ## T.7. - diffusive part
        # Total
        c0x = self.input.d('hatc0',
                           'a',
                           range(0, jmax + 1),
                           range(0, kmax + 1),
                           range(0, fmax + 1),
                           dim='x')
        T0 += -Kh * ny.integrate(c0x, 'z', kmax, 0, self.input.slice('grid'))

        c2x = self.input.d('hatc2',
                           'a',
                           'erosion',
                           'river_river',
                           range(0, jmax + 1),
                           range(0, kmax + 1),
                           range(0, fmax + 1),
                           dim='x')
        T0 += -Kh * ny.integrate(c2x, 'z', kmax, 0, self.input.slice('grid'))

        # Decomposition
        d['T'] = self.dictExpand(d['T'], 'diffusion_tide', ['TM0'])
        d['T'] = self.dictExpand(d['T'], 'diffusion_river', ['TM0'])
        # transport with residual availability
        tmp = -(Kh * ny.integrate(c0x, 'z', kmax, 0,
                                  self.input.slice('grid')))[:, 0, 0]
        if any(abs(tmp)) > 10**-14:
            d['T']['diffusion_tide']['TM0'] = tmp
        tmp = -(Kh * ny.integrate(c2x, 'z', kmax, 0,
                                  self.input.slice('grid')))[:, 0, 0]
        if any(abs(tmp)) > 10**-14:
            d['T']['diffusion_river']['TM0'] = tmp

        ## Diffusion F  ############################################################################################
        ## F.1. - u0*C1ax*f0
        # Total
        F0 += ny.integrate(ny.complexAmplitudeProduct(u0, c1_a0x, 2), 'z',
                           kmax, 0, self.input.slice('grid'))

        # Decomposition
        for submod in self.input.getKeysOf('hatc1', 'ax'):
            c1_ax0_comp = self.input.v('hatc1', 'ax', submod,
                                       range(0, jmax + 1), range(0, kmax + 1),
                                       range(0, fmax + 1))
            d['F'] = self.dictExpand(
                d['F'], submod,
                ['FM' + str(2 * n) for n in range(0, fmax + 1)
                 ])  # add submod index to dict if not already
            # transport with residual availability
            for n in range(0, fmax + 1):
                tmp = np.zeros(u0.shape, dtype=complex)
                tmp[:, :, n] = u0[:, :, n]
                tmp = ny.integrate(
                    ny.complexAmplitudeProduct(tmp, c1_ax0_comp, 2), 'z', kmax,
                    0, self.input.slice('grid'))[:, 0, 0]
                if any(abs(tmp)) > 10**-14:
                    d['F'][submod]['FM' + str(2 * n)] += tmp

        ## F.3. - diffusive part
        # Total
        F0 += -Kh * ny.integrate(c0, 'z', kmax, 0, self.input.slice('grid'))
        F0 += -Kh * ny.integrate(c2, 'z', kmax, 0, self.input.slice('grid'))

        # Decomposition
        d['F'] = self.dictExpand(d['F'], 'diffusion_tide', ['FM0'])
        d['F'] = self.dictExpand(d['F'], 'diffusion_river', ['FM0'])
        # transport with residual availability
        tmp = -(Kh * ny.integrate(c0, 'z', kmax, 0,
                                  self.input.slice('grid')))[:, 0, 0]
        if any(abs(tmp)) > 10**-14:
            d['F']['diffusion_tide']['FM0'] = tmp
        tmp = -(Kh * ny.integrate(c2, 'z', kmax, 0,
                                  self.input.slice('grid')))[:, 0, 0]
        if any(abs(tmp)) > 10**-14:
            d['F']['diffusion_river']['FM0'] = tmp

        ## Solve    ################################################################################################
        ## Add all mechanisms & compute a0c
        from src.DataContainer import DataContainer
        dc = DataContainer(d)
        dc.merge(self.input.slice('grid'))
        T_til = np.real(dc.v('T', range(0, jmax + 1)))
        F_til = np.real(dc.v('F', range(0, jmax + 1)))

        # DEBUG: CHECKS IF COMPOSITE T, F == total T, F
        # print np.max(abs((dc.v('T', range(0, jmax+1))-T0[:, 0, 0])/(T0[:, 0, 0]+10**-10)))
        # print np.max(abs((dc.v('F', range(0, jmax+1))-F0[:, 0, 0])/(F0[:, 0, 0]+10**-10)))

        integral = -ny.integrate(T_til / (F_til - 10**-6), 'x', 0,
                                 range(0, jmax + 1), self.input.slice('grid'))
        if self.input.v('Qsed') is None:
            G = 0
        else:
            G = self.input.v('Qsed') / B[-1, 0, 0]

        P = ny.integrate(G / (F_til - 10**-6) * np.exp(-integral), 'x', 0,
                         range(0, jmax + 1), self.input.slice('grid'))
        ################################################################################################################
        # Boundary condition 1
        ################################################################################################################
        if self.input.v('sedbc') == 'astar':
            astar = self.input.v('astar')
            k = astar * ny.integrate(B[:, 0, 0], 'x', 0, jmax,
                                     self.input.slice('grid')) / ny.integrate(
                                         B[:, 0, 0] * np.exp(integral), 'x', 0,
                                         jmax, self.input.slice('grid'))

            f0 = (k - P) * np.exp(integral)
            f0x = (-T_til * f0 - G) / (F_til - 10**-6)

        ################################################################################################################
        # Boundary condition 2
        ################################################################################################################
        elif self.input.v('sedbc') == 'csea':
            csea = self.input.v('csea')
            c000 = np.real(c0_int[0, 0, 0])
            k = csea / c000 * (self.input.v('grid', 'low', 'z', 0) -
                               self.input.v('grid', 'high', 'z', 0))
            f0 = (k - P) * np.exp(integral)
            f0x = (-T_til * f0 - G) / (F_til - 10**-6)

        else:
            from src.util.diagnostics.KnownError import KnownError
            raise KnownError(
                'sediment boundary sedbc not known: use astar or csea')

        ################################################################################################################
        # Store in dict
        ################################################################################################################
        d['a'] = f0
        d['c0'] = c0 * f0.reshape((jmax + 1, 1, 1))
        d['c1'] = c1_a0 * f0.reshape((jmax + 1, 1, 1)) + c1_a0x * f0x.reshape(
            (jmax + 1, 1, 1))
        d['c2'] = c2 * f0.reshape((jmax + 1, 1, 1))

        return d
Ejemplo n.º 13
0
def zetaFunctionUncoupled(n, M, F, Fopen, Fclosed, data, hasMatrix=False):
    # Init
    jmax = data.v('grid', 'maxIndex', 'x')
    OMEGA = data.v('OMEGA')

    x = data.v('grid', 'axis', 'x')
    dx = (x[1:] - x[:-1]) * data.v('L')

    B = data.v('B', x=x[:-1] + .5 *
               (x[1:] - x[:-1]))  # widths between two grid points

    ##### LEFT HAND SIDE #####
    if not hasMatrix:
        # init
        A = np.zeros([3, jmax + 1], dtype=complex)
        # dx vectors
        Bdx_down = (dx[:jmax - 1] * B[:jmax - 1])
        Bdx_up = (dx[1:jmax] * B[1:jmax])
        dx_av = 0.5 * (dx[1:jmax] + dx[:jmax - 1])

        # Build matrix
        a = M[:-2] / Bdx_down
        b = -M[1:-1] / Bdx_down - M[1:-1] / Bdx_up
        c = M[2:] / Bdx_up
        b += n * 1j * OMEGA * dx_av

        A[2, :-2] += a
        A[1, 1:-1] += b
        A[0, 2:] += c

        # Boundary conditions
        #   Sea (j=0)
        b = -M[0] / (dx[0] * B[0])
        b += 0.5 * n * 1j * OMEGA * dx[0]
        c = M[1] / (dx[0] * B[0])

        A[1, 0] += b
        A[0, 1] += c

        #   Weir (j=jmax)
        A[1, -1] += M[-1]
    else:
        A = M

    ##### RIGHT HAND SIDE #####
    nRHS = F.shape[-1]
    zRHS = np.zeros([jmax + 1, nRHS], dtype=complex)

    # forcing on open boundary
    zRHS[0, :] = -n * 1j * OMEGA * Fopen[0, :]

    # forcing on closed boundary
    zRHS[-1, :] = Fclosed[0, :]

    # internal forcing
    FdivBav = 0.5 * (F[1:, :] + F[:-1, :]) / B.reshape((jmax, 1))
    zRHS[1:-1, :] = -FdivBav[1:] + FdivBav[:-1]
    zRHS[0, :] += -FdivBav[0]

    ##### SOLVE #####
    zetax = solve_banded((1, 1), A, zRHS, overwrite_ab=False, overwrite_b=True)
    zetax = zetax.reshape(jmax + 1, nRHS)

    # integrate to zeta
    zeta = integrate(zetax.reshape((jmax + 1, 1, 1, nRHS)),
                     'x',
                     0,
                     np.arange(0, jmax + 1),
                     data.slice('grid'),
                     INTMETHOD='TRAPEZOIDAL')
    zeta = zeta.reshape((jmax + 1, nRHS))

    zeta += Fopen[0, :]

    return zeta, zetax, A
Ejemplo n.º 14
0
    def uRelax(self, order, init):
        """Compute the absolute velocity and absolute velocity times the depth at 'order',
        i.e. |u|^<order>, (|u|(H+R+zeta))^<order>.
        Then make a relaxation of these signals using the the previous iteration and relaxtion factor set as class var.

        Implements two methods:
            order == None: truncation method. Else: scaling method
            init (bool): initial iteration?
        """
        # Init
        jmax = self.input.v('grid', 'maxIndex', 'x')  # maximum index of x grid (jmax+1 grid points incl. 0)
        kmax = self.input.v('grid', 'maxIndex', 'z')  # maximum index of z grid (kmax+1 grid points incl. 0)
        fmax = self.input.v('grid', 'maxIndex', 'f')  # maximum index of f grid (fmax+1 grid points incl. 0)
        depth = self.input.v('grid', 'low', 'z', range(0, jmax+1), [0], [0]) - self.input.v('grid', 'high', 'z', range(0, jmax+1), [0], [0])

        # test if present u is grid-conform (may not be if the previous runs were on a different resolution)
        utest = self.input.v('u0', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1))
        no_u = False
        if isinstance(utest, bool):
            no_u = True


        ################################################################################################################
        # 1. make the absolute velocity
        ################################################################################################################
        c = ny.polyApproximation(np.abs, 8)  # chebyshev coefficients for abs

        ## Truncation method
        if order == None:
            ##   1a. Gather velocity and zeta components
            zeta = 0
            u = 0
            comp = 0
            while self.input.v('zeta'+str(comp)) and self.input.v('u'+str(comp)) and comp <= self.truncationorder and not no_u:
                zeta += self.input.v('zeta'+str(comp), range(0, jmax + 1), [0], range(0, fmax + 1))
                u += self.input.v('u'+str(comp), range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1))
                for submod in self.ignoreSubmodule:     # remove submodules to be ignored
                    try:
                        zeta -= self.input.v('zeta'+str(comp), submod, range(0, jmax + 1), [0], range(0, fmax + 1))
                        u -= self.input.v('u'+str(comp), submod, range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1))
                    except:
                        pass
                comp += 1
            # if no data for u and zeta is in de DC, then take an initial estimate
            if comp == 0:
                u = np.zeros((jmax+1, kmax+1, fmax+1))
                u[:, :, 0] = 1.
                zeta = np.zeros((jmax+1, 1, fmax+1))

            usurf = u[:, [0], :]
            u = ny.integrate(u, 'z', kmax, 0, self.input.slice('grid'))

            ##   1b. Divide velocity by a maximum amplitude
            uamp = [(np.sum(np.abs(u), axis=-1)+10**-3).reshape((jmax+1, 1, 1)), (np.sum(np.abs(usurf), axis=-1)+10**-3).reshape((jmax+1, 1, 1))]
            u = u/uamp[0]
            usurf = usurf/uamp[1]

            ##  1c. Make absolute value
            uabs = [np.zeros(u.shape, dtype=complex), np.zeros(u.shape, dtype=complex)]  # uabs at depth-av, surface
            for n in [0, 1]:        # compute for DA (0) and surface (1)
                if n == 0:
                    ut = u
                else:
                    ut = usurf
                uabs[n][:, :, 0] = c[0]
                u2 = ny.complexAmplitudeProduct(ut, ut, 2)
                uabs[n] += c[2]*u2
                u4 = ny.complexAmplitudeProduct(u2, u2, 2)
                uabs[n] += c[4]*u4
                u6 = ny.complexAmplitudeProduct(u2, u4, 2)
                uabs[n] += c[6]*u6
                del u2, u6
                u8 = ny.complexAmplitudeProduct(u4, u4, 2)
                uabs[n] += c[8]*u8
                del u4, u8

                uabs[n] = uabs[n] * uamp[n].reshape((jmax+1, 1, 1))

            #   Absolute velocity * depth
            uabsH = uabs[0] + ny.complexAmplitudeProduct(uabs[1], zeta, 2)
            uabs = uabs[0]/depth + ny.complexAmplitudeProduct(uabs[1]-uabs[0]/depth, zeta, 2)

        ## Scaling method
        else:
            ##   1a. Gather velocity and zeta components
            zeta = []
            u = []
            usurf = []
            for comp in range(0, order+1):
                if self.input.v('zeta'+str(comp)) and self.input.v('u'+str(comp)) and not no_u:
                    zetatemp = self.input.v('zeta'+str(comp), range(0, jmax + 1), [0], range(0, fmax + 1))
                    utemp = self.input.v('u'+str(comp), range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1))
                    for submod in self.ignoreSubmodule:     # remove submodules to be ignored
                        try:
                            zetatemp -= self.input.v('zeta'+str(comp), submod, range(0, jmax + 1), [0], range(0, fmax + 1))
                            utemp -= self.input.v('u'+str(comp), submod, range(0, jmax + 1), range(0, kmax + 1), range(0, fmax + 1))
                        except:
                            pass
                # if no u and zeta in DC, then ..
                elif comp == 0:     # .. add velocity 1 to subtidal leading order
                    zetatemp = np.zeros((jmax+1, 1, fmax+1))
                    utemp = np.zeros((jmax+1, kmax+1, fmax+1))
                    utemp[:, :, 0] = 1.
                else:               # .. add nothing at higher orders
                    zetatemp = np.zeros((jmax+1, 1, fmax+1))
                    utemp = np.zeros((jmax+1, kmax+1, fmax+1))

                zeta.append(zetatemp)
                usurf.append(utemp[:, [0], :])
                u.append(ny.integrate(utemp, 'z', kmax, 0, self.input.slice('grid')) / depth)

                ##   1b. Divide velocity by a maximum amplitude
                uamp = []
                uamp.append((np.sum(np.abs(sum(u)), axis=-1)+10**-3).reshape((jmax+1, 1, 1)))
                uamp.append((np.sum(np.abs(sum(usurf)), axis=-1)+10**-3).reshape((jmax+1, 1, 1)))
                u = [i/uamp[0] for i in u]
                usurf = [i/uamp[1] for i in usurf]

            ##  1c. Make absolute value
            uabs = [np.zeros(u[0].shape+(order+1,), dtype=complex), np.zeros(u[0].shape+(order+1,), dtype=complex)]
            for n in [0, 1]:        # compute for DA (0) and surface (1)
                if n == 0:
                    ut = u
                else:
                    ut = usurf
                uabs[n][:, :, 0, 0] = c[0]
                for q in range(0, order+1):
                    uabs[n][:, :, :, q] += c[2]*self.umultiply(2, q, ut)
                    uabs[n][:, :, :, q] += c[4]*self.umultiply(4, q, ut)
                    uabs[n][:, :, :, q] += c[6]*self.umultiply(6, q, ut)
                    uabs[n][:, :, :, q] += c[8]*self.umultiply(8, q, ut)

                uabs[n] = uabs[n] * uamp[n].reshape((jmax+1, 1, 1, 1))

            #   Absolute velocity * depth
            uabsH = uabs[0][:, :, :, order]*depth
            for q in range(0, order):
                uabsH += ny.complexAmplitudeProduct(uabs[1][:, :, :, q]-uabs[0][:, :, :, q], zeta[order-q-1], 2)

            #   Only keep uabs at current order
            uabs = uabs[0][:, :, :, order]      # only keep DA part

        ################################################################################################################
        # 2. Relaxtion
        ################################################################################################################
        ##   2a. Relaxation on uabs
        if hasattr(self, 'u_prev_iter') and self.u_prev_iter.shape == uabs.shape:
            u_prev_iter = self.u_prev_iter
        else:
            u_prev_iter = uabs      # take current uabs if no previous is available

        u_prev_iter2 = u_prev_iter - (uabs)
        u0 = np.max((uabs, np.min((u_prev_iter2 * (1 - self.RELAX), u_prev_iter2 * (1. + self.RELAX)), axis=0) + (uabs)), axis=0)
        u0 = np.min((u0,   np.max((u_prev_iter2 * (1 - self.RELAX), u_prev_iter2 * (1. + self.RELAX)), axis=0) + uabs), axis=0)
        self.u_prev_iter = u0  # save velocity at bed for next iteration

        ##    2b. Relaxation on uabs*depth
        if hasattr(self, 'uH_prev_iter') and self.uH_prev_iter.shape == uabsH.shape:
            u_prev_iter = self.uH_prev_iter
        else:
            u_prev_iter = uabsH     # take current uabsH if no previous is available

        u_prev_iter2 = u_prev_iter - (uabsH)
        uH0 = np.max((uabsH, np.min((u_prev_iter2 * (1 - self.RELAX), u_prev_iter2 * (1. + self.RELAX)), axis=0) + (uabsH)), axis=0)
        uH0 = np.min((uH0,   np.max((u_prev_iter2 * (1 - self.RELAX), u_prev_iter2 * (1. + self.RELAX)), axis=0) + uabsH), axis=0)
        self.uH_prev_iter = uH0  # save velocity at bed for next iteration

        return u0, uH0
Ejemplo n.º 15
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]
Ejemplo n.º 16
0
    def main(self, components, ws, Kv, Kh, Csea, QC, S, Gamma, Gamma_factor, source):
        jmax = self.input.v('grid', 'maxIndex', 'x')
        kmax = self.input.v('grid', 'maxIndex', 'z')
        taumax = self.input.v('taumax') or 1

        if False:#hasattr(self, 'X'):       #DEBUG
            X = self.X
            spinup = False
        else:
            X = np.zeros((jmax+1, len(components)))
            spinup = True

        # time integration and initial condition
        Chat_prim = np.zeros((jmax+1, kmax+1, len(components)))
        Chat_int = np.zeros((jmax+1, len(components)))
        Ts = np.zeros((jmax+1, len(components)))
        Fs = np.zeros((jmax+1, len(components)))
        Hs = np.zeros((jmax+1, len(components)))
        Chat = np.zeros((jmax+1, kmax+1, len(components)))

        ################################################################################################################
        # Compute transport rates & potential concentrations
        ################################################################################################################
        dc = self.input.slice('grid')
        for i, comp_name in enumerate(components):
            T, F, Hs[:, i], Chat[:, :, i] = self.component(ws[i], Kv[i], Kh[i])
            dc.merge({comp_name: {'T': T}})
            dc.merge({comp_name: {'F': F}})
            Ts[:, i] = dc.v(comp_name, 'T', range(0, jmax+1))
            Fs[:, i] = dc.v(comp_name, 'F', range(0, jmax+1))

            # integrals
            Chat_prim[:, :, i] = -ny.primitive(np.real(Chat[:, :, i]), 'z', 0, kmax, self.input.slice('grid'))   # primitive counted from surface
            Chat_int[:, i] = np.sum(Chat_prim[:, :, i], axis=1)

        ## process growth function so that no duplicate computations are done
        Gamma_flat = [item for sublist in Gamma for item in sublist]
        Gamma_list = list(set(Gamma_flat))
        Gamma_index = [[Gamma_list.index(i) for i in j] for j in Gamma]

        ################################################################################################################
        # Initial conditions
        ################################################################################################################
        if spinup:
            for i, comp_name in enumerate(components):
                if i==0:
                    P0 = Csea[i]*np.exp(-10*np.linspace(0, 1, jmax+1))
                    H = self.input.v('grid', 'low', 'z', range(0, jmax+1)) - self.input.v('grid', 'high', 'z', range(0, jmax+1))
                    X[:, i] = P0/np.real(ny.integrate(Chat[:, :, i], 'z', kmax, 0, self.input.slice('grid'))[:, 0])*H
                else:
                    # initial condition (equilibrium without growth)
                    integrand = ny.integrate(Ts[:, i]/(Fs[:, i]), 'x', 0, range(0, jmax+1), self.input.slice('grid'))
                    P = QC[i]/(Fs[:, i])*np.exp(integrand.reshape((jmax+1, 1))*np.ones((1, jmax+1))-integrand.reshape((1, jmax+1)))
                    Pint = ny.integrate(P.reshape((jmax+1, 1, 1, jmax+1)), 'x', 0, range(0, jmax+1), self.input.slice('grid'))
                    Pint = Pint[range(0, jmax+1), 0, 0, range(0, jmax+1)]
                    C0 = np.exp(-integrand)*Csea[i] + Pint
                    X[:, i] = C0/Chat_int[:, i]*H

            self.Xprev = np.ones(X.shape)*np.inf

        ################################################################################################################
        # Time integration
        ################################################################################################################
        init_growth = True
        ctd = True

        # set time step
        if not spinup and self.input.v('dtau'):
            dtau = self.input.v('dtau')*24*3600.
            tau = np.linspace(0, dtau, np.ceil(dtau/self.DT)+1)
            i_tau_now = 0
            dt = tau[1]-tau[0]
        else:
            dt = self.DT
            spinup = True

        # run time stepping
        dind = 0                    # index for the iteration number
        self.dif_prev = np.inf      # difference in previous step (only in spin-up)
        while ctd:
            dind +=1
            ## Growth functions
            Gamma_eval = [fun(Chat, Chat_prim, Chat_int, X[:, :], init_growth) for fun in Gamma_list]
            init_growth = False
            Gamma_sum = [self.sumdict(copy(j)) for j in Gamma_eval]

            Gamma = [[Gamma_sum[i] for i in j] for j in Gamma_index]
            for i, comp_name in enumerate(components):
                G = sum([a*b for a,b in zip(Gamma_factor[i], Gamma[i])])
                G += source[:, i]
                X[:, i] = cSolverTime(Ts[:, i], Fs[:, i], np.zeros(jmax+1), G, Hs[:, i], Hs[:, i]*X[:, i], X[0, i], 'flux', QC[i], dt, X[:, i], self.input)

            if spinup:
                dif = self.DT/dt*np.linalg.norm((X - self.Xprev)/(X+0.001*np.max(X)), np.inf)
                print dind, dif

                ## DEBUG
                # if np.max(X[:, 0]) > 50/1000. and dind > 100:
                #     print 'exit simulation; non-realistic result'
                #     ctd = False
                #     X = np.nan*X
                ## END
                # print dif
                if dif < 10**-5 or dind>2000:#10**-8:
                    ctd = False
                elif self.dif_prev < dif and dind > 100:                                     # adjust time step if diffence increases after 200th iteration (only in spin-up)
                    dt = dt/2.
                    dind = 0
                    print 'timestep: ' + str(dt)
                else:
                    self.Xprev = copy(X)
                    self.dif_prev = dif
            else:
                i_tau_now += 1
                if i_tau_now == len(tau)-1:
                    ctd = False


        ################################################################################################################
        ## Return
        ################################################################################################################
        self.X = copy(X)

        Gamma = [[Gamma_eval[i] for i in j] for j in Gamma_index]
        # Gamma2 = [0]*len(Gamma)
        # for i in range(0, len(Gamma)):
        #     for j in range(1, len(Gamma[i])):
        #         mergeDicts(Gamma[i][0], Gamma[i][j])
        #     Gamma2[i] = Gamma[i][0]
        d = {}


        d['Ceco'] = {}
        d['Teco'] = {}
        d['Feco'] = {}
        d['Geco'] = {}
        for i, comp_name in enumerate(components):
            d['Ceco'][comp_name] = Chat[:, :, i]*X[:, i].reshape(jmax+1, 1)
            d['Geco'][comp_name] = {}
            for j in range(0, len(Gamma[i])):
                d['Geco'][comp_name].update(Gamma[i][j])
            #      d['Geco'][comp_name] = mergeDicts(d['Geco'][comp_name], Gamma[i][j])
            d['Teco'][comp_name] = dc.data[comp_name]['T']
            d['Feco'][comp_name] = dc.data[comp_name]['F']

        return d
Ejemplo n.º 17
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
Ejemplo n.º 18
0
    def run(self):
        # self.timers[0].tic()
        self.logger.info('Running module StaticAvailability')

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

        L = self.input.v('L')
        self.x = self.input.v('grid', 'axis', 'x')
        self.zarr = ny.dimensionalAxis(self.input.slice('grid'), 'z')[:, :, 0]-self.input.v('R', x=self.x/L).reshape((len(self.x), 1))      #YMD 22-8-17 includes reference level; note that we take a reference frame z=[-H-R, 0]

        c00 = np.real(self.input.v('hatc0', 'a', range(0, jmax+1), range(0, kmax+1), 0))
        c04 = np.abs(self.input.v('hatc0', 'a', range(0, jmax+1), range(0, kmax+1), 2))
        # c20 = np.real(self.input.v('hatc2', 'a', range(0, jmax+1), range(0, kmax+1), 0))       # NB. do not include hatc2 in the definition of alpha1 here
        alpha1 = ny.integrate(c00, 'z', kmax, 0, self.input.slice('grid'))[:, 0]
        alpha1[-1] += alpha1[-2]                                                                 # correct alpha1 at last point to prevent zero value
        alpha2 = ny.integrate(c04, 'z', kmax, 0, self.input.slice('grid'))[:, 0]/(alpha1+1e-10) + 1.e-3
        # self.timers[0].toc()

        ################################################################################################################
        ## Compute T and F
        ################################################################################################################
        # self.timers[1].tic()
        d = self.compute_transport()
        G = self.compute_source()
        # self.timers[1].toc()

        ################################################################################################################
        ## 4. Calculate availability
        ################################################################################################################
        # self.timers[2].tic()
        # Add all mechanisms to datacontainer
        dctrans = DataContainer(d)

        # Calculate availability
        a, f0, f0x = self.availability(dctrans.v('F', range(0, jmax+1)), dctrans.v('T', range(0, jmax+1)), G, alpha1, alpha2)
        f0 = f0.reshape(jmax+1, 1)
        f0x = f0x.reshape(jmax+1, 1)

        d['a'] = a
        nfu = ny.functionTemplates.NumericalFunctionWrapper(f0[:, 0], self.input.slice('grid'))
        nfu.addDerivative(f0x[:, 0], 'x')
        d['f'] = nfu.function
        # self.timers[2].toc()

        ################################################################################################################
        # 5. Calculate concentrations, i.e. a*hatc(a) + ax*hatc(ax)
        ################################################################################################################
        # self.timers[3].tic()
        d['c0'] = {}
        d['c1'] = {}
        d['c2'] = {}

        # Calculate c0=f*hatc0
        for submod in self.input.getKeysOf('hatc0', 'a'):
            c0_comp = self.input.v('hatc0', 'a', submod, range(0, jmax+1), range(0, kmax+1), range(0, fmax+1))
            d['c0'][submod] = {}
            tmp = f0[:, None] * c0_comp
            d['c0'][submod] = tmp

        # Calculate c1 = f*hatc1_f + fx*hatc1_fx
        for submod in self.input.getKeysOf('hatc1', 'a'):
            if submod == 'erosion':
                for subsubmod in self.input.getKeysOf('hatc1', 'a', 'erosion'):
                    c1_comp = self.input.v('hatc1', 'a', 'erosion', subsubmod, range(0, jmax+1), range(0, kmax+1), range(0, fmax+1))
                    d['c1'] = self.dictExpand(d['c1'], 'erosion', subsubmod)
                    tmp = f0[:, None] * c1_comp
                    d['c1']['erosion'][subsubmod] = tmp

            elif submod == 'sedadv':
                c1_comp_a = self.input.v('hatc1', 'a', 'sedadv', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1))
                c1_comp_ax = self.input.v('hatc1', 'ax', 'sedadv', range(0, jmax+1), range(0, kmax+1), range(0, fmax+1))
                d['c1'][submod] = {}
                tmp = f0[:, None] * c1_comp_a + f0x[:, None] * c1_comp_ax
                d['c1'][submod] = tmp

            else:
                c1_comp = self.input.v('hatc1', 'a', submod, range(0, jmax+1), range(0, kmax+1), range(0, fmax+1))
                d['c1'][submod] = {}
                tmp = f0[:, None] * c1_comp
                d['c1'][submod] = tmp

        # Calculate c2 = f*hatc2
        for subsubmod in self.input.getKeysOf('hatc2', 'a', 'erosion'):
            c2_comp = self.input.v('hatc2', 'a', 'erosion', subsubmod, range(0, jmax+1), range(0, kmax+1), range(0, fmax+1))
            d['c2'] = self.dictExpand(d['c2'], 'erosion', subsubmod)
            tmp = f0[:, None] * c2_comp
            d['c2']['erosion'][subsubmod] = tmp

        # self.timers[3].toc()
        # self.timers[0].disp('time availability - init')
        # self.timers[1].disp('time availability - T, F')
        # self.timers[2].disp('time availability - a, f')
        # self.timers[3].disp('time availability - to dict')
        # self.timers[4].disp('time availability - cap')
        # self.timers[5].disp('time availability - trap')
        # [self.timers[i].reset() for i in range(0, len(self.timers))]

        return d
Ejemplo n.º 19
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