{ "cells": [ { "cell_type": "markdown", "id": "8d7a9cf0", "metadata": {}, "source": [ "# 4 · Elastostatics as a Minimization Problem\n", "\n", "Posing an elastic object is an **optimization**: find the vertex positions $x$\n", "that minimize\n", "\n", "$$\n", "E(x) = \\underbrace{E_{\\text{elastic}}(x)}_{\\text{wants rest shape}}\n", " + \\underbrace{\\tfrac{K}{2}\\lVert x_{\\text{pin}} - p\\rVert^2}_{\\text{hold pins}}\n", " + \\underbrace{\\tfrac{K}{2}\\lVert x_{\\text{handle}} - h\\rVert^2}_{\\text{drag handle}}.\n", "$$\n", "\n", "We pin part of the shape, drag a **handle**, and let everything else settle. The\n", "pin and handle terms are quadratic *spring* penalties. We minimize silently with\n", "Newton (the solver is tutorial 5's job) and focus on how **different energies\n", "pose differently**." ] }, { "cell_type": "code", "execution_count": 1, "id": "4cdd7923", "metadata": { "execution": { "iopub.execute_input": "2026-06-09T05:24:24.776638Z", "iopub.status.busy": "2026-06-09T05:24:24.776510Z", "iopub.status.idle": "2026-06-09T05:24:25.302094Z", "shell.execute_reply": "2026-06-09T05:24:25.301823Z" } }, "outputs": [], "source": [ "%matplotlib inline\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import simkit\n", "from simkit.solvers import newton_solver\n", "import utils" ] }, { "cell_type": "markdown", "id": "16d9dd3f", "metadata": {}, "source": [ "## A small, readable simulator\n", "\n", "`ElasticPose` is our first simulator class. It composes three energy terms from\n", "`utils` — the elastic material, a fixed **pin** spring, and a movable\n", "**handle** spring — and exposes `energy / gradient / hessian` that sum\n", "those terms **one per line**, exactly as the Newton solver wants them. Every\n", "later tutorial builds its simulator the same way." ] }, { "cell_type": "code", "execution_count": 2, "id": "3fe1420d", "metadata": { "execution": { "iopub.execute_input": "2026-06-09T05:24:25.303263Z", "iopub.status.busy": "2026-06-09T05:24:25.303182Z", "iopub.status.idle": "2026-06-09T05:24:25.305625Z", "shell.execute_reply": "2026-06-09T05:24:25.305418Z" } }, "outputs": [], "source": [ "class ElasticPose:\n", " \"\"\"Minimize elastic(x) + pin spring + handle spring with Newton.\"\"\"\n", "\n", " def __init__(self, X, T, material=\"Neo-Hookean\", K=1e5):\n", " self.p = utils.precompute(X, T, mu=1.0, lam=1.0) # J, vol, masses, ...\n", " self.psi = utils.make_material(material) # elastic term\n", " self.pin = utils.PenaltySpring(self.p.n, self.p.dim, K)\n", " self.handle = utils.PenaltySpring(self.p.n, self.p.dim, K)\n", "\n", " def set_pin(self, idx, targets): self.pin.set(idx, targets); return self\n", " def set_handle(self, idx, targets): self.handle.set(idx, targets); return self\n", "\n", " def energy(self, x):\n", " E_elastic = self.psi.energy(x, self.p)\n", " E_pin = self.pin.energy(x)\n", " E_handle = self.handle.energy(x)\n", " return E_elastic + E_pin + E_handle\n", "\n", " def gradient(self, x):\n", " g_elastic = self.psi.gradient(x, self.p)\n", " g_pin = self.pin.gradient(x)\n", " g_handle = self.handle.gradient(x)\n", " return g_elastic + g_pin + g_handle\n", "\n", " def hessian(self, x):\n", " H_elastic = self.psi.hessian(x, self.p)\n", " H_pin = self.pin.hessian(x)\n", " H_handle = self.handle.hessian(x)\n", " return H_elastic + H_pin + H_handle\n", "\n", " def solve(self, U0, iters=30):\n", " x = newton_solver(U0.reshape(-1, 1), self.energy, self.gradient, self.hessian,\n", " max_iter=iters, do_line_search=True)\n", " return x.reshape(self.p.n, self.p.dim)" ] }, { "cell_type": "markdown", "id": "847b971d", "metadata": {}, "source": [ "## A triangle: pin the left vertex, swing the right one in a figure-8\n", "\n", "The pinned vertex stays put while the handle traces a **figure-8** (a\n", "lemniscate), so the free apex both stretches and compresses. We step the pose\n", "explicitly: at each handle position we re-aim the handle and re-solve, starting\n", "each solve from the previous equilibrium." ] }, { "cell_type": "code", "execution_count": 3, "id": "29fae205", "metadata": { "execution": { "iopub.execute_input": "2026-06-09T05:24:25.306536Z", "iopub.status.busy": "2026-06-09T05:24:25.306488Z", "iopub.status.idle": "2026-06-09T05:24:25.978630Z", "shell.execute_reply": "2026-06-09T05:24:25.978362Z" } }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X = np.array([[-0.5, 0.0], [0.5, 0.0], [0.0, np.sqrt(3) / 2]])\n", "T = np.array([[0, 1, 2]])\n", "PIN, HANDLE = 0, 1\n", "\n", "# figure-8 (lemniscate) traced by the handle, starting from rest (t=0 -> no offset)\n", "t = np.linspace(0, 2 * np.pi, 48)\n", "handle_path = X[HANDLE] + np.stack([0.45 * np.sin(t), 0.6 * np.sin(2 * t)], axis=1)\n", "\n", "pose = ElasticPose(X, T, \"Neo-Hookean\").set_pin(PIN, X[PIN])\n", "states = []\n", "U = X.copy()\n", "for h in handle_path:\n", " pose.set_handle(HANDLE, h)\n", " U = pose.solve(U)\n", " states.append(U.copy())\n", "\n", "fig, anim = utils.animate_mesh(states, T, lims=((-1.2, 1.6), (-1.2, 1.2)),\n", " title=\"Neo-Hookean triangle: handle traces a figure-8\",\n", " pin_pts=X[[PIN]], handle_traj=[s[HANDLE] for s in states],\n", " target_pts=list(handle_path), fps=20, figsize=(6, 5))\n", "utils.show_video(fig, anim, \"media/04_triangle.mp4\", fps=20)" ] }, { "cell_type": "markdown", "id": "e9432898", "metadata": {}, "source": [ "## Same handle, three energies, very different poses\n", "\n", "Pull the handle far up-and-right and compare where the free apex lands under each\n", "model. Linear elasticity (no rotation-invariance) reacts quite differently from\n", "ARAP and Neo-Hookean. We loop over the three materials explicitly, building a\n", "fresh `ElasticPose` for each." ] }, { "cell_type": "code", "execution_count": 4, "id": "5e31daff", "metadata": { "execution": { "iopub.execute_input": "2026-06-09T05:24:25.979736Z", "iopub.status.busy": "2026-06-09T05:24:25.979655Z", "iopub.status.idle": "2026-06-09T05:24:26.065766Z", "shell.execute_reply": "2026-06-09T05:24:26.065470Z" } }, "outputs": [ { "data": { "image/png": "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Fawn1qTUgQMHZMGCBZKfny+33HKLTJ06Vd5///0yHzdlyhR54oknCn+vU6dOsFYRABBixAoAALECAGq3oCSmtm3bJnPnzpWvvvpKzj//fHPfiy++KKNHj5Znn31WWrVqVepjNRHVokWLYKwWACCMECsAAMQKAEBQElNr1qwxw/d8SSk1YsQIcblcsnbtWrnqqqtKfex7770n7777rklOjR07Vh555JEye03l5uaam09GRob56fF4zM1JfNvDdtkDx8t+nH7Mwg2xIjic/j5mu+zBqcfLydsWrttDrAgOp7+P2S57cOrxcvK2eYK0PUFJTKWkpEizZs2KvlBUlDRq1Mj8rTQTJ06U9u3bmx5Vmzdvlvvvv1+2b98u06dPL/UxTz31lDz++OMl7j98+HCRhJWTpKamihOxXfbi1OPlxG3LzMyUcESsCC6nvY992C57cerxcuK2EStoVziJ0z6fPmyX/TjtmGUGqV1RqcTUAw88IE8//XS5QzOqSmtQ+Zx77rnSsmVLGT58uOzatUs6deoU8DEPPvigTJs2rUiPqbZt20qTJk1Mry2nZSf1jd20aVPT+8wp2C57cerxcvK2xcbG1ujrEStCy6nvY7bLXpx6vJy8bcQK2hVO4NTPJ9tlP049ZrFBaldUKjH1m9/8Rm6++eYylznjjDPMMLxDhw4Vub+goMDMvlSZ+lH9+/c3P3fu3FlqYkp3TKCdowffSW+A2rBtbJe9OPV4OXHbanpbiBXhwWnvYx+2y16cerycuG3ECtoVTuK0z6cP22U/TjtmriBtS6USU5rt01t5BgwYIEePHpUNGzZInz59zH2LFy82WUNfsqkivvnmG/NTe04BAOyBWAEAIFYAACoqKOmubt26yWWXXSZTpkyRdevWyapVq+TOO++UG264oXBGvn379knXrl3N35UO1/vjH/9oklm7d++WL774Qn72s5/JRRddJD169AjGagIAQohYAQAgVgAAgtanTGfX08ST1ogaPXq0DBo0SF577bXCv+fn55vC5llZWeb3mJgYWbhwoVx66aXmcToUZPz48fK///2PowQADkWsAAAQKwCgdgvKrHxKZ+B7//33S/17hw4dxLKswt+1YPmyZcuCtToAgDBErAAAECsAoHZzThUuAAAAAAAA2AqJKQAAAAAAAIQEiSkAAAAAAACEBIkpAAAAAAAAhASJ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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "target = np.array([1.5, 1.1])\n", "fig, axes = plt.subplots(1, 3, figsize=(12, 4))\n", "for ax, material in zip(axes, [\"Linear\", \"ARAP\", \"Neo-Hookean\"]):\n", " pose = ElasticPose(X, T, material).set_pin(PIN, X[PIN]).set_handle(HANDLE, target)\n", " U = pose.solve(X.copy())\n", " utils.setup_axes(ax, (-1.0, 2.0), (-0.8, 1.6), title=material)\n", " utils.TriangleArtist(ax, U, rest=X)\n", " ax.plot(*X[PIN], \"s\", color=utils.PIN_C, ms=10)\n", " ax.plot(*target, \"x\", color=\"0.3\", ms=12, mew=2.5)\n", "fig.suptitle(\"Same pin + handle target, three elastic energies\")\n", "fig.tight_layout(); plt.show()" ] }, { "cell_type": "markdown", "id": "f6a54444", "metadata": {}, "source": [ "## A cantilever beam: pin the left edge, swing the whole right edge\n", "\n", "The handle is now **every vertex on the right edge** (not one). We **rotate those\n", "target points about the origin** — the orange handles swing up and down in a\n", "wide arc — which whips the beam through large bends. Starting from rest, the\n", "angle sweeps to about $\\pm 120^\\circ$ and back. Targets are marked with an\n", "×." ] }, { "cell_type": "code", "execution_count": 5, "id": "b14d3d38", "metadata": { "execution": { "iopub.execute_input": "2026-06-09T05:24:26.066831Z", "iopub.status.busy": "2026-06-09T05:24:26.066770Z", "iopub.status.idle": "2026-06-09T05:24:27.293832Z", "shell.execute_reply": "2026-06-09T05:24:27.293540Z" } }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Xb, Tb = utils.triangulated_grid(nx=16, ny=5, width=2.0, height=0.4)\n", "pin_idx = np.where(Xb[:, 0] <= Xb[:, 0].min() + 1e-6)[0]\n", "right_idx = np.where(Xb[:, 0] >= Xb[:, 0].max() - 1e-6)[0]\n", "\n", "def rotate_about_origin(P, theta):\n", " R = np.array([[np.cos(theta), -np.sin(theta)], [np.sin(theta), np.cos(theta)]])\n", " return P @ R.T\n", "\n", "# angle swings +/-120 deg from rest and back\n", "angles = np.deg2rad(120) * np.sin(np.linspace(0, 2 * np.pi, 48))\n", "\n", "beam = ElasticPose(Xb, Tb, \"Neo-Hookean\").set_pin(pin_idx, Xb[pin_idx])\n", "states, targets = [], []\n", "U = Xb.copy()\n", "for th in angles:\n", " tgt = rotate_about_origin(Xb[right_idx], th)\n", " beam.set_handle(right_idx, tgt)\n", " U = beam.solve(U)\n", " states.append(U.copy())\n", " targets.append(tgt.copy())\n", "\n", "fig, anim = utils.animate_mesh(states, Tb, lims=((-1.8, 1.8), (-1.8, 1.8)),\n", " title=\"Cantilever: right edge swung in an arc about the origin\",\n", " pin_pts=Xb[pin_idx], handle_traj=[s[right_idx] for s in states],\n", " target_pts=targets, fps=20, figsize=(6, 6))\n", "utils.show_video(fig, anim, \"media/04_beam.mp4\", fps=20)" ] }, { "cell_type": "markdown", "id": "04a1dffc", "metadata": {}, "source": [ "### Takeaways\n", "* Posing = **minimizing** elastic energy + soft pin/handle springs.\n", "* The *same* setup with a *different* energy gives a *different* equilibrium.\n", "* We solved it silently with Newton. **How** that solve works is next." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.9" } }, "nbformat": 4, "nbformat_minor": 5 }