{ "cells": [ { "cell_type": "markdown", "id": "brakke_crystals_membranes-0", "metadata": {}, "source": [ "# Brakke's samples: crystals and elastic membranes\n", "\n", "\n", "Energies that are not plain surface tension: a crystalline surface energy, and elastic\n", "membranes that remember their unstretched shape. `relax()` recognizes both and leaves\n", "the mesh as it is (no equiangulation or vertex averaging).\n", "\n", "Each sample is run twice from its datafile: once with the recipe Brakke wrote into\n", "it (its `gogo` command, or the usage its comments describe), once with a default\n", "`ev.relax()` given as many refinements as the recipe does (`levels`). The table\n", "shows the energy each ends with, the residual (how far from equilibrium, see\n", "[Relaxing a surface](relaxing.md)), the facet count, the time, and what `relax()`\n", "reports: converged, stable, and any health issues. A lower energy on the same mesh\n", "is not always the better answer: a coarse mesh can lower its energy in ways the\n", "smooth surface can't, so where an exact value is known, the error against it is\n", "the measure. Times are from the documentation build and vary.\n", "\n", "This gallery assumes [Getting started](getting_started.md) and\n", "[Relaxing a surface](relaxing.md); its pages can be read in any order." ] }, { "cell_type": "code", "execution_count": null, "id": "brakke_crystals_membranes-1", "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import pyvista as pv\n", "import pysurfaceevolver as pyse\n", "import brakke_helpers as bh\n", "\n", "pv.set_jupyter_backend(\"static\")" ] }, { "cell_type": "markdown", "id": "brakke_crystals_membranes-2", "metadata": {}, "source": [ "## `crystal.fe`: a crystal growing into its Wulff shape\n", "\n", "A cube of fixed volume whose surface energy depends on each facet's orientation\n", "through a set of Wulff vectors (`octa.wlf`). The minimizing shape is the Wulff shape\n", "of those vectors. A crystalline energy has a corner at its minimum, so the residual\n", "(a force balance) stays above zero there; Evolver has no Hessian for it either.\n", "`relax()` takes gradient rounds and counts the surface as converged once its energy\n", "settles (it says `energy settled`). The recipe is ten gradient steps." ] }, { "cell_type": "code", "execution_count": null, "id": "brakke_crystals_membranes-3", "metadata": {}, "outputs": [], "source": [ "print(bh.recipe(\"crystal.fe\"))\n", "runs = bh.compare(\"crystal.fe\")\n", "bh.show(runs)" ] }, { "cell_type": "markdown", "id": "brakke_crystals_membranes-4", "metadata": {}, "source": [ "`relax()` goes on until the energy settles (what a thousand plain gradient steps\n", "reach), past the recipe's ten." ] }, { "cell_type": "markdown", "id": "brakke_crystals_membranes-5", "metadata": {}, "source": [ "## `mylarcube.fe`: a mylar balloon\n", "\n", "A cube of mylar inflated to the most volume it can hold without stretching: a\n", "`relaxed_elastic_A` energy that resists stretching but lets the sheet wrinkle freely.\n", "The file redefines `r` to keep each facet's reference shape and warns that any other\n", "retriangulation corrupts it; its recipe raises the elastic modulus as it refines and\n", "ends with `hessian_seek`. `relax()` takes the in-plane forces into its residual and\n", "uses `hessian_seek` for its Newton steps. Here `relax()` follows the recipe's ramp:\n", "the same refinements, the modulus raised from 10 to 100, 1000 and 10000 at the same\n", "points." ] }, { "cell_type": "code", "execution_count": null, "id": "brakke_crystals_membranes-6", "metadata": {}, "outputs": [], "source": [ "print(bh.recipe(\"mylarcube.fe\"))\n", "recipe = bh.run_recipe(\"mylarcube.fe\", label=\"recipe: gogo\")\n", "\n", "def ramp(ev):\n", " ev.relax(levels=1)\n", " ev.quantity(\"stretch\").modulus = 100\n", " ev.relax(levels=2)\n", " ev.quantity(\"stretch\").modulus = 1000\n", " ev.relax()\n", " ev.quantity(\"stretch\").modulus = 10000\n", " return ev.relax()\n", "\n", "import time\n", "ev = pyse.Evolver(\"mylarcube.fe\")\n", "t = time.perf_counter()\n", "r = ramp(ev)\n", "relaxed = bh.Run(\"relax() along the same ramp\", ev.total_energy, r.residual,\n", " ev.counts[\"facets\"], time.perf_counter() - t, r.converged, r.stable,\n", " [], ev.mesh())\n", "bh.table([recipe, relaxed])\n", "bh.show([recipe, relaxed])" ] }, { "cell_type": "markdown", "id": "brakke_crystals_membranes-7", "metadata": {}, "source": [ "Neither converges: the wrinkling sheet has many directions that cost almost no energy,\n", "and the file's comments note indefinite Hessians at lower Poisson ratios. The recipe\n", "ends about 0.1% lower (more volume): its conjugate-gradient runs get further on this\n", "slowly settling sheet than `relax()` within its 1000 steps per call. The residual here\n", "counts all force directions, in units of the load (the pressure, 1 here): with a\n", "stiffer sheet the same residual means a smaller strain error." ] }, { "cell_type": "markdown", "id": "brakke_crystals_membranes-8", "metadata": {}, "source": [ "## `relaxed.fe`: the elastic method on one triangle\n", "\n", "A test of the `relaxed_elastic` energy on a single unstretched triangle (two extra\n", "coordinates hold its reference shape): its energy is 0. Stretched by moving a vertex,\n", "it gains energy, and relaxing lets it shrink back (the method gives compression no\n", "energy, so any shape no larger than the reference has none)." ] }, { "cell_type": "code", "execution_count": null, "id": "brakke_crystals_membranes-9", "metadata": {}, "outputs": [], "source": [ "ev = pyse.Evolver(\"relaxed.fe\")\n", "print(\"unstretched:\", ev.total_energy)\n", "ev.command(\"set vertex[2] x 1.5\")\n", "print(\"stretched: \", ev.total_energy)\n", "r = ev.relax()\n", "print(\"relaxed: \", ev.total_energy, r)" ] }, { "cell_type": "markdown", "id": "brakke_crystals_membranes-10", "metadata": {}, "source": [ "## Next\n", "\n", "Strings, metrics and four dimensions: [Brakke's samples: strings, metrics and other\n", "dimensions](brakke_strings.ipynb)." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" } }, "nbformat": 4, "nbformat_minor": 5 }