Hi! I’m trying to model the tissue growth of an embryo using the hyperelastic example. I’m interested in the internal displacements.
I show here an example script which is somehow similar to the real thing: an initial circle is stretched by means of a force into its final shape. The force is variable with time (first points downthen up). This is done in 40 separate time steps:
Now imagine you want to track a “cell”. I do it by applying the computed sequence of displacements to a whatever point on the plane: these are the colored lines. The end point of these are the final position of the “cell”. Now I invert the displacement vectors, and in principle they should be walking back to where they started: these are the black lines.
While overall it seems to work well, there is a small discrepancy between the 2 lines (colored and black). I wonder if you have any idea why is that, maybe it’s something to be expected? Or can be further improved? Or am I doing something wrong?
I also tested with doing a remeshing at each step - instead of keeping the same mesh - and it doesn’t seem to change much (which is very good!):
Thanks a lot for your help!
The code:
from dolfin import *
from mshr import *
import numpy as np
import vedo
set_log_level(30)
class AllBoundaries(SubDomain):
def inside(self, x, on_boundary):
return on_boundary and x[0]<-10
def solve_problem(mesh, mfunc, force):
V = VectorFunctionSpace(mesh, "CG", 1)
u = TrialFunction(V)
v = TestFunction(V)
displacement = Function(V)
bc = [DirichletBC(V, Constant((0,0)), mfunc, 1)]
F = Constant(force)
E = Constant(5000)
nu = Constant(0.3)
mu = E / (2.0*(1+nu))
lmbda = E * nu / ((1.0+nu) * (1-2*nu))
sigma = 2.0 * mu * sym(grad(u)) + lmbda * tr( sym(grad(u)) ) * Identity(2)
solve(inner(sigma, grad(v)) * dx == inner(F, v) * dx, displacement, bc)
displacement.set_allow_extrapolation(True)
return displacement
def update(mesh, displacement):
new_mesh = Mesh(mesh)
ALE.move(new_mesh, displacement)
return new_mesh
def remesh(mesh, res=50):
if isinstance(mesh, vedo.Mesh):
vmesh = mesh
else:
vmesh = vedo.Mesh([mesh.coordinates(), mesh.cells()])
bpts = vmesh.computeNormals(cells=True).boundaries().join(reset=1) #extract boundary
vz = vmesh.celldata["Normals"][0][2] # check z component of normals at first point
bpts.tomesh(invert=vz<0).smooth().write('tmpmesh.xml') #vedo REMESHING + smoothing
return Mesh("tmpmesh.xml")
#################################################################################
N = 40 # number of iterations of stretching
res = 15 # resolution of meshes
do_remesh = False # grab the boundary and remesh the interior at each iteration
vedo.settings.useParallelProjection = True # avoid perspective parallax
circle = Circle(Point(0, 0), 50)
mesh = generate_mesh(circle, res)
meshes = [mesh]
displacements = []
for i in range(N):
mfunc = MeshFunction('size_t', mesh, 1, mesh.domains())
mfunc.set_all(0)
allb = AllBoundaries()
allb.mark(mfunc, 1)
F = np.array([2, (i-N/2)/N])
displacement = solve_problem(mesh, mfunc, F)
new_mesh = update(mesh, displacement)
if do_remesh:
mesh = remesh(new_mesh)
else:
mesh = new_mesh
meshes.append(mesh)
displacements.append(displacement)
# plot things:
txt = vedo.Text2D(f"step{i}")
arrow = vedo.Arrow2D([0,0], F*20).z(1)
vedo.dolfin.plot(mesh, arrow, txt, c='grey5', at=i, N=N, zoom=1.1) # PRESS q to continue
dmesh_i = meshes[0] # initial mesh
dmesh_f = meshes[-1] # final mesh
vmesh_i = vedo.Mesh([dmesh_i.coordinates(), dmesh_i.cells()], c='grey5').z(-1)
vmesh_f = vedo.Mesh([dmesh_f.coordinates(), dmesh_f.cells()], c='grey3').wireframe()
plt = vedo.Plotter()
# move a few points along the deformation of the circle
seeds = vedo.Circle(r=50, res=res).points()
endpoints = []
for i, p in enumerate(seeds):
line = [p]
for disp in displacements:
dp = disp([p[0], p[1]])
newp = p + [dp[0],dp[1], 0.0]
line.append(newp)
p = newp
plt += vedo.Line(line, c=i, lw=4).z(1)
endpoints.append(newp)
# invert everything and move the end points back in place
seeds = list(reversed(endpoints))
displacements = list(reversed(displacements))
for i, p in enumerate(seeds):
line = [p]
for disp in displacements:
dp = disp([p[0], p[1]])
newp = p - [dp[0],dp[1], 0.0]
line.append(newp)
p = newp
plt += vedo.Line(line, c='k', lw=2).z(2)
plt += [vmesh_i, vmesh_f]
plt.show(axes=1)