From c3a1af88f51eb5a934c8f7e9c44ece3d39dc4158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dion=20H=C3=A4fner?= Date: Thu, 2 Apr 2026 10:00:25 +0200 Subject: [PATCH 1/2] add multiphysics demo --- .../demo-executed.ipynb | 1157 ++++++ demo/multiphysics-optimization/demo.ipynb | 3299 +++++++++++++++++ .../requirements.txt | 5 + .../structural_solver/tesseract_api.py | 273 ++ .../structural_solver/tesseract_config.yaml | 6 + .../tesseract_requirements.txt | 2 + .../multiphysics-optimization/test_solvers.py | 260 ++ .../thermal_solver/tesseract_api.py | 233 ++ .../thermal_solver/tesseract_config.yaml | 6 + .../thermal_solver/tesseract_requirements.txt | 2 + pyproject.toml | 1 + 11 files changed, 5244 insertions(+) create mode 100644 demo/multiphysics-optimization/demo-executed.ipynb create mode 100644 demo/multiphysics-optimization/demo.ipynb create mode 100644 demo/multiphysics-optimization/requirements.txt create mode 100644 demo/multiphysics-optimization/structural_solver/tesseract_api.py create mode 100644 demo/multiphysics-optimization/structural_solver/tesseract_config.yaml create mode 100644 demo/multiphysics-optimization/structural_solver/tesseract_requirements.txt create mode 100644 demo/multiphysics-optimization/test_solvers.py create mode 100644 demo/multiphysics-optimization/thermal_solver/tesseract_api.py create mode 100644 demo/multiphysics-optimization/thermal_solver/tesseract_config.yaml create mode 100644 demo/multiphysics-optimization/thermal_solver/tesseract_requirements.txt diff --git a/demo/multiphysics-optimization/demo-executed.ipynb b/demo/multiphysics-optimization/demo-executed.ipynb new file mode 100644 index 000000000..82a7d38f5 --- /dev/null +++ b/demo/multiphysics-optimization/demo-executed.ipynb @@ -0,0 +1,1157 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Multi-Physics Pipeline with End-to-End Gradient Optimization\n", + "\n", + "This demo shows how to compose two physics solvers from different domains \u2014 thermal and structural \u2014 into a coupled pipeline, and solve a design inverse problem with **end-to-end gradients flowing automatically through the full chain**.\n", + "\n", + "Each solver is an independent Tesseract. The pipeline uses two-way (partitioned) coupling: the thermal solver produces a temperature field that causes thermal strain in the structural solver, and the resulting displacement feeds back to the thermal solver by deforming the geometry. Gradients propagate through this coupled iteration via JAX's automatic differentiation.\n", + "\n", + "## What we demonstrate\n", + "\n", + "1. **Two independent Tesseracts** \u2014 each team keeps their solver, their AD strategy, their dependencies\n", + "2. **Two-way coupling** via `jax.lax.scan` \u2014 not a toy feedforward chain, but the real partitioned coupling pattern used in practice\n", + "3. **End-to-end gradients** \u2014 `jax.grad` through the coupled iteration, validated against finite differences\n", + "4. **Gradient-based optimization beats gradient-free** \u2014 fewer evaluations for a 3-parameter design problem\n", + "5. **Solver swapping** \u2014 change one Tesseract, optimization code stays the same" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T11:53:57.971300Z", + "iopub.status.busy": "2026-03-28T11:53:57.971119Z", + "iopub.status.idle": "2026-03-28T11:53:59.602009Z", + "shell.execute_reply": "2026-03-28T11:53:59.601747Z" + } + }, + "outputs": [], + "source": [ + "import jax\n", + "import jax.numpy as jnp\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.optimize import minimize\n", + "\n", + "jax.config.update(\"jax_enable_x64\", True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Load the solvers\n", + "\n", + "Each solver is a standalone Tesseract module with its own `tesseract_api.py`. In production, these would be containerized images composed via `tesseract-jax`'s `apply_tesseract`. Here we import them directly for speed." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T11:53:59.603583Z", + "iopub.status.busy": "2026-03-28T11:53:59.603443Z", + "iopub.status.idle": "2026-03-28T11:54:01.017721Z", + "shell.execute_reply": "2026-03-28T11:54:01.017439Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Thermal solver loaded: Thermal solver Tesseract: 2D steady-state heat equation on a rectangular plate.\n", + "Structural solver loaded: Structural solver Tesseract: 2D linear thermoelastic stress on a rectangular plate.\n" + ] + } + ], + "source": [ + "import sys\n", + "\n", + "sys.path.insert(0, \".\")\n", + "\n", + "import structural_solver.tesseract_api as structural_api\n", + "import thermal_solver.tesseract_api as thermal_api\n", + "\n", + "print(\"Thermal solver loaded:\", thermal_api.__doc__.strip().split(\"\\n\")[0])\n", + "print(\"Structural solver loaded:\", structural_api.__doc__.strip().split(\"\\n\")[0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Forward pass: single-shot thermal \u2192 structural\n", + "\n", + "Before coupling, let's verify each solver works independently and visualize the physics." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T11:54:01.043022Z", + "iopub.status.busy": "2026-03-28T11:54:01.042499Z", + "iopub.status.idle": "2026-03-28T11:54:01.706150Z", + "shell.execute_reply": "2026-03-28T11:54:01.705858Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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5sdk3DXbBptyxrE4L3M9s9+MZ3GehcyQMxYAsN/dykwnAAAKheN5gSfVu3dvqaysTE4zZsxo9j1feeUVOeigg/zG2ssvv1weffRROeGEE1rxUwMAECxNgRdgsjVnzhzp06ePlJWVybBhw2TlypUHjNcbnf369fPjBwwYIE8++WTyb7FYTK677jp/focOHaRnz54yfvx4+fBDm16D+9AYCwBIclNSFdhONMYCAAoyTUGQSR9O2rhRdu7cmZxuuOGGZt/yuOOOk3Xr1sk//vEP+e53vysTJkyQ1157rfU+MwAAbdTxx7V8v0WLFsmUKVNk+vTpsmbNGhk4cKCMGjVKtm7dmjZ++fLlcuGFF8pll13m52MfM2aMP7366qv+32tqavz13HLLLf5///jHP8qbb74pX/nKV/I7TQEAIFzkjAUAoHUH8OrUqZM/mSgpKZFjjz3W//fgwYPlpZdekrvvvlt+9atfZb4hAAC0Au3ZapEVaj+2PWNnzZolkyZNkokTJ/qv586dK0888YTMnz9frr/++v3itT4955xzZOrUqf7r2267TZ5++mm55557/GX16RV9nUr/NnToUNmwYYMcccQRxttGz1gAAAAAyEGu60ptrXluQwAAcl1VVVWjKV09WFdXJ6tXr5aRI0cm50UiEf/1ihUr0q5X56fGK+1J21y80idaHMeRzp07W30GGmMBAEnkjAUAoHXTFJjS9AXPP/+8vP/++37uWH29bNkyueiii8L6hAAAtLtqs7dBrvXt27f7g11279690Xx9vXnz5rTbp/Nt4vfu3evnkNXUBqZPuCSQpgAAkESaAgAAWjdNgSnNcacDhXz00Uf+xedJJ50kTz31lHzxi1/MfCMAAGglbsA0BW5KrvXUxk8d1LK16WBeF1xwgXieJ/fee6/18jTGAgAAAEA795vf/KatNwEAgDbXySDXerdu3SQajcqWLVsazdfXPXr0SLuMzjeJTzTErl+/Xv76179a94pVpCkAAOzXMzbTCQCAgtHKaQoAAMhlOgBX0MmUDnipA10uXbq0UZ51fT18+PC0y+j81HilA3alxicaYv/1r3/JM888I127dpVM0DMWAJAUJPcrOWMBAIWktdMUAACQy4KOM+Jaxk+ZMkUmTJggQ4YMkaFDh8rs2bOlurpaJk6c6P9dU//06tUrmXP26quvljPOOENmzpwp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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Run thermal solver\n", + "thermal_out = thermal_api.apply_jit(\n", + " {\n", + " \"source_x\": jnp.float32(0.5),\n", + " \"source_y\": jnp.float32(0.5),\n", + " \"source_intensity\": jnp.float32(10.0),\n", + " \"source_width\": 0.1,\n", + " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", + " \"conductivity\": 1.0,\n", + " \"boundary_temp\": 0.0,\n", + " }\n", + ")\n", + "temperature = np.asarray(thermal_out[\"temperature\"])\n", + "\n", + "# Run structural solver\n", + "structural_out = structural_api.apply_jit(\n", + " {\n", + " \"temperature\": thermal_out[\"temperature\"],\n", + " \"youngs_modulus\": 200.0,\n", + " \"poissons_ratio\": 0.3,\n", + " \"thermal_expansion\": 1e-3,\n", + " }\n", + ")\n", + "\n", + "fig, axes = plt.subplots(1, 3, figsize=(14, 4))\n", + "im0 = axes[0].imshow(temperature.T, origin=\"lower\", extent=[0, 1, 0, 1], cmap=\"hot\")\n", + "axes[0].set_title(\"Temperature field\")\n", + "plt.colorbar(im0, ax=axes[0])\n", + "\n", + "disp_mag = np.linalg.norm(np.asarray(structural_out[\"displacement\"]), axis=-1)\n", + "im1 = axes[1].imshow(disp_mag.T, origin=\"lower\", extent=[0, 1, 0, 1], cmap=\"viridis\")\n", + "axes[1].set_title(\"Displacement magnitude\")\n", + "plt.colorbar(im1, ax=axes[1])\n", + "\n", + "s = np.asarray(structural_out[\"stress\"])\n", + "von_mises = np.sqrt(\n", + " s[:, :, 0] ** 2 - s[:, :, 0] * s[:, :, 1] + s[:, :, 1] ** 2 + 3 * s[:, :, 2] ** 2\n", + ")\n", + "im2 = axes[2].imshow(von_mises.T, origin=\"lower\", extent=[0, 1, 0, 1], cmap=\"inferno\")\n", + "axes[2].set_title(\"Von Mises stress\")\n", + "plt.colorbar(im2, ax=axes[2])\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. The design problem: thermoelastic inverse optimization\n", + "\n", + "**Problem**: Find the heat source location and intensity that produces desired temperatures at four sensor locations, after the thermoelastic coupling has converged.\n", + "\n", + "This can't be solved with the thermal solver alone \u2014 the displacement from thermal expansion changes the geometry, which changes the temperature field. You need gradients through the full coupled iteration.\n", + "\n", + "**Design variables**: source position $(x, y)$ and log-intensity $\\log(q)$ (3 parameters).\n", + "\n", + "**Objective**: $\\sum_i (T_{\\text{sensor}_i} - T_{\\text{target}_i})^2$ evaluated after coupled convergence." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T11:54:01.707528Z", + "iopub.status.busy": "2026-03-28T11:54:01.707416Z", + "iopub.status.idle": "2026-03-28T11:54:02.000451Z", + "shell.execute_reply": "2026-03-28T11:54:02.000131Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Sensor positions (approx):\n", + " (0.26, 0.26) -> T_target = 0.010\n", + " (0.26, 0.71) -> T_target = 0.020\n", + " (0.71, 0.26) -> T_target = 0.020\n", + " (0.71, 0.71) -> T_target = 0.050\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Objective at initial guess: 6.175704e-03\n" + ] + } + ], + "source": [ + "# Sensor locations (grid indices) and target temperatures\n", + "SENSORS = [(8, 8), (8, 22), (22, 8), (22, 22)]\n", + "TARGETS = [jnp.float32(0.01), jnp.float32(0.02), jnp.float32(0.02), jnp.float32(0.05)]\n", + "\n", + "# Approximate physical positions of sensors (for visualization)\n", + "sensor_positions = [(i / 31, j / 31) for i, j in SENSORS]\n", + "print(\"Sensor positions (approx):\")\n", + "for (sx, sy), t in zip(sensor_positions, TARGETS, strict=False):\n", + " print(f\" ({sx:.2f}, {sy:.2f}) -> T_target = {float(t):.3f}\")\n", + "\n", + "N_COUPLING_ITERS = 3\n", + "\n", + "\n", + "def coupled_objective(params):\n", + " \"\"\"Two-way coupled thermoelastic inverse problem.\n", + "\n", + " params: [source_x, source_y, log_intensity]\n", + " Returns: sum of squared temperature errors at sensor locations.\n", + " \"\"\"\n", + " source_x, source_y, log_intensity = params[0], params[1], params[2]\n", + " intensity = jnp.exp(log_intensity)\n", + "\n", + " temp = jnp.zeros((30, 30), dtype=jnp.float32)\n", + " disp = jnp.zeros((30, 30, 2), dtype=jnp.float32)\n", + "\n", + " def coupling_step(carry, _):\n", + " _temp, disp = carry\n", + " thermal_out = thermal_api.apply_jit(\n", + " {\n", + " \"source_x\": source_x,\n", + " \"source_y\": source_y,\n", + " \"source_intensity\": intensity,\n", + " \"source_width\": jnp.float32(0.15),\n", + " \"displacement\": disp,\n", + " \"conductivity\": 1.0,\n", + " \"boundary_temp\": 0.0,\n", + " }\n", + " )\n", + " structural_out = structural_api.apply_jit(\n", + " {\n", + " \"temperature\": thermal_out[\"temperature\"],\n", + " \"youngs_modulus\": 200.0,\n", + " \"poissons_ratio\": 0.3,\n", + " \"thermal_expansion\": 1e-3,\n", + " }\n", + " )\n", + " return (thermal_out[\"temperature\"], structural_out[\"displacement\"]), None\n", + "\n", + " (final_temp, _), _ = jax.lax.scan(\n", + " coupling_step, (temp, disp), None, length=N_COUPLING_ITERS\n", + " )\n", + "\n", + " loss = jnp.float32(0.0)\n", + " for (si, sj), target in zip(SENSORS, TARGETS, strict=False):\n", + " loss = loss + (final_temp[si, sj] - target) ** 2\n", + " return loss\n", + "\n", + "\n", + "# Test forward pass\n", + "p0 = jnp.array([0.2, 0.2, jnp.log(5.0)], dtype=jnp.float32)\n", + "print(f\"\\nObjective at initial guess: {float(coupled_objective(p0)):.6e}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. End-to-end gradients through the coupled pipeline\n", + "\n", + "The key moment: `jax.grad` differentiates through the entire coupled iteration \u2014 through both solvers, through `lax.scan`, automatically. No manual adjoint derivation, no monolithic rewrite." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T11:54:02.002160Z", + "iopub.status.busy": "2026-03-28T11:54:02.002008Z", + "iopub.status.idle": "2026-03-28T11:54:02.697883Z", + "shell.execute_reply": "2026-03-28T11:54:02.697607Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Gradients at initial guess:\n", + " d(loss)/d(source_x) = 2.295046e-02\n", + " d(loss)/d(source_y) = 2.295046e-02\n", + " d(loss)/d(log_intensity) = 8.693038e-03\n" + ] + } + ], + "source": [ + "grad_fn = jax.grad(coupled_objective)\n", + "\n", + "grads = grad_fn(p0)\n", + "print(\"Gradients at initial guess:\")\n", + "print(f\" d(loss)/d(source_x) = {float(grads[0]):.6e}\")\n", + "print(f\" d(loss)/d(source_y) = {float(grads[1]):.6e}\")\n", + "print(f\" d(loss)/d(log_intensity) = {float(grads[2]):.6e}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Gradient validation against finite differences\n", + "\n", + "For a rigorous audience, correctness proof is non-negotiable." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T11:54:02.699244Z", + "iopub.status.busy": "2026-03-28T11:54:02.699140Z", + "iopub.status.idle": "2026-03-28T11:54:03.348779Z", + "shell.execute_reply": "2026-03-28T11:54:03.348280Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " AD FD Rel. Error\n", + "d(loss)/d(source_x) 2.295046e-02 2.295244e-02 8.63e-05\n", + "d(loss)/d(source_y) 2.295046e-02 2.295244e-02 8.63e-05\n", + "d(loss)/d(log_intensity) 8.693038e-03 8.689240e-03 4.37e-04\n" + ] + } + ], + "source": [ + "eps = 1e-4\n", + "fd_grads = []\n", + "for i in range(3):\n", + " p_plus = p0.at[i].add(eps)\n", + " p_minus = p0.at[i].add(-eps)\n", + " fd_grads.append(\n", + " (coupled_objective(p_plus) - coupled_objective(p_minus)) / (2 * eps)\n", + " )\n", + "\n", + "names = [\"d(loss)/d(source_x)\", \"d(loss)/d(source_y)\", \"d(loss)/d(log_intensity)\"]\n", + "print(f\"{'':32s} {'AD':>14s} {'FD':>14s} {'Rel. Error':>12s}\")\n", + "for name, ad, fd in zip(names, grads, fd_grads, strict=False):\n", + " rel_err = abs(float(ad) - float(fd)) / (abs(float(fd)) + 1e-30)\n", + " print(f\"{name:32s} {float(ad):14.6e} {float(fd):14.6e} {rel_err:12.2e}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Optimization: gradient-based vs gradient-free\n", + "\n", + "We compare:\n", + "- **L-BFGS-B** (gradient-based, using our end-to-end gradients)\n", + "- **Nelder-Mead** (gradient-free)\n", + "\n", + "Both optimize 3 design variables: source position $(x, y)$ and log-intensity." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T11:54:03.350521Z", + "iopub.status.busy": "2026-03-28T11:54:03.350395Z", + "iopub.status.idle": "2026-03-28T11:54:39.034362Z", + "shell.execute_reply": "2026-03-28T11:54:39.034007Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running L-BFGS-B (gradient-based)...\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Source: (0.674, 0.674)\n", + " Intensity: 2.73\n", + " Objective: 3.169720e-06\n", + " Evaluations: 27\n", + "\n", + "Running Nelder-Mead (gradient-free)...\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Source: (0.673, 0.673)\n", + " Intensity: 2.73\n", + " Objective: 3.168822e-06\n", + " Evaluations: 254\n", + "\n", + "Speedup: 254/27 = 9.4x fewer evaluations with gradients\n" + ] + } + ], + "source": [ + "eval_history_grad = []\n", + "eval_history_free = []\n", + "\n", + "\n", + "def objective_and_grad(x):\n", + " p = jnp.array(x, dtype=jnp.float32)\n", + " obj = coupled_objective(p)\n", + " g = grad_fn(p)\n", + " eval_history_grad.append(float(obj))\n", + " return float(obj), np.array([float(g[i]) for i in range(3)])\n", + "\n", + "\n", + "def objective_only(x):\n", + " p = jnp.array(x, dtype=jnp.float32)\n", + " obj = coupled_objective(p)\n", + " eval_history_free.append(float(obj))\n", + " return float(obj)\n", + "\n", + "\n", + "x0 = np.array([0.2, 0.2, np.log(5.0)])\n", + "bounds = [(0.05, 0.95), (0.05, 0.95), (np.log(1.0), np.log(50.0))]\n", + "\n", + "print(\"Running L-BFGS-B (gradient-based)...\")\n", + "result_grad = minimize(\n", + " objective_and_grad,\n", + " x0,\n", + " method=\"L-BFGS-B\",\n", + " jac=True,\n", + " bounds=bounds,\n", + " options={\"maxiter\": 100},\n", + ")\n", + "print(f\" Source: ({result_grad.x[0]:.3f}, {result_grad.x[1]:.3f})\")\n", + "print(f\" Intensity: {np.exp(result_grad.x[2]):.2f}\")\n", + "print(f\" Objective: {result_grad.fun:.6e}\")\n", + "print(f\" Evaluations: {len(eval_history_grad)}\")\n", + "\n", + "print(\"\\nRunning Nelder-Mead (gradient-free)...\")\n", + "result_free = minimize(\n", + " objective_only,\n", + " x0,\n", + " method=\"Nelder-Mead\",\n", + " options={\"maxiter\": 500, \"xatol\": 1e-6, \"fatol\": 1e-15},\n", + ")\n", + "print(f\" Source: ({result_free.x[0]:.3f}, {result_free.x[1]:.3f})\")\n", + "print(f\" Intensity: {np.exp(result_free.x[2]):.2f}\")\n", + "print(f\" Objective: {result_free.fun:.6e}\")\n", + "print(f\" Evaluations: {len(eval_history_free)}\")\n", + "\n", + "print(\n", + " f\"\\nSpeedup: {len(eval_history_free)}/{len(eval_history_grad)} \"\n", + " f\"= {len(eval_history_free) / max(len(eval_history_grad), 1):.1f}x fewer evaluations with gradients\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T11:54:39.037061Z", + "iopub.status.busy": "2026-03-28T11:54:39.036939Z", + "iopub.status.idle": "2026-03-28T11:54:39.208631Z", + "shell.execute_reply": "2026-03-28T11:54:39.208352Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAAHqCAYAAACZcdjsAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAnzVJREFUeJzt3QeYE2XXBuCzvbMLLL0joNIRUbEhggIqiliw/WIDCyj2+lngU7EiKKifvSsqggVFFCmC9KLSi0hdyrJsZ2vyX8+bnWSSTLLJbrJpz31dYZPJJJlkssucOee8b5TZbDYLERERERFRLUTX5sFERERERETAwIKIiIiIiGqNgQUREREREdUaAwsiIiIiIqo1BhZERERERFRrDCyIiIiIiKjWGFgQEREREVGtMbAgIiIiIqJaY2BBRERERES1xsCCiHzmhhtukLZt29oti4qKkqeeekqCyQcffKC2a9WqVRJKzjnnHHWh0PmuwbZt2+T888+X9PR0tY2zZs2SSOPrffPvv/+q58Tvcl0K1OsShQoGFkRhYOfOnTJ27Fjp1KmTJCcnq0vnzp1lzJgx8tdff0m4++yzz2Ty5MmB3gyKADX5ro0cOVL+/vtveeaZZ+Tjjz+Wk08+WcLRjz/+GJSBXU3wbwpRzcTW8HFEFCR++OEHGTFihMTGxsq1114rPXr0kOjoaNm8ebN888038sYbb6jAo02bNgHZvmPHjqlt8/dBwPr16+Xuu+/26+tQcAvG7xq2aenSpfLYY4+p4D+cIbCYNm2aYXDh632Dv2d4zri4OKnL/ezv1yUKdQwsiELYjh075KqrrlL/2c2bN0+aNWtmd//zzz8vr7/+ugo03CkqKpKUlBS/bGNiYqJfnpdCU6R91w4fPqx+ZmRkBPSzCTRf7xuUIwVifwfqdYlCBUuhiELYCy+8oA5G3n//faegAnCG8K677pJWrVrZ1aanpqaqoOSCCy6QtLQ0lemA33//Xa644gpp3bq1JCQkqMfdc8896gydI9SJd+3aVf0ni58zZ870uLZ63759ctNNN0mTJk3U63Tp0kXee+89u3UWLFigHvvll1+qEpKWLVuq1xowYIBs377duh56DmbPni27du1S6+PiWHvvSnFxsdx6663SsGFDqVevnlx//fVy9OhRu3W+/fZbufDCC6V58+ZqW4877jj573//K5WVlU519Jdddpk0bdpUbSe2F0FfXl6e3XqffPKJ9O7dW5KSkqRBgwZqnT179jht21tvvaVeC+udcsopat94Avuif//+TstNJpO0aNFCLr/8cuuyL774Qm0LvgN4/926dZMpU6ZU+xpHjhyR//u//1OPwQEzSn3+/PNPp9rzSP+uYVu0TOEDDzxgtz7uw+2NGzfKNddcI/Xr15czzzzT6+/J8uXLZfDgwap/AyWQ/fr1kyVLlognDh06JDfffLP6bPB+ke388MMPDXsKXnrpJXnllVfU+8E24XVwRl+/r5Gt0PaDdnG1b7T3v3XrVrnuuuvU9jdq1Egef/xxMZvN6r1ecskl6juG36mXX37ZcLu075u2D40u+n3kye+zu/3sqsfit99+k7POOksFhvidwLZv2rTJbh3tPeM7hc8L6+F933jjjepvEVE4YMaCKMTLoDp06CCnnnqqV4+rqKiQQYMGqQMZHDDggAS++uor9R/c7bffrg62V6xYIa+99prs3btX3aeZO3euOohGH8fEiRPVgSb+c8QBWXUOHjwop512mvoPFqUhOJj46aef1AFOfn6+U+nBc889pzIu999/vzpIRzCFg1McUAFKTLAc24gDH8DBrCfw+vjPHf/hb9myRZWN4WBCO0gBHEDg+e699171EwcQTzzxhNrWF198Ua1TVlamPs/S0lK588471YEQDmixf3Jzc9XBA+CgFQdOV155pdxyyy3qbDY+37PPPlvWrl1rPav97rvvqoDn9NNPV5/HP//8IxdffLE6wNQHiUZQFof3c+DAAbUdmsWLF8v+/fvVASr88ssvcvXVV6uDZ2S2AAdCOCgdN26cy+dHgDJ06FD13cD35IQTTlAHawgujETyd2348OFqnyJgwmeN4MpxfQRXHTt2lGeffVYdUHvzPcF3cciQISoAefLJJ9W24yTDueeeqwI3BKSuIIDDATQOcvHZtGvXTn3uOODFd9bxO/DRRx9JQUGB6tsqKSlRASheB70jCEzwfcX3C98r9JF4Ct/XE088UX32OJh/+umn1ff8f//7n3p+fDc//fRTtU/69OmjPgMjeA7H18X7wO9t48aNrcs8+X32dj//+uuvaj+0b99e/e7hs8X+OuOMM2TNmjVOwSf2Kz5vfJ9x/zvvvKO2Ufs9JAppZiIKSXl5eTgKMQ8bNszpvqNHj5oPHz5svRQXF1vv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9Pre/C0K6sACQ8MigsI8FHq4jTdPRERE4UsLKho3bizJyclhfcCNg0uctcZkvuH8Pim49j1eu7i42DookjZFQ00FdWARHx+vJrSbN2+edQhaRHS4PXbs2EBvHhEREfmx/EkLKho2bCjhjoFF5DIHeN8nJSWpnwgu8Pvmriwq6AMLpH22b99uvb1z5041ylODBg2kdevWqt9h5MiRcvLJJ6u5KyZPnqyGqNVGifIXDH+LC/6wERERUd3SeiqQqSAi/9J+z/B7F9KBxapVq6R///7W21rjNIKJDz74QEaMGKFGZHriiSdUShRzVsyZM8epodvXxowZoy5o3k5PT/fraxEREZExnr0nCp3fs4AHFuecc45KAbmDsieWPhERERERBS8OOUFEREREfoN5xJ599lkJB5gbTev7rc7DDz8sd955p0QSBhZEREREATjw1Co3tCGGMWgNRr284oorZNeuXdZ1/v33X7WO4+W6666ze64ZM2aoCYHr16+vGnKPP/54uemmm2Tt2rXWddA7+txzz8kJJ5yg1kFP66mnnirvvPOOy21csGCB3evicV26dJG33nqr2vf3559/yo8//ih33XWXtYb/oYceUvOJpaSkSPPmzeX666+X/fv3u3w9/WXlypUSKu6//3758MMP5Z9//pFIwcCCiIiIKIBGjRqlDqwRTGAy3z179jgFDfDrr79KVlaW9YJBZjQ4WEdfKnpRv/vuO9myZYt89tln0r59ezX5r2b8+PHyyiuvyH//+1/ZuHGjzJ8/X0aPHu3RXCF4TrwuHnfrrbfK7bffrkbqdOe1115TgVJqaqq6jaFN16xZI48//rj6+c0336jnvfjii62POf300+3eJy633HKLtGvXTg3mEyoyMzNl0KBB8sYbb0jEMJOhqVOnmk888URzp06d0ABizsvLC8h2VFZWmrOystTPcPPT3/vNg15ZaO702I/qJ25TZOx7co/7PnJx39scO3bMvHHjRvUzlP6vGTlypPmSSy7xeP1+/fqZx40bZzaZTOaysjL18+OPPzYnJydb19m5c6c6Flm7dq3hcyxdulTdP2XKFMP78ZyaHj16mJ966imv3tP8+fPV8x89etRu+XHHHWd+4YUXXD6uoqLCnJ6ebv7hhx/cPv+KFSvU8+/atcvwfnwujRo1Mk+YMMHt82D7br75ZnNmZqY5LS3N3L9/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HcwPPPCAOS8vL6T3fRT+CXTWhIiIiIiIQht7LIiIiIiIqNYYWBARERERUa0xsCAiIiIiolpjYEFERERERLXGwIKIiIiIiGqNgQUREREREdUaAwsiIiIiIqo1BhZERERERFRrDCyIiMittm3byuTJkyUcREVFyaxZs/z+OgsWLFCvlZub6/fXIiIKFgwsiIiCxA033KAORh0v27dvr5PX/+CDDyQjI8Np+cqVK2X06NF1sg2h6JxzzpG7777bbtnpp58uWVlZkp6eHrDtIiKqa7F1/opEROTS4MGD5f3337db1qhRo4BtTzC8fiiKj4+Xpk2bBnoziIjqFDMWRERBJCEhQR2Q6i8xMTEqmzFs2DC7dXGWHGfLNbh+1113yYMPPigNGjRQj33qqafsHoPSnFtvvVWaNGkiiYmJ0rVrV/nhhx9U6c6NN94oeXl51kyJ9ljHUqjdu3fLJZdcIqmpqVKvXj258sor5eDBg9b78biePXvKxx9/rB6Ls/ZXXXWVFBQUuH3vixcvlrPOOkuSkpKkVatW6r0UFRWp+x599FE59dRTnR7To0cPmTBhgjWzct5550lmZqZ6zX79+smaNWu8Kldat26dWvbvv/+q20eOHJGrr75aWrRoIcnJydKtWzf5/PPPretjvyxcuFCmTJli/dzwWKPnnjFjhnTp0kXtY3wuL7/8st32YNmzzz4rN910k6SlpUnr1q3lrbfest5fVlYmY8eOlWbNmql916ZNG5k4caLbz5SIqC4xsCAiCiMffvihpKSkyPLly+WFF15QB92//PKLus9kMsmQIUNkyZIl8sknn8jGjRvlueeeU4ELSncQPCBQQAkPLvfff7/T8+M5EFTk5OSoA2o89z///CMjRoywW2/Hjh2qlwFBCy5YF6/lCtZHtuayyy6Tv/76S6ZPn64CDRxIw7XXXisrVqxQ62k2bNig1r3mmmvUbQQuI0eOVI9btmyZdOzYUS644IJqAxp3SkpKpHfv3jJ79mxZv369Kgn7v//7P7UtgICib9++MmrUKOvnhqDI0erVq1UAhgDr77//VsHX448/rsrP9BBsnHzyybJ27Vq544475Pbbb5ctW7ao+1599VX57rvv5Msvv1TLPv30UxWMEBEFDTMREQWFkSNHmmNiYswpKSnWy+WXX26975JLLrFbf9y4ceZ+/fpZb+P6mWeeabdOnz59zA899JC6/vPPP5ujo6PNW7ZsMXz9999/35yenu60vE2bNuZXXnlFXZ87d67axt27d1vv37Bhgxn/naxYsULdfvLJJ83Jycnm/Px86zoPPPCA+dRTT3X53m+++Wbz6NGj7Zb9/vvvanuPHTumbvfo0cM8YcIE6/2PPPKI2+esrKw0p6Wlmb///nvrMmznzJkz1fX58+er20ePHrXev3btWrVs586dLp/3wgsvNN933312nzv2hZ7jc19zzTXm8847z24dfCadO3e2+5yvu+46622TyWRu3Lix+Y033lC377zzTvO5556rlhMRBSNmLIiIgkj//v1VOY52wVlqb3Tv3t3uNspmDh06pK7j+Vq2bCmdOnWq8fZt2rRJnZHXn5Xv3LmzavrGfRqcSUc5j9F2GPnzzz/V2XuUV2mXQYMGqQzJzp07rVmLzz77TF1HjICSJCzToBwLmQNkKlAKhexLYWGhKt2qqcrKSvnvf/+rSqBQXobt+vnnn71+Tnw2Z5xxht0y3N62bZt6DaP9h1IqlLNpnxvKrrAPjz/+eFUmNnfu3Bq/LyIif2DzNhFREEEZU4cOHZyWR0dHq4NpvfLycqf14uLi7G7j4BQH54DehbribjuMIABA7wcOmB2h1wDQ6/DQQw+pvoljx47Jnj177EqwUAaFngiUJ6H/AL0MKFNCb4IRfKag/1wdP9MXX3xRPR/KxBBcYP+gt8XVc/rzczvppJNUkPXTTz/Jr7/+qkqrBg4cKF9//bVftoWIyFsMLIiIQgBGZkKNvx7OXjseiLqDs+F79+6VrVu3GmYtMJKR/uy5kRNPPFEd0OOiZS3Qq4EmZWQuagoHzXgeo6BKg2wLGrLRW4DAAo3ajRs3tt6P3pHXX39d9VUAtjE7O7va0a7QF1G/fn3rZ6qH50RPyXXXXadu4yAfn5/+vXr6ueG5HJ8b+wE9Lp5CFgbBFC6XX3656ktBvwuyKUREgcZSKCKiEHDuuefKqlWr5KOPPlLlM08++aRToFEdHJSfffbZqkEaTdfa2e85c+ZYy5eQOZg3b546IC8uLnZ6Dpwhx5l7lCAhc4Am5uuvv149N5qOawqZiD/++EM1a+PgHu/x22+/tTZva/C6X3zxhXz11Vd2ZVCAEiiMRIWyIzSv4353WRoEMQiO0EiN10ODtuNITXhOfFbYNjwvsir6EbC0zw2vh9Gg8LkZZWbuu+8+9bmirAqBCZrsp06datgg78qkSZNU+dfmzZvVc+AzQKmU0dwjRESBwMCCiCgEoN8AowhhKNk+ffqokY5wQO8tDHmKx6OsCGfd8Xza2XaMDHXbbbeps+E4m49RpRyhNAcH/DjDjyAFgUb79u3VKE61gWwKRo7CATOGnO3Vq5c88cQT0rx5c7v1cJYe5U4IehyH33333Xfl6NGjKvuBkZtQVqXPaDhCtkc7UMfrP//88/L000/brfOf//xHPR8+fwzniwN5x9dFcICsAz5PfG5G/Rd4DozmhKAIQ/zivWHELvRNeAo9K9gnCOCwDxHI/Pjjj9aSLiKiQItCB3egN4KIiIiIiEIbT3MQEREREVGtMbAgIiIiIqJaY2BBRERERES1xsCCiIiIiIhqjYEFERERERHVGgMLIiIiIiKqNQYWRERERERUawwsiIiIiIio1hhYEBERERFRrTGwICIiIiKiWmNgQUREREREtcbAgoiIiIiIpLb+H4niATN6ZUGyAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(figsize=(8, 5))\n", + "ax.semilogy(\n", + " eval_history_grad,\n", + " \"o-\",\n", + " label=f\"L-BFGS-B ({len(eval_history_grad)} evals)\",\n", + " linewidth=2,\n", + " markersize=4,\n", + ")\n", + "ax.semilogy(\n", + " eval_history_free,\n", + " \"s-\",\n", + " label=f\"Nelder-Mead ({len(eval_history_free)} evals)\",\n", + " linewidth=2,\n", + " markersize=3,\n", + ")\n", + "ax.set_xlabel(\"Function evaluations\")\n", + "ax.set_ylabel(\"Objective (sensor temperature error)\")\n", + "ax.set_title(\"Gradient-based vs gradient-free optimization\")\n", + "ax.legend()\n", + "ax.grid(True, alpha=0.3)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Visualize the optimized design\n", + "\n", + "Show the converged temperature field with sensor locations and targets." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T11:54:39.210096Z", + "iopub.status.busy": "2026-03-28T11:54:39.209991Z", + "iopub.status.idle": "2026-03-28T11:54:39.364520Z", + "shell.execute_reply": "2026-03-28T11:54:39.364240Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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ZyHGjRunMhTr169HrVq10qi07i2ln4UM1Xb48GF12d96e+WVV9CwYUP1twzLQ2lTJ55++ml1ud/6Q0H8999/KoBlkJq2n4W0mU8YjFp/QJj7AVFa0OucbUqDGyXC5IZDjsgQIvPmzVNDV/To0UMNORIcHKwe79Spk+mjjz6KNzxV5syZTV999ZUaEmn48OEcnkqnz+Lzzz9Xw8UsX77cdPXq1bhbRESEjq8iY34WCbHXvz6fw4ULF9TIF3369DGdOHHCtGbNGlP+/PlNn376qY6vImN+FnJukM9i8eLFaoik33//3VS6dGk1cgylnny/y5CEcpOQZMKECerv8+fPq8flM5DPIuHwVIMGDVLnbBnS0JXDU929e9dUsGDBtIhT1fPI81F8bheoChlXrXjx4irokSFIdu3aFfdYgwYN1EnX1o8//mgqV66cWl+GvVi7dq0OpXZPKfksSpQoYbfyygmC0r5e2GKgqt/nsGPHDjVkngRVMlTVZ599poYOo7T9LB48eGAaMWKECk59fX1NxYoVM7333numW7du6VR697B582a73/vW917+l88i4TaBgYHqc5M6MXfuXJeWUYJHGTbK1TcGqfZlkn8Sy7YSEREREenFrdqoEhEREZH7YKBKRERERIbEQJWIiIiIDImBKhEREREZEgNVIiIiIjIkBqpEREREZEgMVImIiIjIkBioEhEREZEhMVAlIiIiIkNioEpEREREhsRAlYjSrdDQUBQsWBBjxoyJW7Zjxw54e3tj06ZNupaNiIi0y2QymUxO2A8RkS7WrVuHVq1aqQC1fPnyCAwMRMuWLTFhwgS9i0ZERBoxUCWidK93797YuHEjatWqhcOHD2PPnj3w8fHRu1hERKQRA1UiSvfu3r2LypUr4+LFi9i3bx+qVKmid5GIiMgJ2EaViNK906dP48qVK4iNjcW5c+f0Lg4RETkJM6pElK5FR0ejdu3aqm2qtFGdOHGiuvyfP39+vYtGREQaMVAlonRt0KBBWL58OQ4dOoTs2bOjQYMG8Pf3x5o1a/QuGhERacRL/0SUbm3ZskVlUBcsWAA/Pz94eHiov7dt24Zp06bpXTwiItKIGVUiIiIiMiRmVImIiIjIkBioEhEREZEhMVAlIiIiIkNioEpEREREhsRAlYiIiIgMiYEqERERERkSA1UiIiIiMiQGqkRERERkSAxUiYiIiMiQGKgSERERkSExUCUiIiIiQ2KgSkREREQwov8D91ztfgwZKawAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# Run the optimized design through the pipeline\n", + "opt = result_grad.x\n", + "thermal_opt = thermal_api.apply_jit(\n", + " {\n", + " \"source_x\": jnp.float32(opt[0]),\n", + " \"source_y\": jnp.float32(opt[1]),\n", + " \"source_intensity\": jnp.float32(np.exp(opt[2])),\n", + " \"source_width\": jnp.float32(0.15),\n", + " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", + " \"conductivity\": 1.0,\n", + " \"boundary_temp\": 0.0,\n", + " }\n", + ")\n", + "temp_opt = np.asarray(thermal_opt[\"temperature\"])\n", + "\n", + "fig, ax = plt.subplots(figsize=(7, 6))\n", + "im = ax.imshow(temp_opt.T, origin=\"lower\", extent=[0, 1, 0, 1], cmap=\"hot\")\n", + "plt.colorbar(im, ax=ax, label=\"Temperature\")\n", + "\n", + "# Plot sensor locations and achieved vs target temperatures\n", + "for (si, sj), target in zip(SENSORS, TARGETS, strict=False):\n", + " px, py = si / 31, sj / 31\n", + " achieved = float(temp_opt[si, sj])\n", + " ax.plot(px, py, \"wo\", markersize=10, markeredgecolor=\"blue\", markeredgewidth=2)\n", + " ax.annotate(\n", + " f\"T={achieved:.3f}\\n(target={float(target):.3f})\",\n", + " xy=(px, py),\n", + " xytext=(5, 5),\n", + " textcoords=\"offset points\",\n", + " fontsize=8,\n", + " color=\"white\",\n", + " fontweight=\"bold\",\n", + " bbox=dict(boxstyle=\"round,pad=0.2\", facecolor=\"black\", alpha=0.7),\n", + " )\n", + "\n", + "# Plot optimized source location\n", + "ax.plot(\n", + " float(opt[0]),\n", + " float(opt[1]),\n", + " \"r*\",\n", + " markersize=20,\n", + " markeredgecolor=\"white\",\n", + " markeredgewidth=1,\n", + ")\n", + "ax.annotate(\n", + " f\"Source\\n({float(opt[0]):.2f}, {float(opt[1]):.2f})\\nq={float(np.exp(opt[2])):.1f}\",\n", + " xy=(float(opt[0]), float(opt[1])),\n", + " xytext=(10, -20),\n", + " textcoords=\"offset points\",\n", + " fontsize=9,\n", + " color=\"red\",\n", + " fontweight=\"bold\",\n", + " bbox=dict(boxstyle=\"round,pad=0.2\", facecolor=\"white\", alpha=0.8),\n", + ")\n", + "\n", + "ax.set_title(\"Optimized temperature field with sensor locations\")\n", + "ax.set_xlabel(\"x\")\n", + "ax.set_ylabel(\"y\")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. Modularity: swap a solver, change nothing else\n", + "\n", + "We replace the thermal solver with a coarser version (fewer Jacobi iterations \u2014 faster but less accurate). The optimization code is identical. Only the solver changes." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T11:54:39.366150Z", + "iopub.status.busy": "2026-03-28T11:54:39.366025Z", + "iopub.status.idle": "2026-03-28T11:54:49.359087Z", + "shell.execute_reply": "2026-03-28T11:54:49.358612Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running L-BFGS-B with swapped (fast) thermal solver...\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Source: (0.674, 0.674)\n", + " Intensity: 2.73\n", + " Objective: 3.169720e-06\n", + " Evaluations: 27\n", + "\n", + " (Original solver found: (0.674, 0.674), q=2.73)\n" + ] + } + ], + "source": [ + "# Swap in a \"fast\" thermal solver (100 vs 500 Jacobi iterations)\n", + "# In practice: point to a different Tesseract image\n", + "original_solve = thermal_api._solve_heat_jacobi\n", + "\n", + "\n", + "def fast_solve(source, conductivity, boundary_temp, n_iters=100):\n", + " return original_solve(source, conductivity, boundary_temp, n_iters=n_iters)\n", + "\n", + "\n", + "thermal_api._solve_heat_jacobi = fast_solve\n", + "\n", + "# Same optimization code, same objective, same grad_fn\n", + "eval_history_swapped = []\n", + "\n", + "\n", + "def objective_and_grad_swapped(x):\n", + " p = jnp.array(x, dtype=jnp.float32)\n", + " obj = coupled_objective(p)\n", + " g = grad_fn(p)\n", + " eval_history_swapped.append(float(obj))\n", + " return float(obj), np.array([float(g[i]) for i in range(3)])\n", + "\n", + "\n", + "print(\"Running L-BFGS-B with swapped (fast) thermal solver...\")\n", + "result_swapped = minimize(\n", + " objective_and_grad_swapped,\n", + " x0,\n", + " method=\"L-BFGS-B\",\n", + " jac=True,\n", + " bounds=bounds,\n", + " options={\"maxiter\": 100},\n", + ")\n", + "print(f\" Source: ({result_swapped.x[0]:.3f}, {result_swapped.x[1]:.3f})\")\n", + "print(f\" Intensity: {np.exp(result_swapped.x[2]):.2f}\")\n", + "print(f\" Objective: {result_swapped.fun:.6e}\")\n", + "print(f\" Evaluations: {len(eval_history_swapped)}\")\n", + "print(\n", + " f\"\\n (Original solver found: ({result_grad.x[0]:.3f}, {result_grad.x[1]:.3f}), q={np.exp(result_grad.x[2]):.2f})\"\n", + ")\n", + "\n", + "thermal_api._solve_heat_jacobi = original_solve # restore" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8. Implicit differentiation: O(1) memory gradients via the implicit function theorem\n", + "\n", + "The unrolled `lax.scan` approach above stores all intermediate states for backpropagation \u2014 memory scales as O(N) in coupling iterations. For large-scale problems (fine meshes, many iterations), this becomes the bottleneck.\n", + "\n", + "**Implicit differentiation** avoids this entirely. The key insight: at the converged fixed point $(T^*, D^*) = G(T^*, D^*, \\theta)$, the implicit function theorem gives the sensitivity without replaying the iteration. The backward pass solves a single linear system instead of backpropagating through N steps.\n", + "\n", + "Concretely, if $v = \\partial L / \\partial (T^*, D^*)$ is the loss gradient w.r.t. the fixed point, then:\n", + "\n", + "$$\\lambda = (I - \\partial G / \\partial (T, D))^{-T} v$$\n", + "$$\\partial L / \\partial \\theta = \\lambda^T \\cdot \\partial G / \\partial \\theta$$\n", + "\n", + "We solve for $\\lambda$ via fixed-point iteration on the adjoint equation \u2014 the same structure as the forward solve, but linear." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T11:54:49.361002Z", + "iopub.status.busy": "2026-03-28T11:54:49.360882Z", + "iopub.status.idle": "2026-03-28T11:54:49.630737Z", + "shell.execute_reply": "2026-03-28T11:54:49.630348Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Forward pass comparison:\n", + " Unrolled: 6.1757038347e-03\n", + " Implicit: 6.1757038347e-03\n", + " Match: True\n" + ] + } + ], + "source": [ + "def coupled_objective_implicit(params):\n", + " \"\"\"Same inverse problem, but differentiated via the implicit function theorem.\n", + "\n", + " Forward pass: iterate G to convergence (no scan intermediates stored for AD).\n", + " Backward pass: solve adjoint equation (I - dG/d(T,D))^T \u03bb = v via fixed-point iteration.\n", + " \"\"\"\n", + " source_x, source_y, log_intensity = params[0], params[1], params[2]\n", + " intensity = jnp.exp(log_intensity)\n", + "\n", + " def G(temp_disp, params_inner):\n", + " \"\"\"One coupling step: (temp, disp) -> (new_temp, new_disp).\n", + "\n", + " params_inner is (source_x, source_y, intensity) \u2014 the differentiable parameters.\n", + " \"\"\"\n", + " _temp, disp = temp_disp\n", + " sx, sy, q = params_inner\n", + " thermal_out = thermal_api.apply_jit(\n", + " {\n", + " \"source_x\": sx,\n", + " \"source_y\": sy,\n", + " \"source_intensity\": q,\n", + " \"source_width\": jnp.float32(0.15),\n", + " \"displacement\": disp,\n", + " \"conductivity\": 1.0,\n", + " \"boundary_temp\": 0.0,\n", + " }\n", + " )\n", + " structural_out = structural_api.apply_jit(\n", + " {\n", + " \"temperature\": thermal_out[\"temperature\"],\n", + " \"youngs_modulus\": 200.0,\n", + " \"poissons_ratio\": 0.3,\n", + " \"thermal_expansion\": 1e-3,\n", + " }\n", + " )\n", + " return (thermal_out[\"temperature\"], structural_out[\"displacement\"])\n", + "\n", + " @jax.custom_vjp\n", + " def solve_fixed_point(params_inner):\n", + " \"\"\"Run fixed-point iteration to convergence, return the fixed point.\"\"\"\n", + " temp = jnp.zeros((30, 30), dtype=jnp.float32)\n", + " disp = jnp.zeros((30, 30, 2), dtype=jnp.float32)\n", + "\n", + " def step(carry, _):\n", + " return G(carry, params_inner), None\n", + "\n", + " (final_temp, final_disp), _ = jax.lax.scan(\n", + " step, (temp, disp), None, length=N_COUPLING_ITERS\n", + " )\n", + " return (final_temp, final_disp)\n", + "\n", + " def solve_fwd(params_inner):\n", + " fixed_point = solve_fixed_point(params_inner)\n", + " # Save fixed point and params for backward pass (NOT intermediates)\n", + " return fixed_point, (fixed_point, params_inner)\n", + "\n", + " def solve_bwd(res, g):\n", + " \"\"\"Implicit differentiation backward pass.\n", + "\n", + " g = (v_temp, v_disp) \u2014 cotangents w.r.t. the fixed point.\n", + "\n", + " We need to solve: (I - dG/d(T,D))^T \u03bb = v for \u03bb,\n", + " then compute: dL/d\u03b8 = \u03bb^T \u00b7 dG/d\u03b8.\n", + "\n", + " We solve for \u03bb by iterating: \u03bb_{k+1} = v + (dG/d(T,D))^T \u03bb_k.\n", + " This converges if the forward iteration is contractive.\n", + " \"\"\"\n", + " (fixed_temp, fixed_disp), params_inner = res\n", + " v_temp, v_disp = g\n", + "\n", + " # Define G_state: maps (temp, disp) -> (new_temp, new_disp) at fixed params\n", + " def G_state(temp_disp):\n", + " return G(temp_disp, params_inner)\n", + "\n", + " # Solve adjoint: \u03bb = v + (dG/d(T,D))^T \u03bb via fixed-point iteration\n", + " def adjoint_step(lam, _):\n", + " lam_temp, lam_disp = lam\n", + " # Compute (dG/d(T,D))^T @ \u03bb via VJP\n", + " _, vjp_G_state = jax.vjp(G_state, (fixed_temp, fixed_disp))\n", + " dGT_lam = vjp_G_state((lam_temp, lam_disp))[0]\n", + " # \u03bb_{k+1} = v + (dG/d(T,D))^T \u03bb_k\n", + " new_lam_temp = v_temp + dGT_lam[0]\n", + " new_lam_disp = v_disp + dGT_lam[1]\n", + " return (new_lam_temp, new_lam_disp), None\n", + "\n", + " N_ADJOINT_ITERS = 20 # typically converges faster than forward\n", + " lam_init = (v_temp, v_disp)\n", + " (lam_temp, lam_disp), _ = jax.lax.scan(\n", + " adjoint_step, lam_init, None, length=N_ADJOINT_ITERS\n", + " )\n", + "\n", + " # Now compute dL/d\u03b8 = \u03bb^T \u00b7 dG/d\u03b8 via VJP of G w.r.t. params\n", + " def G_params(p):\n", + " return G((fixed_temp, fixed_disp), p)\n", + "\n", + " _, vjp_G_params = jax.vjp(G_params, params_inner)\n", + " grad_params = vjp_G_params((lam_temp, lam_disp))[0]\n", + " return (grad_params,)\n", + "\n", + " solve_fixed_point.defvjp(solve_fwd, solve_bwd)\n", + "\n", + " # --- Use the implicit fixed-point solve ---\n", + " final_temp, _final_disp = solve_fixed_point((source_x, source_y, intensity))\n", + "\n", + " loss = jnp.float32(0.0)\n", + " for (si, sj), target in zip(SENSORS, TARGETS, strict=False):\n", + " loss = loss + (final_temp[si, sj] - target) ** 2\n", + " return loss\n", + "\n", + "\n", + "# Verify forward pass matches the unrolled version\n", + "loss_implicit = coupled_objective_implicit(p0)\n", + "loss_unrolled = coupled_objective(p0)\n", + "print(\"Forward pass comparison:\")\n", + "print(f\" Unrolled: {float(loss_unrolled):.10e}\")\n", + "print(f\" Implicit: {float(loss_implicit):.10e}\")\n", + "print(f\" Match: {jnp.allclose(loss_unrolled, loss_implicit)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T11:54:49.632754Z", + "iopub.status.busy": "2026-03-28T11:54:49.632521Z", + "iopub.status.idle": "2026-03-28T11:54:51.500992Z", + "shell.execute_reply": "2026-03-28T11:54:51.500423Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Unrolled Implicit FD Impl vs FD\n", + "d(loss)/d(source_x) 2.295046e-02 2.295046e-02 2.295244e-02 8.63e-05\n", + "d(loss)/d(source_y) 2.295046e-02 2.295046e-02 2.295244e-02 8.63e-05\n", + "d(loss)/d(log_intensity) 8.693038e-03 8.693038e-03 8.689240e-03 4.37e-04\n" + ] + } + ], + "source": [ + "# Compare gradients: implicit vs unrolled vs finite differences\n", + "grad_implicit = jax.grad(coupled_objective_implicit)(p0)\n", + "grad_unrolled = jax.grad(coupled_objective)(p0)\n", + "\n", + "# Finite differences as ground truth\n", + "eps = 1e-4\n", + "fd_grads_check = []\n", + "for i in range(3):\n", + " p_plus = p0.at[i].add(eps)\n", + " p_minus = p0.at[i].add(-eps)\n", + " fd_grads_check.append(\n", + " (coupled_objective_implicit(p_plus) - coupled_objective_implicit(p_minus))\n", + " / (2 * eps)\n", + " )\n", + "\n", + "names = [\"d(loss)/d(source_x)\", \"d(loss)/d(source_y)\", \"d(loss)/d(log_intensity)\"]\n", + "print(f\"{'':32s} {'Unrolled':>14s} {'Implicit':>14s} {'FD':>14s} {'Impl vs FD':>12s}\")\n", + "for name, u, im, fd in zip(\n", + " names, grad_unrolled, grad_implicit, fd_grads_check, strict=False\n", + "):\n", + " rel_err = abs(float(im) - float(fd)) / (abs(float(fd)) + 1e-30)\n", + " print(\n", + " f\"{name:32s} {float(u):14.6e} {float(im):14.6e} {float(fd):14.6e} {rel_err:12.2e}\"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Memory scaling: why this matters\n", + "\n", + "With the unrolled approach, JAX stores the full state at every coupling iteration for backpropagation. Memory cost: **O(N \u00d7 state_size)**.\n", + "\n", + "With implicit differentiation, the forward pass runs to convergence and discards intermediates. The backward pass solves the adjoint equation at the fixed point only \u2014 no replay of the iteration. Memory cost: **O(state_size)** regardless of N.\n", + "\n", + "For this 30\u00d730 demo the difference is negligible. For production-scale problems (million-node meshes, hundreds of coupling iterations), it's the difference between \"fits in GPU memory\" and \"doesn't\"." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Summary\n", + "\n", + "| What | How |\n", + "|---|---|\n", + "| Each solver is independent | Separate `tesseract_api.py`, separate container, separate team |\n", + "| Two-way coupling | `jax.lax.scan` over alternating solver calls |\n", + "| End-to-end gradients | `jax.grad` \u2014 JAX handles the chain rule through the coupled iteration |\n", + "| Gradient correctness | Validated against finite differences |\n", + "| Implicit differentiation | `jax.custom_vjp` + adjoint solve for O(1) memory |\n", + "| Solver swapping | Change the Tesseract reference, optimization code unchanged |\n", + "\n", + "### What's next\n", + "\n", + "- **Production deployment**: Build and serve Tesseracts as Docker containers, compose via `tesseract-jax`'s `apply_tesseract`\n", + "- **Scale up**: Larger meshes, more coupling iterations, GPU acceleration" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 9. Production path: composing Tesseracts with `tesseract-jax`\n", + "\n", + "The cells above call `apply_jit` directly \u2014 bypassing the Tesseract runtime for speed. In production, each solver is a containerized Tesseract and you compose them with `tesseract-jax`'s `apply_tesseract`, a JAX primitive that routes to the Tesseract's endpoints. `jax.grad` and `jax.jit` work through it automatically.\n", + "\n", + "**Important pattern**: when using `apply_tesseract` inside `lax.scan`, non-differentiable constants must be passed as **numpy arrays** (`np.float32`), not JAX arrays (`jnp.float32`). Inside a scan, JAX traces all array inputs uniformly \u2014 it can't tell which ones are constants. If a non-differentiable field gets traced, the backward pass will try to differentiate through it and the VJP endpoint will reject the field name. Using `np` arrays keeps them opaque to the tracer." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "execution": { + "iopub.execute_input": "2026-03-28T11:54:51.503944Z", + "iopub.status.busy": "2026-03-28T11:54:51.503790Z", + "iopub.status.idle": "2026-03-28T11:54:52.913846Z", + "shell.execute_reply": "2026-03-28T11:54:52.913414Z" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/dion/.virtualenvs/science/lib/python3.12/site-packages/jax/_src/ops/scatter.py:108: FutureWarning: scatter inputs have incompatible types: cannot safely cast value from dtype=float64 to dtype=float32 with jax_numpy_dtype_promotion=standard. In future JAX releases this will result in an error.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Forward pass via apply_tesseract matches direct call:\n", + " Temperature max error: 2.24e-07\n", + " Displacement max error: 2.18e-11\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Gradient through single apply_tesseract: d(sum_T)/d(source_x) = 5.726115e+01\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "End-to-end gradient through apply_tesseract + lax.scan:\n", + " apply_tesseract direct\n", + " d(loss)/d(source_x) 2.295040e-02 2.295046e-02\n", + " d(loss)/d(source_y) 2.295040e-02 2.295046e-02\n", + " d(loss)/d(log_intensity) 8.693015e-03 8.693038e-03\n" + ] + } + ], + "source": [ + "from tesseract_jax import apply_tesseract\n", + "\n", + "from tesseract_core.sdk.tesseract import Tesseract\n", + "\n", + "# Load Tesseracts (in-process, no Docker)\n", + "thermal_tess = Tesseract.from_tesseract_api(\"thermal_solver/tesseract_api.py\")\n", + "structural_tess = Tesseract.from_tesseract_api(\"structural_solver/tesseract_api.py\")\n", + "\n", + "# Forward pass through both Tesseracts via apply_tesseract\n", + "thermal_out_tj = apply_tesseract(\n", + " thermal_tess,\n", + " {\n", + " \"source_x\": jnp.float32(0.5),\n", + " \"source_y\": jnp.float32(0.5),\n", + " \"source_intensity\": jnp.float32(10.0),\n", + " \"source_width\": np.float32(0.1), # np: non-differentiable constant\n", + " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", + " \"conductivity\": np.float32(1.0), # np: non-differentiable constant\n", + " \"boundary_temp\": np.float32(0.0), # np: non-differentiable constant\n", + " },\n", + ")\n", + "\n", + "structural_out_tj = apply_tesseract(\n", + " structural_tess,\n", + " {\n", + " \"temperature\": thermal_out_tj[\"temperature\"],\n", + " \"youngs_modulus\": np.float32(200.0), # np: non-differentiable constant\n", + " \"poissons_ratio\": np.float32(0.3), # np: non-differentiable constant\n", + " \"thermal_expansion\": np.float32(1e-3), # np: non-differentiable constant\n", + " },\n", + ")\n", + "\n", + "# Verify: matches direct apply_jit\n", + "print(\"Forward pass via apply_tesseract matches direct call:\")\n", + "print(\n", + " f\" Temperature max error: \"\n", + " f\"{float(jnp.max(jnp.abs(thermal_out_tj['temperature'] - thermal_out['temperature']))):.2e}\"\n", + ")\n", + "print(\n", + " f\" Displacement max error: \"\n", + " f\"{float(jnp.max(jnp.abs(structural_out_tj['displacement'] - structural_out['displacement']))):.2e}\"\n", + ")\n", + "\n", + "\n", + "# Gradient through a single Tesseract call\n", + "def single_thermal_loss(source_x):\n", + " out = apply_tesseract(\n", + " thermal_tess,\n", + " {\n", + " \"source_x\": source_x,\n", + " \"source_y\": jnp.float32(0.5),\n", + " \"source_intensity\": jnp.float32(10.0),\n", + " \"source_width\": np.float32(0.1),\n", + " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", + " \"conductivity\": np.float32(1.0),\n", + " \"boundary_temp\": np.float32(0.0),\n", + " },\n", + " )\n", + " return jnp.sum(out[\"temperature\"])\n", + "\n", + "\n", + "grad_single = jax.grad(single_thermal_loss)(jnp.float32(0.3))\n", + "print(\n", + " f\"\\nGradient through single apply_tesseract: d(sum_T)/d(source_x) = {float(grad_single):.6e}\"\n", + ")\n", + "\n", + "\n", + "# Full coupled pipeline: apply_tesseract + lax.scan + jax.grad\n", + "# Key: non-differentiable constants use np (not jnp) so JAX doesn't trace them\n", + "def coupled_objective_tesseract(params):\n", + " source_x, source_y, log_intensity = params[0], params[1], params[2]\n", + " intensity = jnp.exp(log_intensity)\n", + "\n", + " temp = jnp.zeros((30, 30), dtype=jnp.float32)\n", + " disp = jnp.zeros((30, 30, 2), dtype=jnp.float32)\n", + "\n", + " def coupling_step(carry, _):\n", + " _temp, disp = carry\n", + " thermal_out = apply_tesseract(\n", + " thermal_tess,\n", + " {\n", + " \"source_x\": source_x,\n", + " \"source_y\": source_y,\n", + " \"source_intensity\": intensity,\n", + " \"source_width\": np.float32(0.15),\n", + " \"displacement\": disp,\n", + " \"conductivity\": np.float32(1.0),\n", + " \"boundary_temp\": np.float32(0.0),\n", + " },\n", + " )\n", + " structural_out = apply_tesseract(\n", + " structural_tess,\n", + " {\n", + " \"temperature\": thermal_out[\"temperature\"],\n", + " \"youngs_modulus\": np.float32(200.0),\n", + " \"poissons_ratio\": np.float32(0.3),\n", + " \"thermal_expansion\": np.float32(1e-3),\n", + " },\n", + " )\n", + " return (thermal_out[\"temperature\"], structural_out[\"displacement\"]), None\n", + "\n", + " (final_temp, _), _ = jax.lax.scan(\n", + " coupling_step, (temp, disp), None, length=N_COUPLING_ITERS\n", + " )\n", + "\n", + " loss = jnp.float32(0.0)\n", + " for (si, sj), target in zip(SENSORS, TARGETS, strict=False):\n", + " loss = loss + (final_temp[si, sj] - target) ** 2\n", + " return loss\n", + "\n", + "\n", + "# End-to-end gradient through apply_tesseract + lax.scan\n", + "grad_tess = jax.grad(coupled_objective_tesseract)(p0)\n", + "grad_direct = jax.grad(coupled_objective)(p0)\n", + "\n", + "print(\"\\nEnd-to-end gradient through apply_tesseract + lax.scan:\")\n", + "print(f\" {'':32s} {'apply_tesseract':>16s} {'direct':>16s}\")\n", + "for name, gt, gd in zip(names, grad_tess, grad_direct, strict=False):\n", + " print(f\" {name:32s} {float(gt):16.6e} {float(gd):16.6e}\")" + ] + } + ], + "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.12.7" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/demo/multiphysics-optimization/demo.ipynb b/demo/multiphysics-optimization/demo.ipynb new file mode 100644 index 000000000..b4a81175c --- /dev/null +++ b/demo/multiphysics-optimization/demo.ipynb @@ -0,0 +1,3299 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Multi-Physics Pipeline with End-to-End Gradient Optimization\n", + "\n", + "This demo shows how to compose two physics solvers from different domains \u2014 thermal and structural \u2014 into a coupled pipeline, and solve a design inverse problem with **end-to-end gradients flowing automatically through the full chain**.\n", + "\n", + "Each solver is an independent Tesseract. The pipeline uses two-way (partitioned) coupling: the thermal solver produces a temperature field that causes thermal strain in the structural solver, and the resulting displacement feeds back to the thermal solver by deforming the geometry. Gradients propagate through this coupled iteration via JAX's automatic differentiation.\n", + "\n", + "## What we demonstrate\n", + "\n", + "1. **Two independent Tesseracts** \u2014 each team keeps their solver, their AD strategy, their dependencies\n", + "2. **Two-way coupling** via `jax.lax.scan` \u2014 not a toy feedforward chain, but the real partitioned coupling pattern used in practice\n", + "3. **End-to-end gradients** \u2014 `jax.grad` through the coupled iteration, validated against finite differences\n", + "4. **Gradient-based optimization beats gradient-free** \u2014 fewer evaluations for a 3-parameter design problem\n", + "5. **Solver swapping** \u2014 change one Tesseract, optimization code stays the same" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import jax\n", + "import jax.numpy as jnp\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from scipy.optimize import minimize\n", + "\n", + "jax.config.update(\"jax_enable_x64\", True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#", + "#", + " ", + "1", + ".", + " ", + "L", + "o", + "a", + "d", + " ", + "t", + "h", + "e", + " ", + "s", + "o", + "l", + "v", + "e", + "r", + "s", + "\n", + "\n", + "E", + "a", + "c", + "h", + " ", + "s", + "o", + "l", + "v", + "e", + "r", + " ", + "i", + "s", + " ", + "a", + " ", + "s", + "t", + "a", + "n", + "d", + "a", + "l", + "o", + "n", + "e", + " ", + "T", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + " ", + "m", + "o", + "d", + "u", + "l", + "e", + " ", + "w", + "i", + "t", + "h", + " ", + "i", + "t", + "s", + " ", + "o", + "w", + "n", + " ", + "`", + "t", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + "_", + "a", + "p", + "i", + ".", + "p", + "y", + "`", + ".", + " ", + "I", + "n", + " ", + "p", + "r", + "o", + "d", + "u", + "c", + "t", + "i", + "o", + "n", + ",", + " ", + "t", + "h", + "e", + "s", + "e", + " ", + "w", + "o", + "u", + "l", + "d", + " ", + "b", + "e", + " ", + "c", + "o", + "n", + "t", + "a", + "i", + "n", + "e", + "r", + "i", + "z", + "e", + "d", + " ", + "i", + "m", + "a", + "g", + "e", + "s", + " ", + "c", + "o", + "m", + "p", + "o", + "s", + "e", + "d", + " ", + "v", + "i", + "a", + " ", + "`", + "t", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + "-", + "j", + "a", + "x", + "`", + "'", + "s", + " ", + "`", + "a", + "p", + "p", + "l", + "y", + "_", + "t", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + "`", + ".", + " ", + "H", + "e", + "r", + "e", + " ", + "w", + "e", + " ", + "i", + "m", + "p", + "o", + "r", + "t", + " ", + "t", + "h", + "e", + "m", + " ", + "d", + "i", + "r", + "e", + "c", + "t", + "l", + "y", + " ", + "f", + "o", + "r", + " ", + "s", + "p", + "e", + "e", + "d", + "." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "\n", + "sys.path.insert(0, \".\")\n", + "\n", + "import structural_solver.tesseract_api as structural_api\n", + "import thermal_solver.tesseract_api as thermal_api\n", + "\n", + "print(\"Thermal solver loaded:\", thermal_api.__doc__.strip().split(\"\\n\")[0])\n", + "print(\"Structural solver loaded:\", structural_api.__doc__.strip().split(\"\\n\")[0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Forward pass: single-shot thermal \u2192 structural\n", + "\n", + "Before coupling, let's verify each solver works independently and visualize the physics." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Run thermal solver\n", + "thermal_out = thermal_api.apply_jit(\n", + " {\n", + " \"source_x\": jnp.float32(0.5),\n", + " \"source_y\": jnp.float32(0.5),\n", + " \"source_intensity\": jnp.float32(10.0),\n", + " \"source_width\": 0.1,\n", + " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", + " \"conductivity\": 1.0,\n", + " \"boundary_temp\": 0.0,\n", + " }\n", + ")\n", + "temperature = np.asarray(thermal_out[\"temperature\"])\n", + "\n", + "# Run structural solver\n", + "structural_out = structural_api.apply_jit(\n", + " {\n", + " \"temperature\": thermal_out[\"temperature\"],\n", + " \"youngs_modulus\": 200.0,\n", + " \"poissons_ratio\": 0.3,\n", + " \"thermal_expansion\": 1e-3,\n", + " }\n", + ")\n", + "\n", + "fig, axes = plt.subplots(1, 3, figsize=(14, 4))\n", + "im0 = axes[0].imshow(temperature.T, origin=\"lower\", extent=[0, 1, 0, 1], cmap=\"hot\")\n", + "axes[0].set_title(\"Temperature field\")\n", + "plt.colorbar(im0, ax=axes[0])\n", + "\n", + "disp_mag = np.linalg.norm(np.asarray(structural_out[\"displacement\"]), axis=-1)\n", + "im1 = axes[1].imshow(disp_mag.T, origin=\"lower\", extent=[0, 1, 0, 1], cmap=\"viridis\")\n", + "axes[1].set_title(\"Displacement magnitude\")\n", + "plt.colorbar(im1, ax=axes[1])\n", + "\n", + "s = np.asarray(structural_out[\"stress\"])\n", + "von_mises = np.sqrt(\n", + " s[:, :, 0] ** 2 - s[:, :, 0] * s[:, :, 1] + s[:, :, 1] ** 2 + 3 * s[:, :, 2] ** 2\n", + ")\n", + "im2 = axes[2].imshow(von_mises.T, origin=\"lower\", extent=[0, 1, 0, 1], cmap=\"inferno\")\n", + "axes[2].set_title(\"Von Mises stress\")\n", + "plt.colorbar(im2, ax=axes[2])\n", + "\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. The design problem: thermoelastic inverse optimization\n", + "\n", + "**Problem**: Find the heat source location and intensity that produces desired temperatures at four sensor locations, after the thermoelastic coupling has converged.\n", + "\n", + "This can't be solved with the thermal solver alone \u2014 the displacement from thermal expansion changes the geometry, which changes the temperature field. You need gradients through the full coupled iteration.\n", + "\n", + "**Design variables**: source position $(x, y)$ and log-intensity $\\log(q)$ (3 parameters).\n", + "\n", + "**Objective**: $\\sum_i (T_{\\text{sensor}_i} - T_{\\text{target}_i})^2$ evaluated after coupled convergence." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Sensor locations (grid indices) and target temperatures\n", + "SENSORS = [(8, 8), (8, 22), (22, 8), (22, 22)]\n", + "TARGETS = [jnp.float32(0.01), jnp.float32(0.02), jnp.float32(0.02), jnp.float32(0.05)]\n", + "\n", + "# Approximate physical positions of sensors (for visualization)\n", + "sensor_positions = [(i / 31, j / 31) for i, j in SENSORS]\n", + "print(\"Sensor positions (approx):\")\n", + "for (sx, sy), t in zip(sensor_positions, TARGETS, strict=False):\n", + " print(f\" ({sx:.2f}, {sy:.2f}) -> T_target = {float(t):.3f}\")\n", + "\n", + "N_COUPLING_ITERS = 3\n", + "\n", + "\n", + "def coupled_objective(params):\n", + " \"\"\"Two-way coupled thermoelastic inverse problem.\n", + "\n", + " params: [source_x, source_y, log_intensity]\n", + " Returns: sum of squared temperature errors at sensor locations.\n", + " \"\"\"\n", + " source_x, source_y, log_intensity = params[0], params[1], params[2]\n", + " intensity = jnp.exp(log_intensity)\n", + "\n", + " temp = jnp.zeros((30, 30), dtype=jnp.float32)\n", + " disp = jnp.zeros((30, 30, 2), dtype=jnp.float32)\n", + "\n", + " def coupling_step(carry, _):\n", + " _temp, disp = carry\n", + " thermal_out = thermal_api.apply_jit(\n", + " {\n", + " \"source_x\": source_x,\n", + " \"source_y\": source_y,\n", + " \"source_intensity\": intensity,\n", + " \"source_width\": jnp.float32(0.15),\n", + " \"displacement\": disp,\n", + " \"conductivity\": 1.0,\n", + " \"boundary_temp\": 0.0,\n", + " }\n", + " )\n", + " structural_out = structural_api.apply_jit(\n", + " {\n", + " \"temperature\": thermal_out[\"temperature\"],\n", + " \"youngs_modulus\": 200.0,\n", + " \"poissons_ratio\": 0.3,\n", + " \"thermal_expansion\": 1e-3,\n", + " }\n", + " )\n", + " return (thermal_out[\"temperature\"], structural_out[\"displacement\"]), None\n", + "\n", + " (final_temp, _), _ = jax.lax.scan(\n", + " coupling_step, (temp, disp), None, length=N_COUPLING_ITERS\n", + " )\n", + "\n", + " loss = jnp.float32(0.0)\n", + " for (si, sj), target in zip(SENSORS, TARGETS, strict=False):\n", + " loss = loss + (final_temp[si, sj] - target) ** 2\n", + " return loss\n", + "\n", + "\n", + "# Test forward pass\n", + "p0 = jnp.array([0.2, 0.2, jnp.log(5.0)], dtype=jnp.float32)\n", + "print(f\"\\nObjective at initial guess: {float(coupled_objective(p0)):.6e}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. End-to-end gradients through the coupled pipeline\n", + "\n", + "The key moment: `jax.grad` differentiates through the entire coupled iteration \u2014 through both solvers, through `lax.scan`, automatically. No manual adjoint derivation, no monolithic rewrite." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "grad_fn = jax.grad(coupled_objective)\n", + "\n", + "grads = grad_fn(p0)\n", + "print(\"Gradients at initial guess:\")\n", + "print(f\" d(loss)/d(source_x) = {float(grads[0]):.6e}\")\n", + "print(f\" d(loss)/d(source_y) = {float(grads[1]):.6e}\")\n", + "print(f\" d(loss)/d(log_intensity) = {float(grads[2]):.6e}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Gradient validation against finite differences\n", + "\n", + "For a rigorous audience, correctness proof is non-negotiable." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "eps = 1e-4\n", + "fd_grads = []\n", + "for i in range(3):\n", + " p_plus = p0.at[i].add(eps)\n", + " p_minus = p0.at[i].add(-eps)\n", + " fd_grads.append(\n", + " (coupled_objective(p_plus) - coupled_objective(p_minus)) / (2 * eps)\n", + " )\n", + "\n", + "names = [\"d(loss)/d(source_x)\", \"d(loss)/d(source_y)\", \"d(loss)/d(log_intensity)\"]\n", + "print(f\"{'':32s} {'AD':>14s} {'FD':>14s} {'Rel. Error':>12s}\")\n", + "for name, ad, fd in zip(names, grads, fd_grads, strict=False):\n", + " rel_err = abs(float(ad) - float(fd)) / (abs(float(fd)) + 1e-30)\n", + " print(f\"{name:32s} {float(ad):14.6e} {float(fd):14.6e} {rel_err:12.2e}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Optimization: gradient-based vs gradient-free\n", + "\n", + "We compare:\n", + "- **L-BFGS-B** (gradient-based, using our end-to-end gradients)\n", + "- **Nelder-Mead** (gradient-free)\n", + "\n", + "Both optimize 3 design variables: source position $(x, y)$ and log-intensity." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "eval_history_grad = []\n", + "eval_history_free = []\n", + "\n", + "\n", + "def objective_and_grad(x):\n", + " p = jnp.array(x, dtype=jnp.float32)\n", + " obj = coupled_objective(p)\n", + " g = grad_fn(p)\n", + " eval_history_grad.append(float(obj))\n", + " return float(obj), np.array([float(g[i]) for i in range(3)])\n", + "\n", + "\n", + "def objective_only(x):\n", + " p = jnp.array(x, dtype=jnp.float32)\n", + " obj = coupled_objective(p)\n", + " eval_history_free.append(float(obj))\n", + " return float(obj)\n", + "\n", + "\n", + "x0 = np.array([0.2, 0.2, np.log(5.0)])\n", + "bounds = [(0.05, 0.95), (0.05, 0.95), (np.log(1.0), np.log(50.0))]\n", + "\n", + "print(\"Running L-BFGS-B (gradient-based)...\")\n", + "result_grad = minimize(\n", + " objective_and_grad,\n", + " x0,\n", + " method=\"L-BFGS-B\",\n", + " jac=True,\n", + " bounds=bounds,\n", + " options={\"maxiter\": 100},\n", + ")\n", + "print(f\" Source: ({result_grad.x[0]:.3f}, {result_grad.x[1]:.3f})\")\n", + "print(f\" Intensity: {np.exp(result_grad.x[2]):.2f}\")\n", + "print(f\" Objective: {result_grad.fun:.6e}\")\n", + "print(f\" Evaluations: {len(eval_history_grad)}\")\n", + "\n", + "print(\"\\nRunning Nelder-Mead (gradient-free)...\")\n", + "result_free = minimize(\n", + " objective_only,\n", + " x0,\n", + " method=\"Nelder-Mead\",\n", + " options={\"maxiter\": 500, \"xatol\": 1e-6, \"fatol\": 1e-15},\n", + ")\n", + "print(f\" Source: ({result_free.x[0]:.3f}, {result_free.x[1]:.3f})\")\n", + "print(f\" Intensity: {np.exp(result_free.x[2]):.2f}\")\n", + "print(f\" Objective: {result_free.fun:.6e}\")\n", + "print(f\" Evaluations: {len(eval_history_free)}\")\n", + "\n", + "print(\n", + " f\"\\nSpeedup: {len(eval_history_free)}/{len(eval_history_grad)} \"\n", + " f\"= {len(eval_history_free) / max(len(eval_history_grad), 1):.1f}x fewer evaluations with gradients\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(figsize=(8, 5))\n", + "ax.semilogy(\n", + " eval_history_grad,\n", + " \"o-\",\n", + " label=f\"L-BFGS-B ({len(eval_history_grad)} evals)\",\n", + " linewidth=2,\n", + " markersize=4,\n", + ")\n", + "ax.semilogy(\n", + " eval_history_free,\n", + " \"s-\",\n", + " label=f\"Nelder-Mead ({len(eval_history_free)} evals)\",\n", + " linewidth=2,\n", + " markersize=3,\n", + ")\n", + "ax.set_xlabel(\"Function evaluations\")\n", + "ax.set_ylabel(\"Objective (sensor temperature error)\")\n", + "ax.set_title(\"Gradient-based vs gradient-free optimization\")\n", + "ax.legend()\n", + "ax.grid(True, alpha=0.3)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Visualize the optimized design\n", + "\n", + "Show the converged temperature field with sensor locations and targets." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Run the optimized design through the pipeline\n", + "opt = result_grad.x\n", + "thermal_opt = thermal_api.apply_jit(\n", + " {\n", + " \"source_x\": jnp.float32(opt[0]),\n", + " \"source_y\": jnp.float32(opt[1]),\n", + " \"source_intensity\": jnp.float32(np.exp(opt[2])),\n", + " \"source_width\": jnp.float32(0.15),\n", + " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", + " \"conductivity\": 1.0,\n", + " \"boundary_temp\": 0.0,\n", + " }\n", + ")\n", + "temp_opt = np.asarray(thermal_opt[\"temperature\"])\n", + "\n", + "fig, ax = plt.subplots(figsize=(7, 6))\n", + "im = ax.imshow(temp_opt.T, origin=\"lower\", extent=[0, 1, 0, 1], cmap=\"hot\")\n", + "plt.colorbar(im, ax=ax, label=\"Temperature\")\n", + "\n", + "# Plot sensor locations and achieved vs target temperatures\n", + "for (si, sj), target in zip(SENSORS, TARGETS, strict=False):\n", + " px, py = si / 31, sj / 31\n", + " achieved = float(temp_opt[si, sj])\n", + " ax.plot(px, py, \"wo\", markersize=10, markeredgecolor=\"blue\", markeredgewidth=2)\n", + " ax.annotate(\n", + " f\"T={achieved:.3f}\\n(target={float(target):.3f})\",\n", + " xy=(px, py),\n", + " xytext=(5, 5),\n", + " textcoords=\"offset points\",\n", + " fontsize=8,\n", + " color=\"white\",\n", + " fontweight=\"bold\",\n", + " bbox=dict(boxstyle=\"round,pad=0.2\", facecolor=\"black\", alpha=0.7),\n", + " )\n", + "\n", + "# Plot optimized source location\n", + "ax.plot(\n", + " float(opt[0]),\n", + " float(opt[1]),\n", + " \"r*\",\n", + " markersize=20,\n", + " markeredgecolor=\"white\",\n", + " markeredgewidth=1,\n", + ")\n", + "ax.annotate(\n", + " f\"Source\\n({float(opt[0]):.2f}, {float(opt[1]):.2f})\\nq={float(np.exp(opt[2])):.1f}\",\n", + " xy=(float(opt[0]), float(opt[1])),\n", + " xytext=(10, -20),\n", + " textcoords=\"offset points\",\n", + " fontsize=9,\n", + " color=\"red\",\n", + " fontweight=\"bold\",\n", + " bbox=dict(boxstyle=\"round,pad=0.2\", facecolor=\"white\", alpha=0.8),\n", + ")\n", + "\n", + "ax.set_title(\"Optimized temperature field with sensor locations\")\n", + "ax.set_xlabel(\"x\")\n", + "ax.set_ylabel(\"y\")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. Modularity: swap a solver, change nothing else\n", + "\n", + "We replace the thermal solver with a coarser version (fewer Jacobi iterations \u2014 faster but less accurate). The optimization code is identical. Only the solver changes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Swap in a \"fast\" thermal solver (100 vs 500 Jacobi iterations)\n", + "# In practice: point to a different Tesseract image\n", + "original_solve = thermal_api._solve_heat_jacobi\n", + "\n", + "\n", + "def fast_solve(source, conductivity, boundary_temp, n_iters=100):\n", + " return original_solve(source, conductivity, boundary_temp, n_iters=n_iters)\n", + "\n", + "\n", + "thermal_api._solve_heat_jacobi = fast_solve\n", + "\n", + "# Same optimization code, same objective, same grad_fn\n", + "eval_history_swapped = []\n", + "\n", + "\n", + "def objective_and_grad_swapped(x):\n", + " p = jnp.array(x, dtype=jnp.float32)\n", + " obj = coupled_objective(p)\n", + " g = grad_fn(p)\n", + " eval_history_swapped.append(float(obj))\n", + " return float(obj), np.array([float(g[i]) for i in range(3)])\n", + "\n", + "\n", + "print(\"Running L-BFGS-B with swapped (fast) thermal solver...\")\n", + "result_swapped = minimize(\n", + " objective_and_grad_swapped,\n", + " x0,\n", + " method=\"L-BFGS-B\",\n", + " jac=True,\n", + " bounds=bounds,\n", + " options={\"maxiter\": 100},\n", + ")\n", + "print(f\" Source: ({result_swapped.x[0]:.3f}, {result_swapped.x[1]:.3f})\")\n", + "print(f\" Intensity: {np.exp(result_swapped.x[2]):.2f}\")\n", + "print(f\" Objective: {result_swapped.fun:.6e}\")\n", + "print(f\" Evaluations: {len(eval_history_swapped)}\")\n", + "print(\n", + " f\"\\n (Original solver found: ({result_grad.x[0]:.3f}, {result_grad.x[1]:.3f}), q={np.exp(result_grad.x[2]):.2f})\"\n", + ")\n", + "\n", + "thermal_api._solve_heat_jacobi = original_solve # restore" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8. Implicit differentiation: O(1) memory gradients via the implicit function theorem\n", + "\n", + "The unrolled `lax.scan` approach above stores all intermediate states for backpropagation \u2014 memory scales as O(N) in coupling iterations. For large-scale problems (fine meshes, many iterations), this becomes the bottleneck.\n", + "\n", + "**Implicit differentiation** avoids this entirely. The key insight: at the converged fixed point $(T^*, D^*) = G(T^*, D^*, \\theta)$, the implicit function theorem gives the sensitivity without replaying the iteration. The backward pass solves a single linear system instead of backpropagating through N steps.\n", + "\n", + "Concretely, if $v = \\partial L / \\partial (T^*, D^*)$ is the loss gradient w.r.t. the fixed point, then:\n", + "\n", + "$$\\lambda = (I - \\partial G / \\partial (T, D))^{-T} v$$\n", + "$$\\partial L / \\partial \\theta = \\lambda^T \\cdot \\partial G / \\partial \\theta$$\n", + "\n", + "We solve for $\\lambda$ via fixed-point iteration on the adjoint equation \u2014 the same structure as the forward solve, but linear." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def coupled_objective_implicit(params):\n", + " \"\"\"Same inverse problem, but differentiated via the implicit function theorem.\n", + "\n", + " Forward pass: iterate G to convergence (no scan intermediates stored for AD).\n", + " Backward pass: solve adjoint equation (I - dG/d(T,D))^T \u03bb = v via fixed-point iteration.\n", + " \"\"\"\n", + " source_x, source_y, log_intensity = params[0], params[1], params[2]\n", + " intensity = jnp.exp(log_intensity)\n", + "\n", + " def G(temp_disp, params_inner):\n", + " \"\"\"One coupling step: (temp, disp) -> (new_temp, new_disp).\n", + "\n", + " params_inner is (source_x, source_y, intensity) \u2014 the differentiable parameters.\n", + " \"\"\"\n", + " _temp, disp = temp_disp\n", + " sx, sy, q = params_inner\n", + " thermal_out = thermal_api.apply_jit(\n", + " {\n", + " \"source_x\": sx,\n", + " \"source_y\": sy,\n", + " \"source_intensity\": q,\n", + " \"source_width\": jnp.float32(0.15),\n", + " \"displacement\": disp,\n", + " \"conductivity\": 1.0,\n", + " \"boundary_temp\": 0.0,\n", + " }\n", + " )\n", + " structural_out = structural_api.apply_jit(\n", + " {\n", + " \"temperature\": thermal_out[\"temperature\"],\n", + " \"youngs_modulus\": 200.0,\n", + " \"poissons_ratio\": 0.3,\n", + " \"thermal_expansion\": 1e-3,\n", + " }\n", + " )\n", + " return (thermal_out[\"temperature\"], structural_out[\"displacement\"])\n", + "\n", + " @jax.custom_vjp\n", + " def solve_fixed_point(params_inner):\n", + " \"\"\"Run fixed-point iteration to convergence, return the fixed point.\"\"\"\n", + " temp = jnp.zeros((30, 30), dtype=jnp.float32)\n", + " disp = jnp.zeros((30, 30, 2), dtype=jnp.float32)\n", + "\n", + " def step(carry, _):\n", + " return G(carry, params_inner), None\n", + "\n", + " (final_temp, final_disp), _ = jax.lax.scan(\n", + " step, (temp, disp), None, length=N_COUPLING_ITERS\n", + " )\n", + " return (final_temp, final_disp)\n", + "\n", + " def solve_fwd(params_inner):\n", + " fixed_point = solve_fixed_point(params_inner)\n", + " # Save fixed point and params for backward pass (NOT intermediates)\n", + " return fixed_point, (fixed_point, params_inner)\n", + "\n", + " def solve_bwd(res, g):\n", + " \"\"\"Implicit differentiation backward pass.\n", + "\n", + " g = (v_temp, v_disp) \u2014 cotangents w.r.t. the fixed point.\n", + "\n", + " We need to solve: (I - dG/d(T,D))^T \u03bb = v for \u03bb,\n", + " then compute: dL/d\u03b8 = \u03bb^T \u00b7 dG/d\u03b8.\n", + "\n", + " We solve for \u03bb by iterating: \u03bb_{k+1} = v + (dG/d(T,D))^T \u03bb_k.\n", + " This converges if the forward iteration is contractive.\n", + " \"\"\"\n", + " (fixed_temp, fixed_disp), params_inner = res\n", + " v_temp, v_disp = g\n", + "\n", + " # Define G_state: maps (temp, disp) -> (new_temp, new_disp) at fixed params\n", + " def G_state(temp_disp):\n", + " return G(temp_disp, params_inner)\n", + "\n", + " # Solve adjoint: \u03bb = v + (dG/d(T,D))^T \u03bb via fixed-point iteration\n", + " def adjoint_step(lam, _):\n", + " lam_temp, lam_disp = lam\n", + " # Compute (dG/d(T,D))^T @ \u03bb via VJP\n", + " _, vjp_G_state = jax.vjp(G_state, (fixed_temp, fixed_disp))\n", + " dGT_lam = vjp_G_state((lam_temp, lam_disp))[0]\n", + " # \u03bb_{k+1} = v + (dG/d(T,D))^T \u03bb_k\n", + " new_lam_temp = v_temp + dGT_lam[0]\n", + " new_lam_disp = v_disp + dGT_lam[1]\n", + " return (new_lam_temp, new_lam_disp), None\n", + "\n", + " N_ADJOINT_ITERS = 20 # typically converges faster than forward\n", + " lam_init = (v_temp, v_disp)\n", + " (lam_temp, lam_disp), _ = jax.lax.scan(\n", + " adjoint_step, lam_init, None, length=N_ADJOINT_ITERS\n", + " )\n", + "\n", + " # Now compute dL/d\u03b8 = \u03bb^T \u00b7 dG/d\u03b8 via VJP of G w.r.t. params\n", + " def G_params(p):\n", + " return G((fixed_temp, fixed_disp), p)\n", + "\n", + " _, vjp_G_params = jax.vjp(G_params, params_inner)\n", + " grad_params = vjp_G_params((lam_temp, lam_disp))[0]\n", + " return (grad_params,)\n", + "\n", + " solve_fixed_point.defvjp(solve_fwd, solve_bwd)\n", + "\n", + " # --- Use the implicit fixed-point solve ---\n", + " final_temp, _final_disp = solve_fixed_point((source_x, source_y, intensity))\n", + "\n", + " loss = jnp.float32(0.0)\n", + " for (si, sj), target in zip(SENSORS, TARGETS, strict=False):\n", + " loss = loss + (final_temp[si, sj] - target) ** 2\n", + " return loss\n", + "\n", + "\n", + "# Verify forward pass matches the unrolled version\n", + "loss_implicit = coupled_objective_implicit(p0)\n", + "loss_unrolled = coupled_objective(p0)\n", + "print(\"Forward pass comparison:\")\n", + "print(f\" Unrolled: {float(loss_unrolled):.10e}\")\n", + "print(f\" Implicit: {float(loss_implicit):.10e}\")\n", + "print(f\" Match: {jnp.allclose(loss_unrolled, loss_implicit)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Compare gradients: implicit vs unrolled vs finite differences\n", + "grad_implicit = jax.grad(coupled_objective_implicit)(p0)\n", + "grad_unrolled = jax.grad(coupled_objective)(p0)\n", + "\n", + "# Finite differences as ground truth\n", + "eps = 1e-4\n", + "fd_grads_check = []\n", + "for i in range(3):\n", + " p_plus = p0.at[i].add(eps)\n", + " p_minus = p0.at[i].add(-eps)\n", + " fd_grads_check.append(\n", + " (coupled_objective_implicit(p_plus) - coupled_objective_implicit(p_minus))\n", + " / (2 * eps)\n", + " )\n", + "\n", + "names = [\"d(loss)/d(source_x)\", \"d(loss)/d(source_y)\", \"d(loss)/d(log_intensity)\"]\n", + "print(f\"{'':32s} {'Unrolled':>14s} {'Implicit':>14s} {'FD':>14s} {'Impl vs FD':>12s}\")\n", + "for name, u, im, fd in zip(\n", + " names, grad_unrolled, grad_implicit, fd_grads_check, strict=False\n", + "):\n", + " rel_err = abs(float(im) - float(fd)) / (abs(float(fd)) + 1e-30)\n", + " print(\n", + " f\"{name:32s} {float(u):14.6e} {float(im):14.6e} {float(fd):14.6e} {rel_err:12.2e}\"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#", + "#", + "#", + " ", + "M", + "e", + "m", + "o", + "r", + "y", + " ", + "s", + "c", + "a", + "l", + "i", + "n", + "g", + ":", + " ", + "w", + "h", + "y", + " ", + "t", + "h", + "i", + "s", + " ", + "m", + "a", + "t", + "t", + "e", + "r", + "s", + "\n", + "\n", + "W", + "i", + "t", + "h", + " ", + "t", + "h", + "e", + " ", + "u", + "n", + "r", + "o", + "l", + "l", + "e", + "d", + " ", + "a", + "p", + "p", + "r", + "o", + "a", + "c", + "h", + ",", + " ", + "J", + "A", + "X", + " ", + "s", + "t", + "o", + "r", + "e", + "s", + " ", + "t", + "h", + "e", + " ", + "f", + "u", + "l", + "l", + " ", + "s", + "t", + "a", + "t", + "e", + " ", + "a", + "t", + " ", + "e", + "v", + "e", + "r", + "y", + " ", + "c", + "o", + "u", + "p", + "l", + "i", + "n", + "g", + " ", + "i", + "t", + "e", + "r", + "a", + "t", + "i", + "o", + "n", + " ", + "f", + "o", + "r", + " ", + "b", + "a", + "c", + "k", + "p", + "r", + "o", + "p", + "a", + "g", + "a", + "t", + "i", + "o", + "n", + ".", + " ", + "M", + "e", + "m", + "o", + "r", + "y", + " ", + "c", + "o", + "s", + "t", + ":", + " ", + "*", + "*", + "O", + "(", + "N", + " ", + "\u00d7", + " ", + "s", + "t", + "a", + "t", + "e", + "_", + "s", + "i", + "z", + "e", + ")", + "*", + "*", + ".", + "\n", + "\n", + "W", + "i", + "t", + "h", + " ", + "i", + "m", + "p", + "l", + "i", + "c", + "i", + "t", + " ", + "d", + "i", + "f", + "f", + "e", + "r", + "e", + "n", + "t", + "i", + "a", + "t", + "i", + "o", + "n", + ",", + " ", + "t", + "h", + "e", + " ", + "f", + "o", + "r", + "w", + "a", + "r", + "d", + " ", + "p", + "a", + "s", + "s", + " ", + "r", + "u", + "n", + "s", + " ", + "t", + "o", + " ", + "c", + "o", + "n", + "v", + "e", + "r", + "g", + "e", + "n", + "c", + "e", + " ", + "a", + "n", + "d", + " ", + "d", + "i", + "s", + "c", + "a", + "r", + "d", + "s", + " ", + "i", + "n", + "t", + "e", + "r", + "m", + "e", + "d", + "i", + "a", + "t", + "e", + "s", + ".", + " ", + "T", + "h", + "e", + " ", + "b", + "a", + "c", + "k", + "w", + "a", + "r", + "d", + " ", + "p", + "a", + "s", + "s", + " ", + "s", + "o", + "l", + "v", + "e", + "s", + " ", + "t", + "h", + "e", + " ", + "a", + "d", + "j", + "o", + "i", + "n", + "t", + " ", + "e", + "q", + "u", + "a", + "t", + "i", + "o", + "n", + " ", + "a", + "t", + " ", + "t", + "h", + "e", + " ", + "f", + "i", + "x", + "e", + "d", + " ", + "p", + "o", + "i", + "n", + "t", + " ", + "o", + "n", + "l", + "y", + " ", + "\u2014", + " ", + "n", + "o", + " ", + "r", + "e", + "p", + "l", + "a", + "y", + " ", + "o", + "f", + " ", + "t", + "h", + "e", + " ", + "i", + "t", + "e", + "r", + "a", + "t", + "i", + "o", + "n", + ".", + " ", + "M", + "e", + "m", + "o", + "r", + "y", + " ", + "c", + "o", + "s", + "t", + ":", + " ", + "*", + "*", + "O", + "(", + "s", + "t", + "a", + "t", + "e", + "_", + "s", + "i", + "z", + "e", + ")", + "*", + "*", + " ", + "r", + "e", + "g", + "a", + "r", + "d", + "l", + "e", + "s", + "s", + " ", + "o", + "f", + " ", + "N", + ".", + "\n", + "\n", + "F", + "o", + "r", + " ", + "t", + "h", + "i", + "s", + " ", + "3", + "0", + "\u00d7", + "3", + "0", + " ", + "d", + "e", + "m", + "o", + " ", + "t", + "h", + "e", + " ", + "d", + "i", + "f", + "f", + "e", + "r", + "e", + "n", + "c", + "e", + " ", + "i", + "s", + " ", + "n", + "e", + "g", + "l", + "i", + "g", + "i", + "b", + "l", + "e", + ".", + " ", + "F", + "o", + "r", + " ", + "p", + "r", + "o", + "d", + "u", + "c", + "t", + "i", + "o", + "n", + "-", + "s", + "c", + "a", + "l", + "e", + " ", + "p", + "r", + "o", + "b", + "l", + "e", + "m", + "s", + " ", + "(", + "m", + "i", + "l", + "l", + "i", + "o", + "n", + "-", + "n", + "o", + "d", + "e", + " ", + "m", + "e", + "s", + "h", + "e", + "s", + ",", + " ", + "h", + "u", + "n", + "d", + "r", + "e", + "d", + "s", + " ", + "o", + "f", + " ", + "c", + "o", + "u", + "p", + "l", + "i", + "n", + "g", + " ", + "i", + "t", + "e", + "r", + "a", + "t", + "i", + "o", + "n", + "s", + ")", + ",", + " ", + "i", + "t", + "'", + "s", + " ", + "t", + "h", + "e", + " ", + "d", + "i", + "f", + "f", + "e", + "r", + "e", + "n", + "c", + "e", + " ", + "b", + "e", + "t", + "w", + "e", + "e", + "n", + " ", + "\"", + "f", + "i", + "t", + "s", + " ", + "i", + "n", + " ", + "G", + "P", + "U", + " ", + "m", + "e", + "m", + "o", + "r", + "y", + "\"", + " ", + "a", + "n", + "d", + " ", + "\"", + "d", + "o", + "e", + "s", + "n", + "'", + "t", + "\"", + "." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#", + "#", + " ", + "S", + "u", + "m", + "m", + "a", + "r", + "y", + "\n", + "\n", + "|", + " ", + "W", + "h", + "a", + "t", + " ", + "|", + " ", + "H", + "o", + "w", + " ", + "|", + "\n", + "|", + "-", + "-", + "-", + "|", + "-", + "-", + "-", + "|", + "\n", + "|", + " ", + "E", + "a", + "c", + "h", + " ", + "s", + "o", + "l", + "v", + "e", + "r", + " ", + "i", + "s", + " ", + "i", + "n", + "d", + "e", + "p", + "e", + "n", + "d", + "e", + "n", + "t", + " ", + "|", + " ", + "S", + "e", + "p", + "a", + "r", + "a", + "t", + "e", + " ", + "`", + "t", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + "_", + "a", + "p", + "i", + ".", + "p", + "y", + "`", + ",", + " ", + "s", + "e", + "p", + "a", + "r", + "a", + "t", + "e", + " ", + "c", + "o", + "n", + "t", + "a", + "i", + "n", + "e", + "r", + ",", + " ", + "s", + "e", + "p", + "a", + "r", + "a", + "t", + "e", + " ", + "t", + "e", + "a", + "m", + " ", + "|", + "\n", + "|", + " ", + "T", + "w", + "o", + "-", + "w", + "a", + "y", + " ", + "c", + "o", + "u", + "p", + "l", + "i", + "n", + "g", + " ", + "|", + " ", + "`", + "j", + "a", + "x", + ".", + "l", + "a", + "x", + ".", + "s", + "c", + "a", + "n", + "`", + " ", + "o", + "v", + "e", + "r", + " ", + "a", + "l", + "t", + "e", + "r", + "n", + "a", + "t", + "i", + "n", + "g", + " ", + "s", + "o", + "l", + "v", + "e", + "r", + " ", + "c", + "a", + "l", + "l", + "s", + " ", + "|", + "\n", + "|", + " ", + "E", + "n", + "d", + "-", + "t", + "o", + "-", + "e", + "n", + "d", + " ", + "g", + "r", + "a", + "d", + "i", + "e", + "n", + "t", + "s", + " ", + "|", + " ", + "`", + "j", + "a", + "x", + ".", + "g", + "r", + "a", + "d", + "`", + " ", + "\u2014", + " ", + "J", + "A", + "X", + " ", + "h", + "a", + "n", + "d", + "l", + "e", + "s", + " ", + "t", + "h", + "e", + " ", + "c", + "h", + "a", + "i", + "n", + " ", + "r", + "u", + "l", + "e", + " ", + "t", + "h", + "r", + "o", + "u", + "g", + "h", + " ", + "t", + "h", + "e", + " ", + "c", + "o", + "u", + "p", + "l", + "e", + "d", + " ", + "i", + "t", + "e", + "r", + "a", + "t", + "i", + "o", + "n", + " ", + "|", + "\n", + "|", + " ", + "G", + "r", + "a", + "d", + "i", + "e", + "n", + "t", + " ", + "c", + "o", + "r", + "r", + "e", + "c", + "t", + "n", + "e", + "s", + "s", + " ", + "|", + " ", + "V", + "a", + "l", + "i", + "d", + "a", + "t", + "e", + "d", + " ", + "a", + "g", + "a", + "i", + "n", + "s", + "t", + " ", + "f", + "i", + "n", + "i", + "t", + "e", + " ", + "d", + "i", + "f", + "f", + "e", + "r", + "e", + "n", + "c", + "e", + "s", + " ", + "|", + "\n", + "|", + " ", + "I", + "m", + "p", + "l", + "i", + "c", + "i", + "t", + " ", + "d", + "i", + "f", + "f", + "e", + "r", + "e", + "n", + "t", + "i", + "a", + "t", + "i", + "o", + "n", + " ", + "|", + " ", + "`", + "j", + "a", + "x", + ".", + "c", + "u", + "s", + "t", + "o", + "m", + "_", + "v", + "j", + "p", + "`", + " ", + "+", + " ", + "a", + "d", + "j", + "o", + "i", + "n", + "t", + " ", + "s", + "o", + "l", + "v", + "e", + " ", + "f", + "o", + "r", + " ", + "O", + "(", + "1", + ")", + " ", + "m", + "e", + "m", + "o", + "r", + "y", + " ", + "|", + "\n", + "|", + " ", + "S", + "o", + "l", + "v", + "e", + "r", + " ", + "s", + "w", + "a", + "p", + "p", + "i", + "n", + "g", + " ", + "|", + " ", + "C", + "h", + "a", + "n", + "g", + "e", + " ", + "t", + "h", + "e", + " ", + "T", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + " ", + "r", + "e", + "f", + "e", + "r", + "e", + "n", + "c", + "e", + ",", + " ", + "o", + "p", + "t", + "i", + "m", + "i", + "z", + "a", + "t", + "i", + "o", + "n", + " ", + "c", + "o", + "d", + "e", + " ", + "u", + "n", + "c", + "h", + "a", + "n", + "g", + "e", + "d", + " ", + "|", + "\n", + "\n", + "#", + "#", + "#", + " ", + "W", + "h", + "a", + "t", + "'", + "s", + " ", + "n", + "e", + "x", + "t", + "\n", + "\n", + "-", + " ", + "*", + "*", + "P", + "r", + "o", + "d", + "u", + "c", + "t", + "i", + "o", + "n", + " ", + "d", + "e", + "p", + "l", + "o", + "y", + "m", + "e", + "n", + "t", + "*", + "*", + ":", + " ", + "B", + "u", + "i", + "l", + "d", + " ", + "a", + "n", + "d", + " ", + "s", + "e", + "r", + "v", + "e", + " ", + "T", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + "s", + " ", + "a", + "s", + " ", + "D", + "o", + "c", + "k", + "e", + "r", + " ", + "c", + "o", + "n", + "t", + "a", + "i", + "n", + "e", + "r", + "s", + ",", + " ", + "c", + "o", + "m", + "p", + "o", + "s", + "e", + " ", + "v", + "i", + "a", + " ", + "`", + "t", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + "-", + "j", + "a", + "x", + "`", + "'", + "s", + " ", + "`", + "a", + "p", + "p", + "l", + "y", + "_", + "t", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + "`", + "\n", + "-", + " ", + "*", + "*", + "S", + "c", + "a", + "l", + "e", + " ", + "u", + "p", + "*", + "*", + ":", + " ", + "L", + "a", + "r", + "g", + "e", + "r", + " ", + "m", + "e", + "s", + "h", + "e", + "s", + ",", + " ", + "m", + "o", + "r", + "e", + " ", + "c", + "o", + "u", + "p", + "l", + "i", + "n", + "g", + " ", + "i", + "t", + "e", + "r", + "a", + "t", + "i", + "o", + "n", + "s", + ",", + " ", + "G", + "P", + "U", + " ", + "a", + "c", + "c", + "e", + "l", + "e", + "r", + "a", + "t", + "i", + "o", + "n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#", + "#", + " ", + "9", + ".", + " ", + "P", + "r", + "o", + "d", + "u", + "c", + "t", + "i", + "o", + "n", + " ", + "p", + "a", + "t", + "h", + ":", + " ", + "c", + "o", + "m", + "p", + "o", + "s", + "i", + "n", + "g", + " ", + "T", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + "s", + " ", + "w", + "i", + "t", + "h", + " ", + "`", + "t", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + "-", + "j", + "a", + "x", + "`", + "\n", + "\n", + "T", + "h", + "e", + " ", + "c", + "e", + "l", + "l", + "s", + " ", + "a", + "b", + "o", + "v", + "e", + " ", + "c", + "a", + "l", + "l", + " ", + "`", + "a", + "p", + "p", + "l", + "y", + "_", + "j", + "i", + "t", + "`", + " ", + "d", + "i", + "r", + "e", + "c", + "t", + "l", + "y", + " ", + "\u2014", + " ", + "b", + "y", + "p", + "a", + "s", + "s", + "i", + "n", + "g", + " ", + "t", + "h", + "e", + " ", + "T", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + " ", + "r", + "u", + "n", + "t", + "i", + "m", + "e", + " ", + "f", + "o", + "r", + " ", + "s", + "p", + "e", + "e", + "d", + ".", + " ", + "I", + "n", + " ", + "p", + "r", + "o", + "d", + "u", + "c", + "t", + "i", + "o", + "n", + ",", + " ", + "e", + "a", + "c", + "h", + " ", + "s", + "o", + "l", + "v", + "e", + "r", + " ", + "i", + "s", + " ", + "a", + " ", + "c", + "o", + "n", + "t", + "a", + "i", + "n", + "e", + "r", + "i", + "z", + "e", + "d", + " ", + "T", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + " ", + "a", + "n", + "d", + " ", + "y", + "o", + "u", + " ", + "c", + "o", + "m", + "p", + "o", + "s", + "e", + " ", + "t", + "h", + "e", + "m", + " ", + "w", + "i", + "t", + "h", + " ", + "`", + "t", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + "-", + "j", + "a", + "x", + "`", + "'", + "s", + " ", + "`", + "a", + "p", + "p", + "l", + "y", + "_", + "t", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + "`", + ",", + " ", + "a", + " ", + "J", + "A", + "X", + " ", + "p", + "r", + "i", + "m", + "i", + "t", + "i", + "v", + "e", + " ", + "t", + "h", + "a", + "t", + " ", + "r", + "o", + "u", + "t", + "e", + "s", + " ", + "t", + "o", + " ", + "t", + "h", + "e", + " ", + "T", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + "'", + "s", + " ", + "e", + "n", + "d", + "p", + "o", + "i", + "n", + "t", + "s", + ".", + " ", + "`", + "j", + "a", + "x", + ".", + "g", + "r", + "a", + "d", + "`", + " ", + "a", + "n", + "d", + " ", + "`", + "j", + "a", + "x", + ".", + "j", + "i", + "t", + "`", + " ", + "w", + "o", + "r", + "k", + " ", + "t", + "h", + "r", + "o", + "u", + "g", + "h", + " ", + "i", + "t", + " ", + "a", + "u", + "t", + "o", + "m", + "a", + "t", + "i", + "c", + "a", + "l", + "l", + "y", + ".", + "\n", + "\n", + "*", + "*", + "I", + "m", + "p", + "o", + "r", + "t", + "a", + "n", + "t", + " ", + "p", + "a", + "t", + "t", + "e", + "r", + "n", + "*", + "*", + ":", + " ", + "w", + "h", + "e", + "n", + " ", + "u", + "s", + "i", + "n", + "g", + " ", + "`", + "a", + "p", + "p", + "l", + "y", + "_", + "t", + "e", + "s", + "s", + "e", + "r", + "a", + "c", + "t", + "`", + " ", + "i", + "n", + "s", + "i", + "d", + "e", + " ", + "`", + "l", + "a", + "x", + ".", + "s", + "c", + "a", + "n", + "`", + ",", + " ", + "n", + "o", + "n", + "-", + "d", + "i", + "f", + "f", + "e", + "r", + "e", + "n", + "t", + "i", + "a", + "b", + "l", + "e", + " ", + "c", + "o", + "n", + "s", + "t", + "a", + "n", + "t", + "s", + " ", + "m", + "u", + "s", + "t", + " ", + "b", + "e", + " ", + "p", + "a", + "s", + "s", + "e", + "d", + " ", + "a", + "s", + " ", + "*", + "*", + "n", + "u", + "m", + "p", + "y", + " ", + "a", + "r", + "r", + "a", + "y", + "s", + "*", + "*", + " ", + "(", + "`", + "n", + "p", + ".", + "f", + "l", + "o", + "a", + "t", + "3", + "2", + "`", + ")", + ",", + " ", + "n", + "o", + "t", + " ", + "J", + "A", + "X", + " ", + "a", + "r", + "r", + "a", + "y", + "s", + " ", + "(", + "`", + "j", + "n", + "p", + ".", + "f", + "l", + "o", + "a", + "t", + "3", + "2", + "`", + ")", + ".", + " ", + "I", + "n", + "s", + "i", + "d", + "e", + " ", + "a", + " ", + "s", + "c", + "a", + "n", + ",", + " ", + "J", + "A", + "X", + " ", + "t", + "r", + "a", + "c", + "e", + "s", + " ", + "a", + "l", + "l", + " ", + "a", + "r", + "r", + "a", + "y", + " ", + "i", + "n", + "p", + "u", + "t", + "s", + " ", + "u", + "n", + "i", + "f", + "o", + "r", + "m", + "l", + "y", + " ", + "\u2014", + " ", + "i", + "t", + " ", + "c", + "a", + "n", + "'", + "t", + " ", + "t", + "e", + "l", + "l", + " ", + "w", + "h", + "i", + "c", + "h", + " ", + "o", + "n", + "e", + "s", + " ", + "a", + "r", + "e", + " ", + "c", + "o", + "n", + "s", + "t", + "a", + "n", + "t", + "s", + ".", + " ", + "I", + "f", + " ", + "a", + " ", + "n", + "o", + "n", + "-", + "d", + "i", + "f", + "f", + "e", + "r", + "e", + "n", + "t", + "i", + "a", + "b", + "l", + "e", + " ", + "f", + "i", + "e", + "l", + "d", + " ", + "g", + "e", + "t", + "s", + " ", + "t", + "r", + "a", + "c", + "e", + "d", + ",", + " ", + "t", + "h", + "e", + " ", + "b", + "a", + "c", + "k", + "w", + "a", + "r", + "d", + " ", + "p", + "a", + "s", + "s", + " ", + "w", + "i", + "l", + "l", + " ", + "t", + "r", + "y", + " ", + "t", + "o", + " ", + "d", + "i", + "f", + "f", + "e", + "r", + "e", + "n", + "t", + "i", + "a", + "t", + "e", + " ", + "t", + "h", + "r", + "o", + "u", + "g", + "h", + " ", + "i", + "t", + " ", + "a", + "n", + "d", + " ", + "t", + "h", + "e", + " ", + "V", + "J", + "P", + " ", + "e", + "n", + "d", + "p", + "o", + "i", + "n", + "t", + " ", + "w", + "i", + "l", + "l", + " ", + "r", + "e", + "j", + "e", + "c", + "t", + " ", + "t", + "h", + "e", + " ", + "f", + "i", + "e", + "l", + "d", + " ", + "n", + "a", + "m", + "e", + ".", + " ", + "U", + "s", + "i", + "n", + "g", + " ", + "`", + "n", + "p", + "`", + " ", + "a", + "r", + "r", + "a", + "y", + "s", + " ", + "k", + "e", + "e", + "p", + "s", + " ", + "t", + "h", + "e", + "m", + " ", + "o", + "p", + "a", + "q", + "u", + "e", + " ", + "t", + "o", + " ", + "t", + "h", + "e", + " ", + "t", + "r", + "a", + "c", + "e", + "r", + "." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from tesseract_jax import apply_tesseract\n", + "\n", + "from tesseract_core.sdk.tesseract import Tesseract\n", + "\n", + "# Load Tesseracts (in-process, no Docker)\n", + "thermal_tess = Tesseract.from_tesseract_api(\"thermal_solver/tesseract_api.py\")\n", + "structural_tess = Tesseract.from_tesseract_api(\"structural_solver/tesseract_api.py\")\n", + "\n", + "# Forward pass through both Tesseracts via apply_tesseract\n", + "thermal_out_tj = apply_tesseract(\n", + " thermal_tess,\n", + " {\n", + " \"source_x\": jnp.float32(0.5),\n", + " \"source_y\": jnp.float32(0.5),\n", + " \"source_intensity\": jnp.float32(10.0),\n", + " \"source_width\": np.float32(0.1), # np: non-differentiable constant\n", + " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", + " \"conductivity\": np.float32(1.0), # np: non-differentiable constant\n", + " \"boundary_temp\": np.float32(0.0), # np: non-differentiable constant\n", + " },\n", + ")\n", + "\n", + "structural_out_tj = apply_tesseract(\n", + " structural_tess,\n", + " {\n", + " \"temperature\": thermal_out_tj[\"temperature\"],\n", + " \"youngs_modulus\": np.float32(200.0), # np: non-differentiable constant\n", + " \"poissons_ratio\": np.float32(0.3), # np: non-differentiable constant\n", + " \"thermal_expansion\": np.float32(1e-3), # np: non-differentiable constant\n", + " },\n", + ")\n", + "\n", + "# Verify: matches direct apply_jit\n", + "print(\"Forward pass via apply_tesseract matches direct call:\")\n", + "print(\n", + " f\" Temperature max error: \"\n", + " f\"{float(jnp.max(jnp.abs(thermal_out_tj['temperature'] - thermal_out['temperature']))):.2e}\"\n", + ")\n", + "print(\n", + " f\" Displacement max error: \"\n", + " f\"{float(jnp.max(jnp.abs(structural_out_tj['displacement'] - structural_out['displacement']))):.2e}\"\n", + ")\n", + "\n", + "\n", + "# Gradient through a single Tesseract call\n", + "def single_thermal_loss(source_x):\n", + " out = apply_tesseract(\n", + " thermal_tess,\n", + " {\n", + " \"source_x\": source_x,\n", + " \"source_y\": jnp.float32(0.5),\n", + " \"source_intensity\": jnp.float32(10.0),\n", + " \"source_width\": np.float32(0.1),\n", + " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", + " \"conductivity\": np.float32(1.0),\n", + " \"boundary_temp\": np.float32(0.0),\n", + " },\n", + " )\n", + " return jnp.sum(out[\"temperature\"])\n", + "\n", + "\n", + "grad_single = jax.grad(single_thermal_loss)(jnp.float32(0.3))\n", + "print(\n", + " f\"\\nGradient through single apply_tesseract: d(sum_T)/d(source_x) = {float(grad_single):.6e}\"\n", + ")\n", + "\n", + "\n", + "# Full coupled pipeline: apply_tesseract + lax.scan + jax.grad\n", + "# Key: non-differentiable constants use np (not jnp) so JAX doesn't trace them\n", + "def coupled_objective_tesseract(params):\n", + " source_x, source_y, log_intensity = params[0], params[1], params[2]\n", + " intensity = jnp.exp(log_intensity)\n", + "\n", + " temp = jnp.zeros((30, 30), dtype=jnp.float32)\n", + " disp = jnp.zeros((30, 30, 2), dtype=jnp.float32)\n", + "\n", + " def coupling_step(carry, _):\n", + " _temp, disp = carry\n", + " thermal_out = apply_tesseract(\n", + " thermal_tess,\n", + " {\n", + " \"source_x\": source_x,\n", + " \"source_y\": source_y,\n", + " \"source_intensity\": intensity,\n", + " \"source_width\": np.float32(0.15),\n", + " \"displacement\": disp,\n", + " \"conductivity\": np.float32(1.0),\n", + " \"boundary_temp\": np.float32(0.0),\n", + " },\n", + " )\n", + " structural_out = apply_tesseract(\n", + " structural_tess,\n", + " {\n", + " \"temperature\": thermal_out[\"temperature\"],\n", + " \"youngs_modulus\": np.float32(200.0),\n", + " \"poissons_ratio\": np.float32(0.3),\n", + " \"thermal_expansion\": np.float32(1e-3),\n", + " },\n", + " )\n", + " return (thermal_out[\"temperature\"], structural_out[\"displacement\"]), None\n", + "\n", + " (final_temp, _), _ = jax.lax.scan(\n", + " coupling_step, (temp, disp), None, length=N_COUPLING_ITERS\n", + " )\n", + "\n", + " loss = jnp.float32(0.0)\n", + " for (si, sj), target in zip(SENSORS, TARGETS, strict=False):\n", + " loss = loss + (final_temp[si, sj] - target) ** 2\n", + " return loss\n", + "\n", + "\n", + "# End-to-end gradient through apply_tesseract + lax.scan\n", + "grad_tess = jax.grad(coupled_objective_tesseract)(p0)\n", + "grad_direct = jax.grad(coupled_objective)(p0)\n", + "\n", + "print(\"\\nEnd-to-end gradient through apply_tesseract + lax.scan:\")\n", + "print(f\" {'':32s} {'apply_tesseract':>16s} {'direct':>16s}\")\n", + "for name, gt, gd in zip(names, grad_tess, grad_direct, strict=False):\n", + " print(f\" {name:32s} {float(gt):16.6e} {float(gd):16.6e}\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.12.0" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/demo/multiphysics-optimization/requirements.txt b/demo/multiphysics-optimization/requirements.txt new file mode 100644 index 000000000..b2c1cbe5d --- /dev/null +++ b/demo/multiphysics-optimization/requirements.txt @@ -0,0 +1,5 @@ +jax[cpu]==0.5.2 +equinox +matplotlib +scipy +tesseract-core diff --git a/demo/multiphysics-optimization/structural_solver/tesseract_api.py b/demo/multiphysics-optimization/structural_solver/tesseract_api.py new file mode 100644 index 000000000..8c82ab8a6 --- /dev/null +++ b/demo/multiphysics-optimization/structural_solver/tesseract_api.py @@ -0,0 +1,273 @@ +# Copyright 2025 Pasteur Labs. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Structural solver Tesseract: 2D linear thermoelastic stress on a rectangular plate. + +Given a temperature field, computes thermal strain, solves for displacement +via a finite-difference discretization of the linear elasticity equations, +and returns the stress field, displacement, and a scalar objective +(compliance = u^T K u, a standard structural optimization objective). + +The displacement output feeds back to the thermal solver for two-way coupling. +""" + +from typing import Any + +import equinox as eqx +import jax +import jax.numpy as jnp +from pydantic import BaseModel, Field + +from tesseract_core.runtime import Array, Differentiable, Float32 +from tesseract_core.runtime.tree_transforms import filter_func, flatten_with_paths + +NX = 30 +NY = 30 + + +class InputSchema(BaseModel): + temperature: Differentiable[Array[(NX, NY), Float32]] = Field( + description="Temperature field from thermal solver (NX x NY)" + ) + youngs_modulus: Float32 = Field(description="Young's modulus", default=200.0) + poissons_ratio: Float32 = Field(description="Poisson's ratio", default=0.3) + thermal_expansion: Float32 = Field( + description="Coefficient of thermal expansion", default=1e-3 + ) + + +class OutputSchema(BaseModel): + displacement: Differentiable[Array[(NX, NY, 2), Float32]] = Field( + description="Displacement field (NX x NY x 2)" + ) + stress: Differentiable[Array[(NX, NY, 3), Float32]] = Field( + description="Stress field (NX x NY x 3: sigma_xx, sigma_yy, sigma_xy)" + ) + objective: Differentiable[Array[(), Float32]] = Field( + description="Scalar compliance objective" + ) + + +def _compute_strain_from_displacement(u, dx, dy): + """Compute strain tensor components from displacement field via central differences.""" + ux = u[:, :, 0] + uy = u[:, :, 1] + + # Strain: eps_xx = du_x/dx, eps_yy = du_y/dy, eps_xy = 0.5*(du_x/dy + du_y/dx) + eps_xx = jnp.gradient(ux, dx, axis=0) + eps_yy = jnp.gradient(uy, dy, axis=1) + eps_xy = 0.5 * (jnp.gradient(ux, dy, axis=1) + jnp.gradient(uy, dx, axis=0)) + + return eps_xx, eps_yy, eps_xy + + +def _thermal_strain(temperature, alpha): + """Isotropic thermal strain: eps_thermal = alpha * T.""" + return alpha * temperature + + +def _stress_from_strain(eps_xx, eps_yy, eps_xy, eps_thermal, E, nu): + """Plane stress constitutive relation with thermal strain.""" + # Mechanical strain = total strain - thermal strain + mech_xx = eps_xx - eps_thermal + mech_yy = eps_yy - eps_thermal + mech_xy = eps_xy # thermal strain is isotropic, no shear component + + # Plane stress stiffness + c = E / (1 - nu**2) + sigma_xx = c * (mech_xx + nu * mech_yy) + sigma_yy = c * (nu * mech_xx + mech_yy) + sigma_xy = E / (2 * (1 + nu)) * 2 * mech_xy + + return sigma_xx, sigma_yy, sigma_xy + + +def _solve_elasticity_jacobi(temperature, E, nu, alpha, n_iters=500): + """Solve 2D linear elasticity with thermal loading via damped Jacobi. + + Simplified: treats the thermal load as a body force and iterates + the equilibrium equations on a staggered grid. + """ + nx, ny = temperature.shape + dx = 1.0 / (nx + 1) + dy = 1.0 / (ny + 1) + + # Lame parameters for plane stress + mu = E / (2 * (1 + nu)) + lam = E * nu / ((1 + nu) * (1 - nu)) # plane stress effective lambda + + # Thermal body force: f_i = -(lambda + 2*mu) * alpha * dT/dx_i + thermal_coeff = (lam + 2 * mu) * alpha + fx = thermal_coeff * jnp.gradient(temperature, dx, axis=0) + fy = thermal_coeff * jnp.gradient(temperature, dy, axis=1) + + # Padded displacement (zero Dirichlet BCs) + u = jnp.zeros((nx + 2, ny + 2, 2)) + omega = 0.6 # relaxation factor + + def iteration(u, _): + ux = u[:, :, 0] + uy = u[:, :, 1] + + # Equilibrium: (lambda + 2*mu) * d2u_x/dx2 + mu * d2u_x/dy2 + # + (lambda + mu) * d2u_y/dxdy = -fx + # Simplified Jacobi update for ux on interior + ux_new = ( + (lam + 2 * mu) * (ux[2:, 1:-1] + ux[:-2, 1:-1]) / dx**2 + + mu * (ux[1:-1, 2:] + ux[1:-1, :-2]) / dy**2 + + fx + ) / (2 * (lam + 2 * mu) / dx**2 + 2 * mu / dy**2) + + uy_new = ( + mu * (uy[2:, 1:-1] + uy[:-2, 1:-1]) / dx**2 + + (lam + 2 * mu) * (uy[1:-1, 2:] + uy[1:-1, :-2]) / dy**2 + + fy + ) / (2 * mu / dx**2 + 2 * (lam + 2 * mu) / dy**2) + + u_interior = jnp.stack([ux_new, uy_new], axis=-1) + u_new = u.at[1:-1, 1:-1].set(omega * u_interior + (1 - omega) * u[1:-1, 1:-1]) + return u_new, None + + u_final, _ = jax.lax.scan(iteration, u, None, length=n_iters) + return u_final[1:-1, 1:-1] + + +@eqx.filter_jit +def apply_jit(inputs: dict) -> dict: + temperature = inputs["temperature"] + E = inputs["youngs_modulus"] + nu = inputs["poissons_ratio"] + alpha = inputs["thermal_expansion"] + + dx = 1.0 / (NX + 1) + dy = 1.0 / (NY + 1) + + # Solve for displacement + displacement = _solve_elasticity_jacobi(temperature, E, nu, alpha) + + # Compute strain and stress + eps_xx, eps_yy, eps_xy = _compute_strain_from_displacement(displacement, dx, dy) + eps_thermal = _thermal_strain(temperature, alpha) + sigma_xx, sigma_yy, sigma_xy = _stress_from_strain( + eps_xx, eps_yy, eps_xy, eps_thermal, E, nu + ) + + stress = jnp.stack([sigma_xx, sigma_yy, sigma_xy], axis=-1) + + # Compliance objective: sum of squared displacement weighted by stiffness + # (simplified proxy for u^T K u) + objective = jnp.sum(displacement**2) + + return { + "displacement": displacement.astype(jnp.float32), + "stress": stress.astype(jnp.float32), + "objective": objective.astype(jnp.float32), + } + + +def apply(inputs: InputSchema) -> OutputSchema: + return apply_jit(inputs.model_dump()) + + +def abstract_eval(abstract_inputs: Any) -> Any: + is_shapedtype_dict = lambda x: type(x) is dict and (x.keys() == {"shape", "dtype"}) + is_shapedtype_struct = lambda x: isinstance(x, jax.ShapeDtypeStruct) + + jaxified_inputs = jax.tree.map( + lambda x: jax.ShapeDtypeStruct(**x) if is_shapedtype_dict(x) else x, + abstract_inputs.model_dump(), + is_leaf=is_shapedtype_dict, + ) + dynamic_inputs, static_inputs = eqx.partition( + jaxified_inputs, filter_spec=is_shapedtype_struct + ) + + def wrapped_apply(dynamic_inputs: Any) -> Any: + inputs = eqx.combine(static_inputs, dynamic_inputs) + return apply_jit(inputs) + + jax_shapes = jax.eval_shape(wrapped_apply, dynamic_inputs) + return jax.tree.map( + lambda x: ( + {"shape": x.shape, "dtype": str(x.dtype)} if is_shapedtype_struct(x) else x + ), + jax_shapes, + is_leaf=is_shapedtype_struct, + ) + + +@eqx.filter_jit +def jvp_jit( + inputs: dict, + jvp_inputs: tuple[str], + jvp_outputs: tuple[str], + tangent_vector: dict, +) -> Any: + filtered_apply = filter_func(apply_jit, inputs, jvp_outputs) + return jax.jvp( + filtered_apply, + [flatten_with_paths(inputs, include_paths=jvp_inputs)], + [tangent_vector], + )[1] + + +def jacobian_vector_product( + inputs: InputSchema, + jvp_inputs: set[str], + jvp_outputs: set[str], + tangent_vector: dict[str, Any], +) -> Any: + return jvp_jit( + inputs.model_dump(), + tuple(jvp_inputs), + tuple(jvp_outputs), + tangent_vector, + ) + + +@eqx.filter_jit +def vjp_jit( + inputs: dict, + vjp_inputs: tuple[str], + vjp_outputs: tuple[str], + cotangent_vector: dict, +) -> Any: + filtered_apply = filter_func(apply_jit, inputs, vjp_outputs) + _, vjp_func = jax.vjp( + filtered_apply, flatten_with_paths(inputs, include_paths=vjp_inputs) + ) + return vjp_func(cotangent_vector)[0] + + +def vector_jacobian_product( + inputs: InputSchema, + vjp_inputs: set[str], + vjp_outputs: set[str], + cotangent_vector: dict[str, Any], +) -> Any: + return vjp_jit( + inputs.model_dump(), + tuple(vjp_inputs), + tuple(vjp_outputs), + cotangent_vector, + ) + + +@eqx.filter_jit +def jac_jit( + inputs: dict, + jac_inputs: tuple[str], + jac_outputs: tuple[str], +) -> Any: + filtered_apply = filter_func(apply_jit, inputs, jac_outputs) + return jax.jacrev(filtered_apply)( + flatten_with_paths(inputs, include_paths=jac_inputs) + ) + + +def jacobian( + inputs: InputSchema, + jac_inputs: set[str], + jac_outputs: set[str], +) -> Any: + return jac_jit(inputs.model_dump(), tuple(jac_inputs), tuple(jac_outputs)) diff --git a/demo/multiphysics-optimization/structural_solver/tesseract_config.yaml b/demo/multiphysics-optimization/structural_solver/tesseract_config.yaml new file mode 100644 index 000000000..0d1236984 --- /dev/null +++ b/demo/multiphysics-optimization/structural_solver/tesseract_config.yaml @@ -0,0 +1,6 @@ +name: "structural-solver" +version: "0.1.0" +description: "2D linear thermoelastic stress solver with compliance objective" + +build_config: + target_platform: "native" diff --git a/demo/multiphysics-optimization/structural_solver/tesseract_requirements.txt b/demo/multiphysics-optimization/structural_solver/tesseract_requirements.txt new file mode 100644 index 000000000..8f33da031 --- /dev/null +++ b/demo/multiphysics-optimization/structural_solver/tesseract_requirements.txt @@ -0,0 +1,2 @@ +jax[cpu]==0.5.2 +equinox diff --git a/demo/multiphysics-optimization/test_solvers.py b/demo/multiphysics-optimization/test_solvers.py new file mode 100644 index 000000000..29e34176c --- /dev/null +++ b/demo/multiphysics-optimization/test_solvers.py @@ -0,0 +1,260 @@ +"""Smoke tests for multiphysics demo solvers.""" + +import sys + +sys.path.insert(0, "thermal_solver") +sys.path.insert(0, "structural_solver") + +import jax +import jax.numpy as jnp + +jax.config.update("jax_enable_x64", True) + +import structural_solver.tesseract_api as structural_api # noqa: E402 +import thermal_solver.tesseract_api as thermal_api # noqa: E402 + + +def test_thermal_forward(): + print("=== Thermal solver forward pass ===") + from thermal_solver.tesseract_api import InputSchema as ThermalInput + + inputs = ThermalInput( + source_x=0.5, + source_y=0.5, + source_intensity=10.0, + displacement=jnp.zeros((30, 30, 2), dtype=jnp.float32), + ) + out = thermal_api.apply(inputs) + temp = out["temperature"] + print( + f" Shape: {temp.shape}, range: [{float(temp.min()):.4f}, {float(temp.max()):.4f}]" + ) + assert temp.shape == (30, 30) + assert float(temp.max()) > 0 + print(" PASSED") + return temp + + +def test_structural_forward(temperature): + print("\n=== Structural solver forward pass ===") + from structural_solver.tesseract_api import InputSchema as StructuralInput + + inputs = StructuralInput(temperature=temperature) + out = structural_api.apply(inputs) + print(f" Displacement: {out['displacement'].shape}, Stress: {out['stress'].shape}") + print(f" Objective: {float(out['objective']):.6e}") + assert out["displacement"].shape == (30, 30, 2) + assert out["stress"].shape == (30, 30, 3) + print(" PASSED") + + +def test_one_way_gradient(): + print("\n=== One-way coupled gradient ===") + + def pipeline(source_x, source_y): + thermal_out = thermal_api.apply_jit( + { + "source_x": source_x, + "source_y": source_y, + "source_intensity": jnp.float32(10.0), + "source_width": 0.1, + "displacement": jnp.zeros((30, 30, 2), dtype=jnp.float32), + "conductivity": 1.0, + "boundary_temp": 0.0, + } + ) + structural_out = structural_api.apply_jit( + { + "temperature": thermal_out["temperature"], + "youngs_modulus": 200.0, + "poissons_ratio": 0.3, + "thermal_expansion": 1e-3, + } + ) + return structural_out["objective"] + + grad_fn = jax.grad(pipeline, argnums=(0, 1)) + sx, sy = jnp.float32(0.3), jnp.float32(0.7) + grads = grad_fn(sx, sy) + + eps = jnp.float32(1e-4) + fd_x = (pipeline(sx + eps, sy) - pipeline(sx - eps, sy)) / (2 * eps) + fd_y = (pipeline(sx, sy + eps) - pipeline(sx, sy - eps)) / (2 * eps) + + rel_err_x = abs(float(grads[0]) - float(fd_x)) / (abs(float(fd_x)) + 1e-30) + rel_err_y = abs(float(grads[1]) - float(fd_y)) / (abs(float(fd_y)) + 1e-30) + print(f" Rel error: x={rel_err_x:.2e}, y={rel_err_y:.2e}") + assert max(rel_err_x, rel_err_y) < 1e-2, "Gradient error too large" + print(" PASSED") + + +def test_two_way_gradient(): + print("\n=== Two-way coupled gradient (lax.scan) ===") + + def coupled_pipeline(source_x, source_y): + temp = jnp.zeros((30, 30), dtype=jnp.float32) + disp = jnp.zeros((30, 30, 2), dtype=jnp.float32) + + def coupling_step(carry, _): + _temp, disp = carry + thermal_out = thermal_api.apply_jit( + { + "source_x": source_x, + "source_y": source_y, + "source_intensity": jnp.float32(10.0), + "source_width": 0.1, + "displacement": disp, + "conductivity": 1.0, + "boundary_temp": 0.0, + } + ) + structural_out = structural_api.apply_jit( + { + "temperature": thermal_out["temperature"], + "youngs_modulus": 200.0, + "poissons_ratio": 0.3, + "thermal_expansion": 1e-3, + } + ) + return ( + thermal_out["temperature"], + structural_out["displacement"], + ), structural_out["objective"] + + _, objectives = jax.lax.scan(coupling_step, (temp, disp), None, length=3) + return objectives[-1] + + grad_fn = jax.grad(coupled_pipeline, argnums=(0, 1)) + sx, sy = jnp.float32(0.3), jnp.float32(0.7) + grads = grad_fn(sx, sy) + + eps = jnp.float32(1e-4) + fd_x = (coupled_pipeline(sx + eps, sy) - coupled_pipeline(sx - eps, sy)) / (2 * eps) + fd_y = (coupled_pipeline(sx, sy + eps) - coupled_pipeline(sx, sy - eps)) / (2 * eps) + + rel_err_x = abs(float(grads[0]) - float(fd_x)) / (abs(float(fd_x)) + 1e-30) + rel_err_y = abs(float(grads[1]) - float(fd_y)) / (abs(float(fd_y)) + 1e-30) + print(f" Rel error: x={rel_err_x:.2e}, y={rel_err_y:.2e}") + assert max(rel_err_x, rel_err_y) < 1e-2, "Gradient error too large" + print(" PASSED") + + +def test_implicit_differentiation(): + print("\n=== Implicit differentiation vs unrolled ===") + + def G(temp_disp, params): + _temp, disp = temp_disp + sx, sy, q = params + thermal_out = thermal_api.apply_jit( + { + "source_x": sx, + "source_y": sy, + "source_intensity": q, + "source_width": jnp.float32(0.15), + "displacement": disp, + "conductivity": 1.0, + "boundary_temp": 0.0, + } + ) + structural_out = structural_api.apply_jit( + { + "temperature": thermal_out["temperature"], + "youngs_modulus": 200.0, + "poissons_ratio": 0.3, + "thermal_expansion": 1e-3, + } + ) + return (thermal_out["temperature"], structural_out["displacement"]) + + N_ITERS = 3 + SENSORS = [(8, 8), (8, 22), (22, 8), (22, 22)] + TARGETS = [ + jnp.float32(0.01), + jnp.float32(0.02), + jnp.float32(0.02), + jnp.float32(0.05), + ] + + def make_loss(temp): + loss = jnp.float32(0.0) + for (si, sj), target in zip(SENSORS, TARGETS, strict=False): + loss = loss + (temp[si, sj] - target) ** 2 + return loss + + # Unrolled version + def unrolled(params): + sx, sy, log_q = params[0], params[1], params[2] + q = jnp.exp(log_q) + temp = jnp.zeros((30, 30), dtype=jnp.float32) + disp = jnp.zeros((30, 30, 2), dtype=jnp.float32) + + def step(carry, _): + return G(carry, (sx, sy, q)), None + + (final_temp, _), _ = jax.lax.scan(step, (temp, disp), None, length=N_ITERS) + return make_loss(final_temp) + + # Implicit version + def implicit(params): + sx, sy, log_q = params[0], params[1], params[2] + q = jnp.exp(log_q) + + @jax.custom_vjp + def solve(p): + temp = jnp.zeros((30, 30), dtype=jnp.float32) + disp = jnp.zeros((30, 30, 2), dtype=jnp.float32) + + def step(carry, _): + return G(carry, p), None + + (ft, fd), _ = jax.lax.scan(step, (temp, disp), None, length=N_ITERS) + return (ft, fd) + + def fwd(p): + fp = solve(p) + return fp, (fp, p) + + def bwd(res, g): + (ft, fd), p = res + vt, vd = g + + def G_state(td): + return G(td, p) + + def adj_step(lam, _): + _, vjp_fn = jax.vjp(G_state, (ft, fd)) + dGT = vjp_fn(lam)[0] + return (vt + dGT[0], vd + dGT[1]), None + + (lt, ld), _ = jax.lax.scan(adj_step, (vt, vd), None, length=20) + + def G_params(pp): + return G((ft, fd), pp) + + _, vjp_p = jax.vjp(G_params, p) + return (vjp_p((lt, ld))[0],) + + solve.defvjp(fwd, bwd) + final_temp, _ = solve((sx, sy, q)) + return make_loss(final_temp) + + p0 = jnp.array([0.3, 0.7, jnp.log(8.0)], dtype=jnp.float32) + grad_u = jax.grad(unrolled)(p0) + grad_i = jax.grad(implicit)(p0) + + for i, name in enumerate(["sx", "sy", "log_q"]): + rel = abs(float(grad_i[i]) - float(grad_u[i])) / (abs(float(grad_u[i])) + 1e-30) + print( + f" {name}: unrolled={float(grad_u[i]):.6e} implicit={float(grad_i[i]):.6e} rel_err={rel:.2e}" + ) + assert rel < 1e-3, f"Implicit gradient for {name} deviates too much: {rel:.2e}" + print(" PASSED") + + +if __name__ == "__main__": + temp = test_thermal_forward() + test_structural_forward(temp) + test_one_way_gradient() + test_two_way_gradient() + test_implicit_differentiation() + print("\nAll smoke tests passed.") diff --git a/demo/multiphysics-optimization/thermal_solver/tesseract_api.py b/demo/multiphysics-optimization/thermal_solver/tesseract_api.py new file mode 100644 index 000000000..3c9911c95 --- /dev/null +++ b/demo/multiphysics-optimization/thermal_solver/tesseract_api.py @@ -0,0 +1,233 @@ +# Copyright 2025 Pasteur Labs. All Rights Reserved. +# SPDX-License-Identifier: Apache-2.0 + +"""Thermal solver Tesseract: 2D steady-state heat equation on a rectangular plate. + +Solves -k * laplacian(T) = q(x, y) with Dirichlet boundary conditions using +a finite-difference discretization on a regular grid. The heat source is a +Gaussian blob with parameterized location and intensity. + +When displacement is provided (from a structural solver), the mesh is deformed +accordingly, introducing geometry-dependent coupling for two-way +thermoelastic problems. +""" + +from typing import Any + +import equinox as eqx +import jax +import jax.numpy as jnp +from pydantic import BaseModel, Field + +from tesseract_core.runtime import Array, Differentiable, Float32 +from tesseract_core.runtime.tree_transforms import filter_func, flatten_with_paths + +# Grid resolution (interior nodes). Kept moderate for demo speed. +NX = 30 +NY = 30 + + +class InputSchema(BaseModel): + source_x: Differentiable[Float32] = Field( + description="Heat source x-location (0-1, fraction of plate width)" + ) + source_y: Differentiable[Float32] = Field( + description="Heat source y-location (0-1, fraction of plate height)" + ) + source_intensity: Differentiable[Float32] = Field( + description="Heat source intensity", default=10.0 + ) + source_width: Float32 = Field(description="Heat source Gaussian width", default=0.1) + displacement: Differentiable[Array[(NX, NY, 2), Float32]] = Field( + description="Displacement field from structural solver (NX x NY x 2). " + "Zero for the first coupling iteration.", + default=None, + ) + conductivity: Float32 = Field(description="Thermal conductivity", default=1.0) + boundary_temp: Float32 = Field( + description="Dirichlet boundary temperature", default=0.0 + ) + + +class OutputSchema(BaseModel): + temperature: Differentiable[Array[(NX, NY), Float32]] = Field( + description="Steady-state temperature field on interior nodes" + ) + + +def _make_grid(nx: int, ny: int): + """Create a unit-square grid of interior node positions.""" + x = jnp.linspace(0, 1, nx + 2)[1:-1] + y = jnp.linspace(0, 1, ny + 2)[1:-1] + X, Y = jnp.meshgrid(x, y, indexing="ij") + return X, Y + + +def _gaussian_source(X, Y, cx, cy, intensity, width): + """Gaussian heat source centered at (cx, cy).""" + r2 = (X - cx) ** 2 + (Y - cy) ** 2 + return intensity * jnp.exp(-r2 / (2 * width**2)) + + +def _solve_heat_jacobi(source, conductivity, boundary_temp, n_iters=500): + """Solve 2D Poisson equation via damped Jacobi iteration. + + This is intentionally simple — not the fastest solver, but fully + differentiable through JAX and easy to understand. + """ + nx, ny = source.shape + dx = 1.0 / (nx + 1) + dy = 1.0 / (ny + 1) + dx2 = dx**2 + dy2 = dy**2 + coeff = 1.0 / (2.0 * conductivity * (1.0 / dx2 + 1.0 / dy2)) + + T = jnp.full((nx + 2, ny + 2), boundary_temp) + + def iteration(T, _): + T_padded = T + laplacian = (T_padded[2:, 1:-1] + T_padded[:-2, 1:-1]) / dx2 + ( + T_padded[1:-1, 2:] + T_padded[1:-1, :-2] + ) / dy2 + T_interior = coeff * (conductivity * laplacian + source) + T_new = T_padded.at[1:-1, 1:-1].set(T_interior) + return T_new, None + + T_final, _ = jax.lax.scan(iteration, T, None, length=n_iters) + return T_final[1:-1, 1:-1] + + +@eqx.filter_jit +def apply_jit(inputs: dict) -> dict: + X, Y = _make_grid(NX, NY) + + # Deform grid if displacement is provided + displacement = inputs.get("displacement") + if displacement is not None: + X = X + displacement[:, :, 0] + Y = Y + displacement[:, :, 1] + + source = _gaussian_source( + X, + Y, + inputs["source_x"], + inputs["source_y"], + inputs["source_intensity"], + inputs["source_width"], + ) + + temperature = _solve_heat_jacobi( + source, + inputs["conductivity"], + inputs["boundary_temp"], + ) + + return {"temperature": temperature.astype(jnp.float32)} + + +def apply(inputs: InputSchema) -> OutputSchema: + return apply_jit(inputs.model_dump()) + + +def abstract_eval(abstract_inputs: Any) -> Any: + is_shapedtype_dict = lambda x: type(x) is dict and (x.keys() == {"shape", "dtype"}) + is_shapedtype_struct = lambda x: isinstance(x, jax.ShapeDtypeStruct) + + jaxified_inputs = jax.tree.map( + lambda x: jax.ShapeDtypeStruct(**x) if is_shapedtype_dict(x) else x, + abstract_inputs.model_dump(), + is_leaf=is_shapedtype_dict, + ) + dynamic_inputs, static_inputs = eqx.partition( + jaxified_inputs, filter_spec=is_shapedtype_struct + ) + + def wrapped_apply(dynamic_inputs: Any) -> Any: + inputs = eqx.combine(static_inputs, dynamic_inputs) + return apply_jit(inputs) + + jax_shapes = jax.eval_shape(wrapped_apply, dynamic_inputs) + return jax.tree.map( + lambda x: ( + {"shape": x.shape, "dtype": str(x.dtype)} if is_shapedtype_struct(x) else x + ), + jax_shapes, + is_leaf=is_shapedtype_struct, + ) + + +@eqx.filter_jit +def jvp_jit( + inputs: dict, + jvp_inputs: tuple[str], + jvp_outputs: tuple[str], + tangent_vector: dict, +) -> Any: + filtered_apply = filter_func(apply_jit, inputs, jvp_outputs) + return jax.jvp( + filtered_apply, + [flatten_with_paths(inputs, include_paths=jvp_inputs)], + [tangent_vector], + )[1] + + +def jacobian_vector_product( + inputs: InputSchema, + jvp_inputs: set[str], + jvp_outputs: set[str], + tangent_vector: dict[str, Any], +) -> Any: + return jvp_jit( + inputs.model_dump(), + tuple(jvp_inputs), + tuple(jvp_outputs), + tangent_vector, + ) + + +@eqx.filter_jit +def vjp_jit( + inputs: dict, + vjp_inputs: tuple[str], + vjp_outputs: tuple[str], + cotangent_vector: dict, +) -> Any: + filtered_apply = filter_func(apply_jit, inputs, vjp_outputs) + _, vjp_func = jax.vjp( + filtered_apply, flatten_with_paths(inputs, include_paths=vjp_inputs) + ) + return vjp_func(cotangent_vector)[0] + + +def vector_jacobian_product( + inputs: InputSchema, + vjp_inputs: set[str], + vjp_outputs: set[str], + cotangent_vector: dict[str, Any], +) -> Any: + return vjp_jit( + inputs.model_dump(), + tuple(vjp_inputs), + tuple(vjp_outputs), + cotangent_vector, + ) + + +@eqx.filter_jit +def jac_jit( + inputs: dict, + jac_inputs: tuple[str], + jac_outputs: tuple[str], +) -> Any: + filtered_apply = filter_func(apply_jit, inputs, jac_outputs) + return jax.jacrev(filtered_apply)( + flatten_with_paths(inputs, include_paths=jac_inputs) + ) + + +def jacobian( + inputs: InputSchema, + jac_inputs: set[str], + jac_outputs: set[str], +) -> Any: + return jac_jit(inputs.model_dump(), tuple(jac_inputs), tuple(jac_outputs)) diff --git a/demo/multiphysics-optimization/thermal_solver/tesseract_config.yaml b/demo/multiphysics-optimization/thermal_solver/tesseract_config.yaml new file mode 100644 index 000000000..10c7c11f2 --- /dev/null +++ b/demo/multiphysics-optimization/thermal_solver/tesseract_config.yaml @@ -0,0 +1,6 @@ +name: "thermal-solver" +version: "0.1.0" +description: "2D steady-state heat equation solver with Gaussian source parameterization" + +build_config: + target_platform: "native" diff --git a/demo/multiphysics-optimization/thermal_solver/tesseract_requirements.txt b/demo/multiphysics-optimization/thermal_solver/tesseract_requirements.txt new file mode 100644 index 000000000..8f33da031 --- /dev/null +++ b/demo/multiphysics-optimization/thermal_solver/tesseract_requirements.txt @@ -0,0 +1,2 @@ +jax[cpu]==0.5.2 +equinox diff --git a/pyproject.toml b/pyproject.toml index 9742f2269..3f3e956d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -196,6 +196,7 @@ ignore = [ "tests/*" = ["D101", "D102", "D103", "D106", "ANN"] "benchmarks/*" = ["D101", "D102", "D103", "D106", "ANN"] "examples/**/*" = ["D101", "D102", "D103", "D106", "ANN"] +"demo/**/*" = ["D101", "D102", "D103", "D106", "ANN"] "tesseract_core/sdk/templates/*" = ["D101", "D102", "D103", "D106", "ANN"] [tool.ruff.lint.pydocstyle] From 1b8c4a01e2822777bdaed6b86d77bfcdef3a7b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dion=20H=C3=A4fner?= Date: Thu, 25 Jun 2026 00:12:20 +0200 Subject: [PATCH 2/2] cleanup --- .../demo-executed.ipynb | 1157 ------ demo/multiphysics-optimization/demo.ipynb | 3219 +++-------------- .../requirements.txt | 9 +- docs/content/demo/demo.md | 6 + docs/index.md | 11 + docs/static/demo-multiphysics.svg | 51 + 6 files changed, 535 insertions(+), 3918 deletions(-) delete mode 100644 demo/multiphysics-optimization/demo-executed.ipynb create mode 100644 docs/static/demo-multiphysics.svg diff --git a/demo/multiphysics-optimization/demo-executed.ipynb b/demo/multiphysics-optimization/demo-executed.ipynb deleted file mode 100644 index 82a7d38f5..000000000 --- a/demo/multiphysics-optimization/demo-executed.ipynb +++ /dev/null @@ -1,1157 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Multi-Physics Pipeline with End-to-End Gradient Optimization\n", - "\n", - "This demo shows how to compose two physics solvers from different domains \u2014 thermal and structural \u2014 into a coupled pipeline, and solve a design inverse problem with **end-to-end gradients flowing automatically through the full chain**.\n", - "\n", - "Each solver is an independent Tesseract. The pipeline uses two-way (partitioned) coupling: the thermal solver produces a temperature field that causes thermal strain in the structural solver, and the resulting displacement feeds back to the thermal solver by deforming the geometry. Gradients propagate through this coupled iteration via JAX's automatic differentiation.\n", - "\n", - "## What we demonstrate\n", - "\n", - "1. **Two independent Tesseracts** \u2014 each team keeps their solver, their AD strategy, their dependencies\n", - "2. **Two-way coupling** via `jax.lax.scan` \u2014 not a toy feedforward chain, but the real partitioned coupling pattern used in practice\n", - "3. **End-to-end gradients** \u2014 `jax.grad` through the coupled iteration, validated against finite differences\n", - "4. **Gradient-based optimization beats gradient-free** \u2014 fewer evaluations for a 3-parameter design problem\n", - "5. **Solver swapping** \u2014 change one Tesseract, optimization code stays the same" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T11:53:57.971300Z", - "iopub.status.busy": "2026-03-28T11:53:57.971119Z", - "iopub.status.idle": "2026-03-28T11:53:59.602009Z", - "shell.execute_reply": "2026-03-28T11:53:59.601747Z" - } - }, - "outputs": [], - "source": [ - "import jax\n", - "import jax.numpy as jnp\n", - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "from scipy.optimize import minimize\n", - "\n", - "jax.config.update(\"jax_enable_x64\", True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 1. Load the solvers\n", - "\n", - "Each solver is a standalone Tesseract module with its own `tesseract_api.py`. In production, these would be containerized images composed via `tesseract-jax`'s `apply_tesseract`. Here we import them directly for speed." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T11:53:59.603583Z", - "iopub.status.busy": "2026-03-28T11:53:59.603443Z", - "iopub.status.idle": "2026-03-28T11:54:01.017721Z", - "shell.execute_reply": "2026-03-28T11:54:01.017439Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Thermal solver loaded: Thermal solver Tesseract: 2D steady-state heat equation on a rectangular plate.\n", - "Structural solver loaded: Structural solver Tesseract: 2D linear thermoelastic stress on a rectangular plate.\n" - ] - } - ], - "source": [ - "import sys\n", - "\n", - "sys.path.insert(0, \".\")\n", - "\n", - "import structural_solver.tesseract_api as structural_api\n", - "import thermal_solver.tesseract_api as thermal_api\n", - "\n", - "print(\"Thermal solver loaded:\", thermal_api.__doc__.strip().split(\"\\n\")[0])\n", - "print(\"Structural solver loaded:\", structural_api.__doc__.strip().split(\"\\n\")[0])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 2. Forward pass: single-shot thermal \u2192 structural\n", - "\n", - "Before coupling, let's verify each solver works independently and visualize the physics." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T11:54:01.043022Z", - "iopub.status.busy": "2026-03-28T11:54:01.042499Z", - "iopub.status.idle": "2026-03-28T11:54:01.706150Z", - "shell.execute_reply": "2026-03-28T11:54:01.705858Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "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5sdk3DXbBptyxrE4L3M9s9+MZ3GehcyQMxYAsN/dykwnAAAKheN5gSfVu3dvqaysTE4zZsxo9j1feeUVOeigg/zG2ssvv1weffRROeGEE1rxUwMAECxNgRdgsjVnzhzp06ePlJWVybBhw2TlypUHjNcbnf369fPjBwwYIE8++WTyb7FYTK677jp/focOHaRnz54yfvx4+fBDm16D+9AYCwBIclNSFdhONMYCAAoyTUGQSR9O2rhRdu7cmZxuuOGGZt/yuOOOk3Xr1sk//vEP+e53vysTJkyQ1157rfU+MwAAbdTxx7V8v0WLFsmUKVNk+vTpsmbNGhk4cKCMGjVKtm7dmjZ++fLlcuGFF8pll13m52MfM2aMP7366qv+32tqavz13HLLLf5///jHP8qbb74pX/nKV/I7TQEAIFzkjAUAoHUH8OrUqZM/mSgpKZFjjz3W//fgwYPlpZdekrvvvlt+9atfZb4hAAC0Au3ZapEVaj+2PWNnzZolkyZNkokTJ/qv586dK0888YTMnz9frr/++v3itT4955xzZOrUqf7r2267TZ5++mm55557/GX16RV9nUr/NnToUNmwYYMcccQRxttGz1gAAAAAyEGu60ptrXluQwAAcl1VVVWjKV09WFdXJ6tXr5aRI0cm50UiEf/1ihUr0q5X56fGK+1J21y80idaHMeRzp07W30GGmMBAEnkjAUAoHXTFJjS9AXPP/+8vP/++37uWH29bNkyueiii8L6hAAAtLtqs7dBrvXt27f7g11279690Xx9vXnz5rTbp/Nt4vfu3evnkNXUBqZPuCSQpgAAkESaAgAAWjdNgSnNcacDhXz00Uf+xedJJ50kTz31lHzxi1/MfCMAAGglbsA0BW5KrvXUxk8d1LK16WBeF1xwgXieJ/fee6/18jTGAgAAAEA795vf/KatNwEAgDbXySDXerdu3SQajcqWLVsazdfXPXr0SLuMzjeJTzTErl+/Xv76179a94pVpCkAAOzXMzbTCQCAgtHKaQoAAMhlOgBX0MmUDnipA10uXbq0UZ51fT18+PC0y+j81HilA3alxicaYv/1r3/JM888I127dpVM0DMWAJAUJPcrOWMBAIWktdMUAACQy4KOM+Jaxk+ZMkUmTJggQ4YMkaFDh8rs2bOlurpaJk6c6P9dU//06tUrmXP26quvljPOOENmzpwp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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Run thermal solver\n", - "thermal_out = thermal_api.apply_jit(\n", - " {\n", - " \"source_x\": jnp.float32(0.5),\n", - " \"source_y\": jnp.float32(0.5),\n", - " \"source_intensity\": jnp.float32(10.0),\n", - " \"source_width\": 0.1,\n", - " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", - " \"conductivity\": 1.0,\n", - " \"boundary_temp\": 0.0,\n", - " }\n", - ")\n", - "temperature = np.asarray(thermal_out[\"temperature\"])\n", - "\n", - "# Run structural solver\n", - "structural_out = structural_api.apply_jit(\n", - " {\n", - " \"temperature\": thermal_out[\"temperature\"],\n", - " \"youngs_modulus\": 200.0,\n", - " \"poissons_ratio\": 0.3,\n", - " \"thermal_expansion\": 1e-3,\n", - " }\n", - ")\n", - "\n", - "fig, axes = plt.subplots(1, 3, figsize=(14, 4))\n", - "im0 = axes[0].imshow(temperature.T, origin=\"lower\", extent=[0, 1, 0, 1], cmap=\"hot\")\n", - "axes[0].set_title(\"Temperature field\")\n", - "plt.colorbar(im0, ax=axes[0])\n", - "\n", - "disp_mag = np.linalg.norm(np.asarray(structural_out[\"displacement\"]), axis=-1)\n", - "im1 = axes[1].imshow(disp_mag.T, origin=\"lower\", extent=[0, 1, 0, 1], cmap=\"viridis\")\n", - "axes[1].set_title(\"Displacement magnitude\")\n", - "plt.colorbar(im1, ax=axes[1])\n", - "\n", - "s = np.asarray(structural_out[\"stress\"])\n", - "von_mises = np.sqrt(\n", - " s[:, :, 0] ** 2 - s[:, :, 0] * s[:, :, 1] + s[:, :, 1] ** 2 + 3 * s[:, :, 2] ** 2\n", - ")\n", - "im2 = axes[2].imshow(von_mises.T, origin=\"lower\", extent=[0, 1, 0, 1], cmap=\"inferno\")\n", - "axes[2].set_title(\"Von Mises stress\")\n", - "plt.colorbar(im2, ax=axes[2])\n", - "\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3. The design problem: thermoelastic inverse optimization\n", - "\n", - "**Problem**: Find the heat source location and intensity that produces desired temperatures at four sensor locations, after the thermoelastic coupling has converged.\n", - "\n", - "This can't be solved with the thermal solver alone \u2014 the displacement from thermal expansion changes the geometry, which changes the temperature field. You need gradients through the full coupled iteration.\n", - "\n", - "**Design variables**: source position $(x, y)$ and log-intensity $\\log(q)$ (3 parameters).\n", - "\n", - "**Objective**: $\\sum_i (T_{\\text{sensor}_i} - T_{\\text{target}_i})^2$ evaluated after coupled convergence." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T11:54:01.707528Z", - "iopub.status.busy": "2026-03-28T11:54:01.707416Z", - "iopub.status.idle": "2026-03-28T11:54:02.000451Z", - "shell.execute_reply": "2026-03-28T11:54:02.000131Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Sensor positions (approx):\n", - " (0.26, 0.26) -> T_target = 0.010\n", - " (0.26, 0.71) -> T_target = 0.020\n", - " (0.71, 0.26) -> T_target = 0.020\n", - " (0.71, 0.71) -> T_target = 0.050\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Objective at initial guess: 6.175704e-03\n" - ] - } - ], - "source": [ - "# Sensor locations (grid indices) and target temperatures\n", - "SENSORS = [(8, 8), (8, 22), (22, 8), (22, 22)]\n", - "TARGETS = [jnp.float32(0.01), jnp.float32(0.02), jnp.float32(0.02), jnp.float32(0.05)]\n", - "\n", - "# Approximate physical positions of sensors (for visualization)\n", - "sensor_positions = [(i / 31, j / 31) for i, j in SENSORS]\n", - "print(\"Sensor positions (approx):\")\n", - "for (sx, sy), t in zip(sensor_positions, TARGETS, strict=False):\n", - " print(f\" ({sx:.2f}, {sy:.2f}) -> T_target = {float(t):.3f}\")\n", - "\n", - "N_COUPLING_ITERS = 3\n", - "\n", - "\n", - "def coupled_objective(params):\n", - " \"\"\"Two-way coupled thermoelastic inverse problem.\n", - "\n", - " params: [source_x, source_y, log_intensity]\n", - " Returns: sum of squared temperature errors at sensor locations.\n", - " \"\"\"\n", - " source_x, source_y, log_intensity = params[0], params[1], params[2]\n", - " intensity = jnp.exp(log_intensity)\n", - "\n", - " temp = jnp.zeros((30, 30), dtype=jnp.float32)\n", - " disp = jnp.zeros((30, 30, 2), dtype=jnp.float32)\n", - "\n", - " def coupling_step(carry, _):\n", - " _temp, disp = carry\n", - " thermal_out = thermal_api.apply_jit(\n", - " {\n", - " \"source_x\": source_x,\n", - " \"source_y\": source_y,\n", - " \"source_intensity\": intensity,\n", - " \"source_width\": jnp.float32(0.15),\n", - " \"displacement\": disp,\n", - " \"conductivity\": 1.0,\n", - " \"boundary_temp\": 0.0,\n", - " }\n", - " )\n", - " structural_out = structural_api.apply_jit(\n", - " {\n", - " \"temperature\": thermal_out[\"temperature\"],\n", - " \"youngs_modulus\": 200.0,\n", - " \"poissons_ratio\": 0.3,\n", - " \"thermal_expansion\": 1e-3,\n", - " }\n", - " )\n", - " return (thermal_out[\"temperature\"], structural_out[\"displacement\"]), None\n", - "\n", - " (final_temp, _), _ = jax.lax.scan(\n", - " coupling_step, (temp, disp), None, length=N_COUPLING_ITERS\n", - " )\n", - "\n", - " loss = jnp.float32(0.0)\n", - " for (si, sj), target in zip(SENSORS, TARGETS, strict=False):\n", - " loss = loss + (final_temp[si, sj] - target) ** 2\n", - " return loss\n", - "\n", - "\n", - "# Test forward pass\n", - "p0 = jnp.array([0.2, 0.2, jnp.log(5.0)], dtype=jnp.float32)\n", - "print(f\"\\nObjective at initial guess: {float(coupled_objective(p0)):.6e}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 4. End-to-end gradients through the coupled pipeline\n", - "\n", - "The key moment: `jax.grad` differentiates through the entire coupled iteration \u2014 through both solvers, through `lax.scan`, automatically. No manual adjoint derivation, no monolithic rewrite." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T11:54:02.002160Z", - "iopub.status.busy": "2026-03-28T11:54:02.002008Z", - "iopub.status.idle": "2026-03-28T11:54:02.697883Z", - "shell.execute_reply": "2026-03-28T11:54:02.697607Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Gradients at initial guess:\n", - " d(loss)/d(source_x) = 2.295046e-02\n", - " d(loss)/d(source_y) = 2.295046e-02\n", - " d(loss)/d(log_intensity) = 8.693038e-03\n" - ] - } - ], - "source": [ - "grad_fn = jax.grad(coupled_objective)\n", - "\n", - "grads = grad_fn(p0)\n", - "print(\"Gradients at initial guess:\")\n", - "print(f\" d(loss)/d(source_x) = {float(grads[0]):.6e}\")\n", - "print(f\" d(loss)/d(source_y) = {float(grads[1]):.6e}\")\n", - "print(f\" d(loss)/d(log_intensity) = {float(grads[2]):.6e}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Gradient validation against finite differences\n", - "\n", - "For a rigorous audience, correctness proof is non-negotiable." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T11:54:02.699244Z", - "iopub.status.busy": "2026-03-28T11:54:02.699140Z", - "iopub.status.idle": "2026-03-28T11:54:03.348779Z", - "shell.execute_reply": "2026-03-28T11:54:03.348280Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " AD FD Rel. Error\n", - "d(loss)/d(source_x) 2.295046e-02 2.295244e-02 8.63e-05\n", - "d(loss)/d(source_y) 2.295046e-02 2.295244e-02 8.63e-05\n", - "d(loss)/d(log_intensity) 8.693038e-03 8.689240e-03 4.37e-04\n" - ] - } - ], - "source": [ - "eps = 1e-4\n", - "fd_grads = []\n", - "for i in range(3):\n", - " p_plus = p0.at[i].add(eps)\n", - " p_minus = p0.at[i].add(-eps)\n", - " fd_grads.append(\n", - " (coupled_objective(p_plus) - coupled_objective(p_minus)) / (2 * eps)\n", - " )\n", - "\n", - "names = [\"d(loss)/d(source_x)\", \"d(loss)/d(source_y)\", \"d(loss)/d(log_intensity)\"]\n", - "print(f\"{'':32s} {'AD':>14s} {'FD':>14s} {'Rel. Error':>12s}\")\n", - "for name, ad, fd in zip(names, grads, fd_grads, strict=False):\n", - " rel_err = abs(float(ad) - float(fd)) / (abs(float(fd)) + 1e-30)\n", - " print(f\"{name:32s} {float(ad):14.6e} {float(fd):14.6e} {rel_err:12.2e}\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 5. Optimization: gradient-based vs gradient-free\n", - "\n", - "We compare:\n", - "- **L-BFGS-B** (gradient-based, using our end-to-end gradients)\n", - "- **Nelder-Mead** (gradient-free)\n", - "\n", - "Both optimize 3 design variables: source position $(x, y)$ and log-intensity." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T11:54:03.350521Z", - "iopub.status.busy": "2026-03-28T11:54:03.350395Z", - "iopub.status.idle": "2026-03-28T11:54:39.034362Z", - "shell.execute_reply": "2026-03-28T11:54:39.034007Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Running L-BFGS-B (gradient-based)...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Source: (0.674, 0.674)\n", - " Intensity: 2.73\n", - " Objective: 3.169720e-06\n", - " Evaluations: 27\n", - "\n", - "Running Nelder-Mead (gradient-free)...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Source: (0.673, 0.673)\n", - " Intensity: 2.73\n", - " Objective: 3.168822e-06\n", - " Evaluations: 254\n", - "\n", - "Speedup: 254/27 = 9.4x fewer evaluations with gradients\n" - ] - } - ], - "source": [ - "eval_history_grad = []\n", - "eval_history_free = []\n", - "\n", - "\n", - "def objective_and_grad(x):\n", - " p = jnp.array(x, dtype=jnp.float32)\n", - " obj = coupled_objective(p)\n", - " g = grad_fn(p)\n", - " eval_history_grad.append(float(obj))\n", - " return float(obj), np.array([float(g[i]) for i in range(3)])\n", - "\n", - "\n", - "def objective_only(x):\n", - " p = jnp.array(x, dtype=jnp.float32)\n", - " obj = coupled_objective(p)\n", - " eval_history_free.append(float(obj))\n", - " return float(obj)\n", - "\n", - "\n", - "x0 = np.array([0.2, 0.2, np.log(5.0)])\n", - "bounds = [(0.05, 0.95), (0.05, 0.95), (np.log(1.0), np.log(50.0))]\n", - "\n", - "print(\"Running L-BFGS-B (gradient-based)...\")\n", - "result_grad = minimize(\n", - " objective_and_grad,\n", - " x0,\n", - " method=\"L-BFGS-B\",\n", - " jac=True,\n", - " bounds=bounds,\n", - " options={\"maxiter\": 100},\n", - ")\n", - "print(f\" Source: ({result_grad.x[0]:.3f}, {result_grad.x[1]:.3f})\")\n", - "print(f\" Intensity: {np.exp(result_grad.x[2]):.2f}\")\n", - "print(f\" Objective: {result_grad.fun:.6e}\")\n", - "print(f\" Evaluations: {len(eval_history_grad)}\")\n", - "\n", - "print(\"\\nRunning Nelder-Mead (gradient-free)...\")\n", - "result_free = minimize(\n", - " objective_only,\n", - " x0,\n", - " method=\"Nelder-Mead\",\n", - " options={\"maxiter\": 500, \"xatol\": 1e-6, \"fatol\": 1e-15},\n", - ")\n", - "print(f\" Source: ({result_free.x[0]:.3f}, {result_free.x[1]:.3f})\")\n", - "print(f\" Intensity: {np.exp(result_free.x[2]):.2f}\")\n", - "print(f\" Objective: {result_free.fun:.6e}\")\n", - "print(f\" Evaluations: {len(eval_history_free)}\")\n", - "\n", - "print(\n", - " f\"\\nSpeedup: {len(eval_history_free)}/{len(eval_history_grad)} \"\n", - " f\"= {len(eval_history_free) / max(len(eval_history_grad), 1):.1f}x fewer evaluations with gradients\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T11:54:39.037061Z", - "iopub.status.busy": "2026-03-28T11:54:39.036939Z", - "iopub.status.idle": "2026-03-28T11:54:39.208631Z", - "shell.execute_reply": "2026-03-28T11:54:39.208352Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAAHqCAYAAACZcdjsAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjcsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvTLEjVAAAAAlwSFlzAAAPYQAAD2EBqD+naQAAnzVJREFUeJzt3QeYE2XXBuCzvbMLLL0joNIRUbEhggIqiliw/WIDCyj2+lngU7EiKKifvSsqggVFFCmC9KLSi0hdyrJsZ2vyX8+bnWSSTLLJbrJpz31dYZPJJJlkssucOee8b5TZbDYLERERERFRLUTX5sFERERERETAwIKIiIiIiGqNgQUREREREdUaAwsiIiIiIqo1BhZERERERFRrDCyIiIiIiKjWGFgQEREREVGtMbAgIiIiIqJaY2BBRERERES1xsCCiHzmhhtukLZt29oti4qKkqeeekqCyQcffKC2a9WqVRJKzjnnHHWh0PmuwbZt2+T888+X9PR0tY2zZs2SSOPrffPvv/+q58Tvcl0K1OsShQoGFkRhYOfOnTJ27Fjp1KmTJCcnq0vnzp1lzJgx8tdff0m4++yzz2Ty5MmB3gyKADX5ro0cOVL+/vtveeaZZ+Tjjz+Wk08+WcLRjz/+GJSBXU3wbwpRzcTW8HFEFCR++OEHGTFihMTGxsq1114rPXr0kOjoaNm8ebN888038sYbb6jAo02bNgHZvmPHjqlt8/dBwPr16+Xuu+/26+tQcAvG7xq2aenSpfLYY4+p4D+cIbCYNm2aYXDh632Dv2d4zri4OKnL/ezv1yUKdQwsiELYjh075KqrrlL/2c2bN0+aNWtmd//zzz8vr7/+ugo03CkqKpKUlBS/bGNiYqJfnpdCU6R91w4fPqx+ZmRkBPSzCTRf7xuUIwVifwfqdYlCBUuhiELYCy+8oA5G3n//faegAnCG8K677pJWrVrZ1aanpqaqoOSCCy6QtLQ0lemA33//Xa644gpp3bq1JCQkqMfdc8896gydI9SJd+3aVf0ni58zZ870uLZ63759ctNNN0mTJk3U63Tp0kXee+89u3UWLFigHvvll1+qEpKWLVuq1xowYIBs377duh56DmbPni27du1S6+PiWHvvSnFxsdx6663SsGFDqVevnlx//fVy9OhRu3W+/fZbufDCC6V58+ZqW4877jj573//K5WVlU519Jdddpk0bdpUbSe2F0FfXl6e3XqffPKJ9O7dW5KSkqRBgwZqnT179jht21tvvaVeC+udcsopat94Avuif//+TstNJpO0aNFCLr/8cuuyL774Qm0LvgN4/926dZMpU6ZU+xpHjhyR//u//1OPwQEzSn3+/PNPp9rzSP+uYVu0TOEDDzxgtz7uw+2NGzfKNddcI/Xr15czzzzT6+/J8uXLZfDgwap/AyWQ/fr1kyVLlognDh06JDfffLP6bPB+ke388MMPDXsKXnrpJXnllVfU+8E24XVwRl+/r5Gt0PaDdnG1b7T3v3XrVrnuuuvU9jdq1Egef/xxMZvN6r1ecskl6juG36mXX37ZcLu075u2D40u+n3kye+zu/3sqsfit99+k7POOksFhvidwLZv2rTJbh3tPeM7hc8L6+F933jjjepvEVE4YMaCKMTLoDp06CCnnnqqV4+rqKiQQYMGqQMZHDDggAS++uor9R/c7bffrg62V6xYIa+99prs3btX3aeZO3euOohGH8fEiRPVgSb+c8QBWXUOHjwop512mvoPFqUhOJj46aef1AFOfn6+U+nBc889pzIu999/vzpIRzCFg1McUAFKTLAc24gDH8DBrCfw+vjPHf/hb9myRZWN4WBCO0gBHEDg+e699171EwcQTzzxhNrWF198Ua1TVlamPs/S0lK588471YEQDmixf3Jzc9XBA+CgFQdOV155pdxyyy3qbDY+37PPPlvWrl1rPav97rvvqoDn9NNPV5/HP//8IxdffLE6wNQHiUZQFof3c+DAAbUdmsWLF8v+/fvVASr88ssvcvXVV6uDZ2S2AAdCOCgdN26cy+dHgDJ06FD13cD35IQTTlAHawgujETyd2348OFqnyJgwmeN4MpxfQRXHTt2lGeffVYdUHvzPcF3cciQISoAefLJJ9W24yTDueeeqwI3BKSuIIDDATQOcvHZtGvXTn3uOODFd9bxO/DRRx9JQUGB6tsqKSlRASheB70jCEzwfcX3C98r9JF4Ct/XE088UX32OJh/+umn1ff8f//7n3p+fDc//fRTtU/69OmjPgMjeA7H18X7wO9t48aNrcs8+X32dj//+uuvaj+0b99e/e7hs8X+OuOMM2TNmjVOwSf2Kz5vfJ9x/zvvvKO2Ufs9JAppZiIKSXl5eTgKMQ8bNszpvqNHj5oPHz5svRQXF1vv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9Pre/C0K6sACQ8MigsI8FHq4jTdPRERE4UsLKho3bizJyclhfcCNg0uctcZkvuH8Pim49j1eu7i42DookjZFQ00FdWARHx+vJrSbN2+edQhaRHS4PXbs2EBvHhEREfmx/EkLKho2bCjhjoFF5DIHeN8nJSWpnwgu8Pvmriwq6AMLpH22b99uvb1z5041ylODBg2kdevWqt9h5MiRcvLJJ6u5KyZPnqyGqNVGifIXDH+LC/6wERERUd3SeiqQqSAi/9J+z/B7F9KBxapVq6R///7W21rjNIKJDz74QEaMGKFGZHriiSdUShRzVsyZM8epodvXxowZoy5o3k5PT/fraxEREZExnr0nCp3fs4AHFuecc45KAbmDsieWPhERERERBS8OOUFEREREfoN5xJ599lkJB5gbTev7rc7DDz8sd955p0QSBhZEREREATjw1Co3tCGGMWgNRr284oorZNeuXdZ1/v33X7WO4+W6666ze64ZM2aoCYHr16+vGnKPP/54uemmm2Tt2rXWddA7+txzz8kJJ5yg1kFP66mnnirvvPOOy21csGCB3evicV26dJG33nqr2vf3559/yo8//ih33XWXtYb/oYceUvOJpaSkSPPmzeX666+X/fv3u3w9/WXlypUSKu6//3758MMP5Z9//pFIwcCCiIiIKIBGjRqlDqwRTGAy3z179jgFDfDrr79KVlaW9YJBZjQ4WEdfKnpRv/vuO9myZYt89tln0r59ezX5r2b8+PHyyiuvyH//+1/ZuHGjzJ8/X0aPHu3RXCF4TrwuHnfrrbfK7bffrkbqdOe1115TgVJqaqq6jaFN16xZI48//rj6+c0336jnvfjii62POf300+3eJy633HKLtGvXTg3mEyoyMzNl0KBB8sYbb0jEMJOhqVOnmk888URzp06d0ABizsvLC8h2VFZWmrOystTPcPPT3/vNg15ZaO702I/qJ25TZOx7co/7PnJx39scO3bMvHHjRvUzlP6vGTlypPmSSy7xeP1+/fqZx40bZzaZTOaysjL18+OPPzYnJydb19m5c6c6Flm7dq3hcyxdulTdP2XKFMP78ZyaHj16mJ966imv3tP8+fPV8x89etRu+XHHHWd+4YUXXD6uoqLCnJ6ebv7hhx/cPv+KFSvU8+/atcvwfnwujRo1Mk+YMMHt82D7br75ZnNmZqY5LS3N3L9/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HcwPPPCAOS8vL6T3fRT+CXTWhIiIiIiIQht7LIiIiIiIqNYYWBARERERUa0xsCAiIiIiolpjYEFERERERLXGwIKIiIiIiGqNgQUREREREdUaAwsiIiIiIqo1BhZERERERFRrDCyIiMittm3byuTJkyUcREVFyaxZs/z+OgsWLFCvlZub6/fXIiIKFgwsiIiCxA033KAORh0v27dvr5PX/+CDDyQjI8Np+cqVK2X06NF1sg2h6JxzzpG7777bbtnpp58uWVlZkp6eHrDtIiKqa7F1/opEROTS4MGD5f3337db1qhRo4BtTzC8fiiKj4+Xpk2bBnoziIjqFDMWRERBJCEhQR2Q6i8xMTEqmzFs2DC7dXGWHGfLNbh+1113yYMPPigNGjRQj33qqafsHoPSnFtvvVWaNGkiiYmJ0rVrV/nhhx9U6c6NN94oeXl51kyJ9ljHUqjdu3fLJZdcIqmpqVKvXj258sor5eDBg9b78biePXvKxx9/rB6Ls/ZXXXWVFBQUuH3vixcvlrPOOkuSkpKkVatW6r0UFRWp+x599FE59dRTnR7To0cPmTBhgjWzct5550lmZqZ6zX79+smaNWu8Kldat26dWvbvv/+q20eOHJGrr75aWrRoIcnJydKtWzf5/PPPretjvyxcuFCmTJli/dzwWKPnnjFjhnTp0kXtY3wuL7/8st32YNmzzz4rN910k6SlpUnr1q3lrbfest5fVlYmY8eOlWbNmql916ZNG5k4caLbz5SIqC4xsCAiCiMffvihpKSkyPLly+WFF15QB92//PKLus9kMsmQIUNkyZIl8sknn8jGjRvlueeeU4ELSncQPCBQQAkPLvfff7/T8+M5EFTk5OSoA2o89z///CMjRoywW2/Hjh2qlwFBCy5YF6/lCtZHtuayyy6Tv/76S6ZPn64CDRxIw7XXXisrVqxQ62k2bNig1r3mmmvUbQQuI0eOVI9btmyZdOzYUS644IJqAxp3SkpKpHfv3jJ79mxZv369Kgn7v//7P7UtgICib9++MmrUKOvnhqDI0erVq1UAhgDr77//VsHX448/rsrP9BBsnHzyybJ27Vq544475Pbbb5ctW7ao+1599VX57rvv5Msvv1TLPv30UxWMEBEFDTMREQWFkSNHmmNiYswpKSnWy+WXX26975JLLrFbf9y4ceZ+/fpZb+P6mWeeabdOnz59zA899JC6/vPPP5ujo6PNW7ZsMXz9999/35yenu60vE2bNuZXXnlFXZ87d67axt27d1vv37Bhgxn/naxYsULdfvLJJ83Jycnm/Px86zoPPPCA+dRTT3X53m+++Wbz6NGj7Zb9/vvvanuPHTumbvfo0cM8YcIE6/2PPPKI2+esrKw0p6Wlmb///nvrMmznzJkz1fX58+er20ePHrXev3btWrVs586dLp/3wgsvNN933312nzv2hZ7jc19zzTXm8847z24dfCadO3e2+5yvu+46622TyWRu3Lix+Y033lC377zzTvO5556rlhMRBSNmLIiIgkj//v1VOY52wVlqb3Tv3t3uNspmDh06pK7j+Vq2bCmdOnWq8fZt2rRJnZHXn5Xv3LmzavrGfRqcSUc5j9F2GPnzzz/V2XuUV2mXQYMGqQzJzp07rVmLzz77TF1HjICSJCzToBwLmQNkKlAKhexLYWGhKt2qqcrKSvnvf/+rSqBQXobt+vnnn71+Tnw2Z5xxht0y3N62bZt6DaP9h1IqlLNpnxvKrrAPjz/+eFUmNnfu3Bq/LyIif2DzNhFREEEZU4cOHZyWR0dHq4NpvfLycqf14uLi7G7j4BQH54DehbribjuMIABA7wcOmB2h1wDQ6/DQQw+pvoljx47Jnj177EqwUAaFngiUJ6H/AL0MKFNCb4IRfKag/1wdP9MXX3xRPR/KxBBcYP+gt8XVc/rzczvppJNUkPXTTz/Jr7/+qkqrBg4cKF9//bVftoWIyFsMLIiIQgBGZkKNvx7OXjseiLqDs+F79+6VrVu3GmYtMJKR/uy5kRNPPFEd0OOiZS3Qq4EmZWQuagoHzXgeo6BKg2wLGrLRW4DAAo3ajRs3tt6P3pHXX39d9VUAtjE7O7va0a7QF1G/fn3rZ6qH50RPyXXXXadu4yAfn5/+vXr6ueG5HJ8b+wE9Lp5CFgbBFC6XX3656ktBvwuyKUREgcZSKCKiEHDuuefKqlWr5KOPPlLlM08++aRToFEdHJSfffbZqkEaTdfa2e85c+ZYy5eQOZg3b546IC8uLnZ6Dpwhx5l7lCAhc4Am5uuvv149N5qOawqZiD/++EM1a+PgHu/x22+/tTZva/C6X3zxhXz11Vd2ZVCAEiiMRIWyIzSv4353WRoEMQiO0EiN10ODtuNITXhOfFbYNjwvsir6EbC0zw2vh9Gg8LkZZWbuu+8+9bmirAqBCZrsp06datgg78qkSZNU+dfmzZvVc+AzQKmU0dwjRESBwMCCiCgEoN8AowhhKNk+ffqokY5wQO8tDHmKx6OsCGfd8Xza2XaMDHXbbbeps+E4m49RpRyhNAcH/DjDjyAFgUb79u3VKE61gWwKRo7CATOGnO3Vq5c88cQT0rx5c7v1cJYe5U4IehyH33333Xfl6NGjKvuBkZtQVqXPaDhCtkc7UMfrP//88/L000/brfOf//xHPR8+fwzniwN5x9dFcICsAz5PfG5G/Rd4DozmhKAIQ/zivWHELvRNeAo9K9gnCOCwDxHI/Pjjj9aSLiKiQItCB3egN4KIiIiIiEIbT3MQEREREVGtMbAgIiIiIqJaY2BBRERERES1xsCCiIiIiIhqjYEFERERERHVGgMLIiIiIiKqNQYWRERERERUawwsiIiIiIio1hhYEBERERFRrTGwICIiIiKiWmNgQUREREREtcbAgoiIiIiIpLb+H4niATN6ZUGyAAAAAElFTkSuQmCC", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig, ax = plt.subplots(figsize=(8, 5))\n", - "ax.semilogy(\n", - " eval_history_grad,\n", - " \"o-\",\n", - " label=f\"L-BFGS-B ({len(eval_history_grad)} evals)\",\n", - " linewidth=2,\n", - " markersize=4,\n", - ")\n", - "ax.semilogy(\n", - " eval_history_free,\n", - " \"s-\",\n", - " label=f\"Nelder-Mead ({len(eval_history_free)} evals)\",\n", - " linewidth=2,\n", - " markersize=3,\n", - ")\n", - "ax.set_xlabel(\"Function evaluations\")\n", - "ax.set_ylabel(\"Objective (sensor temperature error)\")\n", - "ax.set_title(\"Gradient-based vs gradient-free optimization\")\n", - "ax.legend()\n", - "ax.grid(True, alpha=0.3)\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 6. Visualize the optimized design\n", - "\n", - "Show the converged temperature field with sensor locations and targets." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T11:54:39.210096Z", - "iopub.status.busy": "2026-03-28T11:54:39.209991Z", - "iopub.status.idle": "2026-03-28T11:54:39.364520Z", - "shell.execute_reply": "2026-03-28T11:54:39.364240Z" - } - }, - "outputs": [ - { - "data": { - "image/png": "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ZyHGjRunMhTr169HrVq10qi07i2ln4UM1Xb48GF12d96e+WVV9CwYUP1twzLQ2lTJ55++ml1ud/6Q0H8999/KoBlkJq2n4W0mU8YjFp/QJj7AVFa0OucbUqDGyXC5IZDjsgQIvPmzVNDV/To0UMNORIcHKwe79Spk+mjjz6KNzxV5syZTV999ZUaEmn48OEcnkqnz+Lzzz9Xw8UsX77cdPXq1bhbRESEjq8iY34WCbHXvz6fw4ULF9TIF3369DGdOHHCtGbNGlP+/PlNn376qY6vImN+FnJukM9i8eLFaoik33//3VS6dGk1cgylnny/y5CEcpOQZMKECerv8+fPq8flM5DPIuHwVIMGDVLnbBnS0JXDU929e9dUsGDBtIhT1fPI81F8bheoChlXrXjx4irokSFIdu3aFfdYgwYN1EnX1o8//mgqV66cWl+GvVi7dq0OpXZPKfksSpQoYbfyygmC0r5e2GKgqt/nsGPHDjVkngRVMlTVZ599poYOo7T9LB48eGAaMWKECk59fX1NxYoVM7333numW7du6VR697B582a73/vW917+l88i4TaBgYHqc5M6MXfuXJeWUYJHGTbK1TcGqfZlkn8Sy7YSEREREenFrdqoEhEREZH7YKBKRERERIbEQJWIiIiIDImBKhEREREZEgNVIiIiIjIkBqpEREREZEgMVImIiIjIkBioEhEREZEhMVAlIiIiIkNioEpEREREhsRAlYjSrdDQUBQsWBBjxoyJW7Zjxw54e3tj06ZNupaNiIi0y2QymUxO2A8RkS7WrVuHVq1aqQC1fPnyCAwMRMuWLTFhwgS9i0ZERBoxUCWidK93797YuHEjatWqhcOHD2PPnj3w8fHRu1hERKQRA1UiSvfu3r2LypUr4+LFi9i3bx+qVKmid5GIiMgJ2EaViNK906dP48qVK4iNjcW5c+f0Lg4RETkJM6pElK5FR0ejdu3aqm2qtFGdOHGiuvyfP39+vYtGREQaMVAlonRt0KBBWL58OQ4dOoTs2bOjQYMG8Pf3x5o1a/QuGhERacRL/0SUbm3ZskVlUBcsWAA/Pz94eHiov7dt24Zp06bpXTwiItKIGVUiIiIiMiRmVImIiIjIkBioEhEREZEhMVAlIiIiIkNioEpEREREhsRAlYiIiIgMiYEqERERERkSA1UiIiIiMiQGqkRERERkSAxUiYiIiMiQGKgSERERkSExUCUiIiIiQ2KgSkREREQwov8D91ztfgwZKawAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "# Run the optimized design through the pipeline\n", - "opt = result_grad.x\n", - "thermal_opt = thermal_api.apply_jit(\n", - " {\n", - " \"source_x\": jnp.float32(opt[0]),\n", - " \"source_y\": jnp.float32(opt[1]),\n", - " \"source_intensity\": jnp.float32(np.exp(opt[2])),\n", - " \"source_width\": jnp.float32(0.15),\n", - " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", - " \"conductivity\": 1.0,\n", - " \"boundary_temp\": 0.0,\n", - " }\n", - ")\n", - "temp_opt = np.asarray(thermal_opt[\"temperature\"])\n", - "\n", - "fig, ax = plt.subplots(figsize=(7, 6))\n", - "im = ax.imshow(temp_opt.T, origin=\"lower\", extent=[0, 1, 0, 1], cmap=\"hot\")\n", - "plt.colorbar(im, ax=ax, label=\"Temperature\")\n", - "\n", - "# Plot sensor locations and achieved vs target temperatures\n", - "for (si, sj), target in zip(SENSORS, TARGETS, strict=False):\n", - " px, py = si / 31, sj / 31\n", - " achieved = float(temp_opt[si, sj])\n", - " ax.plot(px, py, \"wo\", markersize=10, markeredgecolor=\"blue\", markeredgewidth=2)\n", - " ax.annotate(\n", - " f\"T={achieved:.3f}\\n(target={float(target):.3f})\",\n", - " xy=(px, py),\n", - " xytext=(5, 5),\n", - " textcoords=\"offset points\",\n", - " fontsize=8,\n", - " color=\"white\",\n", - " fontweight=\"bold\",\n", - " bbox=dict(boxstyle=\"round,pad=0.2\", facecolor=\"black\", alpha=0.7),\n", - " )\n", - "\n", - "# Plot optimized source location\n", - "ax.plot(\n", - " float(opt[0]),\n", - " float(opt[1]),\n", - " \"r*\",\n", - " markersize=20,\n", - " markeredgecolor=\"white\",\n", - " markeredgewidth=1,\n", - ")\n", - "ax.annotate(\n", - " f\"Source\\n({float(opt[0]):.2f}, {float(opt[1]):.2f})\\nq={float(np.exp(opt[2])):.1f}\",\n", - " xy=(float(opt[0]), float(opt[1])),\n", - " xytext=(10, -20),\n", - " textcoords=\"offset points\",\n", - " fontsize=9,\n", - " color=\"red\",\n", - " fontweight=\"bold\",\n", - " bbox=dict(boxstyle=\"round,pad=0.2\", facecolor=\"white\", alpha=0.8),\n", - ")\n", - "\n", - "ax.set_title(\"Optimized temperature field with sensor locations\")\n", - "ax.set_xlabel(\"x\")\n", - "ax.set_ylabel(\"y\")\n", - "plt.tight_layout()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 7. Modularity: swap a solver, change nothing else\n", - "\n", - "We replace the thermal solver with a coarser version (fewer Jacobi iterations \u2014 faster but less accurate). The optimization code is identical. Only the solver changes." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T11:54:39.366150Z", - "iopub.status.busy": "2026-03-28T11:54:39.366025Z", - "iopub.status.idle": "2026-03-28T11:54:49.359087Z", - "shell.execute_reply": "2026-03-28T11:54:49.358612Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Running L-BFGS-B with swapped (fast) thermal solver...\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Source: (0.674, 0.674)\n", - " Intensity: 2.73\n", - " Objective: 3.169720e-06\n", - " Evaluations: 27\n", - "\n", - " (Original solver found: (0.674, 0.674), q=2.73)\n" - ] - } - ], - "source": [ - "# Swap in a \"fast\" thermal solver (100 vs 500 Jacobi iterations)\n", - "# In practice: point to a different Tesseract image\n", - "original_solve = thermal_api._solve_heat_jacobi\n", - "\n", - "\n", - "def fast_solve(source, conductivity, boundary_temp, n_iters=100):\n", - " return original_solve(source, conductivity, boundary_temp, n_iters=n_iters)\n", - "\n", - "\n", - "thermal_api._solve_heat_jacobi = fast_solve\n", - "\n", - "# Same optimization code, same objective, same grad_fn\n", - "eval_history_swapped = []\n", - "\n", - "\n", - "def objective_and_grad_swapped(x):\n", - " p = jnp.array(x, dtype=jnp.float32)\n", - " obj = coupled_objective(p)\n", - " g = grad_fn(p)\n", - " eval_history_swapped.append(float(obj))\n", - " return float(obj), np.array([float(g[i]) for i in range(3)])\n", - "\n", - "\n", - "print(\"Running L-BFGS-B with swapped (fast) thermal solver...\")\n", - "result_swapped = minimize(\n", - " objective_and_grad_swapped,\n", - " x0,\n", - " method=\"L-BFGS-B\",\n", - " jac=True,\n", - " bounds=bounds,\n", - " options={\"maxiter\": 100},\n", - ")\n", - "print(f\" Source: ({result_swapped.x[0]:.3f}, {result_swapped.x[1]:.3f})\")\n", - "print(f\" Intensity: {np.exp(result_swapped.x[2]):.2f}\")\n", - "print(f\" Objective: {result_swapped.fun:.6e}\")\n", - "print(f\" Evaluations: {len(eval_history_swapped)}\")\n", - "print(\n", - " f\"\\n (Original solver found: ({result_grad.x[0]:.3f}, {result_grad.x[1]:.3f}), q={np.exp(result_grad.x[2]):.2f})\"\n", - ")\n", - "\n", - "thermal_api._solve_heat_jacobi = original_solve # restore" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 8. Implicit differentiation: O(1) memory gradients via the implicit function theorem\n", - "\n", - "The unrolled `lax.scan` approach above stores all intermediate states for backpropagation \u2014 memory scales as O(N) in coupling iterations. For large-scale problems (fine meshes, many iterations), this becomes the bottleneck.\n", - "\n", - "**Implicit differentiation** avoids this entirely. The key insight: at the converged fixed point $(T^*, D^*) = G(T^*, D^*, \\theta)$, the implicit function theorem gives the sensitivity without replaying the iteration. The backward pass solves a single linear system instead of backpropagating through N steps.\n", - "\n", - "Concretely, if $v = \\partial L / \\partial (T^*, D^*)$ is the loss gradient w.r.t. the fixed point, then:\n", - "\n", - "$$\\lambda = (I - \\partial G / \\partial (T, D))^{-T} v$$\n", - "$$\\partial L / \\partial \\theta = \\lambda^T \\cdot \\partial G / \\partial \\theta$$\n", - "\n", - "We solve for $\\lambda$ via fixed-point iteration on the adjoint equation \u2014 the same structure as the forward solve, but linear." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T11:54:49.361002Z", - "iopub.status.busy": "2026-03-28T11:54:49.360882Z", - "iopub.status.idle": "2026-03-28T11:54:49.630737Z", - "shell.execute_reply": "2026-03-28T11:54:49.630348Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Forward pass comparison:\n", - " Unrolled: 6.1757038347e-03\n", - " Implicit: 6.1757038347e-03\n", - " Match: True\n" - ] - } - ], - "source": [ - "def coupled_objective_implicit(params):\n", - " \"\"\"Same inverse problem, but differentiated via the implicit function theorem.\n", - "\n", - " Forward pass: iterate G to convergence (no scan intermediates stored for AD).\n", - " Backward pass: solve adjoint equation (I - dG/d(T,D))^T \u03bb = v via fixed-point iteration.\n", - " \"\"\"\n", - " source_x, source_y, log_intensity = params[0], params[1], params[2]\n", - " intensity = jnp.exp(log_intensity)\n", - "\n", - " def G(temp_disp, params_inner):\n", - " \"\"\"One coupling step: (temp, disp) -> (new_temp, new_disp).\n", - "\n", - " params_inner is (source_x, source_y, intensity) \u2014 the differentiable parameters.\n", - " \"\"\"\n", - " _temp, disp = temp_disp\n", - " sx, sy, q = params_inner\n", - " thermal_out = thermal_api.apply_jit(\n", - " {\n", - " \"source_x\": sx,\n", - " \"source_y\": sy,\n", - " \"source_intensity\": q,\n", - " \"source_width\": jnp.float32(0.15),\n", - " \"displacement\": disp,\n", - " \"conductivity\": 1.0,\n", - " \"boundary_temp\": 0.0,\n", - " }\n", - " )\n", - " structural_out = structural_api.apply_jit(\n", - " {\n", - " \"temperature\": thermal_out[\"temperature\"],\n", - " \"youngs_modulus\": 200.0,\n", - " \"poissons_ratio\": 0.3,\n", - " \"thermal_expansion\": 1e-3,\n", - " }\n", - " )\n", - " return (thermal_out[\"temperature\"], structural_out[\"displacement\"])\n", - "\n", - " @jax.custom_vjp\n", - " def solve_fixed_point(params_inner):\n", - " \"\"\"Run fixed-point iteration to convergence, return the fixed point.\"\"\"\n", - " temp = jnp.zeros((30, 30), dtype=jnp.float32)\n", - " disp = jnp.zeros((30, 30, 2), dtype=jnp.float32)\n", - "\n", - " def step(carry, _):\n", - " return G(carry, params_inner), None\n", - "\n", - " (final_temp, final_disp), _ = jax.lax.scan(\n", - " step, (temp, disp), None, length=N_COUPLING_ITERS\n", - " )\n", - " return (final_temp, final_disp)\n", - "\n", - " def solve_fwd(params_inner):\n", - " fixed_point = solve_fixed_point(params_inner)\n", - " # Save fixed point and params for backward pass (NOT intermediates)\n", - " return fixed_point, (fixed_point, params_inner)\n", - "\n", - " def solve_bwd(res, g):\n", - " \"\"\"Implicit differentiation backward pass.\n", - "\n", - " g = (v_temp, v_disp) \u2014 cotangents w.r.t. the fixed point.\n", - "\n", - " We need to solve: (I - dG/d(T,D))^T \u03bb = v for \u03bb,\n", - " then compute: dL/d\u03b8 = \u03bb^T \u00b7 dG/d\u03b8.\n", - "\n", - " We solve for \u03bb by iterating: \u03bb_{k+1} = v + (dG/d(T,D))^T \u03bb_k.\n", - " This converges if the forward iteration is contractive.\n", - " \"\"\"\n", - " (fixed_temp, fixed_disp), params_inner = res\n", - " v_temp, v_disp = g\n", - "\n", - " # Define G_state: maps (temp, disp) -> (new_temp, new_disp) at fixed params\n", - " def G_state(temp_disp):\n", - " return G(temp_disp, params_inner)\n", - "\n", - " # Solve adjoint: \u03bb = v + (dG/d(T,D))^T \u03bb via fixed-point iteration\n", - " def adjoint_step(lam, _):\n", - " lam_temp, lam_disp = lam\n", - " # Compute (dG/d(T,D))^T @ \u03bb via VJP\n", - " _, vjp_G_state = jax.vjp(G_state, (fixed_temp, fixed_disp))\n", - " dGT_lam = vjp_G_state((lam_temp, lam_disp))[0]\n", - " # \u03bb_{k+1} = v + (dG/d(T,D))^T \u03bb_k\n", - " new_lam_temp = v_temp + dGT_lam[0]\n", - " new_lam_disp = v_disp + dGT_lam[1]\n", - " return (new_lam_temp, new_lam_disp), None\n", - "\n", - " N_ADJOINT_ITERS = 20 # typically converges faster than forward\n", - " lam_init = (v_temp, v_disp)\n", - " (lam_temp, lam_disp), _ = jax.lax.scan(\n", - " adjoint_step, lam_init, None, length=N_ADJOINT_ITERS\n", - " )\n", - "\n", - " # Now compute dL/d\u03b8 = \u03bb^T \u00b7 dG/d\u03b8 via VJP of G w.r.t. params\n", - " def G_params(p):\n", - " return G((fixed_temp, fixed_disp), p)\n", - "\n", - " _, vjp_G_params = jax.vjp(G_params, params_inner)\n", - " grad_params = vjp_G_params((lam_temp, lam_disp))[0]\n", - " return (grad_params,)\n", - "\n", - " solve_fixed_point.defvjp(solve_fwd, solve_bwd)\n", - "\n", - " # --- Use the implicit fixed-point solve ---\n", - " final_temp, _final_disp = solve_fixed_point((source_x, source_y, intensity))\n", - "\n", - " loss = jnp.float32(0.0)\n", - " for (si, sj), target in zip(SENSORS, TARGETS, strict=False):\n", - " loss = loss + (final_temp[si, sj] - target) ** 2\n", - " return loss\n", - "\n", - "\n", - "# Verify forward pass matches the unrolled version\n", - "loss_implicit = coupled_objective_implicit(p0)\n", - "loss_unrolled = coupled_objective(p0)\n", - "print(\"Forward pass comparison:\")\n", - "print(f\" Unrolled: {float(loss_unrolled):.10e}\")\n", - "print(f\" Implicit: {float(loss_implicit):.10e}\")\n", - "print(f\" Match: {jnp.allclose(loss_unrolled, loss_implicit)}\")" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T11:54:49.632754Z", - "iopub.status.busy": "2026-03-28T11:54:49.632521Z", - "iopub.status.idle": "2026-03-28T11:54:51.500992Z", - "shell.execute_reply": "2026-03-28T11:54:51.500423Z" - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - " Unrolled Implicit FD Impl vs FD\n", - "d(loss)/d(source_x) 2.295046e-02 2.295046e-02 2.295244e-02 8.63e-05\n", - "d(loss)/d(source_y) 2.295046e-02 2.295046e-02 2.295244e-02 8.63e-05\n", - "d(loss)/d(log_intensity) 8.693038e-03 8.693038e-03 8.689240e-03 4.37e-04\n" - ] - } - ], - "source": [ - "# Compare gradients: implicit vs unrolled vs finite differences\n", - "grad_implicit = jax.grad(coupled_objective_implicit)(p0)\n", - "grad_unrolled = jax.grad(coupled_objective)(p0)\n", - "\n", - "# Finite differences as ground truth\n", - "eps = 1e-4\n", - "fd_grads_check = []\n", - "for i in range(3):\n", - " p_plus = p0.at[i].add(eps)\n", - " p_minus = p0.at[i].add(-eps)\n", - " fd_grads_check.append(\n", - " (coupled_objective_implicit(p_plus) - coupled_objective_implicit(p_minus))\n", - " / (2 * eps)\n", - " )\n", - "\n", - "names = [\"d(loss)/d(source_x)\", \"d(loss)/d(source_y)\", \"d(loss)/d(log_intensity)\"]\n", - "print(f\"{'':32s} {'Unrolled':>14s} {'Implicit':>14s} {'FD':>14s} {'Impl vs FD':>12s}\")\n", - "for name, u, im, fd in zip(\n", - " names, grad_unrolled, grad_implicit, fd_grads_check, strict=False\n", - "):\n", - " rel_err = abs(float(im) - float(fd)) / (abs(float(fd)) + 1e-30)\n", - " print(\n", - " f\"{name:32s} {float(u):14.6e} {float(im):14.6e} {float(fd):14.6e} {rel_err:12.2e}\"\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Memory scaling: why this matters\n", - "\n", - "With the unrolled approach, JAX stores the full state at every coupling iteration for backpropagation. Memory cost: **O(N \u00d7 state_size)**.\n", - "\n", - "With implicit differentiation, the forward pass runs to convergence and discards intermediates. The backward pass solves the adjoint equation at the fixed point only \u2014 no replay of the iteration. Memory cost: **O(state_size)** regardless of N.\n", - "\n", - "For this 30\u00d730 demo the difference is negligible. For production-scale problems (million-node meshes, hundreds of coupling iterations), it's the difference between \"fits in GPU memory\" and \"doesn't\"." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Summary\n", - "\n", - "| What | How |\n", - "|---|---|\n", - "| Each solver is independent | Separate `tesseract_api.py`, separate container, separate team |\n", - "| Two-way coupling | `jax.lax.scan` over alternating solver calls |\n", - "| End-to-end gradients | `jax.grad` \u2014 JAX handles the chain rule through the coupled iteration |\n", - "| Gradient correctness | Validated against finite differences |\n", - "| Implicit differentiation | `jax.custom_vjp` + adjoint solve for O(1) memory |\n", - "| Solver swapping | Change the Tesseract reference, optimization code unchanged |\n", - "\n", - "### What's next\n", - "\n", - "- **Production deployment**: Build and serve Tesseracts as Docker containers, compose via `tesseract-jax`'s `apply_tesseract`\n", - "- **Scale up**: Larger meshes, more coupling iterations, GPU acceleration" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 9. Production path: composing Tesseracts with `tesseract-jax`\n", - "\n", - "The cells above call `apply_jit` directly \u2014 bypassing the Tesseract runtime for speed. In production, each solver is a containerized Tesseract and you compose them with `tesseract-jax`'s `apply_tesseract`, a JAX primitive that routes to the Tesseract's endpoints. `jax.grad` and `jax.jit` work through it automatically.\n", - "\n", - "**Important pattern**: when using `apply_tesseract` inside `lax.scan`, non-differentiable constants must be passed as **numpy arrays** (`np.float32`), not JAX arrays (`jnp.float32`). Inside a scan, JAX traces all array inputs uniformly \u2014 it can't tell which ones are constants. If a non-differentiable field gets traced, the backward pass will try to differentiate through it and the VJP endpoint will reject the field name. Using `np` arrays keeps them opaque to the tracer." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "execution": { - "iopub.execute_input": "2026-03-28T11:54:51.503944Z", - "iopub.status.busy": "2026-03-28T11:54:51.503790Z", - "iopub.status.idle": "2026-03-28T11:54:52.913846Z", - "shell.execute_reply": "2026-03-28T11:54:52.913414Z" - } - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/dion/.virtualenvs/science/lib/python3.12/site-packages/jax/_src/ops/scatter.py:108: FutureWarning: scatter inputs have incompatible types: cannot safely cast value from dtype=float64 to dtype=float32 with jax_numpy_dtype_promotion=standard. In future JAX releases this will result in an error.\n", - " warnings.warn(\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Forward pass via apply_tesseract matches direct call:\n", - " Temperature max error: 2.24e-07\n", - " Displacement max error: 2.18e-11\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Gradient through single apply_tesseract: d(sum_T)/d(source_x) = 5.726115e+01\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "End-to-end gradient through apply_tesseract + lax.scan:\n", - " apply_tesseract direct\n", - " d(loss)/d(source_x) 2.295040e-02 2.295046e-02\n", - " d(loss)/d(source_y) 2.295040e-02 2.295046e-02\n", - " d(loss)/d(log_intensity) 8.693015e-03 8.693038e-03\n" - ] - } - ], - "source": [ - "from tesseract_jax import apply_tesseract\n", - "\n", - "from tesseract_core.sdk.tesseract import Tesseract\n", - "\n", - "# Load Tesseracts (in-process, no Docker)\n", - "thermal_tess = Tesseract.from_tesseract_api(\"thermal_solver/tesseract_api.py\")\n", - "structural_tess = Tesseract.from_tesseract_api(\"structural_solver/tesseract_api.py\")\n", - "\n", - "# Forward pass through both Tesseracts via apply_tesseract\n", - "thermal_out_tj = apply_tesseract(\n", - " thermal_tess,\n", - " {\n", - " \"source_x\": jnp.float32(0.5),\n", - " \"source_y\": jnp.float32(0.5),\n", - " \"source_intensity\": jnp.float32(10.0),\n", - " \"source_width\": np.float32(0.1), # np: non-differentiable constant\n", - " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", - " \"conductivity\": np.float32(1.0), # np: non-differentiable constant\n", - " \"boundary_temp\": np.float32(0.0), # np: non-differentiable constant\n", - " },\n", - ")\n", - "\n", - "structural_out_tj = apply_tesseract(\n", - " structural_tess,\n", - " {\n", - " \"temperature\": thermal_out_tj[\"temperature\"],\n", - " \"youngs_modulus\": np.float32(200.0), # np: non-differentiable constant\n", - " \"poissons_ratio\": np.float32(0.3), # np: non-differentiable constant\n", - " \"thermal_expansion\": np.float32(1e-3), # np: non-differentiable constant\n", - " },\n", - ")\n", - "\n", - "# Verify: matches direct apply_jit\n", - "print(\"Forward pass via apply_tesseract matches direct call:\")\n", - "print(\n", - " f\" Temperature max error: \"\n", - " f\"{float(jnp.max(jnp.abs(thermal_out_tj['temperature'] - thermal_out['temperature']))):.2e}\"\n", - ")\n", - "print(\n", - " f\" Displacement max error: \"\n", - " f\"{float(jnp.max(jnp.abs(structural_out_tj['displacement'] - structural_out['displacement']))):.2e}\"\n", - ")\n", - "\n", - "\n", - "# Gradient through a single Tesseract call\n", - "def single_thermal_loss(source_x):\n", - " out = apply_tesseract(\n", - " thermal_tess,\n", - " {\n", - " \"source_x\": source_x,\n", - " \"source_y\": jnp.float32(0.5),\n", - " \"source_intensity\": jnp.float32(10.0),\n", - " \"source_width\": np.float32(0.1),\n", - " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", - " \"conductivity\": np.float32(1.0),\n", - " \"boundary_temp\": np.float32(0.0),\n", - " },\n", - " )\n", - " return jnp.sum(out[\"temperature\"])\n", - "\n", - "\n", - "grad_single = jax.grad(single_thermal_loss)(jnp.float32(0.3))\n", - "print(\n", - " f\"\\nGradient through single apply_tesseract: d(sum_T)/d(source_x) = {float(grad_single):.6e}\"\n", - ")\n", - "\n", - "\n", - "# Full coupled pipeline: apply_tesseract + lax.scan + jax.grad\n", - "# Key: non-differentiable constants use np (not jnp) so JAX doesn't trace them\n", - "def coupled_objective_tesseract(params):\n", - " source_x, source_y, log_intensity = params[0], params[1], params[2]\n", - " intensity = jnp.exp(log_intensity)\n", - "\n", - " temp = jnp.zeros((30, 30), dtype=jnp.float32)\n", - " disp = jnp.zeros((30, 30, 2), dtype=jnp.float32)\n", - "\n", - " def coupling_step(carry, _):\n", - " _temp, disp = carry\n", - " thermal_out = apply_tesseract(\n", - " thermal_tess,\n", - " {\n", - " \"source_x\": source_x,\n", - " \"source_y\": source_y,\n", - " \"source_intensity\": intensity,\n", - " \"source_width\": np.float32(0.15),\n", - " \"displacement\": disp,\n", - " \"conductivity\": np.float32(1.0),\n", - " \"boundary_temp\": np.float32(0.0),\n", - " },\n", - " )\n", - " structural_out = apply_tesseract(\n", - " structural_tess,\n", - " {\n", - " \"temperature\": thermal_out[\"temperature\"],\n", - " \"youngs_modulus\": np.float32(200.0),\n", - " \"poissons_ratio\": np.float32(0.3),\n", - " \"thermal_expansion\": np.float32(1e-3),\n", - " },\n", - " )\n", - " return (thermal_out[\"temperature\"], structural_out[\"displacement\"]), None\n", - "\n", - " (final_temp, _), _ = jax.lax.scan(\n", - " coupling_step, (temp, disp), None, length=N_COUPLING_ITERS\n", - " )\n", - "\n", - " loss = jnp.float32(0.0)\n", - " for (si, sj), target in zip(SENSORS, TARGETS, strict=False):\n", - " loss = loss + (final_temp[si, sj] - target) ** 2\n", - " return loss\n", - "\n", - "\n", - "# End-to-end gradient through apply_tesseract + lax.scan\n", - "grad_tess = jax.grad(coupled_objective_tesseract)(p0)\n", - "grad_direct = jax.grad(coupled_objective)(p0)\n", - "\n", - "print(\"\\nEnd-to-end gradient through apply_tesseract + lax.scan:\")\n", - "print(f\" {'':32s} {'apply_tesseract':>16s} {'direct':>16s}\")\n", - "for name, gt, gd in zip(names, grad_tess, grad_direct, strict=False):\n", - " print(f\" {name:32s} {float(gt):16.6e} {float(gd):16.6e}\")" - ] - } - ], - "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.12.7" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/demo/multiphysics-optimization/demo.ipynb b/demo/multiphysics-optimization/demo.ipynb index b4a81175c..910cf78f5 100644 --- a/demo/multiphysics-optimization/demo.ipynb +++ b/demo/multiphysics-optimization/demo.ipynb @@ -2,26 +2,49 @@ "cells": [ { "cell_type": "markdown", + "id": "1313879b", "metadata": {}, "source": [ "# Multi-Physics Pipeline with End-to-End Gradient Optimization\n", "\n", - "This demo shows how to compose two physics solvers from different domains \u2014 thermal and structural \u2014 into a coupled pipeline, and solve a design inverse problem with **end-to-end gradients flowing automatically through the full chain**.\n", + "In this tutorial, you will learn how to:\n", "\n", - "Each solver is an independent Tesseract. The pipeline uses two-way (partitioned) coupling: the thermal solver produces a temperature field that causes thermal strain in the structural solver, and the resulting displacement feeds back to the thermal solver by deforming the geometry. Gradients propagate through this coupled iteration via JAX's automatic differentiation.\n", + "1. Build two independent physics Tesseracts from different domains -- a thermal solver and a structural solver.\n", + "2. Compose them into a two-way coupled pipeline with Tesseract-JAX, where each solver feeds back into the other.\n", + "3. Compute end-to-end gradients through the coupled iteration with `jax.grad`, and validate them against finite differences.\n", + "4. Perform gradient-based optimization of a thermoelastic inverse-design problem using `scipy.optimize`.\n", + "5. Switch to implicit differentiation for constant-memory gradients via the implicit function theorem.\n", "\n", - "## What we demonstrate\n", + "## Context\n", "\n", - "1. **Two independent Tesseracts** \u2014 each team keeps their solver, their AD strategy, their dependencies\n", - "2. **Two-way coupling** via `jax.lax.scan` \u2014 not a toy feedforward chain, but the real partitioned coupling pattern used in practice\n", - "3. **End-to-end gradients** \u2014 `jax.grad` through the coupled iteration, validated against finite differences\n", - "4. **Gradient-based optimization beats gradient-free** \u2014 fewer evaluations for a 3-parameter design problem\n", - "5. **Solver swapping** \u2014 change one Tesseract, optimization code stays the same" + "Many engineering systems are *multi-physics*: their behaviour emerges from the interaction of several physical processes, each usually modelled by its own specialized solver. A classic example is *thermoelasticity* -- a temperature field makes a material expand, the resulting deformation changes the geometry, and the changed geometry in turn changes how heat flows. Neither solver is correct on its own; the answer lives in the coupling between them.\n", + "\n", + "Designing such systems means solving inverse problems through the coupled physics: *what inputs produce the behaviour we want, once everything has settled into equilibrium?* Answering that efficiently requires gradients through the full coupled chain. Traditionally this means either a fragile hand-coded adjoint or rewriting every solver into one monolithic codebase.\n", + "\n", + "Tesseracts offer a different path, and that is what this demo shows:\n", + "\n", + "- **Separation of solvers** --- each physics component is its own Tesseract, with its own implementation, dependencies, and AD strategy. Teams can develop and ship them independently.\n", + "- **Composition with autodiff** --- because each Tesseract exposes its derivatives, Tesseract-JAX wires them into a single differentiable pipeline. `jax.grad` then propagates gradients through the entire two-way coupling automatically --- no manual adjoint, no monolithic rewrite.\n", + "- **JAX interoperability** --- the coupled iteration is expressed with `jax.lax.scan`, and standard JAX and optimization tooling applies directly to the composed pipeline.\n", + "\n", + "We demonstrate this on a thermoelastic inverse-design problem: find the heat-source location and intensity that produce a set of target temperatures, *after* the thermal and structural solvers have reached a coupled equilibrium." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "06fd4954", + "metadata": {}, + "outputs": [], + "source": [ + "# Install additional requirements for this notebook\n", + "%pip install -r requirements.txt -q" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, + "id": "5bb76f54", "metadata": {}, "outputs": [], "source": [ @@ -30,312 +53,222 @@ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "from scipy.optimize import minimize\n", + "from tesseract_jax import apply_tesseract\n", + "\n", + "from tesseract_core import Tesseract\n", "\n", "jax.config.update(\"jax_enable_x64\", True)" ] }, { "cell_type": "markdown", + "id": "d5f9d3bd", "metadata": {}, "source": [ - "#", - "#", - " ", - "1", - ".", - " ", - "L", - "o", - "a", - "d", - " ", - "t", - "h", - "e", - " ", - "s", - "o", - "l", - "v", - "e", - "r", - "s", - "\n", - "\n", - "E", - "a", - "c", - "h", - " ", - "s", - "o", - "l", - "v", - "e", - "r", - " ", - "i", - "s", - " ", - "a", - " ", - "s", - "t", - "a", - "n", - "d", - "a", - "l", - "o", - "n", - "e", - " ", - "T", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - " ", - "m", - "o", - "d", - "u", - "l", - "e", - " ", - "w", - "i", - "t", - "h", - " ", - "i", - "t", - "s", - " ", - "o", - "w", - "n", - " ", - "`", - "t", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - "_", - "a", - "p", - "i", - ".", - "p", - "y", - "`", - ".", - " ", - "I", - "n", - " ", - "p", - "r", - "o", - "d", - "u", - "c", - "t", - "i", - "o", - "n", - ",", - " ", - "t", - "h", - "e", - "s", - "e", - " ", - "w", - "o", - "u", - "l", - "d", - " ", - "b", - "e", - " ", - "c", - "o", - "n", - "t", - "a", - "i", - "n", - "e", - "r", - "i", - "z", - "e", - "d", - " ", - "i", - "m", - "a", - "g", - "e", - "s", - " ", - "c", - "o", - "m", - "p", - "o", - "s", - "e", - "d", - " ", - "v", - "i", - "a", - " ", - "`", - "t", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - "-", - "j", - "a", - "x", - "`", - "'", - "s", - " ", - "`", - "a", - "p", - "p", - "l", - "y", - "_", - "t", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - "`", - ".", - " ", - "H", - "e", - "r", - "e", - " ", - "w", - "e", - " ", - "i", - "m", - "p", - "o", - "r", - "t", - " ", - "t", - "h", - "e", - "m", - " ", - "d", - "i", - "r", - "e", - "c", - "t", - "l", - "y", - " ", - "f", - "o", - "r", - " ", - "s", - "p", - "e", - "e", - "d", - "." + "## Step 1: Build and serve the solver Tesseracts\n", + "\n", + "Each solver is a standalone Tesseract module with its own `tesseract_api.py`:\n", + "\n", + "- **`thermal_solver`** solves the 2D steady-state heat equation for a Gaussian heat source. When a displacement field is supplied (from the structural solver), it deforms the mesh accordingly --- this is what makes the coupling two-way.\n", + "- **`structural_solver`** solves 2D linear thermoelasticity: given a temperature field, it returns the displacement and stress fields produced by thermal expansion.\n", + "\n", + "We use the `tesseract build` CLI to build each module into a container image. Building can take a few minutes the first time, as the images bundle their dependencies." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, + "id": "e7cbfe3c", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[?25l\u001b[37m⠋\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠙\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠹\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K \u001b[1;2m[\u001b[0m\u001b[34mi\u001b[0m\u001b[1;2m]\u001b[0m Building image \u001b[33m...\u001b[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[37m⠹\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠸\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠼\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠴\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠦\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠧\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠇\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠏\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠋\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠙\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠹\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠸\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠼\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠴\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠦\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠦\u001b[0m \u001b[37mProcessing\u001b[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[?25h\r", + "\u001b[1A\u001b[2K \u001b[1;2m[\u001b[0m\u001b[34mi\u001b[0m\u001b[1;2m]\u001b[0m Built image sh\u001b[1;92ma256:628f\u001b[0m2f2ce6f1, \u001b[1m[\u001b[0m\u001b[32m'thermal-solver:0.1.0'\u001b[0m, \u001b[32m'thermal-solver:latest'\u001b[0m\u001b[1m]\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[\"thermal-solver:0.1.0\", \"thermal-solver:latest\"]\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[?25l\u001b[37m⠋\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K \u001b[1;2m[\u001b[0m\u001b[34mi\u001b[0m\u001b[1;2m]\u001b[0m Building image \u001b[33m...\u001b[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[37m⠋\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠙\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠹\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠸\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠼\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠴\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠦\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠧\u001b[0m \u001b[37mProcessing\u001b[0m\r", + "\u001b[2K\u001b[37m⠇\u001b[0m \u001b[37mProcessing\u001b[0m\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\u001b[?25h\r", + "\u001b[1A\u001b[2K \u001b[1;2m[\u001b[0m\u001b[34mi\u001b[0m\u001b[1;2m]\u001b[0m Built image sh\u001b[1;92ma256:36ae\u001b[0mc53ccce6, \u001b[1m[\u001b[0m\u001b[32m'structural-solver:0.1.0'\u001b[0m, \u001b[32m'structural-solver:latest'\u001b[0m\u001b[1m]\u001b[0m\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[\"structural-solver:0.1.0\", \"structural-solver:latest\"]\n" + ] + } + ], "source": [ - "import sys\n", - "\n", - "sys.path.insert(0, \".\")\n", + "%%bash\n", + "# Build both solver Tesseracts into container images\n", + "tesseract build thermal_solver/\n", + "tesseract build structural_solver/" + ] + }, + { + "cell_type": "markdown", + "id": "382df23c", + "metadata": {}, + "source": [ + "Next we load the built images and start a server for each one using the Tesseract Python SDK. This gives us two running Tesseract instances we can call from Python. We keep references to both so we can compose them in the following steps." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "5b94d0e0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Thermal solver: 2D steady-state heat equation solver with Gaussian source parameterization\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Structural solver: 2D linear thermoelastic stress solver with compliance objective\n" + ] + } + ], + "source": [ + "# Load the built images and start a server for each Tesseract\n", + "thermal = Tesseract.from_image(\"thermal-solver\")\n", + "structural = Tesseract.from_image(\"structural-solver\")\n", "\n", - "import structural_solver.tesseract_api as structural_api\n", - "import thermal_solver.tesseract_api as thermal_api\n", + "thermal.serve()\n", + "structural.serve()\n", "\n", - "print(\"Thermal solver loaded:\", thermal_api.__doc__.strip().split(\"\\n\")[0])\n", - "print(\"Structural solver loaded:\", structural_api.__doc__.strip().split(\"\\n\")[0])" + "print(\"Thermal solver:\", thermal.openapi_schema[\"info\"][\"description\"])\n", + "print(\"Structural solver:\", structural.openapi_schema[\"info\"][\"description\"])" ] }, { "cell_type": "markdown", + "id": "d357b55e", "metadata": {}, "source": [ - "## 2. Forward pass: single-shot thermal \u2192 structural\n", + "## Step 2: Test a forward evaluation with Tesseract-JAX\n", + "\n", + "Before coupling the solvers, let's verify each one works and visualize the physics. The `apply_tesseract` function from [tesseract-jax](https://github.com/pasteurlabs/tesseract-jax) makes a served Tesseract callable as a JAX-compatible function -- which is what later lets us differentiate through it.\n", "\n", - "Before coupling, let's verify each solver works independently and visualize the physics." + "We run the thermal solver for a centered heat source, then feed its temperature field into the structural solver to obtain the resulting displacement and stress." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, + "id": "eb352133", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABWMAAAGPCAYAAAA5ncKaAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjksIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvJkbTWQAAAAlwSFlzAAAPYQAAD2EBqD+naQAAnnFJREFUeJzt3QmYFNW5+P+3umdHGDYFQRAXIioICkJAE/SGiJEYyaLEeAXRkGsibiRERQUTkqBRuPiPRIIJan5XhZhEYtTgVSIaAwbZrhq3uAGibCIMzMBMT1f9n7dI9/QMPcw5XV0z0z3fT56KdM1b1dXVVedUnT71HsfzPE8AAAAAAAAAAKGKhLt6AAAAAAAAAICiMRYAAAAAAAAAmgGNsQAAAAAAAADQDGiMBQAAAAAAAIBmQGMsAAAAAAAAADQDGmMBAAAAAAAAoBnQGAsAAAAAAAAAzYDGWAAAAAAAAABoBjTGAgAAAAAAAEAzoDEWAAAAAAAAAJoBjbEAAAAA2oQXXnhBzj//fOnRo4c4jiNLliwJ/T03b94s//mf/yldunSR0tJSGTBggKxevTr09wUAAK0TjbEAAAAA2oTKykoZOHCgzJs3r1ne79NPP5UzzjhDCgsL5S9/+Yu8/vrrMnv2bOnUqVOzvD8AAGh9HM/zvJbeCAAAAABoTtoz9rHHHpOxY8cm51VXV8vNN98sjzzyiOzatUv69+8vd9xxh5x11lkZvceNN94of//73+Vvf/tbFrccAADkMnrGAgAAAICITJ48WVauXCmLFi2SV155RS688EI599xz5V//+ldG++fxxx+XIUOG+Os54ogj5NRTT5X77ruPfQ0AQBtGz1gAAAAA0tZ7xm7cuFGOPfZY/7+aUzZh1KhRMnToUPnZz35m/R4lJSX+f6dMmeI3yL788sty7bXXyvz582XChAlZ/DQAACBXFLT0BgAAAABAS3v11VclHo/LZz7zmXrzNXWBDr6l3nzzTTnxxBMPuZ4bbrhBbr/9dv/fruv6PWMTDbnaM/a1116jMRYAgDaMNAVAHrnzzjv9Hh3RaFQGDRrkz+vTp49cdtllGfcYue2225qM0xiNBYBcEHaZpWWulr1o2x544AH/OPvggw+a5f2C1Pc4YO/evf411Jo1a2T9+vXJ6Y033pC7777bj9HrLH19qOn73/9+cpceeeSRctJJJ9XbxdqYq71vAeQX03snAKAxFvUqD5Np+fLlbXav/fKXv/Rvrlqj//3f/5Uf/vCH/oi9999/f0aP0gFArjZ4JSZ9JFgfLx49erT8f//f/yd79uxp6U1EiqeeeqpN36i25usIHOi1qj1jt23bJscff3y9qXv37v4uKioqkn79+h1yOvzww5O7U6/L3nrrrXq79+2335ajjz6aXY427ytf+YqUlZUdsq6+5JJL/PPuk08+afbrihdffPGgv+v457169fL//uUvf1nywcMPPyxz585t6c0A2hTSFCDp//2//1dvb/z2t7+VZ5555qD5TT2ale83UV27dm2VPU/++te/SiQSkd/85jf+BUuC3gDofADIZz/+8Y/lmGOOkVgsJlu2bPF/OLzuuutkzpw5/gA6p5xySjL2lltu8Uc4R8s0xs6bN69NNMheeuml8s1vflOKi4tz4jqiLfV+feedd5Kv33//fb/3a+fOnf30BNrwM378eJk9e7bfOLt9+3ZZtmyZX4aMGTPG+v2uv/56GTFihP8j+UUXXSSrVq2SBQsW+BPQ1un59uc//9nP3aznXUNVVVXypz/9yR9EL5EqpLnoj7vaSHnmmWfWm//888/Lhx9+WK9sT9i3b58UFOReE4t+Tk2fotdNAJpH7pUUCM1//ud/1nv90ksv+Y2xDefnC/1Vc//+/VJaWpoX26G9OHQdqQ2xKt2FAgDkmy996Ut+XsaEm266yf+RSnutaM8bfXQ4Uc7qjVIu3iwht+jj7jqhdVm9erWcffbZydc6sJbSwbS0R5w+XfSTn/zETzWwefNmv/H8s5/9bMY94E4//XS/oUnLpMSPRtoDTRuhgLZO6+f27dv7jYHpGmO1IbaysrJFzpfzzjtPHn30Uf8pm9RrBt3WwYMHy44dOxodsC+f6X2r3m/S2QcIhu5ysKKDEOgF5Mknn+xXNt26dZP/+q//kk8//fSgvGV60ao9k/TmWG+ABwwYkExx8Mc//tF/revQymzdunX1ltceI4cddpi89957/qOm7dq18x871YtYbbwMsk1PP/10cpt+9atf+X/TC+//+I//kCOOOMJvvNTcXvfee+9By//zn//0fw1NPLpy1llnHTL/YLp8cYfajl27dvm/SOqjL7od+ljcHXfc4X/GQ9H30M+gFyuJbUs8Bpkuh1ym76P0cR29sdB9fdxxxyW3HQBa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b1//+tet9ztaN8+L+1Omgizb6nhAI6666iq9Qjxo/oIFC7zBgwd7paWlXvv27b0BAwZ4P/zhD72PPvooGXP00Ud7Y8aMOWhZXZ+uN9X777/vz7/zzjuT8yZMmOC1a9fOe/fdd71zzjnHKysr87p16+bNmDHDi8fjWd0m9fjjj3unnHKKV1JS4vXp08e74447vIULF/rbpduXsGXLFn8d+h76t5EjRyb/tmbNGm/YsGFeUVGR17t3b2/OnDne/ffff9A6DrUde/bs8W666Sbv+OOP99fTtWtXb8SIEd5dd93l1dTUpF2m4T5rSN9P/5bJ++i26z5P9fzzz/v7Wpc79thjvfnz5/sxFCe5bffu3f53uHv3Zj1CMpp02QPr2N3SHwdtSKKcTUxaNnXv3t374he/6N19991eRUXFQcs0LLOWLVvmXXDBBV6PHj385fW/F198sff2228nY5577jl/mUceecQvP4844gi/ztHyfMOGDfXWr2Wulr2pfvOb33h9+/b1iouLvX79+vnb3VjZqfXPqaee6sd26tTJr2ueeeaZejG6PaNHj/bKy8v9uuu4447zLrvsMm/16tVN1gu6vpNPPvmg+enqJ5P6Il093lg9Ultb61199dXe4Ycf7jmO02TdEfR64sMPP/S++tWveh07dvT31YUXXuhfG6Sr3/Q40P2un1P3569//Wvv+9//vr9/m3rvdPVtumuAbFxH6HXQj370I+/II4/0j8GzzjrLe+211wLV98isztzyVm+v6qM+GU+6fKb15t69e5PXuRdddJF33nnn8TUi582bN88/J4YOHZr273pv+I1vfMMv07Vs1rgnnniiXkyivn700UfT1hFarh5Kotx9+eWXreun1Lqlurramzp1qjdw4EC/zNf6WP/9y1/+8qB1rVu3zvva177mdenSxa/7dd16Xmu9ZLuuVKbLaXnyrW99y9+v+hkS1zCN7ctsbvd7773nXX755X69q99p586dvbPPPtt79tlnD/nZkJv15rZP7vb2xxZkPOny+XK/6ej/tXSDMNCQ9uDQXhvpHnsAkH36iJA+Grl794ZAA3iVlx/tP45E3lnkm+XLl8vZZ5/tP3WRzadA0Lpp6oh//vOfafOlo+1K1JkfvXVU4AG8epzwYaB6U3MFa49C7QH+ne98J+NtAQAg7Hpzy47ZgQfw6t71+3lxv0ma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ZuoolQMHDvTz8mzbti1tfFVVlV/h3X777Y1Wis8//7xcddVV8tJLL8kzzzwjsVhMzjnnHKmsNB9BFQAA0zQFQSYAANqMLA3g1aFDh3pTwxQFqqioSAYPHizLli2re3vX9V8PHz487ebp/NR4pfeTjcWrDz/80M8Ze+SRR4bfGGvTi0lpzyVNbFtaWup3J77++utl//79mbw1ACCPGmNtR7jUHq933nmn/3hIukpXLV26VC677DI5+eST/cbdBx54QDZu3OgncG8p1JsAkH9ciQSecDDqTADIU1lqjDWlnX7uu+8+efDBB+WNN97wB9vSDjp676nGjx9fr1fttdde699Lzp49288rq6kPVq9eLZMnT/b/vnfvXpk6darf6eeDDz7wG24vuOACOf744/0ORTYKMu3FpDfM2hCrDa36pvoIqD4O2tDDDz8sN954o39jPWLECHn77bf9m2R9vFRvwgEA+ZUz1iSheuoIl6kVYFMjXGZCH11RnTt3lpZAvQkA+SnuOf4UZHnUR50JAHk+fleAnLGe5bLjxo2T7du3y/Tp0/1BuAYNGuQ3tiYG6dIOO3r/maBtltqGecstt/gDc/Xt21eWLFki/fv39/+uaQ9eeeUVv3F3165d0qNHD/8JzJkzZzbaUShrjbGpvZiUNso++eSTfmOrNro2tGLFCjnjjDPkW9/6lv9ae9RefPHF8o9//MP2rQEAOcA0oXomI1za0kdRrrvuOr8eSlSizY16EwAA6kwAQPObPHlysmdrQzroVkMXXnihP6WjT/s//fTTWdkuq2djEr2YtNeSaS8mbVnWZRKpDN577z156qmn5Lzzzgu67QCArIsHSFEQN06o3lw0d+xrr70mixYtapH3p94EgPxFztjsos4EgDzXzGkKWjOrnrGZ9GLSHrG63Jlnnime50ltba1ceeWVfpffxlRXV/tTQuKR16hh63Gh8ScSKbOIbWcY19FinV0sYg/PsdjOIcSWhvXl2qzXRswitso8dJ/hendavL1N7HaL2BKLWD3Hw+CG8JXZZL2uzPI+CPehRm1Q9QLt6UQi9aZkMsKlDf0F9IknnpAXXnhBjjrqKGkJzVFvNlZnegUF4kWbruZrS83PvJhpRaixhxnGdTjQiG+isLzuczbliI57jWOPar/LOPboMvPSsnfxJ8axPQs/NY7tUWAW2yVivr/aR8xLlmInnDyX1RbPnu2Jmn+/nxQcSFXSlC4F5ussLzCvtNsXmNcYJQXmFw4FEfP9lX5IxPRicfNjIVJtdisRM9+1VmWSV2j2/l7cvJyx4XkRcb1IoOVt6BOGGzZsOGj+9773PT/Paq5r8XtNp0gcp+njz7W6wDcXccxuSAoj5jc5pZFy49h2nnlse7e9cexhYv7obruo+U3ZYVHz86e0wKxcK7I4JQstYqMhXbzHLS7ZYxY3RDWuWTm8r9a8OWlv3Py7rbSILfLMY/dELJq/LL5fz+Ju0w3yjH4zljPevzvZZJ1+/CC7wJW8EXrWeO32+7Of/Ux++ctf+iNl//GPf/TTGmhOhcbMmjVLysvLk1PDR14BALk/gFcmI1ya0JsxbYh97LHH5K9//ascc8wxkkts603qTABoGXFxAk82Xn75Zfn444+Tk47wrBp7nLIt4F4TAHKIm4WpLfaMzaQX06233iqXXnqpfPvb3/ZfDxgwwB+97Dvf+Y7cfPPN9ZLlJugjrTpIWOqvlTTIAkD+0bJ+woQJMmTIEBk6dKg/KGTDES579uzpNzgmHmF8/fXXk//evHmzrF+/Xg477DB/FMtEagJNvP6nP/1J2rdv7ydrV/rjnub5aU7NUW9SZwJA23D44fWfUbv99tvluOOOk5EjR0o+4F4TANBWRMLuxVRVVXXQjaPemCZ6L6Wjo5AlHnM1fdwVAJBbPWMTI1zedddd/giXOrqlNqw2HOFSe/8kfPTRR3Lqqaf6k87XZfXfiYZLde+99/q5as866yw58sgjk5OO0NzcmqPepM4EgJZxIH2dE2Cq63iSOqU+Qt8Y/UHyf/7nf+Tyyy8Xxwk3gVFz4V4TAPKcl4WpLfaMzaQX0/nnn++PJK03y8OGDZN33nnH7/Wj8xM3lwCA1qI2QAYbN/QRLjVfXmM/5CU09ffmRr0JAPnJDZgzNrFswycAZ8yYIbfddtshl12yZIns2rVLLrvsMskn1JkAkL881/GnTLVwyt2WbYzVXkzbt2/3ezHpo5/ak6lhL6bUHj233HKL/2ut/lcfJ9XHa7Qh9qc//Wl2PwkAAK0Q9SYA4FA2bdpU70lAfeKhKb/5zW/kS1/6kvTo0SOvdi51JgCgLXC81taFKA19XEdz/Wl2PZPfnjtbrLt+5qVD6xLCOvM5tnMIsaXmgyWKmA80KmKzXhs2g62aD8ws+wzXaz7mt13sdmLlk5D2l8n3oD8IahZUfRQ/W2lcEuXs7t2aGiazXysrKjwpL6/I6nYh8+/yC8dfJwXRpm/oKz9jWruJ7Oll/kRLVXez46j6cPP0FoWdzUelP6Kj+fDtR7XfZRx7dJl5adm72Lyk6Fn4qXFsjwKz2C6Rph91TmgfMT/vi51wxn+ttujusCfxfLeBT1yzkbw/qu1kvM7NMfPYjdXm59iGKvOrpw/3dDSO3bbrMOPY2M4S49ji7Wb9Osq2mH9f7TeZj+Dc7m2zc6w2Xi3L3pmbtfopUc5e+tzFUnRYUcbrqdlbI//v7Eest2vDhg1y7LHH+gM8XnDBBRm/P+p/n2VFx4njNF3PuZ7NBX72Rzkvjpqfz2UR87KqnVduHNvebW8ce5gUm29D1Pym7LCoeV1UWmBWxxVZVG+FFrHRkDKJxC1acmIWPQprDGP31ZpvwN64+QZUxs3Psb1ifq2zJ7LHfBuc3caxVa75NVx13Oz6tKXLGc+LS1XNu1mvN3fcUSQdSjM/ISr2edL1hpq8uN+07hkLAMhn2jCWaQXZ6n/bAwAga+Ke409Bls/E/fffL0cccYSMGTMm4/cGAKDZab0XIE2B5NHtJo2xAIAUNMYCANCcOWOtlnFdvzFWx/AoKOBWDgCQO8gZWyec58wAAAAAAFn17LPP+mN0XH755exZAAByFD+nAgBS0DMWAAATrjjiBkhToMvbOueccyQHhvwAAOBgbsA0BW7+7NSCXOvGG8nyWEwlIYwHZZ7OPLzBxmzGVe1mEdvTIrbdYSF8OPMxMOy+iNYwgJd5PnEpNRwTpqfFyFEWY91YpOEPb9eaD+8hYj7kj0hlluNs90GLP66gA+hkeo/HvWHrUlggEm26mo+XmF8Q1ZZZxB5mdrUU6WBeUHbuUBXKoFzHlu0wju1TYh7bu9B8AK/u0Qrj2M5Rs31WHjEfcK3MMR+EqNBggJtMxDzzkr3YqTGOLXTMBvcoshiascQxP24LHfPPFQ3pLqPWNa9dtteaf7+1+8zWW1tm/v42ZZJfzpmI2Fw1mPO0MTbjPOsHlkfrEXUKjAbwCktBxOwKu9ApNV5nidculEG5yi22oWOB+ZVweZH5OdHB4gK7fYFZ2VpqGKeKI+YXvgWRli/bqy0awPbVmq13j2GcqoiZn1u7a8zXG7XYBpsqNh4xH2A25pjfbcYjZtcPtW545VyL1k/6A2aAHzElj+43W/y+HwAAAAAAAADagpzqGQsACJn+CpvpL7F59NgIAABN0RQFgdIUBOkdBABAjmEArzo0xgIA6uiTnJk+zRnOU6AAALRKrhfxpyDLAwDQZmhqjUA5Yz3JFzTGAgDq0BgLAIAResYCAGCBAbyS+DkWAAAAAAAAAJoBPWMBAHXIGQsAgBFXHH/KVJBlAQDINZ7n+FOmvPzJUkBjLAAgBWkKAAAwQpoCAAAskDM2iZ6xAIA69IwFAMAIjbEAAJjzXJ0C9IzNowG8yBkLAAAAAAAAAM2AnrEAgPo9YzVVQabLAgDQRtAzFgAAC5ovNkDPWAmQb7a1yanG2KhhV94ii3WWWMS2M4wrt1hnR4vYwy1iu1nE9rGILbJZca8QYm12QnlIB4KN/Raxuy1itxvGbTJfZTuL2D5bJRSxkHZtpUXsnizH2ZZJWs41JdQqiJyxecMrjIoXbfqIqi02P6JqS83fP97OrHW+/WHmZ3P3duZn3tFlO41j+5TsMI7tXfiJcWz3aIVxbHnEvAQsc8y+s6hFaeFa/JoSC+kJMZttsPlspvsrbvEdiJh/t2GJWzzgtr+20Di2qsY8ds9es9jaUvNttSmTtJwziouYxdmiMTa/FERKxHEMjhXXvN7yLMq1AqfYKK7IKTNeZ5l7mHHsYWL2/qpjgXk50cXinO5cbF7BdCmqNY7tWGRWvncoqjFeZ2mBeZ1RGMm0p8OhxVzzsm2fRT1QUWN297LLor4oiZo3PRUY1tsHmG9DPGZ+PtZ45udOdWSfcWytU20U5zrmx5djcT2g5ZwJz4u30gG8HMkXpCkAAAAAAAAAgGaQUz1jAQAhYwAvAACMaB8+N8DzKvkzDAkAAAbcyIEpU3mUFo/GWABAHdIUAABghDQFAACY81zHnzIVZNnWhsZYAEAdGmMBADBCYywAAObIGVuHnLEAAAAAAAAA0AzoGQsAqEPOWAAAjNAzFgAAC+SMTaIxFgBQhzQFAAAYoTEWAABz5IytQ5oCAAAAAAAAAGgG9IwFANTx/p2qINNlAQBoIxiIBAAA6s1M0BgLAKhDmgIAAIy44vhTpoIsCwBAziFnbG42xkYN8yoUWqzTJrbMMK6DxTrLLWIPt4jtaRFb1M0iuK9F7LEhxPYIaYe1k3BUWsRut4j9yDCuvcU6S8xDiyxW23OreWy1xXorLGL3hHCeh1XOaDnXlFBv3WiMzRteYUS8aNNHVLzY/IiKl5p3f3bKao3iOpftM15nj7LdxrG9iz8xjy00j+0eNS992kdixrGFFif2fs/se6jyzL4DFbOIbQ1s9lckhHXafLd2NZa5mGdSYxywp8y8kt9VXWocu7fMLDZear6tNmWSV2i2Xi8STmY2csbmF8cpkIjT9DEVccyv7DyLx42ihust9szP0VKv2Di2XdT8c5UXmZ+nnYvNrx26l5iXrUeUmF8/dC2rMorrVLbXeJ1lpebvX1hoU2eYi8XMv7OqfebHzadVhxnFtasyvXMSKYyUhnL3VOuZH4v7XfP17oubnztVFudktWN2jNmUM45F9tGIU9CiPxaSM7YOOWMBAAAAAAAAoBnkVM9YAEDI3AA5YzNdDgCAHETOWAAAqDczQWMsAKAOaQoAADBCmgIAACx4kQN5YzOVRwNGk6YAAAAAAAAAAJoBPWMBAHXoGQsAgBHSFAAAYI4BvOrQGAsAqEPOWAAAjBtjNVVBkOUBAGgrPC9Y3eeRpgAAkLeNsfEMpwwH8Jo3b5706dNHSkpKZNiwYbJq1apGY//5z3/K17/+dT/ecRyZO3du4HUCAJAJL3ljmeGUwXtu3rxZ/vM//1O6dOkipaWlMmDAAFm9ejVfIACg9XOdZO9YL4NJl88X5IwFALSYxYsXy5QpU2TGjBmydu1aGThwoIwePVq2bduWNr6qqkqOPfZYuf3226V79+5ZWScAALng008/lTPOOEMKCwvlL3/5i7z++usye/Zs6dSpU0tvGgAAsEBjLADg4DQFmU6W5syZI5MmTZKJEyfKSSedJPPnz5eysjJZuHBh2vjTTz9d7rzzTvnmN78pxcXFWVknAACZcMUJPNm44447pFevXnL//ffL0KFD5ZhjjpFzzjlHjjvuOL5AAECr53mRwFO+yJ9PAgAILtMUBRkM/FVTUyNr1qyRUaNGJedFIhH/9cqVKzPa/DDWCQDAoQbwCjKpioqKelN1dXXa93v88cdlyJAhcuGFF8oRRxwhp556qtx33318OQCA3JBINeAGmPJEXg7gFbWILbGIbWcYV2axzo4WsZ0tYtsdZhHcyyL2WIvYkyxiTwjh/XtYxHaQcFRYxH5kEfteCAe4jf3moe0qzWM77zWP/cQ8VHaGcJ6XhFQmtbgMGlXrLfvvm8pU2oM1XS/WHTt2SDwel27dutWbr6/ffPPNjDYhjHXmKjcaEbeg6d9c40Xm64wXm2c4LC6NGcV1LjEvJI4q/tQ4tmeheWz3qHlhXR4x+1yq0OJ6sdoieeQu1+xL+yRuWqKJ7IybXzhUuul7pQfVLpK+ASqdzlHzCqNL1OwY6xipMV5nscV3G7E4ZmwuHPYXFhrH7i42vzrdUtLeOHZrqVlsrNi8oIkXme9ckzLOjwup/4kO3uUEGIgkMfiX9nZNpWl2brvttoPi33vvPbn33nv9VDzTpk2Tl19+Wa655hopKiqSCRMmZLwdOKBQiiVicHvsOrXGu8y1KNujYnZOF4r5+VRsuE51WNT8POlgvlrpUmS+v44o2Wcc27PDbuPYwzuaXRN07Gx+7VDaaY9xbLTEvH6zEd9vXh/v+9S8bG+30yz1SfGucFKkxCwa3PbHzQ/Gypj5Mb7HYr0256Tpee5Y1FsRx/xus9DwLtYV8/PWRuoPkW194Mu8bIwFALQc05tKAAAgsmnTJunQoa5nQGNpeFzX9XvG/uxnP/Nfa8/Y1157zU/HQ2MsAAC5g8ZYAECdDHO/Jpe1uKns2rWrRKNR2bp1a735+rqxwbmaEsY6AQBIx/MOTJlKLKt1Zmq92ZgjjzzSz4We6sQTT5Q//OEPfEEAgFbPcx1/ylSQZVsbcsYCALKaMzZxU5mYGmuM1ccqBw8eLMuWLavX60dfDx8+PKNvJYx1AgAQZs5YU2eccYa89dZb9ea9/fbbcvTRR/MFAQBavZYYwGvevHnSp08fKSkpkWHDhsmqVasOGf/oo49Kv379/PgBAwbIU0891WjslVdeKY7jyNy5c623i8ZYAECL0bx3OvjIgw8+KG+88YZ897vflcrKSpk4caL/9/Hjx8tNN91Ub4Cu9evX+5P+e/Pmzf6/33nnHeN1AgCQi66//np56aWX/DQFWu89/PDDsmDBArnqqqtaetMAAGh1Fi9e7N8batq8tWvXysCBA2X06NGybdu2tPErVqyQiy++WK644gpZt26djB071p80JVBDjz32mF8n9+hhM1hRHRpjAQBZ7RlrY9y4cXLXXXfJ9OnTZdCgQX7D6tKlS5MDcG3cuFE+/vjjZPxHH33k58jTSefrsvrvb3/728brBAAgF3vGnn766f7N3yOPPCL9+/eXmTNn+r1xLrnkEr5QAEDOpCnwAkw25syZI5MmTfI75WiaH82xXlZWJgsXLkwbf/fdd8u5554rU6dO9dMAaT172mmnyT333FMvTjsEXX311fLQQw9JocWAqqnIGQsAqOMFyBmbYd68yZMn+1M6y5cvr/daHzHxDBL0HWqdAABkg+s54gQY2VmXt/XlL3/ZnwAAyDWZ/BCZKrFsRUVFvfmaFq9hajx9inLNmjX1nrKMRCIyatQoWblypaSj87UnbSrtSbtkyZJ6KfAuvfRSv8H25JNPlkzRMxYA0GI9YwEAyPUBvIJMAAC0Fdl6oqRXr15SXl6enGbNmnXQe+3YsUPi8fhBT0fq6y1btqTdPp3fVPwdd9whBQUFcs011wTaF/SMBQAAAAAAANDqbdq0yR8oOqGxAaOzTXvaaioDzT+rA3cFQWMsAKCOGyBNQabLAQCQgw70bg3yuGVWNwcAgFbN791qmfc1VaLO1YbY1MbYdLp27SrRaFS2bt1ab76+7t69e9pldP6h4v/2t7/5g3/17t07+Xftffv973/fz+H+wQcfiCnSFAAA6pCmAACAVjmAFwAAuczzIoEnU0VFRTJ48GBZtmxZvXyv+nr48OFpl9H5qfHqmWeeScZrrthXXnnFHyA6MfXo0cPPH/v0009L3vaM1d1usuttxjKziTXt+NzOYp3tLWI7W8TK4RaxvSxij7WIPcEidqBh3DGH/vWjvv4WsSGNst51q0Xsa+ax7esnrM6K/RaxeyxiPzEP7bw3nHOnXQjneVjlDL+QIVu8qONPTXELzRsD3GLz7s+lxTVGcYeXmJ/43Qp3G8f2KPjUOLZzNGYcW2bxSNJ+i25vu9wi49h3Y2aV/Bv7ehqv84N9XYxjP6m2KVXNdSmuNI7tU2peuZxYutko7rjC7cbr7BY1O75V+4j5MRN1zI/FGjE/xj8pPMw41uac/MDwPK8uLjNep1toXhOalHF+HI2eMOBIxJ+aEnHMb6FN1mcbW+CZv3+xEzWOLS0wL6vaF5hfD3QsMi/XupZVGcce3tG8DDy8Z/r8kA21O2qb8ToLu5vXWdI+s9HWm7THfN8WbzGvuws/rJZsq6413weVFrEVMfNjfFeB+flYbLFem3PSccy2IeoUZn2dNuWMTdnVmk2ZMkUmTJggQ4YMkaFDh/q9VysrK2XixIn+38ePHy89e/ZM5py99tprZeTIkTJ79mwZM2aMLFq0SFavXi0LFizw/96lSxd/SlVYWOj3nD3hhBPytzEWABCyIANxMYAXAKAN0Z9bgmQaIEsBAKAt0RQFgdIUuHbLjhs3TrZv3y7Tp0/3B+EaNGiQLF26NDlI18aNGyUSqWt4HjFihDz88MNyyy23yLRp06Rv376yZMkS6d/fpqOfGRpjAQB1yBkLAICRoKkG6LELAGhLWqLenDx5sj+ls3z58oPmXXjhhf5kyiZPbCoaYwEAdegZCwCAGbrGAgBgjB8x6+RHIggAAAAAAAAAaOXoGQsAqJ+mINPcr+ZjOQAAkPsCPm6pywMA0FZ4rn3e14bL5wsaYwEAdcgZCwCAEc87MGUqyLIAAOQa0hQETFMwb9486dOnj5SUlMiwYcNk1apVh4zftWuXXHXVVXLkkUdKcXGxfOYzn5Gnnnoqk7cGADRHzthMJ6RFvQkA+XtTGWTCwagzASA/eV4k8NRme8YuXrxYpkyZIvPnz/cbYufOnSujR4+Wt956S4444oiD4mtqauSLX/yi/7ff//730rNnT9mwYYN07NgxW58BAIBWi3oTAADqTAAAMm6MnTNnjkyaNEkmTpzov9ZG2SeffFIWLlwoN95440HxOn/nzp2yYsUKKSws9Odpr1oAQCtEmoKso94EgDylPVvJGZtV1JkAkL9cz/GnTAVZNqcbY7WX65o1a+Smm25KzotEIjJq1ChZuXJl2mUef/xxGT58uJ+m4E9/+pMcfvjh8q1vfUtuuOEGiUajaZeprq72p4SKiooD7yUi6Zeoz6bjclEIscUW62xnEVt6oC3bTBeL2MMtYntYxB5rEXtMB8PAL1isdJhF7FESjg8tYruZhx6zzCxuz4Fzx8h281D5KJxjsdRid7WLmccWh3Ce25QdNmWSSRkXqiDpBkhT0CL1ZmN1pkSdA1MTPIsrAa/QPMFhWZHZSdqxcJ/xOg8vMC/TukTq9klTyiPmZ15UzC8Cq7xa49hP4uZXBG/s62kUt/KTY4zX+f5288K6ZrdNqWquqNz8O/v48A5Zr4c6RqqMV3l4tMY4tsQxP74KHfNzLOZVh3Lu2JyTpuf5pxZlh02ZZFLGHVhpODdv5IzNrpa+14w6hRJxmj4AI575OW0zTo2+v1GcxUlSFDG/Ci2yuGAtLTAfRadDkXl52alsr3Fsx86fGse2O2qbUVxhX/NtdXsdbxwb72hzw20uusv8Bq6w/Qbj2HZitr9i+8yvByqryoxjP91fahxbWl0U0vlgHht1C7J+njsWd5ARiztI8/cPqdHTdQIN4CVBlm1lrBIu7NixQ+LxuHTrVr/RSF9v2bIl7TLvvfeen55Al9M8sbfeeqvMnj1bfvKTnzT6PrNmzZLy8vLk1KtXL5vNBACgVWiOepM6EwCQD7jXBAC0FaFnv3Vd188Xu2DBAhk8eLCMGzdObr75Zj+9QWP019Ddu3cnp02bNoW9mQAAxQBeLc623qTOBIAW4mVhQiDcawJA7mDgywzTFHTt2tV/3GPr1q315uvr7t27p13myCOP9HPFpj4mcuKJJ/o9gvRRlKKig7uVFxcX+xMAoJmRMzarmqPepM4EgJa9qQyyPOpwrwkA+Y16M8OesXoDqL10li1bVu/XSH2tuXrSOeOMM+Sdd97x4xLefvtt/2YzXUMsAKAFuQF6x5qnD2szqDcBIM/RKzZrqDMBIL/RMzZAmoIpU6bIfffdJw8++KC88cYb8t3vflcqKytl4sSJ/t/Hjx9fL+m6/n3nzp1y7bXX+o2wTz75pPzsZz/zk6wDAJDvqDcBAKDOBAAgozQFSnPXbd++XaZPn+4/Mjlo0CBZunRpcnCSjRs3+qNeJujgW08//bRcf/31csopp0jPnj39hlkd4RIA0MqQpiDrqDcBID/xuGX2UWcCQP5yvYg/ZSrIsjnfGKsmT57sT+ksX778oHmawuCll17K5K0AAM0pkXIg02WRFvUmAOShoINwMYBXWtSZAJDHP2K65FpX+dOsDAAAAAAAAAD51jMWAJCn6BkLAIAh7d2TeQ+fYMsCAJBbSO9Th8ZYAEAdcsYCAGCGNAUAABijMTbPG2OjIeVpKDSMK7JYZ4lFrJRZxLa3iC23iD3cIraHRaz0N4wbZrFOm9g+Eo4PQlrvVrOwHivC+W7LQzoWLY7xkt3msUUhnOeRkMqkFkfP2LzhRRx/aoprc4AWaGu9mdLCmFFceXSf8To7RquMY9sbfPaEMse8lHD9XyzMxLxa49id8cOMYz/Y18Uo7v3tZnG+d9oZh3b6UEJReZT5Zen7Fus9sqzCKO6Eko+N1xnzPjWOLXTMT7Jii9qlfWR/KOeOzTlpep7blB02ZZJJGWcTZ43G2LwS+ff/muJYXQWaJ9Q3eW9V4JmfJAWO+bFfaPGxiiPmCY9LC2Lm9XGpRfnTaY9xbGH3SqM4t9fxxuusPmawcayUm6/XRu3ud4xjiy3WW7jHbL2lO8y/g7JP9oVyzNgcizbHuM25Y3NOmp7nNmzKJPP3Dyejqes5/pSpIMu2NuSMBQAAAAAAAIBmkJc9YwEAGaJnLAAAZrSHTpBeOnnUwwcAgKaQpqAOjbEAgDr6pI/506T1mT8lBABAzvO8A1OQ5QEAaCtojK1DmgIAwME9YzOdAABoK7wsTBZuu+02cRyn3tSvX7+wPh0AAKHkjHUDTPmCnrEAAAAAkANOPvlkefbZZ5OvCwq4nQMAINdQewMA6rgB0hRkuhwAALmoBXLGauNr9+7dM39PAABaNL1P5vVmPqX3oTEWAFCHAbwAADDieAemTCWWraioqDe/uLjYn9L517/+JT169JCSkhIZPny4zJo1S3r37s03BgBo9cgZW4ecsQAAAADQQnr16iXl5eXJSRtY0xk2bJg88MADsnTpUrn33nvl/fffl8997nOyZ8+eZt9mAACQOXrGAgDq0DMWAAAzGQzCddDyIrJp0ybp0KFDcnZjvWK/9KUvJf99yimn+I2zRx99tPzud7+TK664gm8NANDqe8YGGYTLYwAvAEBeImcsAADNmjNWG2JTG2NNdezYUT7zmc/IO++8k/k2AADQTEhTUIeesRaihnGFFuu0iQ1txSUWse0sYq2uKbsZxh1lsc4+IcWGZXP291eHkL7bkpY/bsM6HUzP87zVAj1j582bJ3feeads2bJFBg4cKL/4xS9k6NChjcY/+uijcuutt8oHH3wgffv2lTvuuEPOO++85N/37t0rN954oyxZskQ++eQTOeaYY+Saa66RK6+8MrMNzHdOOMmNCiNmB0RJJGa8ziKLg6zYMd/YQsf8zI+FNHBApZu+J1w6n1SbFdg1u83X2elD41A54qX6+S2zZdtnzSutTw/P/v6y+Q5sRCScY9HmGLc5d2zOSdPz3CoxWoC2zVztGZspre/effddufTSS4OtCD5HIuLkwJWgY3GS2JxOUYvggoib/XJCYwvNy59oSbVxrLQ3uxuIdzzcfJ3lxxuHlrU7TsJQZREb77jRODbSfkPWvwOb79bmmLE5Fm2OcSekc7KlmZZxTkgjM9MYW4ecsQCAFrN48WKZMmWKzJgxQ9auXes3xo4ePVq2bduWNn7FihVy8cUX+49jrlu3TsaOHetPr732WjJG16f59P7nf/5H3njjDbnuuutk8uTJ8vjjjzfjJwMAILt+8IMfyPPPP+//GKn14Ve/+lWJRqN+vQgAAHIHjbEAgDpuSu9Y2ymDH1DnzJkjkyZNkokTJ8pJJ50k8+fPl7KyMlm4cGHa+LvvvlvOPfdcmTp1qpx44okyc+ZMOe200+See+5JxugN6oQJE+Sss86SPn36yHe+8x2/kXfVqlV80wCA7PeMDTJZ+PDDD/2G1xNOOEEuuugi6dKli7z00kty+OEWvfkAAGghmi826JQvaIwFABycMzbTSUQqKirqTdXV6R9hqqmpkTVr1sioUaPqKqVIxH+9cuXKtMvo/NR4pT1pU+NHjBjh94LdvHmzeJ4nzz33nLz99ttyzjnn8E0DAHK2MXbRokXy0Ucf+fWqNszq6+OOC+fxZwAAwkpT4AWY8gWNsQCArOrVq5eUl5cnp1mzZqWN27Fjh8TjcenWrX4OZH2t+WPT0flNxWvOWe1le9RRR0lRUZHfk1bz0n7+85/PyucDAAAAACBTDOAFAMjqAF6bNm2qNyp0cXE4g+I0Rhtj9bFN7R179NFHywsvvCBXXXWV9OjR46BetQAAZEx76ATppZNHPXwAAGhK0FQDbh7VmzTGAgDqpKQbsPbv5bQhNrUxtjFdu3b1Bx7ZunVrvfn6unv37mmX0fmHit+3b59MmzZNHnvsMRkzZow/75RTTpH169fLXXfdRWMsACBrHO/AFGR5AADaCk8cf8pUkGVbG9IUAADqZDp4VwY9ajWFwODBg2XZsmXJea7r+q+HDx+edhmdnxqvnnnmmWR8LBbzJ809m0obfXXdAADkas5YAAByGTlj69AzFgDQYqZMmSITJkyQIUOGyNChQ2Xu3LlSWVkpEydO9P8+fvx46dmzZzLv7LXXXisjR46U2bNn+z1fdfCS1atXy4IFC/y/a49c/fvUqVOltLTUT1Pw/PPPy29/+1uZM2cO3zQAAAAAoEXRGAsAyGrOWBvjxo2T7du3y/Tp0/1BuAYNGiRLly5NDtK1cePGer1cR4wYIQ8//LDccsstfjqCvn37ypIlS6R///7JGG2gvemmm+SSSy6RnTt3+g2yP/3pT+XKK6/kmwYAAACAFkDO2Do0xgIAspoz1tbkyZP9KZ3ly5cfNO/CCy/0p8Zo/tj7778/s40BAMCQZq4LlDOWPQ0AaINpCjIVZNnWhpyxAAAAAAAAANAM6BkLAKjfuzXTNAWMjwUAaEu0h06QXjp51MMHAICmuOL4qQqCLJ8vaIwFANSJB3hmItNGXAAAcpGmKAiQpiDQsgAA5BjSFNShMRYA0KI5YwEAyEk0xgIAYNczNkDvVjePesaSMxYAAAAAAAAAmgE9YwEAdUhTAACAEcc7MGUqyLIAAOQcz/FTFWQsj3Kt0xgLAKhDmgIAAMyQpgAAAGM6eFegAby8/GmMJU0BAKB+z9ggEwAAba0xNsgEAEAbG8DLCzDZmjdvnvTp00dKSkpk2LBhsmrVqkPGP/roo9KvXz8/fsCAAfLUU0/V+/ttt93m/71du3bSqVMnGTVqlPzjH/+w3i4aYwEAAAAAAADkjcWLF8uUKVNkxowZsnbtWhk4cKCMHj1atm3bljZ+xYoVcvHFF8sVV1wh69atk7Fjx/rTa6+9loz5zGc+I/fcc4+8+uqr8uKLL/oNveecc45s377dattojAUA1KFnLAAAVjljg0wAALS1jHhugMnGnDlzZNKkSTJx4kQ56aSTZP78+VJWViYLFy5MG3/33XfLueeeK1OnTpUTTzxRZs6cKaeddprf+JrwrW99y+8Ne+yxx8rJJ5/sv0dFRYW88sorVttGYywAoI4XoGbkphIA0Jbo45JBJwAA2ojmTFNQU1Mja9as8RtOEyKRiP965cqVaZfR+anxSnvSNhav77FgwQIpLy/3e93aYAAvC6bpEGMW67SJDW3F+y1iKy1iKyxiu241DPzQYqUfSMuz2Qabz7Y1+99BZUjHTEjHbVinA2lP0ebYNKJb/Bwdc6NGcfvdQuN11ojZOlW1Z76xMc/8zHetf5M30y5SbRzbpdiswC4qN19n5VHml4TbPttBwlB5lHmszWcz3V8234ENm2MmZnE+2hzjNueOzTlpep5bnTb8sIcW4okrXg5cCXoWJ4nN6RS3CK51I9kvJzQ2Zl7+xPcXG8fKHrO7gegu88eMa3e/YxxbJSGx2Aabz2a6v2y+A5vv1uaYsTkWbY5xL6RzsqWZlnFaHrZmFRX1GzqKi4v9KdWOHTskHo9Lt27d6s3X12+++Wba9W7ZsiVtvM5P9cQTT8g3v/lNqaqqkiOPPFKeeeYZ6dq1q9VnoGcsAKAOaQoAADDDAF4AABhzPZ2cANOB9fTq1cvvjZqYZs2a1azfwtlnny3r16/3c8xqWoOLLrqo0Ty0jaFnLACgfmNspk9Ntv7OJAAAZE3QvK/kjAUAtCWeOP6UqcSymzZtkg4d6p7UatgrVmlP1Wg0Klu31n+qWF9379497fp1vkl8u3bt5Pjjj/enz372s9K3b1/5zW9+IzfddJPxZ6FnLACgTnNmVAcAIJfRMxYAAGPBesU6/qS0ITZ1StcYW1RUJIMHD5Zly5bVvb/r+q+HDx+edvt0fmq80hQEjcWnrre62i7dFT1jAQAAAAAAAOSNKVOmyIQJE2TIkCEydOhQmTt3rlRWVsrEiRP9v48fP1569uyZTHNw7bXXysiRI2X27NkyZswYWbRokaxevdofpEvpsj/96U/lK1/5ip8rVvPSzps3TzZv3iwXXnih1bbRGAsAqEOaAgAAzARMU5BDY74AAJClnLHBlrcxbtw42b59u0yfPt0fhGvQoEGydOnS5CBdGzdulEikLmHAiBEj5OGHH5ZbbrlFpk2b5qcfWLJkifTv39//u6Y90MG/HnzwQb8htkuXLnL66afL3/72Nzn55JOtto3GWABASg0XIN0AaQoAAG0xTUGQ5QEAaCOylTPWxuTJk/0pneXLlx80T3u4NtbLtaSkRP74xz9KNpAzFgAAAAAAAACaAT1jAQB1SFMAAIAZesYCAGAsdRCuTARZtrWhMRYAUD/VgDbIZoI0BQCANsQJmDM2UL5ZAAByjOcdmDIVZNnWhsZYAED9BtVMf3CkMRYAAAAA0EjOV7eZc8a2VnnZGBsPqe0gZhhXY7HO/RaxUmURu8cidrdF7HaL2I8sYru+Zhh4YNS77Nsc0no/tIj9h0Xsa9n/DraHdMzsCecYtzl3akI4z23Kjkw7mgJBOK7nT02J2Bygteap5vfFCo3idsdLjde5K15mHLsnutc4ttgxLyWiFheBhRbXi50ttrdP6SdGcR8f3sF4ne8bR4p8enixhKGovNo49pjDzfaBzf6y+Q5svtuYZ36SxaXWOHaPxZDCNueOzTlpep7blB02ZZJJGWcTl0tuv/12uemmm+Taa6+VuXPntvTm5AXXcBRTL6Rfnw+8f9NqHfOTpNaiG1nM4mNVu+aF4L7aQvNbgX0W5c+n7Y1ji7e0M4orbL/BfJ3GkSLxjhslDNFd5jdwkU3mny1muL9svgOr79bimLE5Fm2OcZtzx+acND3PbdiUSabvH8Z2og00xgIAMhSk5ZhWZwBAW9JCOWNffvll+dWvfiWnnHJKgDcHAKB5eZ7jT5kKsmxrY/4zNQAg/8UDTgAAtLGcsUEmW3v37pVLLrlE7rvvPunUqVMYHwsAgFAH8HIDTPmCxlgAQB034AQAQFvsHZvJ9G8VFRX1purqxlN2XHXVVTJmzBgZNWpU83w+AABaQZXpBXwYpbWhMRYAAAAAWkivXr2kvLw8Oc2aNStt3KJFi2Tt2rWN/h0AAOQGcsYCAOqQMxYAgGbNGbtp0ybp0KFuwL3i4oOHBtIYHazrmWeekZKSEr4hAEDOCZpqwM2jNAU0xgIA6miqgUzrONIUAADakEzzvqYur7QhNrUxNp01a9bItm3b5LTTTkvOi8fj8sILL8g999zjpzaIRqOZbwwAACELmtnOlTaepmDevHnSp08f/1fZYcOGyapVq4yW00drHMeRsWPHZvK2AADkJOpNAEAQX/jCF+TVV1+V9evXJ6chQ4b4g3npv/OpIZY6EwCQ76wbYxcvXixTpkyRGTNm+DmLBg4cKKNHj/Z/qT2UDz74QH7wgx/I5z73uSDbCwAIk/vvVAWZTPn0U2UWUW8CQJ5qxpFI2rdvL/379683tWvXTrp06eL/O19QZwJA/vI8J/DUZhtj58yZI5MmTZKJEyfKSSedJPPnz5eysjJZuHBho8voIzT6q+2PfvQjOfbYY4NuMwAgLPGAEw5CvQkA+Z2mIMiE+qgzASD/c8a6AaY22RhbU1Pj5ysaNWpU3QoiEf/1ypUrG13uxz/+sRxxxBFyxRVXGL2P5jyqqKioNwEAmjGRT6YTmr3epM4EgPzvGZvO8uXLZe7cuZIvuNcEgPzWwtVm7g7gtWPHDr+Xa7du3erN19dvvvlm2mVefPFF+c1vfuPnMjI1a9YsvxdtQ6b3+TbtATUhxFZbrLPSInZfzDy29BOLFW+3iP3IIvY9i9j2hg3uxyyzWOlWi9j6x3T22GzDa+ah71dk/zv4KKRj5pNwjnGbc6c6hPPcpuywKZNMOpfS5pk7mqPebKzOlLhZtyun1uhtDsTGzH+NrqopNIrbFSs1Xuf22kMPcJPqk4LdxrGFjnkpUeY4ofzi3SVqXqqdWLrZcKXm739kmfkP359Ut5MwdCk23wd9LC50TPeXzXdg893u98wfG6jyzG8zPnGLQzl3bM5J0/PcpuywKZP8ci6bcWhRLX2vGfdi4hnc6rsWjwJ5nvlVW1zMLoTjYn6S1Ljm71/jmucd3ldrXgpW1BQZx35adZhxbLudnYxjCz80q+fbyTbzde55xzg20n6DhGKP+c1TbIt53V354RFGcbssvgOb79bmmLE5FmssbqJszh2bc1LLmWyXHa5FZ1HT93c9m8oYzTaAl6k9e/bIpZdeKvfdd5907drVeLmbbrpJdu/enZw2bdoU5mYCABJIU9CiMqk3qTMBoIXQxadFca8JALmFNAUZ9ozVG0MdqXPr1vq9/fR19+7dD4p/9913/YG7zj///OQ899+/MBQUFMhbb70lxx133EHLFRcX+xMAoAUaYzPtQORmPmrynXfeKVu2bPEHhfzFL34hQ4cObTT+0UcflVtvvdWvX/r27St33HGHnHfeefVi3njjDbnhhhvk+eefl9raWj/H+R/+8Afp3bu3NKfmqDepMwGgZQTN+0rO2Pq41wSA/BY0s50rbbRnbFFRkQwePFiWLVtW7yZRXw8fPvyg+H79+smrr77qPzaSmL7yla/I2Wef7f+7V69e2fkUAIA2MWryihUr5OKLL/Zzqa5bt07Gjh3rT6+99lq9Bs0zzzzTr4M0n94rr7ziN96WlJRIc6PeBACAOhMAgIx7xiq9aZ4wYYIMGTLE77mkSeMrKytl4sSJ/t/Hjx8vPXv29HPx6I1v//796y3fsWNH/78N5wMAWoFm/qkyddRkNX/+fHnyySdl4cKFcuONNx4Uf/fdd8u5554rU6dO9V/PnDlTnnnmGbnnnnv8ZdXNN9/s95T9+c9/nlwu3VMYzYV6EwDyVNDRREhlexDqTADIX57n+FOmgiyb842x48aNk+3bt8v06dP9R0oHDRokS5cuTSZa37hxoz9SNAAgB7kBbg69zEZN1pynCVp/jBo1SlauXJl2GZ2vN2qptCftkiVLkk9raGPuD3/4Q3++9p495phj/PfQHrQtgXoTAPIUjbFZR50JAPldbQbp++OJtN3GWDV58mR/SkcfCT2UBx54IJO3BAA0B60dnWC1Y0VFhVFO00xGTdYfAdPF63yl6Q327t0rt99+u/zkJz/x88nqD4Zf+9rX5LnnnpORI0dKS6DeBID8Q87YcFBnAkB+8iRgz1jJn56xdGEFAGSV5gMvLy9PTpq2prkkBru64IIL5Prrr/ef3tB0B1/+8peTaQwAAAAAAMipnrEAgDwVD94zdtOmTdKhQ4fk7HS9YjMZNVnp/EPF6zoLCgrkpJNOqhdz4oknyosvvpjZ5wIAIB3SFAAAYMz1DkyZCrJsa0PPWABA/cbYIJOI3xCbOjXWGFtUVCSDBw+WZcuW1evZqq+HDx+edhmdnxqvdACvRLyu8/TTT5e33nqrXszbb78tRx99NN80ACDraQqCTAAAtLXfML0AU77IqZ6xpol+YxbrtImtNoyrtFjnHovYnRaxPbdbBG+yiG1vEVsi2benfi7KQ+qxwjy2rhNfdllsrnxkEfueYdxbIazT9pjZHs4xbnPuVIZwnodVzpiUc0GSnhutPGDP2LBGTVbXXnutn/d19uzZMmbMGFm0aJGsXr1aFixYkFzn1KlT/QFAPv/5z8vZZ5/t54z985//3GRO83zjxD1xDO70IzHzLy5SbX5w7KsuMorbvv8w43VuLSk3ju1SsNc4tkg+MY6NR8zP6EKLc6ljpMY49rhCs4K1Y6TKeJ0nlHxsHFvppv+BJah2EdMSWKRz1Pz77RKtzPp3YGOPRTeO3W6hcexHtZ2MY7fGzM8dm3PS9Dy3KTtsyiQt57IZZ42esXnFE9efmuJ6tcbrdL24+fs7Zld4tY75+1e75u+/r9a8aWBPrXmfrl015uVau6oy49jiXeZloKnYPvP6rXSH+d1ItMS8frMR32++vfs+Nb+R37XTbN9ut/gOdlh8tzbHjM2xuK/WvC6otjh3ayPm56RJGaPinvn1ZkSiWS9nTLfTlus5/pSpIMu2NjnVGAsAaNujJo8YMUIefvhhueWWW2TatGnSt29fWbJkifTv3z8Z89WvftXPD6sNuNdcc42ccMIJ8oc//EHOPPPMFvmMAAAAAAAk0BgLAMhqztiwR02+8MIL/elQLr/8cn8CACA09IwFAMCY9rcN0ufWzaN9TWMsAKBFG2MBAMhFWl0GeWAyfx62BACgaZ7n+FOmgizb2jCAFwAAAAAAAAA0A3rGAgDq5NswlQAAhIU0BQAAGCNNQR0aYwEA9bIUmI8dWl+mywEAkIsc78AUZHkAANoKzzswZSrIsq0NjbEAgCQaYwEAMETPWAAAjLni+FOmgizb2pAzFgAAAAAAAACaAT1jAQBZyeOT6XIAAOSsPHpkEgCAMLnegSlTQZZtbWiMBQAkkaYAAAAz5IwFAMBCwJyxQmNs62YziMx+i9hKw7gqi3XusojdaRHbca95bLtNFisukXCYfhHbLdZ5uEVsOwmH6UFj+9k+Mox7z2KdNrEWx0zl3nCOcZtzpyqEr8ym7GBgK7SESNyViEF/5WiN+Tqj1eZ5mqr3FRrF7dxvXgB/WN3JOLa8wPzML3FixrEiFcaR7SPm6y22SIHVzfBLO9ziy415n0ouKXRaNidXtcXNwB7X7FxQW+IdjGM3xzqFcu7YnJOm53mhRdlhUyZFal3j8hBoSkyqJSK1Tca5nvmVnWfx3FBczOqMmJifJNWG61R74+ZlVUUsahxbEjXv/1UYKZUwVNeafbbKqjLjdZZ9ss84trDQ5jrDXCxm/p1V7TPft59WHWYUt8Nif23bb/7+n9SYHzMVFrt2r0VdYHPu2JyTpue5Tdlh01s05pjdxbrcwYaOnrEAgCTSFAAAYIgBvAAAMMYAXnVojAUAJJGmAAAAM6QpAADAnBcwTYFHmgIAQL72jM00rQIPgQIA2hR6xgIA0CxPYebb/WYYabQAAAAAAAAAAA2QpgAAkETOWAAAzJCmAAAAsRpszGbAsYaCLNva0BgLAEgiZywAAIZIUwAAgDGqzTo0xgIAkmiMBQDAEHeVAABY9ox1Mt5j+dQzlpyxAAAAANDK3XvvvXLKKadIhw4d/Gn48OHyl7/8paU3CwAAWKJnLAAgiZyxAAC0zpyxRx11lNx+++3St29f8TxPHnzwQbngggtk3bp1cvLJJ2e+IQAANAPPOzBlKsiyrQ2NsQCAJNIUAADQOtMUnH/++fVe//SnP/V7y7700ks0xgIA8rrjjwRctrUpyLVGApNrlpjFOm1iqwzjKizWudsidrtFbLFFbJ+t5rFFFuuV/RaxewzjPrJYZ7lFbImEY38LHwybLNZpEVtjccxsDukYt9ldNuek6XkeVjmj5VxbqoQQHifmiuM2fURFq81bA6L7zLMb1VSZXWLsrCo1XudHxeYFe/sC8wK40DE58zJhXvpEIuYlRfuIWa6tEidqvM5Ci9hISFmuXIvSLeaZf2f7DWP3WCQi2+MWGsduiXcwjt0Y62IeW20e+1GV+bljc056hud5dJ95frhotflx4MTMvlsn3rprzoqK+mVFcXGxPx1KPB6XRx99VCorK/10BQjO82rFNbjbdD3z8tqzKNfihuutjuwzXuc+p9o4tjJuXq7trjGvBwocm/yQ5tsQc83XW1lrtt5P95uXf6UF5sdBYSSc64yYa1537zPcB6qixuyuf1eN+To/qTFvetpZbf7d7q4xr7sr47FQzp1qx/ycjLtm22BTzjgW12WuZ3bMeBbXWcgMOWMBAAf9WpnpBABAW+F4XuBJ9erVS8rLy5PTrFmzGn3PV199VQ477DC/sfbKK6+Uxx57TE466aRm/NQAAARLU+AFmGzNmzdP+vTpIyUlJTJs2DBZtWrVIeP1h85+/fr58QMGDJCnnnoq+bdYLCY33HCDP79du3bSo0cPGT9+vHz0kU2vwQNojAUAJLkpqQpsJxpjAQBtMk1BkEkfTtq0SXbv3p2cbrrppkbf8oQTTpD169fLP/7xD/nud78rEyZMkNdff735PjMAAC3U8ce1fL/FixfLlClTZMaMGbJ27VoZOHCgjB49WrZt25Y2fsWKFXLxxRfLFVdc4edjHzt2rD+99tpr/t+rqqr89dx6663+f//4xz/KW2+9JV/5ylfyO00BACBc5IwFAKB5B/Dq0KGDP5koKiqS448/3v/34MGD5eWXX5a7775bfvWrX2W+IQAANAPt2WqRFeogtj1j58yZI5MmTZKJEyf6r+fPny9PPvmkLFy4UG688caD4rU+Pffcc2Xq1Kn+65kzZ8ozzzwj99xzj7+sPr2ir1Pp34YOHSobN26U3r17G28bPWMBAAAAIAe5rivV1ea5DQEAyHUVFRX1pnT1YE1NjaxZs0ZGjRqVnBeJRPzXK1euTLtenZ8ar7QnbWPxSp9ocRxHOnbsaPUZaIwFACSRMxYAgOZNU2BK0xe88MIL8sEHH/i5Y/X18uXL5ZJLLuErAwC0mWqzl0Gu9R07dviDXXbr1q3efH29ZcuWtNun823i9+/f7+eQ1dQGpk+4JJCmAACQRJoCAACaN02BKc1xpwOFfPzxx/7N5ymnnCJPP/20fPGLX8x8IwAAaCZuwDQFbkqu9dTGTx3UsrnpYF4XXXSReJ4n9957r/XyNMYCAAAAQCv3m9/8pqU3AQCAFtfBINd6165dJRqNytatW+vN19fdu3dPu4zON4lPNMRu2LBB/vrXv1r3ilWkKQAAHNQzNtMJAIA2o5nTFAAAkMt0AK6gkykd8FIHuly2bFm9POv6evjw4WmX0fmp8UoH7EqNTzTE/utf/5Jnn31WunTpIpmgZywAoK6C+veUiUyXAwAgFzV3mgIAANrqvaZksOyUKVNkwoQJMmTIEBk6dKjMnTtXKisrZeLEif7fNfVPz549kzlnr732Whk5cqTMnj1bxowZI4sWLZLVq1fLggULkg2x3/jGN2Tt2rXyxBNP+DlpE/lkO3fu7DcAm6IxFgCQRM5YAAAMBe3dSmMsAKANyVbOWFPjxo2T7du3y/Tp0/1G00GDBsnSpUuTg3Rt3LhRIpG6hAEjRoyQhx9+WG655RaZNm2a9O3bV5YsWSL9+/f3/75582Z5/PHH/X/rulI999xzctZZZ+VnY6w2Epjs+xqLde63iK00jNttsc52FrElFrGFEo6e9dNnHFI70x2mPjGMs+kB3r4V7LCYReyeEPbXdvNVVu41j91sHioWh4zN5soui1ibc7IyhLLDpkwyedSfHqgw4cTi4rhNH1EF1eZXNQX7zPd9tNIsE1LlXvPabUuRecFeUmBeAEdbxVlVYRwZdcw+W6FFt7tii8xVhU5UwhCzuMCOS61xbJXhM227XfOLgS1x89xgG2PmFy8f7O9qHLuhqrNx7JZK83PH5pw0Pc9tyg6bMknLOaO4OIl00LRad784BuVb3DMvf2zUetVGcTVelfE6qxzzC/wiz7wMjNbaZDs0X2+t5xjH7o+br7ciZlZvlVab92orjlhcP0XCuc6odc2/h2rXfN/uM/x+91gcBxUW98W7a8z37a5a8xXvFbNzzPbcsTknTc9z17M5ZixiXbO7WM/Ln3pz8uTJ/pTO8uXLD5p34YUX+lM6ffr08QfsyoacaowFAIRLq5ZMLxfp4AMAaGtINQAAgBkeKKlDYywAIIk0BQAAGLIdTSTd8gAAtBHNnaagNbN5vgAAAAAAAAAAkCF6xgIAkugZCwCAeYqCIGkKSHEAAGhLeKCkDo2xAIAkN0DO2NYwBBIAAM2G5HcAADTLvWa+3W+SpgAAcFDP2EynTMybN88fmbKkpESGDRsmq1atOmT8o48+Kv369fPjBwwYIE899VSjsVdeeaU4jiNz587lWwYAZJXjBp8AAGhTjbFegEnyB42xAIAWs3jxYpkyZYrMmDFD1q5dKwMHDpTRo0fLtm3b0savWLFCLr74Yrniiitk3bp1MnbsWH967bXXDop97LHH5KWXXpIePXo0wycBAAAAAKBpNMYCAFqsZ+ycOXNk0qRJMnHiRDnppJNk/vz5UlZWJgsXLkwbf/fdd8u5554rU6dOlRNPPFFmzpwpp512mtxzzz314jZv3ixXX321PPTQQ1JYWMg3DAAIL01BkAkAgDaCarMOjbEAgIPy+GQ6qYqKinpTdXV12j1cU1Mja9askVGjRtVVSpGI/3rlypVpl9H5qfFKe9KmxruuK5deeqnfYHvyySfz7QIAQh3AK8gEAEBbGsArSJoCL4/qTRpjAQBJboBesYnG2F69ekl5eXlymjVrVto9vGPHDonH49KtW7d68/X1li1b0i6j85uKv+OOO6SgoECuueYavlkAQPjDQgeZAABoI6g26xRIDjFN1huzWOd+i9gqw7g9FuvcaREblXDY7K/0/dvS67w3+7GlH1psQJlFbGEr2LmmB5iI7Itl//iyid3eCmJttndPCF/D/pAOA5NyrrUnLt+0aZN06NAh+bq4uLjZ3lt72moqA80/qwN3tWmxWhG36Zojut+8MaCgyiJ2r9nvvdWl5gXwzgLzgr0gEs6ZErf4HTvmmdfc+y3SadTIp4bvb15rt4+Yl2rFTji/5Vd75t/ZHu0eYegT16wM+qi2k/E6N8fMYzdWdzGO3VDV2Tj2wz0djWN3VpifO26F+bFYbHie25QdNmWSX86ZiBvGoU2Le7XiGOSOcD2bKztztYZFYMzZZ7zO/ZFK49g9EYumAYsqNh4zD97vmpc/lTHzumhXgVlsUcR8nYUWVWE0pEvSuE1xafGd1RjG7qs134C9cfMNqIybn2N7LVoo9kTM7wr3O+bnTsw1PydrXbPtDaucMeV5mQ7NDFP0jAUAZDVNgTbEpk6NNcZ27dpVotGobN26td58fd29e/e0y+j8Q8X/7W9/8wf/6t27t987VqcNGzbI97//fenTpw/fNAAga0hTAABA891runm0s2mMBQC0yABeRUVFMnjwYFm2bFm9fK/6evjw4WmX0fmp8eqZZ55Jxmuu2FdeeUXWr1+fnHr06OHnj3366af5pgEA2cNIJAAAGDuQ+9ULMOXPzs6pNAUAgPwyZcoUmTBhggwZMkSGDh0qc+fOlcrKSpk4caL/9/Hjx0vPnj2TeWevvfZaGTlypMyePVvGjBkjixYtktWrV8uCBQv8v3fp0sWfUhUWFvo9Z0844YQW+IQAAAAAANShMRYAkJRJD9fUZW2NGzdOtm/fLtOnT/cH4Ro0aJAsXbo0OUjXxo0bJZKSv2vEiBHy8MMPyy233CLTpk2Tvn37ypIlS6R///58iwCAFklTEGR5AADa2gMlmcqnapPGWABAUpBcPJkuN3nyZH9KZ/ny5QfNu/DCC/3J1AcffJDhlgEAYDAsdKaCLAsAQC6mKQi4fL6gMRYA0GI9YwEAyFX0jAUAwJz37/9lKsiyeTGA17x58/xRqUtKSmTYsGGyatWqRmPvu+8++dznPiedOnXyp1GjRh0yHgCAfEO9CQAAdSYAABk1xi5evNgfcGXGjBmydu1aGThwoIwePVq2bdvW6COmF198sTz33HOycuVK6dWrl5xzzjmyefNmvgEAaKU9YzOdcDDqTQDI8+R3QSbUQ50JAHmepiDg1GYbY+fMmSOTJk3yR7o+6aSTZP78+VJWViYLFy5MG//QQw/J9773PX9Qln79+smvf/1rcV1Xli1blo3tBwBkkZeSN9Z2yqO6MauoNwEgv9MUBJlQH3UmAOQvNwtTm2yMrampkTVr1vipBpIriET819rr1URVVZXEYjHp3LlzozHV1dVSUVFRbwIAINc0R71JnQkAyAfcawIA2gqrAbx27Ngh8XhcunXrVm++vn7zzTeN1nHDDTdIjx496t2YNjRr1iz50Y9+dNB8fQTW5AfkmJirsogtMYwrDDtprwGbx4X3W8TaNIt/YhHb3jCuncWXW7LbPNbmO7MRC+l7qDSM22Oxzl0WsbtDWu/OkI6vXSHs26qQjgOTczfMXwQZwCu7mqPebKzOdGprxXGjTa6/YJ95jVFYGTWP3WsW5xabrzMWLTaOTZ88Kb1a17w23l9rXmPsKTO9chDZXVxmHPtJ4WFGcYcXmNfaHaPmpVpRSElJasT8WNgVN99f22s7GMVtjZUbr/PD6k7GsR9Vma93S6XpFZHIzgrzfRDbbX7uFFZk/zwvNK1cLcskJ1ZrFueaxVkL+sxkPj1vmQUtfq/p1YhjcHfmeS3bNyvmmpfX+2zuNi1C4xHzc6rGM6uz1L64eVm1J25eHxfHzMq1ooj5TihwHONY80g7NiVIrWceXeOaHePVnnl5XW1xR7TPqTaOrXL2ml/DOeaV0T53dyjnpOuZ7QfXC6fe8gzvJMMq5zwv4ABeXv7Um2G1BaZ1++23y6JFi+Sxxx7zB/9qzE033SS7d+9OTps2bWrOzQSANovHRloXk3qTOhMAWgg5Y1sV7jUBoHUjTUGGPWO7du0q0WhUtm7dWm++vu7evfshl73rrrv8CvLZZ5+VU0455ZCxxcXF/gQAaF70jM2u5qg3qTMBoGVob7cgeV/D6i2Xq7jXBID8Rs/YDHvGFhUVyeDBg+sNvpUYjGv48OGNLvfzn/9cZs6cKUuXLpUhQ4bYvCUAADmLehMAAOpMAAACpSmYMmWK3HffffLggw/KG2+8Id/97nelsrJSJk6c6P99/Pjx/iOTCXfccYfceuutsnDhQunTp49s2bLFn/buNc/tAQBo3p6xmU44GPUmAOQpzV0XdLKguU5PP/10ad++vRxxxBEyduxYeeuttySfUGcCQP7yAqYq8KSNpilQ48aNk+3bt8v06dP9RtVBgwb5PV4TidY3btzojxSdcO+99/ojY37jG9+ot54ZM2bIbbfdlo3PAADIkkRFl+myOBj1JgDkJ01REChNgeWyzz//vFx11VV+g2xtba1MmzZNzjnnHHn99delXbt2kg+oMwEgf7meDiGWecWpy7fZxlg1efJkf0pn+fLl9V5/8MEHmW0ZAKDZkTM2HNSbAJDHA3gFWd6CdoBJ9cADD/g9ZNesWSOf//znJV9QZwJAfvL+/b9MBVk2LxpjAQAAAADBVVRUZDQw4+7du/3/du7cma8BAIB8zhkLAMhfboB8saQpAAC0JY7nBZ5Ur169pLy8PDlpbtim6CDK1113nZxxxhnSv3//Zvi0AAAEEyRfrJtn95v0jAUAJJEzFgAAQ0HvDP+97KZNm6RDhw7J2Sa9YjV37GuvvSYvvvhigA0AAKD5aL7YQDljhTQFAAAAAICAtCE2tTHWJKfqE088IS+88IIcddRR7H8AAHJMTvWMNf3hOWaxzv0WsVWGcVEJhxvS56q0iN1jEbvTItZ0/Nem+wnUKbKILZRw2ByLNRax1SF8t6bHt6qf2ezQDmQzy/7xtSuk9VaFcI7Fsnyeh/l4BgN45ZFYrUik6Ropuq/WeJWFleaXDUUVZpmQ3AInlMuWWNx8vdtrzWvuqhrzGmNXdalx7JaS9saxh5fsNYrrWLjPeJ3lUfPYkohNqWZuv2u+b3fHzfftrphZ7Pb9hxmvc+d+85Hrd1aZb2vl3hLjWLfCfH8VVpgf44W7zc+dogqzHiqFleY1l02Z5JdzJlyLdVpITTWQ6fI2PM+Tq6++Wh577DF/0ORjjjkm4/fGweJutThOy2Xx87yWfQBX+6uZijnmV8LVEfP6pcozLy8LLe72Cjyz64eoa36dUeCZl6uO2FzrhDOYUa2jV/lm4mJWZtZGzMvWmMXdbrVjfszUeOZ3sTHXfL0x13y9tW61RTljth88/64sBF7LlkeuF7BnrEfPWABAHiJNAQAAhvSeMMh9oeWymprg4Ycflj/96U/Svn172bJliz9f88yWlpo3YgEA0BL0BwSbHxEaCrJsa5NTPWMBAOGiZywAAIa0h06QXjqWy957773+f88666x68++//3657LLLMt8OAACaATlj69AYCwAAAACtnKYpAAAAuY/GWABAEj1jAQAw43gHpkwFWRYAgFxDz9g6NMYCAJLIGQsAQOtMUwAAQC4jZ2ydlhsuEgAAAAAAAADaEHrGAgDq9YzVVAWZLgsAQFvhuAemIMsDANCWesZqqoIgy+cLGmMBAEnkjAUAwBBpCgAAMOY6rjgBfol086j7D42xAIAkcsYCAGBIO+gE6aSTPx18AABokvaKdQJUfm4eVZzkjAUAAAAAAACAZlCQaz22TNrBayzWud8itkKyzyY3Y8wittIido9FbJlFbDuL2GLDuCKLdRZaxEYlHGF9v6bHeHVIx0xVHq+3IoSyoybLx0yYvweSpiB/eNUx8SJOk3HRSvMjtGi3+WWDW2BTCpuJ1DrmsdXm21q7z/y36T17zT/X3rJS49itpe2NYz8oNvvOyorMa5bSQvPYwkimmaUPLeaa18b7YubfQ1WNWey+avOrjOp95u/vVZkfi9FK82OxeK95bOFe41ApqjCvZYp3mcUW7a41XqdNmeRVm8V6rs1VljnH8/wpyPJoPVw3Jo5jXs+YcBzz81QzKRoJ6Sld1zNfcTxifk7VOuZ3JNWOeWEVtbjbM/0eoo75OiM51q/N5vHuuBfL7jHr32OYHzNxizK71jM/vmpd81jXcB+ouFsTwnrN961nce6arzOc+ulAxtjMtzfIsq1NTjXGAgDCRZoCAAAMkTMWAACre81gaQryB42xAIAkesYCAGDIC3hnSMdYAEAbwgBedXKrbz0AAAAAAAAA5CgaYwEAB/WMzXQCAKCtSOSMDTIBANBWuFn4n6158+ZJnz59pKSkRIYNGyarVq06ZPyjjz4q/fr18+MHDBggTz31VL2///GPf5RzzjlHunTp4ucZX79+vWSCxlgAwEFPXGYycUsJAGhTvJS8sRlNLf0BAADI38bYxYsXy5QpU2TGjBmydu1aGThwoIwePVq2bduWNn7FihVy8cUXyxVXXCHr1q2TsWPH+tNrr72WjKmsrJQzzzxT7rjjjkD7gsZYAAAAAAAAAHljzpw5MmnSJJk4caKcdNJJMn/+fCkrK5OFCxemjb/77rvl3HPPlalTp8qJJ54oM2fOlNNOO03uueeeZMyll14q06dPl1GjRgXaNhpjAQBJpCkAAMBQoF6x/54AAGgjPHEDT6qioqLeVF1dLQ3V1NTImjVr6jWaRiIR//XKlSslHZ3fsJFVe9I2Fh8EjbEAgBZtjM1mHp9YLCY33HCDP79du3bSo0cPGT9+vHz00Ud8ywCA7HKzMAEA0Ea4jht4Ur169ZLy8vLkNGvWLGlox44dEo/HpVu3bvXm6+stW7ZIOjrfJj4IGmMBAEnNfU+Z7Tw+VVVV/npuvfVW/7+aYP2tt96Sr3zlK3zLAICsYgAvAADMac/WIP/z/n3HuWnTJtm9e3dyuummm3LuayiQHKK9rhyDuJjFOvdL9rkhvb9NbKVF7B6L2EKL2JIQ1luUx7802Bw3NYZxYZ0LYa3XJraqhbchrP1l0rvUy9M8Pkrz+Dz55JN+Hp8bb7zxkHl8lObxeeaZZ/w8Prqs/jKqr1Pp34YOHSobN26U3r17S5tRU60tBU2GOZXmR3NRUfYvGyK15uss2Gdessf2mm9DbZn5emtLzWPjpVHj2FixeQ1XXVxmFPdpoUVpUeC2fAVrUxHWmm+EEzO5ehSJVJvFqUKL2Og+89iCfcahUlBl/v0WWlwYFlaafxFFu2sN40yvXOzKJEnzWGJanvn7o+1yvWpxDO42HTEv2z2LAjPimNWHnsWzSK5ndo7aqrUor13H/Eo44pjfbToW+zZquF6bdeYzzzP7guOe+XebaEQz4Vqs1/XCWq/5uWNzTppe7Fiduxb7wHRbvVaeRqdDhw7+dChdu3aVaDQqW7durTdfX3fv3j3tMjrfJj4IShsAQIukKWiuPD76a6njONKxY0e+aQBA9pAzFgAA82pT4oEnU0VFRTJ48GBZtmxZcp7ruv7r4cOHp11G56fGK+3o01h8m+kZCwAIV5AUdonlNIl6quLiYn+yyePz5ptvZiWPz/79+/0cspraoKlfTwEAsBJ0EK5W3vMIAIBscgMmTHctl9V0eBMmTJAhQ4b4T0rOnTtXKisrk09l6tgiPXv2TOacvfbaa2XkyJEye/ZsGTNmjCxatEhWr14tCxYsSK5z586d/hOXiTFJNCWe0t6zNj1o6RkLAMgqk4TqzUEH87rooov8x2zuvffeFtkGAAAAAEDzGzdunNx1110yffp0GTRokKxfv16WLl2a7Nyjjaoff/xxMn7EiBHy8MMP+42vOpbJ73//e1myZIn0798/GfP444/Lqaee6jfWqm9+85v+a02ZZ4OesQCApEzSDaQum0iontoLNV2v2LDz+CQaYjds2CB//etf6RULAMg+esYCAGBMh+AK1jPWs15m8uTJ/pTO8uXLD5p34YUX+lNjLrvsMn8Kip6xAIAkN0C+WLdBQvXE1FhjbFh5fBINsf/617/k2WeflS5duvANAwCyz83CBABAG9GcOWNbO3rGAgCymjO2JfP4aEPsN77xDVm7dq088cQTfk7aRD7Zzp07+w3AAABkg+N5/hRkeQAA2ormzhnbmtEYCwBo0Tw+27dv9/P4aKOp5vJpmMcnEokclMfnlltukWnTpknfvn3r5fHZvHmzn8dH6bpSPffcc3LWWWc16+cDAAAAACAVjbEAgKR4gPw1mT40ks08Pn369PEH7AIAIHTkjAUAwLza9LO+Zt67NciyrQ2NsQCAFm2MBQAgJ7me5hoItjwAAG2E698xOgGXzw80xgIAWixnLAAAOYuesQAAmFeb9IzNzcZY17ANPRbS+5u2wdu8/36L2EqL2EKL2KKQ1hsNYb2RkN6/NYiH0OgVC+n9bdZbE9J6Yy28vWG9v8l3Sz8aGB1L1TXiGvTYiuwxr11syuDimhKjuIIq81ooXmp+2VJbal4LxEvMf6GvLTaPjdvEFpnHuoVm34RncZXn2lSamXdoyFrhFrGotJxaw3XGzDcgalG5RavNf6oqqLbYhv3msQX7zHdYdF+teWyl2Y5wKi2ueC3KJLe62izOC+vuAPklJp5nUMA55ue04xVm/fFbJ6wyOCSOxdWDTWzEMa+4HMdsvRGLO0ibbW0NbB7vdg2PMZv9ZfMggN2+za3uIJ5nuL2mcf53a17HeZ7p9QB3nGHLrRIEABCqeMAJAIC2w6vrHZvJZHmz+8ILL8j5558vPXr0EMdx/AEsAQDIFa4XDzzlCxpjAQAHpSnIdAIAoM0I0hCbQYqDyspKGThwoMybNy+0jwQAQNhpCrwAU77IqTQFAAAAANAWfelLX/InAACQ22iMBQAk6W+NmT78kT+/UwIAYJoEMUBevX8nUayoqKg3u7i42J8AAMgnB3q3Zp5qIJ96xpKmAACQRM5YAADEfICVoJOI9OrVS8rLy5PTrFmz+AoAAHlHBzBzA0yexcBmrR09YwEASUFyv+ZP1QgAgIEM8r4etLyIbNq0STp06JCcTa9YAEA+OtCz1Qm4fH6gMRYAAAAAWog2xKY2xgIAgPxGYywAoF6agkx/q8w8+w8AAG03ZywAAG2B58VbdPnWhMZYAEASjbEAADRvmgJTe/fulXfeeSf5+v3335f169dL586dpXfv3plvBwAAzcAVVxzSFPhojAUAAACAVm716tVy9tlnJ19PmTLF/++ECRPkgQceaMEtAwAAedsYG6TH1qHWaSpmGFdtsc6IRWy0FazXJlZC2N6w3j/XmB63YaW3jocU6+bQelvy/cN8qJEBvPKHV10tntP00efu2m28zsi+/caxTnGxUVxhcZHxOgsLzS9bPItYsVpvNJRYt8C85vaihldDpnG6zki2r7DC5dg83h03i3UM41Sk1rxkd2LxUGIlVmux3tpQ1utV15gFVptfHbsWsVrOGcV5plfxlvwsBUF6xtqFn3XWWeIFeT9k5W7T6itwzMt2J4Rbc8fi/SNOoXFs1DHf1oJIicU2mK+3UMzX6xjebUYt9kHE4o7bCeku1rO4I9EeiabihmWmyXVmQswxv4Z0PYv95ZqvN7SBoryW/W7tHt03jQ2nrvG8gAN4eQzgBQDIQ6QpAACgdaYpAAAgl9k0MoexfGuSUz1jAQDh0tvCTH9v5JYSANCmuEGeJ0ksDwBA23Dg6Y7M6758ejrE5ml2AAAAAAAAAECG6BkLAEgK8uBH/jw0AgCAAdIUAAAQTi7eEJZvTWiMBQAk0RgLAIAhGmMBALAcbCzzVAP5NIAXaQoAAAAAAAAAoLU2xs6bN0/69OkjJSUlMmzYMFm1atUh4x999FHp16+fHz9gwAB56qmnMt1eAECI3IAT0qPeBIA85HrBJxyEOhMA8pP2bA06tdnG2MWLF8uUKVNkxowZsnbtWhk4cKCMHj1atm3bljZ+xYoVcvHFF8sVV1wh69atk7Fjx/rTa6+9lo3tBwBkUTzghINRbwJAfuKmMvuoMwEgf2nO16BTvnA8T5MdmdOesKeffrrcc889/mvXdaVXr15y9dVXy4033nhQ/Lhx46SyslKeeOKJ5LzPfvazMmjQIJk/f77Re1ZUVEh5ebmU6gYbxEdDao02XW9Lv3+Y67WJlRC2N6z3zzWmjV5hFVXxkGLdHFpvS76/Ftr7RGT37t3SoUMHyYZEOXt8gPNMt/2dLG9XPmjuejPxXZ4lF0iBU9hkvFNcbPxZIhaxYhjrFBeZr7PQPNW9ZxFrt95oKLFugXnN7UVNrob0ZHbM1xkxj20NHJsehXGzWMcwTkVqzUt2JxYPJVZitRbrrQ1lvV51jVlgdbXxOl2LWM8wttaLyXL5U9bqp0Q5+4WO46XAsSjDDtquGlm267fUm63kXvPAHUl27zYdg3o4IeKY1ZuRiPkxF42Y19tRxybWvN4siJQYx0Ys1lso5ut1DO82ozbfl8UdtxPSXaxncUfiWtyRxL2Y4fubrzMm+41jXc+8Hqp1zdcbt1hv3DOvi+KuRR3nmtWbrsX7e4bf1wGmx4xeE7lZrzcLo93EcTLPlqo/gsbiW/Oi3rQawKumpkbWrFkjN910U3JeJBKRUaNGycqVK9Muo/O1J20q7Um7ZMmSRt+nurranxJ0RyvTS2Sb1uUwYsNqAHNawXpz61Ytf7ktfCy6eRybC+VMIsbytzS0gOaoNxurM2slZnRAOZ75BVHEs6gFXCf7jWqu+U2HF7do1IpYrDdi0RgbMd+3rsVNnWf6PVh8XzTGWjbGxi0aY61iLY7buEVjrGvRGGsR67mGN4CeYaOtfwMay/oNqF8eUm+2ei19rxnGVaDNtZpnuF6bx3StYi0a9jyLu8IDA/aYcS3W64pFGWhYxzpWd7s2jbHh3JXZNIbaNMaaNobavX88lGMmvNiQzjPDMsHuPi+M2ANx3G+2ksbYHTt2SDwel27dutWbr6/ffPPNtMts2bIlbbzOb8ysWbPkRz/60UHzzX/zAID898knn/y7J0f2uAF+dMmfh0aypznqzcbqzBfFMD+7+Q/vdrEAkO/1pn+zHOCHUX5UbVX3mge+Sy/LVzzmPy64XpVZnMVvNrXkkALQiurNoGkGvDy647RqjG0u+mto6i+cu3btkqOPPlo2btyY9YaHXKHduvURnU2bNuV8d+xMsQ/YBxwHdT04evfuLZ07d876eRakesufqjG3UGcejPqC/cCxwPnQLPWm62q348yXz6OBSHIJ9ebBqDfZBxwHnAvNUW8e6J2c+Y+Y+TSAl1VjbNeuXSUajcrWrVvrzdfX3bt3T7uMzreJV8XFxf7UkDbEttWGyAT9/OwD9gHHAedC4tG9bKMxNruao96kzmwcZSX7gWOB8yHUepOesVnFvWbLo95kH3AccC6Ee795IBdt5vInTZ/Vni0qKpLBgwfLsmXLkvM0qbq+Hj58eNpldH5qvHrmmWcajQcAIF9QbwIAQJ0JAECgNAWaPmDChAkyZMgQGTp0qMydO9cfwXLixIn+38ePHy89e/b0c/Goa6+9VkaOHCmzZ8+WMWPGyKJFi2T16tWyYMEC27cGAIQsyIMj+fPQSHZRbwJAfvJcV7wAaQry6XHLbKHOBID8daDey3xY+HwaUMy6MXbcuHGyfft2mT59up8YfdCgQbJ06dJk4nTN65ralXnEiBHy8MMPyy233CLTpk2Tvn37+qNb9u/f3/g99RHMGTNmpE1d0FawD9gHHAecC81RHtAYm33NXW9SX7APOBY4HygTmqlcJE1B1nGv2TK4dmAfcBxwLjRHmXBgAK4AjbF5lKbA8fKpaRkAkPHADZqXW7OSZpoZSKvWLf9O+N7Wc1sDAPK/zvyP0nFS4BRlvJ5ar0b+um8x9SYAoE3Um47TXhwnWM9Yz9uTF/Wmdc9YAED+YgAvAABMK01Pu7ZkvrvoEwMAaFOC9YyVPOoZS2MsACCJNAUAANg0pgb4GZPGWABAWxIwZ6zkUb1JYywAIEmrx0yruPypGgEAaJrneuIF6BlLtjgAQFtCztg6maYGBAAAAAAAAADkYmPsvHnzpE+fPlJSUiLDhg2TVatWHTL+0UcflX79+vnxAwYMkKeeekpync0+uO++++Rzn/ucdOrUyZ9GjRrV5D7LBbbHQcKiRYv8RNBjx46VtrYPdu3aJVdddZUceeSR/miHn/nMZ3L+fLDdB3PnzpUTTjhBSktLpVevXnL99dfL/v37JVe98MILcv7550uPHj3843rJkiVNLrN8+XI57bTT/GPg+OOPlwceeCDjnrFBJjQP6kzqzEyPhQTqTepN6s0s1Jv6uGXQCc2CepN6M5PjIIE6kzqTOjM795rB7zZdyRteK7Bo0SKvqKjIW7hwoffPf/7TmzRpktexY0dv69ataeP//ve/e9Fo1Pv5z3/uvf76694tt9ziFRYWeq+++qqXq2z3wbe+9S1v3rx53rp167w33njDu+yyy7zy8nLvww8/9NrKPkh4//33vZ49e3qf+9znvAsuuMDLZbb7oLq62hsyZIh33nnneS+++KK/L5YvX+6tX7/eayv74KGHHvKKi4v9/+rnf/rpp70jjzzSu/76671c9dRTT3k333yz98c//lGfffQee+yxQ8a/9957XllZmTdlyhS/TPzFL37hl5FLly41fs/du3f773WYiNc+w0mX1XXouhAe6kzqzEyPhQTqTepN6s1g9WaizjzL+ao3KnJRxpMuT70ZPupN6s1MjoME6kzqTOrM7N1rihR4jhRmPOny+VJvtorG2KFDh3pXXXVV8nU8Hvd69OjhzZo1K238RRdd5I0ZM6bevGHDhnn/9V//5eUq233QUG1trde+fXvvwQcf9NrSPtDPPWLECO/Xv/61N2HChJxvjLXdB/fee6937LHHejU1NV6+sN0HGvsf//Ef9eZpRXHGGWd4+cCkMfaHP/yhd/LJJ9ebN27cOG/06NHG70NjbO6gzqTOzPRYUNSb1JvUm8HrTRpjcwv1JvVmJseBos6kzqTOzO69Jo2xdVo8TUFNTY2sWbPGf8w+IRKJ+K9XrlyZdhmdnxqvRo8e3Wh8a5fJPmioqqpKYrGYdO7cWdrSPvjxj38sRxxxhFxxxRWS6zLZB48//rgMHz7cT1PQrVs36d+/v/zsZz+TeDwubWUfjBgxwl8m8ZjRe++956dpOO+886StyGaZGA84IVzUmdSZQY4FRb1JvUm9mb16s9arllo3wORVW70f7FFvUm9mehwo6kzqTOrMbLe/ef4gXl6GUz4NGV3Q0huwY8cOv+FIG5JS6es333wz7TJbtmxJG6/zc1Em+6ChG264wc8v2fAkyed98OKLL8pvfvMbWb9+veSDTPaBNjz+9a9/lUsuucRvgHznnXfke9/7nt8wP2PGDGkL++Bb3/qWv9yZZ57pj0pcW1srV155pUybNk3aisbKxIqKCtm3b5+fS7cpRUVF0r1798DlqK5D14VwUGdSZwY5Fqg3qTcV9WbwejNRZ764JXiOfurNcFFvUm9mehxQZ1JnKurM1nWvmU/1Zos3xiK422+/3U8qrgP4aDLytmDPnj1y6aWX+gOZde3aVdoq13X9nsELFiyQaDQqgwcPls2bN8udd96Zk42xmdDjXnsD//KXv/QT8WuD9LXXXiszZ86UW2+9taU3L2do2fH+++/7PQeC0IqxrZRDyE1tsc5U1JsHUG9Sb7amOlNRb6K1a4v1JnXmAdSZ1JnZQr3ZChtjtSFNG5G2bt1ab76+1hbvdHS+TXxrl8k+SLjrrrv8CvLZZ5+VU045RXKV7T5499135YMPPvBHnE+tLFRBQYG89dZbctxxx0m+HwdHHnmkFBYW+sslnHjiif4vTnqDkGu/GGWyD7TBVRvmv/3tb/uvBwwYIJWVlfKd73xHbr75Zv8RpHzXWJnYoUMHo18qUyvJtnKRnauoM6kzMz0WqDcPoN6k3sxWvUmdmRuoN6k3MzkOqDMPoM6kzlTca4ajxVsptLFIe/MtW7asXqOavtZcmOno/NR49cwzzzQa39plsg/Uz3/+c7/339KlS2XIkCGSy2z3Qb9+/eTVV1/1UxQkpq985Sty9tln+//u1auXtIXj4IwzzvB7giYaotXbb7/tV5y51hCb6T7QfMkNG1wTjdMHxr/Kf/lWJqJx1JnUmZkeC9SbB1BvUm8q6s22g3qTejOT44A68wDqTOpMRZ0ZEq8VWLRokVdcXOw98MAD3uuvv+595zvf8Tp27Oht2bLF//ull17q3Xjjjcn4v//9715BQYF31113eW+88YY3Y8YMr7Cw0Hv11Ve9XGW7D26//XavqKjI+/3vf+99/PHHyWnPnj1eW9kHDU2YMMG74IILvFxmuw82btzotW/f3ps8ebL31ltveU888YR3xBFHeD/5yU+8trIP9PzXffDII4947733nve///u/3nHHHedddNFFXq7S83jdunX+pMX0nDlz/H9v2LDB/7t+ft0PCfq5y8rKvKlTp/pl4rx587xoNOotXbq0BT8FwkKdSZ2Z6bHQEPUm9Sb1JvVmW0C9Sb2ZyXHQEHUmdSZ1JnVmNrWKxlj1i1/8wuvdu7ffwDh06FDvpZdeSv5t5MiRfuGX6ne/+533mc98xo8/+eSTvSeffNLLdTb74Oijj/YbaRpO2jCVy2yPg3yrIDPZBytWrPCGDRvmX1wce+yx3k9/+lOvtrbWayv7IBaLebfddpvfAFtSUuL16tXL+973vud9+umnXq567rnn0p7fic+t/9X90HCZQYMG+ftMj4P777+/hbYezYE6kzoz02MhFfUm9Sb1JvVmW0G9Sb2ZyXGQijqTOpM6kzozmxz9v7B63QIAAAAAAAAAWknOWAAAAAAAAABoC2iMBQAAAAAAAIBmQGMsAAAAAAAAADQDGmMBAAAAAAAAoBnQGAsAAAAAAAAAzYDGWAAAAAAAAABoBjTGAgAAAAAAAEAzoDEWAAAAAAAAAJoBjbEAAAAAAAAA0AxojAUAAAAAAACAZkBjLAAAAAAAAAA0AxpjAQAAAAAAAEDC9/8DrLtIhaweoAQAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "# Run thermal solver\n", - "thermal_out = thermal_api.apply_jit(\n", + "# Run the thermal solver for a centered heat source\n", + "thermal_out = apply_tesseract(\n", + " thermal,\n", " {\n", " \"source_x\": jnp.float32(0.5),\n", " \"source_y\": jnp.float32(0.5),\n", " \"source_intensity\": jnp.float32(10.0),\n", - " \"source_width\": 0.1,\n", + " \"source_width\": np.float32(0.1),\n", " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", - " \"conductivity\": 1.0,\n", - " \"boundary_temp\": 0.0,\n", - " }\n", + " \"conductivity\": np.float32(1.0),\n", + " \"boundary_temp\": np.float32(0.0),\n", + " },\n", ")\n", "temperature = np.asarray(thermal_out[\"temperature\"])\n", "\n", - "# Run structural solver\n", - "structural_out = structural_api.apply_jit(\n", + "# Feed the temperature field into the structural solver\n", + "structural_out = apply_tesseract(\n", + " structural,\n", " {\n", " \"temperature\": thermal_out[\"temperature\"],\n", - " \"youngs_modulus\": 200.0,\n", - " \"poissons_ratio\": 0.3,\n", - " \"thermal_expansion\": 1e-3,\n", - " }\n", + " \"youngs_modulus\": np.float32(200.0),\n", + " \"poissons_ratio\": np.float32(0.3),\n", + " \"thermal_expansion\": np.float32(1e-3),\n", + " },\n", ")\n", "\n", "fig, axes = plt.subplots(1, 3, figsize=(14, 4))\n", @@ -362,24 +295,48 @@ }, { "cell_type": "markdown", + "id": "d2b18a38", "metadata": {}, "source": [ - "## 3. The design problem: thermoelastic inverse optimization\n", + "## Step 3: Set up the thermoelastic inverse problem\n", + "\n", + "Now we pose the inverse-design problem: **find the heat-source location and intensity that produce a set of target temperatures at four sensor locations, after the thermoelastic coupling has converged.**\n", "\n", - "**Problem**: Find the heat source location and intensity that produces desired temperatures at four sensor locations, after the thermoelastic coupling has converged.\n", + "This cannot be solved with the thermal solver alone. The displacement from thermal expansion deforms the geometry, which changes the temperature field, which changes the displacement, and so on. The two solvers must be iterated to a coupled equilibrium, and the gradients we need run through that entire iteration.\n", "\n", - "This can't be solved with the thermal solver alone \u2014 the displacement from thermal expansion changes the geometry, which changes the temperature field. You need gradients through the full coupled iteration.\n", + "We express the coupled equilibrium as a fixed-point iteration with `jax.lax.scan`: at each step the thermal solver runs on the current displacement, and the structural solver runs on the resulting temperature. The design variables are the source position $(x, y)$ and the log-intensity $\\log(q)$ (3 parameters), and the objective is the squared temperature error at the sensors:\n", "\n", - "**Design variables**: source position $(x, y)$ and log-intensity $\\log(q)$ (3 parameters).\n", + "$$\\mathcal{L}(\\theta) = \\sum_i \\left(T_{\\text{sensor}_i} - T_{\\text{target}_i}\\right)^2,$$\n", "\n", - "**Objective**: $\\sum_i (T_{\\text{sensor}_i} - T_{\\text{target}_i})^2$ evaluated after coupled convergence." + "evaluated after the coupling has converged." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, + "id": "080b7e06", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Sensor positions (approx):\n", + " (0.26, 0.26) -> T_target = 0.010\n", + " (0.26, 0.71) -> T_target = 0.020\n", + " (0.71, 0.26) -> T_target = 0.020\n", + " (0.71, 0.71) -> T_target = 0.050\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Objective at initial guess: 6.175695e-03\n" + ] + } + ], "source": [ "# Sensor locations (grid indices) and target temperatures\n", "SENSORS = [(8, 8), (8, 22), (22, 8), (22, 22)]\n", @@ -399,6 +356,11 @@ "\n", " params: [source_x, source_y, log_intensity]\n", " Returns: sum of squared temperature errors at sensor locations.\n", + "\n", + " Non-differentiable constants are passed as numpy (np.float32) rather than\n", + " JAX arrays. Inside lax.scan, JAX traces all array inputs uniformly and\n", + " cannot tell which are constants; keeping them as numpy arrays leaves them\n", + " opaque to the tracer, so the backward pass never tries to differentiate them.\n", " \"\"\"\n", " source_x, source_y, log_intensity = params[0], params[1], params[2]\n", " intensity = jnp.exp(log_intensity)\n", @@ -408,24 +370,26 @@ "\n", " def coupling_step(carry, _):\n", " _temp, disp = carry\n", - " thermal_out = thermal_api.apply_jit(\n", + " thermal_out = apply_tesseract(\n", + " thermal,\n", " {\n", " \"source_x\": source_x,\n", " \"source_y\": source_y,\n", " \"source_intensity\": intensity,\n", - " \"source_width\": jnp.float32(0.15),\n", + " \"source_width\": np.float32(0.15),\n", " \"displacement\": disp,\n", - " \"conductivity\": 1.0,\n", - " \"boundary_temp\": 0.0,\n", - " }\n", + " \"conductivity\": np.float32(1.0),\n", + " \"boundary_temp\": np.float32(0.0),\n", + " },\n", " )\n", - " structural_out = structural_api.apply_jit(\n", + " structural_out = apply_tesseract(\n", + " structural,\n", " {\n", " \"temperature\": thermal_out[\"temperature\"],\n", - " \"youngs_modulus\": 200.0,\n", - " \"poissons_ratio\": 0.3,\n", - " \"thermal_expansion\": 1e-3,\n", - " }\n", + " \"youngs_modulus\": np.float32(200.0),\n", + " \"poissons_ratio\": np.float32(0.3),\n", + " \"thermal_expansion\": np.float32(1e-3),\n", + " },\n", " )\n", " return (thermal_out[\"temperature\"], structural_out[\"displacement\"]), None\n", "\n", @@ -439,25 +403,38 @@ " return loss\n", "\n", "\n", - "# Test forward pass\n", + "# Test the forward pass\n", "p0 = jnp.array([0.2, 0.2, jnp.log(5.0)], dtype=jnp.float32)\n", "print(f\"\\nObjective at initial guess: {float(coupled_objective(p0)):.6e}\")" ] }, { "cell_type": "markdown", + "id": "f2853978", "metadata": {}, "source": [ - "## 4. End-to-end gradients through the coupled pipeline\n", + "## Step 4: Compute end-to-end gradients\n", "\n", - "The key moment: `jax.grad` differentiates through the entire coupled iteration \u2014 through both solvers, through `lax.scan`, automatically. No manual adjoint derivation, no monolithic rewrite." + "Because `apply_tesseract` exposes each Tesseract as a native JAX operation, `jax.grad` differentiates through the entire coupled iteration -- through both solvers and through `lax.scan` -- automatically. There is no manual adjoint to derive and no need to merge the solvers into one codebase." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, + "id": "0a6ee1ac", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Gradients at initial guess:\n", + " d(loss)/d(source_x) = 2.295040e-02\n", + " d(loss)/d(source_y) = 2.295040e-02\n", + " d(loss)/d(log_intensity) = 8.693030e-03\n" + ] + } + ], "source": [ "grad_fn = jax.grad(coupled_objective)\n", "\n", @@ -470,18 +447,31 @@ }, { "cell_type": "markdown", + "id": "4dc02fe9", "metadata": {}, "source": [ - "### Gradient validation against finite differences\n", + "### Validate the gradients against finite differences\n", "\n", - "For a rigorous audience, correctness proof is non-negotiable." + "To confirm the end-to-end gradients are correct, we compare them against a central finite-difference approximation of the same objective. The relative error should be small for all three design variables." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, + "id": "fb6b7b25", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " AD FD Rel. Error\n", + "d(loss)/d(source_x) 2.295040e-02 2.296176e-02 4.95e-04\n", + "d(loss)/d(source_y) 2.295040e-02 2.295477e-02 1.90e-04\n", + "d(loss)/d(log_intensity) 8.693030e-03 8.677598e-03 1.78e-03\n" + ] + } + ], "source": [ "eps = 1e-4\n", "fd_grads = []\n", @@ -501,22 +491,52 @@ }, { "cell_type": "markdown", + "id": "3a073ba8", "metadata": {}, "source": [ - "## 5. Optimization: gradient-based vs gradient-free\n", + "## Step 5: Optimize the design with gradients\n", "\n", - "We compare:\n", - "- **L-BFGS-B** (gradient-based, using our end-to-end gradients)\n", - "- **Nelder-Mead** (gradient-free)\n", - "\n", - "Both optimize 3 design variables: source position $(x, y)$ and log-intensity." + "We now solve the inverse problem with a gradient-based optimizer (L-BFGS-B from `scipy.optimize`), feeding it the end-to-end gradients we just validated. For comparison, we also run a gradient-free optimizer (Nelder-Mead) on the same problem. Both search over the same 3 design variables: source position $(x, y)$ and log-intensity." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, + "id": "28581cfa", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running L-BFGS-B (gradient-based)...\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Source: (0.673, 0.673)\n", + " Intensity: 2.73\n", + " Objective: 3.168823e-06\n", + " Evaluations: 29\n", + "\n", + "Running Nelder-Mead (gradient-free)...\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Source: (0.673, 0.673)\n", + " Intensity: 2.73\n", + " Objective: 3.168773e-06\n", + " Evaluations: 250\n", + "\n", + "Speedup: 250/29 = 8.6x fewer evaluations with gradients\n" + ] + } + ], "source": [ "eval_history_grad = []\n", "eval_history_free = []\n", @@ -574,9 +594,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, + "id": "0242ec0f", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAAHqCAYAAACZcdjsAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjksIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvJkbTWQAAAAlwSFlzAAAPYQAAD2EBqD+naQAAnxZJREFUeJzt3Qd4U2XbB/A76aQtbYGWvQVEtiIqLlBQcOPEjai4QMGtrwru+amgorxuceLE14UKMhRREEQFBNlDWkopdNKVnO/6P+EkJ7NJmzTr/7uu0OTkJDlJTsu5z/3c92PSNE0TIiIiIiKiBjA35MFEREREREQMLIiIiIiIKCiYsSAiIiIiogZjYEFERERERA3GwIKIiIiIiBqMgQURERERETUYAwsiIiIiImowBhZERERERNRgDCyIiIiIiKjBGFgQUdBcccUV0rlzZ6dlJpNJ7r///oj6lN988021Xb/99ptEk6FDh6oLRc++BuvXr5eTTz5ZsrKy1DbOnj1b4k2wv5stW7ao58TvcmMK1+sSRQsGFkQxYPPmzTJhwgTp0aOHpKWlqUuvXr1k/Pjx8ueff0qse++992Tq1Knh3gyKA/XZ18aMGSN//fWXPPLII/L222/L4YcfLrHo66+/jsjArj74N4WofhLr+TgiihBffvmljB49WhITE+WSSy6R/v37i9lslrVr18qnn34qL730kgo8OnXqFJbt279/v9q2UB8ErFq1SiZNmhTS16HIFon7GrZpyZIlcs8996jgP5YhsJg+fbrH4CLY3w3+nuE5k5KSpDG/51C/LlG0Y2BBFMU2btwoF154ofrPbt68edKmTRun+5944gl58cUXVaDhS3l5uaSnp4dkG1NTU0PyvBSd4m1f2717t/qZnZ0d1s8m3IL93WA4Uji+73C9LlG04FAooij25JNPqoORN954wy2oAJwhvOmmm6RDhw5OY9MzMjJUUHLqqadK06ZNVaYDfvzxRzn//POlY8eOkpKSoh538803qzN0rjBOvE+fPuo/Wfz87LPP/B5b/e+//8qVV14prVq1Uq/Tu3dvef31153WWbBggXrshx9+qIaQtG/fXr3WsGHDZMOGDfb1UHPw1VdfydatW9X6uLiOvfemoqJCrr32WmnRooVkZmbK5ZdfLnv37nVa5/PPP5fTTjtN2rZtq7b1oIMOkoceekgsFovbOPpzzz1XWrdurbYT24ugr7i42Gm9d955RwYOHChNmjSR5s2bq3W2b9/utm0vv/yyei2sd8QRR6jvxh/4Lk444QS35VarVdq1ayfnnXeefdkHH3ygtgX7AN5/3759Zdq0aXW+xp49e+Syyy5Tj8EBM4b6/PHHH25jz+N9X8O26JnC22+/3Wl93Ifba9askYsvvliaNWsmxx57bMD7ya+//iojR45U9RsYAjlkyBBZvHix+KOgoECuuuoq9dng/SLb+dZbb3msKfi///s/efbZZ9X7wTbhdXBG3/hdI1uhfw/6xdt3o7//f/75Ry699FK1/bm5uXLfffeJpmnqvZ511llqH8Pv1NNPP+1xu/T9Tf8OPV2M35E/v8++vmdvNRY//PCDHHfccSowxO8Etv3vv/92Wkd/z9in8HlhPbzvsWPHqr9FRLGAGQuiKB8G1a1bNznyyCMDelxtba2MGDFCHcjggAEHJPDRRx+p/+Cuv/56dbC9dOlSef7552XHjh3qPt13332nDqJRx/HYY4+pA03854gDsrrs2rVLjjrqKPUfLIaG4GDim2++UQc4JSUlbkMPHn/8cZVxue2229RBOoIpHJzigAowxATLsY048AEczPoDr4//3PEf/rp169SwMRxM6AcpgAMIPN8tt9yifuIAYvLkyWpbn3rqKbVOdXW1+jyrqqrkxhtvVAdCOKDF97Nv3z518AA4aMWB0wUXXCBXX321OpuNz/f444+X33//3X5W+7XXXlMBz9FHH60+j02bNsmZZ56pDjCNQaInGBaH95Ofn6+2Q/fTTz/Jzp071QEqfP/993LRRRepg2dktgAHQjgonThxotfnR4ByxhlnqH0D+0nPnj3VwRqCC0/ieV8755xz1HeKgAmfNYIr1/URXHXv3l0effRRdUAdyH6CffGUU05RAciUKVPUtuMkw4knnqgCNwSk3iCAwwE0DnLx2XTp0kV97jjgxT7rug/MnDlTSktLVd1WZWWlCkDxOqgdQWCC/RX7F/Yr1JH4C/vrIYccoj57HMw//PDDaj//73//q54f++a7776rvpNBgwapz8ATPIfr6+J94Pe2ZcuW9mX+/D4H+j3PnTtXfQ9du3ZVv3v4bPF9HXPMMbJixQq34BPfKz5v7M+4/9VXX1XbqP8eEkU1jYiiUnFxMY5CtFGjRrndt3fvXm337t32S0VF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IuIhY2GstyAiIopFV1xxhTroe/zxx52W4yAQy6PpgN7T+4DTTjtN3Xf//fdLJPjf//4nu3btkgsvvFDdLioqkhtvvFEOPvhgNfN3x44d5aabbpLi4mKnx+E9uF4++OADp3UWLFgghx12mKSkpEi3bt3kzTfflGiSnJwst912m9x5552N8noMLLwYP368rFmzRpYtW9YoX0SsqnHKWLDGgoiIYl9qaqo88cQTsnfvXol0OKPtTYcOHdwOpP/991+ZN2+etGnTRiLFc889J2PHjhWz2XZYu3PnTnX5v//7P1m1apV6D3PmzJGrrrrK7bFvvPGG5OXl2S+jRo2y37d582YVRJ1wwgmycuVKlTm5+uqr5dtvv5Vocskll8hPP/0kq1evDvlrMbCgkDIOf2KNBRERNbp920V2rnRccDvEhg8fLq1bt5bHHnvM53o42DvuuOPUWXUcxOOsenl5udf1169fL0OGDFGBC0ZVfP/9927rbN++XS644ALJzs6W5s2by1lnnSVbtmxxyqjg4PmRRx6Rtm3bqrP63px++ulSWFgoixcvti9766235OSTT5aWLVs6rVtVVaXOjLdr107S09PlyCOPVGf7dXv27JGLLrpI3Z+WliZ9+/aV999/3+k58N4vv/xyycjIUIHL008/LXXZvXu3/PDDD3LGGWfYl/Xp00c++eQTteyggw6SE088Ub3fL774Qmpra50ej88J35V+wWermzFjhnTp0kVtxyGHHCITJkyQ8847T5599tl6f6//+c9/1Gfjqn///vLggw+q6zipfdJJJ0lOTo5kZWWp73zFihU+g0NsGz4zbH+nTp2c9r1mzZrJMccc45aNCQUGFhRSnHmbiIjCBkHECwNFXh7iuOB2iIOLhIQEefTRR+X555+XHTt2eFxn48aNMnLkSDn33HPlzz//lFmzZqkDUhwgemK1WlXAgKEtv/76qzrodR3eUlNTIyNGjJCmTZvKjz/+qAICHKTjdYyZCWQc1q1bpwKTL7/80uv7wGvhbDfO6utw9v/KK690WxfbvWTJEnXwivdz/vnnq9dFMASVlZUycOBA+eqrr1QW4ZprrpHLLrtMli5dan+O22+/XRYuXCiff/65fPfddyow8XVADfjMEKjgwN8XDIPKzMyUxMREtxEqOIA/4ogj5PXXXxdNc5wQxftBkGiEzxfLvdlYx/eK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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "fig, ax = plt.subplots(figsize=(8, 5))\n", "ax.semilogy(\n", @@ -604,31 +636,45 @@ }, { "cell_type": "markdown", + "id": "7fbd7f5b", "metadata": {}, "source": [ - "## 6. Visualize the optimized design\n", + "## Step 6: Visualize the optimized design\n", "\n", - "Show the converged temperature field with sensor locations and targets." + "Finally, we run the optimized design through the thermal solver once more and plot the resulting temperature field, overlaying the sensor locations with their achieved and target temperatures and the recovered source position." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, + "id": "63e93ffe", "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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zKgSERERkSExo0pERETkEDOqemFGlYiIiIgMiYEqERERERkSb/0TEREROcRb/3phRpWIiIiIDIkZVSIiIiKHOISqXphRJSIiIiJDypKRI/RMKVzW3Qnv76Xz8iKbxuWzO6EMOXVe3hnryOWEMuTReXmRV+Py+dPBZ3BGGTw8DXBya/2SinFCGSK0LR4Vrr0IdzQuH6C9CLiicflLTiiDM74ntQhzQi5Tf9EuLokxPqURMaNKRERERIaUYTOqREREREnDVv96YUaViIiIiAyJGVUiIiIih5hR1QszqkRERERkSMyoEhERETnEflT1wowqERERERkSM6pEREREDrGOql6YUSUiIiIiQ2JGlYiIiMghZlT1wowqERERERkSM6pEREREDjGjqhdmVImIiIjIkJhRJSIiInKIGVW9MKNKRERERIaUYTOqbgAypXBZdye8v5fG5bM5oQw5NS6fywll0LoOHyeUIa/G5fM7oQwFNS5fyAllKKJx+aIal3fTuhGcsSGcsTPzGODk9nDCIDxahWtb3OO29iIUuq5x+YtOKMN9fb+nnSFU4/KBTshl6o8jU+mFGVUiIiIiMqQMm1ElIiIiSnpeV+7Fuoox8sZGxIwqERERERkSA1UiIiIiMiTe+iciIiJyiLf+9cKMKhEREREZEjOqRERERA4xo6oXZlSJiIiIyJCYUSUiIiJyiB3+64UZVSIiIiIyJGZUiYiIiBKto+rK3B47/E8IM6pEREREZEjMqBIRERE5xIyqXphRJSIiIiJDYkaViIiIyCFmVPXCjCoRERERGVKWjByhpzRK93DC+7trXD67E8qQU+PyuZxQhjwal8/vhDJoXUcRJ5ShuM7LC2+tO6OkxuV9NS7vjDIUMcABlcsAXzAxTihDqMblA5xQhksalz+lvQiFTmhcwfW0vyuypYv28NGWhyvXT/Ywo0pEREREhpRhM6pEREREScORqfTCjCoRERERGRIzqkRERESJ1pTN5MJtZIyauEbEjCoRERERGRIDVSIiIqJEM56ufiTftGnT4OvrCy8vL9SrVw/79+93OP+qVatQsWJFNX+1atWwefPmOK+//fbbyJQpU5xH8+bNdT02GKgSERERpTErVqyAv78/RowYgcOHD6NGjRpo1qwZbt68aXf+PXv2oGPHjujRoweOHDmCNm3aqMeJE3H7UJPA9MaNG7GP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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ - "# Run the optimized design through the pipeline\n", + "# Run the optimized design through the thermal solver\n", "opt = result_grad.x\n", - "thermal_opt = thermal_api.apply_jit(\n", + "thermal_opt = apply_tesseract(\n", + " thermal,\n", " {\n", " \"source_x\": jnp.float32(opt[0]),\n", " \"source_y\": jnp.float32(opt[1]),\n", " \"source_intensity\": jnp.float32(np.exp(opt[2])),\n", - " \"source_width\": jnp.float32(0.15),\n", + " \"source_width\": np.float32(0.15),\n", " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", - " \"conductivity\": 1.0,\n", - " \"boundary_temp\": 0.0,\n", - " }\n", + " \"conductivity\": np.float32(1.0),\n", + " \"boundary_temp\": np.float32(0.0),\n", + " },\n", ")\n", "temp_opt = np.asarray(thermal_opt[\"temperature\"])\n", "\n", @@ -681,91 +727,45 @@ }, { "cell_type": "markdown", + "id": "afa3d626", "metadata": {}, "source": [ - "## 7. Modularity: swap a solver, change nothing else\n", - "\n", - "We replace the thermal solver with a coarser version (fewer Jacobi iterations \u2014 faster but less accurate). The optimization code is identical. Only the solver changes." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Swap in a \"fast\" thermal solver (100 vs 500 Jacobi iterations)\n", - "# In practice: point to a different Tesseract image\n", - "original_solve = thermal_api._solve_heat_jacobi\n", - "\n", - "\n", - "def fast_solve(source, conductivity, boundary_temp, n_iters=100):\n", - " return original_solve(source, conductivity, boundary_temp, n_iters=n_iters)\n", + "## Step 7: Constant-memory gradients with implicit differentiation\n", "\n", + "The unrolled `lax.scan` above stores every intermediate state for backpropagation, so memory grows as $\\mathcal{O}(N)$ in the number of coupling iterations. For large problems -- fine meshes, many iterations -- that becomes the bottleneck.\n", "\n", - "thermal_api._solve_heat_jacobi = fast_solve\n", + "*Implicit differentiation* avoids it. At the converged fixed point $(T^*, D^*) = G(T^*, D^*, \\theta)$, the implicit function theorem gives the sensitivity without replaying the iteration: the backward pass solves a single linear system instead of backpropagating through $N$ steps.\n", "\n", - "# Same optimization code, same objective, same grad_fn\n", - "eval_history_swapped = []\n", + "Concretely, if $v = \\partial \\mathcal{L} / \\partial (T^*, D^*)$ is the loss gradient with respect to the fixed point, then\n", "\n", + "$$\\lambda = \\left(I - \\partial G / \\partial (T, D)\\right)^{-T} v, \\qquad \\partial \\mathcal{L} / \\partial \\theta = \\lambda^\\top \\, \\partial G / \\partial \\theta.$$\n", "\n", - "def objective_and_grad_swapped(x):\n", - " p = jnp.array(x, dtype=jnp.float32)\n", - " obj = coupled_objective(p)\n", - " g = grad_fn(p)\n", - " eval_history_swapped.append(float(obj))\n", - " return float(obj), np.array([float(g[i]) for i in range(3)])\n", - "\n", - "\n", - "print(\"Running L-BFGS-B with swapped (fast) thermal solver...\")\n", - "result_swapped = minimize(\n", - " objective_and_grad_swapped,\n", - " x0,\n", - " method=\"L-BFGS-B\",\n", - " jac=True,\n", - " bounds=bounds,\n", - " options={\"maxiter\": 100},\n", - ")\n", - "print(f\" Source: ({result_swapped.x[0]:.3f}, {result_swapped.x[1]:.3f})\")\n", - "print(f\" Intensity: {np.exp(result_swapped.x[2]):.2f}\")\n", - "print(f\" Objective: {result_swapped.fun:.6e}\")\n", - "print(f\" Evaluations: {len(eval_history_swapped)}\")\n", - "print(\n", - " f\"\\n (Original solver found: ({result_grad.x[0]:.3f}, {result_grad.x[1]:.3f}), q={np.exp(result_grad.x[2]):.2f})\"\n", - ")\n", - "\n", - "thermal_api._solve_heat_jacobi = original_solve # restore" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 8. Implicit differentiation: O(1) memory gradients via the implicit function theorem\n", - "\n", - "The unrolled `lax.scan` approach above stores all intermediate states for backpropagation \u2014 memory scales as O(N) in coupling iterations. For large-scale problems (fine meshes, many iterations), this becomes the bottleneck.\n", - "\n", - "**Implicit differentiation** avoids this entirely. The key insight: at the converged fixed point $(T^*, D^*) = G(T^*, D^*, \\theta)$, the implicit function theorem gives the sensitivity without replaying the iteration. The backward pass solves a single linear system instead of backpropagating through N steps.\n", - "\n", - "Concretely, if $v = \\partial L / \\partial (T^*, D^*)$ is the loss gradient w.r.t. the fixed point, then:\n", - "\n", - "$$\\lambda = (I - \\partial G / \\partial (T, D))^{-T} v$$\n", - "$$\\partial L / \\partial \\theta = \\lambda^T \\cdot \\partial G / \\partial \\theta$$\n", - "\n", - "We solve for $\\lambda$ via fixed-point iteration on the adjoint equation \u2014 the same structure as the forward solve, but linear." + "We solve for $\\lambda$ by fixed-point iteration on the adjoint equation -- the same structure as the forward solve, but linear. We wrap this in a `jax.custom_vjp` so that `jax.grad` uses the implicit backward pass automatically, while the forward pass still composes the two Tesseracts through `apply_tesseract`." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, + "id": "ba1d047e", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Forward pass comparison:\n", + " Unrolled: 6.1756954528e-03\n", + " Implicit: 6.1756954528e-03\n", + " Match: True\n" + ] + } + ], "source": [ "def coupled_objective_implicit(params):\n", " \"\"\"Same inverse problem, but differentiated via the implicit function theorem.\n", "\n", " Forward pass: iterate G to convergence (no scan intermediates stored for AD).\n", - " Backward pass: solve adjoint equation (I - dG/d(T,D))^T \u03bb = v via fixed-point iteration.\n", + " Backward pass: solve adjoint equation (I - dG/d(T,D))^T λ = v via fixed-point iteration.\n", " \"\"\"\n", " source_x, source_y, log_intensity = params[0], params[1], params[2]\n", " intensity = jnp.exp(log_intensity)\n", @@ -773,28 +773,30 @@ " def G(temp_disp, params_inner):\n", " \"\"\"One coupling step: (temp, disp) -> (new_temp, new_disp).\n", "\n", - " params_inner is (source_x, source_y, intensity) \u2014 the differentiable parameters.\n", + " params_inner is (source_x, source_y, intensity) — the differentiable parameters.\n", " \"\"\"\n", " _temp, disp = temp_disp\n", " sx, sy, q = params_inner\n", - " thermal_out = thermal_api.apply_jit(\n", + " thermal_out = apply_tesseract(\n", + " thermal,\n", " {\n", " \"source_x\": sx,\n", " \"source_y\": sy,\n", " \"source_intensity\": q,\n", - " \"source_width\": jnp.float32(0.15),\n", + " \"source_width\": np.float32(0.15),\n", " \"displacement\": disp,\n", - " \"conductivity\": 1.0,\n", - " \"boundary_temp\": 0.0,\n", - " }\n", + " \"conductivity\": np.float32(1.0),\n", + " \"boundary_temp\": np.float32(0.0),\n", + " },\n", " )\n", - " structural_out = structural_api.apply_jit(\n", + " structural_out = apply_tesseract(\n", + " structural,\n", " {\n", " \"temperature\": thermal_out[\"temperature\"],\n", - " \"youngs_modulus\": 200.0,\n", - " \"poissons_ratio\": 0.3,\n", - " \"thermal_expansion\": 1e-3,\n", - " }\n", + " \"youngs_modulus\": np.float32(200.0),\n", + " \"poissons_ratio\": np.float32(0.3),\n", + " \"thermal_expansion\": np.float32(1e-3),\n", + " },\n", " )\n", " return (thermal_out[\"temperature\"], structural_out[\"displacement\"])\n", "\n", @@ -820,12 +822,12 @@ " def solve_bwd(res, g):\n", " \"\"\"Implicit differentiation backward pass.\n", "\n", - " g = (v_temp, v_disp) \u2014 cotangents w.r.t. the fixed point.\n", + " g = (v_temp, v_disp) — cotangents w.r.t. the fixed point.\n", "\n", - " We need to solve: (I - dG/d(T,D))^T \u03bb = v for \u03bb,\n", - " then compute: dL/d\u03b8 = \u03bb^T \u00b7 dG/d\u03b8.\n", + " We need to solve: (I - dG/d(T,D))^T λ = v for λ,\n", + " then compute: dL/dθ = λ^T · dG/dθ.\n", "\n", - " We solve for \u03bb by iterating: \u03bb_{k+1} = v + (dG/d(T,D))^T \u03bb_k.\n", + " We solve for λ by iterating: λ_{k+1} = v + (dG/d(T,D))^T λ_k.\n", " This converges if the forward iteration is contractive.\n", " \"\"\"\n", " (fixed_temp, fixed_disp), params_inner = res\n", @@ -835,13 +837,13 @@ " def G_state(temp_disp):\n", " return G(temp_disp, params_inner)\n", "\n", - " # Solve adjoint: \u03bb = v + (dG/d(T,D))^T \u03bb via fixed-point iteration\n", + " # Solve adjoint: λ = v + (dG/d(T,D))^T λ via fixed-point iteration\n", " def adjoint_step(lam, _):\n", " lam_temp, lam_disp = lam\n", - " # Compute (dG/d(T,D))^T @ \u03bb via VJP\n", + " # Compute (dG/d(T,D))^T @ λ via VJP\n", " _, vjp_G_state = jax.vjp(G_state, (fixed_temp, fixed_disp))\n", " dGT_lam = vjp_G_state((lam_temp, lam_disp))[0]\n", - " # \u03bb_{k+1} = v + (dG/d(T,D))^T \u03bb_k\n", + " # λ_{k+1} = v + (dG/d(T,D))^T λ_k\n", " new_lam_temp = v_temp + dGT_lam[0]\n", " new_lam_disp = v_disp + dGT_lam[1]\n", " return (new_lam_temp, new_lam_disp), None\n", @@ -852,7 +854,7 @@ " adjoint_step, lam_init, None, length=N_ADJOINT_ITERS\n", " )\n", "\n", - " # Now compute dL/d\u03b8 = \u03bb^T \u00b7 dG/d\u03b8 via VJP of G w.r.t. params\n", + " # Now compute dL/dθ = λ^T · dG/dθ via VJP of G w.r.t. params\n", " def G_params(p):\n", " return G((fixed_temp, fixed_disp), p)\n", "\n", @@ -882,9 +884,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, + "id": "eeed02dd", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Unrolled Implicit FD Impl vs FD\n", + "d(loss)/d(source_x) 2.295040e-02 2.295042e-02 2.296176e-02 4.94e-04\n", + "d(loss)/d(source_y) 2.295040e-02 2.295042e-02 2.295477e-02 1.90e-04\n", + "d(loss)/d(log_intensity) 8.693030e-03 8.693032e-03 8.677598e-03 1.78e-03\n" + ] + } + ], "source": [ "# Compare gradients: implicit vs unrolled vs finite differences\n", "grad_implicit = jax.grad(coupled_objective_implicit)(p0)\n", @@ -914,2372 +928,63 @@ }, { "cell_type": "markdown", + "id": "3ffc182c", "metadata": {}, "source": [ - "#", - "#", - "#", - " ", - "M", - "e", - "m", - "o", - "r", - "y", - " ", - "s", - "c", - "a", - "l", - "i", - "n", - "g", - ":", - " ", - "w", - "h", - "y", - " ", - "t", - "h", - "i", - "s", - " ", - "m", - "a", - "t", - "t", - "e", - "r", - "s", - "\n", - "\n", - "W", - "i", - "t", - "h", - " ", - "t", - "h", - "e", - " ", - "u", - "n", - "r", - "o", - "l", - "l", - "e", - "d", - " ", - "a", - "p", - "p", - "r", - "o", - "a", - "c", - "h", - ",", - " ", - "J", - "A", - "X", - " ", - "s", - "t", - "o", - "r", - "e", - "s", - " ", - "t", - "h", - "e", - " ", - "f", - "u", - "l", - "l", - " ", - "s", - "t", - "a", - "t", - "e", - " ", - "a", - "t", - " ", - "e", - "v", - "e", - "r", - "y", - " ", - "c", - "o", - "u", - "p", - "l", - "i", - "n", - "g", - " ", - "i", - "t", - "e", - "r", - "a", - "t", - "i", - "o", - "n", - " ", - "f", - "o", - "r", - " ", - "b", - "a", - "c", - "k", - "p", - "r", - "o", - "p", - "a", - "g", - "a", - "t", - "i", - "o", - "n", - ".", - " ", - "M", - "e", - "m", - "o", - "r", - "y", - " ", - "c", - "o", - "s", - "t", - ":", - " ", - "*", - "*", - "O", - "(", - "N", - " ", - "\u00d7", - " ", - "s", - "t", - "a", - "t", - "e", - "_", - "s", - "i", - "z", - "e", - ")", - "*", - "*", - ".", - "\n", - "\n", - "W", - "i", - "t", - "h", - " ", - "i", - "m", - "p", - "l", - "i", - "c", - "i", - "t", - " ", - "d", - "i", - "f", - "f", - "e", - "r", - "e", - "n", - "t", - "i", - "a", - "t", - "i", - "o", - "n", - ",", - " ", - "t", - "h", - "e", - " ", - "f", - "o", - "r", - "w", - "a", - "r", - "d", - " ", - "p", - "a", - "s", - "s", - " ", - "r", - "u", - "n", - "s", - " ", - "t", - "o", - " ", - "c", - "o", - "n", - "v", - "e", - "r", - "g", - "e", - "n", - "c", - "e", - " ", - "a", - "n", - "d", - " ", - "d", - "i", - "s", - "c", - "a", - "r", - "d", - "s", - " ", - "i", - "n", - "t", - "e", - "r", - "m", - "e", - "d", - "i", - "a", - "t", - "e", - "s", - ".", - " ", - "T", - "h", - "e", - " ", - "b", - "a", - "c", - "k", - "w", - "a", - "r", - "d", - " ", - "p", - "a", - "s", - "s", - " ", - "s", - "o", - "l", - "v", - "e", - "s", - " ", - "t", - "h", - "e", - " ", - "a", - "d", - "j", - "o", - "i", - "n", - "t", - " ", - "e", - "q", - "u", - "a", - "t", - "i", - "o", - "n", - " ", - "a", - "t", - " ", - "t", - "h", - "e", - " ", - "f", - "i", - "x", - "e", - "d", - " ", - "p", - "o", - "i", - "n", - "t", - " ", - "o", - "n", - "l", - "y", - " ", - "\u2014", - " ", - "n", - "o", - " ", - "r", - "e", - "p", - "l", - "a", - "y", - " ", - "o", - "f", - " ", - "t", - "h", - "e", - " ", - "i", - "t", - "e", - "r", - "a", - "t", - "i", - "o", - "n", - ".", - " ", - "M", - "e", - "m", - "o", - "r", - "y", - " ", - "c", - "o", - "s", - "t", - ":", - " ", - "*", - "*", - "O", - "(", - "s", - "t", - "a", - "t", - "e", - "_", - "s", - "i", - "z", - "e", - ")", - "*", - "*", - " ", - "r", - "e", - "g", - "a", - "r", - "d", - "l", - "e", - "s", - "s", - " ", - "o", - "f", - " ", - "N", - ".", - "\n", - "\n", - "F", - "o", - "r", - " ", - "t", - "h", - "i", - "s", - " ", - "3", - "0", - "\u00d7", - "3", - "0", - " ", - "d", - "e", - "m", - "o", - " ", - "t", - "h", - "e", - " ", - "d", - "i", - "f", - "f", - "e", - "r", - "e", - "n", - "c", - "e", - " ", - "i", - "s", - " ", - "n", - "e", - "g", - "l", - "i", - "g", - "i", - "b", - "l", - "e", - ".", - " ", - "F", - "o", - "r", - " ", - "p", - "r", - "o", - "d", - "u", - "c", - "t", - "i", - "o", - "n", - "-", - "s", - "c", - "a", - "l", - "e", - " ", - "p", - "r", - "o", - "b", - "l", - "e", - "m", - "s", - " ", - "(", - "m", - "i", - "l", - "l", - "i", - "o", - "n", - "-", - "n", - "o", - "d", - "e", - " ", - "m", - "e", - "s", - "h", - "e", - "s", - ",", - " ", - "h", - "u", - "n", - "d", - "r", - "e", - "d", - "s", - " ", - "o", - "f", - " ", - "c", - "o", - "u", - "p", - "l", - "i", - "n", - "g", - " ", - "i", - "t", - "e", - "r", - "a", - "t", - "i", - "o", - "n", - "s", - ")", - ",", - " ", - "i", - "t", - "'", - "s", - " ", - "t", - "h", - "e", - " ", - "d", - "i", - "f", - "f", - "e", - "r", - "e", - "n", - "c", - "e", - " ", - "b", - "e", - "t", - "w", - "e", - "e", - "n", - " ", - "\"", - "f", - "i", - "t", - "s", - " ", - "i", - "n", - " ", - "G", - "P", - "U", - " ", - "m", - "e", - "m", - "o", - "r", - "y", - "\"", - " ", - "a", - "n", - "d", - " ", - "\"", - "d", - "o", - "e", - "s", - "n", - "'", - "t", - "\"", - "." + "### Why this matters: memory scaling\n", + "\n", + "With the unrolled approach, JAX stores the full state at every coupling iteration for backpropagation, so memory scales as $\\mathcal{O}(N \\times \\text{state size})$.\n", + "\n", + "With implicit differentiation, the forward pass runs to convergence and discards the intermediates; the backward pass solves the adjoint equation at the fixed point only, with no replay of the iteration. Memory scales as $\\mathcal{O}(\\text{state size})$, independent of $N$.\n", + "\n", + "For this 30×30 demo the difference is negligible, but for production-scale problems -- large meshes and many coupling iterations -- it is what keeps the backward pass within the available memory." ] }, { "cell_type": "markdown", + "id": "0f1e401b", "metadata": {}, "source": [ - "#", - "#", - " ", - "S", - "u", - "m", - "m", - "a", - "r", - "y", - "\n", - "\n", - "|", - " ", - "W", - "h", - "a", - "t", - " ", - "|", - " ", - "H", - "o", - "w", - " ", - "|", - "\n", - "|", - "-", - "-", - "-", - "|", - "-", - "-", - "-", - "|", - "\n", - "|", - " ", - "E", - "a", - "c", - "h", - " ", - "s", - "o", - "l", - "v", - "e", - "r", - " ", - "i", - "s", - " ", - "i", - "n", - "d", - "e", - "p", - "e", - "n", - "d", - "e", - "n", - "t", - " ", - "|", - " ", - "S", - "e", - "p", - "a", - "r", - "a", - "t", - "e", - " ", - "`", - "t", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - "_", - "a", - "p", - "i", - ".", - "p", - "y", - "`", - ",", - " ", - "s", - "e", - "p", - "a", - "r", - "a", - "t", - "e", - " ", - "c", - "o", - "n", - "t", - "a", - "i", - "n", - "e", - "r", - ",", - " ", - "s", - "e", - "p", - "a", - "r", - "a", - "t", - "e", - " ", - "t", - "e", - "a", - "m", - " ", - "|", - "\n", - "|", - " ", - "T", - "w", - "o", - "-", - "w", - "a", - "y", - " ", - "c", - "o", - "u", - "p", - "l", - "i", - "n", - "g", - " ", - "|", - " ", - "`", - "j", - "a", - "x", - ".", - "l", - "a", - "x", - ".", - "s", - "c", - "a", - "n", - "`", - " ", - "o", - "v", - "e", - "r", - " ", - "a", - "l", - "t", - "e", - "r", - "n", - "a", - "t", - "i", - "n", - "g", - " ", - "s", - "o", - "l", - "v", - "e", - "r", - " ", - "c", - "a", - "l", - "l", - "s", - " ", - "|", - "\n", - "|", - " ", - "E", - "n", - "d", - "-", - "t", - "o", - "-", - "e", - "n", - "d", - " ", - "g", - "r", - "a", - "d", - "i", - "e", - "n", - "t", - "s", - " ", - "|", - " ", - "`", - "j", - "a", - "x", - ".", - "g", - "r", - "a", - "d", - "`", - " ", - "\u2014", - " ", - "J", - "A", - "X", - " ", - "h", - "a", - "n", - "d", - "l", - "e", - "s", - " ", - "t", - "h", - "e", - " ", - "c", - "h", - "a", - "i", - "n", - " ", - "r", - "u", - "l", - "e", - " ", - "t", - "h", - "r", - "o", - "u", - "g", - "h", - " ", - "t", - "h", - "e", - " ", - "c", - "o", - "u", - "p", - "l", - "e", - "d", - " ", - "i", - "t", - "e", - "r", - "a", - "t", - "i", - "o", - "n", - " ", - "|", - "\n", - "|", - " ", - "G", - "r", - "a", - "d", - "i", - "e", - "n", - "t", - " ", - "c", - "o", - "r", - "r", - "e", - "c", - "t", - "n", - "e", - "s", - "s", - " ", - "|", - " ", - "V", - "a", - "l", - "i", - "d", - "a", - "t", - "e", - "d", - " ", - "a", - "g", - "a", - "i", - "n", - "s", - "t", - " ", - "f", - "i", - "n", - "i", - "t", - "e", - " ", - "d", - "i", - "f", - "f", - "e", - "r", - "e", - "n", - "c", - "e", - "s", - " ", - "|", - "\n", - "|", - " ", - "I", - "m", - "p", - "l", - "i", - "c", - "i", - "t", - " ", - "d", - "i", - "f", - "f", - "e", - "r", - "e", - "n", - "t", - "i", - "a", - "t", - "i", - "o", - "n", - " ", - "|", - " ", - "`", - "j", - "a", - "x", - ".", - "c", - "u", - "s", - "t", - "o", - "m", - "_", - "v", - "j", - "p", - "`", - " ", - "+", - " ", - "a", - "d", - "j", - "o", - "i", - "n", - "t", - " ", - "s", - "o", - "l", - "v", - "e", - " ", - "f", - "o", - "r", - " ", - "O", - "(", - "1", - ")", - " ", - "m", - "e", - "m", - "o", - "r", - "y", - " ", - "|", - "\n", - "|", - " ", - "S", - "o", - "l", - "v", - "e", - "r", - " ", - "s", - "w", - "a", - "p", - "p", - "i", - "n", - "g", - " ", - "|", - " ", - "C", - "h", - "a", - "n", - "g", - "e", - " ", - "t", - "h", - "e", - " ", - "T", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - " ", - "r", - "e", - "f", - "e", - "r", - "e", - "n", - "c", - "e", - ",", - " ", - "o", - "p", - "t", - "i", - "m", - "i", - "z", - "a", - "t", - "i", - "o", - "n", - " ", - "c", - "o", - "d", - "e", - " ", - "u", - "n", - "c", - "h", - "a", - "n", - "g", - "e", - "d", - " ", - "|", - "\n", - "\n", - "#", - "#", - "#", - " ", - "W", - "h", - "a", - "t", - "'", - "s", - " ", - "n", - "e", - "x", - "t", - "\n", - "\n", - "-", - " ", - "*", - "*", - "P", - "r", - "o", - "d", - "u", - "c", - "t", - "i", - "o", - "n", - " ", - "d", - "e", - "p", - "l", - "o", - "y", - "m", - "e", - "n", - "t", - "*", - "*", - ":", - " ", - "B", - "u", - "i", - "l", - "d", - " ", - "a", - "n", - "d", - " ", - "s", - "e", - "r", - "v", - "e", - " ", - "T", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - "s", - " ", - "a", - "s", - " ", - "D", - "o", - "c", - "k", - "e", - "r", - " ", - "c", - "o", - "n", - "t", - "a", - "i", - "n", - "e", - "r", - "s", - ",", - " ", - "c", - "o", - "m", - "p", - "o", - "s", - "e", - " ", - "v", - "i", - "a", - " ", - "`", - "t", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - "-", - "j", - "a", - "x", - "`", - "'", - "s", - " ", - "`", - "a", - "p", - "p", - "l", - "y", - "_", - "t", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - "`", - "\n", - "-", - " ", - "*", - "*", - "S", - "c", - "a", - "l", - "e", - " ", - "u", - "p", - "*", - "*", - ":", - " ", - "L", - "a", - "r", - "g", - "e", - "r", - " ", - "m", - "e", - "s", - "h", - "e", - "s", - ",", - " ", - "m", - "o", - "r", - "e", - " ", - "c", - "o", - "u", - "p", - "l", - "i", - "n", - "g", - " ", - "i", - "t", - "e", - "r", - "a", - "t", - "i", - "o", - "n", - "s", - ",", - " ", - "G", - "P", - "U", - " ", - "a", - "c", - "c", - "e", - "l", - "e", - "r", - "a", - "t", - "i", - "o", - "n" + "## Takeaways\n", + "\n", + "In this tutorial, we composed two independent physics Tesseracts into a two-way coupled pipeline and solved a thermoelastic inverse-design problem with end-to-end gradients. The key points:\n", + "\n", + "1. **Independent solvers, composed.** The thermal and structural solvers are separate Tesseracts -- separate `tesseract_api.py`, separate container, separate dependencies. Tesseract-JAX wires them into one differentiable pipeline with `apply_tesseract`, no monolithic rewrite required.\n", + "\n", + "2. **Gradients through two-way coupling.** The coupled equilibrium is a `jax.lax.scan` over alternating solver calls. Because each Tesseract exposes its derivatives, `jax.grad` propagates gradients through the entire iteration automatically, and the result matches finite differences.\n", + "\n", + "3. **Gradients make optimization tractable.** Using the end-to-end gradients, L-BFGS-B solves the inverse problem in far fewer evaluations than the gradient-free Nelder-Mead baseline.\n", + "\n", + "4. **Implicit differentiation for scale.** Wrapping the coupled solve in a `jax.custom_vjp` and solving the adjoint equation at the fixed point gives constant-memory gradients -- $\\mathcal{O}(1)$ in coupling iterations instead of $\\mathcal{O}(N)$ -- without changing the forward composition.\n", + "\n", + "5. **The pattern generalizes.** Wrap each physics component as a Tesseract, compose with `apply_tesseract`, and differentiate with JAX. The same recipe applies to any multi-component, multi-physics differentiable pipeline." ] }, { "cell_type": "markdown", + "id": "a5df9f57", "metadata": {}, "source": [ - "#", - "#", - " ", - "9", - ".", - " ", - "P", - "r", - "o", - "d", - "u", - "c", - "t", - "i", - "o", - "n", - " ", - "p", - "a", - "t", - "h", - ":", - " ", - "c", - "o", - "m", - "p", - "o", - "s", - "i", - "n", - "g", - " ", - "T", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - "s", - " ", - "w", - "i", - "t", - "h", - " ", - "`", - "t", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - "-", - "j", - "a", - "x", - "`", - "\n", - "\n", - "T", - "h", - "e", - " ", - "c", - "e", - "l", - "l", - "s", - " ", - "a", - "b", - "o", - "v", - "e", - " ", - "c", - "a", - "l", - "l", - " ", - "`", - "a", - "p", - "p", - "l", - "y", - "_", - "j", - "i", - "t", - "`", - " ", - "d", - "i", - "r", - "e", - "c", - "t", - "l", - "y", - " ", - "\u2014", - " ", - "b", - "y", - "p", - "a", - "s", - "s", - "i", - "n", - "g", - " ", - "t", - "h", - "e", - " ", - "T", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - " ", - "r", - "u", - "n", - "t", - "i", - "m", - "e", - " ", - "f", - "o", - "r", - " ", - "s", - "p", - "e", - "e", - "d", - ".", - " ", - "I", - "n", - " ", - "p", - "r", - "o", - "d", - "u", - "c", - "t", - "i", - "o", - "n", - ",", - " ", - "e", - "a", - "c", - "h", - " ", - "s", - "o", - "l", - "v", - "e", - "r", - " ", - "i", - "s", - " ", - "a", - " ", - "c", - "o", - "n", - "t", - "a", - "i", - "n", - "e", - "r", - "i", - "z", - "e", - "d", - " ", - "T", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - " ", - "a", - "n", - "d", - " ", - "y", - "o", - "u", - " ", - "c", - "o", - "m", - "p", - "o", - "s", - "e", - " ", - "t", - "h", - "e", - "m", - " ", - "w", - "i", - "t", - "h", - " ", - "`", - "t", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - "-", - "j", - "a", - "x", - "`", - "'", - "s", - " ", - "`", - "a", - "p", - "p", - "l", - "y", - "_", - "t", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - "`", - ",", - " ", - "a", - " ", - "J", - "A", - "X", - " ", - "p", - "r", - "i", - "m", - "i", - "t", - "i", - "v", - "e", - " ", - "t", - "h", - "a", - "t", - " ", - "r", - "o", - "u", - "t", - "e", - "s", - " ", - "t", - "o", - " ", - "t", - "h", - "e", - " ", - "T", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - "'", - "s", - " ", - "e", - "n", - "d", - "p", - "o", - "i", - "n", - "t", - "s", - ".", - " ", - "`", - "j", - "a", - "x", - ".", - "g", - "r", - "a", - "d", - "`", - " ", - "a", - "n", - "d", - " ", - "`", - "j", - "a", - "x", - ".", - "j", - "i", - "t", - "`", - " ", - "w", - "o", - "r", - "k", - " ", - "t", - "h", - "r", - "o", - "u", - "g", - "h", - " ", - "i", - "t", - " ", - "a", - "u", - "t", - "o", - "m", - "a", - "t", - "i", - "c", - "a", - "l", - "l", - "y", - ".", - "\n", - "\n", - "*", - "*", - "I", - "m", - "p", - "o", - "r", - "t", - "a", - "n", - "t", - " ", - "p", - "a", - "t", - "t", - "e", - "r", - "n", - "*", - "*", - ":", - " ", - "w", - "h", - "e", - "n", - " ", - "u", - "s", - "i", - "n", - "g", - " ", - "`", - "a", - "p", - "p", - "l", - "y", - "_", - "t", - "e", - "s", - "s", - "e", - "r", - "a", - "c", - "t", - "`", - " ", - "i", - "n", - "s", - "i", - "d", - "e", - " ", - "`", - "l", - "a", - "x", - ".", - "s", - "c", - "a", - "n", - "`", - ",", - " ", - "n", - "o", - "n", - "-", - "d", - "i", - "f", - "f", - "e", - "r", - "e", - "n", - "t", - "i", - "a", - "b", - "l", - "e", - " ", - "c", - "o", - "n", - "s", - "t", - "a", - "n", - "t", - "s", - " ", - "m", - "u", - "s", - "t", - " ", - "b", - "e", - " ", - "p", - "a", - "s", - "s", - "e", - "d", - " ", - "a", - "s", - " ", - "*", - "*", - "n", - "u", - "m", - "p", - "y", - " ", - "a", - "r", - "r", - "a", - "y", - "s", - "*", - "*", - " ", - "(", - "`", - "n", - "p", - ".", - "f", - "l", - "o", - "a", - "t", - "3", - "2", - "`", - ")", - ",", - " ", - "n", - "o", - "t", - " ", - "J", - "A", - "X", - " ", - "a", - "r", - "r", - "a", - "y", - "s", - " ", - "(", - "`", - "j", - "n", - "p", - ".", - "f", - "l", - "o", - "a", - "t", - "3", - "2", - "`", - ")", - ".", - " ", - "I", - "n", - "s", - "i", - "d", - "e", - " ", - "a", - " ", - "s", - "c", - "a", - "n", - ",", - " ", - "J", - "A", - "X", - " ", - "t", - "r", - "a", - "c", - "e", - "s", - " ", - "a", - "l", - "l", - " ", - "a", - "r", - "r", - "a", - "y", - " ", - "i", - "n", - "p", - "u", - "t", - "s", - " ", - "u", - "n", - "i", - "f", - "o", - "r", - "m", - "l", - "y", - " ", - "\u2014", - " ", - "i", - "t", - " ", - "c", - "a", - "n", - "'", - "t", - " ", - "t", - "e", - "l", - "l", - " ", - "w", - "h", - "i", - "c", - "h", - " ", - "o", - "n", - "e", - "s", - " ", - "a", - "r", - "e", - " ", - "c", - "o", - "n", - "s", - "t", - "a", - "n", - "t", - "s", - ".", - " ", - "I", - "f", - " ", - "a", - " ", - "n", - "o", - "n", - "-", - "d", - "i", - "f", - "f", - "e", - "r", - "e", - "n", - "t", - "i", - "a", - "b", - "l", - "e", - " ", - "f", - "i", - "e", - "l", - "d", - " ", - "g", - "e", - "t", - "s", - " ", - "t", - "r", - "a", - "c", - "e", - "d", - ",", - " ", - "t", - "h", - "e", - " ", - "b", - "a", - "c", - "k", - "w", - "a", - "r", - "d", - " ", - "p", - "a", - "s", - "s", - " ", - "w", - "i", - "l", - "l", - " ", - "t", - "r", - "y", - " ", - "t", - "o", - " ", - "d", - "i", - "f", - "f", - "e", - "r", - "e", - "n", - "t", - "i", - "a", - "t", - "e", - " ", - "t", - "h", - "r", - "o", - "u", - "g", - "h", - " ", - "i", - "t", - " ", - "a", - "n", - "d", - " ", - "t", - "h", - "e", - " ", - "V", - "J", - "P", - " ", - "e", - "n", - "d", - "p", - "o", - "i", - "n", - "t", - " ", - "w", - "i", - "l", - "l", - " ", - "r", - "e", - "j", - "e", - "c", - "t", - " ", - "t", - "h", - "e", - " ", - "f", - "i", - "e", - "l", - "d", - " ", - "n", - "a", - "m", - "e", - ".", - " ", - "U", - "s", - "i", - "n", - "g", - " ", - "`", - "n", - "p", - "`", - " ", - "a", - "r", - "r", - "a", - "y", - "s", - " ", - "k", - "e", - "e", - "p", - "s", - " ", - "t", - "h", - "e", - "m", - " ", - "o", - "p", - "a", - "q", - "u", - "e", - " ", - "t", - "o", - " ", - "t", - "h", - "e", - " ", - "t", - "r", - "a", - "c", - "e", - "r", - "." + "### What's next\n", + "\n", + "- **Add more physics.** Introduce a third coupled solver (e.g. a fluid or electromagnetic field) and let the gradients flow through all of them.\n", + "- **Scale up.** Increase the mesh resolution and the number of coupling iterations, and run the Tesseracts on a GPU.\n", + "- **Swap an implementation.** Because the pipeline composes Tesseracts by reference, you can replace a solver with a different image -- a higher-fidelity model or a learned surrogate -- without touching the optimization code.\n", + "- **Explore other demos.** See the [shape optimization](fem-shape-optimization.ipynb) and [data assimilation](data-assimilation.ipynb) demos for other ways to compose Tesseracts with JAX.\n", + "\n", + "Questions? Feedback? Please reach out through the [Tesseract Community Forum](https://si-tesseract.discourse.group/)." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, + "id": "fd545d2b", "metadata": {}, "outputs": [], "source": [ - "from tesseract_jax import apply_tesseract\n", - "\n", - "from tesseract_core.sdk.tesseract import Tesseract\n", - "\n", - "# Load Tesseracts (in-process, no Docker)\n", - "thermal_tess = Tesseract.from_tesseract_api(\"thermal_solver/tesseract_api.py\")\n", - "structural_tess = Tesseract.from_tesseract_api(\"structural_solver/tesseract_api.py\")\n", - "\n", - "# Forward pass through both Tesseracts via apply_tesseract\n", - "thermal_out_tj = apply_tesseract(\n", - " thermal_tess,\n", - " {\n", - " \"source_x\": jnp.float32(0.5),\n", - " \"source_y\": jnp.float32(0.5),\n", - " \"source_intensity\": jnp.float32(10.0),\n", - " \"source_width\": np.float32(0.1), # np: non-differentiable constant\n", - " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", - " \"conductivity\": np.float32(1.0), # np: non-differentiable constant\n", - " \"boundary_temp\": np.float32(0.0), # np: non-differentiable constant\n", - " },\n", - ")\n", - "\n", - "structural_out_tj = apply_tesseract(\n", - " structural_tess,\n", - " {\n", - " \"temperature\": thermal_out_tj[\"temperature\"],\n", - " \"youngs_modulus\": np.float32(200.0), # np: non-differentiable constant\n", - " \"poissons_ratio\": np.float32(0.3), # np: non-differentiable constant\n", - " \"thermal_expansion\": np.float32(1e-3), # np: non-differentiable constant\n", - " },\n", - ")\n", - "\n", - "# Verify: matches direct apply_jit\n", - "print(\"Forward pass via apply_tesseract matches direct call:\")\n", - "print(\n", - " f\" Temperature max error: \"\n", - " f\"{float(jnp.max(jnp.abs(thermal_out_tj['temperature'] - thermal_out['temperature']))):.2e}\"\n", - ")\n", - "print(\n", - " f\" Displacement max error: \"\n", - " f\"{float(jnp.max(jnp.abs(structural_out_tj['displacement'] - structural_out['displacement']))):.2e}\"\n", - ")\n", - "\n", - "\n", - "# Gradient through a single Tesseract call\n", - "def single_thermal_loss(source_x):\n", - " out = apply_tesseract(\n", - " thermal_tess,\n", - " {\n", - " \"source_x\": source_x,\n", - " \"source_y\": jnp.float32(0.5),\n", - " \"source_intensity\": jnp.float32(10.0),\n", - " \"source_width\": np.float32(0.1),\n", - " \"displacement\": jnp.zeros((30, 30, 2), dtype=jnp.float32),\n", - " \"conductivity\": np.float32(1.0),\n", - " \"boundary_temp\": np.float32(0.0),\n", - " },\n", - " )\n", - " return jnp.sum(out[\"temperature\"])\n", - "\n", - "\n", - "grad_single = jax.grad(single_thermal_loss)(jnp.float32(0.3))\n", - "print(\n", - " f\"\\nGradient through single apply_tesseract: d(sum_T)/d(source_x) = {float(grad_single):.6e}\"\n", - ")\n", - "\n", - "\n", - "# Full coupled pipeline: apply_tesseract + lax.scan + jax.grad\n", - "# Key: non-differentiable constants use np (not jnp) so JAX doesn't trace them\n", - "def coupled_objective_tesseract(params):\n", - " source_x, source_y, log_intensity = params[0], params[1], params[2]\n", - " intensity = jnp.exp(log_intensity)\n", - "\n", - " temp = jnp.zeros((30, 30), dtype=jnp.float32)\n", - " disp = jnp.zeros((30, 30, 2), dtype=jnp.float32)\n", - "\n", - " def coupling_step(carry, _):\n", - " _temp, disp = carry\n", - " thermal_out = apply_tesseract(\n", - " thermal_tess,\n", - " {\n", - " \"source_x\": source_x,\n", - " \"source_y\": source_y,\n", - " \"source_intensity\": intensity,\n", - " \"source_width\": np.float32(0.15),\n", - " \"displacement\": disp,\n", - " \"conductivity\": np.float32(1.0),\n", - " \"boundary_temp\": np.float32(0.0),\n", - " },\n", - " )\n", - " structural_out = apply_tesseract(\n", - " structural_tess,\n", - " {\n", - " \"temperature\": thermal_out[\"temperature\"],\n", - " \"youngs_modulus\": np.float32(200.0),\n", - " \"poissons_ratio\": np.float32(0.3),\n", - " \"thermal_expansion\": np.float32(1e-3),\n", - " },\n", - " )\n", - " return (thermal_out[\"temperature\"], structural_out[\"displacement\"]), None\n", - "\n", - " (final_temp, _), _ = jax.lax.scan(\n", - " coupling_step, (temp, disp), None, length=N_COUPLING_ITERS\n", - " )\n", - "\n", - " loss = jnp.float32(0.0)\n", - " for (si, sj), target in zip(SENSORS, TARGETS, strict=False):\n", - " loss = loss + (final_temp[si, sj] - target) ** 2\n", - " return loss\n", - "\n", - "\n", - "# End-to-end gradient through apply_tesseract + lax.scan\n", - "grad_tess = jax.grad(coupled_objective_tesseract)(p0)\n", - "grad_direct = jax.grad(coupled_objective)(p0)\n", - "\n", - "print(\"\\nEnd-to-end gradient through apply_tesseract + lax.scan:\")\n", - "print(f\" {'':32s} {'apply_tesseract':>16s} {'direct':>16s}\")\n", - "for name, gt, gd in zip(names, grad_tess, grad_direct, strict=False):\n", - " print(f\" {name:32s} {float(gt):16.6e} {float(gd):16.6e}\")" + "# Shut down the Tesseract servers\n", + "thermal.teardown()\n", + "structural.teardown()" ] } ], @@ -3295,5 +1000,5 @@ } }, "nbformat": 4, - "nbformat_minor": 4 + "nbformat_minor": 5 } diff --git a/demo/multiphysics-optimization/requirements.txt b/demo/multiphysics-optimization/requirements.txt index b2c1cbe5d..1e4b0690f 100644 --- a/demo/multiphysics-optimization/requirements.txt +++ b/demo/multiphysics-optimization/requirements.txt @@ -1,5 +1,6 @@ jax[cpu]==0.5.2 -equinox -matplotlib -scipy -tesseract-core +equinox==0.13.6 +matplotlib==3.10.9 +scipy==1.17.1 +tesseract-jax==0.3.0 +tesseract-core[runtime] diff --git a/docs/content/demo/demo.md b/docs/content/demo/demo.md index 8b05b53c6..bbc8fc4d0 100644 --- a/docs/content/demo/demo.md +++ b/docs/content/demo/demo.md @@ -10,6 +10,7 @@ data-assimilation.ipynb lorenz_tesseract.md cfd-optimization.ipynb fem-shape-optimization.ipynb +multiphysics-optimization.ipynb JAX Rosenbrock Minimization PyTorch Rosenbrock Minimization JAX RBF Fitting @@ -58,6 +59,11 @@ Optimize the initial velocity field of a 2D Navier-Stokes simulation so its vort Compose a geometry Tesseract (PyVista, finite-difference gradients) with a FEM Tesseract (jax-fem) to optimize structural bar configurations for minimum compliance. ::: +:::{grid-item-card} Multi-Physics Optimization +:link: multiphysics-optimization.html + +Couple independent thermal and structural Tesseracts into a two-way thermoelastic pipeline and solve an inverse-design problem with end-to-end gradients — including constant-memory gradients via implicit differentiation. +::: :::: diff --git a/docs/index.md b/docs/index.md index c5dc17053..d19de0e16 100644 --- a/docs/index.md +++ b/docs/index.md @@ -263,6 +263,17 @@ Compose a geometry Tesseract with a FEM solver Tesseract for end-to-end parametric structural optimization. ::: +:::{grid-item-card} Multi-Physics Optimization +:link: content/demo/multiphysics-optimization +:link-type: doc +:class-card: demo-card +:img-top: static/demo-multiphysics.svg +:class-img-top: demo-schematic invert-on-dark + +Couple thermal and structural Tesseracts into a two-way thermoelastic +pipeline and solve an inverse-design problem with end-to-end gradients. +::: + :::: :::{div} landing-cta diff --git a/docs/static/demo-multiphysics.svg b/docs/static/demo-multiphysics.svg new file mode 100644 index 000000000..44cbf4309 --- /dev/null +++ b/docs/static/demo-multiphysics.svg @@ -0,0 +1,51 @@ + + + + + + + + + θ (source) + + + + + + + + + + Thermal + + + + + T + + + D + + + + + + Structural + + + + + + + + + + + + loss + + + + + ∇ through coupled iteration +