hi
Currently, I am using the dolfinx library.
I was studying the dolfinx library by myself, and many questions arose, so I wrote a post on the forum.
Condensing the questions into three,
1] Minor question?: The dolfinx library does not use docker, it is directly installed on ubuntu 22.04, and the version is assumed to be 0.4.1. Is there a separate way to check the dolfinx version?
2] To study the dolfinx library, I made an example of applying an external force to the simple 2D cantilever (spanning [0,L]\times[0,H]) as shown below.
Compared with the reliable results obtained from the dolfin library, there is a difference and I think that there is an error when grafting the given formula condition to the code.
(Afterwards, in the example code, L(nelx
) was applied as 2, and H(nely
) was also applied as 2)
The formula can be rearranged as:
governing equation: -\nabla\cdot\sigma(\mathbf{u})=0
Dirichlet boundary condition(clamp): \mathbf{u}=0 at \partial\Omega_{D} (left of cantilever beam)
External load: \textbf{F}_{T}=-1 on \partial\Omega_{N}(for y-direction)
Then, using Cauchy stress tensor and strain energy equation such that
Cauchy stress tensor: \sigma(\mathbf{u})=\lambda\textrm{tr}(\epsilon(\mathbf{u}))\textit{I}\ +2\mu\epsilon(\mathbf{u})
Strain energy equation: \psi(\mathbf{u})=\frac{\lambda}{2}\{\textrm{tr}(\epsilon(\mathbf{u}))\}^{2}\ + \mu\textrm{tr}(\epsilon(\mathbf{u})^{2})
(\epsilon(\mathbf{u})=\frac{1}{2}(\nabla\mathbf{u}\ + (\nabla\mathbf{u})^{T})=sym(\nabla\mathbf{u}), \lambda=0.6, \mu=0.4)
The code using the dolfinx library is written as follows
import ufl
import numpy as np
from dolfinx import fem, mesh
from mpi4py import MPI
from petsc4py import PETSc
Declare the input variables
nelx = 2
nely = 2
volfrac = 0.5
penal = 3
Setting preliminaries
sigma = lambda _u: 2.0 * mu * ufl.sym(ufl.grad(_u)) + lmd * ufl.tr(ufl.sym(ufl.grad(_u))) * ufl.Identity(len(_u))
psi = lambda _u: lmd / 2 * (ufl.tr(ufl.sym(ufl.grad(_u))) ** 2) + mu * ufl.tr(ufl.sym(ufl.grad(_u)) * ufl.sym(ufl.grad(_u)))
mu, lmd = PETSc.ScalarType(0.4), PETSc.ScalarType(0.6)
Prepare finite element analysis
msh = mesh.create_rectangle(MPI.COMM_WORLD, ((0.0, 0.0), (nelx, nely)), (nelx, nely), cell_type=mesh.CellType.triangle)
U = fem.VectorFunctionSpace(msh, ("CG", 1))
D = fem.FunctionSpace(msh, ("DG", 0))
u, v = ufl.TrialFunction(U), ufl.TestFunction(U)
u_sol, density = fem.Function(U), fem.Function(D)
density.x.array[:] = volfrac
Define support
def left_clamp(x):
return np.isclose(x[0], 0.0)
f_dim = msh.topology.dim - 1
bc_facets = mesh.locate_entities_boundary(msh, f_dim, left_clamp)
u_zero = np.array([0.0, 0.0], dtype=PETSc.ScalarType)
bc_l = fem.dirichletbc(u_zero, fem.locate_dofs_topological(U, f_dim, bc_facets), U)
bcs = [bc_l]
Define external load
load_points = [(1, lambda x: np.logical_and(x[0]==nelx, x[1]<=2))]
facet_indices, facet_markers = [], []
for (marker, locator) in load_points:
facets = mesh.locate_entities(msh, f_dim, locator)
facet_indices.append(facets)
facet_markers.append(np.full(len(facets), marker))
facet_indices = np.array(np.hstack(facet_indices), dtype=np.int32)
facet_markers = np.array(np.hstack(facet_markers), dtype=np.int32)
sorted_facets = np.argsort(facet_indices)
facet_tag = mesh.meshtags(msh, f_dim, facet_indices[sorted_facets], facet_markers[sorted_facets])
ds = ufl.Measure("ds", domain=msh, subdomain_data=facet_tag)
f = ufl.dot(v, fem.Constant(msh, PETSc.ScalarType((0.0, -1.0)))) * ds(1)
Set up the variational problem and solver (using SIMP)
k = ufl.inner(density ** penal * sigma(u), ufl.grad(v)) * ufl.dx
problem = fem.petsc.LinearProblem(k, f, bcs)
u_sol = problem.solve()
Then, the result for u_sol
array is
array([-17.05014904, -31.16299225, -23.40409419, -70.10238634,
-1.23442586, -66.45633149, 0.17561615, -26.80259435,
0. , 0. , 20.43334505, -65.04736033,
0. , 0. , 15.06233617, -27.34430426,
0. , 0. ])
the result I want to get (reliable results from code written with the dolfin library)
array([ 2.19098143e+01, -6.77188329e+01, 4.26325641e-15, -6.44827586e+01,
1.51458886e+01, -2.69893899e+01, -1.51458886e+01, -2.69893899e+01,
0.00000000e+00, 0.00000000e+00, 1.08212540e-15, -2.81564987e+01,
-2.19098143e+01, -6.77188329e+01, 0.00000000e+00, 0.00000000e+00,
0.00000000e+00, 0.00000000e+00])
I think that different results were obtained because of wrong coding when applying boundary condition or external load. Which part of the code could be considered bad?
3] Declare ‘FunctionSpace’ in the dolfinx environment, and arosed question how to convert the calculated value stored in the ‘FunctionSpace’ location to a numpy array.
Extending the above code example,
Assuming that the u_sol value is well obtained, how to map this value to a numpy array?
(In the dolfin library, mapping was done as ‘project’)
project(psi(u_sol), D0).vector()[:]
(but I do not know how to do it in the dolfinx library.)