Brakke’s samples: crystals and elastic membranes

Energies that are not plain surface tension: a crystalline surface energy, and elastic membranes that remember their unstretched shape. relax() recognizes both and leaves the mesh as it is (no equiangulation or vertex averaging).

Each sample is run twice from its datafile: once with the recipe Brakke wrote into it (its gogo command, or the usage its comments describe), once with a default ev.relax() given as many refinements as the recipe does (levels). The table shows the energy each ends with, the residual (how far from equilibrium, see Relaxing a surface), the facet count, the time, and what relax() reports: converged, stable, and any health issues. A lower energy on the same mesh is not always the better answer: a coarse mesh can lower its energy in ways the smooth surface can’t, so where an exact value is known, the error against it is the measure. Times are from the documentation build and vary.

This gallery assumes Getting started and Relaxing a surface; its pages can be read in any order.

import numpy as np
import pyvista as pv
import pysurfaceevolver as pyse
import brakke_helpers as bh

pv.set_jupyter_backend("static")

crystal.fe: a crystal growing into its Wulff shape

A cube of fixed volume whose surface energy depends on each facet’s orientation through a set of Wulff vectors (octa.wlf). The minimizing shape is the Wulff shape of those vectors. A crystalline energy has a corner at its minimum, so the residual (a force balance) stays above zero there; Evolver has no Hessian for it either. relax() takes gradient rounds and counts the surface as converged once its energy settles (it says energy settled). The recipe is ten gradient steps.

print(bh.recipe("crystal.fe"))
runs = bh.compare("crystal.fe")
bh.show(runs)
g 10;
energyresidualfacetssecondsconvergedstablenotes
recipe: g 10;3.3712423813.0e+00400.00
relax(levels=0)3.3256067523.3e+00400.02yes
_images/f0de7e529825c25fe385732fed9261526022cedb3728ed139990b6482c9faf4f.png

relax() goes on until the energy settles (what a thousand plain gradient steps reach), past the recipe’s ten.

mylarcube.fe: a mylar balloon

A cube of mylar inflated to the most volume it can hold without stretching: a relaxed_elastic_A energy that resists stretching but lets the sheet wrinkle freely. The file redefines r to keep each facet’s reference shape and warns that any other retriangulation corrupts it; its recipe raises the elastic modulus as it refines and ends with hessian_seek. relax() takes the in-plane forces into its residual and uses hessian_seek for its Newton steps. Here relax() follows the recipe’s ramp: the same refinements, the modulus raised from 10 to 100, 1000 and 10000 at the same points.

print(bh.recipe("mylarcube.fe"))
recipe = bh.run_recipe("mylarcube.fe", label="recipe: gogo")

def ramp(ev):
    ev.relax(levels=1)
    ev.quantity("stretch").modulus = 100
    ev.relax(levels=2)
    ev.quantity("stretch").modulus = 1000
    ev.relax()
    ev.quantity("stretch").modulus = 10000
    return ev.relax()

import time
ev = pyse.Evolver("mylarcube.fe")
t = time.perf_counter()
r = ramp(ev)
relaxed = bh.Run("relax() along the same ramp", ev.total_energy, r.residual,
                 ev.counts["facets"], time.perf_counter() - t, r.converged, r.stable,
                 [], ev.mesh())
bh.table([recipe, relaxed])
bh.show([recipe, relaxed])
g 10; r; g 10; stretch.modulus := 100; g 10; r; g 10; conj_grad; g 20; r; g 50; stretch.modulus := 1000; g 50; stretch.modulus := 10000; g 150; g 200; hessian_seek; hessian_seek; hessian_seek; hessian_seek;
energyresidualfacetssecondsconvergedstablenotes
recipe: gogo-1.2577112756.7e+0030721.02
relax() along the same ramp-1.2563332493.3e+0130726.88no
_images/ec62465e7eb417a0ca38bfb286f81d40a1a9e9cfdd5aa55a7165efd5492a6c71.png

Neither converges: the wrinkling sheet has many directions that cost almost no energy, and the file’s comments note indefinite Hessians at lower Poisson ratios. The recipe ends about 0.1% lower (more volume): its conjugate-gradient runs get further on this slowly settling sheet than relax() within its 1000 steps per call. The residual here counts all force directions, in units of the load (the pressure, 1 here): with a stiffer sheet the same residual means a smaller strain error.

relaxed.fe: the elastic method on one triangle

A test of the relaxed_elastic energy on a single unstretched triangle (two extra coordinates hold its reference shape): its energy is 0. Stretched by moving a vertex, it gains energy, and relaxing lets it shrink back (the method gives compression no energy, so any shape no larger than the reference has none).

ev = pyse.Evolver("relaxed.fe")
print("unstretched:", ev.total_energy)
ev.command("set vertex[2] x 1.5")
print("stretched:  ", ev.total_energy)
r = ev.relax()
print("relaxed:    ", ev.total_energy, r)
unstretched: 0.0
stretched:   0.27126736111111116
relaxed:     0.0 IterationResult(converged after 40 gradient steps and 0 Newton, residual 0, stable, health ok)

Next

Strings, metrics and four dimensions: Brakke’s samples: strings, metrics and other dimensions.