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

implies a boundary integral over the complete boundary, or in FEniCS terms, an integral over all exterior facets. However, the contributions from the parts of the boundary where we have Dirichlet conditions are erased when the linear system is modified by the Dirichlet conditions. We would like, from an efficiency point of view, to integrate v*g*ds only over the parts of the boundary where we actually have Neumann conditions. And more importantly, in other problems one may have different Neumann conditions or other conditions like the Robin type condition. With the mesh function concept we can mark different parts of the boundary and integrate over specific parts. The same concept can also be used to treat multiple Dirichlet conditions. The forthcoming text illustrates how this is done. Essentially, we still stick to the model problem from Section 1.14, but replace the Neumann condition at y = 0 by a Robin condition: − ∂u ∂n = p(u−q), where p and q are specified functions. The Robin condition is most often used to model heat transfer to the surroundings and arise naturally from Newton’s cooling law. Since we have prescribed a simple solution in our model problem, u = 1+ x 2 +2y 2 , we adjust p and q such that the condition holds at y = 0. This implies that q = 1+x 2 +2y 2 and p can be arbitrary (the normal derivative at y = 0: ∂u/∂n = −∂u/∂y = −4y = 0). Now we have four parts of the boundary: Γ N which corresponds to the upper side y = 1, Γ R which corresponds to the lower part y = 0, Γ 0 which corresponds to the left part x = 0, and Γ 1 which corresponds to the right part x = 1. The complete boundary-value problem reads −∇ 2 u = −6 in Ω, (90) u = u L on Γ 0 , (91) u = u R on Γ 1 , (92) − ∂u ∂n = p(u−q) on Γ R, (93) − ∂u ∂n = g on Γ N . (94) Theinvolvedprescribedfunctionsareu L = 1+2y 2 ,u R = 2+2y 2 ,q = 1+x 2 +2y 2 , p is arbitrary, and g = −4y. Integration by parts of − ∫ Ω v∇2 udx becomes as usual ∫ − Ω ∫ v∇ 2 udx = Ω ∫ ∇u·∇vdx− ∂Ω ∂u ∂n vds. The boundary integral vanishes on Γ 0 ∪Γ 1 , and we split the parts over Γ N and Γ R since we have different conditions at those parts: ∫ − v ∂u ∫ ∂n ds = − v ∂u ∫ Γ N ∂n ds− v ∂u ∫ ∫ Γ R ∂n ds = vgds+ vp(u−q)ds. Γ N Γ R ∂Ω 78

The weak form then becomes ∫ ∫ ∫ ∫ ∇u·∇vdx+ gvds+ p(u−q)vds = Ω Γ N Γ R Ω fvdx, We want to write this weak form in the standard notation a(u,v) = L(v), which requires that we identify all integrals with both u and v, and collect these in a(u,v), whiletheremainingintegralswithv andnotugointoL(v). Theintegral from the Robin condition must of this reason be split in two parts: ∫ ∫ ∫ p(u−q)vds = puvds− pqvds. Γ R Γ R Γ R We then have ∫ a(u,v) = ∫ L(v) = Ω Ω ∫ ∇u·∇vdx+ puvds, (95) Γ ∫ R ∫ fvdx− gvds+ pqvds. (96) Γ N Γ R A natural starting point for implementation is the dn2_p2D.py program in the directory stationary/poisson. The new aspects are • definition of a mesh function over the boundary, • marking each side as a subdomain, using the mesh function, • splitting a boundary integral into parts. Task 1 makes use of the MeshFunction object, but contrary to Section 5.2, this is not a function over cells, but a function over cell facets. The topological dimension of cell facets is one lower than the cell interiors, so in a two-dimensional problem the dimension becomes 1. In general, the facet dimension is given as mesh.topology().dim()-1, which we use in the code for ease of direct reuse in other problems. The construction of a MeshFunction object to mark boundary parts now reads boundary_parts = \ MeshFunction("uint", mesh, mesh.topology().dim()-1) As in Section 5.2 we use a subclass of SubDomain to identify the various parts of the mesh function. Problems with domains of more complicated geometries may set the mesh function for marking boundaries as part of the mesh generation. In our case, the y = 0 boundary can be marked by class LowerRobinBoundary(SubDomain): def inside(self, x, on_boundary): tol = 1E-14 # tolerance for coordinate comparisons return on_boundary and abs(x[1]) < tol Gamma_R = LowerRobinBoundary() Gamma_R.mark(boundary_parts, 0) 79

The weak form then becomes<br />

∫ ∫ ∫ ∫<br />

∇u·∇vdx+ gvds+ p(u−q)vds =<br />

Ω Γ N Γ R<br />

Ω<br />

fvdx,<br />

We want to write this weak form in the standard notation a(u,v) = L(v), which<br />

requires that we identify all integrals with both u and v, and collect these in<br />

a(u,v), whiletheremainingintegralswithv andnotugointoL(v). Theintegral<br />

from the Robin condition must of this reason be split in two parts:<br />

∫ ∫ ∫<br />

p(u−q)vds = puvds− pqvds.<br />

Γ R Γ R Γ R<br />

We then have<br />

∫<br />

a(u,v) =<br />

∫<br />

L(v) =<br />

Ω<br />

Ω<br />

∫<br />

∇u·∇vdx+ puvds, (95)<br />

Γ<br />

∫<br />

R<br />

∫<br />

fvdx− gvds+ pqvds. (96)<br />

Γ N Γ R<br />

A natural starting point for implementation is the dn2_p2D.py program in<br />

the directory stationary/poisson. The new aspects are<br />

• definition of a mesh function over the boundary,<br />

• marking each side as a subdomain, using the mesh function,<br />

• splitting a boundary integral into parts.<br />

Task 1 makes use of the MeshFunction object, but contrary to Section 5.2, this<br />

is not a function over cells, but a function over cell facets. The topological dimension<br />

of cell facets is one lower than the cell interiors, so in a two-dimensional<br />

problem the dimension becomes 1. In general, the facet dimension is given as<br />

mesh.topology().dim()-1, which we use in the code for ease of direct reuse in<br />

other problems. The construction of a MeshFunction object to mark boundary<br />

parts now reads<br />

boundary_parts = \<br />

MeshFunction("uint", mesh, mesh.topology().dim()-1)<br />

As in Section 5.2 we use a subclass of SubDomain to identify the various parts of<br />

the mesh function. Problems with domains of more complicated geometries may<br />

set the mesh function for marking boundaries as part of the mesh generation.<br />

In our case, the y = 0 boundary can be marked by<br />

class LowerRobinBoundary(SubDomain):<br />

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

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

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

Gamma_R = LowerRobinBoundary()<br />

Gamma_R.mark(boundary_parts, 0)<br />

79

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

Saved successfully!

Ooh no, something went wrong!