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.")
# 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.")
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.")