Hi, consider
from dolfin import *
# The idea here is to exploit the divergence theorem
#
# \int_{surface of bounded volume} vec.n dS = \int_{bounded volume} div(v) dx
#
# For circle centered at (0, 0) we have n = (x, y)/radius. Now suppose that
# vec = f*(x, y). Then
#
# \int_{surface of bounded volume} vec.n dS = radius*\int_{surface of bounded volume} f dS
radius = 0.2
mesh = Mesh('domain.xml')
# Conforming mesh
# Here we load the cell function with marked circle (tag 1) of radius 0.2
volumes = MeshFunction('size_t', mesh, 'domain_physical_region.xml')
# If not given, the cell function would be done manually
for cell in cells(mesh):
if cell.midpoint().norm() < radius:
assert volumes[cell] == 1 # volumes[cell] = 1
def circle_integral(f, vols=volumes, rad=radius):
# The circle is marked as 1
dV = Measure('dx', domain=vols.mesh(), subdomain_data=vols, subdomain_id=1)
x = SpatialCoordinate(mesh)
value = assemble(div(f*x)*dV)
# Take the radius into account
value /= rad
return value
# Sanity
f = Constant(1)
value = circle_integral(f)
print(value, 2*pi*radius*f(0), abs(value - 2*pi*radius*f(0)))
# Something more advanced
x = SpatialCoordinate(mesh)
f = inner(x, x)
value = circle_integral(f)
print(value, 2*pi*radius**3, abs(value - 2*pi*radius**3))
# Finally chech on nonconforming mesh
in_circle = CompiledSubDomain('x[0]*x[0] + x[1]*x[1] < rad', rad=radius**2)
true = 2*pi*radius**3
e0, h0 = None, None
for i in range(3, 12):
ncells = 2**i
mesh = RectangleMesh(Point(-1, -1), Point(1, 1), ncells, ncells, 'crossed')
volumes = MeshFunction('size_t', mesh, mesh.topology().dim(), 0)
in_circle.mark(volumes, 1)
x = SpatialCoordinate(mesh)
f = inner(x, x)
value = circle_integral(f, volumes, radius)
e, h = abs(value - true), mesh.hmin()
if e0 is not None:
rate = ln(e/e0)/ln(h/h0)
else:
rate = -1.
e0, h0 = e, h
print('error %g(%.2f)' % (e, rate))
The Gmsh file used is as follows
// to refine `gmsh -2 domain.geo -clscale 0.5`
// dolfin-convert domain.msh domain.xml
size = 0.1;
len = 1;
rad = 0.2;
// Quarter domain
Point(1) = {0, 0, 0, size};
Point(2) = {len, 0, 0, size};
Point(3) = {len, len, 0, size};
Point(4) = {0, len, 0, size};
// Circle
Point(5) = {rad, 0, 0, size};
Point(6) = {0, rad, 0, size};
Line(1) = {1, 5};
Line(2) = {5, 2};
Line(3) = {2, 3};
Line(4) = {3, 4};
Line(5) = {4, 6};
Line(6) = {6, 1};
Circle(7) = {5, 1, 6};
Line Loop(1) = {7, 6, 1};
Plane Surface(1) = {1};
Physical Surface(1) = {1}; // Inside circle
Line Loop(2) = {5, -7, 2, 3, 4};
Plane Surface(2) = {2};
Physical Surface(2) = {2}; // Outside
// The rest by symmetry
vols[] = Symmetry {1, 0, 0, 0} {Duplicata { Surface{2}; Surface{1}; }};
Physical Surface(1) += {vols[1]};
Physical Surface(2) += {vols[0]};
vols[] = Symmetry {0, -1, 0, 0} {Duplicata { Surface{vols[0]}; Surface{vols[1]}; }};
Physical Surface(1) += {vols[1]};
Physical Surface(2) += {vols[0]};
vols[] = Symmetry {-1, 0, 0, 0} {Duplicata { Surface{vols[0]}; Surface{vols[1]}; }};
Physical Surface(1) += {vols[1]};
Physical Surface(2) += {vols[0]};