This is a read only copy of the old FEniCS QA forum. Please visit the new QA forum to ask questions

Integrating forces on the boundary

+2 votes

I am trying to integrate the traction forces on the boundary of a domain in a simple elasticity problem. My aim is to calculate total reaction forces on the Dirichlet boundary. The setting is so:

A domain the shape of a unit square is clamped on its left end, and is subjected to a traction force (1,1) on its right end.

I want to integrate the tractions on both the left and right boundaries and for the x and y directions. To this end, I prepared the following forms for x and y directions

$$F_x = \int_{\partial \Omega'} \delta u (\boldsymbol{\sigma}\mathbf{n})\cdot\mathbf{e}_x\;\mathrm{d}A$$
$$F_y = \int_{\partial \Omega'} \delta u (\boldsymbol{\sigma}\mathbf{n})\cdot\mathbf{e}_y\;\mathrm{d}A$$

where $\partial\Omega'\subset\partial\Omega$ is the part of the boundary that I want to integrate on, $\delta u$ is a scalar test function, $\mathbf{n}$ is the normal to the surface, $\mathbf{e}_x=(1,0)$ and $\mathbf{e}_y=(0,1)$ are the basis vectors for the x and y directions, and $\mathrm{d}A$ is the area of the boundary (edge length in 2D).

I have modified a linear elasticity problem to do these calculations:

from dolfin import *

mesh = UnitSquareMesh(32, 32)
V = VectorFunctionSpace(mesh, "Lagrange", 1)

# Sub domain for clamp at left end
def left(x, on_boundary):
    return x[0] < DOLFIN_EPS and on_boundary

# Sub domain for force at right end
def right(x, on_boundary):
    return x[0] > 1 - DOLFIN_EPS and on_boundary

# Material parameters
kappa = 1.0
mu = 1.0

Du = TrialFunction(V)
du = TestFunction(V)
u  = Function(V)

# The force on the right boundary
f  = Constant((1.0, 1.0))

ex  = Constant((1.0, 0.0))
ey  = Constant((0.0, 1.0))

I = Identity(len(u))

n = FacetNormal(mesh)

# Create mesh function over the cell facets
boundary_subdomains = MeshFunction("size_t", mesh, mesh.topology().dim() - 1)
boundary_subdomains.set_all(0)
AutoSubDomain(left).mark(boundary_subdomains, 1)
AutoSubDomain(right).mark(boundary_subdomains, 2)

dss = ds(subdomain_data=boundary_subdomains)

zero = Constant((0.0, 0.0))
dirichlet_val = Constant((1.0, 0.0))
bcs = DirichletBC(V, zero, left)

eps = sym(grad(u))
deps = sym(grad(du))

sigma = kappa * tr(eps) * I + 2 * mu * dev(eps)

F = inner(deps, sigma) * dx - inner(f, du) * dss(2)
J = derivative(F, u, Du)

solve(F == 0, u, bcs, J=J)

# Integrate the forces
scalar_space = FunctionSpace(mesh, "CG", 1)
normal_stresses = Function(scalar_space)
test_function = TestFunction(scalar_space)

fx_left = test_function * dot(dot(sigma, n), ex) * dss(1)
fx_right = test_function * dot(dot(sigma, n), ex) * dss(2)

fy_left = test_function * dot(dot(sigma, n), ey) * dss(1)
fy_right = test_function * dot(dot(sigma, n), ey) * dss(2)

traction_x_left = assemble(fx_left)
traction_x_right = assemble(fx_right)

traction_y_left = assemble(fy_left)
traction_y_right = assemble(fy_right)

total_force_x_left = traction_x_left.sum()
total_force_x_right = traction_x_right.sum()

total_force_y_left = traction_y_left.sum()
total_force_y_right = traction_y_right.sum()

print("%f ?= 0"%(total_force_x_left + total_force_x_right))
print("%f ?= 0"%(total_force_y_left + total_force_y_right))

The last two lines test whether $(F_x)_\text{left} + (F_x)_\text{right} = 0$ and $(F_y)_\text{left} + (F_y)_\text{right} = 0$, which should be satisfied for the balance of momentum. However, I get the following output:

0.251940 ?= 0
-0.124432 ?= 0

The solution should be $(F_x)_\text{left} = -1$, $(F_y)_\text{left} = -1$, $(F_x)_\text{right} = 1$ and $(F_y)_\text{right} = 1$, but it's not for some reason, and it can't seem to satisfy the balance equation. Can anyone tell me what I am doing wrong?

asked Feb 20, 2017 by hosolmaz FEniCS User (1,510 points)
edited Feb 20, 2017 by hosolmaz

I figured this out so you don't need to try to answer. It will take me some time to post the answer though.

Hello,
I looked at your example and I a very interesting by the solution you find.
I have the same problem.
Thanks

2 Answers

0 votes
 
Best answer

In the meantime, I figured out the solution to my problem.

What I suggested in the question was that differentially, the following equality must hold

$$
\int_{\partial \Omega^t} \delta \mathbf{u} \cdot (\boldsymbol{\sigma}\mathbf{n})\;\mathrm{d}A
= \int_{\partial \Omega^t} \delta \mathbf{u} \cdot \boldsymbol{\gamma}_\text{known} \;\mathrm{d}A
\tag{1}
$$

where $\boldsymbol{\gamma}_\text{known}$ is the traction on $\partial\Omega^t$, incorporated as a Neumann boundary condition.

However, this does not work very well when you are working with finite elements. The reason is that when you solve the problem

$$
\int_{\Omega} \delta \boldsymbol{\varepsilon}:\boldsymbol{\sigma}\;\mathrm{d}V
- \int_{\partial \Omega^{t}} \delta \mathbf{u} \cdot \boldsymbol{\gamma}_\text{known} \;\mathrm{d}A = 0
\tag{2}
$$

you obtain the solution vector $\mathbf{u}$ that satisfies (1).

The fact that the weak solution $\mathbf{u}$ satisfies (2) does not imply it will also satisfy (1), because the solution is a discretized one, and solving (1) would require

  1. the solution (2) for $\mathbf{u}$ by projecting it to the Gauss integration points,
  2. and re-projection of the stresses (evaluated at the nodes), back to the Gauss points.

The projections are where this error is introduced, which causes the slight difference from the expected result.

If we desire that our integrated value and given traction match, we need not look at any expression other than (2), just because (2) is the only equality that our discretized solution $\mathbf{u}$ satisfies. Since $\partial\Omega = \partial\Omega^t \cup \partial\Omega^u$, and (2) is satisfied for the given traction $\boldsymbol{\gamma}_\text{known}$, we must subtract the vectors assembled for (2) to obtain the unknown forces, i.e.

$$
F_\text{external, unknown} = F_\text{internal} - F_\text{external, known},.
$$

Then, we can use the degree of freedom map to sum the forces in the horizontal and vertical directions respectively. Here is a code that works for this problem

from dolfin import *
mesh = UnitSquareMesh(32, 32)

V = VectorFunctionSpace(mesh, "Lagrange", 1)

# Sub domain for clamp at left end
def left(x, on_boundary):
    return x[0] < DOLFIN_EPS and on_boundary

# Sub domain for rotation at right end
def right(x, on_boundary):
    return x[0] > 1 - DOLFIN_EPS and on_boundary

# Material parameters
kappa = 1.0
mu = 1.0

Du = TrialFunction(V)
du = TestFunction(V)
u  = Function(V)

# The force on the right boundary
f  = Constant((1.0, 1.0))

I = Identity(len(u))

n = FacetNormal(mesh)

# Create mesh function over the cell facets
boundary_subdomains = MeshFunction("size_t", mesh, mesh.topology().dim() - 1)
boundary_subdomains.set_all(0)
AutoSubDomain(left).mark(boundary_subdomains, 1)
AutoSubDomain(right).mark(boundary_subdomains, 2)

dss = ds(subdomain_data=boundary_subdomains)

zero = Constant((0.0, 0.0))
bcs = DirichletBC(V, zero, left)

eps = sym(grad(u))
deps = sym(grad(du))

sigma = kappa * tr(eps) * I + 2 * mu * dev(eps)

f_int = inner(deps, sigma) * dx
f_ext = inner(f, du) * dss(2)

F = f_int - f_ext
J = derivative(F, u, Du)

solve(F == 0, u, bcs, J=J)

f_ext_known = assemble(f_ext)
f_ext_unknown = assemble(f_int) - f_ext_known

x_dofs = V.sub(0).dofmap().dofs()
y_dofs = V.sub(1).dofmap().dofs()

Fx = 0
for i in x_dofs:
    Fx += f_ext_unknown[i]

Fy = 0
for i in y_dofs:
    Fy += f_ext_unknown[i]

# The following must be equal to -1 * f
print("Horizontal reaction force: %f"%(Fx))
print("Vertical reaction force: %f"%(Fy))

Note that if you a displacement controlled problem, namely only Dirichlet boundary conditions and no Neumann boundary conditions, you should use a different approach since you do not have an external force term in the problem.

answered Mar 9, 2017 by hosolmaz FEniCS User (1,510 points)
0 votes

Can you give the program with the good solution ?
I want exactly to solve the same problem and I got the same problem...

Thanks
Stéphane

answered Feb 28, 2017 by stephanepa FEniCS Novice (350 points)
edited Feb 28, 2017 by stephanepa
...