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;
| energy | residual | facets | seconds | converged | stable | notes | |
|---|---|---|---|---|---|---|---|
| recipe: g 10; | 3.371242381 | 3.0e+00 | 40 | 0.00 | |||
| relax(levels=0) | 3.325606752 | 3.3e+00 | 40 | 0.02 | yes |
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;
| energy | residual | facets | seconds | converged | stable | notes | |
|---|---|---|---|---|---|---|---|
| recipe: gogo | -1.257711275 | 6.7e+00 | 3072 | 1.02 | |||
| relax() along the same ramp | -1.256333249 | 3.3e+01 | 3072 | 6.88 | no |
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.