def compute_errors(u_e, u): """Compute various measures of the error u - u_e, where u is a finite element Function and u_e is an Expression. Adapted from https://fenicsproject.org/pub/tutorial/html/._ftut1020.html """ print('u_e', u_e.ufl_element().degree()) # Get function space V = u.function_space() # Explicit computation of L2 norm error = (u - u_e)**2 * dl.dx E1 = np.sqrt(abs(dla.assemble(error))) # Explicit interpolation of u_e onto the same space as u u_e_ = dla.interpolate(u_e, V) error = (u - u_e_)**2 * dl.dx E2 = np.sqrt(abs(dla.assemble(error))) # Explicit interpolation of u_e to higher-order elements. # u will also be interpolated to the space Ve before integration Ve = dl.FunctionSpace(V.mesh(), 'P', 5) u_e_ = dla.interpolate(u_e, Ve) error = (u - u_e)**2 * dl.dx E3 = np.sqrt(abs(dla.assemble(error))) # Infinity norm based on nodal values u_e_ = dla.interpolate(u_e, V) E4 = abs(u_e_.vector().get_local() - u.vector().get_local()).max() # L2 norm E5 = dl.errornorm(u_e, u, norm_type='L2', degree_rise=3) # H1 seminorm E6 = dl.errornorm(u_e, u, norm_type='H10', degree_rise=3) # Collect error measures in a dictionary with self-explanatory keys errors = { 'u - u_e': E1, 'u - interpolate(u_e, V)': E2, 'interpolate(u, Ve) - interpolate(u_e, Ve)': E3, 'infinity norm (of dofs)': E4, 'L2 norm': E5, 'H10 seminorm': E6 } return errors
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 test_fenics_forward(): numpy_output, _, _, _, = evaluate_primal(assemble_fenics, templates, *inputs) u1 = fa.interpolate(fa.Constant(1.0), V) J = assemble_fenics(u1, fa.Constant(0.5), fa.Constant(0.6)) assert np.isclose(numpy_output, J)
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