def fenics_solve(f): u = fa.Function(V, name="State") v = fn.TestFunction(V) F = (ufl.inner(ufl.grad(u), ufl.grad(v)) - f * v) * ufl.dx bcs = [fa.DirichletBC(V, 0.0, "on_boundary")] fa.solve(F == 0, u, bcs) return u
def J(f): a = f * inner(grad(u), grad(v)) * dx L = inner(f, v) * dx + inner(g1, v) * ds(1) + inner(g2, v) * ds(2) solve(a == L, u_, bc) return assemble(u_**2 * dx)
def run_steady_state_model(function_space, kappa, forcing, boundary_conditions=None, velocity=None): """ Solve steady-state diffusion equation -grad (k* grad u) = f """ mesh = function_space.mesh() if boundary_conditions == None: bndry_obj = dl.CompiledSubDomain("on_boundary") boundary_conditions = [['dirichlet', bndry_obj, dla.Constant(0)]] num_bndrys = len(boundary_conditions) boundaries = mark_boundaries(mesh, boundary_conditions) dirichlet_bcs = collect_dirichlet_boundaries(function_space, boundary_conditions, boundaries) # To express integrals over the boundary parts using ds(i), we must first # redefine the measure ds in terms of our boundary markers: ds = dl.Measure('ds', domain=mesh, subdomain_data=boundaries) dx = dl.Measure('dx', domain=mesh) # Variational problem at each time u = dl.TrialFunction(function_space) v = dl.TestFunction(function_space) a = kappa * dl.inner(dl.grad(u), dl.grad(v)) * dx L = forcing * v * dx if velocity is not None: a += v * dl.dot(velocity, dl.grad(u)) * dx beta_1_list = [] alpha_1_list = [] for ii in range(num_bndrys): if (boundary_conditions[ii][0] == 'robin'): alpha = boundary_conditions[ii][3] a += alpha * u * v * ds(ii) elif ((boundary_conditions[ii][0] == 'robin') or (boundary_conditions[ii][0] == 'neumann')): beta = boundary_conditions[ii][2] L -= beta * v * ds(ii) u = dla.Function(function_space) # dl.assemble, apply and solve does not work with # fenics adjoint # A, b = dla.assemble_system(a, L, dirichlet_bcs) # # apply boundary conditions # for bc in dirichlet_bcs: # bc.apply(A, b) # dla.solve(A, u.vector(), b) dla.solve(a == L, u, dirichlet_bcs) return u
def forward(x): u = fn.TrialFunction(V) w = fn.TestFunction(V) sigma = lmbda * tr(sym(grad(u))) * Identity(2) + 2 * G * sym( grad(u)) # Stress R = simp(x) * inner(sigma, grad(w)) * dx - dot(b, w) * dx a, L = ufl.lhs(R), ufl.rhs(R) u = fa.Function(V) fa.solve(a == L, u, bcs) return u
def solve_fenics(kappa0, kappa1): f = fa.Expression( "10*exp(-(pow(x[0] - 0.5, 2) + pow(x[1] - 0.5, 2)) / 0.02)", degree=2) u = fa.Function(V) bcs = [fa.DirichletBC(V, fa.Constant(0.0), "on_boundary")] inner, grad, dx = ufl.inner, ufl.grad, ufl.dx JJ = 0.5 * inner(kappa0 * grad(u), grad(u)) * dx - kappa1 * f * u * dx v = fenics.TestFunction(V) F = fenics.derivative(JJ, u, v) fa.solve(F == 0, u, bcs=bcs) return u
def J(f): u_1 = Function(V) u_1.vector()[:] = 1 a = u_1 * u * v * dx + dt * f * inner(grad(u), grad(v)) * dx L = u_1 * v * dx # Time loop t = dt while t <= T: solve(a == L, u_, bc) u_1.assign(u_) t += dt return assemble(u_1**2 * dx)
def forward(rho): """Solve the forward problem for a given fluid distribution rho(x).""" w = fenics_adjoint.Function(W) (u, p) = fenics.split(w) (v, q) = fenics.TestFunctions(W) inner, grad, dx, div = ufl.inner, ufl.grad, ufl.dx, ufl.div F = ( alpha(rho) * inner(u, v) * dx + inner(grad(u), grad(v)) * dx + inner(grad(p), v) * dx + inner(div(u), q) * dx ) bcs = [ fenics_adjoint.DirichletBC(W.sub(0).sub(1), 0, "on_boundary"), fenics_adjoint.DirichletBC(W.sub(0).sub(0), inflow_outflow_bc, "on_boundary"), ] fenics_adjoint.solve(F == 0, w, bcs=bcs) return w
def test_solver_ident_zeros(): """ Test using ident zeros to restrict half of the domain """ from fenics_adjoint import (UnitSquareMesh, Function, assemble, solve, project, Expression, DirichletBC) mesh = UnitSquareMesh(10, 10) cf = MeshFunction("size_t", mesh, mesh.topology().dim(), 0) top_half().mark(cf, 1) ff = MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0) top_boundary().mark(ff, 1) dx = Measure("dx", domain=mesh, subdomain_data=cf) V = FunctionSpace(mesh, "CG", 1) u, v = TrialFunction(V), TestFunction(V) a = inner(grad(u), grad(v)) * dx(1) w = Function(V) with stop_annotating(): w.assign(project(Expression("x[0]", degree=1), V)) rhs = w**3 * v * dx(1) A = assemble(a, keep_diagonal=True) A.ident_zeros() b = assemble(rhs) bc = DirichletBC(V, Constant(1), ff, 1) bc.apply(A, b) uh = Function(V) solve(A, uh.vector(), b, "umfpack") J = assemble(inner(uh, uh) * dx(1)) Jhat = ReducedFunctional(J, Control(w)) with stop_annotating(): w1 = project(Expression("x[0]*x[1]", degree=2), V) results = taylor_to_dict(Jhat, w, w1) assert (min(results["R0"]["Rate"]) > 0.95) assert (min(results["R1"]["Rate"]) > 1.95) assert (min(results["R2"]["Rate"]) > 2.95)
def run_model(function_space, kappa, forcing, init_condition, dt, final_time, boundary_conditions=None, second_order_timestepping=False, exact_sol=None, velocity=None, point_sources=None, intermediate_times=None): """ Use implicit euler to solve transient advection diffusion equation du/dt = grad (k* grad u) - vel*grad u + f WARNING: when point sources solution changes significantly when mesh is varied """ mesh = function_space.mesh() time_independent_boundaries = False if boundary_conditions is None: bndry_obj = dl.CompiledSubDomain("on_boundary") boundary_conditions = [['dirichlet', bndry_obj, dla.Constant(0)]] time_independent_boundaries = True num_bndrys = len(boundary_conditions) boundaries = mark_boundaries(mesh, boundary_conditions) dirichlet_bcs = collect_dirichlet_boundaries(function_space, boundary_conditions, boundaries) # To express integrals over the boundary parts using ds(i), we must first # redefine the measure ds in terms of our boundary markers: ds = dl.Measure('ds', domain=mesh, subdomain_data=boundaries) dx = dl.Measure('dx', domain=mesh) # Variational problem at each time u = dl.TrialFunction(function_space) v = dl.TestFunction(function_space) # Previous solution if hasattr(init_condition, 't'): assert init_condition.t == 0 u_1 = dla.interpolate(init_condition, function_space) if not second_order_timestepping: theta = 1 else: theta = 0.5 if hasattr(forcing, 't'): forcing_1 = copy_expression(forcing) else: forcing_1 = forcing def steady_state_form(u, v, f): F = kappa * dl.inner(dl.grad(u), dl.grad(v)) * dx F -= f * v * dx if velocity is not None: F += dl.dot(velocity, dl.grad(u)) * v * dx return F F = u*v*dx-u_1*v*dx + dt*theta*steady_state_form(u, v, forcing) + \ dt*(1.-theta)*steady_state_form(u_1, v, forcing_1) a, L = dl.lhs(F), dl.rhs(F) # a = u*v*dx + theta*dt*kappa*dl.inner(dl.grad(u), dl.grad(v))*dx # L = (u_1 + dt*theta*forcing)*v*dx # if velocity is not None: # a += theta*dt*v*dl.dot(velocity,dl.grad(u))*dx # if second_order_timestepping: # L -= (1-theta)*dt*dl.inner(kappa*dl.grad(u_1), dl.grad(v))*dx # L += (1-theta)*dt*forcing_1*v*dx # if velocity is not None: # L -= (1-theta)*dt*(v*dl.dot(velocity,dl.grad(u_1)))*dx beta_1_list = [] alpha_1_list = [] for ii in range(num_bndrys): if (boundary_conditions[ii][0] == 'robin'): alpha = boundary_conditions[ii][3] a += theta * dt * alpha * u * v * ds(ii) if second_order_timestepping: if hasattr(alpha, 't'): alpha_1 = copy_expression(alpha) alpha_1_list.append(alpha_1) else: alpha_1 = alpha L -= (1 - theta) * dt * alpha_1 * u_1 * v * ds(ii) if ((boundary_conditions[ii][0] == 'robin') or (boundary_conditions[ii][0] == 'neumann')): beta = boundary_conditions[ii][2] L -= theta * dt * beta * v * ds(ii) if second_order_timestepping: if hasattr(beta, 't'): beta_1 = copy_expression(beta) beta_1_list.append(beta_1) else: # boundary condition is constant in time beta_1 = beta L -= (1 - theta) * dt * beta_1 * v * ds(ii) if time_independent_boundaries: # TODO this can be used if dirichlet and robin conditions are not # time dependent. A = dla.assemble(a) for bc in dirichlet_bcs: bc.apply(A) solver = dla.LUSolver(A) #solver.parameters["reuse_factorization"] = True else: solver = None u_2 = dla.Function(function_space) u_2.assign(u_1) t = 0.0 dt_tol = 1e-12 n_time_steps = 0 if intermediate_times is not None: intermediate_u = [] intermediate_cnt = 0 # assert in chronological order assert np.allclose(intermediate_times, np.array(intermediate_times)) assert np.all(intermediate_times < final_time) while t < final_time - dt_tol: # Update current time prev_t = t forcing_1.t = prev_t t += dt t = min(t, final_time) forcing.t = t # set current time for time varying boundary conditions for ii in range(num_bndrys): if hasattr(boundary_conditions[ii][2], 't'): boundary_conditions[ii][2].t = t # set previous time for time varying boundary conditions when # using second order timestepping. lists will be empty if using # first order timestepping for jj in range(len(beta_1_list)): beta_1_list[jj].t = prev_t for jj in range(len(alpha_1_list)): alpha_1_list[jj].t = prev_t #A, b = dl.assemble_system(a, L, dirichlet_bcs) # for bc in dirichlet_bcs: # bc.apply(A,b) if boundary_conditions is not None: A = dla.assemble(a) for bc in dirichlet_bcs: bc.apply(A) b = dla.assemble(L) for bc in dirichlet_bcs: bc.apply(b) if point_sources is not None: ps_list = [] for ii in range(len(point_sources)): point, expr = point_sources[ii] ps_list.append((dl.Point(point[0], point[1]), expr(t))) ps = dla.PointSource(function_space, ps_list) ps.apply(b) if solver is None: dla.solve(A, u_2.vector(), b) else: solver.solve(u_2.vector(), b) # tape = dla.get_working_tape() # tape.visualise() #print ("t =", t, "end t=", final_time) # Update previous solution u_1.assign(u_2) # import matplotlib.pyplot as plt # plt.subplot(131) # pp=dl.plot(u_1) # plt.subplot(132) # dl.plot(forcing,mesh=mesh) # plt.subplot(133) # dl.plot(forcing_1,mesh=mesh) # plt.colorbar(pp) # plt.show() # compute error if exact_sol is not None: exact_sol.t = t error = dl.errornorm(exact_sol, u_2) print('t = %.2f: error = %.3g' % (t, error)) # dl.plot(exact_sol,mesh=mesh) # plt.show() if (intermediate_times is not None and intermediate_cnt < intermediate_times.shape[0] and t >= intermediate_times[intermediate_cnt]): # save solution closest to intermediate time u_t = dla.Function(function_space) u_t.assign(u_2) intermediate_u.append(u_t) intermediate_cnt += 1 n_time_steps += 1 # print ("t =", t, "end t=", final_time,"# time steps", n_time_steps) if intermediate_times is None: return u_2 else: return intermediate_u + [u_2]
def J(f): a = f * inner(grad(u), grad(v)) * dx + u**2 * v * dx - f * v * dx L = 0 solve(a == L, u, bc) return assemble(u**2 * dx)
def J(c): a = inner(grad(u), grad(v)) * dx L = c * v * dx solve(a == L, u_, bc) return assemble(u_**2 * dx)
def constrained_newton_energy_solve(F, uh, dirichlet_bcs=None, bc0=None, linear_solver=None, opts=dict(), C=None, constraint_vec=None): """ See https://uvilla.github.io/inverse15/UnconstrainedMinimization.html F: dl.Expression The energy functional. uh : dl.Function Final solution. The initial state on entry to the function will be used as initial guess and then overwritten dirichlet_bcs : list The Dirichlet boundary conditions on the unknown u. bc0 : list The Dirichlet boundary conditions for the step (du) in the Newton iterations. """ max_iter = opts.get("max_iter", 20) # exit when sqrt(g,g)/sqrt(g_0,g_0) <= rel_tolerance" rtol = opts.get("rel_tolerance", 1e-8) # exit when sqrt(g,g) <= abs_tolerance atol = opts.get("abs_tolerance", 1e-9) # exit when (g,du) <= gdu_tolerance gdu_tol = opts.get("gdu_tolerance", 1e-14) # define armijo sufficient decrease c_armijo = opts.get("c_armijo", 1e-4) # exit if max backtracking steps reached max_backtrack = opts.get("max_backtracking_iter", 20) # define verbosity prt_level = opts.get("print_level", 0) termination_reasons = [ "Maximum number of Iteration reached", #0 "Norm of the gradient less than tolerance", #1 "Maximum number of backtracking reached", #2 "Norm of (g, du) less than tolerance" #3 ] it = 0 total_cg_iter = 0 converged = False reason = 0 L = F if C is not None: L += C if prt_level > 0: print("Solving Constrained Nonlinear Problem") else: if prt_level > 0: print("Solving Unconstrained Nonlinear Problem") # Compute gradient and hessian grad = dla.derivative(L, uh) H = dla.derivative(grad, uh) # Applying boundary conditions if dirichlet_bcs is not None: if type(dirichlet_bcs) is dla.DirichletBC: bcsl = [dirichlet_bcs] else: bcsl = dirichlet_bcs [bc.apply(uh.vector()) for bc in bcsl] if constraint_vec is not None: assert C is not None dcd_state = dla.assemble(dla.derivative(C, u)) dcd_lagrangeMult = dcd_state * constraint_vec if not dcd_lagrangeMult.norm("l2") < 1.e-14: msg = "The initial guess does not satisfy the constraint." raise ValueError(msg) # Setting variables Fn = dla.assemble(F) gn = dla.assemble(grad) g0_norm = gn.norm("l2") gn_norm = g0_norm tol = max(g0_norm * rtol, atol) du = dla.Function(uh.function_space()).vector() #if linear_solver =='PETScLU': # linear_solver = dl.PETScLUSolver(uh.function_space().mesh().mpi_comm()) #else: # assert linear_solver is None if prt_level > 0: print("{0:>3} {1:>6} {2:>15} {3:>15} {4:>15} {5:>15}".format( "Nit", "CGit", "Energy", "||g||", "(g,du)", "alpha")) print("{0:3d} {1:6d} {2:15e} {3:15e} {4:15} {5:15}".format( 0, 0, Fn, g0_norm, " NA ", " NA")) converged = False reason = 0 for it in range(max_iter): if bc0 is not None: [Hn, gn] = dla.assemble_system(H, grad, bc0) else: Hn = dla.assemble(H) gn = dla.assemble(grad) Hn.init_vector(du, 1) if linear_solver is None: lin_it = dla.solve(Hn, du, -gn, "cg", "petsc_amg") else: print('a') lin_it = dla.solve(Hn, du, -gn, "lu") #linear_solver.set_operator(Hn) #lin_it = linear_solver.solve(du, -gn) total_cg_iter += lin_it du_gn = du.inner(gn) alpha = 1.0 if (np.abs(du_gn) < gdu_tol): converged = True reason = 3 uh.vector().axpy(alpha, du) Fn = dla.assemble(F) gn_norm = gn.norm("l2") break uh_backtrack = uh.copy(deepcopy=True) bk_converged = False #Backtrack for j in range(max_backtrack): uh.assign(uh_backtrack) uh.vector().axpy(alpha, du) Fnext = dla.assemble(F) #print(Fnext,Fn + alpha*c_armijo*du_gn) if Fnext < Fn + alpha * c_armijo * du_gn: Fn = Fnext bk_converged = True break alpha /= 2. if not bk_converged: reason = 2 break gn_norm = gn.norm("l2") if prt_level > 0: print("{0:3d} {1:6d} {2:15e} {3:15e} {4:15e} {5:15e}".format( it + 1, lin_it, Fn, gn_norm, du_gn, alpha)) if gn_norm < tol: converged = True reason = 1 break if prt_level > 0: if reason is 3: print("{0:3d} {1:6d} {2:15e} {3:15e} {4:15e} {5:15e}".format( it + 1, lin_it, Fn, gn_norm, du_gn, alpha)) print(termination_reasons[reason]) if converged: print("Newton converged in ", it, \ "nonlinear iterations and ", total_cg_iter, "linear iterations." ) else: print("Newton did NOT converge in ", it, "iterations.") print("Final norm of the gradient: ", gn_norm) print("Value of the cost functional: ", Fn) if reason in [0, 2]: raise Exception(termination_reasons[reason]) return uh
def unconstrained_newton_solve(F, J, uh, dirichlet_bcs=None, bc0=None, linear_solver=None, opts=dict()): """ F: dl.Expression The variational form. uh : dl.Function Final solution. The initial state on entry to the function will be used as initial guess and then overwritten dirichlet_bcs : list The Dirichlet boundary conditions on the unknown u. bc0 : list The Dirichlet boundary conditions for the step (du) in the Newton iterations. """ max_iter = opts.get("max_iter", 50) # exit when sqrt(g,g)/sqrt(g_0,g_0) <= rel_tolerance" rtol = opts.get("rel_tolerance", 1e-8) # exit when sqrt(g,g) <= abs_tolerance atol = opts.get("abs_tolerance", 1e-9) # exit when (g,du) <= gdu_tolerance gdu_tol = opts.get("gdu_tolerance", 1e-14) # define armijo sufficient decrease c_armijo = opts.get("c_armijo", 1e-4) # exit if max backtracking steps reached max_backtrack = opts.get("max_backtracking_iter", 20) # define verbosity prt_level = opts.get("print_level", 0) termination_reasons = [ "Maximum number of Iteration reached", #0 "Norm of the gradient less than tolerance", #1 "Maximum number of backtracking reached", #2 "Norm of (g, du) less than tolerance", #3 "Norm of residual less than tolerance" ] #4 it = 0 total_cg_iter = 0 converged = False reason = 0 if prt_level > 0: print("Solving Nonlinear Problem") # Applying boundary conditions if dirichlet_bcs is not None: if type(dirichlet_bcs) is dla.DirichletBC: bcsl = [dirichlet_bcs] else: bcsl = dirichlet_bcs [bc.apply(uh.vector()) for bc in bcsl] if type(bc0) is dla.DirichletBC: bc0 = [bc0] # Setting variables gn = dla.assemble(F) res_func = dla.Function(uh.function_space()) res_func.assign(dla.Function(uh.function_space(), gn)) res = res_func.vector() if bc0 is not None: for bc in bc0: bc.apply(res) Fn = res.norm("l2") g0_norm = gn.norm("l2") gn_norm = g0_norm tol = max(g0_norm * rtol, atol) res_tol = max(Fn * rtol, atol) du = dla.Function(uh.function_space()).vector() if linear_solver == 'PETScLU': linear_solver = dla.PETScLUSolver( uh.function_space().mesh().mpi_comm()) else: assert linear_solver is None if prt_level > 0: print("{0:>3} {1:>6} {2:>15} {3:>15} {4:>15} {5:>15} {6:>6}".format( "Nit", "CGit", "||r||", "||g||", "(g,du)", "alpha", "Nbt")) print("{0:3d} {1:6d} {2:15e} {3:15e} {4:15} {5:10} {6:s}". format(0, 0, Fn, g0_norm, " NA ", " NA", "NA")) converged = False reason = 0 nbt = 0 for it in range(max_iter): if bc0 is not None: [Hn, gn] = dla.assemble_system(J, F, bc0) else: Hn = dla.assemble(J) gn = dla.assemble(F) Hn.init_vector(du, 1) if linear_solver is None: lin_it = dla.solve(Hn, du, -gn, "cg", "petsc_amg") else: linear_solver.set_operator(Hn) lin_it = linear_solver.solve(du, -gn) total_cg_iter += lin_it du_gn = du.inner(gn) alpha = 1.0 if (np.abs(du_gn) < gdu_tol): converged = True reason = 3 uh.vector().axpy(alpha, du) gn_norm = gn.norm("l2") Fn = gn_norm break uh_backtrack = uh.copy(deepcopy=True) bk_converged = False #Backtrack for nbt in range(max_backtrack): uh.assign(uh_backtrack) uh.vector().axpy(alpha, du) res = dla.assemble(F) if bc0 is not None: for bc in bc0: bc.apply(res) Fnext = res.norm("l2") #print(Fn,Fnext,Fn + alpha*c_armijo*du_gn) if Fnext < Fn + alpha * c_armijo * du_gn: #if True: Fn = Fnext bk_converged = True break alpha /= 2. if not bk_converged: reason = 2 break gn_norm = gn.norm("l2") if prt_level > 0: print("{0:3d} {1:6d} {2:15e} {3:15e} {4:15e} {5:15e} {6:3d}". format(it + 1, lin_it, Fn, gn_norm, du_gn, alpha, nbt + 1)) if gn_norm < tol: converged = True reason = 1 break if Fn < res_tol: converged = True reason = 4 break if prt_level > 0: if reason is 3: print("{0:3d} {1:6d} {2:15e} {3:15e} {4:15e} {5:15e} {6:3d}". format(it + 1, lin_it, Fn, gn_norm, du_gn, alpha, nbt + 1)) print(termination_reasons[reason]) if converged: print("Newton converged in ", it, \ "nonlinear iterations and ", total_cg_iter, "linear iterations." ) else: print("Newton did NOT converge in ", it, "iterations.") print("Final norm of the gradient: ", gn_norm) print("Value of the cost functional: ", Fn) if reason in [0, 2]: raise Exception(termination_reasons[reason]) return uh
def run_model(function_space, time_step, final_time, forcing, boundary_conditions, init_condition, nonlinear_diffusion, second_order_timestepping=False, nlsparam=dict(), positivity_tol=0): if boundary_conditions is None: bndry_obj = dl.CompiledSubDomain("on_boundary") boundary_conditions = [['dirichlet', bndry_obj, dla.Constant(0)]] dt = time_step mesh = function_space.mesh() num_bndrys = len(boundary_conditions) assert num_bndrys > 0 # specify None for no boundaries if (len(boundary_conditions) == 1 and isinstance(boundary_conditions[0][2], dla.DirichletBC)): ds = dl.Measure('ds', domain=mesh) dirichlet_bcs = [boundary_conditions[0][2]] else: boundaries = mark_boundaries(mesh, boundary_conditions) dirichlet_bcs = collect_dirichlet_boundaries( function_space, boundary_conditions, boundaries) ds = dl.Measure('ds', domain=mesh, subdomain_data=boundaries) dx = dl.Measure('dx', domain=mesh) u = dl.TrialFunction(function_space) v = dl.TestFunction(function_space) # Previous solution u_1 = dla.interpolate(init_condition, function_space) u_2 = dla.Function(function_space) u_2.assign(u_1) if not second_order_timestepping: theta = 1 else: theta = 0.5 if second_order_timestepping and hasattr(forcing, 't'): forcing_1 = copy_expression(forcing) else: forcing_1 = forcing kappa = nonlinear_diffusion(u) a = u*v*dx + theta*dt*kappa*dl.inner(dl.grad(u), dl.grad(v))*dx L = (u_1 + theta*dt*forcing)*v*dx # subtract of positivity preserving part added to diffusion if positivity_tol > 0: a -= positivity_tol*dl.inner(dl.grad(u), dl.grad(v))*dx if second_order_timestepping: kappa_1 = nonlinear_diffusion(u_1) L -= (1-theta)*dt*kappa_1*dl.inner(dl.grad(u_1), dl.grad(v))*dx L += (1-theta)*dt*forcing_1*v*dx beta_1_list = [] alpha_1_list = [] for ii in range(num_bndrys): if (boundary_conditions[ii][0] == 'robin'): alpha = boundary_conditions[ii][3] a += theta*dt*alpha*u*v*ds(ii) if second_order_timestepping: if hasattr(alpha, 't'): alpha_1 = copy_expression(alpha) alpha_1_list.append(alpha_1) else: alpha_1 = alpha L -= (1-theta)*dt*alpha_1*u_1*v*ds(ii) if ((boundary_conditions[ii][0] == 'robin') or (boundary_conditions[ii][0] == 'neumann')): beta = boundary_conditions[ii][2] print(type(theta), type(dt), type(beta), type(v)) L -= theta*dt*beta*v*ds(ii) if second_order_timestepping: if hasattr(beta, 't'): beta_1 = copy_expression(beta) beta_1_list.append(beta_1) else: # boundary condition is constant in time beta_1 = beta L -= (1-theta)*dt*beta_1*v*ds(ii) if hasattr(init_condition, 't'): t = init_condition.t else: t = 0.0 while t < final_time: # print('TIME',t) # Update current time prev_t = t forcing_1.t = prev_t t += dt t = min(t, final_time) forcing.t = t # set current time for time varying boundary conditions for ii in range(num_bndrys): if hasattr(boundary_conditions[ii][2], 't'): boundary_conditions[ii][2].t = t # set previous time for time varying boundary conditions when # using second order timestepping. lists will be empty if using # first order timestepping for jj in range(len(beta_1_list)): beta_1_list[jj].t = prev_t for jj in range(len(alpha_1_list)): alpha_1_list[jj].t = prev_t # solver must be redefined at every timestep F = a-L F = dl.action(F, u_2) J = dl.derivative(F, u_2, u) dla.solve(F == 0, u_2, dirichlet_bcs, J=J, solver_parameters=nlsparam) # import matplotlib.pyplot as plt # pl = dl.plot(sol); plt.colorbar(pl); plt.show() # import matplotlib.pyplot as plt # pl = dl.plot(sol); plt.show() # Update previous solution u_1.assign(u_2) return u_1