示例#1
0
    def solve(self, annotate=True):
        ''' Solve the shallow water equations '''

        ############################### Setting up the equations ###########################

        # Initialise solver settings
        if not type(self.problem) == SWProblem:
            raise TypeError("Do not know how to solve problem of type %s." %
                type(self.problem))

        # Get parameters
        problem_params = self.problem.parameters
        solver_params = self.parameters
        farm = problem_params.tidal_farm
        if farm:
            turbine_friction = farm.friction_function

        # Performance settings
        parameters['form_compiler']['quadrature_degree'] = \
            solver_params.quadrature_degree
        parameters['form_compiler']['cpp_optimize_flags'] = \
            " ".join(solver_params.cpp_flags)
        parameters['form_compiler']['cpp_optimize'] = True
        parameters['form_compiler']['optimize'] = True

        # Get domain measures
        ds = problem_params.domain.ds
        dx = problem_params.domain.dx

        # Get the boundary normal direction
        n = FacetNormal(self.mesh)

        # Get temporal settings
        theta = Constant(problem_params.theta)
        dt = Constant(problem_params.dt)
        finish_time = Constant(problem_params.finish_time)
        t = Constant(problem_params.start_time)

        # Get equation settings
        g = problem_params.g
        h = problem_params.depth
        nu = problem_params.viscosity
        include_advection = problem_params.include_advection
        include_viscosity = problem_params.include_viscosity
        linear_divergence = problem_params.linear_divergence
        f_u = problem_params.f_u
        include_les = solver_params.les_model

        # Get boundary conditions
        bcs = problem_params.bcs

        # Get function spaces
        V, Q = self.V, self.Q
        dgu = "Discontinuous" in str(V)

        # Test and trial functions
        v = TestFunction(V)
        u = TrialFunction(V)
        q = TestFunction(Q)
        eta = TrialFunction(Q)

        # Functions
        u00 = Function(V)
        u0 = Function(V, name="u0")
        ut = Function(V) # Tentative velocity
        u1 = Function(V, name="u")
        eta0 = Function(Q, name="eta0")
        eta1 = Function(Q, name="eta")

        # Large eddy model
        if include_les:
            les_V = FunctionSpace(problem_params.domain.mesh, "CG", 1)
            les = LES(les_V, u0,
                    solver_params.les_parameters['smagorinsky_coefficient'])
            eddy_viscosity = les.eddy_viscosity
            nu += eddy_viscosity
        else:
            eddy_viscosity = None

        # Define the water depth
        if linear_divergence:
            H = h
        else:
            H = eta0 + h

        if f_u is None:
            f_u = Constant((0, 0))

        # Bottom friction
        friction = problem_params.friction

        if farm:
            friction += Function(turbine_friction, name="turbine_friction",
                    annotate=annotate)

        # Load initial conditions
        # Projection is necessary to obtain 2nd order convergence
        # FIXME: The problem should specify the ic for each component separately.
        u_ic = project(problem_params.initial_condition_u, self.V)
        u0.assign(u_ic, annotate=False)
        u00.assign(u_ic, annotate=False)
        eta_ic = project(problem_params.initial_condition_eta, self.Q)
        eta0.assign(eta_ic, annotate=False)
        eta1.assign(eta_ic, annotate=False)

        # Tentative velocity step
        u_mean = theta * u + (1. - theta) * u0
        u_bash = 3./2 * u0 - 1./2 * u00
        u_diff = u - u0
        norm_u0 = inner(u0, u0)**0.5
        F_u_tent = ((1/dt) * inner(v, u_diff) * dx()
                    + inner(v, grad(u_bash)*u_mean) * dx()
                    + g * inner(v, grad(eta0)) * dx()
                    + friction / H * norm_u0 * inner(u_mean, v) * dx
                    - inner(v, f_u) * dx())
        # Viscosity term
        if dgu:
            # Taken from http://maths.dur.ac.uk/~dma0mpj/summer_school/IPHO.pdf
            sigma = 1. # Penalty parameter.
            # Set tau=-1 for SIPG, tau=0 for IIPG, and tau=1 for NIPG
            tau = 0.
            edgelen = FacetArea(self.mesh)('+')  # Facetarea is continuous, so
            # we can select either side
            alpha = sigma/edgelen

            F_u_tent += nu * inner(grad(v), grad(u_mean)) * dx()
            for d in range(2):
                F_u_tent += - nu * inner(avg(grad(u_mean[d])), jump(v[d], n))*dS
                F_u_tent += - nu * tau * inner(avg(grad(v[d])), jump(u[d], n))*dS
                F_u_tent += alpha * nu * inner(jump(u[d], n), jump(v[d], n))*dS

        else:
            F_u_tent += nu * inner(grad(v), grad(u_mean)) * dx()

        a_u_tent = lhs(F_u_tent)
        L_u_tent = rhs(F_u_tent)

        # Pressure correction
        eta_diff = eta - eta0
        ut_mean = theta * ut + (1. - theta) * u0
        F_p_corr = (q*eta_diff + g * dt**2 * theta**2 * H * inner(grad(q),
            grad(eta_diff)))*dx() + dt*q*div(H*ut_mean)*dx()
        a_p_corr = lhs(F_p_corr)
        L_p_corr = rhs(F_p_corr)

        # Velocity correction
        eta_diff = eta1 - eta0
        a_u_corr = inner(v, u)*dx()
        L_u_corr = inner(v, ut)*dx() - dt*g*theta*inner(v, grad(eta_diff))*dx()

        bcu, bceta = self._generate_strong_bcs(dgu)

        # Assemble matrices
        A_u_corr = assemble(a_u_corr)
        for bc in bcu: bc.apply(A_u_corr)
        a_u_corr_solver = LUSolver(A_u_corr)
        a_u_corr_solver.parameters["reuse_factorization"] = True

        if linear_divergence:
            A_p_corr = assemble(a_p_corr)
            for bc in bceta: bc.apply(A_p_corr)
            a_p_corr_solver = LUSolver(A_p_corr)
            a_p_corr_solver.parameters["reuse_factorization"] = True

        yield({"time": t,
               "u": u0,
               "eta": eta0,
               "eddy_viscosity": eddy_viscosity,
               "is_final": self._finished(t, finish_time)})

        log(INFO, "Start of time loop")
        adjointer.time.start(t)
        timestep = 0

        # De/activate annotation
        annotate_orig = parameters["adjoint"]["stop_annotating"]
        parameters["adjoint"]["stop_annotating"] = not annotate

        while not self._finished(t, finish_time):
            # Update timestep
            timestep += 1
            t = Constant(t + dt)

            # Update bc's
            t_theta = Constant(t - (1.0 - theta) * dt)
            bcs.update_time(t, only_type=["strong_dirichlet"])
            bcs.update_time(t_theta, exclude_type=["strong_dirichlet"])

            # Update source term
            if f_u is not None:
                f_u.t = Constant(t_theta)

            if include_les:
                log(PROGRESS, "Compute eddy viscosity.")
                les.solve()

            # Compute tentative velocity step
            log(PROGRESS, "Solve for tentative velocity.")
            A_u_tent = assemble(a_u_tent)
            b = assemble(L_u_tent)
            for bc in bcu: bc.apply(A_u_tent, b)

            solve(A_u_tent, ut.vector(), b)

            # Pressure correction
            log(PROGRESS, "Solve for pressure correction.")
            b = assemble(L_p_corr)
            for bc in bceta: bc.apply(b)

            if linear_divergence:
                a_p_corr_solver.solve(eta1.vector(), b)
            else:
                A_p_corr = assemble(a_p_corr)
                for bc in bceta: bc.apply(A_p_corr)
                solve(A_p_corr, eta1.vector(), b)

            # Velocity correction
            log(PROGRESS, "Solve for velocity update.")
            b = assemble(L_u_corr)
            for bc in bcu: bc.apply(b)

            a_u_corr_solver.solve(u1.vector(), b)

            # Rotate functions for next timestep
            u00.assign(u0)
            u0.assign(u1)
            eta0.assign(eta1)

            # Increase the adjoint timestep
            adj_inc_timestep(time=float(t), finished=self._finished(t,
                finish_time))

            yield({"time": t,
                   "u": u0,
                   "eta": eta0,
                   "eddy_viscosity": eddy_viscosity,
                   "is_final": self._finished(t, finish_time)})

        # Reset annotation flag
        parameters["adjoint"]["stop_annotating"] = annotate_orig

        log(INFO, "End of time loop.")
示例#2
0
# A time vector, noting 1600sps is used.
tt = np.linspace(0, 32*10/1600, 32*10, endpoint=False)

# A phase comparison vector. This should be the idea output.
pt = np.concatenate((((2*np.pi*50.0*tt+np.pi) % (2*np.pi) - np.pi),(2*np.pi*ft*tt+np.pi) % (2*np.pi) - np.pi))

# The test input vector
yt =  np.concatenate((mag*np.cos(2*np.pi*50*tt) + dc_offset, mag*np.cos(2*np.pi*ft*tt) + dc_offset))

# Re-define tt to extend the full length.
tt = np.linspace(0, 2*32*10/1600, 2*32*10, endpoint=False)
step_time = (32*10)/1600 # used for drawing a line of the plots

# Create and run the filter, noting increasing the number of iterations
# will reduce the LES filter settling time at the cost of higher computation time.
les = LES(iterations=1)
les_out = les.run_les(yt)


# Visualisation of the output
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, sharex=True, sharey=False)
fig.suptitle('LES Freq Step Test', fontsize=16)

# Plots have the LES generated lines wider so the correct lines is overlayed and visable.
# Plot the phases
ax1.plot(tt, les_out[1], linewidth=3)
ax1.plot(tt, pt)
ax1.set_title('Phase (rad)')
ax1.axvline(x=step_time, ls='--', c='red')

# Plot the freqency
    def solve(self, annotate=True):
        ''' Returns an iterator for solving the shallow water equations. '''

        ############################### Setting up the equations ###########################

        # Get parameters
        problem_params = self.problem.parameters
        solver_params = self.parameters
        farm = problem_params.tidal_farm

        # Performance settings
        parameters['form_compiler']['quadrature_degree'] = \
            solver_params.quadrature_degree
        parameters['form_compiler']['cpp_optimize_flags'] = \
            " ".join(solver_params.cpp_flags)
        parameters['form_compiler']['cpp_optimize'] = True
        parameters['form_compiler']['optimize'] = True

        # Get domain measures
        ds = problem_params.domain.ds

        # Initialise solver settings
        if type(self.problem) == SWProblem:
            log(INFO, "Solve a transient shallow water problem")

            theta = Constant(problem_params.theta)
            dt = Constant(problem_params.dt)
            finish_time = Constant(problem_params.finish_time)

            t = Constant(problem_params.start_time)

            include_time_term = True

        elif type(self.problem) == MultiSteadySWProblem:
            log(INFO, "Solve a multi steady-state shallow water problem")

            theta = Constant(1)
            dt = Constant(problem_params.dt)
            finish_time = Constant(problem_params.finish_time)

            # The multi steady-state case solves the steady-state equation also
            # for the start time
            t = Constant(problem_params.start_time - dt)

            include_time_term = False

        elif type(self.problem) == SteadySWProblem:
            log(INFO, "Solve a steady-state shallow water problem")

            theta = Constant(1.)
            dt = Constant(1.)
            finish_time = Constant(0.5)

            t = Constant(0.)

            include_time_term = False

        else:
            raise TypeError("Do not know how to solve problem of type %s." %
                type(self.problem))

        g = problem_params.g
        depth = problem_params.depth
        include_advection = problem_params.include_advection
        include_viscosity = problem_params.include_viscosity
        viscosity = problem_params.viscosity
        bcs = problem_params.bcs
        linear_divergence = problem_params.linear_divergence
        cache_forward_state = solver_params.cache_forward_state
        f_u = problem_params.f_u

        u_dg = "Discontinuous" in str(self.function_space.split()[0])

        # Define test functions
        v, q = TestFunctions(self.function_space)

        # Define functions
        state = Function(self.function_space, name="Current_state")
        self.state = state
        state_new = Function(self.function_space, name="New_state")

        # Load initial condition (or initial guess for stady problems)
        # Projection is necessary to obtain 2nd order convergence
        ic = project(problem_params.initial_condition, self.function_space)
        state.assign(ic, annotate=False)

        # Split mixed functions
        u, h = split(state_new)

        u0, h0 = split(state)

        # Define the water depth
        if linear_divergence:
            H = depth
        else:
            H = h + depth

        # Create initial conditions and interpolate
        state_new.assign(state, annotate=annotate)

        # u_(n+theta) and h_(n+theta)
        u_mid = (1.0 - theta) * u0 + theta * u
        h_mid = (1.0 - theta) * h0 + theta * h

        # The normal direction
        n = FacetNormal(self.mesh)

        # Large eddy model
        include_les = solver_params.les_model
        if include_les:
            les_V = FunctionSpace(problem_params.domain.mesh, "CG", 1)
            les = LES(les_V, u0, solver_params.les_parameters['smagorinsky_coefficient'])
            eddy_viscosity = les.eddy_viscosity
            viscosity += eddy_viscosity
        else:
            eddy_viscosity = None

        # k-eps RANS model
        #include_keps = solver_params.keps_model
        #if include_keps:
        #    keps_V = FunctionSpace(problem_params.domain.mesh, "CG", 1)
        #    keps = KEpsilon(keps_V, u, dt, problem_params.domain.mesh)
        #    eddy_viscosity = keps.eddy_viscosity_old
        #    viscosity += eddy_viscosity
        #else:
        #    eddy_viscosity = None
            
        # Mass matrix contributions
        M = inner(v, u) * dx
        M += inner(q, h) * dx
        M0 = inner(v, u0) * dx
        M0 += inner(q, h0) * dx

        # Divergence term.
        Ct_mid = -H * inner(u_mid, grad(q)) * dx
        #+inner(avg(u_mid),jump(q,n))*dS # This term is only needed for dg
                                         # element pairs which is not supported

        # The surface integral contribution from the divergence term
        bc_contr = -H * dot(u_mid, n) * q * ds

        for function_name, u_expr, facet_id, bctype in bcs.filter(function_name='u'):

            if bctype in ('weak_dirichlet', 'free_slip'):
                # Subtract the divergence integral again
                bc_contr -= -H * dot(u_mid, n) * q * ds(facet_id)
                # for weak Dirichlet we replace it with the bc expression
                if bctype=='weak_dirichlet':
                  bc_contr -= H * dot(u_expr, n) * q * ds(facet_id)

            elif bctype == 'flather':
                # Subtract the divergence integral again
                bc_contr -= -H * dot(u_mid, n) * q * ds(facet_id)
 
                # The Flather boundary condition
                #bc_contr -= H * dot(u_expr, n) * q * ds(facet_id)
                Ct_mid += sqrt(g * H) * inner(h_mid, q) * ds(facet_id) + H * dot(u_expr, n) * q * ds(facet_id)


        # Pressure gradient term
        weak_eta_bcs = bcs.filter(function_name='eta', bctype='weak_dirichlet')

        # don't integrate pressure gradient by parts (a.o. allows dg test function v)
        C_mid = g * inner(v, grad(h_mid)) * dx

        for function_name, eta_expr, facet_id, bctype in weak_eta_bcs:
            # Apply the eta boundary conditions weakly on boundary IDs 1 and 2
            C_mid +=  g * inner(dot(v, n), (eta_expr-h_mid)) * ds(facet_id)

        # Bottom friction
        friction = problem_params.friction

        if not farm:
            tf = Constant(0)
        elif type(farm.friction_function) == list:
            tf = Function(farm.friction_function[0], name="turbine_friction", annotate=annotate)
        else:
            tf = Function(farm.friction_function, name="turbine_friction", annotate=annotate)

        # Friction term
        # FIXME: FEniCS fails on assembling the below form for u_mid = 0, even
        # though it is differentiable. Even this potential fix does not help:
        #norm_u_mid = conditional(inner(u_mid, u_mid)**0.5 < DOLFIN_EPS, Constant(0),
        #        inner(u_mid, u_mid)**0.5)
        norm_u_mid = inner(u_mid, u_mid)**0.5
        R_mid = friction / H * norm_u_mid * inner(u_mid, v) * dx(self.mesh)

        if farm:

            if not farm.turbine_specification.thrust:
                R_mid += tf/H*dot(u_mid, u_mid)**0.5*inner(u_mid, v)*farm.site_dx
            else: 
                u_mag = dot(u_mid, u_mid)**0.5
                C_t = farm.turbine_specification.compute_C_t(u_mag)
                R_mid += (tf * farm.turbine_specification.turbine_parametrisation_constant * \
                          C_t / H) * u_mag * inner(u_mid, v) * farm.site_dx
        
        # Advection term
        if include_advection:
            Ad_mid = inner(dot(grad(u_mid), u_mid), v) * dx

            # un is |u.n| on the down-side (incoming), and 0 on the up-side of a facet (outgoing)
            un = (abs(dot(u, n))-dot(u,n))/2.0

            if u_dg:
              # at the downside, we want inner(|u.n|*(u_down-u_up),v_down)  - u_down-u_up being the gradient along the flow
              Ad_mid += (inner(un('+')*(u_mid('+')-u_mid('-')), v('+')) + inner(un('-')*(u_mid('-')-u_mid('+')), v('-')))*dS

            # apply weak_diricihlet bc for the advection term at the incoming boundaries only
            for function_name, u_expr, facet_id, bctype in bcs:

                if function_name =="u" and bctype == 'weak_dirichlet':
                    # this is the same thing as for DG above, except u_up is the boundary value and u_down is u+ or u- (they are the same)
                    # the fact that these are the same also means that the DG term above vanishes at the boundary and is replaced here
                    Ad_mid += inner(un*(u_mid-u_expr), v)*ds(facet_id)


        if include_viscosity:
            # Check that we are not using a DG velocity function space, as the facet integrals are not implemented.
            if u_dg:
                raise NotImplementedError("The viscosity term for \
                    discontinuous elements is not supported.")
            
            #D_mid = viscosity*inner(grad(u_mid) + grad(u_mid).T, grad(v))*dx - viscosity*(2.0/3.0)*inner(div(u_mid)*Identity(2), grad(v))*dx
            D_mid = viscosity * inner(2*sym(grad(u_mid)), grad(v)) * dx

        # Create the final form
        G_mid = C_mid + Ct_mid + R_mid

        # Add the advection term
        if include_advection:
            G_mid += Ad_mid

        # Add the viscosity term
        if include_viscosity:
            G_mid += D_mid

        # Add the source term
        G_mid -= inner(f_u, v) * dx
        F = dt * G_mid - dt * bc_contr

        # Add the time term
        if include_time_term:
            F += M - M0

        # Generate the scheme specific strong boundary conditions
        strong_bcs = self._generate_strong_bcs()

        ############################### Perform the simulation ###########################

        if solver_params.dump_period > 0:
            writer = StateWriter(solver=self)
            if type(self.problem) == SWProblem:
                log(INFO, "Writing state to disk...")
                writer.write(state)

        result = {"time": t,
                  "u": u0,
                  "eta": h0,
                  "tf": tf,
                  "state": state,
                  "is_final": self._finished(t, finish_time)}
        solver_params.callback(result)
        yield(result)
        print "Power at %.2f = %.2f" % (float(t), assemble(1000.0*tf*dot(u_mid, u_mid)**1.5*dx))

        log(INFO, "Start of time loop")
        adjointer.time.start(t)
        timestep = 0
        while not self._finished(t, finish_time):
            # Update timestep
            timestep += 1
            t = Constant(t + dt)

            # Update bc's
            t_theta = Constant(t - (1.0 - theta) * dt)
            bcs.update_time(t, only_type=["strong_dirichlet"])
            bcs.update_time(t_theta, exclude_type=["strong_dirichlet"])

            # Update source term
            f_u.t = Constant(t_theta)

            if include_les:
                log(PROGRESS, "Compute eddy viscosity from LES model.")
                les.solve()

            #if include_keps:
            #    log(PROGRESS, "Compute eddy viscosity from k-epsilon RANS model.")
            #    e = keps.solve(u0)
            #    eddy_viscosity.assign(e)

            # Set the initial guess for the solve
            if cache_forward_state and self.state_cache.has_key(float(t)):
                log(INFO, "Read initial guess from cache for t=%f." % t)
                # Load initial guess for solver from cache
                state_new.assign(self.state_cache[float(t)], annotate=False)

            elif not include_time_term:
                log(INFO, "Set the initial guess for the nonlinear solver to the initial condition.")
                # Reset the initial guess after each timestep
                ic = problem_params.initial_condition
                state_new.assign(ic, annotate=False)

            # Solve non-linear system with a Newton solver
            if self.problem._is_transient:
                log(INFO, "Solve shallow water equations at time %s" % float(t))
            else:
                log(INFO, "Solve shallow water equations.")

            solve(F == 0, state_new, bcs=strong_bcs,
                  solver_parameters=solver_params.dolfin_solver,
                  annotate=annotate,
                  J=derivative(F, state_new))

            # After the timestep solve, update state
            state.assign(state_new)

            if cache_forward_state:
                # Save state for initial guess cache
                log(INFO, "Cache solution t=%f as next initial guess." % t)
                if not self.state_cache.has_key(float(t)):
                    self.state_cache[float(t)] = Function(self.function_space)
                self.state_cache[float(t)].assign(state_new, annotate=False)

            # Set the control function for the upcoming timestep.
            if farm:
                if type(farm.friction_function) == list:
                    tf.assign(farm.friction_function[timestep])
                else:
                    tf.assign(farm.friction_function)

            if (solver_params.dump_period > 0 and
                timestep % solver_params.dump_period == 0):
                log(INFO, "Write state to disk...")
                writer.write(state)

            # Return the results
            result = {"time": t,
                      "u": u0,
                      "eta": h0,
                      "tf": tf,
                      "state": state,
                      "is_final": self._finished(t, finish_time)}
            solver_params.callback(result)
            yield(result)

            # Increase the adjoint timestep
            adj_inc_timestep(time=float(t), finished=self._finished(t,
                finish_time))

            print "Power at %.2f = %.2f" % (float(t), assemble(1000.0*tf*dot(u_mid, u_mid)**1.5*dx))

        # If we're outputting the individual turbine power
        if self.parameters.print_individual_turbine_power:
            self.parameters.output_writer.individual_turbine_power(self)

        log(INFO, "End of time loop.")
示例#4
0
    def solve(self, annotate=True):
        ''' Solve the shallow water equations '''

        ############################### Setting up the equations ###########################

        # Initialise solver settings
        if not type(self.problem) == SWProblem:
            raise TypeError("Do not know how to solve problem of type %s." %
                            type(self.problem))

        # Get parameters
        problem_params = self.problem.parameters
        solver_params = self.parameters
        farm = problem_params.tidal_farm
        if farm:
            turbine_friction = farm.friction_function

        # Performance settings
        parameters['form_compiler']['quadrature_degree'] = \
            solver_params.quadrature_degree
        parameters['form_compiler']['cpp_optimize_flags'] = \
            " ".join(solver_params.cpp_flags)
        parameters['form_compiler']['cpp_optimize'] = True
        parameters['form_compiler']['optimize'] = True

        # Get domain measures
        ds = problem_params.domain.ds
        dx = problem_params.domain.dx

        # Get the boundary normal direction
        n = FacetNormal(self.mesh)

        # Get temporal settings
        theta = Constant(problem_params.theta)
        dt = Constant(problem_params.dt)
        finish_time = Constant(problem_params.finish_time)
        t = Constant(problem_params.start_time)

        # Get equation settings
        g = problem_params.g
        h = problem_params.depth
        nu = problem_params.viscosity
        include_advection = problem_params.include_advection
        include_viscosity = problem_params.include_viscosity
        linear_divergence = problem_params.linear_divergence
        f_u = problem_params.f_u
        include_les = solver_params.les_model

        # Get boundary conditions
        bcs = problem_params.bcs

        # Get function spaces
        V, Q = self.V, self.Q
        dgu = "Discontinuous" in str(V)

        # Test and trial functions
        v = TestFunction(V)
        u = TrialFunction(V)
        q = TestFunction(Q)
        eta = TrialFunction(Q)

        # Functions
        u00 = Function(V)
        u0 = Function(V, name="u0")
        ut = Function(V)  # Tentative velocity
        u1 = Function(V, name="u")
        eta0 = Function(Q, name="eta0")
        eta1 = Function(Q, name="eta")

        # Large eddy model
        if include_les:
            les_V = FunctionSpace(problem_params.domain.mesh, "CG", 1)
            les = LES(les_V, u0,
                      solver_params.les_parameters['smagorinsky_coefficient'])
            eddy_viscosity = les.eddy_viscosity
            nu += eddy_viscosity
        else:
            eddy_viscosity = None

        # Define the water depth
        if linear_divergence:
            H = h
        else:
            H = eta0 + h

        if f_u is None:
            f_u = Constant((0, 0))

        # Bottom friction
        friction = problem_params.friction

        if farm:
            friction += Function(turbine_friction,
                                 name="turbine_friction",
                                 annotate=annotate)

        # Load initial conditions
        # Projection is necessary to obtain 2nd order convergence
        # FIXME: The problem should specify the ic for each component separately.
        u_ic = project(problem_params.initial_condition_u, self.V)
        u0.assign(u_ic, annotate=False)
        u00.assign(u_ic, annotate=False)
        eta_ic = project(problem_params.initial_condition_eta, self.Q)
        eta0.assign(eta_ic, annotate=False)
        eta1.assign(eta_ic, annotate=False)

        # Tentative velocity step
        u_mean = theta * u + (1. - theta) * u0
        u_bash = 3. / 2 * u0 - 1. / 2 * u00
        u_diff = u - u0
        norm_u0 = inner(u0, u0)**0.5
        F_u_tent = ((1 / dt) * inner(v, u_diff) * dx() +
                    inner(v,
                          grad(u_bash) * u_mean) * dx() +
                    g * inner(v, grad(eta0)) * dx() +
                    friction / H * norm_u0 * inner(u_mean, v) * dx -
                    inner(v, f_u) * dx())
        # Viscosity term
        if dgu:
            # Taken from http://maths.dur.ac.uk/~dma0mpj/summer_school/IPHO.pdf
            sigma = 1.  # Penalty parameter.
            # Set tau=-1 for SIPG, tau=0 for IIPG, and tau=1 for NIPG
            tau = 0.
            edgelen = FacetArea(self.mesh)('+')  # Facetarea is continuous, so
            # we can select either side
            alpha = sigma / edgelen

            F_u_tent += nu * inner(grad(v), grad(u_mean)) * dx()
            for d in range(2):
                F_u_tent += -nu * inner(avg(grad(u_mean[d])), jump(v[d],
                                                                   n)) * dS
                F_u_tent += -nu * tau * inner(avg(grad(v[d])), jump(u[d],
                                                                    n)) * dS
                F_u_tent += alpha * nu * inner(jump(u[d], n), jump(v[d],
                                                                   n)) * dS

        else:
            F_u_tent += nu * inner(grad(v), grad(u_mean)) * dx()

        a_u_tent = lhs(F_u_tent)
        L_u_tent = rhs(F_u_tent)

        # Pressure correction
        eta_diff = eta - eta0
        ut_mean = theta * ut + (1. - theta) * u0
        F_p_corr = (q * eta_diff + g * dt**2 * theta**2 * H *
                    inner(grad(q), grad(eta_diff))) * dx() + dt * q * div(
                        H * ut_mean) * dx()
        a_p_corr = lhs(F_p_corr)
        L_p_corr = rhs(F_p_corr)

        # Velocity correction
        eta_diff = eta1 - eta0
        a_u_corr = inner(v, u) * dx()
        L_u_corr = inner(v, ut) * dx() - dt * g * theta * inner(
            v, grad(eta_diff)) * dx()

        bcu, bceta = self._generate_strong_bcs(dgu)

        # Assemble matrices
        A_u_corr = assemble(a_u_corr)
        for bc in bcu:
            bc.apply(A_u_corr)
        a_u_corr_solver = LUSolver(A_u_corr)
        a_u_corr_solver.parameters["reuse_factorization"] = True

        if linear_divergence:
            A_p_corr = assemble(a_p_corr)
            for bc in bceta:
                bc.apply(A_p_corr)
            a_p_corr_solver = LUSolver(A_p_corr)
            a_p_corr_solver.parameters["reuse_factorization"] = True

        yield ({
            "time": t,
            "u": u0,
            "eta": eta0,
            "eddy_viscosity": eddy_viscosity,
            "is_final": self._finished(t, finish_time)
        })

        log(INFO, "Start of time loop")
        adjointer.time.start(t)
        timestep = 0

        # De/activate annotation
        annotate_orig = parameters["adjoint"]["stop_annotating"]
        parameters["adjoint"]["stop_annotating"] = not annotate

        while not self._finished(t, finish_time):
            # Update timestep
            timestep += 1
            t = Constant(t + dt)

            # Update bc's
            t_theta = Constant(t - (1.0 - theta) * dt)
            bcs.update_time(t, only_type=["strong_dirichlet"])
            bcs.update_time(t_theta, exclude_type=["strong_dirichlet"])

            # Update source term
            if f_u is not None:
                f_u.t = Constant(t_theta)

            if include_les:
                log(PROGRESS, "Compute eddy viscosity.")
                les.solve()

            # Compute tentative velocity step
            log(PROGRESS, "Solve for tentative velocity.")
            A_u_tent = assemble(a_u_tent)
            b = assemble(L_u_tent)
            for bc in bcu:
                bc.apply(A_u_tent, b)

            solve(A_u_tent, ut.vector(), b)

            # Pressure correction
            log(PROGRESS, "Solve for pressure correction.")
            b = assemble(L_p_corr)
            for bc in bceta:
                bc.apply(b)

            if linear_divergence:
                a_p_corr_solver.solve(eta1.vector(), b)
            else:
                A_p_corr = assemble(a_p_corr)
                for bc in bceta:
                    bc.apply(A_p_corr)
                solve(A_p_corr, eta1.vector(), b)

            # Velocity correction
            log(PROGRESS, "Solve for velocity update.")
            b = assemble(L_u_corr)
            for bc in bcu:
                bc.apply(b)

            a_u_corr_solver.solve(u1.vector(), b)

            # Rotate functions for next timestep
            u00.assign(u0)
            u0.assign(u1)
            eta0.assign(eta1)

            # Increase the adjoint timestep
            adj_inc_timestep(time=float(t),
                             finished=self._finished(t, finish_time))

            yield ({
                "time": t,
                "u": u0,
                "eta": eta0,
                "eddy_viscosity": eddy_viscosity,
                "is_final": self._finished(t, finish_time)
            })

        # Reset annotation flag
        parameters["adjoint"]["stop_annotating"] = annotate_orig

        log(INFO, "End of time loop.")