Hello,
I successfully minimized the energy of a strained sheet for the displacement field (2d vector). However, when I add the tensorial field q_{\alpha\beta} to the energy, A^{\alpha\beta\gamma\delta}q_{\alpha\beta}q_{\gamma\delta}, the resulting energy becomes 300 orders of magnitude higher, 2.3046e+302 instead of 0.02325. Of course, this doesn’t make sense because the tensorial field could have vanished, so the energy would not have changed. What did I do wrong?
Here is a minimal working example:
import ufl
from ufl import *
import dolfinx
from dolfinx import *
from mpi4py import MPI
from petsc4py import PETSc
from petsc4py.PETSc import ScalarType
import numpy as np
domain = dolfinx.mesh.create_unit_square(MPI.COMM_WORLD, 10, 10)
#The trial functions are the 2d vector u and the degree 2 tensor q
VFS = ufl.VectorElement('CG',domain.ufl_cell(),1, dim=2)
TFS = ufl.TensorElement('CG', domain.ufl_cell(),degree=2)
mel = MixedElement([VFS,TFS])
V = dolfinx.fem.FunctionSpace(domain, VFS)
Q = dolfinx.fem.FunctionSpace(domain, TFS)
Y = dolfinx.fem.FunctionSpace(domain, mel)
y = fem.Function(Y)
u, q = ufl.split(y)
yt = ufl.TestFunction(Y)
v,p = ufl.split(yt)
#impose clamped boundary conditions
def lower_boundary(x):
return np.isclose(x[1],0);
def upper_boundary(x):
return np.isclose(x[1],1);
fdim = domain.topology.dim - 1
boundary_facets_up = mesh.locate_entities_boundary(domain, fdim, upper_boundary)
dofs_up = fem.locate_dofs_topological(V, fdim, boundary_facets_up)
u_up = ScalarType((0,0.1))
bc_up = fem.dirichletbc(u_up, dofs_up, V)
boundary_facets_down = mesh.locate_entities_boundary(domain, fdim, lower_boundary)
dofs_down = fem.locate_dofs_topological(V, fdim, boundary_facets_down)
u_down = ScalarType((0,-0.1))
bc_down = fem.dirichletbc(u_down, dofs_down, V)
bc = [bc_up, bc_down]
#The energy
mu = 0.4
Lambda = 0.5
tdim=domain.topology.dim
# define strain and stress
def epsilon(u):
return sym(grad(u))
def sigma(u):
return 2*mu*epsilon(u) + Lambda*tr(epsilon(u))*Identity(tdim)
def sigmaq(q):
return 2*mu*q + Lambda*tr(q)*Identity(q.ufl_shape[0])
Energy = 1/2*inner(sigma(u),epsilon(u))*dx+1/8*inner(sigmaq(q),q)*dx
# Minimization
Res = derivative(Energy, y, yt)
problem = fem.petsc.NonlinearProblem(Res, y, bcs=bc)
solver = nls.petsc.NewtonSolver(MPI.COMM_WORLD, problem)
solver.convergence_criterion = "incremental"
solver.rtol = 1e-6
solver.report = True
ksp = solver.krylov_solver
opts = PETSc.Options()
option_prefix = ksp.getOptionsPrefix()
opts[f"{option_prefix}ksp_type"] = "cg"
opts[f"{option_prefix}pc_type"] = "gamg"
opts[f"{option_prefix}pc_factor_mat_solver_type"] = "mumps"
ksp.setFromOptions()
log.set_log_level(log.LogLevel.INFO)
n, converged = solver.solve(y)
assert(converged)
print(f"Number of interations: {n:d}")
print("Energy = ", fem.assemble_scalar(fem.form(Energy)))