A FEniCS Tutorial - FEniCS Project

A FEniCS Tutorial - FEniCS Project A FEniCS Tutorial - FEniCS Project

fenicsproject.org
from fenicsproject.org More from this publisher
19.06.2015 Views

The code for the y = 1 boundary is similar and is seen in dnr_p2D.py. The Dirichlet boundaries are marked similarly, using subdomain number 2 for Γ 0 and 3 for Γ 1 : class LeftBoundary(SubDomain): def inside(self, x, on_boundary): tol = 1E-14 # tolerance for coordinate comparisons return on_boundary and abs(x[0]) < tol Gamma_0 = LeftBoundary() Gamma_0.mark(boundary_parts, 2) class RightBoundary(SubDomain): def inside(self, x, on_boundary): tol = 1E-14 # tolerance for coordinate comparisons return on_boundary and abs(x[0] - 1) < tol Gamma_1 = RightBoundary() Gamma_1.mark(boundary_parts, 3) Specifying the DirichletBC objects may now make use of the mesh function (instead of a SubDomain subclass object) and an indicator for which subdomain each condition should be applied to: u_L = Expression(’1 + 2*x[1]*x[1]’) u_R = Expression(’2 + 2*x[1]*x[1]’) bcs = [DirichletBC(V, u_L, boundary_parts, 2), DirichletBC(V, u_R, boundary_parts, 3)] Some functions need to be defined before we can go on with the a and L of the variational problem: g = Expression(’-4*x[1]’) q = Expression(’1 + x[0]*x[0] + 2*x[1]*x[1]’) p = Constant(100) # arbitrary function can go here u = TrialFunction(V) v = TestFunction(V) f = Constant(-6.0) The new aspect of the variational problem is the two distinct boundary integrals. Having a mesh function over exterior cell facets (our boundary_parts object), where subdomains (boundary parts) are numbered as 0,1,2,..., the special symbol ds(0) implies integration over subdomain (part) 0, ds(1) denotes integration over subdomain (part) 1, and so on. The idea of multiple ‘ds‘-type objects generalizes to volume integrals too: dx(0), dx(1), etc., are used to integrate over subdomain 0, 1, etc., inside Ω. The variational problem can be defined as a = inner(nabla_grad(u), nabla_grad(v))*dx + p*u*v*ds(0) L = f*v*dx - g*v*ds(1) + p*q*v*ds(0) For the ds(0) and ds(1) symbols to work we must obviously connect them (or a and L) to the mesh function marking parts of the boundary. This is done by a certain keyword argument to the assemble function: 80

A = assemble(a, exterior_facet_domains=boundary_parts) b = assemble(L, exterior_facet_domains=boundary_parts) Then essential boundary conditions are enforced, and the system can be solved in the usual way: for bc in bcs: bc.apply(A, b) u = Function(V) U = u.vector() solve(A, U, b) The complete code is in the dnr_p2D.py file in the stationary/poisson directory. 6 More Examples Many more topics could be treated in a FEniCS tutorial, e.g., how to solve systems of PDEs, how to work with mixed finite element methods, how to create more complicated meshes and mark boundaries, and how to create more advanced visualizations. However, to limit the size of this tutorial, the examples end here. There are, fortunately, a rich set of FEniCS demos. The FEniCS documentation explains a collection of PDE solvers in detail: the Poisson equation, the mixed formulation for the Poission equation, the Biharmonic equation, the equations of hyperelasticity, the Cahn-Hilliard equation, and the incompressible Navier-Stokes equations. Both Python and C++ versions of these solvers are explained. An eigenvalue solver is also documented. In the dolfin/demo directory of the DOLFIN source code tree you can find programs for these and many other examples, including the advection-diffusion equation, the equations of elastodynamics, a reaction-diffusion equation, various finite element methods for the Stokes problem, discontinuous Galerkin methods for the Poisson and advection-diffusion equations, and an eigenvalue problem arising from electromagnetic waveguide problem with Nedelec elements. There are also numerous demos on how to apply various functionality in FEniCS, e.g., mesh refinement and error control, moving meshes (for ALE methods), computing functionals over subsets of the mesh (such as lift and drag on bodies in flow), and creating separate subdomain meshes from a parent mesh. Theprojectcbc.solve(https://launchpad.net/cbc.solve)offersmorecomplete PDE solvers for the Navier-Stokes equations, the equations of hyperelasticity, fluid-structure interaction, viscous mantle flow, and the bidomain model of electrophysiology. Most of these solvers are described in the ”FEniCS book”[14](https://launchpad.net/fenics-book). Anotherproject,cbc.rans (https://launchpad.net/cbc.rans), offers an environment for very flexible and easy implementation of Navier-Stokes solvers and turbulence [20, 19]. For example, cbc.rans contains an elliptic relaxation model for turbulent flow involving 18 nonlinear PDEs. FEniCS proved to be an ideal environment for implementing such complicated PDE models. The easy construction of systems 81

The code for the y = 1 boundary is similar and is seen in dnr_p2D.py.<br />

The Dirichlet boundaries are marked similarly, using subdomain number 2<br />

for Γ 0 and 3 for Γ 1 :<br />

class LeftBoundary(SubDomain):<br />

def inside(self, x, on_boundary):<br />

tol = 1E-14 # tolerance for coordinate comparisons<br />

return on_boundary and abs(x[0]) < tol<br />

Gamma_0 = LeftBoundary()<br />

Gamma_0.mark(boundary_parts, 2)<br />

class RightBoundary(SubDomain):<br />

def inside(self, x, on_boundary):<br />

tol = 1E-14 # tolerance for coordinate comparisons<br />

return on_boundary and abs(x[0] - 1) < tol<br />

Gamma_1 = RightBoundary()<br />

Gamma_1.mark(boundary_parts, 3)<br />

Specifying the DirichletBC objects may now make use of the mesh function<br />

(instead of a SubDomain subclass object) and an indicator for which subdomain<br />

each condition should be applied to:<br />

u_L = Expression(’1 + 2*x[1]*x[1]’)<br />

u_R = Expression(’2 + 2*x[1]*x[1]’)<br />

bcs = [DirichletBC(V, u_L, boundary_parts, 2),<br />

DirichletBC(V, u_R, boundary_parts, 3)]<br />

Some functions need to be defined before we can go on with the a and L of<br />

the variational problem:<br />

g = Expression(’-4*x[1]’)<br />

q = Expression(’1 + x[0]*x[0] + 2*x[1]*x[1]’)<br />

p = Constant(100) # arbitrary function can go here<br />

u = TrialFunction(V)<br />

v = TestFunction(V)<br />

f = Constant(-6.0)<br />

The new aspect of the variational problem is the two distinct boundary integrals.<br />

Having a mesh function over exterior cell facets (our boundary_parts<br />

object), where subdomains (boundary parts) are numbered as 0,1,2,..., the<br />

special symbol ds(0) implies integration over subdomain (part) 0, ds(1) denotes<br />

integration over subdomain (part) 1, and so on. The idea of multiple<br />

‘ds‘-type objects generalizes to volume integrals too: dx(0), dx(1), etc., are<br />

used to integrate over subdomain 0, 1, etc., inside Ω.<br />

The variational problem can be defined as<br />

a = inner(nabla_grad(u), nabla_grad(v))*dx + p*u*v*ds(0)<br />

L = f*v*dx - g*v*ds(1) + p*q*v*ds(0)<br />

For the ds(0) and ds(1) symbols to work we must obviously connect them (or<br />

a and L) to the mesh function marking parts of the boundary. This is done by<br />

a certain keyword argument to the assemble function:<br />

80

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!