diff --git a/08-GD-2D-pde-constrained1.ipynb b/08-GD-2D-pde-constrained1.ipynb new file mode 100644 index 0000000..5dfa6aa --- /dev/null +++ b/08-GD-2D-pde-constrained1.ipynb @@ -0,0 +1,619 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f22c29d2-19b8-440d-bfdf-df258322a99b", + "metadata": {}, + "source": [ + "# PDE Constrained Optimisation with G-ADOPT\n", + "## Example: Inversion for Initial Condition with given Final State\n", + "\n", + "In this tutorial example we will see how we can use the PDE constrained optimisation functionality of G-ADOPT/Firedrake to optimize one of the inputs to a PDE for a specified desired outcome. We will use a time-dependent advection-diffussion equation as our PDE and see how, for a given final state of the solution we can retrieve what the initial condition should be." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "742b8007-fa95-4ade-8e9c-7b9759052357", + "metadata": {}, + "outputs": [], + "source": [ + "# Load Firedrake on Colab\n", + "try:\n", + " import firedrake\n", + "except ImportError:\n", + " !wget \"https://github.com/g-adopt/tutorials/releases/latest/download/firedrake-install-real.sh\" -O \"/tmp/firedrake-install.sh\" && bash \"/tmp/firedrake-install.sh\"\n", + " import firedrake" + ] + }, + { + "cell_type": "markdown", + "id": "04c1573f-624c-40f0-b093-170d6a81581d", + "metadata": {}, + "source": [ + "The usual imports, except we also import the inverse module of gadopt `gadopt.inverse`, which provides\n", + "the interface to the inversion functionality we need, but also switches\n", + "on the \"tape\" which automatically registers all operations that form\n", + "part of the forward model, which is used to automatically form the adjoint (backward) model." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "2a4ba5bf-69c1-4649-ae30-a9e4d4f96cf1", + "metadata": {}, + "outputs": [], + "source": [ + "# Usual imports\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "from gadopt import *\n", + "# Starts the tape\n", + "from gadopt.inverse import *" + ] + }, + { + "cell_type": "markdown", + "id": "1e5717ab-e34a-445c-bb5f-91f08024f488", + "metadata": {}, + "source": [ + "## Create Synthetic Twin Experiment With Final State for a Known Initial Condition\n", + "We first run a advection-diffusion model with known initial condition. Of that model we only store the solution at the final timestep, which we will use in our inversion experiment later on as the target final state.\n", + "\n", + "Setup of the model, with mesh, functionspaces, prescribed velocity field, boundary conditions, etc. We use the `EnergySolver` of G-ADOPT to set up an energy equation in the Boussinesq Approximation, which is just a scalar advection-diffusion equation for temperature." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "093bd2b5-d76f-48be-aebb-fe042fac56a3", + "metadata": {}, + "outputs": [], + "source": [ + "mesh = UnitSquareMesh(20, 20)\n", + "left, right, bottom, top = 1, 2, 3, 4 # Boundary IDs\n", + "\n", + "V = VectorFunctionSpace(mesh, \"CG\", 2) # function space for velocity\n", + "Q = FunctionSpace(mesh, \"CG\", 1) # function space for the scalar (Temperature)\n", + "T = Function(Q, name='Temperature')\n", + "\n", + "# set up velocity field: anti-clockwise rotation around (0.5, 0.5)\n", + "x, y = SpatialCoordinate(mesh)\n", + "u = interpolate(as_vector((-y+0.5, x-0.5)), V)\n", + "u.rename('Velocity')\n", + "\n", + "# Rayleigh number Ra is not actually used here, kappa is the diffusivity\n", + "approximation = BoussinesqApproximation(Ra=1, kappa=1e-2)\n", + "temp_bcs = {} # all closed boundaries by default\n", + "delta_t = .1 # timestep\n", + "energy_solver = EnergySolver(T, u, approximation, delta_t, ImplicitMidpoint, bcs=temp_bcs)" + ] + }, + { + "cell_type": "markdown", + "id": "90124c96-15f4-47ec-8d1f-283d20ff24af", + "metadata": {}, + "source": [ + "Setup the initial condition: a Gaussian at $(0.75, 0.5)$. This will be the initial condition we will try to invert for later on." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "51499bd4-2523-4128-aa7f-a9dde4ea7b7e", + "metadata": {}, + "outputs": [], + "source": [ + "x0, y0 = 0.75, 0.5\n", + "w = .1\n", + "r2 = (x-x0)**2 + (y-y0)**2\n", + "T.interpolate(exp(-r2/w**2));" + ] + }, + { + "cell_type": "markdown", + "id": "214a7207-8569-4d52-a075-9803512fc030", + "metadata": {}, + "source": [ + "A little plotting helper function to plot the Temperature with specified upper bound for the colour scale." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "6f0355a8-a2ee-4fa5-8f30-1ac4dc1f2d3f", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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y6/sGjJkiPbs2SOfz+f6WNu6HpZluX4uu+y+AUwsjh0wHRFHp+TkncVeffVVjR8/XqtWrdL111+vK6+8Unl5eUG/IcukSZN06tQp/ed//meH+w4cOFDSt69db8rn86m8vNz/504MHDhQn332WYs4Nj9Ha5xct4EDB6qhoUH/+7//G7C9srJSx48fD2rsAJwh4uiUevToIUm2QpyQkNAieL///e916NChoM596623KisrS3fddZf27NnT4s8PHz6shx9+WJKUl5cnj8ej//iP/wgYw6pVq1RVVaWrr77a8fknTpyoL7/8Uq+++qp/28mTJ9t9Rn+j5ORkSfau28SJEyVJS5cuDdi+ZMkSSQpq7ACc4Z0b0Ck1vkPavHnzdP3116tbt26aNGmSP+5NXXPNNXrooYc0Y8YMXXbZZfroo4/04osvatCgQUGdOz09Xa+//romTpyo4cOHB7xj244dO/Tyyy9rzJgxkr59cldhYaEWLFigq666Stdee612796tp59+WpdeemnAk9jsmjlzppYtW6Zp06Zp+/btysrK0gsvvOAPdHu6d++uCy64QOvXr9e5556rs846S0OHDtXQoUNb7Dts2DDl5+fr2Wef1fHjxzVu3Dht27ZNa9eu1eTJkzV+/HjHYwfgDBFHp3TppZdq4cKFWrFihTZt2qSGhgaVl5e3GvH7779fNTU1eumll7R+/Xpdcskl2rBhQ0hvMZqbm6uPP/5Yjz32mDZs2KAXXnhB8fHxOv/88zV37lzdfvvt/n2Li4vVp08fLVu2THPmzNFZZ52lWbNmadGiRY7eUa1RcnKySktLdccdd+ipp55ScnKybrrpJv3kJz/RVVdd1eHxzz33nO644w7NmTNHPp9PRUVFrUa8cd9BgwZpzZo1ev3115WZmanCwkIVFRU5HjcA5+IsnlUCAICRuCcOAIChiDgAAIYi4gAAGMpxxN9//31NmjRJ/fr1U1xcnN54440Oj9m8ebMuueQSeb1eDR48WGvWrAliqAAAxKZotdFxxGtqajRs2DAtX77c1v7l5eW6+uqrNX78eJWVlenOO+/ULbfcorfeesvxYAEAiEXRamNIz06Pi4vT66+/rsmTJ7e5z3333acNGzbo448/9m+7/vrrdfz4cW3atCnYUwMAEJMi2cawv05869atysvLC9g2YcIE3XnnnW0eU1tbq9ra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GIqIAwBgKCIOAIChiDgAAIaKmYjzGeX2OLlOK1eu1NixY5Wenq709HTl5eV1eF07A6d/lxqtW7dOcXFxmjx5cngHGCOcXqfjx49r9uzZysrKktfr1bnnntsl/rtzep2WLl2q8847T927d1d2drbmzJmj06dPR2i00fH+++9r0qRJ6tevn+Li4mx9gMfmzZt1ySWXyOv1avDgwVqzZk3Yx9kphf6quNCtW7fO8ng81urVq62///3v1syZM61evXpZlZWVre7/5z//2UpISLAeffRR65NPPrEeeOABxy+QN5HT63TjjTday5cvt3bu3Gl9+umn1vTp0620tDTriy++iPDII8fpNWpUXl5u9e/f3xo7dqz1r//6r5EZbBQ5vU61tbXWqFGjrIkTJ1offPCBVV5ebm3evNkqKyuL8Mgjy+l1evHFFy2v12u9+OKLVnl5ufXWW29ZWVlZ1pw5cyI88sjauHGjNW/ePOu1116zJFmvv/56u/vv27fPSk5OtgoKCqxPPvnEeuqpp6yEhARr06ZNkRlwJxITER89erQ1e/Zs//f19fVWv379rJKSklb3/8UvfmFdffXVAdtyc3Otf/u3fwvrOKPN6XVqrq6uzurZs6e1du3acA0x6oK5RnV1ddZll11mPffcc1Z+fn6XiLjT6/TMM89YgwYNsnw+X6SGGBOcXqfZs2dbP/rRjwK2FRQUWJdffnlYxxlL7ET83nvvtS688MKAbVOmTLEmTJgQxpF1TlFfTm/8DNa8vDz/Njufwdp0f+nbz2Bta//OIJjr1NzJkyd15syZqH2SULgFe40eeugh9e3bVzfffHMkhhl1wVynN998U2PGjNHs2bOVkZGhoUOHatGiRaqvr4/UsCMumOt02WWXafv27f4l93379mnjxo2aOHFiRMZsiq74b3i4RP2jSKP1GaymCeY6NXffffepX79+Lf7j6SyCuUYffPCBVq1apbKysgiMMDYEc5327dund999VzfddJM2btyovXv36rbbbtOZM2dUVFQUiWFHXDDX6cYbb9TRo0f1gx/8QJZlqa6uTrfeeqvuv//+SAzZGG39G15dXa1Tp06pe/fuURqZeaI+E0dkLF68WOvWrdPrr78e1o/jM8mJEyc0depUrVy5Ur179472cGJaQ0OD+vbtq2effVYjR47UlClTNG/ePK1YsSLaQ4spmzdv1qJFi/T0009rx44deu2117RhwwYtXLgw2kNDJxX1mXi0PoPVNMFcp0aPP/64Fi9erHfeeUcXX3xxOIcZVU6v0Weffab9+/dr0qRJ/m0NDQ2SpMTERO3evVvnnHNOeAcdBcH8XcrKylK3bt2UkJDg33b++eeroqJCPp9PHo8nrGOOhmCu04MPPqipU6fqlltukSRddNFFqqmp0axZszRv3ryofp52LGnr3/DU1FRm4Q5F/W8Un1FuTzDXSZIeffRRLVy4UJs2bdKoUaMiMdSocXqNhgwZoo8++khlZWX+r2uvvVbjx49XWVmZsrOzIzn8iAnm79Lll1+uvXv3+n/JkaQ9e/YoKyurUwZcCu46nTx5skWoG3/xsfisKb+u+G942ET7mXWWFZ3PYDWR0+u0ePFiy+PxWK+++qr11Vdf+b9OnDgRrR8h7Jxeo+a6yrPTnV6nAwcOWD179rRuv/12a/fu3dYf/vAHq2/fvtbDDz8crR8hIpxep6KiIqtnz57Wyy+/bO3bt8/64x//aJ1zzjnWL37xi2j9CBFx4sQJa+fOndbOnTstSdaSJUusnTt3Wp9//rllWZY1d+5ca+rUqf79G19ids8991iffvqptXz5cl5iFqSYiLhlRf4zWE3l5DoNHDjQktTiq6ioKPIDjyCnf5ea6ioRtyzn12nLli1Wbm6u5fV6rUGDBlmPPPKIVVdXF+FRR56T63TmzBmruLjYOuecc6ykpCQrOzvbuu2226xjx45FfuAR9N5777X6b03jtcnPz7fGjRvX4pjhw4dbHo/HGjRokPX8889HfNydAZ8nDgCAoaJ+TxwAAASHiAMAYCgiDgCAoYg4AACGIuIAABiKiAMAYCgiDgCAoYg4AACGIuIAABiKiAMAYCgiDgCAof5/gM5Lau6JvNMAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def plot_temp(T, title=None, Tmax=1, ax=None, colorbar=True):\n", + " if ax is None:\n", + " fig, ax = plt.subplots()\n", + " else:\n", + " fig = ax.get_figure()\n", + " levels = np.linspace(0, Tmax, 11)\n", + " # this tells the tape to *not* register the interpolation that happens inside the plotting script\n", + " with stop_annotating():\n", + " c = tricontourf(T, axes=ax, levels=levels)\n", + " ax.set_title(title)\n", + " ax.set_aspect('equal')\n", + " if colorbar:\n", + " cax = fig.add_axes([ax.get_position().x1+0.05,ax.get_position().y0,0.02,ax.get_position().y1-ax.get_position().y0])\n", + " fig.colorbar(c, cax=cax)\n", + "plot_temp(T, 'Initial Condition', Tmax=1)" + ] + }, + { + "cell_type": "markdown", + "id": "e421c116-803c-42d8-b708-c9ccb0c06844", + "metadata": {}, + "source": [ + "The actual model: ten timesteps. Pretty simple, huh?" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "56f8a2d4-6174-4153-917a-ff5dd4daeaeb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n" + ] + } + ], + "source": [ + "for i in range(10):\n", + " energy_solver.solve()" + ] + }, + { + "cell_type": "markdown", + "id": "10398fea-ea08-42df-834a-53bef21a9368", + "metadata": {}, + "source": [ + "Plot the final temperature solution and save it in a checkpoint file." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "cda4c1fd-e722-4626-b182-19a85d2ae2d5", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAfoAAAGzCAYAAADHQtXtAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA5pElEQVR4nO3dfXRU9YH/8c8QSIKExCiQBxoJD1WrCNggEZVylKzBerC0ugV0JVLUailrTa2CCgGxkFLqoS0oByrC9qdCn3S7ysZqNO1aI2yB1Kpgy1NBJAFUEgiSgeT+/mAzZsgkzJ3MfZz365wcZbgz851rnPd878PcgGEYhgAAgC91c3oAAADAOoQeAAAfI/QAAPgYoQcAwMcIPQAAPkboAQDwMUIPAICPEXoAAHyM0AMA4GOEHgltz549CgQCWrNmjaXPk5+frzvuuMPS5wCASAg9fG3NmjUKBAIRf2bNmuX08No5duyYysrKNHToUPXq1Uvnn3++RowYofvuu08fffRRaLkNGzZo3rx5XXquhQsX6sUXX+zagAG4XnenBwDY4bHHHtPAgQPDbhs6dKgGDBigzz77TD169HBoZJ87efKkvvKVr2j79u0qKSnRzJkzdezYMb333nt67rnn9PWvf125ubmSTod++fLlXYr9woULdcstt2jixInxeQEAXInQIyHccMMNGjlyZMS/S01NtXk0kb344ovaunWrnn32Wd16661hf3fixAkFg0GHRgbAy9h0j4QWaR/9HXfcobS0NO3fv18TJ05UWlqa+vbtqwceeEDNzc1h91+yZImuuuoqnX/++erZs6cKCgr0m9/8Jqax7Ny5U5J09dVXt/u71NRUpaenh8a3fPlySQrbFWFmTIFAQI2NjVq7dm3o/m2PIdi/f7++9a1vKSsrSykpKbr00ku1evXqmF4XAGcxo0dCqK+v1+HDh8Nu69OnT4fLNzc3q7i4WIWFhVqyZIlee+01/eQnP9HgwYN17733hpb76U9/qptuukm33XabgsGg1q1bp3/913/VSy+9pBtvvNHUGAcMGCBJ+o//+A89+uijYfFu69vf/rY++ugjvfrqq/rlL3/Z7u+jGdMvf/lL3XnnnRo1apTuvvtuSdLgwYMlSXV1dbryyisVCAT03e9+V3379tV///d/a/r06WpoaND3vvc9U68LgMMMwMeeeeYZQ1LEH8MwjN27dxuSjGeeeSZ0n5KSEkOS8dhjj4U91uWXX24UFBSE3Xb8+PGwPweDQWPo0KHGddddF3b7gAEDjJKSkk7Hevz4ceOiiy4yJBkDBgww7rjjDuPpp5826urq2i07Y8YMo6P/faMdU69evSKOafr06UZOTo5x+PDhsNsnT55sZGRktHt8AO7GpnskhOXLl+vVV18N+zmbe+65J+zPY8aM0a5du8Ju69mzZ+jfP/30U9XX12vMmDHasmWL6TH27NlTGzdu1A9+8ANJp88YmD59unJycjRz5kw1NTVF/TixjskwDP32t7/VhAkTZBiGDh8+HPopLi5WfX19TK8NgHPYdI+EMGrUqA4PxoskNTVVffv2DbstMzNTn376adhtL730kh5//HHV1NSEhbijze5nk5GRocWLF2vx4sX65z//qcrKSi1ZskTLli1TRkaGHn/88bM+RlfGdOjQIR05ckQrV67UypUrIy5z8ODB6F8QAMcReiCCpKSksy7zP//zP7rpppv0la98RU8++aRycnLUo0cPPfPMM3ruuee6PIYBAwboW9/6lr7+9a9r0KBBevbZZ88a+q6OqaWlRZL0b//2byopKYm4zLBhw8y/GACOIfRAjH77298qNTVVr7zyilJSUkK3P/PMM3F9nszMTA0ePFjvvvtu6LaOZudmxhTpMfr27avevXurublZRUVFcRg9AKexjx6IUVJSkgKBQNgpd3v27In52+b++te/tjszQJL++c9/6v3339dFF10Uuq1Xr16SpCNHjsQ8pl69ekW8/80336zf/va3YR8sWh06dMjEKwLgBszogRjdeOONeuKJJzR+/HjdeuutOnjwoJYvX64hQ4bonXfeMf14r776qsrKynTTTTfpyiuvVFpamnbt2qXVq1erqakp7FvwCgoKJEn//u//ruLiYiUlJWny5MmmxlRQUKDXXntNTzzxhHJzczVw4EAVFhaqvLxcb7zxhgoLC3XXXXfpkksu0SeffKItW7botdde0yeffNKl9QbAZk4f9g9YqfX0uv/93/+N+PcdnV7Xq1evdsuWlZW1O6Xt6aefNr74xS8aKSkpxsUXX2w888wzEZeL5vS6Xbt2GXPnzjWuvPJKo1+/fkb37t2Nvn37GjfeeKPx+uuvhy176tQpY+bMmUbfvn2NQCAQ9nzRjmn79u3GV77yFaNnz56G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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_temp(T, 'Final State', Tmax=0.25)\n", + "with CheckpointFile('final.h5', 'w') as f:\n", + " f.save_mesh(mesh)\n", + " f.save_function(T)" + ] + }, + { + "cell_type": "markdown", + "id": "8bf12388-c4d3-47ff-8408-fa35bacd8d30", + "metadata": {}, + "source": [ + "## Advection Diffusion Model with Unknown Initial Condition\n", + "We now start completely from scratch again with an advection-diffusion model with the same configuration, except this time\n", + "we don't know the correct initial condition. As we want to measure for different initial conditions, how well the final state of the model matches the one we just saved, we first read back that target final state. We will also use the mesh from the checkpoint file to construct the model." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "50df4864-c4aa-4671-abb7-6676d231d689", + "metadata": {}, + "outputs": [], + "source": [ + "with CheckpointFile('final.h5', 'r') as f:\n", + " mesh = f.load_mesh()\n", + " T_target = f.load_function(mesh, 'Temperature')" + ] + }, + { + "cell_type": "markdown", + "id": "058988a3-1e62-4d52-8052-b6942aad4eb1", + "metadata": {}, + "source": [ + "Setup exactly as before:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "9743b4cc-343b-4506-b501-ac4d22388d98", + "metadata": {}, + "outputs": [], + "source": [ + "V = VectorFunctionSpace(mesh, \"CG\", 2)\n", + "Q = FunctionSpace(mesh, \"CG\", 1)\n", + "T = Function(Q, name='Temperature')\n", + "\n", + "x, y = SpatialCoordinate(mesh)\n", + "u = interpolate(as_vector((-y+0.5, x-0.5)), V)\n", + "u.rename('Velocity')\n", + "\n", + "approximation = BoussinesqApproximation(Ra=1, kappa=1e-2)\n", + "temp_bcs = {} # all closed boundaries by default\n", + "delta_t = .1\n", + "energy_solver = EnergySolver(T, u, approximation, delta_t, ImplicitMidpoint, bcs=temp_bcs)" + ] + }, + { + "cell_type": "markdown", + "id": "91a1d0ce-869b-448c-958c-6085c809877f", + "metadata": {}, + "source": [ + "This time however, we don't want to use the known initial condition. Instead we will start with the final state from our last model, which will then be further rotated and diffused. After again ten timesteps we compute the mismatch between the new final state, and the checkpointed final state. This computation, the ten timesteps and the mismatch calculation, forms the forward model that we want to invert. Its adjoint will be created automatically from the tape that registers all operations in the model. Since the tape was automatically started at the top when we imported `gadopt.inverse`, we want to make sure we don't get mixed up with any operations that happened in our initial twin model, so we first clear everything that has already been registered off the tape." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "d13ea66e-12d7-4a76-a2b9-588a95ec4b7e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + "Mismatch functional J=0.6916401392014154\n" + ] + } + ], + "source": [ + "tape = get_working_tape()\n", + "tape.clear_tape()\n", + "\n", + "T.interpolate(T_target)\n", + "\n", + "# we want to vary the _initial_ (current) state of T\n", + "# here we specify the current state of T as the control\n", + "m = Control(T)\n", + "\n", + "for i in range(10):\n", + " energy_solver.solve()\n", + "\n", + "# For good performance of optimisation algorithms, it is important to\n", + "# scale both the control and the functional values to be of order 1\n", + "# Note that mathematically scaling the functional should not change the optimal solution\n", + "scaling = 1./assemble(T_target**2*dx)\n", + "J = assemble(scaling * (T-T_target)**2*dx)\n", + "print(F\"Mismatch functional J={J}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "4baa83ca-bf63-4e41-8b36-0f0c36f2cd5b", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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0qVL8emnn2L48OGwWq0uP+cAl+f0gJycHGzZsgWFhYUwmZwPlc6ZMwdZWVm2nysrK9msiXyYK72DfYOIPOnkyZN2h2iNRqNi2x47dqzt/3v27IlevXohKSkJhYWFGDJkiEvrkBTwIiIi4O/vj7KyMrvpZWVliI6ObnLZ3Nxc5OTkYNeuXejVq1eT8xqNRkVfSCKSlxK9g32DiDwpNDS02XPw3Olt0dHRknthYmIiIiIicPToUZcDnqRDtIGBgUhJSUFBQYFtWm1tLQoKCpCWluZ0uWXLlmHhwoXIz89Hnz59pGySiHSAvYOI9Mid3paWlmY3PwDs3LmzyV546tQpXLx4ETExMS7XJvkQbVZWFjIzM9GnTx/069cPK1asQFVVFSZPngwAmDhxIjp06GA7Vr106VLMmzcPmzdvRnx8vO0Yc0hICEJCQqRunog0ir2DiPRIam+bOXMmBg0ahJdffhkjRozAli1b8M9//hOvvfYaAODy5ctYsGAB7r//fkRHR+PYsWN45pln0LlzZ2RkZLhcl+SAN2bMGJw/fx7z5s2D2WxGcnIy8vPzbScMnjhxAn5+Pw8Mrl69GhaLBQ888IDderKzszF//nypmycijWLvICI9ktrb+vfvj82bN+OFF17Ac889h1tuuQXbtm1Djx49AAD+/v746quvsHHjRpSXlyM2NhZDhw7FwoULJZ2GIvk+eN7A+1kReZe372XlDvYNIu/zdu+o6wODb5+NAH8X74NnrcYnB3M01e8c4XfREhEREekMAx4RERGRzjDgEREREekMAx4RERGRzjDgEREREekMAx4RERGRzjDgEREREekMAx4RERGRzjDgEREREekMAx4RERGRzjDgEREREekMAx4RERGRzjDgEREREekMAx4RERGRzjDgEREREekMAx4RERGRzgR4uwAiIiIiORmOn4XBL9C1eWstMlejDI7gEREREekMAx4RERGRzjDgEREREekMAx4RERGRzjDgEREREekMAx4RERGRzjDgEREREekMAx4RERGRzjDgEREREekMAx4RERGRzjDgEREREekMAx4RERGRzjDgEREREekMAx4RERGRzjDgEREREekMAx4RERGRzjDgEREREemMWwEvLy8P8fHxMJlMSE1Nxb59+5qc/5133kHXrl1hMpnQs2dP7Nixw61iiUjb2DuISI883duE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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig, ax = plt.subplots(1,2)\n", + "plot_temp(T, 'Final State', Tmax=.25, ax=ax[0], colorbar=False)\n", + "plot_temp(T_target, 'Target Final State', Tmax=.25, ax=ax[1])" + ] + }, + { + "cell_type": "markdown", + "id": "6a27c9ef-40d1-40e4-b621-48e55727fbdf", + "metadata": {}, + "source": [ + "Now we have run the forward model including the calculation of the forward model, we can define the *reduced functional* which combines the functional with the control we specified above:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "69a3038a-df24-4fea-aa3b-dcb457dd4ec6", + "metadata": {}, + "outputs": [], + "source": [ + "Jhat = ReducedFunctional(J, m)" + ] + }, + { + "cell_type": "markdown", + "id": "d27f4c36-b6b9-4a8c-a2f4-af0cff56b809", + "metadata": {}, + "source": [ + "The reduced functional allows us to rerun the forward model for different values of the control. It can be used as a function that takes in any choice of the control, runs the forward model and computes the functional. For instance we can rerun the model again using `T_target` as the initial condition, i.e. rerunnnig the exact same model we have just run:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "48fa1503-559c-4a8a-a6bb-0718023635bb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + "0.6916401392014154\n" + ] + } + ], + "source": [ + "print(Jhat(T_target))" + ] + }, + { + "cell_type": "markdown", + "id": "d45dff65-c03d-4d98-afaf-e7c376e9657b", + "metadata": {}, + "source": [ + "As expected it produces the exact same functional value. Now we can try to see what happens if we use the correct initial condition, that we have used in our twin experiment:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "e9acd308-4642-4d06-a501-47066b340308", + "metadata": {}, + "outputs": [], + "source": [ + "x0, y0 = 0.75, 0.5\n", + "w = .1\n", + "r2 = (x-x0)**2 + (y-y0)**2\n", + "T0 = interpolate(exp(-r2/w**2), Q)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "accde8c0-ab9f-4c27-b317-58fc5046ffc7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + "0.0\n" + ] + } + ], + "source": [ + "print(Jhat(T0))" + ] + }, + { + "cell_type": "markdown", + "id": "62c229ca-07b5-4b1f-a9e7-1224c1ec4a06", + "metadata": {}, + "source": [ + "Using the \"correct\" initial condition, we reach the same final state as in our twin model, and thus the functional ends up being exactly zero!\n", + "\n", + "In addition to rerunning the model by evaluating the reduced functional, we can also calculate its derivative. This computes the sensitivity of the model with respect to its control (the initial condition). Here it tells us in what locations a (small) increase in the initial condition will lead to an increase in the functional." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "a94b00c1-b718-4926-8df4-ec71e604b665", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + "Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + "Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + "Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + "Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + "Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + "Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + "Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + "Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + "Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + "Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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y2+88UZ89tlnMBqNFm8FbI+9l9GVOnbsiEGDBmHDhg249tprcc0112DIkCEYMmRIi3Xtud5cwZ23UWv69euH0aNH49FHH0VNTQ2ysrLQtWtXPP300y4d07hx4/Dee+8hICAAgwYNQkFBAb744gt07drVYr2oqCjo9XosW7YMZWVlMBqN5s8YePDBB/HII4/gnnvuwW233YYDBw5g69atCAoKsumyuuLvgIhvhXOzpre7NP0YDAYRFhYmbrvtNrFixQpRXl5u9XTHjx8XU6dOFWFhYcLb21t0795djBs3Tnz00Uctztva2+yufitcc5MnTxYAREJCgtVtb968WQwbNkz4+PiIyMhIsWzZMrFmzZoW51dSUiLGjh0r/Pz8BADzW5iufitcc/PmzRMARL9+/VrdZzt27BCJiYkiICBA+Pj4iL59+4pp06aJ//znP62eprmQkBABQJhMJvOy3bt3CwAiPj6+xfpjxowRgwcPtnperV3G1qCVt8J9+OGHFus1vcVr7dq15mVXvxVOCCH27NkjoqOjhcFgsHiLlbW3wtl6vbnirXBCOHcbbRr/uXPnLJYnJSWJTp06mX9v2k8vvviiePnll0VERIQwGo0iPj5eHDhwoMVYnf27uXDhgkhOThZBQUGic+fOIjExURw+fLjF29iEEGL16tWiT58+Qq/XW9zeGxoaxJw5c0RQUJDw9fUViYmJ4tixY62+Fa61t8k6+3dA2sbPlici2SouLkbv3r3x4osv4sknn5R6OESKwefciYiIVIZxJyIiUhnGnYiISGXsjvvOnTsxfvx4hIeHQ6fTYdOmTe2eJj8/HyNGjIDRaES/fv2wbt06B4ZKRFrT9GFEfL6dyD52x72qqgrDhw9Hdna2TeufPHkSY8eOxc0334yioiI88cQTePDBB7F161a7B0tERETtc+rV8jqdDh9//DEmTJjQ6jpz5szBli1bLL57+f7778fFixeRm5vr6KaJiIioFW7/EJuCgoIWH6GYmJiIJ554otXT1NTUoKamxvx7Y2Mjzp8/j65du0r6caBERGQ/IQQqKioQHh7e4nsdXOnSpUuora11yXkZDAaLDxdTGrfHvaSkBKGhoRbLQkNDUV5ejt9++83qlzdkZGTY9fnfREQkf2fOnEGPHj3cct6XLl1CDz9//Frf8iN7HREWFoaTJ08qNvCy/PjZtLQ0pKammn8vKytDz549sT/vU/h17iThyDyrs+moR7bTeNw927l46LhbzhcAftx7ym3nrRQ9RvZy6/l3GdjXLefr1fdat5xvaypDPbs9aqmisgq/u3Uc/Pz83LaN2tpa/Fpfh4+HDkOnVr6F0FZVDQ34/bffoLa2lnFvTVhYGEwmk8Uyk8kEf3//Vr9m02g0wmg0tlju17kT/Dp3dss4ZanzCACAX8kh925n2OXvNm/84bBLz9Z/xCAAwIXvWn6jl7MGjrb8+s7TBSddvg258zN4u/X8G46fRuCQlt+j7rSfLz8w8+o/wPXnbYV/5RlUhA30yLaobZ54WrWTXu903NXA7XGPi4tDTk6OxbJt27YhLi7O3ZtWjaY7JndHvunO1tWRbx4Id4QeAHrG9Tb/vxZD7y4XvvvBPYHH5duZpwLf9LfDyJNW2P3KhsrKShQVFaGoqAjA5be6FRUV4fTp0wAuH1KfOnWqef1HHnkEJ06cwNNPP43Dhw/jjTfewMaNGzF79mzXXAIN8dQdk1f/AeYfVwsc0t/84y4943pb/JBz3PWADHD9A8n2uP0oGJFM2D1z/89//oObb77Z/HvTc+NJSUlYt24dfvnlF3PoAaB3797YsmULZs+ejRUrVqBHjx546623kJiY6ILha4+nZvFNmgfeXTN6d8YD4KzeFdQygwc4iydtUMS3wpWXlyMgIADHvtqhrefcbSDFTMSdsy13h745pYdeiqMS7jziAnjuefgmDLxnVFRWol/szSgrK4O/v79bttHUic+jfueSF9TdXrTfreN1N362vMJJcefkrkP2ANx+yL45Hrq3n7sffPEwPZFryPKtcGQfTx+qb+KuF+ABnnkRXnM8dG87dx6iB3iYnsgVGHcVaX7n5MnQu/N5eUDa0LdFyw8C1BZ44PLfDANPasG4q5TUoXfX4VVPh74tVz8I0FrsPRF4wLPPwzPwpBaMuwZIEXp3Rx6QV+gB5w7tK/VpAXcHHuBheiJHMO4a4+nQu/uQfRM5hx5oPdjWngJQ2gv81Bh4gLN4UjbGXcPU9J755uQWekB5wbYXA08kL3wrHKEibKDH78Dc+Sl4zXniE/HoMk88kPL0W+WAy4HnW+ZIaThzJzOp31IHaG9GrzaemsEDnv/AG87iSUk4c6cWmmbyUn5ADmf0yuWpB05SzeKJlIAzd2qTVG+pAzijVzJPzOAB6Z6HB/hqepI3xp1sxtCTHEkReICH6UneeFieHCLlnZqn7sh52F45pDhETyRnjDs5TAuBBxh5ah2fgye5YtzJKVIH3tORJ/ni7J3oCsadnCb1846cxZOUOHsnOWLcSRU8/YIqRl6epJq9M/AkN4w7uYTUs3fA84fpAUaermDgSU4Yd3IZOQQe8PwsHmDk5YTPvRMx7uRiWg48wMhrHWfvJBeMO6mWVIEHGHmpSTl7Z+BJDhh3cjm5zN4BaZ6Hb46fYa9NDDxJjXEnt5BT4AFpZ/FNGHnP4nPvpGWMO7kNA2+dFmbzar5stuLsnaTEuJNbyTHwcok8wNm8u0k9e2fgSSqMO7md3AIPyGcW30QLs3mtYuBJCow7eYRcAy+3yAPKD73cxi317J3UraGhAfPnz0fv3r3RsWNH9O3bF4sXL4YQwryOEAILFixAt27d0LFjRyQkJOCHH9z7ldKMO3mMHAMPyDfygPJCr5Rxehpn7+q1bNkyrFy5Eq+//joOHTqEZcuWYfny5XjttdfM6yxfvhyvvvoqVq1aha+++gqdOnVCYmIiLl265LZxdXDbORNZURE2ULZ3dE2Bl+tMr3k4L3zn3kf99mLU2+dXcki2D3DJcXv27MHdd9+NsWPHAgAiIyPx97//HXv37gVwedaelZWFZ599FnfffTcA4N1330VoaCg2bdqE+++/3y3j4sydPE7ud3ByncU313xGL2VYpd6+reT6gI3krby83OKnpqamxTqjRo1CXl4ejh49CgA4cOAAdu/ejTvuuAMAcPLkSZSUlCAhIcF8moCAAMTGxqKgoMBtY+fMncgKuc/ir9YUWE/N6JUQdDni7N39eozsBT+Dt1PnUVFbBxTtR0REhMXy9PR0LFy40GLZ3LlzUV5ejgEDBkCv16OhoQEvvPACJk+eDAAoKSkBAISGhlqcLjQ01Pxv7sC4kyTkfHi+Oa/+AxQTeMC26DrzAECpUVfC0RiSnzNnzsDf39/8u9FobLHOxo0b8f777+ODDz7A4MGDUVRUhCeeeALh4eFISkry5HAtMO5E7VBa4Ntja6AvfPeDYmNO5Ar+/v4Wcbfmqaeewty5c83PnQ8dOhSnTp1CRkYGkpKSEBYWBgAwmUzo1q2b+XQmkwlRUVFuGzufcyfJKOnwpBZnfgw7Ufuqq6vh5WWZUr1ej8bGRgBA7969ERYWhry8PPO/l5eX46uvvkJcXJzbxsWZO5GN1DaDJyLnjR8/Hi+88AJ69uyJwYMHY//+/cjMzMT//u//AgB0Oh2eeOIJPP/88+jfvz969+6N+fPnIzw8HBMmTHDbuBh3Ijsw8OQsvqhOXV577TXMnz8fM2fOxNmzZxEeHo6HH34YCxYsMK/z9NNPo6qqCg899BAuXryI0aNHIzc3Fz4+Pm4bl040/xgdmSovL0dAQACOfbUDfp07Sz0ccjElvLDuagy8ssjtaRWtxb2ishL9Ym9GWVlZu89hO6qpEwcfmuCSV8sPenOTW8frbnzOncgBcosFEVFzjDtJTqmzGAaeiOSKcSdyAgNPRHLEuBM5Sc5fPEN8AEbaxLgTuQgjQrZS4otISVkYdyIX4iyeiOSAcSdyAwZeHng9kFYx7iQLSn3FfFs4iyciqTDuRG7GwEuD+520jHEn8gDO4onIkxh3Ig9i4D2D+5m0jnEn8jDO4t2L+5aIcSeSDCPketynRJcx7kQSYoxch/uS6ArGnUhiPEzvPO4/IksdpB4AUZOKsIGa/ljO5oHi98Wrmxo/14HkhXEnkqGm0DPybeOMncg6xp1Ixhh56xh1orYx7kQKwMhfpoao85A8eQLjTqQgWo28GqJO5EmMO5ECaSXyjDqRYxh3IgVTa+QZdSLnMO4kK1p/O5yj1BB5LQRdi8+3/+zdC5XeFVIPQ3MYdyIVsRZIOQdfC0HXmp+9e0k9BALjTqR6bQXU0+HXcsy1OGsn6TDuRBrmipm+loNtK4adPM2hz5bPzs5GZGQkfHx8EBsbi71797a5flZWFq677jp07NgRERERmD17Ni5duuTQgInIvZo+697WH2obw05SsDvuGzZsQGpqKtLT07Fv3z4MHz4ciYmJOHv2rNX1P/jgA8ydOxfp6ek4dOgQ3n77bWzYsAHPPPOM04Mn9eGL6YiInGd33DMzMzFjxgwkJydj0KBBWLVqFXx9fbFmzRqr6+/Zswc33HADJk2ahMjISNx+++144IEH2p3tExEpHWftJBW74l5bW4vCwkIkJCRcOQMvLyQkJKCgoMDqaUaNGoXCwkJzzE+cOIGcnBzceeedrW6npqYG5eXlFj9EREqixbDzlfLyYdcL6kpLS9HQ0IDQ0FCL5aGhoTh82PqLcCZNmoTS0lKMHj0aQgjU19fjkUceafOwfEZGBhYtWmTP0IiIiNBlYF/4dzQ6dR7632pcNBrpOPSCOnvk5+djyZIleOONN7Bv3z7885//xJYtW7B48eJWT5OWloaysjLzz5kzZ9w9TJIJLc52SH20djv+2bsXZ+0yY9fMPSgoCHq9HiaTyWK5yWRCWFiY1dPMnz8fU6ZMwYMPPggAGDp0KKqqqvDQQw9h3rx58PJq+fjCaDTCaHTukRcRkRS0FHYGXb7smrkbDAZER0cjLy/PvKyxsRF5eXmIi4uzeprq6uoWAdfr9QAAIYS94yUikqWKsIEMO8mG3R9ik5qaiqSkJMTExGDkyJHIyspCVVUVkpOTAQBTp05F9+7dkZGRAQAYP348MjMz8bvf/Q6xsbE4duwY5s+fj/Hjx5sjT9QcP1+elIZRJ7mxO+4TJ07EuXPnsGDBApSUlCAqKgq5ubnmF9mdPn3aYqb+7LPPQqfT4dlnn8VPP/2E4OBgjB8/Hi+88ILrLgURkQS0FHVSFp1QwLHx8vJyBAQE4NhXO+DXubPUwyEP4Myd5E6rYXdk5l5ZWYH4EX1RVlYGf39/N4zqSid+fuUvTr9avvy3GoTPftmt43U3t79anohIbRh2kjvGnWRJq3eeJH+8bZIS8FvhiIhswKiTknDmTkTUDoadh+SVhjN3IqJWMOqkVJy5k2zxjpWkorUPpCH14cydiOi/GHTreEheeRh3ItI0Bp3UiHEnIk1i1EnN+Jw7yRrvgMnV+Hy6fXhIXpk4cyci1WPMHcOwKxfjTkSqxag7jmFXNsadZI9fAUv2YNCdw6irA+NORIrHoLsGw64ejDspAmfvdDUG3XUYdfVh3EkxGHhtY8xdj1FXL8adFIWB1w7G3H08HfXTFwM9uj1i3EmBGHh1YszdT4qZevHFawCUe3y7Wse4kyIx8MrHmHuWdGEnKTDupFgMvPIw6NJg2LWHcSdFY+DliyGXB0+HnVGXB8adFI+BlxYjLl8Mu3Yx7qQKDLxnMehE8sa4k2ow8O7FoCsHn2Mnxp1UhYF3LQZdWfihNNSEcSfVYeBtx3irg9RR56xdfrykHgCROzBarasIG2j+IeX62buX+YfkY+nSpdDpdHjiiSfMyy5duoSUlBR07doVnTt3xj333AOTyeTWcTDupFqM1xUMunrILeictV/x9ddf469//SuGDRtmsXz27Nn45JNP8OGHH+Jf//oXfv75Z/zhD39w61gYd1I1LceMQVcPztLlr7KyEpMnT8bq1asRGHjls/TLysrw9ttvIzMzE7fccguio6Oxdu1a7NmzB19++aXbxsPn3En11P4cPOOtTkoIudpn7eXllp+JbzQaYTQara6bkpKCsWPHIiEhAc8//7x5eWFhIerq6pCQkGBeNmDAAPTs2RMFBQW4/vrr3TJ2xp00QU2BZ8zVSwlBlzuvvtfCq1NH586j6jcAQEREhMXy9PR0LFy4sMX669evx759+/D111+3+LeSkhIYDAZ06dLFYnloaChKSkqcGmdbGHfSjKYo+pUcUkTsGXH1U3LM1T5rB4AzZ87A39/f/Lu1WfuZM2fw+OOPY9u2bfDx8fHk8NrEuJPmNEXTWjylDD5jrg1KDnoTLYQdAPz9/S3ibk1hYSHOnj2LESNGmJc1NDRg586deP3117F161bU1tbi4sWLFrN3k8mEsLAwdw2dcSdqrrXA2hJ9xpmsUUPMm9NK2G1166234ttvv7VYlpycjAEDBmDOnDmIiIiAt7c38vLycM899wAAjhw5gtOnTyMuLs5t42LciWzQ1iyfUafm1BZzapufnx+GDBlisaxTp07o2rWrefn06dORmpqKa665Bv7+/njssccQFxfnthfTAYw7kcMYddJayDlrd8wrr7wCLy8v3HPPPaipqUFiYiLeeOMNt26TcScisoPWgk72y8/Pt/jdx8cH2dnZyM7O9tgYGHciojYw5pc5M2svLuHnpXka405EdBUG3XVO/MywS4FxJyJNY8jb5+isnWGXDuNORJrCmJMWMO5EpHoMuuM4a1cmxp2IVIlBd44zL6Bj2KXHuBORKjDmruHse9kZdnlg3IlIsRh01+KH1KgH405EisKgu4crws5Zu3ww7kQkewy6e3HGrj6MOxHJEoPuGa4KO2ft8sK4E5GsMOqewxm7ejHuRCQ5Bt3zXBl2ztrlh3EnIskw6p7H2bo2MO5E5FEMunTcEXbO2uWJcScij2DUpcUZu7Yw7kTkVoy69NwVds7a5YtxJyKXY9DlgzN2bWLcichlGHV5cWfYOWuXN8adiJzGqMsPw65tjDsROYxRlxcegqcmjDsR2Y1RlwcpYs5ZuzIw7kRkM0ZdekqcnZ88Xib1EDSHcScimzDs0pJD1DlrVw7GnYjaxKhLSw5RBxwP+/EfOGuXAuNORFYx6tKSS9RJmRx6KJadnY3IyEj4+PggNjYWe/fubXP9ixcvIiUlBd26dYPRaMS1116LnJwchwZMRO71s3cvhl0ixRevMf/ICWftymP3zH3Dhg1ITU3FqlWrEBsbi6ysLCQmJuLIkSMICQlpsX5tbS1uu+02hISE4KOPPkL37t1x6tQpdOnSxRXjJyIXYdA9S24BJ3WxO+6ZmZmYMWMGkpOTAQCrVq3Cli1bsGbNGsydO7fF+mvWrMH58+exZ88eeHt7AwAiIyOdGzURuRTD7l5KDjln7cpk17VWW1uLwsJCJCQkXDkDLy8kJCSgoKDA6mk2b96MuLg4pKSkIDQ0FEOGDMGSJUvQ0NDQ6nZqampQXl5u8UNErsdD8K7X/NC6HA+x24NhVy67Zu6lpaVoaGhAaGioxfLQ0FAcPnzY6mlOnDiB7du3Y/LkycjJycGxY8cwc+ZM1NXVIT093eppMjIysGjRInuGRkR2YtSdp+Rwt0epb3urDL0Wus6dnTuPykoXjUY6bn+1fGNjI0JCQvDmm29Cr9cjOjoaP/30E1588cVW456WlobU1FTz7+Xl5YiIiHD3UIk0gVF3nJpj3pxSw05X2BX3oKAg6PV6mEwmi+UmkwlhYWFWT9OtWzd4e3tDr9eblw0cOBAlJSWora2FwWBocRqj0Qij0WjP0IjIBgy7fbQS8+acDTsPycuDXdeiwWBAdHQ08vLyzMsaGxuRl5eHuLg4q6e54YYbcOzYMTQ2NpqXHT16FN26dbMadiJyPT63bhu1PFfuKM7Y1cPuazI1NRWrV6/GO++8g0OHDuHRRx9FVVWV+dXzU6dORVpamnn9Rx99FOfPn8fjjz+Oo0ePYsuWLViyZAlSUlJcdymIqFWMeuu0HvPmGHZ1sfs594kTJ+LcuXNYsGABSkpKEBUVhdzcXPOL7E6fPg0vrys3koiICGzduhWzZ8/GsGHD0L17dzz++OOYM2eO6y4FEVnFsLek9Yhbw7Crj0MvqJs1axZmzZpl9d/y8/NbLIuLi8OXX37pyKaIyAGMekuMunWuDDufb5cPfrY8kcow7Fcw6G3jjF29GHciFWHYL2PU28ewqxvjTqQCjDqDbg+GXf0YdyIFY9QZdXu5K+x8vl1eGHcihdJ62Bl1+zHs2sG4EymQVsPOoDuOh+K1hXEnUhgthp1Rd447w85Zuzwx7kQKocWoAwy7sxh2bWLciRRAi2Fn1J3HQ/HaxbgTyZzWws6oKwNn7fLGuBPJGMNOjnD3jJ1hlz/GnUimtBR2Rt11eCieAMadSJYYdrIXo07NMe5EMqOVsDPqrsGokzW8VRDJCMNO9mDYqTWcuRPJBMNOtmLUqT28hRDJAMNOtpI67HylvDJw5k4kMYadbCF11AGGXUkYdyIJaSHsjLrzGHayl/S3GCKNYtjJFnIIOykPZ+5EHqaFqAMMu7PkFHXO2pVHPrceIg1g2MkWDDs5Sz63ICKVY9jJFgw7uQIPyxN5AMNO7ZFT1En5GHciN2PYqTVyDjpn7crGuBO5EcNO1sg56qQOvIURkVMYdtud+NlLEWHnrN1+2dnZiIyMhI+PD2JjY7F3715JxyP/WxmRQmlh1s6w20YpUQcYdkds2LABqampSE9Px759+zB8+HAkJibi7Nmzko1JGbc2IoVh2AlQVtQBhv1q5eXlFj81NTVW18vMzMSMGTOQnJyMQYMGYdWqVfD19cWaNWs8POIr+Jw7kYsx7KSkoDdRS9h/8e6JCm8/p86j0rsCABAREWGxPD09HQsXLrRYVltbi8LCQqSlpZmXeXl5ISEhAQUFBU6NwxmMO5ELaSHs1DolRp1ad+bMGfj7+5t/NxqNLdYpLS1FQ0MDQkNDLZaHhobi8OHDbh9jaxh3IhfRStg5a7eOYVcff39/i7grCW+NRGQzht06hl27goKCoNfrYTKZLJabTCaEhYVJNCrGncgltDJrJ0tKe8EcuZ7BYEB0dDTy8vLMyxobG5GXl4e4uDjJxsXD8kRO0krYOWu3xKhTk9TUVCQlJSEmJgYjR45EVlYWqqqqkJycLNmYGHciIjuoMepqeaW8VCZOnIhz585hwYIFKCkpQVRUFHJzc1u8yM6TGHciJ3DWri1qDDu5xqxZszBr1iyph2HGuBM5iGHXDkadlIZxJ3KAVsKudYw6KRVvuUR20lLYtTxrZ9hJyXjrJbKDlsKuZQw7KR1vwUQ20lrYtTpr11rY+Up5ddLWrZjIQQy7Nmgt7KRevCUTtUNrYdcqLYads3b10t6tmcgOWgy7FmftDDupjfZu0UQ20mLYtYhhJzXi+9yJyExLs3YtRh1g2LVCm7duonZw1q5uWg07aQdv4URX0WrYtTRrJ1I7xp2INIWzdtIC3sqJmtHqrJ20o2//AKmHQB7AuBP9l5bDzkPy2sLAqx/jTkSawUPypBV8KxwRtD1rJ23q2z/ApW+La+towKVqncu2Q7Zh3ImINMqZwPPQvrzxGBVpntZn7Vp5vp2H5K1zJNIMu/zx1k5ERKQyjDtpmtZn7USAfTNxztqVgXEnItXjIfn2Mdrqwls8aRZn7dp5vp1cgw8AlINxJ01i2IlaYrzVg3EnIlXjIXn7tBZ4hl9ZeKsnzeGsnYjUzqG4Z2dnIzIyEj4+PoiNjcXevXttOt369euh0+kwYcIERzZL5DSG/Qo+306tuXqWzlm78tgd9w0bNiA1NRXp6enYt28fhg8fjsTERJw9e7bN0xUXF+PJJ59EfHy8w4MlcgbDTmQ7Bl3Z7I57ZmYmZsyYgeTkZAwaNAirVq2Cr68v1qxZ0+ppGhoaMHnyZCxatAh9+vRpdxs1NTUoLy+3+CFyBsOuTXy+3XmMvDLZ9dnytbW1KCwsRFpamnmZl5cXEhISUFBQ0OrpnnvuOYSEhGD69OnYtWtXu9vJyMjAokWL7BkaUasYdiLHKDHspy8Gwrfe36nzqK5U/teu2PWwtrS0FA0NDQgNDbVYHhoaipKSEqun2b17N95++22sXr3a5u2kpaWhrKzM/HPmzBl7hklEBADoE94o9RCIJOHWhycVFRWYMmUKVq9ejaCgIJtPZzQaYTQa3Tgy0grO2olIi+yKe1BQEPR6PUwmk8Vyk8mEsLCwFusfP34cxcXFGD9+vHlZY+PlR9IdOnTAkSNH0LdvX0fGTURERK2w67C8wWBAdHQ08vLyzMsaGxuRl5eHuLi4FusPGDAA3377LYqKisw/d911F26++WYUFRUhIiLC+UtA1ArO2olIq+w+LJ+amoqkpCTExMRg5MiRyMrKQlVVFZKTkwEAU6dORffu3ZGRkQEfHx8MGTLE4vRdunQBgBbLiYjcoU94I181T5pjd9wnTpyIc+fOYcGCBSgpKUFUVBRyc3PNL7I7ffo0vLz4h0TS4qydiLTMoRfUzZo1C7NmzbL6b/n5+W2edt26dY5skoiIiGzEKTapDmftdDW+JY60hnEnIiJSGcadVIWzdiIixp1UhGGntvDQPGkJ405ERG4VGcYHVp7GuJMqcNZOJE88YiINxp2INIOh8Zw+4Y3c3xJi3EnxOGsnkhdGXXqMOxERkcow7qRonLUTyQtn7fLAuBORpjA+7sN9Kx+MOykWZ+3kKEbI9bhP5YVxJ9KoyC7npR4CEbkJ405EmsS3arkO96P8MO6kSDwk7xqcvTNMzuL+kyfGnYg0j4FyDPebfDHuRERgqOzF/SVvjDspDg/JuxYPzV/BYNmG+0n+GHciomYYrrZx/ygD405EdBUGjJSOcSdF4SF59+Ch+ZYY+Ja4T5SDcSciagVjdgX3hbIw7qQYnLWTFBg17gMlYtyJCAAPzbdFy3HT8mVXMsadFIGzdpKaFiOnxcusFh2kHgARyUdkl/MovniN1MOQrabYnfhZvfMiBl0d1HsLJdXgrJ3kRo0B5BfpeFZNTQ2ioqKg0+lQVFRk8W/ffPMN4uPj4ePjg4iICCxfvtzu82fcSdYYdpIrNYVQTZdFKZ5++mmEh4e3WF5eXo7bb78dvXr1QmFhIV588UUsXLgQb775pl3nz8PyREQO6hPeqOhD9Ix628rLyy1+NxqNMBqNTp/vZ599hs8//xz/+Mc/8Nlnn1n82/vvv4/a2lqsWbMGBoMBgwcPRlFRETIzM/HQQw/ZvA3GnWSLs3Zp8Hl3+yjxeXg1R724xAs+vs5dF5eqL58+IiLCYnl6ejoWLlzo1HmbTCbMmDEDmzZtgq+vb4t/LygowI033giDwWBelpiYiGXLluHChQsIDAy0aTuMOxGRCzQPplxDr+aou8OZM2fg7+9v/t3ZWbsQAtOmTcMjjzyCmJgYFBcXt1inpKQEvXv3tlgWGhpq/jdb4y7PWyBpHmft0uJ73p3T9OI0ucRUTmNREn9/f4uf1uI+d+5c6HS6Nn8OHz6M1157DRUVFUhLS3P72DlzJyKreHjeNaSc0TPonvGXv/wF06ZNa3OdPn36YPv27SgoKGjxICEmJgaTJ0/GO++8g7CwMJhMJot/b/o9LCzM5jEx7kREHuLJ0Msp7D27XJB6CG4VHByM4ODgdtd79dVX8fzzz5t///nnn5GYmIgNGzYgNjYWABAXF4d58+ahrq4O3t7eAIBt27bhuuuus/mQPMC4kwzxkLx8cPbuPu2FXk5xdkZkl/OorJR6FPLQs2dPi987d+4MAOjbty969OgBAJg0aRIWLVqE6dOnY86cOfjuu++wYsUKvPLKK3Zti3EnojYx8O6nlpCT8wICAvD5558jJSUF0dHRCAoKwoIFC+x6GxzAuBORDRh4cgRfmNm2yMhICCFaLB82bBh27drl1Hnz1fJERORyDLu0GHeSFT7fLl+8syZSDsadiGzGwJMteDuRHuNORHbhHTeR/DHuJBs8JE+kfHzwJw+MOxHZjXfgZA1vF/LBuJMscNauPLwjp+Z4e5AXxp2IHMY7dAJ4O5Ajxp0kx1k7kXIx7PLEuBORU3jnrl287uWLcSdJcdauDryT1x5e5/LGuBORS/DOnkg+GHcichkGXht4Pcsf405ELsU7fiLpMe5E5HIMvHrxulUGxp2I3IIRIJIO405EbsPAqwuvT+Vg3InIrRgEdeD1qCyMO0mG73HXjsgu5xkHBeN1pzyMOxF5DCOhPLzOlKmD1AMgIm1pikXxxWskHgm1hVFXNs7cSRI8JE+Mh3zxulE+xp2IJMPn4uWH14c6MO5EJDkGRXp8oKUujDt5HA/JkzWMi3S439WHcSciWWFoPIcPqNTLobhnZ2cjMjISPj4+iI2Nxd69e1tdd/Xq1YiPj0dgYCACAwORkJDQ5vpERIyO+3H/qpvdcd+wYQNSU1ORnp6Offv2Yfjw4UhMTMTZs2etrp+fn48HHngAO3bsQEFBASIiInD77bfjp59+cnrwpDw8JE/2YIBcjw+ctMHuuGdmZmLGjBlITk7GoEGDsGrVKvj6+mLNmjVW13///fcxc+ZMREVFYcCAAXjrrbfQ2NiIvLy8VrdRU1OD8vJyix8i0ibGyDW4H7XFrg+xqa2tRWFhIdLS0szLvLy8kJCQgIKCApvOo7q6GnV1dbjmmtY/wCIjIwOLFi2yZ2hEpHKRXc7zg28cpKWonzxeBoOPcOo8ai8pf0Jp18y9tLQUDQ0NCA0NtVgeGhqKkpISm85jzpw5CA8PR0JCQqvrpKWloayszPxz5swZe4ZJRCrVNPvUUqycxX2lTR79+NmlS5di/fr1yM/Ph4+PT6vrGY1GGI1GD46MiJSGH2PbPoZdu+yKe1BQEPR6PUwmk8Vyk8mEsLCwNk/70ksvYenSpfjiiy8wbNgw+0dKRGRF84Ax9Jcx6mTXYXmDwYDo6GiLF8M1vTguLi6u1dMtX74cixcvRm5uLmJiYhwfLRFRG7R+yF7rl5+usPuwfGpqKpKSkhATE4ORI0ciKysLVVVVSE5OBgBMnToV3bt3R0ZGBgBg2bJlWLBgAT744ANERkaan5vv3LkzOnfu7MKLQkR0mZZm84w5WWN33CdOnIhz585hwYIFKCkpQVRUFHJzc80vsjt9+jS8vK4cEFi5ciVqa2vxxz/+0eJ80tPTsXDhQudGT0TUDjU+N8+gU3scekHdrFmzMGvWLKv/lp+fb/F7cXGxI5sgFeIH2JCUlB55Bp3s4dFXyxMRSe3qSMo59gw6OYpxJyJNay+gUsSfUSdnMe5ERG2wFlp7gs9QkxQYdyIiOzHYJHf8PnciIiKVYdzJI/hKeSIiz2HciYiIVIZxJyIiUhnGnYiISGUYdyIiIpVh3Mnt+GI6IiLPYtyJiIhUhnEnIiJSGcadiIhIZRh3IiIilWHciYiIVIZxJyIiUhnGnYiISGUYd3IrvsediMjzGHciIiKVYdyJiIhUhnEnIiJSGcadiIhIZRh3IiIilWHciYiIVIZxJ7fh2+CIiCwdPXoUd999N4KCguDv74/Ro0djx44dFuucPn0aY8eOha+vL0JCQvDUU0+hvr7eru0w7kRERB4ybtw41NfXY/v27SgsLMTw4cMxbtw4lJSUAAAaGhowduxY1NbWYs+ePXjnnXewbt06LFiwwK7tMO5EREQeUFpaih9++AFz587FsGHD0L9/fyxduhTV1dX47rvvAACff/45Dh48iL/97W+IiorCHXfcgcWLFyM7Oxu1tbU2b4txJyIisqK8vNzip6amxqnz69q1K6677jq8++67qKqqQn19Pf76178iJCQE0dHRAICCggIMHToUoaGh5tMlJiaivLwc33//vc3b6uDUSIlawefbiUgKxYd/grehzKnzqKutBABERERYLE9PT8fChQsdPl+dTocvvvgCEyZMgJ+fH7y8vBASEoLc3FwEBgYCAEpKSizCDsD8e9Ohe1tw5k5ERGTFmTNnUFZWZv5JS0uzut7cuXOh0+na/Dl8+DCEEEhJSUFISAh27dqFvXv3YsKECRg/fjx++eUXl46dM3ciIiIr/P394e/v3+56f/nLXzBt2rQ21+nTpw+2b9+OTz/9FBcuXDCf7xtvvIFt27bhnXfewdy5cxEWFoa9e/danNZkMgEAwsLCbB47405EROSE4OBgBAcHt7tedXU1AMDLy/KguZeXFxobGwEAcXFxeOGFF3D27FmEhIQAALZt2wZ/f38MGjTI5jHxsDwREZEHxMXFITAwEElJSThw4ACOHj2Kp556CidPnsTYsWMBALfffjsGDRqEKVOm4MCBA9i6dSueffZZpKSkwGg02rwtxp2IiMgDgoKCkJubi8rKStxyyy2IiYnB7t278X//938YPnw4AECv1+PTTz+FXq9HXFwc/vSnP2Hq1Kl47rnn7NoWD8uTy/GV8kRE1sXExGDr1q1trtOrVy/k5OQ4tR3O3ImIiFSGcSciIlIZxp2IiEhlGHciIiKVYdyJiIhUhnEnIiJSGcadiIhIZRh3IiIilWHcyaX4ATZERNJj3ImIiFRGc3HnzNJ9uG+JiORBc3En92DYiYjkQ1NxbwoQQ0RERGqmqbgTERFpgWbjztk7ERGplWbjTkREpFaajjtn764TXndK6iEQEdF/aTruREREasS4ExERqYxm4t7aIXgemiciIrXRTNyJiIi0gnEnIiJSGcYdPDRPRETqwrgTERGpDOP+X5y9ExGRWmgi7gw3ERFpiUNxz87ORmRkJHx8fBAbG4u9e/e2uf6HH36IAQMGwMfHB0OHDkVOTo5DgyX54gMoIiL5sDvuGzZsQGpqKtLT07Fv3z4MHz4ciYmJOHv2rNX19+zZgwceeADTp0/H/v37MWHCBEyYMAHfffed04N3NQaKiIjUwO64Z2ZmYsaMGUhOTsagQYOwatUq+Pr6Ys2aNVbXX7FiBf7nf/4HTz31FAYOHIjFixdjxIgReP31150evC0YbPfjPiYikpcO9qxcW1uLwsJCpKWlmZd5eXkhISEBBQUFVk9TUFCA1NRUi2WJiYnYtGlTq9upqalBTU2N+feysjIAQEVllT3DxS/ePYGaCrtOU1FXadf6WufIPiYibamqvHwfIYRw+7bqXXAf7orzkJpdcS8tLUVDQwNCQ0MtloeGhuLw4cNWT1NSUmJ1/ZKSkla3k5GRgUWLFrVY/rtbx9kzXCIikpFff/0VAQEBbjlvg8GAsLAw5G+83SXnFxYWBoPB4JLzkoJdcfeUtLQ0i9n+xYsX0atXL5w+fdptNww1KC8vR0REBM6cOQN/f3+phyNb3E/t4z6yDfeTbcrKytCzZ09cc801btuGj48PTp48idraWpecn8FggI+Pj0vOSwp2xT0oKAh6vR4mk8liuclkQlhYmNXThIWF2bU+ABiNRhiNxhbLAwIC+AdkA39/f+4nG3A/tY/7yDbcT7bx8nLvu699fHwUHWRXsmtPGwwGREdHIy8vz7yssbEReXl5iIuLs3qauLg4i/UBYNu2ba2uT0RERM6x+7B8amoqkpKSEBMTg5EjRyIrKwtVVVVITk4GAEydOhXdu3dHRkYGAODxxx/HmDFj8PLLL2Ps2LFYv349/vOf/+DNN9907SUhIiIiAA7EfeLEiTh37hwWLFiAkpISREVFITc31/yiudOnT1scehk1ahQ++OADPPvss3jmmWfQv39/bNq0CUOGDLF5m0ajEenp6VYP1dMV3E+24X5qH/eRbbifbMP95Hk64Yn3JhAREZHHaOKz5YmIiLSEcSciIlIZxp2IiEhlGHciIiKVYdyJiIhURjZx53fE28ae/bR69WrEx8cjMDAQgYGBSEhIaHe/qoG9t6Um69evh06nw4QJE9w7QJmwdz9dvHgRKSkp6NatG4xGI6699lpN/N3Zu5+ysrJw3XXXoWPHjoiIiMDs2bNx6dIlD41WGjt37sT48eMRHh4OnU7X5heDNcnPz8eIESNgNBrRr18/rFu3zu3j1BQhA+vXrxcGg0GsWbNGfP/992LGjBmiS5cuwmQyWV3/3//+t9Dr9WL58uXi4MGD4tlnnxXe3t7i22+/9fDIPcve/TRp0iSRnZ0t9u/fLw4dOiSmTZsmAgICxI8//ujhkXuOvfuoycmTJ0X37t1FfHy8uPvuuz0zWAnZu59qampETEyMuPPOO8Xu3bvFyZMnRX5+vigqKvLwyD3L3v30/vvvC6PRKN5//31x8uRJsXXrVtGtWzcxe/ZsD4/cs3JycsS8efPEP//5TwFAfPzxx22uf+LECeHr6ytSU1PFwYMHxWuvvSb0er3Izc31zIA1QBZxHzlypEhJSTH/3tDQIMLDw0VGRobV9e+77z4xduxYi2WxsbHi4Ycfdus4pWbvfrpafX298PPzE++88467hig5R/ZRfX29GDVqlHjrrbdEUlKSJuJu735auXKl6NOnj6itrfXUEGXB3v2UkpIibrnlFotlqamp4oYbbnDrOOXElrg//fTTYvDgwRbLJk6cKBITE904Mm2R/LB803fEJyQkmJfZ8h3xzdcHLn9HfGvrq4Ej++lq1dXVqKurc+s3M0nJ0X303HPPISQkBNOnT/fEMCXnyH7avHkz4uLikJKSgtDQUAwZMgRLlixBQ0ODp4btcY7sp1GjRqGwsNB86P7EiRPIycnBnXfe6ZExK4UW78M9TfKvfPXUd8QrnSP76Wpz5sxBeHh4iz8qtXBkH+3evRtvv/02ioqKPDBCeXBkP504cQLbt2/H5MmTkZOTg2PHjmHmzJmoq6tDenq6J4btcY7sp0mTJqG0tBSjR4+GEAL19fV45JFH8Mwzz3hiyIrR2n14eXk5fvvtN3Ts2FGikamH5DN38oylS5di/fr1+Pjjj/mViP9VUVGBKVOmYPXq1QgKCpJ6OLLW2NiIkJAQvPnmm4iOjsbEiRMxb948rFq1SuqhyUp+fj6WLFmCN954A/v27cM///lPbNmyBYsXL5Z6aKQxks/cPfUd8UrnyH5q8tJLL2Hp0qX44osvMGzYMHcOU1L27qPjx4+juLgY48ePNy9rbGwEAHTo0AFHjhxB37593TtoCThyW+rWrRu8vb2h1+vNywYOHIiSkhLU1tbCYDC4dcxScGQ/zZ8/H1OmTMGDDz4IABg6dCiqqqrw0EMPYd68eW7/PnOlaO0+3N/fn7N2F5H8lsbviLeNI/sJAJYvX47FixcjNzcXMTExnhiqZOzdRwMGDMC3336LoqIi889dd92Fm2++GUVFRYiIiPDk8D3GkdvSDTfcgGPHjpkf/ADA0aNH0a1bN1WGHXBsP1VXV7cIeNMDIsHv6DLT4n24x0n9ij4hLr/dxGg0inXr1omDBw+Khx56SHTp0kWUlJQIIYSYMmWKmDt3rnn9f//736JDhw7ipZdeEocOHRLp6emaeSucPftp6dKlwmAwiI8++kj88ssv5p+KigqpLoLb2buPrqaVV8vbu59Onz4t/Pz8xKxZs8SRI0fEp59+KkJCQsTzzz8v1UXwCHv3U3p6uvDz8xN///vfxYkTJ8Tnn38u+vbtK+677z6pLoJHVFRUiP3794v9+/cLACIzM1Ps379fnDp1SgghxNy5c8WUKVPM6ze9Fe6pp54Shw4dEtnZ2XwrnIvJIu5CCPHaa6+Jnj17CoPBIEaOHCm+/PJL87+NGTNGJCUlWay/ceNGce211wqDwSAGDx4stmzZ4uERS8Oe/dSrVy8BoMVPenq65wfuQfbelprTStyFsH8/7dmzR8TGxgqj0Sj69OkjXnjhBVFfX+/hUXuePfuprq5OLFy4UPTt21f4+PiIiIgIMXPmTHHhwgXPD9yDduzYYfW+pmnfJCUliTFjxrQ4TVRUlDAYDKJPnz5i7dq1Hh+3mvH73ImIiFRG8ufciYiIyLUYdyIiIpVh3ImIiFSGcSciIlIZxp2IiEhlGHciIiKVYdyJiIhUhnEnIiJSGcadiIhIZRh3IiIilWHciYiIVOb/A3sz9ITkC8P7AAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# we want to compute the derivative at the \"wrong\" initial condition T_target\n", + "# so we first rerun the forward model with that value for the control\n", + "Jhat(T_target)\n", + "\n", + "# ask for L2 Riesz representation to get grid-independent result\n", + "gradJ = Jhat.derivative(options={\"riesz_representation\": \"L2\"})\n", + "\n", + "fig, ax = plt.subplots()\n", + "levels = np.linspace(-100, 100, 11)\n", + "from matplotlib import colors\n", + "cmap = plt.cm.coolwarm\n", + "with stop_annotating():\n", + " c = tricontourf(gradJ, axes=ax, levels=levels, norm=colors.CenteredNorm(), cmap=cmap)\n", + "ax.set_title('Derivative wrt Initial Temperature')\n", + "ax.set_aspect('equal')\n", + "fig.colorbar(c)" + ] + }, + { + "cell_type": "markdown", + "id": "b2780a32-23ab-4970-8a5c-39533bdd4758", + "metadata": {}, + "source": [ + "## Invert for Optimal Initial Condition Using Gradient-Based Optimisation Algorithm\n", + "We now have all the ingredients:\n", + "- the ability to rerun and re-evaluate the functional for arbitrary input control values,\n", + "- compute the derivative of the functional with respect to that control,\n", + "that are needed to perform an inversion for the initial condition using a gradient based optimisation algorithm.\n", + "\n", + "To keep things simple, we here use the \"L-BFGS-B\" algorithm as it is implemented in scipy. The `minimize()` function that is exported by `gadopt.inverse` provides a wrapper around [scipy's minimize](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html) to translate between G-ADOPT/Firedrake objects and numpy arrays. G-ADOPT also provides an interface to the [ROL optimisation library](https://trilinos.github.io/) library, which we generally recommend over the scipy interface." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9dec8e63-9b11-4bad-a4f7-7be1497a7f46", + "metadata": {}, + "outputs": [], + "source": [ + "# the L-BFGS-B allows for \"box constraints\", min and max values for the control\n", + "# which we can provide as functions in the same functionspace as the control\n", + "Tmin = Function(Q) # Tmin is not initialised, so remains as a zero lower bound for the control\n", + "Tmax = Function(Q)\n", + "Tmax.assign(1) # upper bound of 1\n", + "\n", + "# select L-BFGS-B as the method and provide bounds\n", + "# the tolerance is an absolute tolerance on the norm of the gradient which should be reduced to near zero\n", + "# minimize() returns the found optimal control, i.e. best fit initial condition\n", + "T_opt = minimize(Jhat, method='L-BFGS-B', bounds=[Tmin, Tmax], tol=1e-5)" + ] + }, + { + "cell_type": "markdown", + "id": "c11f1f2d-29c5-4bcd-9ed9-5a97501e6331", + "metadata": {}, + "source": [ + "Let's see how well we have done:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35689694-ac2d-472d-b440-b08c4c0af691", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(1,2)\n", + "plot_temp(T_opt, 'Optimal Initial Condition', Tmax=1, ax=ax[0], colorbar=False)\n", + "plot_temp(T0, 'Initial Condition from Twin', Tmax=1, ax=ax[1])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1bcb2a32-77a7-4b8c-94d3-7964be6abb7a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/09-GD-2D-pde-constrained2.ipynb b/09-GD-2D-pde-constrained2.ipynb new file mode 100644 index 0000000..367e2d7 --- /dev/null +++ b/09-GD-2D-pde-constrained2.ipynb @@ -0,0 +1,512 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b43078aa-e572-4818-83a3-2901497d9c21", + "metadata": {}, + "source": [ + "# PDE Constrained Optimisation with G-ADOPT\n", + "## Example: Inversion for Initial Condition with Given Voundary Values\n", + "\n", + "In this second example of the inversion functionality with G-ADOPT/Firedrake, we will invert for an initial condition to match given time-dependent boundary values." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "2a4ba5bf-69c1-4649-ae30-a9e4d4f96cf1", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "# Load Firedrake on Colab\n", + "try:\n", + " import firedrake\n", + "except ImportError:\n", + " !wget \"https://github.com/g-adopt/tutorials/releases/latest/download/firedrake-install-real.sh\" -O \"/tmp/firedrake-install.sh\" && bash \"/tmp/firedrake-install.sh\"\n", + " import firedrake\n", + "from gadopt import *\n", + "from gadopt.inverse import *" + ] + }, + { + "cell_type": "markdown", + "id": "456dd6dd-6575-467a-9a3f-df37f7821c72", + "metadata": {}, + "source": [ + "## Create Synthetic Twin Experiment and Record Solution at all Timesteps\n", + "Setup is nearly the same as in our first example, except the velocity is now counter clock wise around the origin $(0,0)$ in the corner of the unit square domain. This also means that we now have an inflow at the bottom boundary and an outflow boundary at the left of the domain." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "093bd2b5-d76f-48be-aebb-fe042fac56a3", + "metadata": {}, + "outputs": [], + "source": [ + "mesh = UnitSquareMesh(20, 20)\n", + "left, right, bottom, top = 1, 2, 3, 4 # Boundary IDs\n", + "\n", + "V = VectorFunctionSpace(mesh, \"CG\", 2)\n", + "Q = FunctionSpace(mesh, \"CG\", 1)\n", + "T = Function(Q, name='Temperature')\n", + "\n", + "x, y = SpatialCoordinate(mesh)\n", + "u = interpolate(as_vector((-y, x)), V)\n", + "u.rename('Velocity')\n", + "\n", + "approximation = BoussinesqApproximation(Ra=1, kappa=5e-2)\n", + "# specify a zero Dirichlet for the bottom inflow boundaries\n", + "temp_bcs = {\n", + " bottom: {'T': 0},\n", + "}\n", + "delta_t = .1\n", + "energy_solver = EnergySolver(T, u, approximation, delta_t, ImplicitMidpoint, bcs=temp_bcs)" + ] + }, + { + "cell_type": "markdown", + "id": "8fe333dc-cf95-4f76-8588-434601058f06", + "metadata": {}, + "source": [ + "The initial condition that we, again, later will invert for, is now centered in the domain." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "51499bd4-2523-4128-aa7f-a9dde4ea7b7e", + "metadata": {}, + "outputs": [], + "source": [ + "x0, y0 = 0.5, 0.5\n", + "w = .2\n", + "r2 = (x-x0)**2 + (y-y0)**2\n", + "T.interpolate(exp(-r2/w**2));" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "6f0355a8-a2ee-4fa5-8f30-1ac4dc1f2d3f", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAfEAAAGzCAYAAAA/oi4aAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA3u0lEQVR4nO3dfXRU9YH/8U8SyAQIgVggARqJyCoqCgqSRctS11QsSpe2nuJDIXAU1xY9lfhEREkQJawKsisoFUWs1YJ11eOvsFhNZa2FXSoPXa0Kq4BQbAJUSDBAAsn9/eFmzORx7sx9+s68X+fkjwx3Mt9cYN7z/d57Z1Isy7IEAACMk+r3AAAAQGyIOAAAhiLiAAAYiogDAGAoIg4AgKGIOAAAhiLiAAAYiogDAGAoIg4AgKGIOBJCSkqKysrKoto2Pz9f06ZNs/0Ye/bsUUpKilatWmX7vkGwYcMGpaSkaMOGDeHbpk2bpvz8/KjuX1ZWppSUFHcGByAmRByBsGrVKqWkpOi9995z5Odt3LhRZWVlOnLkiCM/LxZVVVW68847NXToUHXv3l09evTQyJEj9eCDD/o6ro4cO3ZMZWVlEaEHEFxd/B4A4ITjx4+rS5ev/zlv3LhR8+bN07Rp09S7d++IbXfs2KHUVHdfv/7xj3/UhAkT9OWXX+rHP/6xRo4cKUl67733tHDhQr3zzjv67W9/6+oYorFixQo1NjaGvz927JjmzZsnSfr2t78dse19992n2bNnezk8AJ0g4kgIGRkZUW8bCoVcHIl05MgRff/731daWpq2bdumoUOHRvz5Qw89pBUrVrg6hmh17do16m27dOkS8UIJgP9YTkdgTZs2TZmZmdq/f78mTZqkzMxM9e3bV3feeacaGhoitm1+TLysrEx33XWXJOmMM85QSkqKUlJStGfPHkmtj4l/8cUXuvPOO3X++ecrMzNTWVlZ+u53v6s//elPMY375z//ufbv36/Fixe3Crgk5eTk6L777ou47YknntB5552nUCikAQMGaObMma2W3L/97W9r2LBh+vDDD3XZZZepe/fuGjhwoB5++OFWj/GXv/xFkyZNUo8ePdSvXz/NmjVLdXV1rbZrfkx8z5496tu3ryRp3rx54f3WfL+2PCZ+6tQpzZ8/X2eeeaZCoZDy8/N17733tnqs/Px8XX311Xr33Xc1evRoZWRkaPDgwfrFL37R4b4E0DEijkBraGjQ+PHj9Y1vfEOPPvqoxo0bp0WLFumpp55q9z4/+MEPdN1110mSHnvsMT3//PN6/vnnw4FqadeuXXrttdd09dVXa/Hixbrrrrv0/vvva9y4cfr8889tj/n1119Xt27ddM0110S1fVlZmWbOnKkBAwZo0aJF+uEPf6if//znuuKKK3Ty5MmIbQ8fPqwrr7xSw4cP16JFizR06FDdc889+o//+I/wNsePH9fll1+uN954Q7feeqvmzJmj3//+97r77rs7HEffvn315JNPSpK+//3vh/fbD37wg3bvc9NNN2nu3Lm66KKL9Nhjj2ncuHEqLy/Xtdde22rbTz75RNdcc42+853vaNGiRcrOzta0adP05z//Oar9BKANFhAAzz77rCXJ+uMf/xi+raioyJJkPfDAAxHbXnjhhdbIkSMjbpNklZaWhr9/5JFHLEnW7t27Wz3WoEGDrKKiovD3J06csBoaGiK22b17txUKhSIee/fu3ZYk69lnn+3wd8nOzraGDx/e4TZNDhw4YKWnp1tXXHFFxBiWLl1qSbJWrlwZvm3cuHGWJOsXv/hF+La6ujorNzfX+uEPfxi+bcmSJZYk66WXXgrfVltbaw0ZMsSSZL399tvh24uKiqxBgwaFvz948GCrfdmktLTUav6UsX37dkuSddNNN0Vsd+edd1qSrN/97nfh2wYNGmRJst55552I3z0UCll33HFHJ3sJQHuYiSPwbrnllojvx44dq127djn280OhUPhEt4aGBv3tb39TZmamzj77bG3dutX2z6upqVHPnj2j2vatt95SfX29br/99oiT7WbMmKGsrCytXbs2YvvMzEz9+Mc/Dn+fnp6u0aNHR+yPdevWqX///hErAd27d9fNN99s+3fpyLp16yRJxcXFEbffcccdktRq7Oeee67Gjh0b/r5v3746++yzHf27BJINEUegZWRktFoGz87O1uHDhx17jMbGRj322GP6u7/7O4VCIfXp00d9+/bV//zP/6i6utr2z8vKytLRo0ej2vazzz6TJJ199tkRt6enp2vw4MHhP2/yzW9+s9Vx6Zb747PPPtOQIUNabdfyMeL12WefKTU1VUOGDIm4PTc3V71792419tNPP73Vz3D67xJINkQcgZaWlub6YyxYsEDFxcX6h3/4B/3yl7/UG2+8oTfffFPnnXdexOVX0Ro6dKh27typ+vp6x8fa3v6wLMvxx4pWtG8AE8SxA6Yj4khIdt5Z7OWXX9Zll12mZ555Rtdee62uuOIKFRYWxvyGLBMnTtTx48f17//+751uO2jQIElfXbveXH19vXbv3h3+czsGDRqkTz/9tFUcWz5GW+zst0GDBqmxsVH/+7//G3F7VVWVjhw5EtPYAdhDxJGQevToIUlRhTgtLa1V8H79619r//79MT32Lbfcov79++uOO+7Qzp07W/35gQMH9OCDD0qSCgsLlZ6ern/7t3+LGMMzzzyj6upqXXXVVbYff8KECfr888/18ssvh287duxYh2f0N+nevbuk6PbbhAkTJElLliyJuH3x4sWSFNPYAdjDOzcgITW9Q9qcOXN07bXXqmvXrpo4cWI47s1dffXVeuCBBzR9+nRdcsklev/99/XCCy9o8ODBMT12dna2Xn31VU2YMEEjRoyIeMe2rVu36le/+pXGjBkj6auTu0pKSjRv3jxdeeWV+t73vqcdO3boiSee0MUXXxxxElu0ZsyYoaVLl2rq1KnasmWL+vfvr+effz4c6I5069ZN5557rtasWaOzzjpLp512moYNG6Zhw4a12nb48OEqKirSU089pSNHjmjcuHHavHmznnvuOU2aNEmXXXaZ7bEDsIeIIyFdfPHFmj9/vpYvX67169ersbFRu3fvbjPi9957r2pra/Xiiy9qzZo1uuiii7R27dq43mK0oKBAH3zwgR555BGtXbtWzz//vFJTU3XOOedo9uzZuvXWW8PblpWVqW/fvlq6dKlmzZql0047TTfffLMWLFhg6x3VmnTv3l0VFRW67bbb9Pjjj6t79+664YYb9N3vfldXXnllp/d/+umnddttt2nWrFmqr69XaWlpmxFv2nbw4MFatWqVXn31VeXm5qqkpESlpaW2xw3AvhSLs0oAADASx8QBADAUEQcAwFBEHAAAQ9mO+DvvvKOJEydqwIABSklJ0WuvvdbpfTZs2KCLLrpIoVBIQ4YM0apVq2IYKgAAweRXG21HvLa2VsOHD9eyZcui2n737t266qqrdNlll2n79u26/fbbddNNN+mNN96wPVgAAILIrzbGdXZ6SkqKXn31VU2aNKndbe655x6tXbtWH3zwQfi2a6+9VkeOHNH69etjfWgAAALJyza6fp34pk2bVFhYGHHb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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "def plot_temp(T, title=None, Tmax=1, ax=None, colorbar=True):\n", + " if ax is None:\n", + " fig, ax = plt.subplots()\n", + " else:\n", + " fig = ax.get_figure()\n", + " levels = np.linspace(0, Tmax, 11)\n", + " with stop_annotating():\n", + " c = tricontourf(T, axes=ax, levels=levels)\n", + " ax.set_title(title)\n", + " ax.set_aspect('equal')\n", + " if colorbar:\n", + " cax = fig.add_axes([ax.get_position().x1+0.05,ax.get_position().y0,0.02,ax.get_position().y1-ax.get_position().y0])\n", + " fig.colorbar(c, cax=cax)\n", + "plot_temp(T, 'Initial Condition', Tmax=1)" + ] + }, + { + "cell_type": "markdown", + "id": "779244bd-3913-43ac-98a3-ffd34caf7a06", + "metadata": {}, + "source": [ + "We run the model for twenty timesteps to ensure the entire Gaussian has left the domain. In this twin model we now checkpoint the solution at every timestep, so that we can later use it as the target boundary values." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "56f8a2d4-6174-4153-917a-ff5dd4daeaeb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n", + " Linear ImplicitMidpoint-EnergyEquation_stage0_ solve converged due to CONVERGED_ITS iterations 1\n" + ] + } + ], + "source": [ + "with CheckpointFile('series.h5', 'w') as f:\n", + " f.save_mesh(mesh)\n", + " for i in range(20):\n", + " f.save_function(T, idx=i)\n", + " energy_solver.solve()\n", + " # after saving idx=0, 19 at beginning of each timestep\n", + " # we include idx=20 for the solution at the end of the final timestep\n", + " f.save_function(T, idx=i)" + ] + }, + { + "cell_type": "markdown", + "id": "adffcf39-a407-457c-9fb6-b044add99e62", + "metadata": {}, + "source": [ + "As expected the solution has completely disappeared:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "cda4c1fd-e722-4626-b182-19a85d2ae2d5", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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zJgxOn36tObOnavKykqlp6dr+/bt/ifzjx8/rujov/1u4Ha7tWPHDs2cOVMDBgxQjx499Oyzz2rWrFlOpwYAoM1y2se6ujpNnTpVH3/8sdq3b69+/frpV7/6lcaMGRP0nI7fJx4JvE8cAOzVVt4n/rVfznfw6vSL+ni6J2JrDhafnQ4AgKWIOAAAliLiAABYiogDAGApIg4AgKWIOAAAliLiAABYiogDAGApIg4AgKWIOAAAliLiAABYiogDAGApIg4AgKWIOAAAliLiAABYiogDAGApIg4AgKWIOAAAliLiAABYiogDAGApIg4AgKWIOAAAliLiAABYiogDAGApIg4AgKWIOAAAliLiAABYiogDAGApIg4AgKViI70AAADCIa6qnWLi2wU1tvFiYyuv5vrgnjgAAJYi4gAAWIqIAwBgKSIOAICliDgAAJYi4gAAWIqIAwBgKSIOAICliDgAAJYi4gAAWIqIAwBgKSIOAICliDgAAJYi4gAAWIqIAwBgKSIOAICliDgAAJYi4gAAWIqIAwBgKSIOAICliDgAAJYi4gAAWIqIAwBgKSIOAICliDgAAJYi4gAAWIqIAwBgKSIOAICliDgAAJYi4gAAWIqIAwBgKSIOAICliDgAAJYKKeJFRUVKS0tTfHy8MjMztXv37qDO27x5s6KiojR69OhQpgUAoE1z0sfVq1dr2LBhSk5OVnJysrKzs4Pu6WWOI75lyxbl5eXJ4/GorKxMAwcOVE5Ojk6dOnXF844eParnnntOw4YNczolAABtntM+lpSU6PHHH9c777yj0tJSud1uPfzwwzp58mTQczqO+NKlSzVlyhRNnDhRd955p1auXKmbbrpJa9eubfGcxsZGjRs3TvPnz1evXr2uOkd9fb1qa2sDLgAAhNuXW1RfX9/iWKd93Lhxo6ZOnar09HT169dPL7/8snw+n4qLi4Nen6OIe71e7dmzR9nZ2X+7guhoZWdnq7S0tMXzFixYoK5du2rSpElBzVNQUKCkpCT/xe12O1kmAABN3HRKuqkyyMtf7zy73e6AHhUUFDR73aH28e9duHBBly5d0s033xz0bYoNeqSk6upqNTY2KiUlJeB4SkqKDh482Ow57777rtasWaPy8vKg58nPz1deXp7/59raWkIOAAi7EydOKDEx0f+zy+VqdlwoffyyWbNmqXv37gG/CFyN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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_temp(T, 'Final State', Tmax=.5)" + ] + }, + { + "cell_type": "markdown", + "id": "0a89dd4e-9b20-4030-876e-86474888ccfa", + "metadata": {}, + "source": [ + "## Advection Diffusion Model with Unknown Initial Condition\n", + "We now again set up the model where we do not know the initial condition, where we are now trying to find the optimal initial condition such that we closely match the recored outflow boundary values." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "50df4864-c4aa-4671-abb7-6676d231d689", + "metadata": {}, + "outputs": [], + "source": [ + "with CheckpointFile('series.h5', 'r') as f:\n", + " mesh = f.load_mesh()" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "9743b4cc-343b-4506-b501-ac4d22388d98", + "metadata": {}, + "outputs": [], + "source": [ + "V = VectorFunctionSpace(mesh, \"CG\", 2)\n", + "Q = FunctionSpace(mesh, \"CG\", 1)\n", + "T = Function(Q, name='Temperature')\n", + "\n", + "x, y = SpatialCoordinate(mesh)\n", + "u = interpolate(as_vector((-y, x)), V)\n", + "u.rename('Velocity')\n", + "\n", + "approximation = BoussinesqApproximation(Ra=1, kappa=5e-2)\n", + "temp_bcs = {\n", + " bottom: {'T': 0},\n", + "}\n", + "delta_t = .1\n", + "energy_solver = EnergySolver(T, u, approximation, delta_t, ImplicitMidpoint, bcs=temp_bcs)\n", + "# make it a bit quieter:\n", + "energy_solver.solver_parameters.pop('ksp_converged_reason')" + ] + }, + { + "cell_type": "markdown", + "id": "da09fbc8-0c26-44fd-9613-c3e0cce0c6eb", + "metadata": {}, + "source": [ + "As a first guess we use a Gaussian that is in the wrong place: centred around $(0.7, 0.7)$ instead of $(0.5, 0.5)$:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "b2c12b95-6caf-4406-b1cc-3426c08260f8", + "metadata": {}, + "outputs": [], + "source": [ + "x0, y0 = 0.7, 0.7\n", + "w = .2\n", + "r2 = (x-x0)**2 + (y-y0)**2\n", + "Twrong = interpolate(exp(-r2/w**2), Q)" + ] + }, + { + "cell_type": "markdown", + "id": "e996c56d-ec4f-4c90-9d71-264d748f8f44", + "metadata": {}, + "source": [ + "As in our first example, we make sure to clear the tape before our actual model starts and specify the control at the right stage. During the model we load back in the solutions from the twin model, but only use its values at the boundary to compute a mismatch with the current model as an integral over the left boundary. Note that we start calculating the functional already in the first timestep, and we keep on adding terms to it, all of this will still be automatically recorded by the pyadjoint tape." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "d13ea66e-12d7-4a76-a2b9-588a95ec4b7e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.0638596121236412\n" + ] + } + ], + "source": [ + "tape = get_working_tape()\n", + "tape.clear_tape()\n", + "\n", + "T.interpolate(Twrong)\n", + "\n", + "# we want to vary the _initial_ (current) state of T\n", + "# here we specify the current state of T as the control\n", + "m = Control(T)\n", + "\n", + "J = AdjFloat(0.0)\n", + "factor = AdjFloat(0.5) # first and final boundary integral is weighted by 0.5\n", + "# to implement mid-point rule time-integration\n", + "\n", + "with CheckpointFile('series.h5', 'r') as f:\n", + " for i in range(20):\n", + " T_target = f.load_function(mesh, 'Temperature', idx=i)\n", + " J = J + factor * assemble((T-T_target)**2*ds(left))\n", + " factor = 1.0 # remaing timesteps weighted by 1\n", + " energy_solver.solve()\n", + " \n", + " T_target = f.load_function(mesh, 'Temperature', idx=i)\n", + " # add final contribution weighted again by 0.5\n", + " J = J + factor * assemble((T-T_target)**2*ds(left))\n", + "\n", + "print(J)" + ] + }, + { + "cell_type": "markdown", + "id": "717cd9c2-2ab5-4dd0-865e-659259f32141", + "metadata": {}, + "source": [ + "We define the reduced functional using the final value of `J` and the specified control. This allows us to rerun the model with arbitrary initial condition. Again we first try to simply rerun the model with the same \"wrong\" initial condition." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "69a3038a-df24-4fea-aa3b-dcb457dd4ec6", + "metadata": {}, + "outputs": [], + "source": [ + "Jhat = ReducedFunctional(J, m)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "48fa1503-559c-4a8a-a6bb-0718023635bb", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0.06385919930808436" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Jhat(Twrong)" + ] + }, + { + "cell_type": "markdown", + "id": "9a466fb5-fd62-48f5-8664-2c6dcd074c86", + "metadata": {}, + "source": [ + "Now try to rerun the model with \"correct\" initial condition from the twin experiment, and we see that indeed we end up with a near-zero misfit." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "e9acd308-4642-4d06-a501-47066b340308", + "metadata": {}, + "outputs": [], + "source": [ + "x0, y0 = 0.5, 0.5\n", + "w = .2\n", + "r2 = (x-x0)**2 + (y-y0)**2\n", + "T0 = interpolate(exp(-r2/w**2), Q)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "accde8c0-ab9f-4c27-b317-58fc5046ffc7", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1.481456131569618e-05" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Jhat(T0)" + ] + }, + { + "cell_type": "markdown", + "id": "1e7c9c49-21e1-4319-a25b-6be6e69eba11", + "metadata": {}, + "source": [ + "We can again look at the gradient, but this time the gradient is a lot less intuitive." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "f38da06a-060c-4cf8-b9fd-721a2938be9e", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAgQAAAGzCAYAAABQJQ/GAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAACETUlEQVR4nO2dd3xUVfr/P5MyLY1AOgRCUZCuuMQgCGo0uoiyNkSX9kNssCroCqgQsACWZbGwsLoK6q5L8auuCosiiqxLwJXiWoAVBCmSQCgJJFNS7u+PMJMpd2ZuObfO83695gVzc+4555a553Of5znPsXAcx4EgCIIgiLgmQesOEARBEAShPSQICIIgCIIgQUAQBEEQBAkCgiAIgiBAgoAgCIIgCJAgIAiCIAgCJAgIgiAIggAJAoIgCIIgQIKAIAiCIAiQIDAty5cvh8ViwYEDB1Rve+PGjbBYLNi4caPqbRuZ8ePHo6ioSFDZOXPmwGKxSGpn2LBhGDZsmKR9CYIwLyQIFMY3MPs+drsdBQUFKCsrw4svvogzZ85o3UXJ/OlPf8Ly5cu17oaiiD1Gi8WCKVOmMGm7vr4ec+bMUV1Y+cRGrE88i4offvgBc+bM0URwE4RSWGgtA2VZvnw5JkyYgCeeeAKdO3dGQ0MDKisrsXHjRqxfvx4dO3bEBx98gL59+zJtt6mpCQ0NDbDZbJLfJGPRu3dvZGVlhQ1Yzc3N8Hq9sFqtSEgwtuaMdIyRsFgsmDx5Ml5++WXRbTU0NKC5uRk2mw0AUF1djezsbJSXl2POnDlBZRsbG9HY2Ai73S66Hd9AHumY/vvf/+K///2v//vZs2dx77334je/+Q1uvPFG//bc3FxcddVVots3A++88w5uueUWfP7553EtjAhzkaR1B+KFa6+9FhdffLH/+8yZM/HZZ5/huuuuw/XXX49du3bB4XDIbqeurg4pKSlITExEYmKi7PqkkJCQIGmg0hP19fVwOp2qtpmcnCy4bFJSEpKSlPn59u3bN0igVldX495770Xfvn3x29/+VpE2tcb3u9EavfSDiE+M/fpmcK644grMmjULP//8M/76178G/W337t24+eab0bZtW9jtdlx88cX44IMPgsr43BFffPEF7rvvPuTk5KBDhw5Bf/OZNK+77jp06dKFtx8lJSVBYmXZsmW44oorkJOTA5vNhp49e2LJkiVB+xQVFeH777/HF198EWZCDo0hmDJlClJTU1FfXx/W9ujRo5GXl4empib/tn/+858YMmQIUlJSkJaWhuHDh+P777+Pei5Pnz6NxMREvPjii/5t1dXVSEhIQLt27RBoCLv33nuRl5fn/z5s2DD07t0b27Ztw2WXXQan04lHH3006jEKxXcuVq1ahaeffhodOnSA3W7HlVdeib179waVDYwhOHDgALKzswEAc+fO9bfvsxTwxRAIuW4sEXOPfvnll7j//vuRnZ2NNm3a4O6774bX68Xp06cxduxYZGZmIjMzE4888kjQtTpw4AAsFguef/55/PGPf0SnTp3gcDgwdOhQfPfdd7L6xPe7+fnnn3Hfffehe/fucDgcaNeuHW655ZYg18Dy5ctxyy23AAAuv/xy/7Xx3e+B1ymQoqIijB8/XlA/AGm/A4KQA1kINGbMmDF49NFH8cknn2DSpEkAgO+//x6XXnop2rdvjxkzZiAlJQWrVq3CyJEj8X//93/4zW9+E1THfffdh+zsbMyePRt1dXW87YwaNQpjx47Ff/7zH/zqV7/yb//555+xZcsWPPfcc/5tS5YsQa9evXD99dcjKSkJH374Ie677z40Nzdj8uTJAIBFixbhd7/7HVJTU/HYY48BaDEhR2p78eLFWLNmjf9BCrS8hX/44YcYP36835rx1ltvYdy4cSgrK8MzzzyD+vp6LFmyBIMHD8aOHTsiBt21adMGvXv3xqZNm3D//fcDAL788ktYLBacPHkSP/zwA3r16gUA+Ne//oUhQ4YE7X/ixAlce+21uO222/Db3/4Wubm5GDZsmOBjjMWCBQuQkJCAhx9+GDU1NXj22Wdxxx13YOvWrbzls7OzsWTJkjBTfTTXkpDrxgqx9+jvfvc75OXlYe7cudiyZQteeeUVtGnTBps3b0bHjh0xb948rF27Fs899xx69+6NsWPHBu3/5ptv4syZM5g8eTLcbjdeeOEFXHHFFfj222/914TF7+Y///kPNm/ejNtuuw0dOnTAgQMHsGTJEgwbNgw//PADnE4nLrvsMtx///148cUX8eijj+KCCy4AAP+/YuHrh9TfAUHIgiMUZdmyZRwA7j//+U/EMhkZGdyFF17o/37llVdyffr04dxut39bc3MzN2jQIO68884Lq3vw4MFcY2Mjb7v79+/nOI7jampqOJvNxj30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T58+qKurw1133YXHHnsMCQn0DgZEfoanp6eTdUBDNL87rVYrBgwYELTWc3NzMzZs2OBf6zmUkpKSoPJAy9rPkcqbASnnCQCeffZZPPnkk1i3bh0uvvhiNbqqGWLPUY8ePfDtt99i586d/s/111+Pyy+/HDt37kRhYaGa3VcNKffSpZdeir179/oFEwD873//Q35+vinFACDtPNXX14cN+j4RxdE6cn7i8RluCLSOauS4lqk9NpuNW758OffDDz9wd911F9emTRuusrKS4ziOGzNmDDdjxgx/+X//+99cUlIS9/zzz3O7du3iysvL42baoZjztGDBAs5qtXLvvPMOd/ToUf/nzJkzWh2C4og9R6HEyywDsefp4MGDXFpaGjdlyhRuz5493EcffcTl5ORwTz31lFaHoApiz1N5eTmXlpbG/f3vf+d++ukn7pNPPuG6du3K3XrrrVodgiqcOXOG27FjB7djxw4OALdw4UJux44d3M8//8xxHMfNmDGDGzNmjL+8b9rh73//e27Xrl3c4sWLadqhDtCFIOA4jnvppZe4jh07clarlRs4cCC3ZcsW/9+GDh3KjRs3Lqj8qlWruPPPP5+zWq1cr169uDVr1qjcY20Qc546derEAQj7lJeXq99xFRF7LwUSL4KA48Sfp82bN3PFxcWczWbjunTpwj399NNcY2Ojyr1WHzHnqaGhgZszZw7XtWtXzm63c4WFhdx9993HnTp1Sv2Oq8jnn3/O+6zxnZtx48ZxQ4cODdunf//+nNVq5bp06cItW7ZM9X4TwVg4juxYBEEQBBHvaB5DQBAEQRCE9pAgIAiCIAiCBAFBEARBECQICIIgCIIACQKCIAiCIECCgCAIgiAIkCAgCIIgCAIkCAiCIAiCAAkCgiAIgiBAgoAgCIIgCJAgIAiCIAgCwP8H5HojaFjLb9oAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# evaluate the gradient around an initial guess of T=0 as the initial condition\n", + "T_init = Function(Q)\n", + "Jhat(T_init)\n", + "\n", + "# ask for L2 Riesz representation to get grid-independent result\n", + "gradJ = Jhat.derivative(options={\"riesz_representation\": \"L2\"})\n", + "\n", + "fig, ax = plt.subplots()\n", + "levels = np.linspace(-5, 5, 41)\n", + "from matplotlib import colors\n", + "cmap = plt.cm.coolwarm\n", + "with stop_annotating():\n", + " c = tricontourf(gradJ, axes=ax, levels=levels, norm=colors.CenteredNorm(), cmap=cmap)\n", + "ax.set_title('Derivative wrt Initial Temperature')\n", + "ax.set_aspect('equal')\n", + "fig.colorbar(c);" + ] + }, + { + "cell_type": "markdown", + "id": "6e853f89-8b66-44e1-863b-49e85717cb8f", + "metadata": {}, + "source": [ + "## Invert for Optimal Initial Condition Using Gradient-Based Optimisation Algorithm\n", + "Finally, we again use L-BFGS-B to invert for the inital condition. We have last evaluated the reduced functional with a zero initial condition as the control value, so this will be our initial guess." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "9dec8e63-9b11-4bad-a4f7-7be1497a7f46", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/skramer/firedrake/src/firedrake/firedrake/adjoint_utils/function.py:112: UserWarning: Could not find overloaded class of type ''.\n", + " other = create_overloaded_object(other)\n" + ] + } + ], + "source": [ + "# create bounds of 0 and 1 enforced during optimisation\n", + "Tmin = Function(Q)\n", + "Tmax = Function(Q)\n", + "Tmax.assign(1)\n", + "T_opt = minimize(Jhat, method='L-BFGS-B', bounds=[Tmin, Tmax], tol=1e-5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecc77ca9-58a1-4647-8122-689f30504897", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(1,2)\n", + "plot_temp(T_opt, 'Optimal Initial Condition', Tmax=1, ax=ax[0], colorbar=False)\n", + "plot_temp(T0, 'Initial Condition from Twin', Tmax=1, ax=ax[1])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.11.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}