Mesh deformation results in ripping of geometry

Hello all,
I am trying to create an inflation simulation in NGSolve by minimizing the potential energy functional which is calculated by the stresses on the boundary - the work done by inflation, i.e. the functional and it’s derivative are given by

VEC = VectorH1(mesh, order=2, dim=mesh.dim)

p_cf = CoefficientFunction(p)
F    = Id(mesh.dim) + Grad(u)

F_bnd = Id(mesh.dim) + Grad(u).Trace()

W    = neo_hookean_energy_nonneg(F_bnd, mu, lmbda)

E_bnd = W*ds
E_vol = -p_cf*dx


S_bnd = E_bnd.DiffShape(X)
S_vol = E_vol.DiffShape(X)

S = S_bnd + S_vol
dJOmegaAuto = LinearForm(VEC)
dJOmegaAuto += S

This works without any errors.

However, when I try using this to compute the deformation on my test cube, I see ‘discontinuities’ in my mesh:

For the optimization, I am using the following code:

from math import isfinite
Qk = 1.0                     # Zhang–Hager running weights
Ck = None                    # Zhang–Hager reference value (set on first call)

def zh_ls(Jold, g_vec, direction_gf, phi_gf, *, descent=True,
          c1=1e-3, shrink=0.5, max_backtracks=30, move_frac=0.3,
          alpha_hint=None, theta=0.85):
    """
    Zhang-Hager non-monotone Armijo line search.
    """

    global Qk, Ck

    # --- boundary move-limit initial α ---
    bm = float(Integrate(1, mesh, BND))
    if bm <= 0:
        return 0.0, Jold
    rms_b = (Integrate(InnerProduct(direction_gf, direction_gf), mesh, BND)/bm + 1e-30)**0.5
    if rms_b == 0.0:
        return 0.0, Jold

    alpha_ml = move_frac * hmax / rms_b
    alpha = alpha_ml if alpha_hint is None else min(alpha_hint, alpha_ml)

    # set reference Ck on first call
    if Ck is None:
        Ck = Jold

    # directional derivative at 0
    gTd = float(InnerProduct(g_vec, direction_gf.vec))
    if not descent:
        gTd = -gTd   # reuse same inequality by flipping sign convention below

    # --- snapshot & trial ---
    phi_old = phi_gf.vec.CreateVector(); phi_old.data = phi_gf.vec
    trial   = phi_gf.vec.CreateVector()

    def ok(Jnew, a):
        rhs = Ck + c1 * a * ( -gTd if not descent else gTd )
        return Jnew <= rhs

    for _ in range(max_backtracks):
        trial.data = phi_old
        trial.data += alpha * direction_gf.vec

        # commit trial deformation
        phi_gf.vec.data = trial
        mesh.SetDeformation(phi_gf)

        # u := trial deformation for surface energy
        gfu.vec.data = trial
        Jnew = float(Integrate(energy_functional_nonneg(gfu), mesh))
        if not isfinite(Jnew):
            alpha *= shrink
            continue

        if ok(Jnew, alpha):
            # update Zhang-Hager reference
            Qk1 = theta*Qk + 1.0
            Ck  = (theta*Qk*Ck + Jnew) / Qk1
            Qk  = Qk1
            return alpha, Jnew

        alpha *= shrink

    # revert on failure
    phi_gf.vec.data = phi_old
    mesh.SetDeformation(phi_gf)
    gfu.vec.data = phi_old
    return 0.0, Jold

The output rendered is generated by

fes = VectorH1(mesh, order=2, dirichlet=".*")
gfu = GridFunction(fes)
scene_u = Draw (gfu, mesh, "state")

and then updated as in the Zhang-Hager code snippet. Where could this error originate from? I am thinking that this might be related to the fact that I am using two different H1 spaces (VEC for the shape derivative and fes in the rendering snippet), but I wanted to make sure that I am not missing any crucial information regarding the inner workings of NGsolve (i.e. a rendering bug or some flag that I forgot to set).

Kind regards

Hi,
VectorH1 and H1(mesh, dim=mesh.dim) are not equivalent, they store their coefficients in different order. Best would be to use the same space for both, else either use Set or transform the vectors correctly.

VectorH1 stores its coefficients as cx1, cx2, cx3,… cy1, cy2, … cz1, cz2, …
H1(dim=3) stores as cx1, cy1, cz1, cx2, cy2, …

Thank you for your response. I now changed gfu = GridFunction(VEC) (I do not use fes anywhere else in my code), but my body still looks like this

(but the transformation does indeed look more natural)

Any ideas?

can you send a simple complete example producing such an output ?
The NGSolve Draw of a continuous function should produce a continuous deformation.

Joachim

Hi, and thanks for your reply - I’ve attached a cleaned-up version of my code as a Jupyter notebook, reproducing the bug on my computer. May the bug even stem from the fact that my deformation tensor is wrongly assembled by adding Trace() on the gradient of u?

sim_inf_min.ipynb (11.9 KB)

looks like you generate a singular matrix, what I get is:

NgException: UmfpackInverse: Numeric factorization failed.

I assume that the error is thrown in SolveDeformationEquationAuto by the matrix b? For me, this code block runs without any issues:

image

If the error is thrown elsewhere, please let me know, but the whole notebook runs without throwing for me.

VEC = VectorH1(mesh, order=2, dim=mesh.dim)

is not what you want I think, VectorH1 has alreay mesh.dim compoments.
Use it without the dim argument.

Ah, I see - this fixed the error for me, thank you so much!