Hello everyone,
I am trying to model subdomains in the FEniCS. I am able to do that with UserExpression but it makes the code slow. Therefore, I tried to used C++ code snippets.
I follow the C++ userexpression from this link: Bitbucket
My code is as follows
from fenics import *
from mshr import *
import matplotlib.pyplot as plt
from ufl import nabla_div
nu = 0.3
domain = Rectangle(Point(0.0, 0.0), Point(100.0, 100.0))
mesh = generate_mesh(domain, 32)
V = VectorFunctionSpace(mesh, 'P', 1)
tol = 1e-14
class Omega_0(SubDomain):
def inside(Self, x, on_boundary):
return x[1] <= 0.5+tol
class Omega_1(SubDomain):
def inside(Self, x, on_boundary):
return x[1] >= 0.5+tol
materials = MeshFunction("double", mesh, mesh.topology().dim(), 0)
subdomain_0 = Omega_0()
subdomain_1 = Omega_1()
subdomain_0.mark(materials, 0)
subdomain_1.mark(materials, 1)
cpp_code = """
#include <pybind11/pybind11.h>
#include <pybind11/eigen.h>
namespace py = pybind11;
#include <dolfin/function/Expression.h>
#include <dolfin/mesh/MeshFunction.h>
class K : public dolfin::Expression
{
public:
K() : dolfin::Expression(1) {}
void eval(Eigen::Ref<Eigen::VectorXd> values, Eigen::Ref<const Eigen::VectorXd> x, const ufc::cell& cell) const override
{
if ((*materials)[cell.index] == 0)
values[0] = 200E3;
else
values[0] = 20E3;
}
std::shared_ptr<dolfin::MeshFunction<double>> materials;
};
PYBIND11_MODULE(SIGNATURE, m)
{
py::class_<K, std::shared_ptr<K>, dolfin::Expression>
(m, "K")
.def(py::init<>())
.def_readwrite("materials", &K::materials);
}
"""
E_1 = CompiledExpression(compile_cpp_code(cpp_code).K(),
materials= materials, degree=0)
lambda_1 = (E_1*nu)/((1+nu)*(1-2*nu))
mu_1 = E_1/(2*(1+nu))
def boundary_D_y(x, on_boundary):
return on_boundary and near(x[1], 0, tol)
def boundary_D_x(x, on_boundary):
return near(x[1], 0, tol) and near(x[0], 0, tol)
bc_y = DirichletBC(V.sub(1), Constant(0), boundary_D_y)
bc_x = DirichletBC(V, Constant((0, 0)), boundary_D_x, method='pointwise')
bcs = [bc_y, bc_x]
class boundary_N_y(SubDomain):
def inside(self, x, on_boundary):
return on_boundary and near(x[1], 100, tol)
boundary_markers = MeshFunction("size_t", mesh, mesh.topology().dim()-1, 0)
B_N_Y = boundary_N_y()
B_N_Y.mark(boundary_markers, 1)
ds = Measure('ds', domain=mesh, subdomain_data=boundary_markers)
def epsilon(u):
return 0.5*(nabla_grad(u) + nabla_grad(u).T)
def sigma(u):
return lambda_1*nabla_div(u)*Identity(d) + 2*mu_1*epsilon(u)
u = TrialFunction(V)
d = u.geometric_dimension()
v = TestFunction(V)
T = Constant((0, 100)) # Applied load
a = inner(sigma(u), epsilon(v))*dx
L = dot(T, v)*ds(1)
u = Function(V)
solve(a == L, u, bcs)
The compilation of this code, leads to the following error
Invalid ranks 1 and 2 in product.
Traceback (most recent call last):
File “Case_0_0.py”, line 118, in
a = inner(sigma(u), epsilon(v))dx
File “Case_0_0.py”, line 111, in sigma
return lambda_1nabla_div(u)Identity(d) + 2mu_1*epsilon(u)
File “/usr/lib/python3/dist-packages/ufl/exproperators.py”, line 182, in _mul
return _mult(self, o)
File “/usr/lib/python3/dist-packages/ufl/exproperators.py”, line 156, in _mult
error(“Invalid ranks {0} and {1} in product.”.format(r1, r2))
File “/usr/lib/python3/dist-packages/ufl/log.py”, line 158, in error
raise self._exception_type(self._format_raw(*message))
ufl.log.UFLException: Invalid ranks 1 and 2 in product.
It is my first time to use C++ expression. Can you please guide me me how I can fix the error in the code.
Thanks
Manish