def test01_solve_2d(self): """ Solve a simple 2D problem with no hanging nodes """ mesh = QuadMesh(resolution=(5, 5)) # Mark dirichlet boundaries mesh.mark_region('left', lambda x, dummy: np.abs(x) < 1e-9, entity_type='half_edge') mesh.mark_region('right', lambda x, dummy: np.abs(x - 1) < 1e-9, entity_type='half_edge') Q1 = QuadFE(mesh.dim(), 'Q1') dQ1 = DofHandler(mesh, Q1) dQ1.distribute_dofs() phi = Basis(dQ1, 'u') phi_x = Basis(dQ1, 'ux') phi_y = Basis(dQ1, 'uy') problem = [ Form(1, test=phi_x, trial=phi_x), Form(1, test=phi_y, trial=phi_y), Form(0, test=phi) ] assembler = Assembler(problem, mesh) assembler.add_dirichlet('left', dir_fn=0) assembler.add_dirichlet('right', dir_fn=1) assembler.assemble() # Get matrix dirichlet correction and right hand side A = assembler.get_matrix().toarray() x0 = assembler.assembled_bnd() b = assembler.get_vector() ua = np.zeros((phi.n_dofs(), 1)) int_dofs = assembler.get_dofs('interior') ua[int_dofs, 0] = np.linalg.solve(A, b - x0) dir_bc = assembler.get_dirichlet() dir_vals = np.array([dir_bc[dof] for dof in dir_bc]) dir_dofs = [dof for dof in dir_bc] ua[dir_dofs] = dir_vals ue_fn = Nodal(f=lambda x: x[:, 0], basis=phi) ue = ue_fn.data() self.assertTrue(np.allclose(ue, ua)) self.assertTrue(np.allclose(x0 + A.dot(ua[int_dofs, 0]), b))
def test_mark_region(self): """ This is a method in Mesh2D, but """ # # Define Mesh # mesh = QuadMesh(resolution=(2,2)) mesh.cells.get_child(2).mark('1') mesh.cells.refine(refinement_flag='1') # # Mark left boundary vertices # f_left = lambda x,dummy: np.abs(x)<1e-9 mesh.mark_region('left', f_left, on_boundary=True) # # Check that left boundary vertices are the only # count = 0 for segment in mesh.get_boundary_segments(): for he in segment: # Half-edge should not be marked self.assertFalse(he.is_marked('left')) # Cell should not be marked self.assertFalse(he.cell().is_marked('left')) for v in he.get_vertices(): if f_left(*v.coordinates()): # # Left boundary vertices should be marked # self.assertTrue(v.is_marked('left')) count += 1 else: # # No other boundary vertices should be marked # self.assertFalse(v.is_marked('left')) self.assertEqual(count, 8)
def test_get_region(self): # # Define Mesh # mesh = QuadMesh(resolution=(2,2)) mesh.cells.get_child(2).mark('1') mesh.cells.refine(refinement_flag='1') # # Mark left boundary vertices # f_left = lambda x,dummy: np.abs(x)<1e-9 mesh.mark_region('left', f_left, on_boundary=True) for v,cell in mesh.get_region('left', entity_type='vertex', return_cells=True, on_boundary=True): self.assertTrue(v.is_marked('left'))
def test_get_region_dofs(self): """ Test the function for returning the dofs associated with a region. """ # # 2D # mesh = QuadMesh() for etype in ['Q1','Q2','Q3']: element = QuadFE(2, etype) dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() # # Mark half-edges # bnd_right = lambda x,dummy: np.abs(x-1)<1e-9 mesh.mark_region('right', bnd_right, \ entity_type='half_edge', \ on_boundary=True) # Check that mesh.mark_region is doing the right thing. cell = mesh.cells.get_child(0) marked_edge = False for he in cell.get_half_edges(): if he.is_marked('right'): # # All vertices should be on the boundary # marked_edge = True for v in he.get_vertices(): x,y = v.coordinates() self.assertTrue(bnd_right(x,y)) else: # # Not all vertices on should be on the boundary # on_right = True for v in he.get_vertices(): x,y = v.coordinates() if not bnd_right(x,y): on_right = False self.assertFalse(on_right) # # Some half-edge should be marked # self.assertTrue(marked_edge) # # Check that we get the right number of dofs # n_dofs = {True: {'Q1': 0, 'Q2': 1, 'Q3': 2}, False: {'Q1': 2, 'Q2': 3, 'Q3': 4}} for interior in [True, False]: dofs = dofhandler.get_region_dofs(entity_type='half_edge', \ entity_flag='right', \ interior=interior, \ on_boundary=True) # # Check that we get the right number of dofs # self.assertEqual(len(dofs), n_dofs[interior][etype])
from mesh import QuadMesh from mesh import Vertex from mesh import HalfEdge from solver import LinearSystem as LS from plot import Plot import numpy as np # ============================================================================= # Computational mesh # ============================================================================= mesh = QuadMesh(box=[-0.5, 0.5, -0.5, 0.5], resolution=(20, 20)) # Mark slit region slit = HalfEdge(Vertex((0, 0)), Vertex((0, -0.5))) sf = lambda x, y: slit.contains_points(np.array([x, y]))[0] mesh.mark_region('slit', sf, entity_type='half_edge') # Mark perimeter tol = 1e-9 pf = lambda x,y: np.abs(x+0.5)<tol or np.abs(x-0.5)<tol or \ np.abs(y+0.5)<tol or np.abs(y-0.5)<tol mesh.mark_region('perimeter', pf, entity_type='half_edge') # Get rid of neighbors of half-edges on slit for he in mesh.half_edges.get_leaves('slit'): if he.unit_normal()[0] < 0: he.mark('B') mesh.tear_region('B') # ============================================================================= # Functions
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()))
import matplotlib.pyplot as plt """ Investigate local error estimates on the resolution of a random field """ plot = Plot() # # Computational mesh # mesh = QuadMesh(resolution=(4, 4)) # Mark boundary bnd_fn = lambda x, y: abs(x) < 1e-6 or abs(1 - x) < 1e-6 or abs( y) < 1e-6 or abs(1 - y) < 1e-6 mesh.mark_region('bnd', bnd_fn, entity_type='half_edge', on_boundary=True) # Mark averaging region dmn_fn = lambda x, y: x >= 0.75 and x <= 1 and y >= 0.75 and y <= 1 mesh.mark_region('dmn', dmn_fn, entity_type='cell', strict_containment=True, on_boundary=False) #cells = mesh.get_region(flag='dmn', entity_type='cell', on_boundary=False, subforest_flag=None) plot.mesh(mesh, regions=[('bnd', 'edge'), ('dmn', 'cell')]) # # Elements # Q0 = QuadFE(mesh.dim(), 'DQ0') # Constants for parameter
""" from mesh import QuadMesh from fem import DofHandler, Basis, QuadFE from function import Nodal from gmrf import GaussianField, SPDMatrix, Covariance from plot import Plot from assembler import Assembler, Form, Kernel import numpy as np # Computational mesh mesh = QuadMesh(resolution=(50, 50)) # Mark Dirichlet boundary regions out_fn = lambda x, y: abs(x - 1) < 1e-8 and 0.8 <= y and y <= 1 mesh.mark_region('out', out_fn, entity_type='half_edge', on_boundary=True) in_fn = lambda x, y: abs(x) < 1e-8 and 0 <= y and y <= 0.2 mesh.mark_region('in', in_fn, entity_type='half_edge', on_boundary=True) x_min, x_max = 0.7, 0.8 y_min, y_max = 0.4, 0.5 reg_fn = lambda x, y: x >= x_min and x <= x_max and y >= y_min and y <= y_max mesh.mark_region('reg', reg_fn, entity_type='cell') # Elements Q1 = QuadFE(mesh.dim(), 'Q1') dQ1 = DofHandler(mesh, Q1) dQ1.distribute_dofs() phi = Basis(dQ1)
def reference_solution(): """ Use sparse grid method to compute a benchmark solution """ mesh = QuadMesh(resolution=(10,10)) mesh.mark_region('boundary', lambda x,y:True, entity_type='half_edge', on_boundary=True) element = QuadFE(mesh.dim(), 'Q1') dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() n = dofhandler.n_dofs() phi = Basis(dofhandler, 'u') phi_x = Basis(dofhandler, 'ux') phi_y = Basis(dofhandler, 'uy') yd_fn = Explicit(lambda x: np.sin(2*np.pi*x[:,0])*np.sin(2*np.pi*x[:,1]),dim=2) g = np.ones((n,1)) # # Random diffusion coefficient # # Sparse grid tasmanian_library="/home/hans-werner/bin/TASMANIAN-6.0/libtasmaniansparsegrid.so" grid = TasmanianSG.TasmanianSparseGrid(tasmanian_library=tasmanian_library) dimensions = 4 outputs = 1 depth = 4 type = 'tensor' rule = 'gauss-legendre' grid.makeGlobalGrid(dimensions, outputs, depth, type, rule) Y = grid.getPoints() w = grid.getQuadratureWeights() n_samples = grid.getNumPoints() x = dofhandler.get_dof_vertices() a_nodal = 1 + 0.1*(np.outer(np.cos(np.pi*x[:,1]),Y[:,0])+\ np.outer(np.cos(np.pi*x[:,0]),Y[:,1])+\ np.outer(np.sin(2*np.pi*x[:,1]),Y[:,2])+\ np.outer(np.sin(2*np.pi*x[:,0]),Y[:,3])) a = Nodal(data=a_nodal, dofhandler=dofhandler) yd_vec = yd_fn.eval(x) problems = [[Form(a, test=phi_x, trial=phi_x), Form(a, test=phi_y, trial=phi_y)], [Form(1, test=phi, trial=phi)]] assembler = Assembler(problems, mesh) assembler.assemble() A = assembler.af[0]['bilinear'].get_matrix() M = assembler.af[1]['bilinear'].get_matrix() state = LS(phi) state.add_dirichlet_constraint('boundary') adjoint = LS(phi) adjoint.add_dirichlet_constraint('boundary') tau = 10 k_max = 20 alpha = 0.1 u = np.zeros((n,1)) norm_dJ_iter = [] J_iter = [] u_iter = [] for k in range(k_max): print('iteration', k) # # Compute average cost and gradient # dJ = np.zeros((n,1)) J = 0 print('sampling') for n in range(n_samples): print(n) yn, pn, Jn, dJn = cost_gradient(state,adjoint,A[n],M, g,u,yd_vec,alpha) J += w[n]*Jn dJ += w[n]*dJn print('') norm_dJ = np.sqrt(dJ.T.dot(M.dot(dJ))) # # Store current iterates # norm_dJ_iter.append(norm_dJ) J_iter.append(J) u_iter.append(u) # # Check for convergence # if norm_dJ<1e-8: break # # Update iterate # u -= tau*dJ
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)
from solver import LinearSystem from diagnostics import Verbose import numpy as np """ Simulate the time dependent advection-diffusion-reaction system u_t - div*(D*grad(u)) + div(v*u) + R(u) = 0 subject to the appropriate initial and boundary conditions, using SUPG and """ comment = Verbose() # Computational mesh mesh = QuadMesh(box=[0, 10, 0, 10], resolution=(100, 100)) left = mesh.mark_region('left', lambda x, y: abs(x) < 1e-10) # Finite elements # Piecewise constants E0 = QuadFE(mesh.dim(), 'DQ0') V0 = DofHandler(mesh, E0) V0.distribute_dofs() # Piecewise linears E1 = QuadFE(mesh.dim(), 'Q1') V1 = DofHandler(mesh, E1) V1.distribute_dofs() v = Basis(V1, 'v') v_x = Basis(V1, 'vx')
# ============================================================================= # Mesh and Elements # ============================================================================= # Finite element mesh x_min = 0 x_max = 2 y_min = 0 y_max = 1 mesh = QuadMesh(box=[x_min, x_max, y_min, y_max], resolution=(20, 10)) # Mark Dirichlet Edges 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 - 2) < 1e-9, entity_type='half_edge') # Element element_Q0 = QuadFE(mesh.dim(), 'DQ0') element_Q1 = QuadFE(mesh.dim(), 'Q1') dh_Q0 = DofHandler(mesh, element_Q0) dh_Q0.distribute_dofs() n_Q0 = dh_Q0.n_dofs() dh_Q1 = DofHandler(mesh, element_Q1) dh_Q1.distribute_dofs()
def test03_solve_2d(self): """ Test problem with Neumann conditions """ # # Define Mesh # mesh = QuadMesh(resolution=(2, 1)) mesh.cells.get_child(1).mark(1) mesh.cells.refine(refinement_flag=1) # 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']: # # Define element and basis type # element = QuadFE(2, etype) dofhandler = DofHandler(mesh, element) dofhandler.distribute_dofs() u = Basis(dofhandler, 'u') ux = Basis(dofhandler, 'ux') uy = Basis(dofhandler, 'uy') # # Exact solution # ue = Nodal(f=lambda x: x[:, 0], basis=u) # # Set up forms # one = Constant(1) ax = Form(kernel=Kernel(one), trial=ux, test=ux) ay = Form(kernel=Kernel(one), trial=uy, test=uy) L = Form(kernel=Kernel(Constant(0)), test=u) Ln = Form(kernel=Kernel(one), test=u, dmu='ds', flag='right') problem = [ax, ay, L, Ln] assembler = Assembler(problem, mesh) assembler.add_dirichlet('left', dir_fn=0) assembler.add_hanging_nodes() assembler.assemble() # # Automatic solve # ya = assembler.solve() self.assertTrue(np.allclose(ue.data()[:, 0], ya)) # # Explicit solve # # System Matrices A = assembler.get_matrix().toarray() b = assembler.get_vector() x0 = assembler.assembled_bnd() # Solve linear system xa = np.zeros(u.n_dofs()) int_dofs = assembler.get_dofs('interior') xa[int_dofs] = np.linalg.solve(A, b - x0) # Resolve Dirichlet conditions dir_dofs, dir_vals = assembler.get_dirichlet(asdict=False) xa[dir_dofs] = dir_vals[:, 0] # Resolve hanging nodes C = assembler.hanging_node_matrix() xa += C.dot(xa) self.assertTrue(np.allclose(ue.data()[:, 0], xa))
def test02_solve_2d(self): """ Solve 2D problem with hanging nodes """ # Mesh mesh = QuadMesh(resolution=(2, 2)) mesh.cells.get_leaves()[0].mark(0) mesh.cells.refine(refinement_flag=0) mesh.mark_region('left', lambda x, y: abs(x) < 1e-9, entity_type='half_edge') mesh.mark_region('right', lambda x, y: abs(x - 1) < 1e-9, entity_type='half_edge') # Element Q1 = QuadFE(2, 'Q1') dofhandler = DofHandler(mesh, Q1) dofhandler.distribute_dofs() dofhandler.set_hanging_nodes() # Basis functions phi = Basis(dofhandler, 'u') phi_x = Basis(dofhandler, 'ux') phi_y = Basis(dofhandler, 'uy') # # Define problem # problem = [ Form(1, trial=phi_x, test=phi_x), Form(1, trial=phi_y, test=phi_y), Form(0, test=phi) ] ue = Nodal(f=lambda x: x[:, 0], basis=phi) xe = ue.data().ravel() # # Assemble without Dirichlet and without Hanging Nodes # assembler = Assembler(problem, mesh) assembler.add_dirichlet('left', dir_fn=0) assembler.add_dirichlet('right', dir_fn=1) assembler.add_hanging_nodes() assembler.assemble() # Get dofs for different regions int_dofs = assembler.get_dofs('interior') # Get matrix and vector A = assembler.get_matrix().toarray() b = assembler.get_vector() x0 = assembler.assembled_bnd() # Solve linear system xa = np.zeros(phi.n_dofs()) xa[int_dofs] = np.linalg.solve(A, b - x0) # Resolve Dirichlet conditions dir_dofs, dir_vals = assembler.get_dirichlet(asdict=False) xa[dir_dofs] = dir_vals[:, 0] # Resolve hanging nodes C = assembler.hanging_node_matrix() xa += C.dot(xa) self.assertTrue(np.allclose(xa, xe))