{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "56b35836cc904086",
   "metadata": {},
   "source": [
    "# Parallel adjoint with a waveguide bend\n",
    "\n",
    "Adjoint methods are a core tool for inverse design, where the goal is to efficiently compute gradients of an objective with respect to many design parameters. In the standard adjoint workflow, Tidy3D first runs the forward simulation and then constructs the required adjoint simulations on the fly from the recorded monitor data. At that point, it determines which adjoint simulations are needed to obtain the requested gradients and runs them afterward.\n",
    "\n",
    "For some supported monitor outputs, however, the required adjoint simulations are known in advance and do not depend on the forward result. In those cases, Tidy3D can prepare one or more adjoint simulations, launch them in parallel with the forward simulation, and combine them with the forward data afterward. This is the idea behind parallel adjoint.\n",
    "\n",
    "To use parallel adjoint efficiently, the simulation has to be set up such that it is already clear beforehand which adjoint simulations will be needed. In practice, this means using only supported and gradient-relevant monitor outputs, and restricting those outputs to the data that actually enters the objective.\n",
    "\n",
    "When the supported adjoint work dominates the total runtime, this can lead to a speedup approaching 2x. In this notebook, we use a simple 2D waveguide bend as a toy example and compare the runtime of a single gradient evaluation with parallel adjoint switched off and on.\n",
    "\n",
    "If you are new to autograd in Tidy3D, useful general introductions are [Autograd0Overview](https://www.flexcompute.com/tidy3d/examples/notebooks/Autograd0Overview/), [Autograd0Quickstart](https://www.flexcompute.com/tidy3d/examples/notebooks/Autograd0Quickstart/), [Autograd1Intro](https://www.flexcompute.com/tidy3d/examples/notebooks/Autograd1Intro/), and [Autograd2GradientChecking](https://www.flexcompute.com/tidy3d/examples/notebooks/Autograd2GradientChecking/).\n",
    "\n",
    "<img src=\"./img/adjoint_30.png\" style=\"width:65%;\" alt=\"Schematic comparing regular adjoint and parallel adjoint workflows.\">\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 225,
   "id": "fc6d6196d7712a25",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-03-31T13:52:36.852555Z",
     "start_time": "2026-03-31T13:52:36.688379Z"
    }
   },
   "outputs": [],
   "source": [
    "import time\n",
    "\n",
    "import autograd as ag\n",
    "import autograd.numpy as anp\n",
    "import matplotlib.pylab as plt\n",
    "import numpy as np\n",
    "import tidy3d as td\n",
    "import tidy3d.web as web\n",
    "from tidy3d.config import config\n",
    "\n",
    "# make sure that runtime measures are not impacted by caching\n",
    "td.config.web.enable_caching = False\n",
    "td.config.local_cache.enabled = False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4b07aa49dacf6240",
   "metadata": {},
   "source": [
    "## Setup\n",
    "\n",
    "As a simple toy example, we use a 90 degree SiN waveguide bend and measure the gradient of the transmitted mode power with respect to a single geometric parameter. The parameter controls the waveguide width near the middle of the bend and tapers linearly back to the nominal width at the input and output.\n",
    "\n",
    "The point here is not this particular parameterization. It is just a compact example that makes the `parallel adjoint` workflow easy to see.\n",
    "\n",
    "We use a clean 2D approximation of the bend. The simulation is invariant in `z`, so the computational domain is collapsed with `size=(Lx, Ly, 0)`, PML is applied only in `x` and `y`, and we use a uniform cladding background for the 2D model.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 226,
   "id": "b26245115ac00d30",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-03-31T13:52:36.917137Z",
     "start_time": "2026-03-31T13:52:36.863960Z"
    }
   },
   "outputs": [],
   "source": [
    "wavelength = 1.55\n",
    "freq0 = td.C_0 / wavelength\n",
    "fwidth = freq0 / 8\n",
    "monitor_freq = freq0\n",
    "\n",
    "# discretization of the bend profile\n",
    "num_pts = 40\n",
    "angles = np.linspace(0, np.pi / 2, num_pts + 2)[1:-1]\n",
    "bend_position = np.linspace(0.0, 1.0, num_pts + 2)[1:-1]\n",
    "middle_weight = 1.0 - np.abs(2.0 * bend_position - 1.0)\n",
    "\n",
    "# refractive indices\n",
    "n_wg = 2.0\n",
    "n_sub = 1.5\n",
    "\n",
    "# geometric parameters\n",
    "design_buffer = 1.0 * wavelength\n",
    "straight_length = 1.0 * wavelength\n",
    "h = 0.7\n",
    "wg_width = 1.5\n",
    "middle_width_max = 2.3\n",
    "radius = 6.0\n",
    "\n",
    "# simulation and mode settings\n",
    "monitor_name = \"mode\"\n",
    "min_steps_per_wvl = 20\n",
    "num_modes = 3\n",
    "mode_spec = td.ModeSpec(num_modes=num_modes)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c001f6559c2ca7bd",
   "metadata": {},
   "source": [
    "From these values, we can define the simulation size.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 227,
   "id": "f6814212f149e812",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-03-31T13:52:36.957943Z",
     "start_time": "2026-03-31T13:52:36.939248Z"
    }
   },
   "outputs": [],
   "source": [
    "outer_radius_max = radius + middle_width_max / 2\n",
    "Lx = Ly = straight_length + outer_radius_max + design_buffer\n",
    "Lz = design_buffer + h + design_buffer\n",
    "\n",
    "middle_width0 = 2.0"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dea593b5d3061872",
   "metadata": {},
   "source": [
    "## Bend Parameterization\n",
    "\n",
    "Here we define how our waveguide bend is built dependent on a single parameter by defining vertex positions. Note that this parametrization is just for demonstration purposes.\n",
    "\n",
    "We keep the ends of the bend fixed and vary only the width towards the center. The bend starts with the nominal width at both ends, reaches a parameter-defined width at 45 degrees, and changes linearly along the arc.\n",
    "\n",
    "For a more deliberate waveguide-bend parametrization, see [Autograd8WaveguideBend](https://www.flexcompute.com/tidy3d/examples/notebooks/Autograd8WaveguideBend/).\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 228,
   "id": "1f61ea7ef80a9de6",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-03-31T13:52:37.021931Z",
     "start_time": "2026-03-31T13:52:37.003233Z"
    }
   },
   "outputs": [],
   "source": [
    "def section_widths(middle_width):\n",
    "    \"\"\"Waveguide width along the bend.\"\"\"\n",
    "    return wg_width + (middle_width - wg_width) * middle_weight\n",
    "\n",
    "\n",
    "def make_vertices(middle_width):\n",
    "    \"\"\"Polygon vertices for the bend.\"\"\"\n",
    "    widths = section_widths(middle_width)\n",
    "    outer_radii = radius + widths / 2\n",
    "    inner_radii = radius - widths / 2\n",
    "\n",
    "    x0 = -Lx / 2 + straight_length\n",
    "    y0 = -Ly / 2 + straight_length\n",
    "\n",
    "    vertices = []\n",
    "\n",
    "    vertices.append((-Lx / 2 + 1e-2, y0 + radius + wg_width / 2))\n",
    "    vertices.append((x0, y0 + radius + wg_width / 2))\n",
    "\n",
    "    for angle, outer_radius in zip(angles, outer_radii):\n",
    "        x = outer_radius * np.sin(angle) + x0\n",
    "        y = outer_radius * np.cos(angle) + y0\n",
    "        vertices.append((x, y))\n",
    "\n",
    "    vertices.append((x0 + radius + wg_width / 2, y0))\n",
    "    vertices.append((x0 + radius + wg_width / 2, -Ly / 2 + 1e-2))\n",
    "    vertices.append((x0 + radius - wg_width / 2, -Ly / 2 + 1e-2))\n",
    "    vertices.append((x0 + radius - wg_width / 2, y0))\n",
    "\n",
    "    for angle, inner_radius in zip(angles[::-1], inner_radii[::-1]):\n",
    "        x = inner_radius * np.sin(angle) + x0\n",
    "        y = inner_radius * np.cos(angle) + y0\n",
    "        vertices.append((x, y))\n",
    "\n",
    "    vertices.append((x0, y0 + radius - wg_width / 2))\n",
    "    vertices.append((-Lx / 2 + 1e-2, y0 + radius - wg_width / 2))\n",
    "    return vertices\n",
    "\n",
    "\n",
    "def make_polyslab(middle_width):\n",
    "    \"\"\"`PolySlab` representation of the bend.\"\"\"\n",
    "    return td.PolySlab(vertices=make_vertices(middle_width), slab_bounds=(-h / 2, h / 2), axis=2)\n",
    "\n",
    "\n",
    "def make_bend(middle_width):\n",
    "    \"\"\"Waveguide bend structure.\"\"\"\n",
    "    return td.Structure(\n",
    "        geometry=make_polyslab(middle_width),\n",
    "        medium=td.Medium(permittivity=n_wg**2),\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f6225c12c9becddc",
   "metadata": {},
   "source": [
    "## Sources, Monitors, and Simulation\n",
    "\n",
    "Here, we add short straight input and output waveguide sections around the bend and then define the source, monitor, and full 2D simulation. The straight sections serve as clean ports: the `ModeSource` launches a guided mode from the input arm, and the ModeMonitor measures the outgoing modal amplitude on the output arm after the bend. The source and monitor planes are made slightly wider than the nominal waveguide using design_buffer so the modal fields are captured comfortably. Finally, `make_sim()` assembles the full simulation with the bend geometry, the two straight access waveguides, a uniform substrate-index background for the 2D model, automatic meshing, and PML boundaries in x and y.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 230,
   "id": "df60674c837b8096",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-03-31T13:52:37.597231Z",
     "start_time": "2026-03-31T13:52:37.547499Z"
    }
   },
   "outputs": [],
   "source": [
    "box_in = td.Box.from_bounds(\n",
    "    rmin=(-Lx / 2 - 1, -Ly / 2 + straight_length + radius - wg_width / 2, -h / 2),\n",
    "    rmax=(\n",
    "        -Lx / 2 + straight_length + 1e-3,\n",
    "        -Ly / 2 + straight_length + radius + wg_width / 2,\n",
    "        +h / 2,\n",
    "    ),\n",
    ")\n",
    "box_out = td.Box.from_bounds(\n",
    "    rmin=(-Lx / 2 + straight_length + radius - wg_width / 2, -Ly / 2 - 1, -h / 2),\n",
    "    rmax=(-Lx / 2 + straight_length + radius + wg_width / 2, -Ly / 2 + straight_length, +h / 2),\n",
    ")\n",
    "\n",
    "wg_in = td.Structure(geometry=box_in, medium=td.Medium(permittivity=n_wg**2))\n",
    "wg_out = td.Structure(geometry=box_out, medium=td.Medium(permittivity=n_wg**2))\n",
    "sim_medium = td.Medium(permittivity=n_sub**2)\n",
    "\n",
    "mode_width = wg_width + 2 * design_buffer\n",
    "mode_height = Lz\n",
    "\n",
    "mode_src = td.ModeSource(\n",
    "    size=(0, mode_width, mode_height),\n",
    "    center=(-Lx / 2 + straight_length / 2, -Ly / 2 + straight_length + radius, 0),\n",
    "    direction=\"+\",\n",
    "    source_time=td.GaussianPulse(freq0=freq0, fwidth=fwidth),\n",
    ")\n",
    "\n",
    "mode_mnt = td.ModeMonitor(\n",
    "    size=(mode_width, 0, mode_height),\n",
    "    center=(-Lx / 2 + straight_length + radius, -Ly / 2 + straight_length / 2, 0),\n",
    "    name=monitor_name,\n",
    "    freqs=[monitor_freq],\n",
    "    mode_spec=mode_spec,\n",
    ")\n",
    "\n",
    "\n",
    "def make_sim(middle_width):\n",
    "    return td.Simulation(\n",
    "        size=(Lx, Ly, 0),\n",
    "        medium=sim_medium,\n",
    "        structures=[wg_in, wg_out, make_bend(middle_width)],\n",
    "        sources=[mode_src],\n",
    "        grid_spec=td.GridSpec.auto(min_steps_per_wvl=min_steps_per_wvl),\n",
    "        boundary_spec=td.BoundarySpec.pml(x=True, y=True, z=False),\n",
    "        monitors=[mode_mnt],\n",
    "        run_time=10 / fwidth,\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d16e4db808812e33",
   "metadata": {},
   "source": "Let's visualize our experimental setup to review the correct arrangement of our components."
  },
  {
   "cell_type": "code",
   "execution_count": 231,
   "id": "4b4bd843097db09f",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-03-31T13:52:37.835721Z",
     "start_time": "2026-03-31T13:52:37.617801Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAekAAAHqCAYAAAAgWrY5AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAcqBJREFUeJzt3Xl4G9WhPv53RqPFlixZkbeYLA5ZyUZWQqAtFHIxkAtNS4HyAwKUli1hSy/wpZdCF24DtOxb2t4CvS0UGlrWUmgIEAgJhGxAyEJIQhKS2I4dW5JlaxnN/P4wki1vmpFGi6338zx+IPIZ6WjOWK9m5iyCqqoqiIiIKO+Iua4AERER9Y4hTURElKcY0kRERHmKIU1ERJSnGNJERER5iiFNRESUpxjSREREeYohTURElKcY0kRERHmKIU2UB04++WRMnjw519VI8POf/xyCIBjyXDU1Nbj00ksNeS69jHwfMe+88w4EQcA777xj6PMSdceQJurmo48+wuLFizFp0iTY7XaMGDEC5513Hj7//PMeZU8++WQIggBBECCKIpxOJ8aPH4+LL74YK1asyEHtyUiPPfYYnnrqqVxXgwqYlOsKEOWbu+++G++//z7OPfdcTJ06FXV1dXjkkUcwY8YMfPDBBz3OeIcNG4alS5cCAAKBAL744gv84x//wF/+8hecd955+Mtf/gKz2ZyLt5I3duzYAVEceOcEjz32GMrKynpcBfjWt76F9vZ2WCyW3FSMCgZDmqibJUuW4Jlnnkn4AD7//PMxZcoU3HXXXfjLX/6SUN7lcuGiiy5KeOyuu+7Cddddh8ceeww1NTW4++67s1L3fGW1WnNdBUOJogibzZbralABGHhfbYky7IQTTuhxhjR27FhMmjQJ27Zt0/QcJpMJDz30ECZOnIhHHnkEXq9X03YbNmzACSecgKKiIowaNQrLli3rUSYUCuGOO+7AmDFjYLVaMXz4cNx8880IhUIJ5QRBwOLFi/Hiiy9i8uTJsFqtmDRpEl5//fUez7l69WrMnj0bNpsNo0ePxu9+9ztN9QWAnTt34pxzzkFVVRVsNhuGDRuGH/zgBwnvufs96aeeegqCIGD16tW47rrrUF5ejtLSUlx55ZUIh8NoaWnBwoUL4Xa74Xa7cfPNN6Prgn193RP+8ssvIQhC0kvUTz75JE455RRUVFTAarVi4sSJePzxxxPK1NTU4LPPPsOqVavitzROPvnkfl9/+fLlmDlzJoqKilBWVoaLLroIBw4cSChz6aWXwuFw4MCBA1iwYAEcDgfKy8vxX//1X4hGo/3vbCo4PJMm0kBVVdTX12PSpEmatzGZTLjgggvws5/9DKtXr8b8+fP7Ld/c3IwzzzwT5513Hi644AL87W9/w9VXXw2LxYIf/vCHAABFUXD22Wdj9erVuOKKK3DMMcfg008/xf3334/PP/8cL774YsJzrl69Gv/4xz9wzTXXoKSkBA899BDOOecc7Nu3Dx6PBwDw6aef4rTTTkN5eTl+/vOfQ5Zl3HHHHaisrEz6HsPhMGpraxEKhXDttdeiqqoKBw4cwKuvvoqWlha4XK5+t49t84tf/AIffPABfv/736O0tBRr1qzBiBEj8Otf/xqvvfYafvOb32Dy5MlYuHBh0jpp8fjjj2PSpEk4++yzIUkSXnnlFVxzzTVQFAWLFi0CADzwwAO49tpr4XA48N///d8A0O8+eeqpp3DZZZdh9uzZWLp0Kerr6/Hggw/i/fffx6ZNm1BaWhovG41GUVtbizlz5uC3v/0t3nzzTdx7770YPXo0rr76akPeIw0SKhEl9ec//1kFoP7xj39MePykk05SJ02a1Od2L7zwggpAffDBB/t9/pNOOkkFoN57773xx0KhkDpt2jS1oqJCDYfD8XqIoqi+9957CdsvW7ZMBaC+//778ccAqBaLRf3iiy/ij3388ccqAPXhhx+OP7ZgwQLVZrOpe/fujT+2detW1WQyqck+IjZt2qQCUJcvX95vuZEjR6qXXHJJ/N9PPvmkCkCtra1VFUWJPz537lxVEAT1qquuij8my7I6bNgw9aSTToo/9vbbb6sA1Lfffjvhdfbs2aMCUJ988sn4Y3fccUeP99HW1tajjrW1terRRx+d8NikSZMSXrev1w+Hw2pFRYU6efJktb29PV7u1VdfVQGot99+e/yxSy65RAWg/vKXv0x4zunTp6szZ87s8VpU2Hi5myiJ7du3Y9GiRZg7dy4uueQSXds6HA4AgN/vT1pWkiRceeWV8X9bLBZceeWVaGhowIYNGwB0XE495phjMGHCBDQ2NsZ/TjnlFADA22+/nfCc8+bNw+jRo+P/njp1KpxOJ3bv3g2g44zujTfewIIFCzBixIh4uWOOOQa1tbVJ6xw7U37jjTfQ1taWtHx3l19+ecLwqDlz5kBVVVx++eXxx0wmE2bNmhWvsxGKiori/+/1etHY2IiTTjoJu3fv1nxroqv169ejoaEB11xzTcK96vnz52PChAn45z//2WObq666KuHf3/zmNw19jzQ4MKSJ+lFXV4f58+fD5XLh+eefh8lk0rV9a2srAKCkpCRp2erqatjt9oTHxo0bB6DjXivQcf/3s88+Q3l5ecJPrFxDQ0PC9l2DN8btdqO5uRkAcPjwYbS3t2Ps2LE9yo0fPz5pnUeNGoUlS5bgf//3f1FWVoba2lo8+uijmoOue/1ioT98+PAej8fqbIT3338f8+bNg91uR2lpKcrLy/HTn/4UAFIK6b179wLofZ9NmDAh/vsYm82G8vLyhMe6tgtRDO9JE/XB6/XijDPOQEtLC9577z1UV1frfo4tW7YAAMaMGWNInRRFwZQpU3Dffff1+vvu4dbXlwq1SyesdN1777249NJL8dJLL+Hf//43rrvuOixduhQffPABhg0b1u+2fdWvt8e71rmvyUm0dLzatWsXTj31VEyYMAH33Xcfhg8fDovFgtdeew33338/FEVJ+hzp0vtljwoXQ5qoF8FgEGeddRY+//xzvPnmm5g4caLu54hGo3jmmWdQXFyMb3zjG0nLHzx4EIFAIOFsOjaBSk1NDQBg9OjR+Pjjj3HqqacaMotWeXk5ioqKsHPnzh6/27Fjh+bnmTJlCqZMmYLbbrsNa9aswYknnohly5bhzjvvTLuOvXG73QCAlpaWhMe7n7H25pVXXkEoFMLLL7+ccCbf/VYB0PeXge5GjhwJoGOfxW49xOzYsSP+eyK9eLmbqJtoNIrzzz8fa9euxfLlyzF37tyUnuO6667Dtm3bcN1118HpdCbdRpblhKFP4XAYv/vd71BeXo6ZM2cCAM477zwcOHAAf/jDH3ps397ejkAgoKueJpMJtbW1ePHFF7Fv377449u2bcMbb7yRdHufzwdZlhMemzJlCkRR7DEkzEgjR46EyWTCu+++m/D4Y489lnTb2Fls1zNzr9eLJ598skdZu93e44tAb2bNmoWKigosW7Ys4X3/61//wrZt25L27CfqC8+kibr5yU9+gpdffhlnnXUWjhw50mPyku4Tl3i93niZtra2+Ixju3btwg9+8AP86le/0vS61dXVuPvuu/Hll19i3LhxeO6557B582b8/ve/j89YdvHFF+Nvf/sbrrrqKrz99ts48cQTEY1GsX37dvztb3/DG2+8gVmzZul6v7/4xS/w+uuv45vf/CauueYayLKMhx9+GJMmTcInn3zS77ZvvfUWFi9ejHPPPRfjxo2DLMv485//DJPJhHPOOUdXPfRwuVw499xz8fDDD0MQBIwePRqvvvpqj3vyvTnttNNgsVhw1lln4corr0Rrayv+8Ic/oKKiAocOHUooO3PmTDz++OO48847MWbMGFRUVPQ4UwYAs9mMu+++G5dddhlOOukkXHDBBfEhWDU1NbjxxhsNe+9UYHLbuZwo/8SGQ/X1019Zh8Ohjh07Vr3ooovUf//737pec9KkSer69evVuXPnqjabTR05cqT6yCOP9CgbDofVu+++W500aZJqtVpVt9utzpw5U/3FL36her3eeDkA6qJFi3ps3304lKqq6qpVq9SZM2eqFotFPfroo9Vly5b1OnSpu927d6s//OEP1dGjR6s2m00dMmSI+u1vf1t98803+33N2BCsjz76KKFc7DUPHz6c8Pgll1yi2u32hMcOHz6snnPOOWpxcbHqdrvVK6+8Ut2yZYumIVgvv/yyOnXqVNVms6k1NTXq3XffrT7xxBMqAHXPnj3xcnV1der8+fPVkpISFUB8OFZfQ8Cee+45dfr06arValWHDBmiXnjhhepXX32V9L30VU8iQVUN7EFCREREhuE9aSIiojzFkCYiIspTDGkiIqI8xZAmIiLKUwxpIiKiPMWQJiIiylOczEQjRVFw8OBBlJSUGDIdIxERFSZVVeH3+1FdXQ1R7P9cmSGt0cGDB/Hwww9DklLfZaqqorm5udfFDSwWS7yxFEVBOBxO+XVSJUlSwvsLhUKGLsSghSAIsFqt8X/Lstxj2slsYHt0YHt0Ynt0KpT2EAQBbre7zxMzQRASQlZVVc0LtPz617/G/v37ky5Cw5DWqKSkBJIkobi4OOk3n76oqoqamppeV8AJh8PxJfJcLhcsFkta9U2FoihoamoC0PFHGFs2MNu8Xm/8j97j8aS8v9PB9ujE9ujA9uhUKO0RjUbR2NjY79XTrl9QzGazpiutsSDXsoQtQ1qj2I4XRTE+j7IeiqJAURRYrdYeB3Q4HEZLS0t8Ifq2tjYUFxdn9cCPHfBmsxlWqxXBYBDRaFTTQWQkv98PRVHgcDgQCoXQ3t6e9Q8itkcntkcHtkenQmqPcDgMURTjP93FFlMRRRGqqiIajcJqtSZtj0gkAkDbKmvsOJZj4XAYjY2NMJvNKCsrQ1lZGcxmMxobG7N2CSl2wEciEZSVlcHj8cDpdMLn88Hv92elDkDHB5DP54PT6YTH40FZWRkikQiampqyssYvwPboiu3Rge3Rie3RKRQKQZZlSJKEoqIiWCwWqKqKUChkaHswpHOo6wEf+zYsiiI8Hk/WDvzuB3zs23BJSUlWD/yuH0Cxb8MWiyWrH0Rsj05sjw5sj05sj05dAzrWR0CSpIwENUM6R3o74GOydeD3dcDHZOvA7+0DKCZbH0Rsj05sjw5sj05sj069BXRMJoKaIZ0D/R3wMZk+8JMd8DGZPvD7+wCKyfQHEdujE9ujA9ujE9ujU38BHWN0UDOksywSiSQ94GMydeBrPeBjMnXga/kAisnUB5GWD6AYtkcntkcntkeHwd4eWgI6xsigZkhnkaIoaG5u1nTAxxh94Os94GOMPvD1fADFGP1BpOcDKIbt0Ynt0Ynt0WGwtkc4HNYc0DFGBTVDWgeTyZTyYPloNBpvZL1DJow68FM94GOMOvBT+QCKMeqDKJUPoBi2Rye2Rye2R4fB1h6yLCMajeoK6BgjgpohrVMkEtG9o2VZRjgchiAIKC0tTWlMY7oHfroHfEy6B346H0Ax6X4QpfMBFMP26MT26MT26DBY2iMQCEBRFJhMJt0BHZNuUDOkdYjtXD07umtAm0ymtCYdSPXAN+qAj0n1wDfiAygm1Q8iIz6AYtgendgendgeHQZDe7S2tkIUxbTr0D2o9VyRZUjroKoqJEnS/I2oa0BrmYVGC70HvtEHfIzeA9/ID6AYvR9ERn4AxbA9OrE9OrE9Ogz09nA4HGmt19BV16COzTimBUNap9i3qmRB3T2gjVw5S+uBn6kDPkbrgZ+JD6AYrR9EmfgAimF7dGJ7dGJ7dBjI7WG32w2tQyyo9WBIpyDZPYZMnEF3l+zAz/QBH5PswM/kB1BMsg+iTH4AxbA9OrE9OrE9OrA9OnVfvSsZhnSK+grqbAR0TF8HfrYO+Ji+DvxsHPAxfX0QZeMDKIbt0Ynt0Ynt0YHt0UnPfuYqWGmIfRsKh8MIhUIwm81ZC+iY2IHf1NSExsZGeDwe+Hy+rB3wMbGD2ufzxR/L1gEfE/sgamxsRFNTE5xOZ3ylnGytFMT26MT26MT26MD20I8hnaZYUIdCIYRCoawGdEzswG9sbERjYyMAoLy8POtrvHY/8HNxwMc+iA4fPpy1M4Tu2B6d2B6d2B4d2B768HI3ERFRnmJIpyl2D1oUxfhgd6PXE00mdk9HluX4JaNsru8a0/WeTi7WdwU677HFzhhkWc7qersA26MrtkcntkcHtoc+DOk0dO8klqn1RPvTvdOF1WrN6vquMd07XWR7fVegZycYq9Wa1fV2AbZHV2yPTmyPDmwP/XhPWidVVaEoCqLRaDygzWYzgI4DUBTFeAeyYDAIi8UCURShKIruQexa6tLc3AxZluF2uwEgfpA7nU40NzejoaEBbrc7XsdMCAQCaG1thcPhgNVqjdfBarWiuLgYLS0tkGXZ8DGHXUUiETQ3N0OSJDidTsiyHP+dy+VK2BdGjlnviu3Rie3Rie3RYSC2RyQSiX/mGykajWouy5DWITaVmyzLkGUZoijGO451bcRYcMuyjEgkEp+lLHaGraeB+qtL7DK7w+FANBrt8bxFRUUIh8MIBALxLwtGi71Hu90Ok8mEYDCY8HuTyQS73Y5wOByfsc1oiqIgHA7DarXCYrEgFAr1KONwOBAOh+Hz+WCxWAz/IGJ7dGJ7dGJ7dBio7QF07D8j90fsJE8rhrQOLS0tOOqoo9DW1oaioqKk3zq7fnuN/RGceeaZcLlcWaw1ERGlwuv14rXXXoPVajXk7D6WCXqeiyGtg6qqCAQCsNlsmoYtWCyW+L2W1tZWFBUVweVyYciQIVmqMRERpctsNqc9RCwcDsPr9cJqtaKoqEjzduw4poPVaoXJZNI1rrBrL8ps914kIqL0RCIRBAKBtJ4jrfW503rlAqMoCpxOp+57JRaLBW63W9fyZERElHtmsxmtra0p9/pOd+pVhrQOsY4PqTDicgkREWVXrE9RKsOzjJgbnfeksyibU+8REZEx7HY7JEmKTyGqZfpQoxYvYUgTEREl0X2u7/6C2sjVxRjSREREGmgJaqOX/2RIExERadRfUGdifW6GNBERkQ69BXUmAhpgSBMREenWNajD4TBCoVBG1udmSBMREaUgdgYdmwPc6IAGOE6aiIgoJbEz6Jh0ZybrDc+kiYiIdOp+DzoQCOgaR60VQ3qQ8ck+vNnyZsJj80rnwSk5c1QjIqLBpbdOYnrGUevBkCYiItKov17cmQhqhjQREZEGWoZZGR3UDGkiIqIk9IyDNjKoGdJZxKUqiYgGnkgkAq/Xq2sctFFBzZDWQZJS312qqiIcDhtYGyIiyjRFUeDz+WC1WnWPgzYiqBnSOkiShLa2NhQXF+vaTlEUNDc3c6lKIqIBJhwOQ5KklCcqSTeoGdI6yLKMQCAAq9WqeUcrioKmpibIsgyHw5HhGhIRkZEEQYDb7U7rJKt7UJtMJs3bMqR1kGUZdrtd8zeiWEBHIhG43W5Eo9FsVJOIiAxisVggCELaz9M1qK1Wq+btGNI6FRcXw2q1Jg3qrgFdVlYGAAxpIqIBxoiAjonlxZEjRzRvw5BOQbJ7DN0D2mKxsNMYERGhpKQkYb7vZBjSKeorqHsLaCIiohg9nY8Z0mnoHtR2u50BTUREhmFIp6lrUPt8PgiCwIAmIiJDcOCuAex2e/z/rVYrA5qIiAzBkE5T7B60IAiw2WwIBoPw+/25rhYREQ0CvNydht46ifn9/ows/E1ERIWHIZ2ivnpxZ2rhbyIiGhwURdFcliGdgmTDrBjURETUm9iCHVoxpHXSOg66e1DrmQaOiIgGn1h+6Jl9kiGtUyx0tQyz6hrUxcXFuiZVJyKi3NNzaTrZ88RO8Fwul+bt8rp391133QVBEHDDDTf0W2758uWYMGECbDYbpkyZgtdeey3h96qq4vbbb8fQoUNRVFSEefPmYefOnbrrY7FYEI1GdY2DLikpgdPpRGtrK2RZ1v2aRESUO+FwGJFIJK3n6H4FVpK0nx/nbUh/9NFH+N3vfoepU6f2W27NmjW44IILcPnll2PTpk1YsGABFixYgC1btsTL3HPPPXjooYewbNkyfPjhh7Db7aitrUUwGNRVJ1EU4XK5dI+DLikpgcPhSLuhiYgouwRBQHNzc8rrL6Q7VXRehnRraysuvPBC/OEPf4Db7e637IMPPojTTz8dN910E4455hj86le/wowZM/DII48A6DiLfuCBB3DbbbfhO9/5DqZOnYr/+7//w8GDB/Hiiy/qqlcoFNL1Dagru90Os9mc0rZERJQbFosFkiShsbFRd1AbsZZDXob0okWLMH/+fMybNy9p2bVr1/YoV1tbi7Vr1wIA9uzZg7q6uoQyLpcLc+bMiZfRSlVVXeW7SzXgiYgoNwRBgNvthtls1hXURi22lHep8eyzz2Ljxo346KOPNJWvq6tDZWVlwmOVlZWoq6uL/z72WF9lehMKhRKWE9PTZZ6IiAYPQRDg8XjQ1NSExsbGpKFr5GqIeXUmvX//flx//fV4+umnYbPZclqXpUuXwuVyxX+GDx+e0/oQEVHuiKIIj8eT9Iza6OWK8yqkN2zYgIaGBsyYMQOSJEGSJKxatQoPPfQQJEnqdWxZVVUV6uvrEx6rr69HVVVV/Pexx/oq05tbb70VXq83/rN///503x4REQ1gyYLa6IAG8iykTz31VHz66afYvHlz/GfWrFm48MILsXnz5l7HGc+dOxcrV65MeGzFihWYO3cuAGDUqFGoqqpKKOPz+fDhhx/Gy/TGarXC6XQm/BARUWHrK6gzEdBAnt2TLikpweTJkxMes9vt8Hg88ccXLlyIo446CkuXLgUAXH/99TjppJNw7733Yv78+Xj22Wexfv16/P73vweA+DjrO++8E2PHjsWoUaPws5/9DNXV1ViwYEFW3x8REQ18saCO3aP2eDzw+XyGBzSQZyGtxb59+yCKnRcATjjhBDzzzDO47bbb8NOf/hRjx47Fiy++mBD2N998MwKBAK644gq0tLTgG9/4Bl5//fWc3/cmIqKBKRbUjY2NaGxsBACUl5cbGtDAAAjpd955p99/A8C5556Lc889t8/nEAQBv/zlL/HLX/7S4NoRERFlTl7dkyYiIhoIYvegZVmOX+JOZcKTZBjSREREOnTvJGa1WjUNz0oFQ5qIiEijvnpxax1HrRdDmoiISINkw6wyEdQMaSIioiS0joM2OqgZ0kRERP1QVVXXRCVGBjVDWgdBENLaXpZlg2pCRETZoKoqmpubdU9UYlRQM6R1sFqtKQdtIBBAJBIxuEZERJRJ4XA4YZiVHkYENUNaB0VR4PV6de9ov9+P1tZWmM3mDNWMiIgyQVVVuN3ulGcSSzeoGdI6hMNhmEwmXTva7/fD5/PB4XBAkvJ+gjciIurCYrGkfYLVPaj1XJFlSOvkdDo1fyOKBbTT6YTdbs9SDYmIyChd14pI93liQe31erVvZ8irFxCtly66BnRJSUmWa0lERPkmlh+9Lbvc5zYZrM+glSyoGdBERNQbURThdDq1l89gXQa1voKaAU1ERP3RcwmdPZnS0H3hb6vVimAwyIAmIiJD8Ew6TbGgVlUVwWAQNpuNAU1ERIZgSBsgEAjE/z8UChm+nigRERUmhnSaut6DHjp0aEbWEyUiosLEkE5D905imVpPlIiIChNDOkV99eJmUBMRUX/a2to0l2VIpyDZMCsGNRER9cbv9yf0Y0qGIa1TW1ubpnHQ3YOaK2AREQ08qqoa9lyxEzw900RznLQOkiQhEAhgyJAhmoZZdR1H3dzcDIfDkYVa5o6qqogqKmRFQURWICsK5OjXP4qKSFQBAIhCx9rcoiBA6PL/sX9Logir2QSb2QSTQfPmEhGlIhwOw2azpf08Xa/A6pkWlCGtgyRJ8EcAb3MQaA5q31BVIUVk+EJe3P78GkSloozVUTa14UjptoTH/tVihhQtzthrZpJkEmEzm2CVTLCZJVjNJljNJhSZJThsZpQUWeAssqDE1vHjLLKgpMgCm9kEQRByXX0iGuBUVUVzczMqKipSXmyj+y1SPfekGdI6yLIMRUxhyTJBQFSywhTlJW+95KiC1qiCVujbd5JJRInNjCEOGzyOIngcNpSVFGHI1/912608SyeipCwWC1pbW9HU1ASPx6M7qNOdKpohrYOeNUB7EqCK2i9xUHrkqILmQAjNgRB21fdcFk4QAHexDZ4SGyqdxahy21FdasfQUjtcxVaehRMRgI7blm63G16vV3dQG7GWA0OaCpKqAkcCQRwJBLGzriXhd0UWCUNL7agq7Qzuo4Y44Cq25qayRJRTZrMZZWVlaGxs1BzURi22xJAm6qY9LGN3gxe7GxLPwEuLrRhZ5sTIshKMLHdihMcJhy2F2x9ENOBYLBbNQW3kaogMaSKNWtpCaNl3GB/vOxx/rKykqCO0y5yoKXeiptwFs4n3uokGIy1BbfRyxQxpojQ0+tvR6G/Hhj0NAACzScSocifGVrkxpqoUR1e4YJHYF4FosOgvqI0OaIAhTWSoSFTB53Ut+Pzr+9wmUUBNWUdojx1aitEVpbCaGdpEA1lvQR0IBAwPaIAhTZRRUUXFrgYvdjV48fongCQKGF1ZisnDyzBpmAdVrmL2JCcagLoG9aFDhwDA8IAGGNJEWSUrKnYcasaOQ834+7qd8DhsmDTMg0nDPBg/dAjPsokGEIvFAqvVimCwY3IrPdN9asWQJsqhptYg3t1+AO9uPwBJFDC2yo3Jw8swvaYcbnv6UxESUeb4/X4Eg0HYbDaEQqGUJzzpD0OaKE/IioptB49g28EjWP7h5zi6woXpNRWYXlMOjyNzU8kSkX7dO4mFw2Fd46i1YkgT5anYWO2/r9uJkWVOzKipwPSaCpQ7GdhEudRbL24946j1YEgTDQB7G33Y2+jDC+u/wHBPCWaNqsRxoytRykviRFnV3zCrTAQ1Q5pogNnf5Mf+Jj9e3PAFjqkeguPHDMWxI8s5Hpsow7SMgzY6qBnSRAOUqgJbDxzB1gNHYDObMHNUJY4fMxSjK10c1kVkMD0TlRgZ1AzpbFLVXNeABqlgJIr3Pz+I9z8/iPKSIswZU4W5Y6sxxMHL4UTpCgQCaGtr0zUO2qigZkjrYLFYUg9aVYGgRo2tEFEvDvvb8eqmPfjn5j2YOrwcJx1zFMZXD4HIs2si3WRZRiAQQGlpqe6JSowIaoa0DqIowqSEEVXNHQsSayQoUUhyEKrI3U3Zo6rAx18vCFLhLMa3jjkKc8cMRbGVK3cRaRWJROBwOFKeSay3oNaDy/XoEAqFIKgKJLld8xl1R0C3QxVEqGL+duyJKjKiipzralCGNPja8PyHO3Hrc6vx9Opt2N/kz3WViAYEs9mc9kxisaCORCJoamqCoiiat+WpnQ6qqiJqskBSZUhyO2SpqN8z6q4BHTVZIKraGybb1u5dgXr/Poz2TMbRnolw2ty5rhJlQFhWsPrzg1j9+UEcXeHCqZNHYNqIcogiL4UT9UaSjInJrmfUkUhE++sb8uoFRBVMkE1mSHJ7v0HdNaBlqQhCHgc0AITkNniDR/DxoTXYWr8eQ50jMaZsMqqdo2DK4ysAlLrdDV7sfutTVDiLMG/ySBw/pgpmDuMiyphYUNfX12vehiGdAlU0QZaK+gzq7gENQQAGQMduSTSj2OxAJBrGvpad+Mq7CyXWUowpm4JRQybAbnHmuoqUAQ2+djyzZjte3bQbJ08cjm9NOAp23rcmygiLxQKXy6W5PEM6RX0Fda8BnWPb6zbDH2jtt4w/5AUACIIAi2SFBVZEFRn+YAs2fLUKnx76AMNLx2C0ZxKqSoZDENidYbDxtYfx8oZdeOPjL/GN8UfhlEnDOYSLKAP0XEJnSKehe1BHTZaOXtx5FNAAsO3Qx/AHvTAJ/V/KtEjWhH+bRAnFFgdUVUU4GsKuxs+w58h2lNo8GFs+FTXu8bCZizNZdcqBkBzFys/24e2t+zFnTBXOOHYU5wsnyhGGdJoSgzr/AjrGKtlgk1L7oBUEAVbJBovJiqgqo7n9MD7c9yY2H3wfNe7xGO2ZhDL7UM5yNcgoqoq1Ow/hwy/qcMLYoTh9Wg1X4yLKMoY0aSYIAiTBDMlihqIqCEdD2Fa/AV80bcGoIcfgxJrTc11FygBFVbH684NY+8UhnDiuGmccW8OFPYiyhCGdpu7DrCQ5qGl41kDWEdBByIoMs8kKT3EVRpSOyXW1KMOiiop3tx/Amp2H8M3xR6F26ki4iq3JNySilDGk09BbJ7H+en3nkqoqiCr9T0sqCmKfl6xVVUVUlRGSg1AB2KQijCmbgtGeSfAUV/FSdwGRowre3rofq3ccwEnHDMPpx9awNzhRhjCkU9RXL+5kw7NyQTKZEYy0IRRt77OMqnZczi4227s9riIcDSKiRCAKJriLKzDu605j1hTvcdPgEIkqeHPLPqz5/CDOnDYKJx0zDJKJvf6JkpFl7bM7MqRTkGyYVa9BnUPfHvefCAX7Pyg2HXgPDa0H4v+OKh1nzQoUWEw2jPaMx5iySah0DOPwK0rQFpbx/LqdWLXtKyyYPQbTR5bzygpRH8LhMLxer+byDGmdBDUKSQ4l7cXd2/CsXHHYnChNMlTKbLIAUBGSg4goYYiCiBKbG2PLpmDUkGNQbHFkp7I0YB32t+MPb32K0ZUufP+4sagp1z5hA1EhCIfDaGxshMmkfWY/hrQOgiDAFA1DNUmaLmN3DWqTHIJqyu/7dlFVgQRgpHv811OCjoSYZGw1UXe76r24+5X1mHV0JRbMGs1hWzSg6bk03Z9YQJvNZhQVaf+bYEjrYLVaO3px67jPHA/qSBuQpONWLtUMOQZl9moc7TkGJdbSXFeHBoH1u+uxee9hnDZlBGqn1sDCecFpAIpEIggEArBYUr8a2jWgPR4PgsGg5m0Z0jooioKoaNHdEawjqG0wKdpXPsm20Z6Jua4CDUJyVMFrm7/Eul31OP/4cZg8vCzXVSLSxWw2o7W1FZIkpbSmdPeAFkV9fXrYA0iHcDicek9tQYTKS8dUoBr97Xh0xcf43cpPcKRV+1kEUa5JkgSHwwGfzwe/X9867OkGNMAz6exij1cqcJv3Hsa2A0dw5vRROHXScJhS+NAiyja73Q5JkuDz+QBA0xm1EQEN5NmZ9NKlSzF79myUlJSgoqICCxYswI4dO5Jut3z5ckyYMAE2mw1TpkzBa6+9lvB7VVVx++23Y+jQoSgqKsK8efOwc+fOTL0NIupHSI7ihY++wP+8uA4765pzXR0iTUpKSuB0OjWdURsV0ECehfSqVauwaNEifPDBB1ixYgUikQhOO+00BAKBPrdZs2YNLrjgAlx++eXYtGkTFixYgAULFmDLli3xMvfccw8eeughLFu2DB9++CHsdjtqa2t13bwnImMdagngvtc24s+rt6E9bEwPWqJM0hLURgY0AAiqqqppPUMGHT58GBUVFVi1ahW+9a1v9Vrm/PPPRyAQwKuvvhp/7Pjjj8e0adOwbNkyqKqK6upq/OQnP8F//dd/AQC8Xi8qKyvx1FNP4Qc/+IGmuvh8Ptx8881wDx8LSPqHUglKFKIaRUvZhI7e4Rkim9pwpPSThMeGtEyFFOWSkpS/3HYrLjzxGEwa5sl1VYjijhw5guXLl8NmsyX07vb7/fD5fHA6nQmXvrUGdFtbG370ox/B6/XC6XT2W4e8OpPuLjYry5AhQ/oss3btWsybNy/hsdraWqxduxYAsGfPHtTV1SWUcblcmDNnTrwMEeVWcyCER/69Gf/33la0hfJ3FAQR0PsZtdFn0DF523FMURTccMMNOPHEEzF58uQ+y9XV1aGysjLhscrKStTV1cV/H3usrzK9CYVCCIVC8X/HOgwQUeas3XkI2w4cwYUnTuBwLcprsTNon8+HcDiMUChkeEADeXwmvWjRImzZsgXPPvtsTl5/6dKlcLlc8Z/hw4fnpB5EhaalLYRHV3zMs2rKeyUlJbDZbAgGg1BV1fCABvI0pBcvXoxXX30Vb7/9NoYNG9Zv2aqqKtTX1yc8Vl9fj6qqqvjvY4/1VaY3t956K7xeb/xn//79qbwVIkrR2p2H8MsXPsTWr5pyXRWiXsXOoGP66+ScqrwKaVVVsXjxYrzwwgt46623MGrUqKTbzJ07FytXrkx4bMWKFZg7dy4AYNSoUaiqqkoo4/P58OGHH8bL9MZqtcLpdCb8EFF2edtCePjfm/H8hzsRiSq5rg5RXNd70EOHDtU8PEuvvLonvWjRIjzzzDN46aWXUFJSEr9n7HK54hOSL1y4EEcddRSWLl0KALj++utx0kkn4d5778X8+fPx7LPPYv369fj9738PoGNRjBtuuAF33nknxo4di1GjRuFnP/sZqqursWDBgpy8TyLSZ+Vn+/B5XTN+ePIkVLnsyTcgyqDeOol1vUcNaJvwRIu8OpN+/PHH4fV6cfLJJ2Po0KHxn+eeey5eZt++fTh06FD83yeccAKeeeYZ/P73v8exxx6L559/Hi+++GJCZ7Obb74Z1157La644grMnj0bra2teP3112Gz2bL6/ogodfub/Fj60jq8//lB5PHIURrk+uvFrWfCE63yepx0PuE4aaL8MaOmAv/fiRNgt+b38q80sHUfJ611mFVf46hj9IyTzqvL3UREWmz8sgF7Dntx2UmTMLbKnevqUAHQMw7ayEvfeXW5m4hIq+ZACPf/ayPe+ORLXv6mjIpEIronKjHq0jdDWgdJSufCgwpBiRpWFyICVBV4cf0u/P6tTzn/N2WEoihobm5OaaISI4KaIa2DJEkQlRQmV1BVmOQQAH7bJ8qEzXsP466XP8LB5tZcV4UGmXA4DEmSUp6oJN2gZkjrIMsyTIoMMRrWvpGqQpLbIagKVMGUucoRFbgGXxvueWU91u+uT16YSCNBEOB2u9OaSSydoGbHMR1kWUZUlGD6OqQVk6X/DboEtCzZIA7yM+m5Y4eiNRiBPxhG4Ov/BiO8xE/ZE5Kj+OM7W/DlYS++O3sMTAZP0UiFx2KxQBCEtJ+na2cyq9WqeTuGtE5HV5cjGo1+3b3e1mevPUVR0NTUhEjEjLKyjoUCgsEglnz/hH5X9UqXT/bhzZbES/LzSk+CU8rNjGlyVEFrKIKWQAhHWttxJBDCkdZgx0+g478Bzs9MBlv52X7sbfTjR9+eDFex9g9Eou6MCOiYWF4cOXJE8zYM6RQk617fGdARlJWVxcfXFSLJJKK02IrSYitqynv/ohAIRVDvbUNdSwB13gDqWtpQ5w2g0d8OdtqlVH1R34K7X/kIV887FsM9xsz+RJSukpKShPm+k2FIp6ivoO4toKl/dqsZR1e4cHSFK+HxSFRBXUsAext92Nfkx/5GP75qboXMOZxJo+ZACPf+cwMuO3kSjh1RnuvqEAEAiou1Ty7FkE5D96C22+0MaAOZTSKGe0oSzoKiioJDLQHsa/Rjz2EvvqhvQV1LWw5rSfkuJEfxuzc/wfdmj8Gpk0cYevmSKNMY0mnqGtQ+nw+CIDCgM8gkihg2pATDhpTghHHVAIDWYBhf1HvxRV0LdtW3YF+THwqvk1MXKoC/f/QF6rxt+MHc8ZBM7FBGAwND2gB2uz1+Nm21WhnQWeawWTBtZDmmjey4nBmMyPiirgVbDzThs6+OoMHHM23q8P7nB3HY344rTpnCeb9pQGBIpyl2D1oQBFitVgSDQfj9fsOWKSP9bGYJk4eXYfLwjl71jf52bD3QhK1fHcGOQ0c4LKzAfX6oGfe8sh6L/uNYVLi48AzlN4Z0GnrrJBZb/QQwbj1RSk9ZSRG+NWEYvjVhGOSogs8PNWPT3gZ8vPcw/EEO/ypEDb423PPqetxwxnQMG8K/U8pfDOkU9dWLO1MLf5MxJJOIicM8mDjMgwvmTsCuhhZs3nsYm788jCOBYK6rR1kUCEXwwL82Magp6xRF+wgVhnQKkg2zYlAPDKIoYGyVG2Or3Pj+cWOxt9GHdbvq8NHuerTyDLsgMKgp2xRFiWeDFgxpnbSOg+4e1HqmgaPsEwQBNeUu1JS7cM5xY7H1qyP4cNchfLyvkeOyBzkGNWVLLD+iUe39YhjSOsVCV8swq65BXVxcDJOJC2wMBCZRxJQRZZgyogztYRkbv2zAms8PYneDN9dVowxhUFNf9FyaTvY8sRM8l8uVfIOvcbCgDhaLBdFoVNc46NjqJ62trZBlrnc70BRZJJw4rho3/ecs/PeC4/CtCUfBZuaXrcEoFtRfHUlt3V8anMLhMCKR9G5/db8CK0naz48Z0jqIogiXy6V7HHRJSQkcDkfaDU25NWxICS44YQKW/uAb+P9OmIBhQxy5rhIZjEFN3QmCgObm5pTXX0h3qmiGtA6hUEjXN6Cu7HY7zGZOnjAY2MwSvjnhKPz0O8fhpv+chRk1FeBMk4NHIBTBI//+GC3s7U/ouIIqSRIaGxt1B7URazkwpHVQ05xqMtWAp/wkCAKOrnDhx6dMwS/OOQEnTxwGi8Q/qcHA2xbCY29+ghAnvil4giDA7XbDbDbrCmqjFlviJwqRAcqdRTj/+PH49fnfwNkzR8NZxKlhB7r9TX489e5nnAeeIAgCPB6P5qA2cjVEhjSRgexWM844tgZ3nnciLjhhPNx2Dr0byDbvPYyXN+zKdTUoD4iiqCmojV6umCFNlAFmk4hvTRiGX3z/BIb1APfGJ3uxdufBXFeD8kCyoDY6oAGGNFFGdQ3rH8xlWA9UT7+/HTvrmnNdDcoDfQV1JgIaYEgTZYXZJOKkYzrC+rzjx8FhY0//gSSqqPjdyk+47CkB6BnUoVAoIwENMKSJsspsEvHticPxy++fgNqpI2E28U9woAiEZDz+5scIRjgpEXUGddfhWUYHNMCQJsqJIouEBbPG4OfnzMXxY4aCw6wHhrqWNvxl9ba0h2MSacWQJsqhIQ4bLvnWRPz0O8dh/FB3rqtDGmzY04CVn+3PdTUox2L3oGVZjp9BpzLhSTIMaaI8MMxTgutPn44ff3syO5cNAC989AU+P8SOZIWqeycxq9Wqaxy1HgxpojwhCAJmjKrE7d87HqdNGQmRc43mLUVV8b9vf8qpQwtQX724tY6j1oshTZRnbGYJ3509Brd9dw4vgecxfzCCP7y9heuNF5Bkw6wyEdQMaaI8NbTUjutPn44fnjyJQ7by1O4GL/7+0c5cV4OyQOs4aKODmiFNlMcEQcDso6tw+3ePx6yjK3NdHerFO1u/wrpddbmuBmWQqqq6xkEbGdQMaR2ENO8RyjLHV1JqSoosuPzkybhq3lS4uHhH3nnm/e04zIlOBiVVVdHc3Kx7ohKjgpohrYPVak05aAOBACKRiME1okJz7Ihy3P6943HC2KG5rgp1EZKjeOKdzxBVeH96sAmHwwnDrPQwIqgZ0jooigKv16t7R/v9frS2tsJs5n1FSl+x1YyLvzkRi/7jWC6JmUe+bPThlY27c10NMpiqqnC73amvB51mUDOkdQiHwzCZTLp2tN/vh8/ng8PhgCRJGa4hFZLJw8vw3wvmYPJwT66rQl/79yd7sf3gkVxXgwxksVjSPsHqHtR6rsgypHVyOp2avxHFAtrpdMJut2ephlRInEUWXDPvWPxg7njOA54HVABPvbsVrUHe2hosRNGYv6uuQe31erVvZ8irFxCtly66BnRJSUmWa0mFRBAEnHTMMNx69mwMG+LIdXUKnrcthL+s3sr5vamHWH6YTCbN2+i+/rpnzx6899572Lt3L9ra2lBeXo7p06dj7ty5sNlsep9uQIrt6KamJjQ2NvboUMCAplwY6nbg5rNm4/kPP8e72w/kujoF7eN9jXhvxwF8a8KwXFeF8owoinA6nZrLaw7pp59+Gg8++CDWr1+PyspKVFdXo6ioCEeOHMGuXbtgs9lw4YUX4pZbbsHIkSNTqvxA0ldQM6Apl8wmERecMAGjK0vx9PvbEJbZ2zhXnv9wJ8ZVuVFVyltdlEjPJXRNJadPn46HHnoIl156Kfbu3YtDhw5hw4YNWL16NbZu3Qqfz4eXXnoJiqJg1qxZWL58ecqVH0i6X/puampiQFNeOG50FW4+azYqnMW5rkrBikQV/N97W6EovOxNqdMU0nfddRc+/PBDXHPNNRg+fHiP31utVpx88slYtmwZtm/fjqOPPtrwiuarWFCrqopgMAibzcaAprxwlNuB/3f2bMyoqch1VQrWnsM+vPXZvlxXgwYwTSFdW1ur+Qk9Hg9mzpyZcoUGokAgEP//UChk+HqiRKkqskj40bcn45zZY8A1tXLj5Y27UecNJC9I1IuUB+42NDSgoaEBSrcZdqZOnZp2pQaS7sOs+upMRpQrgiBg3pSRqCy144l3tiAYiea6SgUlElXw5/e24SdnzoQo8qsS6aM7pDds2IBLLrkE27Ztiw8xEAQBqqpCEAREo4XzAdBbJ7H+en0T5dKU4WW46T9n4bEVH6OplesgZ9PuBi/e2rof8yaPyHVVaIDRPU76hz/8IcaNG4c1a9Zg9+7d2LNnT8J/C0VfvbgztfA3kRGq3Q7cctZsjKkszXVVCs7LG3ah3stFOAhoa9N+HOg+k969ezf+/ve/Y8yYMXo3HTSSDbPqbXgWUb4oKbLg+tOn45k127F256FcV6dgdFz23oolvOxd0Px+f0I/pmR0n0mfeuqp+Pjjj/VuNmi0tbVpGmbV/YyaK2BRPpFMIi7+xjE4c9qoXFeloOxq8GLV9q9yXQ3SwciZ42IneHqmidZ9Jv2///u/uOSSS7BlyxZMnjy5x8TjZ599tt6nHDAkSUIgEMCQIUM0DbPqekbd3NwMh4NTNlL+EAQBZ804Gq5iC55dswMczZsdL2/YhRk1FXAVW3NdFdIgHA4bMptm1yuwGZ0WdO3atXj//ffxr3/9q8fvBnvHMUmSYLfbdY2DjgV1Q0MD709TXvrWhGEosVnwxKrPIEc5Q1mmBSNRPL9uJy4/eXKuq0IaqKqK5uZmVFRUpLzYRvdbpHruSet+xWuvvRYXXXQRDh06BEVREn4Gc0ADgCzLKC7WP4OTKIpwu90QBN6Hovw0vaYC19VOQ5GFy6lmw/rd9VzScoCwWCyQZRlNTU09hhxrke5U0bpDuqmpCTfeeCMqKyt1v9hAp2cN0O4EQeBwLMprY6vc+MmZM+Es4nGaDc+u3YEIr1zkvdhJViQS0R3URqzloDukv/e97+Htt99O6cUKHc+kKd8dNcSBG8+cwfulWVDvbcObWzhl6EBgNptRVlamK6iNWmxJ97WtcePG4dZbb8Xq1asxZcqUHh3HrrvuupQrQ0S5V+WyY8mZM/DAvzaiORDKdXUGtX9t3oPZR1eirKQo11WhJCwWC8rKyuKLKXk8nj7vURu5GmJKvbsdDgdWrVqFVatWJfxOEASGNNEgUOEsxk/OnIn7/7WRs5NlUCSq4LkPduCaecfyStsAoCWojV6uWHdI79mzJ+0XJaL85ykpwpIzZ+KB1zfisK8919UZtLbsb8Kn+xsxdUR5rqtCGvQX1EYHNJDCPem+HDp0CPfcc49RT0dEeWCIw4YlZ87k5dgM+/u6LxBNoecw5UYsqLveo85EQAMpnEn/8Ic/7PXxvXv3Yt26dbj55pvTrhQR5Y/SYituOH067n1tA+9RZ0iDrw3vbT+AkycOz3VVSKOuZ9SHDnVMr2t0QAMpnEk3Nzcn/DQ2NmLdunV455138Nvf/taQSj366KOoqamBzWbDnDlzsG7dun7LL1++HBMmTIDNZsOUKVPw2muvJfxeVVXcfvvtGDp0KIqKijBv3jzs3LnTkLrmG6fkxPfKvpfw45Scua4WDXCekiJcd/p0lNjMyQtTSl7dtAdtIU4fPJBYLBZYrZ0jIfRM96mV7pB+4YUXEn5efvllbNmyBb/85S/x4osvpl2h5557DkuWLMEdd9yBjRs34thjj0VtbS0aGhp6Lb9mzRpccMEFuPzyy7Fp0yYsWLAACxYswJYtW+Jl7rnnHjz00ENYtmwZPvzwQ9jtdtTW1iIYZIcYIq2qXHZcVzudE55kSCAUwb8+/jLX1SAd/H4/gsEgbDYbBEFIecKT/hh2T/qCCy7AO++8k/bz3Hffffjxj3+Myy67DBMnTsSyZctQXFyMJ554otfyDz74IE4//XTcdNNNOOaYY/CrX/0KM2bMwCOPPAKg4yz6gQcewG233YbvfOc7mDp1Kv7v//4PBw8eNORLBVEhGeYpwbWnTYNV0j73MGn3ztb9aPSzk95A0PUetMfj0T2OWivDQvrjjz/G9OnT03qOcDiMDRs2YN68efHHRFHEvHnzsHbt2l63Wbt2bUJ5AKitrY2X37NnD+rq6hLKuFwuzJkzp8/nBIBQKASfz5fwQ0TAqAoXFp12LIM6A2RFxYvrv8h1NSiJ3jqJ9daZzAi6r1stWbKkx2P19fV46aWXMH/+/ITf33fffbqeu7GxEdFotMeUo5WVldi+fXuv29TV1fVavq6uLv772GN9lenN0qVL8Ytf/CLhsSuvvFLbGyEa5MZWubHotGPx6L8/Rkge3HP2Z9uGPQ04ZZIXR1e4cl0V6kV/vbj1THiile6tN23a1OPn4MGDmD17NhoaGuKPbd68Oa2K5dqtt94Kr9cb/9m/f3+uq0SUV2JBzTNq4/193U5D1zEmY2gZZmX0GbXuM+lMzttdVlYGk8mE+vr6hMfr6+tRVVXV6zZVVVX9lo/9t76+HkOHDk0oM23atD7rYrVaE3rtEVFPPKPOjN0NXmzZ34QpI8pyXRX6mp5x0EaeURt2T9oIFosFM2fOxMqVK+OPKYqClStXYu7cub1uM3fu3ITyALBixYp4+VGjRqGqqiqhjM/nw4cfftjnc2aK0b3+iPIBz6gz45VNu3k2nScCgYDuiUqMOqPWFNKnn346Pvjgg6Tl/H4/7r77bjz66KMpVQbouOf9hz/8AX/605+wbds2XH311QgEArjssssAAAsXLsStt94aL3/99dfj9ddfx7333ovt27fj5z//OdavX4/FixcD6JhP/IYbbsCdd96Jl19+GZ9++ikWLlyI6upqLFiwQFfdLBZLyjs6EokgHA6ntC1Rvhtb5ca1tdNgMzOojbK/yY+P9x7OdTUKnizLaG1tTWmiEiOCWtPl7nPPPRfnnHMOXC4XzjrrLMyaNQvV1dWw2Wxobm7G1q1bsXr1arz22muYP38+fvOb3+iuSMz555+Pw4cP4/bbb0ddXR2mTZuG119/Pd7xa9++fQmXDU444QQ888wzuO222/DTn/4UY8eOxYsvvojJkyfHy9x8880IBAK44oor0NLSgm984xt4/fXXYbPZdNVNFEX4fD4UFxfrunQRDofR3NzMy+c0qI2uLMWNZ8zAQ29sRoCTchji1U17MHVkOUQuvpEzkUgEDocj5ZnEerv0rYegaryeEgqFsHz5cjz33HNYvXo1vF5vxxMIAiZOnIja2lpcfvnlOOaYY/S/iwHA5/PhlltuwahRo2Cz2TTfYwiHw2hsbIQoiigqKsJ5552HIUOGZKHGRLlxsLkVD72+Cd52Xjkywo9OnoyZR1cmL0iGO3LkCP7617/C4XDAYrGk9VyxLDCbzSgqKsIVV1wBr9cLp7P/GSE1dxyzWq246KKLcNFFFwEAvF4v2tvb4fF4eqwpPVipqgqXy4XW1lZNnQG6NorT6UQoxHmPafCrdjuwZP5MPPj6JhzhMpdpe3XzbkyvqYAo8mw6FyTJmBn2up5RRyLarzSl3HHM5XKhqqqqYAI6RpIkTfcYuga0x+PhWrFUUGLrUVc4uXpWuupa2rB+T33ygpT3YkEdjWofCZFXvbsHimSdAboHdLqD2YkGoiEOG248YwaXuTTAPzft5lKWg4TFYoHLpX2iGqZHivoKagY0UadSuw03nDEdQ+z6OmlSogZfOzbs6X2RIRp49FxCZ4KkoXtQh0IhBjRRNx5HEW44YwZKizm6IR3//mQvx00XIKZImmJBHTuDliSJAU3UTbmzCDeeMQPOovR6yBayA82t2HbgSK6rQVmmO0kuueQSvPvuu5moCxENYhWuYtxwxgw4bIXV2dRIb3y6N9dVoCzTHdJerxfz5s3D2LFj8etf/xoHDhzIRL0GjNgZdOyMWpbljCz8TTQYDC21Y9F/cD3qVH1+qBlfHuayuYVEd0i/+OKLOHDgAK6++mo899xzqKmpwRlnnIHnn39e19ivwaB7JzGr1Zqxhb+JBouacieuOGUKZ9FK0QqeTReUlG6clpeXY8mSJfj444/x4YcfYsyYMbj44otRXV2NG2+8ETt37jS6nnmnr17cmVr4m2gwmTjMg4XfHJyzE2bapr0NaPC15boalAZZljWXTat306FDh7BixQqsWLECJpMJZ555Jj799FNMnDgR999/fzpPndeSDbNiUBMlN2fMUHx39phcV2PAUVXgzS37cl0NSlE4HI5Pq62F7pCORCL4+9//jv/8z//EyJEjsXz5ctxwww04ePAg/vSnP+HNN9/E3/72N/zyl7/U+9QDgizLmoZZdQ9qDp0g6uk/Jo/AqZOG57oaA87anYfg49zoA07sBM9k0t4nQ/ekpEOHDoWiKLjggguwbt06TJs2rUeZb3/72ygtLdX71HlPEAR4vV7NC2x0nau1ubkZRUWceYmoK0EQ8L3ZY3HY345P9jXmujoDhhxV8P7nB3HGsTW5rsqgp+fSdH+6L7Chle4z6fvvvx8HDx7Eo48+2mtAA0BpaSn27Nmj96nzntVqhclk0jUOumuvb64nTdSTKAq47KRJOMrtyHVVBpT3tn8FReEVukyLRCIIBAJpPUc6M1HqDumLL75Y9zrMg4WiKHA6nbonKrFYLHC73bzkTdQHm1nC1f8xFSUcQ61ZcyCET/fz6kOmmc1mtLa2wu/3p7R9ulNFc1osHcLhcMoziZnN5rTXIyUazDyOIlx56lRIXJJRs1Xbv8p1FQY9SZLgcDjg8/l0B7URazkwpLOIU4US9W90ZSku+gaHZmm17cAR1Hs5HCvT7HY7nE6nrqA2arElpgYR5ZU5Y4ayx7cO7/FsOitKSko0B7WRqyEypIko73x39hiMrtC+5m4hW7PzEMJyNNfVKAhagtro5YoZ0kSUd0yiiB99ezI7kmnQHpbx0e76XFejYPQX1EYHNMCQJqI8VWq34fJvTwan+E7u3W285J1NvQV1JgIaYEgTUR4bP3QIzp4xOtfVyHv7mvw40Nya62oUlK5B3dTUlJGABhjSRJTnTps6EpOHe3Jdjbz3wc5Dua5CwSkpKYHNZkMwGISqqoYHNMCQJqI8JwoCFn5jIpxFnGegP+t21SHKxXyyKhwOIxQKxf+d7sxkvWFIE1HeKymyYOE3J+a6GnnN1x7GtgNHcl2NgtH1HvTQoUN1j6PWiiFNRAPCpGEefHsix0/354MveMk7G3rrJKZnHLUeDGkiGjC+O2s0F+Lox8f7GhEIRXJdjUGtv17cmQhqhjQRDRhmyYTLTp4EycSPrt7IUQUb93DMdKZoGWZldFDzSCeiAeUotwMLZnJYVl8++KIu11UYlPSMgzYyqBnSWcSlKomM8e2JwzGq3JnrauSl3Q1eHPZx0Q0jRSIR3eOgjQpqhrQOkiSlvK2qqgiHwwbWhqhwiaKAi785kcta9mHTl4dzXYVBQ1EUNDc3pzRRiRFBzZDWQZIktLXp/4Yaa2SeSRMZZ2ipHWdOPzrX1chLG7/kfWmjhMNhSJKU8kQl6QY1Q1oHWZYRCAR07WhFUdDU1ARZlmGxcDIGIiOdNmUEhg1hb+/u9jb60eRvz3U1BgVBEOB2u9OaSSydoGZI6yDLMux2u+YdHQvoSCSSdiMTUU8mUcTCb06EyFU4etj0ZUOuqzAoWCwWCAYcX12DWs8VWaaGTsXFxZq+EXUN6LKyMpjNXHKPKBOGe0pw6mROctLdRoa0IYwI6JhYUOuZPpQhnYJkly66BzQvcxNl1pnTRqG02JrrauSVPYd9ONIazHU1qJuSkhLY7XbN5RnSKeorqBnQRNlnM0v4/nFjc12NvLN5L8+m81FxcbHmsgzpNHQPagY0Ue7MGFWB8UPdua5GXtm4hyE90DGk09Q1qA8dOsSAJsoRQRDwg7njYeLY6bhdDV742kPJC1LeYkgboOv9BavVyoAmypGqUjtOnTQi19XIK1u/4vKVAxlDOk2xS9yCIMBmsyEYDBq+nigRaXfGtBo4i/hFOeazr5pyXQVKA0M6Dd3vQXs8nowt/E1E2tjMEv5z+qhcVyNvbD3QBEXhbIcDFUM6RX11EsvUwt9EpN0J46pRVaq9B+1g1haWseewN9fVoC4URdFcliGdgmS9uBnURLllEkV8d9aYXFcjb/CSd/5QFAU+n09zeYa0TlqHWTGoiXJryvAyjK0qzXU18sIWhnReiOVHNBrVvA1DWiefz6d5mFXXoNYzDRwRpU8QBHxvNic4AYD9TX542zgUKxV6Lk0ne57YCZ7L5dK8HUNaB4vFgmg0qmscdCyoW1tbIctyhmtIRF3VlDsxo6Yi19XIC1sP8Gw6FeFwGJFIJK3n6H4FVpIkzdsypHUQRREul0v3OOiSkhI4HI60G5qI9DuTPb0BAFsPcLx0KgRBQHNzM8LhcErbpzsTJUNah1AopOsbUFd2u50rYRHlwFFuB8+mAXxR1wJV5VAsvSwWCyRJQmNjo+6gNmKqaIa0Duke4KkGPBGl58zpo1Dok4W2tIXQ6G/PdTUGHEEQ4Ha7YTabdQW1UWs5MKSJaNA7yu3AjFE8m95Z15LrKgxIgiDA4/FoDmojF1tiSBNRQThjGs+mP69rznUVBixRFDUFtdGrITKkiaggHOV2YHqB35vmmXR6kgV1JpYrZkgTUcH4jykjc12FnDrSGkRTK+9Lp6OvoM5EQAMMaSIqIDXlzoKfhWznoZZcV2HA6x7UoVAoIwENMKSJqMDMm1zY603v5H1pQ8SCuuvwLKMDGmBIE1GBmTy8DJWuwl0h64t6rog1kDCkiaigiIJQ0GfTDb42tIc5RXG6YvegZVmOn0GnMuFJMgxpIio4c0ZXocRWuDMA7m3UvlQi9dS9k5jVatU1jloPhjQRFRyzZMKJ44/KdTVyhiGdur56cWsdR61X3oR0JBLBLbfcgilTpsBut6O6uhoLFy7EwYMHk2776KOPoqamBjabDXPmzMG6desSfh8MBrFo0SJ4PB44HA6cc845qK+vz9RbIaIB4Jvjj4JQoLOb7GvkGvepSDbMKhNBnTch3dbWho0bN+JnP/sZNm7ciH/84x/YsWMHzj777H63e+6557BkyRLccccd2LhxI4499ljU1taioaEhXubGG2/EK6+8guXLl2PVqlU4ePAgvve972X6LRFRHhvisGHysLJcVyMnvuSZtG5ax0EbHdR5E9IulwsrVqzAeeedh/Hjx+P444/HI488gg0bNmDfvn19bnfffffhxz/+MS677DJMnDgRy5YtQ3FxMZ544gkAgNfrxR//+Efcd999OOWUUzBz5kw8+eSTWLNmDT744INsvT0iykPfmlCYl7yPtAbhbze2g9NgpqqqrnHQRgZ13oR0b7xeLwRBQGlpaa+/D4fD2LBhA+bNmxd/TBRFzJs3D2vXrgUAbNiwAZFIJKHMhAkTMGLEiHgZrYQ0r43JMntUEuWTiUd5MMRhy3U1coL3pbVRVRXNzc26JyoxKqjzNqSDwSBuueUWXHDBBXA6nb2WaWxsRDQaRWVlZcLjlZWVqKurAwDU1dXBYrH0CPquZXoTCoXg8/kSfqxWa8pBGwgEEIlEUtqWiDJDFAV8s0A7kO1r4n1pLcLhcMIwKz2MCOqchfTTTz8Nh8MR/3nvvffiv4tEIjjvvPOgqioef/zxnNRv6dKlcLlc8Z/hw4dDURR4vV7dO9rv96O1tRVmc+EO+SDKVyeMGwqxAHuQ8UxaG1VV4Xa7U18POs2gzllIn3322di8eXP8Z9asWQA6A3rv3r1YsWJFn2fRAFBWVgaTydSjp3Z9fT2qqqoAAFVVVQiHw2hpaemzTG9uvfVWeL3e+M/+/fsRDodhMpl07Wi/3w+fzweHwwFJkjRtQ0TZ4yyyYuJRQ3Jdjaw71BLIdRUGBIvFkvYJVveg1nNFNmchXVJSgjFjxsR/ioqK4gG9c+dOvPnmm/B4PP0+h8ViwcyZM7Fy5cr4Y4qiYOXKlZg7dy4AYObMmTCbzQllduzYgX379sXL9MZqtcLpdCb8AIDT6dT8jSgW0E6nE3a7Pek+IaLcOG5M31/YB6tGXzvCcjTX1ch7omhMTHYNaq9X+9SseXNPOhKJ4Pvf/z7Wr1+Pp59+GtFoFHV1dairq0sIw1NPPRWPPPJI/N9LlizBH/7wB/zpT3/Ctm3bcPXVVyMQCOCyyy4D0NFr/PLLL8eSJUvw9ttvY8OGDbjsssswd+5cHH/88brrqfXSRdeALikp0f06RJQ9x44oh81synU1skoFUO9ty3U1CkosP0wm7cda3lx/PXDgAF5++WUAwLRp0xJ+9/bbb+Pkk08GAOzatQuNjY3x351//vk4fPgwbr/9dtTV1WHatGl4/fXXEzqT3X///RBFEeeccw5CoRBqa2vx2GOPpVzX2I5uampCY2Njjw4FDGiigcUimTC9pgJrdx7KdVWy6lBLAMM9/IzKJlEU+72N213ehHRNTQ1UVU1a7ssvv+zx2OLFi7F48eI+t7HZbHj00Ufx6KOPplPFBH0FNQOaaGCaM6aq8EK6mfelc0HPJfS8udw9EHW/9N3U1MSAJhqgxla54bZbc12NrGLnsfzHkE5TLKhVVUUwGITNZmNAEw1AoiBg5qjK5AUHEYZ0/mNIGyAQ6DzQQ6GQ4euJElF2TK+pyHUVsuqwvw0R9vDOawzpNHW9Bz106NCMrCdKRNlRU+6Eqyi1SSsGIlUF6n3s4Z3PGNJp6N5JLFPriRJRdoiCgGNHlue6GlnV6A/mugrUD4Z0ivrqxc2gJhrYCu2Sd1Nre66rUHDa2rRfvWBIpyDZMCsGNdHANbaqFHZr3oxOzbgmnklnld/vT+jHlAxDWqe2tjZNw6y6BzVXwCIaGEyiiKkjCueSN8+k+6dl/g6tYid4eqaJZkjrIEkSAoGA5nHQXYO6ubkZiqJkoZZElK7Jw/pfN2Aw4Zl0/8LhsCFB3fUKbHFxsebtGNI6SJIEu92uaxx0LKglSeJlb6IBYkL1kIJZvrKptd3Qs8XBRlXVtE+y0pmJkiGtgyzLur4BxYiiCLfbDaFA/uiJBrpiqxk15drnVx7IgpEo2sLal04sNBaLBbIso6mpKaWgTneqaIa0DnrWAO1OEISUFw0nouybVFCXvHlfui+xk6xIJKI7qI1Yy4EhnUU8kyYaOCYeNSTXVciaxlbel+6P2WxGWVmZrqA2arElhjQRUS9GeJywW825rkZW+NpCua5C3rNYLJqD2sjVEBnSRES9EEUBx1QXxtm0r52dWrXQEtRGL1fMkCYi6sOYqtJcVyEr/EGGtFb9BbXRAQ0wpImI+lQwId3OyZb06C2oMxHQAEOaiKhPQ0vtKLYM/ilCeSatX9egPnToUEYCGmBIExH1SRQEjK4szXU1Ms7Pe9IpsVgssFqt8X/rme5TK4Y0EVE/CuGSN8+kU+P3+xEMBmGz2SAIQsoTnvSHIU1E1I8xBXAmHYxEEZajua7GgNL1HrTH49E9jlorhjQRUT9GeEpgNg3+j0qeTWvXWycxPeOo9Rj8Rx4RURokk4ij3I5cVyPjAkH28Naiv17cmQhqhjQRURIjyoztsZuPQrzcnZSWYVZGBzVDmogoiRFlg39FrGCEId0fPeOgjQxqhnQWGd3rj4iyY4SnAM6kGdJ9CgQCusdBGxXUDGkdLBZLyjs6EokgHGbHDKKBaGipHZI4uFexC0a4pnRvZFlGa2trShOVGBHUDGkdRFGEz+fTvaPD4TCam5u5VCXRACWZRFQP8s5jvCfdu0gkAofDkfJMYukGNUNah1AohGg0qmtHh8NhNDY2QpIkWCyWDNeQiDJlsF/y5uXu3pnN5rRnEksnqBnSOqiqCpfLpXlHxwLabDbD7XbzTJpoAKtyGz/lYz5hSPdOkoyZu71rUPt8Ps3bMaR1kiRJ0zeirgHt8XgY0EQD3FDX4A5p3pPOvFhQR6PavxAxpFOQ7NJF94AWRe5mooGusrQ411XIKN6Tzg6LxQKXy6W5PNMjRX0FNQOaaHBy222wSIP371lVc12DwqHnEvrgPeKyoHtQh0IhBjTRICUKAioH8SVvRWFK5yOmSJpiQd21FzcDmmhwqnIN3kveKhjS+YhJQkSkUeUgDmmF17vzEkM6TbEz6NgZtSzLGVn4m4hyr6ykKNdVyBh+ZOUnhnQauncSs1qtGVv4m4hyz2235boKGcPL3fmJIZ2ivnpxZ2rhbyLKvSGOwRvSvNydPbKsfUw6QzoFyYZZMaiJBie33YrBOi0RP6ayIxwOw+v1ai7PkNZJlmVNw6y6B7XKb6lEA55JFOEqtua6GhnBy92ZFzvBM5lMmrdhSOsgCAK8Xq/mcdBdg7q5uZlBTTQIDNZL3qZBvhRnqvRcmu5P1yuwTqdT83YMaR2sVitMJpOucdBde31zPWmigc9tH5xn0hLnduhVJBJBIBBI6znSmYmSraKDoihwOp26JyqxWCxwu908kyYaBJxFg3PJWbOJcdAbs9mM1tZW+P3+lLZPd6potooO4XA45ZnEzGYz15MmGgQctsH5dywxpHslSRIcDgd8Pp/uoDZiLQdjFsokTThVKNHA57CZc12FjGBI981ut0OSpPg60CUlJUm3MWqxJYY0EZEOg/ZMmicR/YoFs5agNnI1RIY0EZEODuvgPJPmPenktAS10csVM6SJiHQoGbSXuzkES4v+gtrogAbYcYyISJdsXu4eHqqHWYlk5bV4uVu7kpISOJ3OhM5kmQhogCFNRKSLWcrOx6ZLbsXF9f/GCb4tWXk9UeCZtB5dg7qpqSkjAQ0wpImI8tK01p1wRgOY1boDJjWa6+pQL0pKSmCz2RAMBqGqquEBDTCkiYjyjkmNYmbrDiiCALfsx/i2fbmuEvUiHA4jFArF/53uzGS9YUgTEeWZce37MUT2w28qhgAVM1t35LpK1E3Xe9BDhw7tcY/aKOzdTUSUZ2b6d0CAiqhgQlC0YHTwIMoiLWg0l+a6aoTeO4npGUetB8+kiYjySFmkBaODBxAUO3qRhwQzLKqM6a2f57hmBPTfi7u3Xt/pYkgTEeWRaa07YVVlhISvx2MLAmRBxIzWnVkbjkW90zLMyuigZkgTEeUJsxLBzNbPIQsi0GVIVJtogzPaholte3NYu8KmZxy0kUHNkM4iLlVJRP2Z2LYXzmgb2sTENasVQQSgYlbrdoCfI1kXiUR0j4M2KqgZ0jpIUur97FRVRTgcNrA2RDSoqF+HMFQogqnHr9tFK0aE6lEdbsx+3QqYoihobm5OaaISI4KaIa2DJEloa2vTvV2skXkmTUR9qQ43YUSoHu3dzqJjwoIEsxrF9NadWa5ZYQuHw5AkKeWJStIN6rwN6auuugqCIOCBBx5IWvbRRx9FTU0NbDYb5syZg3Xr1iX8PhgMYtGiRfB4PHA4HDjnnHNQX1+vu06yLCMQCOja0YqioKmpCbIsw2IZnEvcEVH6prXuhFmNIiz0ccVOEBARTDg2sAu2aKj3MmQ4QRDgdrvTmkksnaDOy5B+4YUX8MEHH6C6ujpp2eeeew5LlizBHXfcgY0bN+LYY49FbW0tGhoa4mVuvPFGvPLKK1i+fDlWrVqFgwcP4nvf+57uesmyDLvdrnlHxwI6Eomk3chENHjZlBCmtX2BiGBK6DDWXZtohV1px5S23VmsXWGzWCwQDJjXvGtQ67kim3epceDAAVx77bV4+umnYTYnXxLuvvvuw49//GNcdtllmDhxIpYtW4bi4mI88cQTAACv14s//vGPuO+++3DKKadg5syZePLJJ7FmzRp88MEHuutXXFys6RtR14AuKyvT9F6IqDBNDuyBPdre56XuGFUQoULALP92CLx9lhVGBHRMLKj1TB+aVyGtKAouvvhi3HTTTZg0aVLS8uFwGBs2bMC8efPij4miiHnz5mHt2rUAgA0bNiASiSSUmTBhAkaMGBEv05tQKASfz5fwE5Ps0kX3gOZlbiLqi6CqHaELFYAKUY322oNbUBWIahRhUcLQyBGMCNVlv7KUtpKSEtjtds3l8yqk7777bkiShOuuu05T+cbGRkSjUVRWViY8XllZibq6jgO4rq4OFosFpaWlfZbpzdKlS+FyueI/w4cPT/h9X0HNgCYiPVzRVnhkH6IwwR4NwRENoiTanlDGpEbhllthj4ZgVqJQAYwOHspNhSltxcXFmsvmbO7up59+GldeeWX83//85z/x4IMPYuPGjYZeXkjVrbfeiiVLlsT/7fP5cOeddyaU6T5Xq91uZ0ATkS4tJgeerDwTFrVjNrH/aFmPmm4BLKoqQqIZL3i+hRbJAQA4aPFkva6UfTkL6bPPPhtz5syJ/3v58uVoaGjAiBEj4o9Fo1H85Cc/wQMPPIAvv/yyx3OUlZXBZDL16KldX1+PqqoqAEBVVRXC4TBaWloSzqa7lumN1WqF1dr//SEgMah9Ph8EQWBAE5F2goCD1rL4P4NC3/1XDljKcNjizkatKE/k7HJ3SUkJxowZE/+54oor8Mknn2Dz5s3xn+rqatx000144403en0Oi8WCmTNnYuXKlfHHFEXBypUrMXfuXADAzJkzYTabE8rs2LED+/bti5dJV9f7C1arlQFNRESGyJulKj0eDzyexMs3ZrMZVVVVGD9+fPyxU089Fd/97nexePFiAMCSJUtwySWXYNasWTjuuOPwwAMPIBAI4LLLLgMAuFwuXH755ViyZAmGDBkCp9OJa6+9FnPnzsXxxx+fdr1j96AFQYDVakUwGITf7zdsmTIiIipceRPSWu3atQuNjZ3T4p1//vk4fPgwbr/9dtTV1WHatGl4/fXXEzqT3X///RBFEeeccw5CoRBqa2vx2GOPpV2X3jqJ+f1+w9cTJSKiwpTXId3bfejeHlu8eHH8zLo3NpsNjz76KB599FHD6tZXL+5MLfxNRESDg6IomsvmdUjnq2TDrBjURETUG0VREubdSIYhrZPWcdDdg1pLT3EiIhq8YvkRjUY1b8OQ1ikWulqGWXUN6uLiYphMPZefIyLqShFEiKoKl9ya8HhIMH+9rjRlk55L08meJ3aC53K5NG/HkNbBYrHEZzjTOswqFtQtLS26poIjGvDCzbmuQWZEZBQjtbWBtVhTOgF7iip6PB4WJQQlIWOvLUW9g7fNACDF8eXhcBhmszmtobXdr8DKsqx5W4a0DqIowuVy6W6skpISyLKMcDicoZoR5aF9y3Ndg4wwRaOYYfo8cy9Q9PVPNzYA0/Flxl62yrsV2FeWvOBANeaKlDYTBAHNzc0pB3Vvt0j1hDSvnegQCoUgSal9r7Hb7VwJi4hogLFYLJAkCY2NjbpPtIxYy4EhrYOa5tJwqQY8ERHlhiAIcLvdMJvNuoLaqMWWmBpERHnEEQ7D1UsQyIKI+uIiIA8WICo0giDA4/GgqakJjY2NSUPXyNUQGdJElBkjzs11DTIiGpGxMfp+xp7/3KZ3MaGtocfjQdGCD4Z+A83mzMy7UOUahUldFjiiRKIoagpqo5crZkgTUWYM1tWaBBltyNwERYpqggIR3q+XpAQAsyLDokYQVosy9tqyyTV428wgyYLa6IAGeE+aiIhIs1hQd79HnYmABhjSREREunQP6lAolJGABhjSREREusWCuuvwLKMDGmBIExER5S2GNBERkU6xe9CyLMfPoFOZ8CQZhjQREZEO3TuJWa3WXjuTGYFDsIiIcswT8cKqRAAAFrXveZ3LIy0wqx3LHDaYSyGL/AjPtr56cWsdR60XW5iIKIdKZT+uOvQSrGpHSAuqCgWJs4opggBrNIIfNL7V8W8IeNc1DW+Vzsh6fQtZsmFWmQhqXu4mIsohr8mBFskBsyIjKJrRbrLAbypOKBMVTPBKdgRFM6IQIaoKvrRW5ajGhUnrOOi+xlGniiFNRJRDqiBgvWMCFEFAFCJkQep1fu6oYIIsSLCoEdRbhmCPbWgOaluYVFXVNQ7ayKBmSOsgpDmxvZ41RImocHxqPxptog1FSv8f5oKqAAA2OMZD5UIbWaGqKpqbm3VPVGJUUDOkdbBarSkHbSAQQCQSMbhGRDQYtJls+MR+dEensX6WxC1SwmgTbfjEPjqLtSts4XA4YZiVHkYENUNaB0VR4PV6de9ov9+P1tZWmM3mDNWMiAa6TY5xiAimvnt3qyosqtxx1m2yZbdyBUxVVbjd7pQ7gKUb1AxpHcLhMEwmk64d7ff74fP54HA4IEnsTE9EvfvKUo4DlnIUKaFef29RZUQEEzY6xmW5ZoXNYrGkfYLVPaj1XJFlSOvkdDo1fyOKBbTT6YTdbs9SDYloQBIEfFQyAQAgfn3vuasiJYQDlnJ8ZSnPds0KmigaE5Ndg9rr9WrfzpBXLyBaL110DeiSksytPUtEg8dnxTXwm4p7nE3HQnt9yfhee37TwBDLD5PJpH2bDNZn0EoW1AxoIkpFWLRgk31sx6xiXTqQFSkh+E3F2FI8Koe1IyOIogin06m9fAbrMqj1FdQMaCJKx2bHWIQFKT4DGVQVZjWKzfYxCIvGLoNIuaHnEjpDOg3dg7qpqYkBTURpqbcMwZe2KtiiHV/8rWoEYUHCJnYYK0gM6TTFglpVVQSDQdhsNgY0EaVlvWMCIAgwqVHYlDC+tFah3jIk19WiHGBIGyAQCMT/PxQKGb6eKBEVlu3FI9AiOeCItkOFgA0l43NdJcoRhnSaut6DHjp0aEbWEyWiwiILEjbYx0FSo/BKDmwrGpnrKlGOcHYNHURRhCzL8QAOBAJobW2Fw+GITxnqdDrR3NyMhoYGuN3u+CD4SCQCWZZ1jY8jovwTlqMwye0Zf51NthGYZNqBTUVjoCoRmJTMTissykEcOXIko68x0Hi9XsiybPiUznomM2FI61BaWoqmpqZ4WCuKAlEU4fP54PP54uVUVYUsyzh48CAkSYIoilAUBaqq4rXXXjNs5jFFURAOhyEIAiwWS48FQGIHl9lszthsZ6qqIhwOQ1VVWCyWHr0Wk9XRKP2912R1NArbo9Ngb4/SJr/msoISBaBCFUw9xzirKgQ1CkCAKvYcO/t3aTTCERNKG7frql8PqgJBVaAKIiD03N+CEsXW1bvwxbqB2R5a6f37iEajaGlpgSAIhu4XPaHPkNYhdlDJsoxoNAqTydTnfK6CICAcDiMSicQPBlVVYbVaDZnDOxKJwOfzQZIkuN3uPj9su57tGz3rWWx1GFmWE64adGc2m9Hc3IxoNNpvXVMVCAQQCAT6fY82mw3Nzc1obW3tt66pYnt0KoT2UIQ2DaVUmOQQBFWBLNl6DUcIAFQRkhwEVAVRyfr1gx3aTUWa69QXQYnAFI0gajJDFfvYz6aOE4mB2h5apPL3YbfbIYqioSEdDoehKD1nlOsLQ1qnaDQKRVEgSRKsVmuf5URRhCiKCIVC8W+HgiDAbDanPFF7TDgchtfrhdVqhcfj6ffgsVgskCQp/gdiVM/z2ALoiqKgoqKi3/cUm/u2sbERPp8vaZ318Pv9aGtrQ2lpadL3VlFRgaamJni93pRWtOkL26NTobRHb2e9iQVUSHI7BKiQzcVJypsgCyIkuR2maBiyVGTYrGJiNAyTIiMqWaGY+t+/FRWeAdseyaT69xEIBKCqKkwmkyF/I6FQCNFolOOkMyV22TpZQHctb7Va42fVer499SUcDqOxsRFms1nzh2tJSQmcTid8Ph/8fu2X6foSO+D1rK9qsVhQVlaGSCQS/2NJl96JY4xciD2G7dGJ7fG1WECrCmSpKHmgoyP0ZakIgqpAktv7Xa5SKzEahikaRtRkSRrQwOBtj3T+PmJXTVUD2iMUCkGWZUiSpOtyPkNah9glDy0BHdM1qNPtgJDKAR9j1IGfygEfY2QwpDqzm5EfRGyPTmyPr6UQ0PFNDQxqvQEd326QtUe6fx9utxuqqiIUCqX199E1oPXkB8CQ1kVV1ZQ6NHQN6ubm5pQO/HQO+Jh0D/x0DvgYI4Ih3alXjfggYnt0Ynt8LY2Ajj+FAUGdakDHtx8k7WHE30esE1s6QZ1OQAMMaV3S+SYlCAJMJhMkSdJ94BtxwMekeuAbccDHpBMMRs2Nns4HEdujE9vjawYEdPyp0gjqdAM6/jwDvD2M/PsQRREWiyWloE43oAGGdFaJoojS0lJdB76RB3yM3gPfyAM+JpVgMHrxklQ+iNgendgeXzMwoONPmUJQGxXQ8ecboO2Rib+P2EgePUFtREADDOms03PgZ+KAj9F64GfigI/REwyZWl2M7dGJ7dFJczBkIKDjT60jqI0O6PjzDrD2yOTfhyRJmoPaqIAGGNI5oeXAz+QBH5PswM/kAR+jJRgyvfwn26MT26NT0mDIYEDHX0JDUGcqoOPPP0DaIxt/H1qC2siABhjSOdPfgZ+NAz6mrwM/Gwd8TH/BkK31udkendgenfoMhiwEdPyl+gnqTAd0/HXyvD2y+ffRX1AbHdAAQzqnejvws3nAx3Q/8LN5wMf0FgzZCoQYtkcntken3tojWwEd01tQZyugY/K5PbL999FbUGcioAHOOJZzsQO/qakJhw8fBtDxAZmtAz4m9qEbm4dcEISsHfAxsWBobGzEoUOHACBrgRDD9ujE9ujUoz2yGNAxsaCW5HaYIx3L42YroGPytj1y8PcRG44bDofR3t4ef8zIgAZ4Jp0XRFGE0+mM/9vpdGb1gI/pOleu1WrN6gEfY7FYEg5yo+fv1YLt0Ynt0anre1dEU1YDOkYVTVC6vK7S11zcGZSP7ZGrvw9JkhLmITd6znOAIZ0XwuEwmpqaYDabYTab0dTUlPX1qGOXjARBgM1mQzAYNGaKRJ38fj+CwSBsNhsEQTBsyko92B6d2B4dureHqEQhRrO/ZrwYDUNUovGgNmoKUT3ysT1y9fcRu9QdW4Qj3ZnJesOQzrGu93TKyspQVlZm6Ny5WnS/p+PxeIydy1ijrvc8PR6P4XNLa8H26MT26NBbe0RNFpii4awGddd70FGpyPC5vrXI1/bIxd9H13vQRUVFKU94kgzvSWsUm2BdUZSU5t+ObR9rWKBjyUuv1wuTyYSioiIEg0EAQFFRESKRCOrr6+FyuTK2tirQ8X58Ph+i0ShcLhdkWYYsyzCZTLBarThy5AhCoRCKi4szVgcAaGtrQyAQgN1uh8lkQltbx1KADocDXq8XdXV1Gb+sxvboxPbo0Fd7KKoAQIQpEgSicsYvO4tKpGM1K1HqeG05AhWALEgwRcMwKQFERUtaq2fF2rgv+dwemfr7iK16qKoqotFo/HFZluNn0KIoxjPBZDJBlmW0t7fHVz7s630A0LRwh6AasbxHAfjqq68wfPjwXFeDiIgGif3792PYsGH9lmFIa6QoCg4ePIiSkpI+vx0NZD6fD8OHD8f+/fsTOoVQB+6fvnHf9I/7p2+Fum9UVYXf70d1dXXSq1G83K2RKIpJv/EMBk6ns6D+WPTi/ukb903/uH/6Voj7xuVyaSrHjmNERER5iiFNRESUpxjSBKBjMoA77rjD8NlyBgvun75x3/SP+6dv3DfJseMYERFRnuKZNBERUZ5iSBMREeUphjQREVGeYkgXiKuuugqCIOCBBx5IWvbRRx9FTU0NbDYb5syZg3Xr1iX8PhgMYtGiRfB4PHA4HDjnnHNQX1+foZpnRiQSwS233IIpU6bAbrejuroaCxcuxMGDB5NuWwj7J9l77G758uWYMGECbDYbpkyZgtdeey3h96qq4vbbb8fQoUNRVFSEefPmYefOnZl8C4ZbunQpZs+ejZKSElRUVGDBggXYsWNH0u0KYd90d9ddd0EQBNxwww39livEfaObSoPeP/7xD/XYY49Vq6ur1fvvv7/fss8++6xqsVjUJ554Qv3ss8/UH//4x2ppaalaX18fL3PVVVepw4cPV1euXKmuX79ePf7449UTTjghw+/CWC0tLeq8efPU5557Tt2+fbu6du1a9bjjjlNnzpzZ73aFsH+0vMeu3n//fdVkMqn33HOPunXrVvW2225TzWaz+umnn8bL3HXXXarL5VJffPFF9eOPP1bPPvtsddSoUWp7e3u23lbaamtr1SeffFLdsmWLunnzZvXMM89UR4wYoba2tva5TaHsm67WrVun1tTUqFOnTlWvv/76PssV4r5JBUN6kPvqq6/Uo446St2yZYs6cuTIpCF93HHHqYsWLYr/OxqNqtXV1erSpUtVVe0IN7PZrC5fvjxeZtu2bSoAde3atRl5D9mybt06FYC6d+/ePssUwv5J9h67O++889T58+cnPDZnzhz1yiuvVFVVVRVFUauqqtTf/OY38d+3tLSoVqtV/etf/5qBd5AdDQ0NKgB11apVfZYptH3j9/vVsWPHqitWrFBPOumkfkO60PZNqni5exBTFAUXX3wxbrrpJkyaNClp+XA4jA0bNmDevHnxx0RRxLx587B27VoAwIYNGxCJRBLKTJgwASNGjIiXGai8Xi8EQUBpaWmvvy+E/aPlPXa3du3ahPIAUFtbGy+/Z88e1NXVJZRxuVyYM2fOgNgnffF6vQCAIUOG9Fmm0PbNokWLMH/+/B7vuTeFtm9Sxbm7B7G7774bkiThuuuu01S+sbER0WgUlZWVCY9XVlZi+/btAIC6ujpYLJYeQVZZWYm6ujpD6p0LwWAQt9xyCy644II+5xAuhP2j5T12V1dX12v52PuN/be/MgONoii44YYbcOKJJ2Ly5Ml9liukffPss89i48aN+OijjzSVL6R9kw6eSQ8STz/9NBwOR/xn1apVePDBB/HUU08NylW79Oq+f95777347yKRCM477zyoqorHH388h7WkgWLRokXYsmULnn322VxXJS/s378f119/PZ5++mnYbLZcV2dQYUgPEmeffTY2b94c/1mzZg0aGhowYsQISJIESZKwd+9e/OQnP0FNTU2vz1FWVgaTydSjJ3J9fT2qqqoAAFVVVQiHw2hpaemzTD7qvn9mzZoFoDOg9+7dixUrVvS7Es9g3j8xWt5jd1VVVUn3Sewxrc+ZzxYvXoxXX30Vb7/9dtKV8Qpl32zYsAENDQ2YMWNG/PNm1apVeOihhyBJEqLRaI9tCmXfpIsh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",
      "text/plain": [
       "<Figure size 600x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# the bend overlaps slightly with the straight waveguide sections by construction. Ignore this warning.\n",
    "td.config.logging.level = \"ERROR\"\n",
    "sim = make_sim(middle_width0)\n",
    "\n",
    "fig, ax = plt.subplots(figsize=(6, 5), tight_layout=True)\n",
    "sim.plot(z=0.0, ax=ax)\n",
    "ax.set_title(\"2D bend simulation\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a2f34fdd76beecaf",
   "metadata": {},
   "source": [
    "## Select the Mode of Interest\n",
    "\n",
    "Next, we solve for a few modes on the input waveguide cross section and assume that we are interested in the mode that appears as `mode_index=2`. We then tighten the source and monitor setup around this physical mode before the differentiable simulation by using `to_source` on the `ModeSolver` result and by defining `ModeSpec(num_modes=1, target_neff=target_neff)`.\n",
    "\n",
    "This is the key step that makes the example compatible with `parallel adjoint`: the target mode is fixed before the forward run, so the required adjoint simulation is already known. After tightening the mode specification, the same physical mode is tracked as `mode_index=0` in the differentiable simulation.\n",
    "\n",
    "This matters because parallel adjoint prepares adjoint simulations from the monitor outputs that may contribute to the objective. If we kept `ModeSpec(num_modes=3)` and only selected one mode afterward inside the objective, Tidy3D would still need to prepare adjoint simulations for all three monitored mode indices. By shrinking the `ModeSpec` to the one mode we actually use, the `ModeMonitor` contributes only one adjoint simulation in this example.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "79a4cb003724442d",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-03-31T13:52:38.996744Z",
     "start_time": "2026-03-31T13:52:37.861037Z"
    }
   },
   "outputs": [],
   "source": [
    "from tidy3d.plugins.mode import ModeSolver\n",
    "\n",
    "ms = ModeSolver(simulation=sim, plane=mode_src, mode_spec=mode_spec, freqs=[freq0])\n",
    "mode_data = ms.solve()\n",
    "\n",
    "print(\"Effective index of computed modes:\", np.array(mode_data.n_eff))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 233,
   "id": "d65b16ff4e07b0d4",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-03-31T13:52:39.025176Z",
     "start_time": "2026-03-31T13:52:39.018069Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Targeting the mode that appeared as mode_index=2 in the initial solve.\n",
      "Using ModeSpec(num_modes=1, target_neff=1.8282) for the differentiable run.\n"
     ]
    }
   ],
   "source": [
    "target_mode_index = 2\n",
    "target_neff = float(np.real(np.array(mode_data.n_eff).squeeze()[target_mode_index]))\n",
    "\n",
    "# Restrict the differentiable simulation to the one physical mode we want.\n",
    "# After tightening the ModeSpec, this target mode is tracked as mode_index = 0.\n",
    "mode_src = ms.to_source(\n",
    "    mode_index=target_mode_index,\n",
    "    source_time=mode_src.source_time,\n",
    "    direction=mode_src.direction,\n",
    ")\n",
    "mode_spec = td.ModeSpec(num_modes=1, target_neff=target_neff)\n",
    "mode_mnt = mode_mnt.updated_copy(mode_spec=mode_spec)\n",
    "mode_index = 0\n",
    "\n",
    "# at the output plane, the guided wave travels in the negative monitor direction\n",
    "output_direction = \"-\"\n",
    "\n",
    "print(f\"Targeting the mode that appeared as mode_index={target_mode_index} in the initial solve.\")\n",
    "print(f\"Using ModeSpec(num_modes=1, target_neff={target_neff:.4f}) for the differentiable run.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f39f57cbb925464d",
   "metadata": {},
   "source": [
    "## Objective Function\n",
    "\n",
    "Our figure of merit is the transmission of the selected output mode at a single target frequency.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 234,
   "id": "a478a995667d1227",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-03-31T13:52:39.068910Z",
     "start_time": "2026-03-31T13:52:39.064547Z"
    }
   },
   "outputs": [],
   "source": [
    "def objective(middle_width):\n",
    "    sim = make_sim(middle_width)\n",
    "    sim_data = web.run(\n",
    "        sim,\n",
    "        task_name=\"bend\",\n",
    "        verbose=False,\n",
    "    )\n",
    "\n",
    "    amps = (\n",
    "        sim_data[monitor_name]\n",
    "        .amps.sel(\n",
    "            direction=output_direction,\n",
    "            mode_index=mode_index,\n",
    "        )\n",
    "        .values\n",
    "    )\n",
    "    transmission = anp.abs(anp.array(amps)) ** 2\n",
    "    return anp.sum(transmission)\n",
    "\n",
    "\n",
    "value_and_grad = ag.value_and_grad(objective)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d669cac173103aa1",
   "metadata": {},
   "source": "Next, we define a small helper that toggles the relevant adjoint settings and measures the runtime of one gradient evaluation. Note that we can use the `with config as cfg:` context to use temporary changes which are reverted after leaving the `with` block.\n"
  },
  {
   "cell_type": "code",
   "execution_count": 235,
   "id": "99b9b2adcd8dbcb",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-03-31T13:52:39.116805Z",
     "start_time": "2026-03-31T13:52:39.112399Z"
    }
   },
   "outputs": [],
   "source": [
    "def timed_value_and_grad(middle_width, parallel_run):\n",
    "    with config as cfg:  # optional context manager to ensure temporary changes\n",
    "        cfg.adjoint.local_gradient = (\n",
    "            True  # note that parallel adjoint is currently only supported with local gradients\n",
    "        )\n",
    "        cfg.adjoint.parallel_run = parallel_run\n",
    "\n",
    "        t0 = time.perf_counter()\n",
    "        value, grad = value_and_grad(middle_width)\n",
    "        elapsed = time.perf_counter() - t0\n",
    "\n",
    "    return {\n",
    "        \"value\": float(value),\n",
    "        \"grad\": float(grad),\n",
    "        \"elapsed\": elapsed,\n",
    "    }"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "816ca07eff502380",
   "metadata": {},
   "source": [
    "## Compare Sequential and Parallel Adjoint\n",
    "\n",
    "We now evaluate the same gradient twice: once with `parallel adjoint` disabled, and once with it enabled."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 236,
   "id": "bf088ccb558fe06b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2026-03-31T13:54:22.305734Z",
     "start_time": "2026-03-31T13:52:39.162917Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "method                   objective      gradient      time [s]\n",
      "--------------------------------------------------------------\n",
      "sequential adjoint      3.8935e-01    3.5744e-01         67.91\n",
      "parallel adjoint        3.8935e-01    3.5748e-01         35.21\n",
      "\n",
      "speedup = 1.93x\n"
     ]
    }
   ],
   "source": [
    "result_parallel = timed_value_and_grad(middle_width0, parallel_run=True)\n",
    "result_sequential = timed_value_and_grad(middle_width0, parallel_run=False)\n",
    "\n",
    "print(f\"{'method':<20}{'objective':>14}{'gradient':>14}{'time [s]':>14}\")\n",
    "print(\"-\" * 62)\n",
    "print(\n",
    "    f\"{'sequential adjoint':<20}\"\n",
    "    f\"{result_sequential['value']:>14.4e}\"\n",
    "    f\"{result_sequential['grad']:>14.4e}\"\n",
    "    f\"{result_sequential['elapsed']:>14.2f}\"\n",
    ")\n",
    "print(\n",
    "    f\"{'parallel adjoint':<20}\"\n",
    "    f\"{result_parallel['value']:>14.4e}\"\n",
    "    f\"{result_parallel['grad']:>14.4e}\"\n",
    "    f\"{result_parallel['elapsed']:>14.2f}\"\n",
    ")\n",
    "print()\n",
    "print(f\"speedup = {result_sequential['elapsed'] / result_parallel['elapsed']:.2f}x\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "908fefbe290a2f08",
   "metadata": {},
   "source": [
    "In a successful run, the objective value and gradient should agree between the two evaluations (plus some numerical noise), while the parallel run finishes sooner.\n",
    "\n",
    "The achievable speedup is not determined only by the pure simulation time. It also depends on how much of the total wall-clock time is spent in work that cannot be overlapped: constructing the simulations, uploading them, monitoring them, downloading the results, and the local postprocessing that combines forward and adjoint data. If these fixed costs are large compared to the actual solver runtime, the observed speedup will be smaller. If the supported adjoint work dominates the runtime, the speedup can approach 2x.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "15919cd860ba7620",
   "metadata": {},
   "source": [
    "## Rules and Guardrails\n",
    "\n",
    "Parallel adjoint is controlled through the standard adjoint configuration. The direction policy determines how many mode directions are prepared for a `ModeMonitor`, and `max_num_adjoint_per_fwd` sets the per-run cap for parallel adjoint work.\n",
    "\n",
    "Supported monitor outputs:\n",
    "\n",
    "- `ModeMonitor` amplitudes.\n",
    "- `DiffractionMonitor` amplitudes.\n",
    "- point `FieldMonitor` probes with `size=(0, 0, 0)` and `colocate=True`.\n",
    "\n",
    "If any unsupported monitor is present in the differentiable simulation, Tidy3D falls back to the sequential adjoint pipeline for that run.\n",
    "Unsupported monitors include:\n",
    "\n",
    "- planar or volumetric `FieldMonitor` outputs.\n",
    "- All other monitors which are not listed above.\n",
    "\n",
    "Direction policy for `ModeMonitor` outputs:\n",
    "\n",
    "- `\"assume_outgoing\"` is the default. Tidy3D infers the outgoing mode direction from the monitor position relative to the simulation center and keeps only the mode that points away from the center toward the outer simulation bounds. This avoids running adjoint simulations for the other direction.\n",
    "- `\"run_both_directions\"` prepares both `\"+\"` and `\"-\"` directions for each monitored mode. Use this if you are not sure in which direction the mode propagates across the monitor. Tidy3D will then run adjoint simulations for both directions, which increases the mode-monitor part of the parallel adjoint work.\n",
    "\n",
    "How many parallel adjoint simulations can be produced?\n",
    "\n",
    "- `ModeMonitor`: one basis per `(freq, mode_index, direction)`. With `\"assume_outgoing\"`, this is `num_freqs * num_modes`. With `\"run_both_directions\"`, this becomes `2 * num_freqs * num_modes`.\n",
    "- `DiffractionMonitor`: one basis per `(freq, order_x, order_y, polarization)` for propagating orders only. In practice this is typically `2 * num_freqs * num_propagating_orders`, because the polarizations are `s` and `p`.\n",
    "- point `FieldMonitor`: one basis per `(freq, field_component)`, so `num_freqs * num_components` for the selected components among `Ex`, `Ey`, `Ez`, `Hx`, `Hy`, and `Hz`.\n",
    "- Tidy3D then groups compatible bases by port, so the number of launched adjoint simulations can be smaller than the basis count.\n",
    "- If the grouped count exceeds `config.adjoint.max_adjoint_per_fwd`, parallel adjoint is disabled and Tidy3D falls back to the sequential path.\n",
    "\n",
    "Practical guidance:\n",
    "\n",
    "- Include only monitors in the differentiable simulation that are actually used for the gradient calculation.\n",
    "- Restrict each supported monitor to the essential data that enters the objective, such as the mode of interest, the relevant frequency, or the needed field components.\n",
    "- Place `ModeMonitor` outputs such that the mode of interest points away from the simulation center toward the outer boundary. This makes efficient use of the default `\"assume_outgoing\"` policy.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "48df8e830bae7ae",
   "metadata": {},
   "source": [
    "For more general autograd workflows:\n",
    "\n",
    "- [Autograd0Overview](https://www.flexcompute.com/tidy3d/examples/notebooks/Autograd0Overview/)\n",
    "- [Autograd0Quickstart](https://www.flexcompute.com/tidy3d/examples/notebooks/Autograd0Quickstart/)\n",
    "- [Autograd1Intro](https://www.flexcompute.com/tidy3d/examples/notebooks/Autograd1Intro/)\n",
    "- [Autograd2GradientChecking](https://www.flexcompute.com/tidy3d/examples/notebooks/Autograd2GradientChecking/)\n",
    "- [Autograd3InverseDesign](https://www.flexcompute.com/tidy3d/examples/notebooks/Autograd3InverseDesign/)\n",
    "\n",
    "For more waveguide bend examples:\n",
    "\n",
    "- [Autograd8WaveguideBend](https://www.flexcompute.com/tidy3d/examples/notebooks/Autograd8WaveguideBend/)\n",
    "- [Autograd18TopologyBend](https://www.flexcompute.com/tidy3d/examples/notebooks/Autograd18TopologyBend/)\n"
   ]
  }
 ],
 "metadata": {
  "applications": [
   "Passive photonic integrated circuit components"
  ],
  "description": "This notebook introduces the parallel adjoint workflow in Tidy3D FDTD with a simple 2D waveguide-bend example. After fixing the target guided mode with a mode solve, it compares one gradient evaluation with and without parallel adjoint to show when canonical adjoint basis simulations can run alongside the forward simulation.",
  "feature_image": "./img/adjoint_30.png",
  "features": [
   "Mode analysis",
   "2D simulation"
  ],
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "keywords": "parallel adjoint, adjoint method, inverse design, waveguide bend, mode analysis, 2D simulation, Tidy3D, FDTD",
  "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.11.2"
  },
  "title": "How to use parallel adjoint for mode gradients in Tidy3D FDTD"
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
