def test02_1d_dirichlet_higher_order(self): mesh = Mesh1D() for etype in ['Q2', 'Q3']: element = QuadFE(1, etype) dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() # Basis functions ux = Basis(dofhandler, 'ux') u = Basis(dofhandler, 'u') # Exact solution ue = Nodal(f=lambda x: x * (1 - x), basis=u) # Define coefficient functions one = Constant(1) two = Constant(2) # Define forms a = Form(kernel=Kernel(one), trial=ux, test=ux) L = Form(kernel=Kernel(two), test=u) problem = [a, L] # Assemble problem assembler = Assembler(problem, mesh) assembler.assemble() A = assembler.get_matrix() b = assembler.get_vector() # Set up linear system system = LinearSystem(u, A=A, b=b) # Boundary functions bnd_left = lambda x: np.abs(x) < 1e-9 bnd_right = lambda x: np.abs(1 - x) < 1e-9 # Mark mesh mesh.mark_region('left', bnd_left, entity_type='vertex') mesh.mark_region('right', bnd_right, entity_type='vertex') # Add Dirichlet constraints to system system.add_dirichlet_constraint('left', 0) system.add_dirichlet_constraint('right', 0) # Solve system system.solve_system() system.resolve_constraints() # Compare solution with the exact solution ua = system.get_solution(as_function=True) self.assertTrue(np.allclose(ua.data(), ue.data()))
def test_assemble_iiform(self): mesh = Mesh1D(resolution=(1, )) Q1 = QuadFE(1, 'DQ1') dofhandler = DofHandler(mesh, Q1) dofhandler.distribute_dofs() phi = Basis(dofhandler, 'u') k = Explicit(lambda x, y: x * y, n_variables=2, dim=1) kernel = Kernel(k) form = IIForm(kernel, test=phi, trial=phi) assembler = Assembler(form, mesh) assembler.assemble() Ku = Nodal(lambda x: 1 / 3 * x, basis=phi) #af = assembler.af[0]['bilinear'] M = assembler.get_matrix().toarray() u = Nodal(lambda x: x, basis=phi) u_vec = u.data() self.assertTrue(np.allclose(M.dot(u_vec), Ku.data()))
def test_assemble_ipform(self): # ===================================================================== # Test 7: Assemble Kernel # ===================================================================== mesh = Mesh1D(resolution=(10, )) Q1 = QuadFE(1, 'DQ1') dofhandler = DofHandler(mesh, Q1) dofhandler.distribute_dofs() phi = Basis(dofhandler, 'u') k = Explicit(lambda x, y: x * y, n_variables=2, dim=1) kernel = Kernel(k) form = IPForm(kernel, test=phi, trial=phi) assembler = Assembler(form, mesh) assembler.assemble() #af = assembler.af[0]['bilinear'] M = assembler.get_matrix().toarray() u = Nodal(lambda x: x, basis=phi) v = Nodal(lambda x: 1 - x, basis=phi) u_vec = u.data() v_vec = v.data() I = v_vec.T.dot(M.dot(u_vec)) self.assertAlmostEqual(I[0, 0], 1 / 18)
def sensitivity_sample_qoi(exp_q, dofhandler): """ Sample QoI by means of Taylor expansion J(q+dq) ~= J(q) + dJdq(q)dq """ # Basis phi = Basis(dofhandler, 'v') phi_x = Basis(dofhandler, 'vx') # Define problem exp_q_fn = Nodal(data=exp_q, basis=phi) primal = [Form(exp_q_fn, test=phi_x, trial=phi_x), Form(1, test=phi)] adjoint = [Form(exp_q_fn, test=phi_x, trial=phi_x), Form(0, test=phi)] qoi = [Form(exp_q_fn, test=phi_x)] problems = [primal, adjoint, qoi] # Define assembler assembler = Assembler(problems) # # Dirichlet conditions for primal problem # assembler.add_dirichlet('left', 0, i_problem=0) assembler.add_dirichlet('right', 1, i_problem=0) # Dirichlet conditions for adjoint problem assembler.add_dirichlet('left', 0, i_problem=1) assembler.add_dirichlet('right', -1, i_problem=1) # Assemble system assembler.assemble() # Compute solution and qoi at q (primal) u = assembler.solve(i_problem=0) # Compute solution of the adjoint problem v = assembler.solve(i_problem=1) # Evaluate J J = u.dot(assembler.get_vector(2)) # # Assemble gradient # ux_fn = Nodal(data=u, basis=phi_x) vx_fn = Nodal(data=v, basis=phi_x) k_int = Kernel(f=[exp_q_fn, ux_fn, vx_fn], F=lambda exp_q, ux, vx: exp_q * ux * vx) problem = [Form(k_int, test=phi)] assembler = Assembler(problem) assembler.assemble() dJ = -assembler.get_vector() return dJ
def __init__(self, f, u, eps, upwind_type='classical'): """ Constructor Inputs: f: Map, explicit kernel function u: Map, velocity function eps: double >0, diffusivity upwind_scheme: str, type of upwind scheme used """ Kernel.__init__(self, f) self.__upwind_type = upwind_type self.__vel = u self.__eps = eps
def test_n_samples(self): # # 1D # # Define mesh mesh = Mesh1D(resolution=(10,)) # Define function f = Explicit([lambda x: x, lambda x: -2+2*x**2], dim=1) n_samples = f.n_samples() k = Kernel(f) n_points = 101 x0, x1 = mesh.bounding_box() x = np.linspace(x0,x1,n_points) self.assertEqual(k.eval(x).shape, (n_points, n_samples)) self.assertTrue(np.allclose(k.eval(x)[:,0],x)) self.assertTrue(np.allclose(k.eval(x)[:,1], -2+2*x**2))
def test_eval(self): # # 1D # # Define Kernel function def k_fn(x,y,c = 2): return x*y + c k = Explicit(f=lambda x,y,c: x*y+c, parameters={'c':1}, n_variables=2, dim=1) # Construct kernel, specifying parameter c kernel = Kernel(k) # Evaluation points x = np.ones((11,1)) y = np.linspace(0,1,11)[:,None] # Check accuracy self.assertTrue(np.allclose(kernel.eval((x,y)), x*y+1)) # Define kernel with default parameters k.set_parameters({'c':2}) kernel = Kernel(k) # Check accuracy self.assertTrue(np.allclose(kernel.eval((x,y)), x*y+2))
def test_edge_integrals(self): """ Test computing """ mesh = QuadMesh(resolution=(1, 1)) Q = QuadFE(2, 'Q1') dQ = DofHandler(mesh, Q) dQ.distribute_dofs() phi = Basis(dQ, 'u') f = Nodal(data=np.ones((phi.n_dofs(), 1)), basis=phi) kernel = Kernel(f) form = Form(kernel, dmu='ds') assembler = Assembler(form, mesh) cell = mesh.cells.get_leaves()[0] shape_info = assembler.shape_info(cell) xg, wg, phi, dofs = assembler.shape_eval(cell)
def test01_1d_dirichlet_linear(self): """ Solve one dimensional boundary value problem with dirichlet conditions on left and right """ # # Define mesh # mesh = Mesh1D(resolution=(10, )) for etype in ['Q1', 'Q2', 'Q3']: element = QuadFE(1, etype) dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() phi = Basis(dofhandler) # # Exact solution # ue = Nodal(f=lambda x: x, basis=phi) # # Define Basis functions # u = Basis(dofhandler, 'u') ux = Basis(dofhandler, 'ux') # # Define bilinear form # one = Constant(1) zero = Constant(0) a = Form(kernel=Kernel(one), trial=ux, test=ux) L = Form(kernel=Kernel(zero), test=u) problem = [a, L] # # Assemble # assembler = Assembler(problem, mesh) assembler.assemble() # # Form linear system # A = assembler.get_matrix() b = assembler.get_vector() system = LinearSystem(u, A=A, b=b) # # Dirichlet conditions # # Boundary functions bm_left = lambda x: np.abs(x) < 1e-9 bm_rght = lambda x: np.abs(x - 1) < 1e-9 # Mark boundary regions mesh.mark_region('left', bm_left, on_boundary=True) mesh.mark_region('right', bm_rght, on_boundary=True) # Add Dirichlet constraints system.add_dirichlet_constraint('left', ue) system.add_dirichlet_constraint('right', ue) # # Solve system # #system.solve_system() system.solve_system() # # Get solution # #ua = system.get_solution(as_function=True) uaa = system.get_solution(as_function=True) #uaa = uaa.data().ravel() # Compare with exact solution #self.assertTrue(np.allclose(ua.data(), ue.data())) self.assertTrue(np.allclose(uaa.data(), ue.data()))
def test04_1d_periodic(self): # # Dirichlet Problem on a Periodic Mesh # # Define mesh, element mesh = Mesh1D(resolution=(100, ), periodic=True) element = QuadFE(1, 'Q3') dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() # Basis functions u = Basis(dofhandler, 'u') ux = Basis(dofhandler, 'ux') # Exact solution ue = Nodal(f=lambda x: np.sin(2 * np.pi * x), basis=u) # # Mark dirichlet regions # bnd_left = lambda x: np.abs(x) < 1e-9 mesh.mark_region('left', bnd_left, entity_type='vertex') # # Set up forms # # Bilinear form a = Form(kernel=Kernel(Constant(1)), trial=ux, test=ux) # Linear form f = Explicit(lambda x: 4 * np.pi**2 * np.sin(2 * np.pi * x), dim=1) L = Form(kernel=Kernel(f), test=u) # # Assemble # problem = [a, L] assembler = Assembler(problem, mesh) assembler.assemble() A = assembler.get_matrix() b = assembler.get_vector() # # Linear System # system = LinearSystem(u, A=A, b=b) # Add dirichlet constraint system.add_dirichlet_constraint('left', 0, on_boundary=False) # Assemble constraints #system.set_constraint_relation() #system.incorporate_constraints() system.solve_system() #system.resolve_constraints() # Compare with interpolant of exact solution ua = system.get_solution(as_function=True) #plot = Plot(2) #plot.line(ua) #plot.line(ue) self.assertTrue(np.allclose(ua.data(), ue.data()))
def test_eval_projection(self): """ Test validity of the local projection-based kernel. Choose u, v in V k(x,y) in VxV (symmetric/non-symm) cell01, cell02 Compare v^T*Kloc*u ?= Icell01 Icell02 k(x,y)u(y)dy dx """ # # 1D # # Mesh mesh = Mesh1D(resolution=(3, )) # Finite element space etype = 'Q1' element = QuadFE(1, etype) # Dofhandler dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() # Basis functions phi = Basis(dofhandler, 'u') # Symmetric kernel function kfns = { 'symmetric': lambda x, y: x * y, 'non_symmetric': lambda x, y: x - y } vals = { 'symmetric': (1 / 2 * 1 / 9 - 1 / 3 * 1 / 27) * (1 / 3 - 1 / 3 * 8 / 27), 'non_symmetric': (1 / 18 - 1 / 3 * 1 / 27) * (1 / 2 - 2 / 9) + (1 / 18 - 1 / 3) * (1 / 3 - 1 / 3 * 8 / 27) } for ktype in ['symmetric', 'non_symmetric']: # Get kernel function kfn = kfns[ktype] # Define integral kernel kernel = Kernel(Explicit(kfn, dim=1, n_variables=2)) # Define Bilinear Form form = IPForm(kernel, trial=phi, test=phi) # # Compute inputs required for evaluating form_loc # # Assembler assembler = Assembler(form, mesh) # Cells ci = mesh.cells.get_child(0) cj = mesh.cells.get_child(2) # Shape function info on cells ci_sinfo = assembler.shape_info(ci) cj_sinfo = assembler.shape_info(cj) # Gauss nodes and weights on cell xi_g, wi_g, phii, dofsi = assembler.shape_eval(ci) xj_g, wj_g, phij, dofsj = assembler.shape_eval(cj) # # Evaluate form # form_loc = form.eval((ci,cj), (xi_g,xj_g), \ (wi_g,wj_g), (phii,phij), (dofsi,dofsj)) # # Define functions # u = Nodal(f=lambda x: x, basis=phi) v = Nodal(f=lambda x: 1 - x, basis=phi) # # Get local node values # # Degrees of freedom ci_dofs = phi.dofs(ci) cj_dofs = phi.dofs(cj) uj = u.data()[np.array(cj_dofs)] vi = v.data()[np.array(ci_dofs)] if ktype == 'symmetric': # Local form by hand c10 = 1 / 54 c11 = 1 / 27 c20 = 3 / 2 - 1 - 3 / 2 * 4 / 9 + 8 / 27 c21 = 4 / 27 fl = np.array([[c10 * c20, c10 * c21], [c11 * c20, c11 * c21]]) # Compare computed and explicit local forms self.assertTrue(np.allclose(fl, form_loc)) # Evaluate Ici Icj k(x,y) y dy (1-x)dx fa = np.dot(vi.T, form_loc.dot(uj)) fe = vals[ktype] self.assertAlmostEqual(fa, fe)
Q1 = QuadFE(1, 'Q1') qe = Function(qfn, 'explicit', dim=1) one = Function(1, 'constant') # # Basis functions # u = Basis(Q1, 'u') ux = Basis(Q1, 'ux') q = Basis(Q0, 'q') # # Forms # a_qe = Form(kernel=Kernel(qe), trial=ux, test=ux) a_one = Form(kernel=Kernel(one), trial=ux, test=ux) m = Form(kernel=Kernel(one), trial=u, test=u) L = Form(kernel=Kernel(one), test=u) # # Problems # problems = [[a_qe,L], [a_one], [m]] # # Assembly # assembler = Assembler(problems, mesh) assembler.assemble()
def test_eval_interpolation(self): # # 1D # # Mesh mesh = Mesh1D(resolution=(3, )) # Finite element space etype = 'Q1' element = QuadFE(1, etype) # Dofhandler dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() # Basis functions phi = Basis(dofhandler, 'u') # Symmetric kernel function kfns = { 'symmetric': lambda x, y: x * y, 'non_symmetric': lambda x, y: x - y } vals = { 'symmetric': np.array([0, 1 / 9 * (1 - 8 / 27)]), 'non_symmetric': np.array([1 / 3 * (-1 + 8 / 27), 1 / 6 * 5 / 9 - 1 / 3 * 19 / 27]) } for ktype in ['symmetric', 'non_symmetric']: # Get kernel function kfn = kfns[ktype] # Define integral kernel kernel = Kernel(Explicit(kfn, dim=1, n_variables=2)) # Define Bilinear Form form = IIForm(kernel, trial=phi, test=phi) # # Compute inputs required for evaluating form_loc # # Assembler assembler = Assembler(form, mesh) # Cells cj = mesh.cells.get_child(2) ci = mesh.cells.get_child(0) # Gauss nodes and weights on cell xj_g, wj_g, phij, dofsj = assembler.shape_eval(cj) # # Evaluate form # form_loc = form.eval(cj, xj_g, wj_g, phij, dofsj) # # Define functions # u = Nodal(lambda x: x, basis=phi) # # Get local node values # # Degrees of freedom cj_dofs = phi.dofs(cj) ci_dofs = phi.dofs(ci) uj = u.data()[np.array(cj_dofs)] # Evaluate Ici Icj k(x,y) y dy (1-x)dx fa = form_loc[ci_dofs].dot(uj) fe = vals[ktype][:, None] self.assertTrue(np.allclose(fa, fe))
# Monte Carlo Sample # ============================================================================= n_batches = 1 n_samples_per_batch = 10 n_samples = n_batches * n_samples_per_batch f_mc = [] g_mc = [] for n_batch in tqdm(range(n_batches)): # # Generate random sample # z = np.random.normal(size=(r, n_samples_per_batch)) q_smpl = Vr.dot(np.diag(np.sqrt(lr)).dot(z)) q.set_data(q_smpl) expq = Kernel(q, F=lambda f: np.exp(f)) # # Assemble system # problems = [[Form(expq, test=phi_x, trial=phi_x)], [Form(test=phi, trial=phi)]] assembler = Assembler(problems, mesh) assembler.assemble() M = assembler.af[0]['bilinear'].get_matrix()[0] for n in range(n_samples_per_batch): A = assembler.af[0]['bilinear'].get_matrix()[n] fn, gn, yn, pn = sample_cost_gradient(state, adjoint, A, M, u, y_data, gamma) f_mc.append(fn)
def test_ft(): plot = Plot() vb = Verbose() # ============================================================================= # Parameters # ============================================================================= # # Flow # # permeability field phi = Constant(1) # porosity D = Constant(0.0252) # dispersivity K = Constant(1) # permeability # ============================================================================= # Mesh and Elements # ============================================================================= # Mesh mesh = QuadMesh(resolution=(30, 30)) # Mark left and right regions mesh.mark_region('left', lambda x, y: np.abs(x) < 1e-9, entity_type='half_edge') mesh.mark_region('right', lambda x, y: np.abs(x - 1) < 1e-9, entity_type='half_edge') # Elements p_element = QuadFE(2, 'Q1') # element for pressure c_element = QuadFE(2, 'Q1') # element for concentration # Dofhandlers p_dofhandler = DofHandler(mesh, p_element) c_dofhandler = DofHandler(mesh, c_element) p_dofhandler.distribute_dofs() c_dofhandler.distribute_dofs() # Basis functions p_ux = Basis(p_dofhandler, 'ux') p_uy = Basis(p_dofhandler, 'uy') p_u = Basis(p_dofhandler, 'u') p_inflow = lambda x, y: np.ones(shape=x.shape) p_outflow = lambda x, y: np.zeros(shape=x.shape) c_inflow = lambda x, y: np.zeros(shape=x.shape) # ============================================================================= # Solve the steady state flow equations # ============================================================================= vb.comment('Solving flow equations') # Define problem flow_problem = [ Form(1, test=p_ux, trial=p_ux), Form(1, test=p_uy, trial=p_uy), Form(0, test=p_u) ] # Assemble vb.tic('assembly') assembler = Assembler(flow_problem) assembler.add_dirichlet('left', 1) assembler.add_dirichlet('right', 0) assembler.assemble() vb.toc() # Solve linear system vb.tic('solve') A = assembler.get_matrix().tocsr() b = assembler.get_vector() x0 = assembler.assembled_bnd() # Interior nodes pa = np.zeros((p_u.n_dofs(), 1)) int_dofs = assembler.get_dofs('interior') pa[int_dofs, 0] = spla.spsolve(A, b - x0) # Resolve Dirichlet conditions dir_dofs, dir_vals = assembler.get_dirichlet(asdict=False) pa[dir_dofs] = dir_vals vb.toc() # Pressure function pfn = Nodal(data=pa, basis=p_u) px = pfn.differentiate((1, 0)) py = pfn.differentiate((1, 1)) #plot.contour(px) #plt.show() # ============================================================================= # Transport Equations # ============================================================================= # Specify initial condition c0 = Constant(1) dt = 1e-1 T = 6 N = int(np.ceil(T / dt)) c = Basis(c_dofhandler, 'c') cx = Basis(c_dofhandler, 'cx') cy = Basis(c_dofhandler, 'cy') print('assembling transport equations') k_phi = Kernel(f=phi) k_advx = Kernel(f=[K, px], F=lambda K, px: -K * px) k_advy = Kernel(f=[K, py], F=lambda K, py: -K * py) tht = 1 m = [Form(kernel=k_phi, test=c, trial=c)] s = [ Form(kernel=k_advx, test=c, trial=cx), Form(kernel=k_advy, test=c, trial=cy), Form(kernel=Kernel(D), test=cx, trial=cx), Form(kernel=Kernel(D), test=cy, trial=cy) ] problems = [m, s] assembler = Assembler(problems) assembler.add_dirichlet('left', 0, i_problem=0) assembler.add_dirichlet('left', 0, i_problem=1) assembler.assemble() x0 = assembler.assembled_bnd() # Interior nodes int_dofs = assembler.get_dofs('interior') # Dirichlet conditions dir_dofs, dir_vals = assembler.get_dirichlet(asdict=False) # System matrices M = assembler.get_matrix(i_problem=0) S = assembler.get_matrix(i_problem=1) # Initialize c0 and cp c0 = np.ones((c.n_dofs(), 1)) cp = np.zeros((c.n_dofs(), 1)) c_fn = Nodal(data=c0, basis=c) # # Compute solution # print('time stepping') for i in range(N): # Build system A = M + tht * dt * S b = M.dot(c0[int_dofs]) - (1 - tht) * dt * S.dot(c0[int_dofs]) # Solve linear system cp[int_dofs, 0] = spla.spsolve(A, b) # Add Dirichlet conditions cp[dir_dofs] = dir_vals # Record current iterate c_fn.add_samples(data=cp) # Update c0 c0 = cp.copy() #plot.contour(c_fn, n_sample=i) # # Quantity of interest # def F(c, px, py, entity=None): """ Compute c(x,y,t)*(grad p * n) """ n = entity.unit_normal() return c * (px * n[0] + py * n[1]) px.set_subsample(i=np.arange(41)) py.set_subsample(i=np.arange(41)) #kernel = Kernel(f=[c_fn,px,py], F=F) kernel = Kernel(c_fn) #print(kernel.n_subsample()) form = Form(kernel, flag='right', dmu='ds') assembler = Assembler(form, mesh=mesh) assembler.assemble() QQ = assembler.assembled_forms()[0].aggregate_data()['array'] Q = np.array([assembler.get_scalar(i_sample=i) for i in np.arange(N + 1)]) t = np.linspace(0, T, N + 1) plt.plot(t, Q) plt.show() print(Q)
def test09_1d_inverse(self): """ Compute the inverse of a matrix and apply it to a vector/matrix. """ # # Mesh # mesh = Mesh1D(resolution=(1, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-9, on_boundary=True) mesh.mark_region('right', lambda x: np.abs(1 - x) < 1e-9, on_boundary=True) # # Elements # Q3 = QuadFE(1, 'Q3') dofhandler = DofHandler(mesh, Q3) dofhandler.distribute_dofs() # # Basis # u = Basis(dofhandler, 'u') ux = Basis(dofhandler, 'ux') # # Define sampled right hand side and exact solution # xv = dofhandler.get_dof_vertices() n_points = dofhandler.n_dofs() n_samples = 6 a = np.arange(n_samples) ffn = lambda x, a: a * x ufn = lambda x, a: a / 6 * (x - x**3) + x fdata = np.zeros((n_points, n_samples)) udata = np.zeros((n_points, n_samples)) for i in range(n_samples): fdata[:, i] = ffn(xv, a[i]).ravel() udata[:, i] = ufn(xv, a[i]).ravel() # Define sampled function fn = Nodal(data=fdata, basis=u) ue = Nodal(data=udata, basis=u) # # Forms # one = Constant(1) a = Form(Kernel(one), test=ux, trial=ux) L = Form(Kernel(fn), test=u) problem = [[a], [L]] # # Assembler # assembler = Assembler(problem, mesh) assembler.assemble() A = assembler.get_matrix() b = assembler.get_vector(i_problem=1) # # Linear System # system = LinearSystem(u, A=A) # Set constraints system.add_dirichlet_constraint('left', 0) system.add_dirichlet_constraint('right', 1) system.solve_system(b) # Extract finite element solution ua = system.get_solution(as_function=True) system2 = LinearSystem(u, A=A, b=b) # Set constraints system2.add_dirichlet_constraint('left', 0) system2.add_dirichlet_constraint('right', 1) system2.solve_system() u2 = system2.get_solution(as_function=True) # Check that the solution is close self.assertTrue(np.allclose(ue.data()[:, 0], ua.data()[:, 0])) self.assertTrue(np.allclose(ue.data()[:, [0]], u2.data()))
def plot_heuristics(f, tht, basis, region, condition): """ Parameters ---------- f : lambda, Function of θ to be integrated. n : int, Sample size for Monte Carlo sample """ tht.update_support() # # Plot samples of the random field # n = 10000 tht_sample = tht.sample(n) tht_fn = Nodal(data=tht_sample, basis=basis) # # Compute the quantity of interest # # Define the kernel kf = Kernel(tht_fn, F=f) # Assemble over the mesh problems = [[Form(kernel=kf, flag=region)], [Form(flag=region)]] assembler = Assembler(problems, basis.mesh()) assembler.assemble() # Extract sample dx = assembler.get_scalar(i_problem=1) q_sample = assembler.get_scalar(i_sample=None) / dx # # Compute correlation coefficients of q with spatial data # plot = Plot(quickview=False) fig, ax = plt.subplots() plt_args = {'linewidth': 0.5, 'color': 'k'} ax = plot.line(tht_fn, axis=ax, i_sample=list(range(100)), plot_kwargs=plt_args) fig.savefig('ex01_sample_paths.eps') fig, ax = plt.subplots() ftht = Nodal(data=f(tht_sample), basis=basis) ax = plot.line(ftht, axis=ax, i_sample=list(range(100)), plot_kwargs=plt_args) fig.savefig('ex01_integrand.eps') fig, ax = plt.subplots(1, 1) plt.hist(q_sample, bins=50, density=True) ax.set_title(r'Histogram $Q(\theta)$') fig.savefig('ex01_histogram.eps') plt.close('all') dh = basis.dofhandler() n_dofs = dh.n_dofs() # Extract the region on which we condition cnd_dofs = dh.get_region_dofs(entity_flag=condition) I = np.eye(n_dofs) I = I[cnd_dofs, :] # Measured tht tht_msr = tht_sample[cnd_dofs, 0][:, None] n_cnd = 30 cnd_tht = tht.condition(I, tht_msr, n_samples=n_cnd) #cnd_tht_data = np.array([tht_sample[:,0] for dummy in range(n_cnd)]) #cnd_tht_data[cnd_dofs,:] = cnd_tht cnd_tht_fn = Nodal(data=f(cnd_tht), basis=basis) fig, ax = plt.subplots() ax = plot.line(cnd_tht_fn, axis=ax, i_sample=np.arange(n_cnd), plot_kwargs=plt_args) fig.tight_layout() plt.show()
def dJdq_sen(q, u, dq): """ Compute the directional derivative dJ(q,dq) by means of the sensitivity equation. -(exp(q)*s')' = (exp(q)*dq*u')' s(0) = s(1) = 0 and computing dJ(q,dq) = -exp(q(1))*dq(1)*u'(1) - exp(q(1))*s'(1) """ # # Finite Element Specification # # Reference state u_dh = u.basis().dofhandler() mesh = u_dh.mesh phi = Basis(u_dh, 'u') phi_x = Basis(u_dh, 'ux') ux_fn = Nodal(data=u.data(), basis=phi_x) # Reference diffusivitity q_dh = q.basis().dofhandler() psi = q.basis() exp_q = Nodal(data=np.exp(q.data()), basis=phi) # Define sensitivity equation ker_sen = Kernel(f=[exp_q, dq, ux_fn], F=lambda eq, dq, ux: -eq * dq * ux) sensitivity_eqn = [ Form(exp_q, test=phi_x, trial=phi_x), Form(ker_sen, test=phi_x) ] # Assembler assembler = Assembler(sensitivity_eqn, u_dh.mesh, n_gauss=(6, 36)) # Apply Dirichlet Boundary conditions assembler.add_dirichlet('left', 0) assembler.add_dirichlet('right', 0) # Assemble system assembler.assemble() # Solve for sensitivity s_fn = Nodal(basis=phi) for i in range(dq.n_samples()): # Solve for ith sensitivity s = assembler.solve(i_vector=i) s_fn.add_samples(s) # Derivative of sensitivity sx_fn = Nodal(data=s_fn.data(), basis=phi_x) # Sensitivity k_sens = Kernel(f=[exp_q, dq, ux_fn, sx_fn], F=lambda eq, dq, ux, sx: -eq * dq * ux - eq * sx) sens_qoi = Form(k_sens, dmu='dv', flag='right') # Assemble assembler = Assembler(sens_qoi, mesh=mesh) assembler.assemble() # Differential dJ = np.array([assembler.get_scalar(i_sample=i) \ for i in range(dq.n_samples())]) return dJ
gamma = 0.1 # # Random diffusion coefficient # n_samples = 200 cov = Covariance(dh_y, name='gaussian', parameters={'l':0.1}) k = GaussianField(ny, K=cov) k.update_support() kfn = Nodal(dofhandler=dh_y, data=k.sample(n_samples=n_samples)) # ============================================================================= # Assembly # ============================================================================= K = Kernel(kfn, F=lambda f:np.exp(f)) # diffusivity problems = [[Form(K, test=phi_x, trial=phi_x)], [Form(test=phi, trial=phi)]] assembler = Assembler(problems, mesh) assembler.assemble() # Mass matrix (for control) M = assembler.af[1]['bilinear'].get_matrix() # ============================================================================= # Define State and Adjoint Systems # ============================================================================= state = LS(phi)
def test02_sensitivity(): """ Check that the sensitivity calculation works. Compare J(q+eps*dq) - J(q) ~= eps*dJ^T dq """ # # Mesh # mesh = Mesh1D(resolution=(20, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-10) mesh.mark_region('right', lambda x: np.abs(x - 1) < 1e-10) # # Element # Q = QuadFE(mesh.dim(), 'Q3') dQ = DofHandler(mesh, Q) dQ.distribute_dofs() nx = dQ.n_dofs() x = dQ.get_dof_vertices() # # Basis # phi = Basis(dQ, 'v') phi_x = Basis(dQ, 'vx') # # Parameters # # Reference q q_ref = np.zeros(nx) # Perturbation dq = np.ones(nx) # Perturbed q n_eps = 10 # Number of refinements epsilons = [10**(-l) for l in range(n_eps)] q_per = np.empty((nx, n_eps)) for i in range(n_eps): q_per[:, i] = q_ref + epsilons[i] * dq # Define finite element function exp_qref = Nodal(data=np.exp(q_ref), basis=phi) exp_qper = Nodal(data=np.exp(q_per), basis=phi) # # PDEs # # 1. State Equation state_eqn = [Form(exp_qref, test=phi_x, trial=phi_x), Form(1, test=phi)] state_dbc = {'left': 0, 'right': 1} # 2. Perturbed Equation perturbed_eqn = [ Form(exp_qper, test=phi_x, trial=phi_x), Form(1, test=phi) ] perturbed_dbc = {'left': 0, 'right': 1} # 3. Adjoint Equation adjoint_eqn = [Form(exp_qref, test=phi_x, trial=phi_x), Form(0, test=phi)] adjoint_dbc = {'left': 0, 'right': -1} # Combine eqns = [state_eqn, perturbed_eqn, adjoint_eqn] bcs = [state_dbc, perturbed_dbc, adjoint_dbc] # # Assembly # assembler = Assembler(eqns) # Boundary conditions for i, bc in zip(range(3), bcs): for loc, val in bc.items(): assembler.add_dirichlet(loc, val, i_problem=i) # Assemble assembler.assemble() # # Solve # # Solve state ur = assembler.solve(i_problem=0) u_ref = Nodal(data=ur, basis=phi) ux_ref = Nodal(data=ur, basis=phi_x) # Solve perturbed state u_per = Nodal(basis=phi) ue_per = Nodal(basis=phi) for i in range(n_eps): # FEM solution up = assembler.solve(i_problem=1, i_matrix=i) u_per.add_samples(up) # Exact perturbed solution eps = epsilons[i] ue_per.add_samples(0.5 * np.exp(-eps) * (x - x**2) + x) ux_per = Nodal(data=u_per.data(), basis=phi_x) # Solve adjoint equation v = assembler.solve(i_problem=2) v_adj = Nodal(data=v, basis=phi) vx_adj = Nodal(data=v, basis=phi_x) # # Check against exact solution # ue = -0.5 * x**2 + 1.5 * x ve = -x assert np.allclose(ue, u_ref.data()) assert np.allclose(ve, v_adj.data()) assert np.allclose(ue_per.data(), u_per.data()) # # Quantities of Interest # # Reference k_ref = Kernel(f=[exp_qref, ux_ref], F=lambda eq, ux: eq * ux) ref_qoi = [Form(k_ref, dmu='dv', flag='right')] # Perturbed k_per = Kernel(f=[exp_qper, ux_per], F=lambda eq, ux: eq * ux) per_qoi = [Form(k_per, dmu='dv', flag='right')] # Adjoint k_adj = Kernel(f=[exp_qref, ux_ref, vx_adj], F=lambda eq, ux, vx: -eq * ux * vx) adj_qoi = [Form(k_adj, test=phi)] qois = [ref_qoi, per_qoi, adj_qoi] # Assemble assembler = Assembler(qois) assembler.assemble() # Evaluate J_ref = assembler.get_scalar(0) J_per = [] for i in range(n_eps): J_per.append(assembler.get_scalar(1, i)) # Finite difference approximation dJ = [] for eps, J_p in zip(epsilons, J_per): dJ.append((J_p - J_ref) / eps) # Adjoint differential dJ_adj = assembler.get_vector(2).dot(dq) # # Check against exact qois # # Check reference sol Je_ref = 0.5 assert np.allclose(Je_ref, J_ref) # Check perturbed cost Je_per = -0.5 + np.exp(np.array(epsilons)) assert np.allclose(Je_per, J_per) # Check derivative by the adjoint equation dJdq = 1 assert np.allclose(dJ_adj, dJdq)
def test05_2d_dirichlet(self): """ Two dimensional Dirichlet problem with hanging nodes """ # # Define mesh # mesh = QuadMesh(resolution=(1, 2)) mesh.cells.get_child(1).mark(1) mesh.cells.refine(refinement_flag=1) mesh.cells.refine() # # Mark left and right boundaries # bm_left = lambda x, dummy: np.abs(x) < 1e-9 bm_right = lambda x, dummy: np.abs(1 - x) < 1e-9 mesh.mark_region('left', bm_left, entity_type='half_edge') mesh.mark_region('right', bm_right, entity_type='half_edge') for etype in ['Q1', 'Q2', 'Q3']: # # Element # element = QuadFE(2, etype) dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() # # Basis # u = Basis(dofhandler, 'u') ux = Basis(dofhandler, 'ux') uy = Basis(dofhandler, 'uy') # # Construct forms # ue = Nodal(f=lambda x: x[:, 0], basis=u) ax = Form(kernel=Kernel(Constant(1)), trial=ux, test=ux) ay = Form(kernel=Kernel(Constant(1)), trial=uy, test=uy) L = Form(kernel=Kernel(Constant(0)), test=u) problem = [ax, ay, L] # # Assemble # assembler = Assembler(problem, mesh) assembler.assemble() # # Get system matrices # A = assembler.get_matrix() b = assembler.get_vector() # # Linear System # system = LinearSystem(u, A=A, b=b) # # Constraints # # Add dirichlet conditions system.add_dirichlet_constraint('left', ue) system.add_dirichlet_constraint('right', ue) # # Solve # system.solve_system() #system.resolve_constraints() # # Check solution # ua = system.get_solution(as_function=True) self.assertTrue(np.allclose(ua.data(), ue.data()))
def dJdq_adj(q, u, dq=None): """ Compute the directional derivative dJ(q,dq) by solving the adjoint equation -(exp(q)v')' = 0, v(0)=0, v(1)=1 and computing ( v, (exp(q)*dq(1)*u')' ) + exp(q(1))*dq(1)*u'(1) = -(exp(q)*dq u', v') Inputs: q: Nodal, single reference log diffusitivity u: Nodal, single reference system response dq: Nodal/None, sampled perturbation vector (or None) Output: dJdq: Derivative of J wrt q If dq = Nodal, return directional derivative in direction dq If dq = None, return gradient """ # # Finite Element Specification # # Reference solution u_dh = u.basis().dofhandler() phi = Basis(u_dh, 'u') phi_x = Basis(u_dh, 'ux') ux = Nodal(data=u.data(), basis=phi_x) # Reference diffusivity q_dh = q.basis().dofhandler() psi = Basis(q_dh, 'q') exp_q = Nodal(data=np.exp(q.data()), basis=psi) # Define adjoint equations adjoint_eqn = [Form(exp_q, test=phi_x, trial=phi_x), Form(0, test=phi)] # Assembler assembler = Assembler(adjoint_eqn) # Apply Dirichlet BC assembler.add_dirichlet('left', 0) assembler.add_dirichlet('right', 1) # Assemble assembler.assemble() # Solve for adjoint v = assembler.solve() # Get derivative vx = Nodal(data=v, basis=phi_x) # Assemble if dq is None: # # Compute the gradient # # Kernel k_adj = Kernel(f=[exp_q, ux, vx], F=lambda eq, ux, vx: -eq * ux * vx) # Linear form adj_qoi = [Form(k_adj, test=psi)] # Assemble assembler = Assembler(adj_qoi) assembler.assemble() # Get gradient vector dJdq = assembler.get_vector() else: # # Compute the directional derivative # # Kernel k_adj = Kernel(f=[exp_q, dq, ux, vx], F=lambda eq, dq, ux, vx: -eq * dq * ux * vx) # Constant form adj_qoi = [Form(k_adj)] # Assemble assembler = Assembler(adj_qoi, mesh=u_dh.mesh) assembler.assemble() # Get directional derivatives for each direction dJdq = np.array( [assembler.get_scalar(i_sample=i) for i in range(dq.n_samples())]) # Return return dJdq
def test08_1d_sampled_rhs(self): # # Mesh # mesh = Mesh1D(resolution=(1, )) mesh.mark_region('left', lambda x: np.abs(x) < 1e-9, on_boundary=True) mesh.mark_region('right', lambda x: np.abs(1 - x) < 1e-9, on_boundary=True) # # Elements # Q3 = QuadFE(1, 'Q3') dofhandler = DofHandler(mesh, Q3) dofhandler.distribute_dofs() # # Basis # v = Basis(dofhandler, 'u') vx = Basis(dofhandler, 'ux') # # Define sampled right hand side and exact solution # xv = dofhandler.get_dof_vertices() n_points = dofhandler.n_dofs() n_samples = 6 a = np.arange(n_samples) f = lambda x, a: a * x u = lambda x, a: a / 6 * (x - x**3) + x fdata = np.zeros((n_points, n_samples)) udata = np.zeros((n_points, n_samples)) for i in range(n_samples): fdata[:, i] = f(xv, a[i]).ravel() udata[:, i] = u(xv, a[i]).ravel() # Define sampled function fn = Nodal(data=fdata, basis=v) ue = Nodal(data=udata, basis=v) # # Forms # one = Constant(1) a = Form(Kernel(one), test=vx, trial=vx) L = Form(Kernel(fn), test=v) problem = [a, L] # # Assembler # assembler = Assembler(problem, mesh) assembler.assemble() A = assembler.get_matrix() b = assembler.get_vector() # # Linear System # system = LinearSystem(v, A=A, b=b) # Set constraints system.add_dirichlet_constraint('left', 0) system.add_dirichlet_constraint('right', 1) #system.set_constraint_relation() #system.incorporate_constraints() # Solve and resolve constraints system.solve_system() #system.resolve_constraints() # Extract finite element solution ua = system.get_solution(as_function=True) # Check that the solution is close print(ue.data()[:, [0]]) print(ua.data()) self.assertTrue(np.allclose(ue.data()[:, [0]], ua.data()))
dofhandler.distribute_dofs() comment.toc() print('number of dofs:', dofhandler.n_dofs()) # Basis functions p_u = Basis(dofhandler, 'u') p_ux = Basis(dofhandler, 'ux') p_uy = Basis(dofhandler, 'uy') pp_u = Basis(dofhandler, 'u') f = lambda x: x[:, 0] * (1 - x[:, 0]) * x[:, 1] * (1 - x[:, 1]) qq = Explicit(f=f, dim=2) fNodal = Nodal(f=f, basis=p_u) qk = Kernel(f=[qq], F=lambda qq, mu=3: 3 * qq) p_inflow = lambda x, y: np.ones(shape=x.shape) p_outflow = lambda x, y: np.zeros(shape=x.shape) c_inflow = lambda x, y: np.zeros(shape=x.shape) # ============================================================================= # Solve the steady state flow equations # ============================================================================= # Define problem flow_problem = [ Form(fNodal), Form(1, test=p_uy, trial=p_uy), Form(1, test=p_u)
# Generate truncated field at the sparse grid points eta_trunc_sg = V[:, :k].dot(np.diag(np.sqrt(D[:k])).dot(z.T)) # Generate a Monte Carlo sample on top of sparse grid n_mc = 20 zz = np.random.randn(n_dofs - k, n_mc) eta_tail_mc = V[:, k:].dot(np.diag(np.sqrt(D[k:]))).dot(zz) # ----------------------------------------------------------------------------- # Sample and Integrate # ----------------------------------------------------------------------------- # Samples of random field theta_trunc = Nodal(data=eta_trunc_sg[:, [50]] + eta_tail_mc, basis=phi_1) # Assembler k = Kernel(theta_trunc, F=lambda tht: tht**2) problem = Form(flag='integration', kernel=k) assembler = Assembler(problem, mesh) assembler.assemble() v = assembler.get_scalar(i_sample=3) #plot = Plot(quickview=False) #fig, ax = plt.subplots() #plot.mesh(mesh,regions=[('region','cell')]) """ ax = plot.line(theta_trunc, axis=ax, i_sample=np.arange(n_mc), plot_kwargs={'linewidth':0.2, 'color':'k'}) """ #plt.show()
def test_constructor(self): # ===================================================================== # Test 1D # ===================================================================== # # Kernel consists of a single explicit Function: # f1 = lambda x: x+2 f = Explicit(f1, dim=1) k = Kernel(f) x = np.linspace(0,1,100) n_points = len(x) # Check that it evaluates correctly. self.assertTrue(np.allclose(f1(x), k.eval(x).ravel())) # Check shape of kernel self.assertEqual(k.eval(x).shape, (n_points,1)) # # Kernel consists of a combination of two explicit functions # f1 = Explicit(lambda x: x+2, dim=1) f2 = Explicit(lambda x: x**2 + 1, dim=1) F = lambda f1, f2: f1**2 + f2 f_t = lambda x: (x+2)**2 + x**2 + 1 k = Kernel([f1,f2], F=F) # Check evaluation self.assertTrue(np.allclose(f_t(x), k.eval(x).ravel())) # Check shape self.assertEqual(k.eval(x).shape, (n_points,1)) # # Same thing as above, but with nodal functions # mesh = Mesh1D(resolution=(1,)) Q1 = QuadFE(1,'Q1') Q2 = QuadFE(1,'Q2') dQ1 = DofHandler(mesh,Q1) dQ2 = DofHandler(mesh,Q2) # Distribute dofs [dQ.distribute_dofs() for dQ in [dQ1,dQ2]] # Basis functions phi1 = Basis(dQ1,'u') phi2 = Basis(dQ2,'u') f1 = Nodal(lambda x: x+2, basis=phi1) f2 = Nodal(lambda x: x**2 + 1, basis=phi2) k = Kernel([f1,f2], F=F) # Check evaluation self.assertTrue(np.allclose(f_t(x), k.eval(x).ravel())) # # Replace f2 above with its derivative # k = Kernel([f1,f2], derivatives=['f', 'fx'], F=F) f_t = lambda x: (x+2)**2 + 2*x # Check derivative evaluation F = F(f1, df2_dx) self.assertTrue(np.allclose(f_t(x), k.eval(x).ravel())) # # Sampling # one = Constant(1) f1 = Explicit(lambda x: x**2 + 1, dim=1) # Sampled function a = np.linspace(0,1,11) n_samples = len(a) # Define Dofhandler dh = DofHandler(mesh, Q2) dh.distribute_dofs() dh.set_dof_vertices() xv = dh.get_dof_vertices() n_dofs = dh.n_dofs() phi = Basis(dh, 'u') # Evaluate parameterized function at mesh dof vertices f2_m = np.empty((n_dofs, n_samples)) for i in range(n_samples): f2_m[:,i] = xv.ravel() + a[i]*xv.ravel()**2 f2 = Nodal(data=f2_m, basis=phi) # Define kernel F = lambda f1, f2, one: f1 + f2 + one k = Kernel([f1,f2,one], F=F) # Evaluate on a fine mesh x = np.linspace(0,1,100) n_points = len(x) self.assertEqual(k.eval(x).shape, (n_points, n_samples)) for i in range(n_samples): # Check evaluation self.assertTrue(np.allclose(k.eval(x)[:,i], f1.eval(x)[:,i] + x + a[i]*x**2+ 1)) # # Sample multiple constant functions # f1 = Constant(data=a) f2 = Explicit(lambda x: 1 + x**2, dim=1) f3 = Nodal(data=f2_m[:,-1], basis=phi) F = lambda f1, f2, f3: f1 + f2 + f3 k = Kernel([f1,f2,f3], F=F) x = np.linspace(0,1,100) for i in range(n_samples): self.assertTrue(np.allclose(k.eval(x)[:,i], \ a[i] + f2.eval(x)[:,i] + f3.eval(x)[:,i])) # # Submeshes # mesh = Mesh1D(resolution=(1,)) mesh_labels = Tree(regular=False) mesh = Mesh1D(resolution=(1,)) Q1 = QuadFE(1,'Q1') Q2 = QuadFE(1,'Q2') dQ1 = DofHandler(mesh,Q1) dQ2 = DofHandler(mesh,Q2) # Distribute dofs [dQ.distribute_dofs() for dQ in [dQ1,dQ2]] # Basis p1 = Basis(dQ1) p2 = Basis(dQ2) f1 = Nodal(lambda x: x, basis=p1) f2 = Nodal(lambda x: -2+2*x**2, basis=p2) one = Constant(np.array([1,2])) F = lambda f1, f2, one: 2*f1**2 + f2 + one I = mesh.cells.get_child(0) kernel = Kernel([f1,f2, one], F=F) rule1D = GaussRule(5,shape='interval') x = I.reference_map(rule1D.nodes())
def reference_qoi(f, tht, basis, region, n=1000000, verbose=True): """ Parameters ---------- f : lambda function, Function of θ to be integrated. tht : GaussianField, Random field θ defined on mesh in terms of its mean and covariance basis : Basis, Basis function defining the nodal interpolant. It incorporates the mesh, the dofhandler, and the derivative. region : meshflag, Flag indicating the region of integration n : int, default=1000000 Sample size Returns ------- Q_ref : double, Reference quantity of interest err : double, Expected RMSE given by var(Q)/n. """ # # Assemble integral # batch_size = 100000 n_batches = n // batch_size + (0 if (n % batch_size) == 0 else 1) if verbose: print('Computing Reference Quantity of Interest') print('========================================') print('Sample size: ', n) print('Batch size: ', batch_size) print('Number of batches: ', n_batches) Q_smpl = np.empty(n) for k in range(n_batches): # Determine sample sizes for each batch if k < n_batches - 1: n_sample = batch_size else: # Last sample may be smaller than batch_size n_sample = n - k * batch_size if verbose: print(' - Batch Number ', k) print(' - Sample Size: ', n_sample) print(' - Sampling random field') # Sample from field tht_smpl = tht.sample(n_sample) # Define kernel tht_n = Nodal(data=tht_smpl, basis=basis) kf = Kernel(tht_n, F=f) # Define forms if k == 0: problems = [[Form(kernel=kf, flag=region)], [Form(flag=region)]] else: problems = [Form(kernel=kf, flag=region)] if verbose: print(' - Assembling.') # Compute the integral assembler = Assembler(problems, basis.mesh()) assembler.assemble() # # Compute statistic # # Get samples if k == 0: dx = assembler.get_scalar(i_problem=1) if verbose: print(' - Updating samples \n') batch_sample = assembler.get_scalar(i_problem=0, i_sample=None) Q_smpl[k * batch_size:k * batch_size + n_sample] = batch_sample / dx # Compute mean and MSE Q_ref = np.mean(Q_smpl) err = np.var(Q_smpl) / n # Return reference return Q_ref, err
def __init__(self, u, dfdx=None, samples='all'): """ Constructor """ Kernel.__init__(self, u, dfdx=dfdx, F=None, samples=samples)
one = Function(1, 'constant') k1 = 1e-9 k2 = 1000 # # Basis functions # u = Basis(Q1, 'u') ux = Basis(Q1, 'ux') q = Basis(Q1, 'q') # # Forms # a_qe = Form(kernel=Kernel(qe), trial=ux, test=ux) a_one = Form(kernel=Kernel(one), trial=ux, test=ux) L = Form(kernel=Kernel(one), test=u) # # Problems # problems = [[a_qe,L], [a_one]] # # Assembly # assembler = Assembler(problems, mesh) assembler.assemble()
# Gaussian random field θ tht = GaussianField(dQ1.n_dofs(), K=K) # Sample from field tht_fn = Nodal(data=tht.sample(n_samples=3), basis=phi) plot = Plot() plot.contour(tht_fn) # # Advection # v = [0.1, -0.1] plot.mesh(mesh, regions=[('in', 'edge'), ('out', 'edge'), ('reg', 'cell')]) k = Kernel(tht_fn, F=lambda tht: np.exp(tht)) adv_diff = [ Form(k, trial=phi_x, test=phi_x), Form(k, trial=phi_y, test=phi_y), Form(0, test=phi), Form(v[0], trial=phi_x, test=phi), Form(v[1], trial=phi_y, test=phi) ] average = [Form(1, test=phi, flag='reg'), Form(1, flag='reg')] assembler = Assembler([adv_diff, average], mesh) assembler.add_dirichlet('out', dir_fn=0) assembler.add_dirichlet('in', dir_fn=10) assembler.assemble()