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

solving the elastic wave equation in two domains with different materials

+1 vote

My problem involves solving the equation on the form:

$$\frac{\partial^2 \vec{u}}{\partial t^2} = \frac{1}{\rho}\nabla \cdot P$$

Where u is the displacement vector, $\rho$ is the density and P is the stress tensor given as:

$$P = \lambda(\nabla \cdot \vec{u})I + \mu (\nabla \vec{u} + \nabla \vec{u}^T)$$

I solve this in two domains with different material properties $\lambda$, $\mu$ and $\rho$. I use an explicit second order difference method for the time variable, and FEM for the spatial variables. This gives a variational form:

$$\int_{\Omega}\vec{u}^{(n+1)}\cdot \vec{v}d\Omega = \int_{\Omega}(2\vec{u}^{(n)} - \vec{u}^{(n-1)})\cdot \vec{v} d\Omega + \int_{\Gamma}\vec{n} \cdot P^{(n)} \cdot \vec{v} d\Gamma - \
\int_{\Omega}P^{(n)} : \nabla \vec{v} d\Omega $$
where n denotes the value at time n. I have attached a simplified code with given initial conditions.

from dolfin import *

# Constants
ys = 1
t = 0
dt = 0.01
T = 10 
rho1 = 1
rho2 = 10
mu1 = 1
mu2 = 0
lamda1 = 1
lamda2 = 1

# Mesh, functionspace, functions
mesh = RectangleMesh(0,0,2,2,20,20)
V = VectorFunctionSpace(mesh, "CG", 1)
D = VectorFunctionSpace(mesh, "DG", 0)
u = TrialFunction(V)
v = TestFunction(V)

# Define Subdomains
cf = CellFunction("size_t", mesh, 0)
domain1 = AutoSubDomain(lambda x: x[1] > ys)
domain1.mark(cf,1)

# Define variable constants
rhof = Expression(("x[1] > ys ? rho1 : rho2",
                   "x[1] > ys ? rho1 : rho2"),
                  ys=ys,rho1=rho1,rho2=rho2)
muf = Expression(("x[1] > ys ? mu1 : mu2",
                  "x[1] > ys ? mu1 : mu2"),
                 ys=ys,mu1=mu1,mu2=mu2)
lamdaf = Expression(("x[1] > ys ? lamda1 : lamda2",
                     "x[1] > ys ? lamda1 : lamda2"),
                    ys=ys,lamda1=lamda1,lamda2=lamda2)
stepf = Expression(("x[1] > ys ? pow(dt,2)/rho1 : pow(dt,2)/rho2",
                    "x[1] > ys ? pow(dt,2)/rho1 : pow(dt,2)/rho2"),
                   ys=ys,dt=dt,rho1=rho1,rho2=rho2)

rho = interpolate(rhof, D)
mu = interpolate(muf, D)
lamda = interpolate(lamdaf, D)
step = interpolate(stepf, D)

# Stress tensor
def sigma(u, lamda, mu):
    return lamda*div(u)*Identity(2) + mu*(grad(u) + grad(u).T)

# Initial conditions
Ixy = Constant((1,0))
Vxy = Constant((2,0))
u2 = interpolate(Ixy, V)
u1 = interpolate(Vxy, V)

# Variational forms
F = inner(u,v)*dx - 2*inner(u1,v)*dx + inner(u2,v)*dx + \
    step*inner(sigma(u1,lamda,mu),grad(v))*dx

t = 2*dt
left = assemble(lhs(F))
u = Function(V)

# Time stepping
while t < T + DOLFIN_EPS:
    plot(u2, rescale=False)
    right = assemble(rhs(F))
    begin("solving at time step t=%g" % t)
    solve(left, u.vector(), right)
    end()

    u2.assign(u1)
    u1.assign(u)

I'm guessing fenics does not like the expression objects for the variable constants, but some advice is needed here. Is there a way to get around this with the current definitions, or is there a way to get around this by following the same logic as in the fenics tutorial for vectorized functions as described in the chapter "Handling Domains with different materials"? Any help is greatly appreciated!

The error message is
daniel@satelite:~/masteroppgave/py$ python question.py
Product can only represent products of scalars.
Traceback (most recent call last):
File "question.py", line 59, in
stepinner(sigma(u1,lamda,mu),grad(v))dx
File "question.py", line 49, in sigma
return lamdadiv(u)Identity(2) + mu(grad(u) + grad(u).T)
File "/usr/lib/python2.7/dist-packages/ufl/exproperators.py", line 181, in _mul
return _mult(self, o)
File "/usr/lib/python2.7/dist-packages/ufl/exproperators.py", line 154, in _mult
p = Product(a, b[ii])
File "/usr/lib/python2.7/dist-packages/ufl/algebra.py", line 174, in new
error("Product can only represent products of scalars.")
File "/usr/lib/python2.7/dist-packages/ufl/log.py", line 154, in error
raise self._exception_type(self._format_raw(
message))
ufl.log.UFLException: Product can only represent products of scalars.
daniel@satelite:~/masteroppgave/py$

asked Aug 13, 2014 by danieljt FEniCS Novice (410 points)
edited Aug 14, 2014 by danieljt

Shouldn't your material properties be scalar expressions?

Yes, the material properties should by definition be scalars, but fenics seems to work directly with components of the vector equation, so I am forced to set the constants for both the x and y directions for the forms to work. I have tried with scalar values by using FunctionsSpace without success, but I'll try and find the code and post the error! I think I could also be saved by defining a Constant object with variable values if this is possible, or doing the same procedure as in the tutorial for vector equations, but I'm no expert on the field!

I also see that the last term to the right hand side of my variational form has disappeared to the right. I'll try and fix it, but the last part should be:

$$-\int_{\Omega}P^{(n)}:\nabla \vec{v} d\Omega$$

You can define the material properties as

D = FunctionSpace(mesh, "DG", 0)

# Define variable constants
rhof = Expression("x[1] > ys ? rho1 : rho2",
                  ys=ys,rho1=rho1,rho2=rho2)
muf = Expression("x[1] > ys ? mu1 : mu2",
                 ys=ys,mu1=mu1,mu2=mu2)
lamdaf = Expression("x[1] > ys ? lamda1 : lamda2",
                    ys=ys,lamda1=lamda1,lamda2=lamda2)

rho = interpolate(rhof, D)
mu = interpolate(muf, D)
lamda = interpolate(lamdaf, D)

I would also (for clarity) include dt in the variational form:

F = inner(u,v)*dx - 2*inner(u1,v)*dx + inner(u2,v)*dx + \
    Constant(dt)**2/rho*inner(sigma(u1,lamda,mu),grad(v))*dx

Thank you øyvind, the program I had is now running with your fixes. I'll do some more tests on my original program, but if you set your advice as an answer I'll mark this question as solved.

1 Answer

+1 vote
 
Best answer

You can define the material properties as scalars rather than vectors, like this:

D = FunctionSpace(mesh, "DG", 0)

# Define variable constants
rhof = Expression("x[1] > ys ? rho1 : rho2",
                  ys=ys,rho1=rho1,rho2=rho2)
muf = Expression("x[1] > ys ? mu1 : mu2",
                 ys=ys,mu1=mu1,mu2=mu2)
lamdaf = Expression("x[1] > ys ? lamda1 : lamda2",
                    ys=ys,lamda1=lamda1,lamda2=lamda2)

rho = interpolate(rhof, D)
mu = interpolate(muf, D)
lamda = interpolate(lamdaf, D)

I would also (for clarity) include dt in the variational form:

F = inner(u,v)*dx - 2*inner(u1,v)*dx + inner(u2,v)*dx + \
    Constant(dt)**2/rho*inner(sigma(u1,lamda,mu),grad(v))*dx
answered Aug 15, 2014 by Øyvind Evju FEniCS Expert (17,700 points)
selected Aug 23, 2014 by danieljt

Thank you very much øyvind! That solved the problem!

...