Ejemplo n.º 1
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.º 2
0
    def run(self):
        """         """
        self.logger.info('Running module DynamicAvailability_upwind')

        ################################################################################################################
        # Init
        ################################################################################################################
        jmax = self.input.v('grid', 'maxIndex', 'x')
        kmax = self.input.v('grid', 'maxIndex', 'z')
        fmax = self.input.v('grid', 'maxIndex', 'f')
        self.x = ny.dimensionalAxis(self.input.slice('grid'), 'x')[:, 0, 0]
        self.dx = (self.x[1:] - self.x[:-1])
        self.zarr = ny.dimensionalAxis(self.input.slice('grid'), 'z')[:, :, 0]

        self.B = self.input.v('B', range(0, jmax + 1))
        self.Bx = self.input.d('B', range(0, jmax + 1), dim='x')

        self.Kh = self.input.v('Kh')
        self.u0tide_bed = self.input.v('u0', 'tide', range(0, jmax + 1), kmax,
                                       1)
        c00 = np.real(
            self.input.v('hatc0', range(0, jmax + 1), range(0, kmax + 1), 0))

        c04 = np.abs(
            self.input.v('hatc0', range(0, jmax + 1), range(0, kmax + 1), 2))
        c04_int = np.trapz(c04, x=-self.zarr)
        hatc2 = np.abs(
            self.input.v('hatc2', range(0, jmax + 1), range(0, kmax + 1), 0))
        alpha1 = np.trapz(c00 + hatc2, x=-self.zarr, axis=1)
        if alpha1[-1] == 0:
            alpha1[-1] = alpha1[-2]
        alpha2 = c04_int / alpha1 + 1e-3

        ## load time series Q
        t = self.interpretValues(self.input.v('t'))
        toutput = self.interpretValues(self.input.v('toutput'))
        toutput[0] = t[
            0]  # correct output time; first time level is always equal to initial computation time
        Qarray = self.interpretValues(self.input.v('Q1'))
        if len(Qarray) != len(t):
            from src.util.diagnostics.KnownError import KnownError
            raise KnownError(
                'Length of Q does not correspond to length of time array.')

    ################################################################################################################
    # Compute transport, source and BC
    ################################################################################################################
    ## Transport
        d = self.compute_transport()
        dc = DataContainer(d)

        #       change size of those components that depend on the river discharge and put init value in first element
        T_r = copy(dc.v('T', 'river', range(0, jmax + 1)))
        T_rr = copy(dc.v('T', 'river_river', range(0, jmax + 1)))
        T_dr = copy(dc.v('T', 'diffusion_river', range(0, jmax + 1)))
        F_dr = dc.v('F', 'diffusion_river', range(0, jmax + 1))

        d['T']['river'] = np.zeros((jmax + 1, 1, 1, len(toutput)))
        d['T']['river'][:, 0, 0, 0] = T_r
        d['T']['river_river'] = np.zeros((jmax + 1, 1, 1, len(toutput)))
        d['T']['river_river'][:, 0, 0, 0] = T_rr
        d['T']['diffusion_river'] = np.zeros((jmax + 1, 1, 1, len(toutput)))
        d['T']['diffusion_river'][:, 0, 0, 0] = T_dr
        d['F']['diffusion_river'] = np.zeros((jmax + 1, 1, 1, len(toutput)))
        d['F']['diffusion_river'][:, 0, 0, 0] = F_dr

        T = dc.v('T', range(0, jmax + 1), 0, 0, 0)
        F = dc.v('F', range(0, jmax + 1), 0, 0, 0)

        ## Source
        G = self.compute_source()  #NB does not change over long time scale

        ## Seaward boundary condition
        if self.input.v('sedbc') == 'csea':
            csea = self.input.v('csea')
            fsea = csea / alpha1[0] * (
                self.input.v('grid', 'low', 'z', 0) -
                self.input.v('grid', 'high', 'z', 0)
            )  #NB does not change over long time scale
        else:
            from src.util.diagnostics.KnownError import KnownError
            raise KnownError(
                'incorrect seaward boundary type (sedbc) for sediment module')

        ## compute TQ, uQ, hatc2Q: quantities relative to the river discharge
        u1river = np.real(
            self.input.v('u1', 'river', range(0, jmax + 1), range(0, kmax + 1),
                         0))
        Q_init = -np.trapz(u1river[-1, :], x=-self.zarr[-1, :]) * self.B[
            -1]  # initial discharge
        self.TQ = T_r / Q_init  # river transport per discharge unit
        self.uQ = u1river / Q_init  # river velocity per discharge unit

        ################################################################################################################
        # Initialise X = (f, S)
        ################################################################################################################
        if self.input.v('initial') == 'erodibility':
            finit = self.input.v('finit', range(0, jmax + 1))
            Sinit = self.init_stock(finit, alpha1, alpha2)

        elif self.input.v('initial') == 'stock':
            Sinit = self.input.v('Sinit', range(0, jmax + 1))
            finit = self.erodibility_stock_relation(alpha2, Sinit / alpha1)

        elif self.input.v('initial') == 'equilibrium':
            _, finit, _ = self.availability(F, T, G, alpha1, alpha2)
            Sinit = self.init_stock(finit, alpha1, alpha2)

        else:
            from src.util.diagnostics.KnownError import KnownError
            raise KnownError(
                'incorrect initial value for sediment module. Use erodibility, stock or equilibrium'
            )

        X = np.concatenate((finit, Sinit))
        f = np.zeros((jmax + 1, 1, 1, len(toutput)))
        S = np.zeros((jmax + 1, 1, 1, len(toutput)))
        f[:, 0, 0, 0] = finit
        S[:, 0, 0, 0] = Sinit

        ################################################################################################################
        # Time integrator
        ################################################################################################################
        T_base = dc.v('T', range(0, jmax + 1), 0, 0, 0) - dc.v(
            'T', 'river', range(0, jmax + 1), 0, 0, 0) - dc.v(
                'T', 'river_river', range(0, jmax + 1), 0, 0, 0) - dc.v(
                    'T', 'diffusion_river', range(0, jmax + 1), 0, 0, 0)
        F_base = dc.v('F', range(0, jmax + 1), 0, 0, 0) - dc.v(
            'F', 'diffusion_river', range(0, jmax + 1), 0, 0, 0)

        #   loop
        self.timer.tic()
        qq = 1  # counter for saving
        for i, Q in enumerate(Qarray[1:]):
            # quantities at old time step
            Told = copy(T)
            Fold = copy(F)
            alpha1old = copy(alpha1)
            alpha2old = copy(alpha2)

            # Update transport terms and hatc2 & load new transport terms
            T_riv, T_rivriv, T_difriv, F_difriv = self.update_transport(Q)
            ur = self.uQ[:, -1] * Q
            hatc2 = self.update_hatc2(ur)
            T = T_base + T_riv + T_rivriv + T_difriv
            F = F_base + F_difriv

            # Make one time step and iterate over non-linearity
            self.dt = t[i + 1] - t[i]

            alpha1 = np.trapz(c00 + hatc2, x=-self.zarr, axis=1)
            if alpha1[-1] == 0:
                alpha1[-1] = alpha1[-2]
            alpha2 = c04_int / alpha1 + 1e-3
            X = self.timestepping(T, F, alpha1, alpha2, Told, Fold, alpha1old,
                                  alpha2old, X, fsea, G)

            # save output on output timestep
            if t[i + 1] >= toutput[qq]:
                toutput[qq] = t[
                    i +
                    1]  # correct output time to real time if time step and output time do not correspond
                d['T']['river'][:, 0, 0, qq] = T_riv
                d['T']['river_river'][:, 0, 0, qq] = T_rivriv
                d['T']['diffusion_river'][:, 0, 0, qq] = T_difriv
                d['F']['diffusion_river'][:, 0, 0, qq] = F_difriv
                f[:, 0, 0, qq] = X[:jmax + 1]
                S[:, 0, 0, qq] = X[jmax + 1:]
                qq += 1
                qq = np.minimum(qq, len(toutput) - 1)

            # display progress
            if i % np.floor(len(Qarray[1:]) / 100.) == 0:
                percent = float(i) / len(Qarray[1:])
                hashes = '#' * int(round(percent * 10))
                spaces = ' ' * (10 - len(hashes))
                sys.stdout.write("\rProgress: [{0}]{1}%".format(
                    hashes + spaces, int(round(percent * 100))))
                sys.stdout.flush()
        sys.stdout.write('\n')
        self.timer.toc()
        self.timer.disp('time integration time')

        ################################################################################################################
        # Prepare output
        ################################################################################################################
        d['f'] = f
        d['a'] = S

        fx = np.gradient(f, self.x, axis=0, edge_order=2)
        hatc0 = self.input.v('hatc0', 'a', range(0, jmax + 1),
                             range(0, kmax + 1), range(0, fmax + 1), [0])
        hatc1 = self.input.v('hatc1', 'a', range(0, jmax + 1),
                             range(0, kmax + 1), range(0, fmax + 1), [0])
        hatc1x = self.input.v('hatc1', 'ax', range(0, jmax + 1),
                              range(0, kmax + 1), range(0, fmax + 1), [0])
        hatc2 = self.input.v('hatc2', 'a', range(0, jmax + 1),
                             range(0, kmax + 1), range(0, fmax + 1), [0])
        d['c0'] = hatc0 * f
        d['c1'] = hatc1 * f + hatc1x * fx
        d['c2'] = hatc2 * f

        d['t'] = toutput

        return d
Ejemplo n.º 3
0
    def run(self):
        """Run function to initiate the calculation of the sediment transport

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

        # Initiate variables
        self.SIGMA = self.input.v('OMEGA')
        self.RHOS = self.input.v('RHOS')
        self.DS = self.input.v('DS')
        self.GPRIME = self.input.v('G') * (self.RHOS - self.input.v('RHO0')) / self.input.v('RHO0')    #
        self.ASTAR = self.input.v('astar')
        self.WS = self.input.v('ws0')
        self.KH = self.input.v('Kh')
        self.L = self.input.v('L')
        self.x = self.input.v('grid', 'axis', 'x') * self.input.v('L')
        self.dx = self.x[1:]-self.x[:-1]
        jmax = self.input.v('grid', 'maxIndex', 'x')
        kmax = self.input.v('grid', 'maxIndex', 'z')
        fmax = self.input.v('grid', 'maxIndex', 'f')
        self.z = self.input.v('grid', 'axis', 'z', 0, range(0, kmax+1))
        self.zarr = ny.dimensionalAxis(self.input.slice('grid'), 'z')[:, :, 0]-self.input.v('R', x=self.x/self.L).reshape((len(self.x), 1))      #YMD 22-8-17 includes reference level; note that we take a reference frame z=[-H-R, 0]
        self.Av0 = self.input.v('Kv', range(0, jmax+1), 0, 0).reshape(jmax+1, 1)
        self.Av0x = self.input.d('Kv', range(0, jmax+1), 0, 0, dim='x').reshape(jmax+1, 1)
        self.H = (self.input.v('H', range(0, jmax+1)).reshape(jmax+1, 1) +
                  self.input.v('R', range(0, jmax+1)).reshape(jmax+1, 1))
        self.Hx = (self.input.d('H', range(0, jmax+1), dim='x').reshape(jmax+1, 1) +
                   self.input.d('R', range(0, jmax+1), dim='x').reshape(jmax+1, 1))
        self.B = self.input.v('B', range(0, jmax+1))
        self.Bx = self.input.d('B', range(0, jmax+1), dim='x').reshape(jmax+1, 1)
        self.sf = self.input.v('Roughness', range(0, jmax+1), 0, 0).reshape(jmax+1, 1)
        self.sfx = self.input.d('Roughness', range(0, jmax+1), 0, 0, dim='x').reshape(jmax+1, 1)
        self.submodules_hydro = self.input.data['u1'].keys()
        self.submodules_sed = self.input.v('submodules')
        # Extract leading order surface elevation and horizontal and vertical velocities
        self.zeta0 = self.input.v('zeta0', 'tide', range(0, jmax+1), 0, 1).reshape(jmax+1, 1)
        self.u0 = self.input.v('u0', 'tide', range(0, jmax+1), range(0, kmax+1), 1)
        self.w0 = self.input.v('w0', 'tide', range(0, jmax+1), range(0, kmax+1), 1)
        # Initiate dictionary to save results
        d = {}

        ################################################################################################################
        ## Calculate leading, first and second order concentration amplitudes hatc0, hatc1 and hatc2
        ################################################################################################################
        # Allocate space
        d['hatc0'] = {}
        d['hatc1'] = {'a': {}, 'ax': {}}
        d['hatc2'] = {}
        # Calculate leading order concentration amplitudes
        d['hatc0'] = self.erosion_lead()
        # Calculate first order concentration amplitudes
        for sedmod in self.submodules_sed:
            hatc1 = getattr(self, sedmod)()
            for k in hatc1.keys():
                d['hatc1'][k].update(hatc1[k])
        # Calculate second order concentration amplitudes
        d['hatc2'] = self.erosion_second()

        ################################################################################################################
        ## Calculate Transport function T and diffusion function F
        ################################################################################################################
        # Allocate space
        d['T'] = {}
        d['F'] = {}
        ## Transport T #################################################################################################
        # Transport terms that are a function of the first order velocity, i.e. u1*c0 terms.
        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)])
            # calculate residual Transport terms
            for n in (0, 2):
                tmp = u1_comp[:, :, n]
                if n==0:
                    if submod == 'stokes':
                        tmp = np.real(np.trapz(tmp * self.c00, x=-self.zarr, axis=1))
                        if any(tmp) > 10**-14:
                            d['T'][submod] = self.dictExpand(d['T'][submod], 'TM0', ['return', 'drift'])
                            d['T'][submod]['TM0']['return'] += tmp
                    else:
                        tmp = np.real(np.trapz(tmp * self.c00, x=-self.zarr, axis=1))
                        if any(tmp) > 10**-14:
                            d['T'][submod]['TM' + str(2 * n)] += tmp
                elif n==2:
                    if submod == 'stokes':
                        tmp = np.real(np.trapz((tmp * np.conj(self.c04) + np.conj(tmp) * self.c04) / 4., x=-self.zarr, axis=1))
                        if any(tmp) > 10**-14:
                            d['T'][submod] = self.dictExpand(d['T'][submod], 'TM4', ['return', 'drift'])
                            d['T'][submod]['TM4']['return'] += tmp
                    else:
                        tmp = np.real(np.trapz((tmp * np.conj(self.c04) + np.conj(tmp) * self.c04) / 4., x=-self.zarr, axis=1))
                        if any(tmp) > 10**-14:
                            d['T'][submod]['TM' + str(2 * n)] += tmp

        # Transport terms that are a function of the first order concentration, i.e. u0*c1 terms.
        for submod in d['hatc1']['a'].keys():
            if submod == 'erosion':
                for subsubmod in d['hatc1']['a'][submod].keys():
                    c1_comp = d['hatc1']['a'][submod][subsubmod]
                    d['T'] = self.dictExpand(d['T'], subsubmod, ['TM' + str(2 * n) for n in range(0, fmax + 1)])
                    tmp = c1_comp[:, :, 1]
                    tmp = np.real(np.trapz((self.u0 * np.conj(tmp) + np.conj(self.u0) * tmp) / 4., x=-self.zarr, axis=1))
                    if subsubmod == 'stokes':
                        if any(tmp) > 10**-14:
                            d['T'][subsubmod] = self.dictExpand(d['T'][subsubmod], 'TM2', ['return', 'drift'])
                            d['T'][subsubmod]['TM2']['return'] += tmp
                    else:
                        if any(tmp) > 10**-14:
                            d['T'][subsubmod]['TM2'] += tmp
            else:
                c1_comp = d['hatc1']['a'][submod]
                d['T'] = self.dictExpand(d['T'], submod, ['TM' + str(2 * n) for n in range(0, fmax + 1)])
                tmp = c1_comp[:, :, 1]
                tmp = np.real(np.trapz((self.u0 * np.conj(tmp) + np.conj(self.u0) * tmp) / 4., x=-self.zarr, axis=1))
                if any(tmp) > 10**-14:
                    d['T'][submod]['TM2'] += tmp

        # Transport terms that are related to diffusion, i.e. K_h*c0 or K_h*c2
        d['T'] = self.dictExpand(d['T'], 'diffusion_tide', ['TM' + str(2 * n) for n in range(0, fmax + 1)])
        d['T']['diffusion_tide']['TM0'] = np.real(-np.trapz(self.KH * self.c00x, x=-self.zarr, axis=1))
        d['T'] = self.dictExpand(d['T'], 'diffusion_river', ['TM' + str(2 * n) for n in range(0, fmax + 1)])
        tmp = d['hatc2']['a']['erosion']['river_river'][:, :, 0]
        tmp, __ = np.gradient(tmp, self.x[1], edge_order=2)
        tmp = np.real(-np.trapz(self.KH * tmp, x=-self.zarr, axis=1))
        if any(tmp) > 10**-14:
            d['T']['diffusion_river']['TM0'] = tmp

        # Transport terms that are related to Stokes drift, i.e. u0*c0*zeta0
        if 'stokes' in self.submodules_hydro:
            for n in (0, 2):
                u0s = self.u0[:, 0]
                tmp = d['hatc0']['a']['erosion'][:, 0, n]
                if n==0:
                    tmp = np.real(np.conj(u0s) * tmp * self.zeta0[:, 0] + u0s * tmp * np.conj(self.zeta0[:, 0])) / 4
                elif n==2:
                    tmp = np.real(u0s * np.conj(tmp) * self.zeta0[:, 0] + np.conj(u0s) * tmp * np.conj(self.zeta0[:, 0])) / 8
                if any(tmp) > 10**-14:
                    d['T']['stokes']['TM' + str(2 * n)]['drift'] = tmp


        # Transport term that is related to the river-river interaction u1river*c2river
        d['T'] = self.dictExpand(d['T'], 'river_river', ['TM' + str(2 * n) for n in range(0, fmax + 1)])
        if self.input.v('u1', 'river') is not None:
            u1_comp = self.input.v('u1', 'river', range(0, jmax+1), range(0, kmax+1), 0)
            tmp = d['hatc2']['a']['erosion']['river_river'][:, :, 0]
            d['T']['river_river']['TM0'] = np.real(np.trapz(u1_comp * tmp, x=-self.zarr, axis=1))

        ## Diffusion F #################################################################################################
        # Diffusive part, i.e. Kh*c00 and Kh*c20
        d['F'] = self.dictExpand(d['F'], 'diffusion_tide', ['FM' + str(2 * n) for n in range(0, fmax + 1)])
        d['F']['diffusion_tide']['FM0'] = np.real(-np.trapz(self.KH * self.c00, x=-self.zarr, axis=1))
        d['F'] = self.dictExpand(d['F'], 'diffusion_river', ['FM' + str(2 * n) for n in range(0, fmax + 1)])
        tmp = d['hatc2']['a']['erosion']['river_river'][:, :, 0]
        tmp = np.real(-np.trapz(self.KH * tmp, x=-self.zarr, axis=1))
        d['F']['diffusion_river']['FM0'] = tmp

        # Part of F that is related to sediment advection, i.e. u0*c1sedadv
        for submod in d['hatc1']['ax'].keys():
            c1_comp = d['hatc1']['ax'][submod]
            d['F'] = self.dictExpand(d['F'], submod, ['FM' + str(2 * n) for n in range(0, fmax + 1)])
            tmp = c1_comp[:, :, 1]
            tmp = np.real(np.trapz((self.u0 * np.conj(tmp) + np.conj(self.u0) * tmp) / 4., x=-self.zarr, axis=1))
            if any(tmp) > 10**-14:
                d['F']['sedadv']['FM2'] += tmp

        ################################################################################################################
        # Calculate availability
        ################################################################################################################
        # Add all mechanisms to datacontainer
        dctrans = DataContainer(d)
        # Calculate availability
        d['a'] = {}
        d['a'] = self.availability(dctrans.v('F'), dctrans.v('T')).reshape(len(self.x), 1)
        ax = np.gradient(d['a'][:, 0], self.x[1], edge_order=2).reshape(len(self.x), 1)

        ################################################################################################################
        # Calculate concentrations, i.e. a*hatc(a) + ax*hatc(ax)
        ################################################################################################################
        d['c0'] = {}
        d['c1'] = {}
        d['c2'] = {}
        # Calculate a*c0(a)
        for submod in d['hatc0']['a'].keys():
            c0_comp = d['hatc0']['a'][submod]
            d['c0'][submod] = {}
            tmp = d['a'][:, None] * c0_comp
            d['c0'][submod] = tmp

        # Calculate a*c1(a) + ax*c1(ax)
        for submod in d['hatc1']['a'].keys():
            if submod == 'erosion':
                for subsubmod in d['hatc1']['a'][submod].keys():
                    c1_comp = d['hatc1']['a'][submod][subsubmod]
                    d['c1'] = self.dictExpand(d['c1'], submod, subsubmod)
                    tmp = d['a'][:, None] * c1_comp
                    d['c1'][submod][subsubmod] = tmp
            elif submod == 'sedadv':
                c1_comp_a = d['hatc1']['a'][submod]
                c1_comp_ax = d['hatc1']['ax'][submod]
                d['c1'][submod] = {}
                tmp = d['a'][:, None] * c1_comp_a + ax[:, None] * c1_comp_ax
                d['c1'][submod] = tmp
            else:
                c1_comp = d['hatc1']['a'][submod]
                d['c1'][submod] = {}
                tmp = d['a'][:, None] * c1_comp
                d['c1'][submod] = tmp

        # Calculate a*c2(a)
        for submod in d['hatc2']['a']['erosion'].keys():
            c2_comp = d['hatc2']['a']['erosion'][submod]
            d['c2'] = self.dictExpand(d['c2'], 'erosion', submod)
            tmp = d['a'][:, None] * c2_comp
            d['c2']['erosion'][submod] = tmp
        return d
Ejemplo n.º 4
0
class NumericalFunctionBase(FunctionBase):
    #Variables

    #Methods
    def __init__(self, dimNames):
        FunctionBase.__init__(self, dimNames)
        self.dataContainer = DataContainer()
        self.valueSize = 0
        return

    def function(self, **kwargs):
        if len([
                i for i in kwargs.keys()
                if i in self.dataContainer.v('grid', 'dimensions')
        ]) == 0:
            return self.__setReturnReference(kwargs.get('operation'))

        # evaluate function
        try:
            returnval = self.__evaluateFunction(**kwargs)
        except FunctionEvaluationError:
            returnval = self.__setReturnReference(kwargs.get('operation'))
        return returnval

    def __evaluateFunction(self, **kwargs):
        """Overrides the function method of FunctionBase, but is very similar.
        The difference is only that FunctionBase transfers kwargs to args before calling the actual functions
        Here we keep the kwargs as the actual functions also use this.
        """
        requestSize = sum(
            [dim in kwargs for dim in self.dimNames]
        )  # count the number of dimensions in kwargs (this makes sure that other parameters or irrelevant dimensions are ignored)

        operation = kwargs.get('operation')
        try:
            kwargs.pop('operation')
        except:
            pass
        # direct to actual function
        if operation is None:
            returnval = self.value(**kwargs)
        elif operation == 'd':
            returnval = self.derivative(**kwargs)
        elif operation == 'n':
            returnval = -self.value(**kwargs)
        elif operation == 'dn':
            returnval = -self.derivative(**kwargs)
        else:
            raise FunctionEvaluationError
        return returnval

    def __setReturnReference(self, operation=None):
        '''No difference with FunctionBase, but required here to refer to its own functions
        '''
        if not operation:
            returnval = self.function
        elif operation == 'n':
            returnval = self.negfunction
        elif operation == 'd':
            returnval = self.derfunction
        elif operation == 'dn':
            returnval = self.dnfunction
        else:
            raise KnownError(
                'Function called with unknown operation. (This error indicates an incorrectly defined function)'
            )
        return returnval

    def negfunction(self, **kwargs):
        """No difference with FunctionBase, but required here to refer to its own functions
        """
        # reset operations
        if kwargs.get(
                'operation'
        ) == 'n':  # if the negative of a negfunction is called, return to function.
            kwargs.pop('operation')
        elif kwargs.get('operation') == 'd':
            kwargs['operation'] = 'dn'
        else:
            kwargs['operation'] = 'n'

        # evaluate
        returnval = self.function(**kwargs)
        return returnval

    def addGrid(self, gridData, gridName='grid'):
        # set own DataContainer containing grid data
        data = gridData.slice(gridName, excludeKey=True)
        self.dataContainer.addData(
            'grid', data.data
        )  # improper use of the DataContainer by accessing its data directly
        return

    def addValue(self, value):
        """Add a variable 'value' to the numerical function

        Parameters:
            value (ndarray) - value to be put in the internal DataContainer
        """
        self.dataContainer.addData('value', value)
        self.valueSize = len(value.shape)
        return

    def addDerivative(self, derivative, dim):
        self.dataContainer.merge({'derivative': {dim: derivative}})
        return

    ### Depreciated v2.2 [dep01] ###
    def addSecondDerivative(self, derivative, dim):
        """ Depreciated v2.2
        """
        self.dataContainer.merge({'secondDerivative': {dim: derivative}})
        return

    ### End ###

    def value(self, **kwargs):
        """Return the value of the variable in this numerical function.

        Parameters:
            kwargs (dict) - coordinates

        Returns:
            Array value using DataContainer interpolation.
        """
        return self.dataContainer.v('value', **kwargs)

    def derivative(self, **kwargs):
        """Similar to .value(). Returns the derivative uploaded to the numerical function or makes a call
        to a numerical derivation method if no derivative is uploaded.
        """
        # kwargs.pop('operation')       # obsolete
        dim = kwargs.get('dim')
        v = self.dataContainer.v(
            'derivative', dim,
            **kwargs)  # try if analytical derivative is available
        if v is None:
            v = self.dataContainer.d(
                'value', **kwargs)  # else take numerical derivative
        return v

    ### Depreciated v2.2 [dep01] ###
    def secondDerivative(self, **kwargs):
        """See .derivative(). This method does the same for the second derivative
        Depreciated 2.2 [dep01]
        """
        # kwargs.pop('operation')       # obsolete
        dim = kwargs.get('dim')
        v = self.dataContainer.v('secondDerivative', dim, **kwargs)
        if v is None:
            v = self.dataContainer.dd('value', **kwargs)
        return v
Ejemplo n.º 5
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.º 6
0
    def run(self):
        """Run function to initiate the calculation of the sediment concentration based on dynamic erodibility. Hereby,
        we solve the following three equations:

        S_t = - [Flux_x + Flux * (B_x/B)]                    (1)

        Flux = T*f + F*f_x                                   (2)

        f = f(Stilde)                                        (3)

        with:

        S      = sediment stock, which is the total amount of sediment in the water column and the erodible bottom
        Flux   = sediment transport
        f      = relative sediment erodibility
        B      = estuary width
        T      = transport function
        F      = diffusion function
        Stilde = S / Chat, with Chat is the subtidal carrying capacity

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

        ## Initiate variables
        # general variables
        self.RHOS = self.input.v('RHOS')
        self.DS = self.input.v('DS')
        self.WS = self.input.v('ws0')
        self.GPRIME = self.input.v('G') * (
            self.RHOS - self.input.v('RHO0')) / self.input.v('RHO0')
        self.Mhat = self.input.v('Mhat')
        self.CSEA = self.input.v('csea')
        self.FCAP = self.input.v('fcap')
        self.P = self.input.v('p')
        self.TOL = self.input.v('tol')
        self.ASTAR = self.input.v('astar')
        self.Kh = self.input.v('Kh')
        self.L = self.input.v('L')
        self.x = self.input.v('grid', 'axis', 'x') * self.L
        self.dx = (self.x[1:] - self.x[:-1]).reshape(len(self.x) - 1, 1)
        jmax = self.input.v('grid', 'maxIndex', 'x')
        kmax = self.input.v('grid', 'maxIndex', 'z')
        fmax = self.input.v('grid', 'maxIndex', 'f')
        self.z = self.input.v('grid', 'axis', 'z', 0, range(0, kmax + 1))
        self.zarr = ny.dimensionalAxis(self.input.slice('grid'), 'z')[:, :, 0]
        self.H = (self.input.v('H', range(0, jmax + 1)).reshape(jmax + 1, 1) +
                  self.input.v('R', range(0, jmax + 1)).reshape(jmax + 1, 1))
        self.Hx = (self.input.d('H', range(0, jmax + 1), dim='x').reshape(
            jmax + 1, 1) + self.input.d('R', range(0, jmax + 1),
                                        dim='x').reshape(jmax + 1, 1))
        self.B = self.input.v('B', range(0, jmax + 1)).reshape(jmax + 1, 1)
        self.Bx = self.input.d('B', range(0, jmax + 1),
                               dim='x').reshape(jmax + 1, 1)
        self.sf = self.input.v('Roughness', range(0, jmax + 1), 0,
                               0).reshape(jmax + 1, 1)
        self.Av0 = self.input.v('Av', range(0, jmax + 1), 0,
                                0).reshape(jmax + 1, 1)

        # velocity
        self.u1river = np.real(
            self.input.v('u1', 'river', range(0, jmax + 1), range(0, kmax + 1),
                         0))
        self.Q_fromhydro = -np.trapz(self.u1river[-1, :],
                                     x=-self.zarr[-1, :]) * self.B[-1]

        # c hat
        self.c00 = np.real(
            self.input.v('hatc0', range(0, jmax + 1), range(0, kmax + 1), 0))
        self.c04 = self.input.v('hatc0', range(0, jmax + 1),
                                range(0, kmax + 1), 2)

        ## Compute transport (in superclass)
        d = self.compute_transport()
        dc = DataContainer(d)
        self.Fc = (dc.v('F', range(0, jmax + 1)) -
                   dc.v('F', 'diffusion_river', range(0, jmax + 1))).reshape(
                       jmax + 1, 1)
        self.Tc = (dc.v('T') -
                   (dc.v('T', 'river', range(0, jmax + 1)) +
                    dc.v('T', 'river_river', range(0, jmax + 1)) +
                    dc.v('T', 'diffusion_river', range(0, jmax + 1)))).reshape(
                        len(self.x), 1)
        self.TQ = dc.v('T', 'river', range(0, jmax + 1)).reshape(
            jmax + 1, 1) / self.Q_fromhydro

        ## User input
        #TODO: make a consistent and effective script that handles user input of the discharge time series or any other time-dependent variable
        #load time serie Q
        self.dt = self.interpretValues(self.input.v('dt'))
        if self.input.v('t') is not None:
            self.t = self.interpretValues(self.input.v('t'))
        self.Q = self.interpretValues(self.input.v('Q'))

        ## Run
        self.logger.info('Running time-integrator')
        vars = self.implicit()

        ## Collect output
        d = {}
        for key, value in vars.iteritems():
            d[key] = value
        return d