{ "cells": [ { "cell_type": "markdown", "id": "b1000001", "metadata": {}, "source": [ "# Tutorial 7b: Differentiable Lens Optimization\n", "\n", "**Prerequisites:** Tutorial 1f (Differentiable Ray Tracing Hello World), Tutorial 5a (Simple Optimization)\n", "\n", "Tutorial 1f demonstrated the basics of switching to the PyTorch backend and running a quick\n", "gradient-based loop. This tutorial is a deeper dive: we will build a complete differentiable\n", "optimization pipeline, compare it to a SciPy baseline, and extend it to multi-field optimization.\n", "\n", "By the end you will know how to:\n", "- Compute gradients of an optical metric (RMS spot size) with respect to design parameters\n", "- Run a PyTorch Adam loop and monitor convergence\n", "- Compare differentiable optimization to the Levenberg-Marquardt (LeastSquares) baseline\n", "- Optimize a multi-field merit function using autograd\n", "- Apply gradient clipping and parameter bounds for stable training" ] }, { "cell_type": "markdown", "id": "b1000002", "metadata": {}, "source": [ "## 1. Why differentiable optimization?\n", "\n", "Traditional merit-function optimizers (Levenberg-Marquardt, Differential Evolution) estimate\n", "gradients via finite differences \u2014 one extra forward ray-trace per variable. For a 10-variable\n", "problem that means 10 extra traces per iteration.\n", "\n", "With autograd the gradient arrives essentially *free*: one forward pass builds the computation\n", "graph; `.backward()` traverses it once to produce exact gradients for all variables simultaneously.\n", "\n", "**When to use autograd vs. merit-function optimizers:**\n", "\n", "| Situation | Recommendation |\n", "|---|---|\n", "| Many variables, smooth landscape | Autograd + Adam |\n", "| Categorical variables (glass choice) | `GlassExpert` (SciPy) |\n", "| Non-smooth constraints, global search | Differential Evolution / SHGO |\n", "| Tight integration with an ML pipeline | Autograd \u2014 same graph as the rest of the model |" ] }, { "cell_type": "code", "execution_count": 1, "id": "b1000003", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Backend: torch\n", "Precision: 64\n" ] } ], "source": [ "import matplotlib.pyplot as plt\n", "import torch\n", "import torch.optim as optim\n", "\n", "import optiland.backend as be\n", "\n", "# Switch to the PyTorch backend and enable gradient tracking\n", "be.set_backend(\"torch\")\n", "be.set_device(\"cpu\")\n", "be.set_precision(\"float64\")\n", "be.grad_mode.enable()\n", "\n", "print(\"Backend:\", be.get_backend())\n", "print(\"Precision:\", be.get_precision())" ] }, { "cell_type": "markdown", "id": "b1000004", "metadata": {}, "source": [ "## 2. Setting up a differentiable lens\n", "\n", "We build a simple singlet. When the PyTorch backend is active, surface parameters (radii,\n", "thicknesses) are stored as `torch.Tensor` objects that participate in the computation graph." ] }, { "cell_type": "code", "execution_count": 2, "id": "b1000005", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "r1: tensor(70., dtype=torch.float64, requires_grad=True)\n", "r2: tensor(-70., dtype=torch.float64, requires_grad=True)\n" ] } ], "source": [ "from optiland.materials import Material\n", "from optiland.optic import Optic\n", "\n", "\n", "def make_singlet(r1=70.0, r2=-70.0, thickness=70.0):\n", " \"\"\"Construct a singlet with the given radii and image distance.\"\"\"\n", " lens = Optic(name=\"Singlet\")\n", " glass = Material(\"N-BK7\")\n", " lens.surfaces.add(index=0, radius=be.inf, thickness=be.inf)\n", " lens.surfaces.add(index=1, radius=r1, thickness=7.0, material=glass, is_stop=True)\n", " lens.surfaces.add(index=2, radius=r2, thickness=thickness)\n", " lens.surfaces.add(index=3) # image plane\n", " lens.set_aperture(aperture_type=\"EPD\", value=25.0)\n", " lens.fields.set_type(\"angle\")\n", " lens.fields.add(y=0.0)\n", " lens.wavelengths.add(value=0.55, is_primary=True)\n", " return lens\n", "\n", "\n", "lens = make_singlet()\n", "\n", "# The radii are torch tensors with requires_grad=True\n", "r1_param = lens.surfaces.surfaces[1].geometry.radius\n", "r2_param = lens.surfaces.surfaces[2].geometry.radius\n", "print(\"r1:\", r1_param)\n", "print(\"r2:\", r2_param)" ] }, { "cell_type": "markdown", "id": "b1000006", "metadata": {}, "source": [ "## 3. Computing gradients of an optical metric\n", "\n", "We compute the RMS spot radius as a differentiable scalar, then call `.backward()` to obtain\n", "the gradient of the loss with respect to each design parameter." ] }, { "cell_type": "code", "execution_count": 3, "id": "b1000007", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "RMS spot radius: 0.944229 mm\n", "d(loss)/d(r1) : -0.078014\n", "d(loss)/d(r2) : 0.079865\n" ] } ], "source": [ "from optiland.analysis import SpotDiagram\n", "\n", "\n", "def rms_spot(lens):\n", " \"\"\"Return the RMS spot radius as a differentiable scalar tensor.\"\"\"\n", " return SpotDiagram(lens).rms_spot_radius()[0][0]\n", "\n", "\n", "# Zero out any existing gradients\n", "if r1_param.grad is not None:\n", " r1_param.grad.zero_()\n", "if r2_param.grad is not None:\n", " r2_param.grad.zero_()\n", "\n", "loss = rms_spot(lens)\n", "loss.backward()\n", "\n", "print(f\"RMS spot radius: {loss.item():.6f} mm\")\n", "print(f\"d(loss)/d(r1) : {r1_param.grad.item():.6f}\")\n", "print(f\"d(loss)/d(r2) : {r2_param.grad.item():.6f}\")" ] }, { "cell_type": "markdown", "id": "b1000008", "metadata": {}, "source": [ "## 4. Custom loss function\n", "\n", "Any differentiable combination of ray-trace outputs can serve as the loss. Here we define a\n", "combined loss that penalises both the RMS spot radius and deviation of the focal length from a\n", "target value." ] }, { "cell_type": "code", "execution_count": 4, "id": "b1000009", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Combined loss: 99.0889\n" ] } ], "source": [ "EFL_TARGET = 100.0 # mm\n", "\n", "\n", "def combined_loss(lens, w_spot=1.0, w_efl=0.1):\n", " \"\"\"Penalise RMS spot size + deviation from target focal length.\"\"\"\n", " spot = SpotDiagram(lens).rms_spot_radius()[0][0]\n", " efl = lens.paraxial.f2()\n", " # Convert to a differentiable scalar tensor\n", " efl_tensor = be.array(efl) if not isinstance(efl, torch.Tensor) else efl\n", " efl_penalty = (efl_tensor - EFL_TARGET) ** 2\n", " return w_spot * spot + w_efl * efl_penalty\n", "\n", "\n", "loss_val = combined_loss(lens)\n", "print(f\"Combined loss: {loss_val.item():.4f}\")" ] }, { "cell_type": "markdown", "id": "b1000010", "metadata": {}, "source": [ "## 5. Full gradient descent optimization loop\n", "\n", "We pass the two radius tensors directly to a PyTorch Adam optimizer and run the standard\n", "train loop: zero gradients \u2192 forward pass \u2192 backward \u2192 step." ] }, { "cell_type": "code", "execution_count": 5, "id": "b1000011", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Step 1 | loss=0.94423 mm | r1=70.50 r2=-70.50\n", "Step 30 | loss=0.11524 mm | r1=76.18 r2=-76.33\n", "Step 60 | loss=0.11655 mm | r1=76.08 r2=-76.67\n", "Step 90 | loss=0.11429 mm | r1=75.90 r2=-77.13\n", "Step 120 | loss=0.11365 mm | r1=75.52 r2=-77.50\n", "Step 150 | loss=0.11299 mm | r1=75.09 r2=-77.94\n", "\n", "Final RMS spot: 0.11299 mm\n" ] } ], "source": [ "lens = make_singlet() # fresh lens with default radii\n", "r1_param = lens.surfaces.surfaces[1].geometry.radius\n", "r2_param = lens.surfaces.surfaces[2].geometry.radius\n", "\n", "optimizer = optim.Adam([r1_param, r2_param], lr=0.5)\n", "\n", "losses = []\n", "n_steps = 150\n", "\n", "for step in range(n_steps):\n", " optimizer.zero_grad()\n", " loss = rms_spot(lens)\n", " losses.append(loss.item())\n", " loss.backward()\n", " # Clip gradients to prevent instability\n", " torch.nn.utils.clip_grad_norm_([r1_param, r2_param], max_norm=50.0)\n", " optimizer.step()\n", "\n", " if (step + 1) % 30 == 0 or step == 0:\n", " print(f\"Step {step+1:3d} | loss={loss.item():.5f} mm \"\n", " f\"| r1={r1_param.item():.2f} r2={r2_param.item():.2f}\")\n", "\n", "print(f\"\\nFinal RMS spot: {losses[-1]:.5f} mm\")" ] }, { "cell_type": "code", "execution_count": 6, "id": "85189b79", "metadata": {}, "outputs": [ { "data": { "image/png": "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azPs98QTT8i4cePkd7/7nf82+gnUnj175JZbbjH9QI9JLr74Ytm0aZP/fl137eGHH5azzz7b3P+jH/1IvvnmG1vbjMhqbGyUhx56qM1x66OPPmr6RiT6CaEKndIDIO18N998szz77LNyww03yAsvvCAPPPCA/zFVVVVy3XXXSe/eveWpp56S66+/Xh555BF58cUXbW07IuvVV1+VxYsXm+VK//CHP8jw4cNl3rx5Ul5ebnfTYJOPP/5YLrroIhOu9D1Dd7LX94qamhr/Y+677z5566235K677jLvG2VlZeaAGbFp48aN5rOjsLCwze30E1RUVMiVV14pCQkJ8vvf/96cxPvpT38qmZmZ/sfoCd1nnnlGbrrpJhPOU1JSzOeQhnLEhlWrVsnzzz8vv/jFL+S5554z//9PPvmkOYaNSD/RJdWBQK1atappxowZ/u+fe+65ptNPP73J6/X6b7v//vubLrjgAptaCDtcdtllTXfddZf/+8bGxqYpU6Y0rVy50tZ2wTnKy8ubTjjhhKZ169aZ7ysrK5tOOumkptdee83/mG3btpnHrF+/3saWwg4ej6fp+9//ftN7773X9MMf/rDp3nvvNbfTT2AdV1x55ZWd3u/z+ZrOOuuspieffNJ/m/adCRMmNL3yyisRaiXs9uMf/7jptttua3Pbz3/+86b/+Z//iUg/YaQKXaIjU63PDK1fv16OP/54SUxM9N82YcIE+frrr82ZJUQ/nQ66efNmOemkk/y3xcXFyfjx403/AKz3DmW9f3zxxRdm9Kp1vxk0aJD06tWLfhODdHqfTsVp3R8U/QRKRyqPOeYY+eUvf2mmE8+aNUteeukl//07d+40U0L1c8eSkZEho0ePlg0bNtjUakTad77zHfnwww/NMajasmWLfPbZZ6YsIRL9JCHon4CYsWPHDjOE+pOf/MR/m3bOPn36tHlcTk6O/77WAQzRaf/+/WYes/X/btHvD62hQWzy+XymRmbs2LEybNgw//uDnozp3r17u35DvUxs+dvf/mZOzOg0nUPRT2AdDGv5wezZs2XOnDmmluree+81fWPatGn+vpCbm9vmefST2HLFFVeIx+ORH/zgB+bkrn72aM3U1KlTzf3h7ieEqhi0dOnSIy4moXNS9Wxg6wJRnXN65plnyve///0ItBJANI1CfPXVV6ZgGGht9+7dJnBr3V1y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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "_ = lens.draw()" ] }, { "cell_type": "code", "execution_count": 7, "id": "b1000012", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAAGGCAYAAADmRxfNAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvc2/+5QAAAAlwSFlzAAAPYQAAD2EBqD+naQAAWRNJREFUeJzt3Qd4VGXWwPGTHtIDIYTepDcRBLGxCgg2xIKIBWRd/VRYEdxdcV3FsiI2ZFHXtqJixY4VUAQrRUF6lU4ghJZGejLfc94w46QyyczkziT/n884M3fuzH3n3Jvhnvu2AJvNZhMAAAAAcEOgO28GAAAAAEViAQAAAMBtJBYAAAAA3EZiAQAAAMBtJBYAAAAA3EZiAQAAAMBtJBYAAAAA3EZiAQAAAMBtJBYAAAAA3EZiAdRDDzzwgAQEBJRaVlhYKP/4xz+kZcuWEhgYKCNGjDDLs7Ky5C9/+YskJSWZ99x5553ib3bt2mXK/tprr9U4VocPHz7pum3atJEbb7xR/N2f/vQnc/Mkq2JTV/YJAPgDEgvAz+nJsp742m/h4eHSrFkzGTp0qMyaNUsyMzNd+pzZs2fLE088IVdddZW8/vrrMmnSJLN82rRpZhu33XabvPHGG3LDDTeIr3r77bdl5syZUpfYbDYT93PPPVfi4uIkIiJCevToIQ899JAcP368xp+7ceNGkzRp0uXvfv75Z/Nd0tLSpL5YvXq1XH/99eZCQFhYmDRs2FAGDx4sr776qhQVFVldPAD1VIBN/9UC4Lf0pH/cuHHmRLNt27ZSUFAgKSkpsmTJEvn666+lVatW8umnn0rPnj1L1U7oTZMQu2uuuUZ+/PFH2bdvX6nPP+OMMyQ4ONi85usuueQSWb9+fbmTZf2Zy8vLk5CQEAkKCqrWZ+oJ64MPPiiHDh2ShISEk14d1yv9NakZqYieIF577bXy3nvvyTnnnCNXXHGFSSx++OEHk0R17dpVvvnmG2nSpEm1P/uDDz6QkSNHyuLFi8vVTuTn55v70NBQ8RSNv9aE6T7wtCeffFL+/ve/y86dO80+qK3tWuV///uf3HrrrWa/a6LfoUMHcwFh0aJF8sUXX8i///1v+ec//2l1MQHUQ8FWFwCAZ1x44YXSt29fx/N77rlHvv32W3OyPXz4cNm0aZM0aNDAvKaJgt6cpaammiviZelyPYH1lOLiYnPi6pzUeJu9JsffPP744yap+Nvf/mZqk+xuueUWufrqq01zNW3m89VXX3l0u55MKOz0qroVrNqutyxbtswkFQMGDJAvv/xSoqOjHa9pM8Vff/3VJNf+TGviIiMjrS4GgJrQGgsA/uvVV1/VWkfbL7/8UuHr06ZNM6+/9NJLjmVTp041y9TOnTvN47K3xYsXV7hc11e5ubm2+++/39a+fXtbaGiorUWLFra///3vZrkzfc/48eNtb775pq1r16624OBg28cff2xe27dvn23cuHG2xMRE8xn6+iuvvFLq/fZyzJ071/bvf//b1rx5c1tYWJjt/PPPt23bts2x3sCBA8uVtXXr1qW+o8bKbs2aNbaxY8fa2rZtaz6vSZMmpiyHDx8utX17rDZt2mQbOXKkLTo62tawYUPbHXfcYcvJySm1rm5PP9PZsWPHbBMnTjTx0e+o8Zo+fbqtqKioyv2anZ1ti4+Pt3Xs2NFWUFBQ4TpaXi3b0qVLS5Xh4osvti1YsMDWq1cv8926dOli+/DDD8sdMxXtc3ss9VbRPnjggQdszZo1s0VFRdmuvPJKW1pamtnn+h0bN25si4yMtN14443ljoOysalo+2WPMVf2kX3/VPYZFe2T7du326666ioT3wYNGtj69+9v+/zzz2t03NW2YcOGmb+h3bt3u7R+VlaWbfLkyY7jT4+nJ554wlZcXFzh36n+bXbr1s3x9/jVV1851nn//ffNekuWLCm3nRdeeMG8tm7dOscy/ZvRY0TjrLHr06ePbd68eaXeZz8W9TNvu+02cwzFxcU5Xn/22WfN/g8PD7edfvrptu+//77c8VmT36Oqvqed/j79+c9/tjVt2tSs16ZNG9utt95qy8vLc/vvG6irqLEA6jhtKqHNIhYuXCg333xzudcbN25s2vA/8sgjpqP2o48+apZ36dLFLNe+Fi1atJC77rrLsb7WOmgtiDaP0qvnuu66devk6aeflq1bt8onn3xSahtac6JX3idMmGCaE2lzlYMHD5pmVlqboMv1c/XK+0033SQZGRnlOolPnz7dNGnRq/fp6enmav51110ny5cvN6/fe++9Zrk25dJyqKioqErjos3EduzYYZqRacf0DRs2yEsvvWTu9apw2c7tWkOg5db46Ovaf+XYsWMyZ86cSreRnZ0tAwcOlOTkZPm///s/0yxN+wNobdKBAweq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JpO88847HcuIrXuSk5Pl+uuvN/Fr0KCB9OjRQ3799VfH69r17f7775emTZua1wcPHizbtm2ztMz+oqioSO677z5p27atiV379u3l4YcfNjG1I76u+/777+XSSy81E2Pp78Ann3xS6nVXYnn06FG57rrrzPwAcXFxctNNN0lWVlYtfxP/i29BQYHcfffd5vchMjLSrDNmzBgzya8z4luzY9fZrbfeataZOXNmqeXEtvpILGrR3LlzZfLkyWbkgVWrVkmvXr1k6NChkpqaanXR/M53331nTmyXLVsmX3/9tfkBvuCCC+T48eOOdSZNmiSfffaZvP/++2Z9/TG+4oorLC23v/nll1/kxRdflJ49e5ZaTmxr7tixY3LWWWdJSEiIfPXVV7Jx40Z56qmnJD4+3rHO448/LrNmzZIXXnhBli9fbk4q9LdCEzpU7bHHHpPnn39enn32Wdm0aZN5rvF85plnHOsQX9fpb6r+W6UXxSriSiz1xGzDhg3mt/rzzz83J3y33HJLLX4L/4xvdna2OVfQRFnvP/roI3MBbfjw4aXWI741O3btPv74Y3MuoQlIWcS2BnRUKNSOfv362caPH+94XlRUZGvWrJnt0UcftbRcdUFqaqpejrR999135nlaWpotJCTE9v777zvW2bRpk1ln6dKlFpbUf2RmZto6dOhg+/rrr20DBw60TZw40Swntu65++67bWeffXalrxcXF9uSkpJsTzzxhGOZxjwsLMz2zjvv1FIp/dfFF19s+/Of/1xq2RVXXGG77rrrzGPiW3P6N/7xxx87nrsSy40bN5r3/fLLL451vvrqK1tAQIAtOTm5lr+Bf8W3IitWrDDr7d692zwnvu7Fdt++fbbmzZvb1q9fb2vdurXt6aefdrxGbGuGGotakp+fLytXrjTVxHaBgYHm+dKlSy0tW12Qnp5u7hs2bGjuNdZai+Ec786dO0urVq2It4u0Rujiiy8uFUNFbN3z6aefSt++fWXkyJGmGV/v3r3l5Zdfdry+c+dOSUlJKRXf2NhY03SS+J7cmWeeKYsWLZKtW7ea52vWrJEff/xRLrzwQvOc+HqOK7HUe21Cose8na6v//5pDQeq/2+dNtnRmCriW3PFxcVyww03yN///nfp1q1budeJbc0E1/B9qKbDhw+btr9NmjQptVyfb9682bJy1ZUfB23/r81LunfvbpbpP3ahoaGOH1/neOtrqNq7775rqt61KVRZxNY9O3bsME11tFnkP//5TxPjO+64w8R07NixjhhW9FtBfE9uypQpkpGRYZLdoKAg87v7yCOPmCYNivh6jiux1HtNoJ0FBwebi0DEu3q0eZn2uRg9erRp86+Ib81pM0mNlf7+VoTY1gyJBerElfX169ebq5Jw3969e2XixImmTakOMgDPJ8J6BWzatGnmudZY6PGrbdQ1sYB73nvvPXnrrbfk7bffNlchV69ebS48aPtp4gt/pbXEV199teksrxcm4B6tef/Pf/5jLqBpDRA8h6ZQtSQhIcFcPSs7co4+T0pKsqxc/m7ChAmmQ9XixYulRYsWjuUaU21+lpaWVmp94u3aD64OKHDaaaeZqzN60w7a2kFTH+vVSGJbczp6TteuXUst69Kli+zZs8c8tseQ34qa0WYNWmtxzTXXmNF0tKmDDjagI8kp4us5rsRS78sOUFJYWGhG2yHe1Usqdu/ebS742GsrFPGtmR9++MHETZvw2v+d0/jeddddZuRORWxrhsSilmgzhz59+pi2v85XLvX5gAEDLC2bP9KrNppU6GgO3377rRla0pnGWkfdcY63jqahJ2/Eu2qDBg2SdevWmSu99pteYdemJPbHxLbmtMle2aGRtT9A69atzWM9lvUfLef4atMebdNLfE9OR9LRNtDO9KKO/t4q4us5rsRS7/UihF6wsNPfbN0f2hcDriUVOoTvN998Y4aodkZ8a0YvOKxdu7bUv3Naq6kXJhYsWGDWIbY1VMNO36iBd99914yW8dprr5nRBm655RZbXFycLSUlxeqi+Z3bbrvNFhsba1uyZIntwIEDjlt2drZjnVtvvdXWqlUr27fffmv79ddfbQMGDDA3VJ/zqFCK2NacjuoSHBxse+SRR2zbtm2zvfXWW7aIiAjbm2++6Vhn+vTp5rdh3rx5trVr19ouu+wyW9u2bW05OTmWlt0fjB071ozy8vnnn9t27txp++ijj2wJCQm2f/zjH451iG/1Rof77bffzE1PGWbMmGEe20clciWWw4YNs/Xu3du2fPly248//mhGmxs9erSF38o/4pufn28bPny4rUWLFrbVq1eX+rcuLy/P8RnEt2bHblllR4VSxLb6SCxq2TPPPGNOyEJDQ83ws8uWLbO6SH5JfyQqur366quOdfQftttvv90WHx9vTtwuv/xy84MM9xMLYuuezz77zNa9e3dzoaFz5862l156qdTrOoznfffdZ2vSpIlZZ9CgQbYtW7ZYVl5/kpGRYY5V/Z0NDw+3tWvXznbvvfeWOhEjvq5bvHhxhb+1msC5GssjR46Yk7GoqChbTEyMbdy4ceakD1XHVxPjyv6t0/fZEd+aHbuuJBbEtvoC9H81re0AAAAAAEUfCwAAAABuI7EAAAAA4DYSCwAAAABuI7EAAAAA4DYSCwAAAABuI7EAAAAA4DYSCwAAAABuI7EAAAAA4DYSCwCAX2nTpo3MnDnT6mIAAMogsQAAVOrGG2+UESNGmMd/+tOf5M4776y1bb/22msSFxdXbvkvv/wit9xyS62VAwDgmmAX1wMAwCPy8/MlNDS0xu9v3LixR8sDAPAMaiwAAC7VXHz33Xfyn//8RwICAsxt165d5rX169fLhRdeKFFRUdKkSRO54YYb5PDhw473ak3HhAkTTG1HQkKCDB061CyfMWOG9OjRQyIjI6Vly5Zy++23S1ZWlnltyZIlMm7cOElPT3ds74EHHqiwKdSePXvksssuM9uPiYmRq6++Wg4ePOh4Xd936qmnyhtvvGHeGxsbK9dcc41kZmbWWvwAoD4gsQAAnJQmFAMGDJCbb75ZDhw4YG6aDKSlpcn5558vvXv3ll9//VXmz59vTur15N7Z66+/bmopfvrpJ3nhhRfMssDAQJk1a5Zs2LDBvP7tt9/KP/7xD/PamWeeaZIHTRTs2/vb3/5WrlzFxcUmqTh69KhJfL7++mvZsWOHjBo1qtR627dvl08++UQ+//xzc9N1p0+f7tWYAUB9Q1MoAMBJ6VV+TQwiIiIkKSnJsfzZZ581ScW0adMcy2bPnm2Sjq1bt0rHjh3Nsg4dOsjjjz9e6jOd+2toTcK///1vufXWW+W///2v2ZZuU2sqnLdX1qJFi2TdunWyc+dOs001Z84c6datm+mLcfrppzsSEO2zER0dbZ5rrYq+95FHHvFYjACgvqPGAgBQY2vWrJHFixebZkj2W+fOnR21BHZ9+vQp995vvvlGBg0aJM2bNzcn/Hqyf+TIEcnOznZ5+5s2bTIJhT2pUF27djWdvvU158TFnlSopk2bSmpqao2+MwCgYtRYAABqTPtEXHrppfLYY4+Ve01P3u20H4Uz7Z9xySWXyG233WZqDRo2bCg//vij3HTTTaZzt9aMeFJISEip51oTorUYAADPIbEAALhEmycVFRWVWnbaaafJhx9+aGoEgoNd/ydl5cqV5sT+qaeeMn0t1HvvvXfS7ZXVpUsX2bt3r7nZay02btxo+n5ozQUAoPbQFAoA4BJNHpYvX25qG3TUJ00Mxo8fbzpOjx492vRp0OZPCxYsMCM6VZUUnHLKKVJQUCDPPPOM6WytIzbZO3U7b09rRLQvhG6voiZSgwcPNiNLXXfddbJq1SpZsWKFjBkzRgYOHCh9+/b1ShwAABUjsQAAuERHZQoKCjI1ATqXhA7z2qxZMzPSkyYRF1xwgTnJ107Z2sfBXhNRkV69epnhZrUJVffu3eWtt96SRx99tNQ6OjKUdubWEZ50e2U7f9ubNM2bN0/i4+Pl3HPPNYlGu3btZO7cuV6JAQCgcgE2m81WxesAAAAAcFLUWAAAAABwG4kFAAAAALeRWAAAAABwG4kFAAAAALeRWAAAAABwG4kFAAAAALeRWAAAAABwG4kFAAAAALeRWAAAAABwG4kFAAAAALeRWAAAAABwG4kFAAAAAHHX/wMO+SdCq+6OjwAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(8, 4))\n", "plt.plot(losses)\n", "plt.xlabel(\"Iteration\")\n", "plt.ylabel(\"RMS spot radius [mm]\")\n", "plt.title(\"Differentiable Optimization \u2014 Convergence\")\n", "plt.grid(alpha=0.3)\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "b1000013", "metadata": {}, "source": [ "## 6. Comparing to the SciPy optimizer\n", "\n", "We solve the same problem with Optiland's `LeastSquares` optimizer (Levenberg-Marquardt)\n", "and compare convergence speed and final result quality." ] }, { "cell_type": "code", "execution_count": 8, "id": "b1000014", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Warning: Method 'lm' (Levenberg-Marquardt) chosen, but number of residuals (1) is less than number of variables (2). This is not supported by 'lm'. Switching to 'trf' method.\n", "SciPy LM result: r1=76.3238 r2=-76.6639\n", "Final RMS Spot Size: 0.114909 mm\n" ] } ], "source": [ "# Switch back to NumPy for the SciPy baseline\n", "be.set_backend(\"numpy\")\n", "\n", "from optiland.optimization import LeastSquares, OptimizationProblem\n", "\n", "lens_np = make_singlet() # re-build under numpy backend\n", "\n", "problem = OptimizationProblem()\n", "problem.add_variable(lens_np, \"radius\", surface_number=1)\n", "problem.add_variable(lens_np, \"radius\", surface_number=2)\n", "problem.add_operand(\n", " operand_type=\"rms_spot_size\",\n", " target=0.0,\n", " weight=1,\n", " input_data={\n", " \"optic\": lens_np,\n", " \"Hx\": 0,\n", " \"Hy\": 0,\n", " \"wavelength\": 0.55,\n", " \"distribution\": \"hexapolar\",\n", " \"num_rays\": 6, # 6 rings\n", " \"surface_number\": -1, # image surface\n", " },\n", ")\n", "\n", "optimizer = LeastSquares(problem)\n", "result = optimizer.optimize()\n", "\n", "np_final_r1 = lens_np.surfaces.surfaces[1].geometry.radius\n", "np_final_r2 = lens_np.surfaces.surfaces[2].geometry.radius\n", "print(f\"SciPy LM result: r1={np_final_r1:.4f} r2={np_final_r2:.4f}\")\n", "\n", "final_rms = problem.operands[0].value.copy()\n", "print(f\"Final RMS Spot Size: {final_rms:.6f} mm\")" ] }, { "cell_type": "code", "execution_count": 9, "id": "1a2735e3", "metadata": {}, "outputs": [ { "data": { "image/png": "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p/k+f/bZZ3u+9KUv9bS3t/vuu++++3rOPPPMKLUQ0XDhhRf23H777b7Pu7q6ehYuXNizatWqqLYL9lFfX99z1FFH9axfv9583tjY2PPFL36x59VXX/V9z9atW833fPDBB1FsKaKhqamp54wzzuj5xz/+0fONb3yj56677jL3009gnVdccsklA369u7u756STTur55S9/6btP+868efN6Xn755RFqJaLtO9/5Ts/NN98ccN8PfvCDnv/+7/8ekX7CSBWGREem/K8MffDBB3LEEUdISkqK77558+bJ9u3bzZUlxD6dDrpx40b54he/6LsvMTFR5s6da/oHYL13KOv945NPPjGjV/79pqysTEpLS+k3cUin9+lUHP/+oOgnUDpSecghh8iPfvQjM534/PPPlxdffNH39Z07d5opofp3x+JyuWTmzJmyYcOGKLUaI+2www6Tt956y5yDqsrKSnn//fdNWcJI9JPkYf8LiBs7duwwQ6jf/e53ffdp5xwzZkzA9xUUFPi+5h/AEJv27dtn5jFb/+8W/bxvDQ3iU3d3t6mRmT17tkydOtX3/qAXY7Kzs/v1G+pl4ssf/vAHc2FGp+n0RT+BdTKs5QdLliyRpUuXmlqqu+66y/SNxYsX+/pCYWFhwOPoJ/Hl4osvlqamJvn3f/93c3FX//ZozdSiRYvM1yPdTwhVcej+++8/4GISOidVrwb6F4jqnNOvfOUrcsYZZ4xAKwHE0ijEli1bTMEw4K+qqsoEbq27S0tLi3ZzYFN6cjxjxgz59re/bT6fPn26eU/RoKWhClCvvvqqvPzyy3LrrbfKlClTZNOmTaYms7i4eET6CaEqDl1wwQVmlbbBjB071vdxTU2NXH755WZY9frrrw/4Pk37fRcjsD7veyUAsSkvL0+SkpKC9gP6ADRQvfHGG2aBgZKSEt/92jd06mhjY2PAKAT9Jr7oCJX+n+vfJYuOfL/77rtmMQK9CEg/QVFRkUyaNCngPv38z3/+s/nY6gs62qDf699PdOEkxIf77rvPrD6sK/spnRmxe/dus2CShqpI9xNCVRzKz883Ryh0hEoDlV4Vuummm8xwqj8NWg8++KCZ866r8qh//vOfMnHiRKb+xQmdfqH9480335QTTjjBd1VR5zWfc8450W4eokRXDr3jjjvktddeM1sx+F+oUVofoe8Z2m90iWSl00V15ELfVxAfvvCFL5iVuPzpVh76N0RPjrR2in4CnTps1clY9HNdeVjp+4ueMOvfnWnTpvnqOHVrj7POOisqbcbIa21t7Xeeqhd9rSXVI91PCFUYNFB985vfNG9aWke1d+9e39eshL9w4UJZuXKl+SOofwB1OH7t2rVm+XXED53nvmzZMjM949BDD5Vf//rXZunsA42IIrZHqHQahk7tyszMNMtgW0XBuoSt3uoeIroUf25urmRlZcmdd95pTpRnzZoV7eZjhOj/u1VnZ9H+oSPg1v30E+jCFP/5n/8pjz/+uFmoQpff14UqrNkzCQkJct5558ljjz0m48ePNyfPul+RTvuyLvYh9i1YsMD0Eb0YM3nyZDP9b82aNWbfqpHoJwm6BGAYfg/EoJdeekluvvnmoF97++23Azb/1RMoLRzVP4Q6OqHFgogvuoiJ7lWmw+o6jK77yOiKOohPuoFrMDribYVt3Rfk3nvvNQsVtLe3m5VDdXUv/2kZiD+XXXaZuYqsG0Yr+gnU3/72N1mxYoVZNEsXyNKLef413no6q6PiGrZ0uujhhx9u+omOeiI+NDU1mY19//KXv5iBAH2P0KmAuoemtUp1JPsJoQoAAAAAhoF9qgAAAABgGAhVAAAAADAMhCoAAAAAGAZCFQAAAAAMA6EKAAAAAIaBUAUAAAAAw0CoAgAAAIBhIFQBAOKGbjysGxProRs/jjTdON36+dbmtgAA50uOdgMAABhqMLn88ssH/PpRRx0ljzzyyIBf18eefvrp4nK5ZKTNnj1bXn75ZfnZz34m7e3tI/7zAQCRQagCADiKFUz6ev311+W2226Ts88+e9DHZ2ZmSlFRkURDSkqK+dlpaWmEKgCIIUz/AwA4ihVM/A+dyvfzn/9cli5dKl/5yleG9O+99NJLcsIJJ8jf/vY3OfPMM2X+/Pnywx/+UFpbW+V3v/udmTL4pS99Se68807p6uryPU7vf/TRR+XGG2+UBQsWyOLFi+Wvf/2r7N27V66++mpz33/8x3/Ixx9/HIFnAQBgJ4QqAICjaaDS+qQjjzxS/uu//uug/g0NUE899ZQsX75c7r//flm/fr384Ac/kHXr1pmwdsstt8gLL7wgf/rTnwIet3btWjNytmbNGjn22GNNwLrpppvkq1/9qvzqV7+ScePGmc97enrC9NsCAOyIUAUAcKzu7m65/vrrJSkpSW699VZJSEg4qH+ns7NTrr32Wpk+fboJZyeeeKK89957csMNN8jkyZPNqJMuLqH1XP6OOeYYOeuss2TChAly6aWXSlNTk8yYMcOMlk2cOFEuuugi2bp1q9TV1YXpNwYA2BGhCgDgWA888IBs2LDBLPyQlZV10P9Oenq6GVWyFBYWypgxY0z9laWgoMBM7fNXXl4e8Bg1derUgMeovo8DAMQWFqoAADjSH/7wBzPF7t577zUjRcORnJx8wPt0FExHxgb6HmuULNh9fR8HAIgtjFQBABxn06ZN8pOf/ESuuOIKmTdvXrSbAwCIc4xUAQAcZd++fWYRCd2PatGiRVJbWxvwda2vys/Pj1r7AADxh1AFAHCUN954Q3bv3m2OhQsX9vv66NGjzTLpAACMlIQe1nkFAMQJ3VvqvPPOk/PPPz+q7Vi2bJlZCl4X2AAAOB81VQCAuKL7UOkS6W63e8R/9rvvvmt+9v/93/+N+M8GAEQOI1UAgLihUwZ1Tyo1duxYSUwc2WuLuslwTU2N+TgjI0OKiopG9OcDACKDUAUAAAAAw8D0PwAAAAAYBkIVAAAAAAwDoQoAAAAAhoFQBQAAAADDQKgCAAAAgGEgVAEAAADAMBCqAAAAAGAYCFUAAAAAMAyEKgAAAACQg/f/ASyAC91cvSXSAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "_ = lens_np.draw()" ] }, { "cell_type": "code", "execution_count": 10, "id": "b1000015", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Autograd Adam final (r1, r2) : (75.0938, -77.9356)\n", "\tFinal RMS Spot Size: 0.11299 mm\n", "LM (SciPy) final (r1, r2) : (76.3238, -76.6639)\n", "\tFinal RMS Spot Size: 0.114909 mm\n" ] } ], "source": [ "# Restore PyTorch backend\n", "be.set_backend(\"torch\")\n", "be.set_precision(\"float64\")\n", "be.grad_mode.enable()\n", "\n", "print(f\"Autograd Adam final (r1, r2) : ({r1_param.item():.4f}, {r2_param.item():.4f})\")\n", "print(f\"\\tFinal RMS Spot Size: {losses[-1]:.5f} mm\")\n", "print(f\"LM (SciPy) final (r1, r2) : ({np_final_r1:.4f}, {np_final_r2:.4f})\")\n", "print(f\"\\tFinal RMS Spot Size: {final_rms:.6f} mm\")" ] }, { "cell_type": "markdown", "id": "b1000016", "metadata": {}, "source": [ "## 7. Multi-field differentiable optimization\n", "\n", "Real designs must perform well across many field points. We build a loss that averages RMS spot\n", "size over three normalized field angles and optimize simultaneously." ] }, { "cell_type": "code", "execution_count": 11, "id": "b1000017", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Step 50 | mean RMS=0.27707 mm | r1=76.49 r2=-77.46\n", "Step 100 | mean RMS=0.27034 mm | r1=75.66 r2=-78.84\n", "Step 150 | mean RMS=0.26638 mm | r1=74.32 r2=-80.36\n" ] } ], "source": [ "from optiland.optic import Optic\n", "\n", "\n", "def make_singlet_multifield(r1=70.0, r2=-70.0, thickness=70.0):\n", " \"\"\"Singlet with three field angles.\"\"\"\n", " lens = Optic(name=\"Singlet (multi-field)\")\n", " glass = Material(\"N-BK7\")\n", " lens.surfaces.add(index=0, radius=be.inf, thickness=be.inf)\n", " lens.surfaces.add(index=1, radius=r1, thickness=7.0, material=glass, is_stop=True)\n", " lens.surfaces.add(index=2, radius=r2, thickness=thickness)\n", " lens.surfaces.add(index=3)\n", " lens.set_aperture(aperture_type=\"EPD\", value=25.0)\n", " lens.fields.set_type(\"angle\")\n", " lens.fields.add(y=0.0)\n", " lens.fields.add(y=5.0)\n", " lens.fields.add(y=10.0)\n", " lens.wavelengths.add(value=0.55, is_primary=True)\n", " return lens\n", "\n", "\n", "lens_mf = make_singlet_multifield()\n", "r1_mf = lens_mf.surfaces.surfaces[1].geometry.radius\n", "r2_mf = lens_mf.surfaces.surfaces[2].geometry.radius\n", "\n", "optimizer_mf = optim.Adam([r1_mf, r2_mf], lr=0.5)\n", "losses_mf = []\n", "\n", "for step in range(150):\n", " optimizer_mf.zero_grad()\n", " # Average RMS across all three fields\n", " rms_all = SpotDiagram(lens_mf).rms_spot_radius()\n", " loss = sum(rms_all[fi][0] for fi in range(3)) / 3\n", " losses_mf.append(loss.item())\n", " loss.backward()\n", " torch.nn.utils.clip_grad_norm_([r1_mf, r2_mf], max_norm=50.0)\n", " optimizer_mf.step()\n", "\n", " if (step + 1) % 50 == 0:\n", " print(f\"Step {step+1:3d} | mean RMS={loss.item():.5f} mm \"\n", " f\"| r1={r1_mf.item():.2f} r2={r2_mf.item():.2f}\")" ] }, { "cell_type": "code", "execution_count": 12, "id": "b1000018", "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig, axes = plt.subplots(1, 2, figsize=(12, 4))\n", "axes[0].plot(losses)\n", "axes[0].set_title(\"On-axis only\")\n", "axes[0].set_xlabel(\"Iteration\")\n", "axes[0].set_ylabel(\"RMS spot [mm]\")\n", "axes[0].grid(alpha=0.3)\n", "axes[1].plot(losses_mf)\n", "axes[1].set_title(\"3-field average\")\n", "axes[1].set_xlabel(\"Iteration\")\n", "axes[1].set_ylabel(\"Mean RMS spot [mm]\")\n", "axes[1].grid(alpha=0.3)\n", "plt.tight_layout()\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "b1000019", "metadata": {}, "source": [ "## 8. Practical considerations\n", "\n", "**Numerical precision:** PyTorch defaults to `float32`. For optical design, switch to `float64`\n", "(as done in this tutorial) to avoid precision losses in intersection and normal computations.\n", "\n", "**Parameter bounds:** Unconstrained optimizers can walk radii to near-zero (degenerate surfaces).\n", "Either clamp with `param.data.clamp_(min_val, max_val)` after each step, or use Optiland's\n", "`TorchAdamOptimizer` which handles bounds automatically.\n", "\n", "**Gradient clipping:** Large gradients (especially early in training) can cause NaN. Clip with\n", "`torch.nn.utils.clip_grad_norm_` as shown above.\n", "\n", "**When to use Optiland's built-in PyTorch optimizer:**\n", "For standard workflows, `TorchAdamOptimizer` (via `OptimizationProblem`) handles gradient\n", "enabling, parameter wrapping, bounds, and scheduling automatically:\n", "\n", "```python\n", "from optiland.optimization import OptimizationProblem, TorchAdamOptimizer\n", "\n", "problem = OptimizationProblem()\n", "problem.add_variable(lens, 'radius', surface_number=1)\n", "problem.add_variable(lens, 'radius', surface_number=2)\n", "problem.add_operand('rms_spot_size', target=0.0, weight=1,\n", " input_data={'optic': lens, 'Hx': 0, \"Hy\": 0,\n", " 'wavelength': 0.55, 'distribution': 'hexapolar',\n", " 'num_rays': 6, \"surface_number\": -1})\n", "\n", "opt = TorchAdamOptimizer(problem)\n", "opt.optimize(n_steps=200, lr=0.5)\n", "```\n", "\n", "Use the manual loop (as in this tutorial) when you need a custom loss function, gradient\n", "clipping, multi-task loss weighting, or integration with an external ML training loop." ] }, { "cell_type": "markdown", "id": "b1000020", "metadata": {}, "source": [ "## Conclusion\n", "\n", "In this tutorial you learned how to:\n", "\n", "- Enable the PyTorch backend and compute gradients of optical metrics\n", "- Run a standard Adam loop with gradient clipping for stable convergence\n", "- Define a custom combined loss (spot size + focal length penalty)\n", "- Compare autograd optimization to a SciPy Levenberg-Marquardt baseline\n", "- Extend to multi-field optimization with a single `.backward()` call\n", "\n", "**Next steps:**\n", "- Try optimizing conic constants or freeform coefficients in addition to radii\n", "- Use GPU acceleration with `be.set_device('cuda')` for large ray sets\n", "- Integrate the differentiable lens into a larger PyTorch model for end-to-end camera-system training" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.13.2" } }, "nbformat": 4, "nbformat_minor": 5 }