├── .gitignore ├── .markdownlint.yaml ├── LICENSE ├── README.md ├── [1]_ODE_PINN.ipynb ├── [1]_ODE_PINN_ClassForm.ipynb ├── [2]_PDE_Burgers_PINN.ipynb ├── [3]_PDE_Laplace_PINN.ipynb ├── [3]_PDE_Laplace_PINN_ClassForm.ipynb ├── [4]_ODE_Supervised_and_PINN.ipynb ├── [5]_System_of_ODEs_PINN.ipynb ├── [6]_ODE_PINN_finite_difference.ipynb └── [7]_PDE_LAPLACE_FO_PINN.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | **/__pycache__ 3 | **/.ipynb_checkpoints 4 | **/.DS_Store 5 | *.Icon 6 | *.egg-info/ 7 | .trunk -------------------------------------------------------------------------------- /.markdownlint.yaml: -------------------------------------------------------------------------------- 1 | # Autoformatter friendly markdownlint config (all formatting rules disabled) 2 | default: true 3 | blank_lines: false 4 | bullet: false 5 | html: false 6 | indentation: false 7 | line_length: false 8 | spaces: false 9 | url: false 10 | whitespace: false 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 ASEM000 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Physics informed neural network](https://maziarraissi.github.io/PINNs/) in [JAX](https://github.com/google/jax) 2 | 3 | Example notebooks for various applications in Physics informed neural network. 4 | 5 | | Description | Functional form | Class form ✨*New*✨ | 6 | |---|---|---| 7 | | **[ODE]** | Open In Colab | Open In Colab | 8 | | **[PDE]** Burgers | Open In Colab | | 9 | | **[PDE]** Laplace | Open In Colab | Open In Colab | 10 | | **[ODE]** Supervised loss + PINN | Open In Colab | | 11 | | **[ODE]** System of ODE | Open In Colab | | 12 | | **[ODE]** Finite difference | Open In Colab | | 13 | 14 | 15 | If you find it useful please give it a ⭐ 16 | -------------------------------------------------------------------------------- /[1]_ODE_PINN.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": null, 16 | "metadata": { 17 | "id": "v77fdC1ZLyg1" 18 | }, 19 | "outputs": [], 20 | "source": [ 21 | "#Credits : Mahmoud Asem @Asem000 Septemeber 2021" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 3, 27 | "metadata": { 28 | "colab": { 29 | "base_uri": "https://localhost:8080/" 30 | }, 31 | "id": "vAR0swbLX_ZI", 32 | "outputId": "23ef5ef3-495b-4582-96a2-3108e8dce0bb" 33 | }, 34 | "outputs": [ 35 | { 36 | "name": "stdout", 37 | "output_type": "stream", 38 | "text": [ 39 | "Collecting optax\n", 40 | " Downloading optax-0.0.9-py3-none-any.whl (118 kB)\n", 41 | "\u001b[K |████████████████████████████████| 118 kB 8.5 MB/s eta 0:00:01\n", 42 | "\u001b[?25hCollecting chex>=0.0.4\n", 43 | " Downloading chex-0.0.8-py3-none-any.whl (57 kB)\n", 44 | "\u001b[K |████████████████████████████████| 57 kB 6.1 MB/s eta 0:00:01\n", 45 | "\u001b[?25hRequirement already satisfied: jaxlib>=0.1.37 in /usr/local/lib/python3.7/dist-packages (from optax) (0.1.70+cuda110)\n", 46 | "Requirement already satisfied: jax>=0.1.55 in /usr/local/lib/python3.7/dist-packages (from optax) (0.2.19)\n", 47 | "Requirement already satisfied: absl-py>=0.7.1 in /usr/local/lib/python3.7/dist-packages (from optax) (0.12.0)\n", 48 | "Requirement already satisfied: numpy>=1.18.0 in /usr/local/lib/python3.7/dist-packages (from optax) (1.19.5)\n", 49 | "Requirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from absl-py>=0.7.1->optax) (1.15.0)\n", 50 | "Requirement already satisfied: dm-tree>=0.1.5 in /usr/local/lib/python3.7/dist-packages (from chex>=0.0.4->optax) (0.1.6)\n", 51 | "Requirement already satisfied: toolz>=0.9.0 in /usr/local/lib/python3.7/dist-packages (from chex>=0.0.4->optax) (0.11.1)\n", 52 | "Requirement already satisfied: opt-einsum in /usr/local/lib/python3.7/dist-packages (from jax>=0.1.55->optax) (3.3.0)\n", 53 | "Requirement already satisfied: flatbuffers<3.0,>=1.12 in /usr/local/lib/python3.7/dist-packages (from jaxlib>=0.1.37->optax) (1.12)\n", 54 | "Requirement already satisfied: scipy in /usr/local/lib/python3.7/dist-packages (from jaxlib>=0.1.37->optax) (1.4.1)\n", 55 | "Installing collected packages: chex, optax\n", 56 | "Successfully installed chex-0.0.8 optax-0.0.9\n" 57 | ] 58 | } 59 | ], 60 | "source": [ 61 | "#Imports\n", 62 | "import jax \n", 63 | "import jax.numpy as jnp\n", 64 | "import numpy as np\n", 65 | "import matplotlib.pyplot as plt\n", 66 | "from matplotlib import cm\n", 67 | "import matplotlib as mpl\n", 68 | "!pip install optax\n", 69 | "import optax" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": 4, 75 | "metadata": { 76 | "id": "yoPHsh5lWvyP" 77 | }, 78 | "outputs": [], 79 | "source": [ 80 | "import sympy as sp" 81 | ] 82 | }, 83 | { 84 | "cell_type": "markdown", 85 | "metadata": { 86 | "id": "7bg4nSbsXVwD" 87 | }, 88 | "source": [ 89 | "### Generate a a differential equation and its solution using SymPy" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 19, 95 | "metadata": { 96 | "id": "P9664e-mVMTN" 97 | }, 98 | "outputs": [], 99 | "source": [ 100 | "t= sp.symbols('t')\n", 101 | "f = sp.Function('y')\n", 102 | "diffeq = sp.Eq(f(t).diff(t,t) + f(t).diff(t)-t*sp.cos(2*sp.pi*t),0)\n", 103 | "sol = sp.simplify(sp.dsolve(diffeq,ics={f(0):1,f(t).diff(t).subs(t,0):10}).rhs)" 104 | ] 105 | }, 106 | { 107 | "cell_type": "code", 108 | "execution_count": 20, 109 | "metadata": { 110 | "colab": { 111 | "base_uri": "https://localhost:8080/", 112 | "height": 54 113 | }, 114 | "id": "klgFeU6bcTrC", 115 | "outputId": "cad6a477-37e0-414d-daf6-6e4f05a288cd" 116 | }, 117 | "outputs": [ 118 | { 119 | "data": { 120 | "text/latex": [ 121 | "$\\displaystyle - t \\cos{\\left(2 \\pi t \\right)} + \\frac{d}{d t} y{\\left(t \\right)} + \\frac{d^{2}}{d t^{2}} y{\\left(t \\right)} = 0$" 122 | ], 123 | "text/plain": [ 124 | "Eq(-t*cos(2*pi*t) + Derivative(y(t), t) + Derivative(y(t), (t, 2)), 0)" 125 | ] 126 | }, 127 | "execution_count": 20, 128 | "metadata": {}, 129 | "output_type": "execute_result" 130 | } 131 | ], 132 | "source": [ 133 | "diffeq" 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": 21, 139 | "metadata": { 140 | "colab": { 141 | "base_uri": "https://localhost:8080/", 142 | "height": 60 143 | }, 144 | "id": "E4Uu2hbiYJtv", 145 | "outputId": "e58180aa-779a-49fa-9771-b9f4763bb037" 146 | }, 147 | "outputs": [ 148 | { 149 | "data": { 150 | "text/latex": [ 151 | "$\\displaystyle \\left. \\frac{d}{d t} y{\\left(t \\right)} \\right|_{\\substack{ t=0 }} = 10$" 152 | ], 153 | "text/plain": [ 154 | "Eq(Subs(Derivative(y(t), t), t, 0), 10)" 155 | ] 156 | }, 157 | "execution_count": 21, 158 | "metadata": {}, 159 | "output_type": "execute_result" 160 | } 161 | ], 162 | "source": [ 163 | "sp.Eq(f(t).diff(t).subs(t,0),10)" 164 | ] 165 | }, 166 | { 167 | "cell_type": "code", 168 | "execution_count": 22, 169 | "metadata": { 170 | "colab": { 171 | "base_uri": "https://localhost:8080/", 172 | "height": 38 173 | }, 174 | "id": "29QUbt_2YwlJ", 175 | "outputId": "3d9edb85-a44f-42cc-8776-bccda97cbc7e" 176 | }, 177 | "outputs": [ 178 | { 179 | "data": { 180 | "text/latex": [ 181 | "$\\displaystyle y{\\left(0 \\right)} = 1$" 182 | ], 183 | "text/plain": [ 184 | "Eq(y(0), 1)" 185 | ] 186 | }, 187 | "execution_count": 22, 188 | "metadata": {}, 189 | "output_type": "execute_result" 190 | } 191 | ], 192 | "source": [ 193 | "sp.Eq(f(t).subs(t,0),1)" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": 24, 199 | "metadata": { 200 | "colab": { 201 | "base_uri": "https://localhost:8080/", 202 | "height": 101 203 | }, 204 | "id": "r9KVq1yjYfld", 205 | "outputId": "b6e56baa-b419-49e0-bba9-3706d96b394c" 206 | }, 207 | "outputs": [ 208 | { 209 | "data": { 210 | "text/latex": [ 211 | "$\\displaystyle y{\\left(t \\right)} = \\frac{\\left(2 \\pi t e^{t} \\sin{\\left(2 \\pi t \\right)} + 8 \\pi^{3} t e^{t} \\sin{\\left(2 \\pi t \\right)} - 16 \\pi^{4} t e^{t} \\cos{\\left(2 \\pi t \\right)} - 4 \\pi^{2} t e^{t} \\cos{\\left(2 \\pi t \\right)} + 16 \\pi^{3} e^{t} \\sin{\\left(2 \\pi t \\right)} + e^{t} \\cos{\\left(2 \\pi t \\right)} + 12 \\pi^{2} e^{t} \\cos{\\left(2 \\pi t \\right)} - e^{t} + 36 \\pi^{2} e^{t} + 336 \\pi^{4} e^{t} + 704 \\pi^{6} e^{t} - 640 \\pi^{6} - 304 \\pi^{4} - 44 \\pi^{2}\\right) e^{- t}}{4 \\pi^{2} \\left(1 + 8 \\pi^{2} + 16 \\pi^{4}\\right)}$" 212 | ], 213 | "text/plain": [ 214 | "Eq(y(t), (2*pi*t*exp(t)*sin(2*pi*t) + 8*pi**3*t*exp(t)*sin(2*pi*t) - 16*pi**4*t*exp(t)*cos(2*pi*t) - 4*pi**2*t*exp(t)*cos(2*pi*t) + 16*pi**3*exp(t)*sin(2*pi*t) + exp(t)*cos(2*pi*t) + 12*pi**2*exp(t)*cos(2*pi*t) - exp(t) + 36*pi**2*exp(t) + 336*pi**4*exp(t) + 704*pi**6*exp(t) - 640*pi**6 - 304*pi**4 - 44*pi**2)*exp(-t)/(4*pi**2*(1 + 8*pi**2 + 16*pi**4)))" 215 | ] 216 | }, 217 | "execution_count": 24, 218 | "metadata": {}, 219 | "output_type": "execute_result" 220 | } 221 | ], 222 | "source": [ 223 | "sp.Eq(f(t),sol)" 224 | ] 225 | }, 226 | { 227 | "cell_type": "code", 228 | "execution_count": 25, 229 | "metadata": { 230 | "colab": { 231 | "base_uri": "https://localhost:8080/", 232 | "height": 37 233 | }, 234 | "id": "MNVOpPyCW-GU", 235 | "outputId": "c333d114-01de-4132-8ebf-effd19785112" 236 | }, 237 | "outputs": [ 238 | { 239 | "data": { 240 | "text/latex": [ 241 | "$\\displaystyle 0$" 242 | ], 243 | "text/plain": [ 244 | "0" 245 | ] 246 | }, 247 | "execution_count": 25, 248 | "metadata": {}, 249 | "output_type": "execute_result" 250 | } 251 | ], 252 | "source": [ 253 | "#verify solution\n", 254 | "sp.simplify(-t*sp.cos(sp.pi*2*t)+sol.diff(t)+sol.diff(t,t))" 255 | ] 256 | }, 257 | { 258 | "cell_type": "markdown", 259 | "metadata": { 260 | "id": "NQ61lEQeXgrc" 261 | }, 262 | "source": [ 263 | "### Constructing the MLP" 264 | ] 265 | }, 266 | { 267 | "cell_type": "code", 268 | "execution_count": 61, 269 | "metadata": { 270 | "id": "Lml6PGLPZgmr" 271 | }, 272 | "outputs": [], 273 | "source": [ 274 | "N_b = 1\n", 275 | "N_c = 100\n", 276 | "\n", 277 | "tmin,tmax=0. ,jnp.pi\n", 278 | "\n", 279 | "'''boundary conditions'''\n", 280 | "\n", 281 | "\n", 282 | "# U[0] = 1\n", 283 | "t_0 = jnp.ones([N_b,1],dtype='float32')*0.\n", 284 | "ic_0 = jnp.ones_like(t_0) \n", 285 | "IC_0 = jnp.concatenate([t_0,ic_0],axis=1)\n", 286 | "\n", 287 | "# U_t[0] = 10\n", 288 | "t_b1 = jnp.zeros([N_b,1])\n", 289 | "bc_1 = jnp.ones_like(t_b1) * 10\n", 290 | "BC_1 = jnp.concatenate([t_b1,bc_1],axis=1)\n", 291 | "\n", 292 | "conds = [IC_0,BC_1]\n", 293 | "\n", 294 | "#collocation points\n", 295 | "\n", 296 | "key=jax.random.PRNGKey(0)\n", 297 | "\n", 298 | "t_c = jax.random.uniform(key,minval=tmin,maxval=tmax,shape=(N_c,1))\n", 299 | "colloc = t_c\n", 300 | "\n", 301 | "def ODE_loss(t,u):\n", 302 | " u_t=lambda t:jax.grad(lambda t:jnp.sum(u(t)))(t)\n", 303 | " u_tt=lambda t:jax.grad(lambda t : jnp.sum(u_t(t)))(t)\n", 304 | " return -t*jnp.cos(2*jnp.pi*t) + u_t(t) + u_tt(t)" 305 | ] 306 | }, 307 | { 308 | "cell_type": "code", 309 | "execution_count": 68, 310 | "metadata": { 311 | "id": "KoZZJl2TbI_n" 312 | }, 313 | "outputs": [], 314 | "source": [ 315 | "def init_params(layers):\n", 316 | " keys = jax.random.split(jax.random.PRNGKey(0),len(layers)-1)\n", 317 | " params = list()\n", 318 | " for key,n_in,n_out in zip(keys,layers[:-1],layers[1:]):\n", 319 | " lb, ub = -(1 / jnp.sqrt(n_in)), (1 / jnp.sqrt(n_in)) # xavier initialization lower and upper bound\n", 320 | " W = lb + (ub-lb) * jax.random.uniform(key,shape=(n_in,n_out))\n", 321 | " B = jax.random.uniform(key,shape=(n_out,))\n", 322 | " params.append({'W':W,'B':B})\n", 323 | " return params\n", 324 | "\n", 325 | "def fwd(params,t):\n", 326 | " X = jnp.concatenate([t],axis=1)\n", 327 | " *hidden,last = params\n", 328 | " for layer in hidden :\n", 329 | " X = jax.nn.tanh(X@layer['W']+layer['B'])\n", 330 | " return X@last['W'] + last['B']\n", 331 | "\n", 332 | "@jax.jit\n", 333 | "def MSE(true,pred):\n", 334 | " return jnp.mean((true-pred)**2)\n", 335 | "\n", 336 | "def loss_fun(params,colloc,conds):\n", 337 | " t_c =colloc[:,[0]]\n", 338 | " ufunc = lambda t : fwd(params,t)\n", 339 | " ufunc_t=lambda t:jax.grad(lambda t:jnp.sum(ufunc(t)))(t)\n", 340 | " loss =jnp.mean(ODE_loss(t_c,ufunc) **2)\n", 341 | "\n", 342 | " t_ic,u_ic = conds[0][:,[0]],conds[0][:,[1]] \n", 343 | " loss += MSE(u_ic,ufunc(t_ic))\n", 344 | "\n", 345 | " t_bc,u_bc = conds[1][:,[0]],conds[1][:,[1]] \n", 346 | " loss += MSE(u_bc,ufunc_t(t_bc))\n", 347 | "\n", 348 | " return loss\n", 349 | "\n", 350 | "@jax.jit\n", 351 | "def update(opt_state,params,colloc,conds):\n", 352 | " # Get the gradient w.r.t to MLP params\n", 353 | " grads=jax.jit(jax.grad(loss_fun,0))(params,colloc,conds)\n", 354 | " \n", 355 | " #Update params\n", 356 | " updates, opt_state = optimizer.update(grads, opt_state)\n", 357 | " params = optax.apply_updates(params, updates)\n", 358 | "\n", 359 | " #Update params\n", 360 | " # return jax.tree_multimap(lambda params,grads : params-LR*grads, params,grads)\n", 361 | " return opt_state,params\n" 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "execution_count": 69, 367 | "metadata": { 368 | "id": "ae1ZDoy0c29c" 369 | }, 370 | "outputs": [], 371 | "source": [ 372 | "# construct the MLP of 6 hidden layers of 8 neurons for each layer\n", 373 | "params = init_params([1] + [20]*4+[1])" 374 | ] 375 | }, 376 | { 377 | "cell_type": "code", 378 | "execution_count": 70, 379 | "metadata": { 380 | "id": "jySmbUwic5yk" 381 | }, 382 | "outputs": [], 383 | "source": [ 384 | "lr = optax.piecewise_constant_schedule(1e-3,{10_000:5e-3,30_000:1e-3,50_000:5e-4,70_000:1e-4})\n", 385 | "optimizer = optax.adam(lr)\n", 386 | "opt_state = optimizer.init(params)" 387 | ] 388 | }, 389 | { 390 | "cell_type": "code", 391 | "execution_count": 71, 392 | "metadata": { 393 | "colab": { 394 | "base_uri": "https://localhost:8080/" 395 | }, 396 | "id": "kBzGA8OVc8C6", 397 | "outputId": "effacbde-f915-47cd-8f13-a44e6b697062" 398 | }, 399 | "outputs": [ 400 | { 401 | "name": "stdout", 402 | "output_type": "stream", 403 | "text": [ 404 | "Epoch=0\tloss=1.026e+02\n", 405 | "Epoch=100\tloss=1.500e+01\n", 406 | "Epoch=200\tloss=7.508e+00\n", 407 | "Epoch=300\tloss=5.177e+00\n", 408 | "Epoch=400\tloss=3.458e+00\n", 409 | "Epoch=500\tloss=2.615e+00\n", 410 | "Epoch=600\tloss=2.391e+00\n", 411 | "Epoch=700\tloss=2.254e+00\n", 412 | "Epoch=800\tloss=2.133e+00\n", 413 | "Epoch=900\tloss=2.013e+00\n", 414 | "Epoch=1000\tloss=1.855e+00\n", 415 | "Epoch=1100\tloss=1.549e+00\n", 416 | "Epoch=1200\tloss=1.018e+00\n", 417 | "Epoch=1300\tloss=9.915e-01\n", 418 | "Epoch=1400\tloss=9.756e-01\n", 419 | "Epoch=1500\tloss=9.618e-01\n", 420 | "Epoch=1600\tloss=9.480e-01\n", 421 | "Epoch=1700\tloss=9.327e-01\n", 422 | "Epoch=1800\tloss=9.145e-01\n", 423 | "Epoch=1900\tloss=8.902e-01\n", 424 | "Epoch=2000\tloss=7.379e-01\n", 425 | "Epoch=2100\tloss=3.372e-01\n", 426 | "Epoch=2200\tloss=1.753e-02\n", 427 | "Epoch=2300\tloss=4.962e-03\n", 428 | "Epoch=2400\tloss=3.304e-03\n", 429 | "Epoch=2500\tloss=2.670e-03\n", 430 | "Epoch=2600\tloss=2.238e-03\n", 431 | "Epoch=2700\tloss=1.883e-03\n", 432 | "Epoch=2800\tloss=1.577e-03\n", 433 | "Epoch=2900\tloss=1.311e-03\n", 434 | "Epoch=3000\tloss=1.082e-03\n", 435 | "Epoch=3100\tloss=8.856e-04\n", 436 | "Epoch=3200\tloss=7.198e-04\n", 437 | "Epoch=3300\tloss=5.825e-04\n", 438 | "Epoch=3400\tloss=4.711e-04\n", 439 | "Epoch=3500\tloss=6.700e-04\n", 440 | "Epoch=3600\tloss=3.161e-04\n", 441 | "Epoch=3700\tloss=3.296e-04\n", 442 | "Epoch=3800\tloss=2.278e-04\n", 443 | "Epoch=3900\tloss=2.032e-04\n", 444 | "Epoch=4000\tloss=1.785e-04\n", 445 | "Epoch=4100\tloss=1.624e-04\n", 446 | "Epoch=4200\tloss=1.494e-04\n", 447 | "Epoch=4300\tloss=1.377e-04\n", 448 | "Epoch=4400\tloss=2.545e-04\n", 449 | "Epoch=4500\tloss=1.195e-04\n", 450 | "Epoch=4600\tloss=2.162e-03\n", 451 | "Epoch=4700\tloss=1.041e-04\n", 452 | "Epoch=4800\tloss=1.321e-04\n", 453 | "Epoch=4900\tloss=9.035e-05\n", 454 | "Epoch=5000\tloss=8.385e-05\n", 455 | "Epoch=5100\tloss=8.181e-05\n", 456 | "Epoch=5200\tloss=7.205e-05\n", 457 | "Epoch=5300\tloss=2.472e-03\n", 458 | "Epoch=5400\tloss=6.137e-05\n", 459 | "Epoch=5500\tloss=6.695e-05\n", 460 | "Epoch=5600\tloss=5.197e-05\n", 461 | "Epoch=5700\tloss=4.714e-05\n", 462 | "Epoch=5800\tloss=7.266e-05\n", 463 | "Epoch=5900\tloss=3.922e-05\n", 464 | "Epoch=6000\tloss=1.470e-03\n", 465 | "Epoch=6100\tloss=3.234e-05\n", 466 | "Epoch=6200\tloss=1.919e-03\n", 467 | "Epoch=6300\tloss=2.676e-05\n", 468 | "Epoch=6400\tloss=2.389e-05\n", 469 | "Epoch=6500\tloss=2.301e-05\n", 470 | "Epoch=6600\tloss=1.962e-05\n", 471 | "Epoch=6700\tloss=3.187e-04\n", 472 | "Epoch=6800\tloss=1.618e-05\n", 473 | "Epoch=6900\tloss=2.400e-03\n", 474 | "Epoch=7000\tloss=1.355e-05\n", 475 | "Epoch=7100\tloss=2.970e-04\n", 476 | "Epoch=7200\tloss=1.146e-05\n", 477 | "Epoch=7300\tloss=1.040e-05\n", 478 | "Epoch=7400\tloss=3.527e-05\n", 479 | "Epoch=7500\tloss=9.057e-06\n", 480 | "Epoch=7600\tloss=4.930e-04\n", 481 | "Epoch=7700\tloss=3.244e-04\n", 482 | "Epoch=7800\tloss=1.300e-03\n", 483 | "Epoch=7900\tloss=7.630e-06\n", 484 | "Epoch=8000\tloss=1.313e-05\n", 485 | "Epoch=8100\tloss=1.451e-05\n", 486 | "Epoch=8200\tloss=7.152e-06\n", 487 | "Epoch=8300\tloss=6.462e-05\n", 488 | "Epoch=8400\tloss=5.616e-03\n", 489 | "Epoch=8500\tloss=6.044e-06\n", 490 | "Epoch=8600\tloss=7.831e-05\n", 491 | "Epoch=8700\tloss=5.532e-06\n", 492 | "Epoch=8800\tloss=8.422e-05\n", 493 | "Epoch=8900\tloss=1.461e-03\n", 494 | "Epoch=9000\tloss=5.241e-06\n", 495 | "Epoch=9100\tloss=2.537e-04\n", 496 | "Epoch=9200\tloss=4.977e-06\n", 497 | "Epoch=9300\tloss=4.646e-05\n", 498 | "Epoch=9400\tloss=4.768e-06\n", 499 | "Epoch=9500\tloss=1.605e-05\n", 500 | "Epoch=9600\tloss=4.656e-06\n", 501 | "Epoch=9700\tloss=3.441e-03\n", 502 | "Epoch=9800\tloss=4.752e-06\n", 503 | "Epoch=9900\tloss=6.980e-03\n", 504 | "CPU times: user 17.7 s, sys: 139 ms, total: 17.8 s\n", 505 | "Wall time: 17.7 s\n" 506 | ] 507 | } 508 | ], 509 | "source": [ 510 | "%%time\n", 511 | "epochs = 10_000\n", 512 | "for _ in range(epochs):\n", 513 | " opt_state,params = update(opt_state,params,colloc,conds)\n", 514 | "\n", 515 | " # print loss and epoch info\n", 516 | " if _ %(100) ==0:\n", 517 | " print(f'Epoch={_}\\tloss={loss_fun(params,colloc,conds):.3e}')" 518 | ] 519 | }, 520 | { 521 | "cell_type": "code", 522 | "execution_count": 80, 523 | "metadata": { 524 | "colab": { 525 | "base_uri": "https://localhost:8080/", 526 | "height": 282 527 | }, 528 | "id": "eWeNvDsdDEuI", 529 | "outputId": "32551eeb-25df-4d2e-8cae-82cc52b41ac5" 530 | }, 531 | "outputs": [ 532 | { 533 | "data": { 534 | "text/plain": [ 535 | "" 536 | ] 537 | }, 538 | "execution_count": 80, 539 | "metadata": {}, 540 | "output_type": "execute_result" 541 | }, 542 | { 543 | "data": { 544 | "image/png": "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", 545 | "text/plain": [ 546 | "
" 547 | ] 548 | }, 549 | "metadata": { 550 | "needs_background": "light" 551 | }, 552 | "output_type": "display_data" 553 | } 554 | ], 555 | "source": [ 556 | "lam_sol= sp.lambdify(t,sol)\n", 557 | "\n", 558 | "dT = 1e-3\n", 559 | "Tf = jnp.pi\n", 560 | "T = np.arange(0,Tf+dT,dT)\n", 561 | "\n", 562 | "\n", 563 | "sym_sol =np.array([lam_sol(i) for i in T])\n", 564 | "\n", 565 | "plt.plot(T,sym_sol,'--r',label='sympy solution')\n", 566 | "plt.plot(T,fwd(params,T.reshape(-1,1))[:,0],'--k',label='NN solution')\n", 567 | "plt.legend()" 568 | ] 569 | } 570 | ], 571 | "metadata": { 572 | "colab": { 573 | "authorship_tag": "ABX9TyPlDK/9ZvMulH91+B+B32BC", 574 | "collapsed_sections": [], 575 | "include_colab_link": true, 576 | "name": "[1] ODE-PINN.ipynb", 577 | "provenance": [] 578 | }, 579 | "kernelspec": { 580 | "display_name": "Python 3.8.9 64-bit", 581 | "language": "python", 582 | "name": "python3" 583 | }, 584 | "language_info": { 585 | "codemirror_mode": { 586 | "name": "ipython", 587 | "version": 3 588 | }, 589 | "file_extension": ".py", 590 | "mimetype": "text/x-python", 591 | "name": "python", 592 | "nbconvert_exporter": "python", 593 | "pygments_lexer": "ipython3", 594 | "version": "3.8.9" 595 | }, 596 | "vscode": { 597 | "interpreter": { 598 | "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" 599 | } 600 | } 601 | }, 602 | "nbformat": 4, 603 | "nbformat_minor": 4 604 | } 605 | -------------------------------------------------------------------------------- /[1]_ODE_PINN_ClassForm.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "id": "view-in-github", 7 | "colab_type": "text" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "source": [ 16 | "!pip install optax\n", 17 | "!pip install pytreeclass\n", 18 | "!pip install tqdm" 19 | ], 20 | "metadata": { 21 | "id": "PmiMsCTpOtKE", 22 | "colab": { 23 | "base_uri": "https://localhost:8080/" 24 | }, 25 | "outputId": "673af120-a5ba-45a4-953f-e77dee359c09" 26 | }, 27 | "execution_count": 1, 28 | "outputs": [ 29 | { 30 | "output_type": "stream", 31 | "name": "stdout", 32 | "text": [ 33 | "Requirement already satisfied: optax in /usr/local/lib/python3.10/dist-packages (0.1.7)\n", 34 | "Requirement already satisfied: absl-py>=0.7.1 in /usr/local/lib/python3.10/dist-packages (from optax) (1.4.0)\n", 35 | "Requirement already satisfied: chex>=0.1.5 in /usr/local/lib/python3.10/dist-packages (from optax) (0.1.7)\n", 36 | "Requirement already satisfied: jax>=0.1.55 in /usr/local/lib/python3.10/dist-packages (from optax) (0.4.14)\n", 37 | "Requirement already satisfied: jaxlib>=0.1.37 in /usr/local/lib/python3.10/dist-packages (from optax) (0.4.14+cuda11.cudnn86)\n", 38 | "Requirement already satisfied: numpy>=1.18.0 in /usr/local/lib/python3.10/dist-packages (from optax) (1.23.5)\n", 39 | "Requirement already satisfied: dm-tree>=0.1.5 in /usr/local/lib/python3.10/dist-packages (from chex>=0.1.5->optax) (0.1.8)\n", 40 | "Requirement already satisfied: toolz>=0.9.0 in /usr/local/lib/python3.10/dist-packages (from chex>=0.1.5->optax) (0.12.0)\n", 41 | "Requirement already satisfied: typing-extensions>=4.2.0 in /usr/local/lib/python3.10/dist-packages (from chex>=0.1.5->optax) (4.7.1)\n", 42 | "Requirement already satisfied: ml-dtypes>=0.2.0 in /usr/local/lib/python3.10/dist-packages (from jax>=0.1.55->optax) (0.2.0)\n", 43 | "Requirement already satisfied: opt-einsum in /usr/local/lib/python3.10/dist-packages (from jax>=0.1.55->optax) (3.3.0)\n", 44 | "Requirement already satisfied: scipy>=1.7 in /usr/local/lib/python3.10/dist-packages (from jax>=0.1.55->optax) (1.10.1)\n", 45 | "Requirement already satisfied: pytreeclass in /usr/local/lib/python3.10/dist-packages (0.6.0)\n", 46 | "Requirement already satisfied: jax>=0.4.7 in /usr/local/lib/python3.10/dist-packages (from pytreeclass) (0.4.14)\n", 47 | "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.10/dist-packages (from pytreeclass) (4.7.1)\n", 48 | "Requirement already satisfied: ml-dtypes>=0.2.0 in /usr/local/lib/python3.10/dist-packages (from jax>=0.4.7->pytreeclass) (0.2.0)\n", 49 | "Requirement already satisfied: numpy>=1.22 in /usr/local/lib/python3.10/dist-packages (from jax>=0.4.7->pytreeclass) (1.23.5)\n", 50 | "Requirement already satisfied: opt-einsum in /usr/local/lib/python3.10/dist-packages (from jax>=0.4.7->pytreeclass) (3.3.0)\n", 51 | "Requirement already satisfied: scipy>=1.7 in /usr/local/lib/python3.10/dist-packages (from jax>=0.4.7->pytreeclass) (1.10.1)\n", 52 | "Requirement already satisfied: tqdm in /usr/local/lib/python3.10/dist-packages (4.66.1)\n" 53 | ] 54 | } 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": 2, 60 | "metadata": { 61 | "id": "vAR0swbLX_ZI" 62 | }, 63 | "outputs": [], 64 | "source": [ 65 | "# Imports\n", 66 | "from __future__ import annotations\n", 67 | "from typing import Callable\n", 68 | "import jax\n", 69 | "import jax.numpy as jnp\n", 70 | "import numpy as np\n", 71 | "import matplotlib.pyplot as plt\n", 72 | "import optax\n", 73 | "import sympy as sp\n", 74 | "import pytreeclass as pytc\n", 75 | "from tqdm.notebook import tqdm" 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": { 81 | "id": "7bg4nSbsXVwD" 82 | }, 83 | "source": [ 84 | "### Generate a a differential equation and its solution using SymPy" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": 3, 90 | "metadata": { 91 | "id": "P9664e-mVMTN" 92 | }, 93 | "outputs": [], 94 | "source": [ 95 | "t= sp.symbols('t')\n", 96 | "f = sp.Function('y')\n", 97 | "diffeq = sp.Eq(f(t).diff(t,t) + f(t).diff(t)-t*sp.cos(2*sp.pi*t),0)\n", 98 | "sol = sp.simplify(sp.dsolve(diffeq,ics={f(0):1,f(t).diff(t).subs(t,0):10}).rhs)" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": 4, 104 | "metadata": { 105 | "id": "klgFeU6bcTrC", 106 | "colab": { 107 | "base_uri": "https://localhost:8080/", 108 | "height": 54 109 | }, 110 | "outputId": "060d7276-cb05-418f-8be9-91e7a671a8bb" 111 | }, 112 | "outputs": [ 113 | { 114 | "output_type": "execute_result", 115 | "data": { 116 | "text/plain": [ 117 | "Eq(-t*cos(2*pi*t) + Derivative(y(t), t) + Derivative(y(t), (t, 2)), 0)" 118 | ], 119 | "text/latex": "$\\displaystyle - t \\cos{\\left(2 \\pi t \\right)} + \\frac{d}{d t} y{\\left(t \\right)} + \\frac{d^{2}}{d t^{2}} y{\\left(t \\right)} = 0$" 120 | }, 121 | "metadata": {}, 122 | "execution_count": 4 123 | } 124 | ], 125 | "source": [ 126 | "diffeq" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": 5, 132 | "metadata": { 133 | "id": "E4Uu2hbiYJtv", 134 | "colab": { 135 | "base_uri": "https://localhost:8080/", 136 | "height": 61 137 | }, 138 | "outputId": "d66ce7f6-f1b4-4667-faa7-8708227ff805" 139 | }, 140 | "outputs": [ 141 | { 142 | "output_type": "execute_result", 143 | "data": { 144 | "text/plain": [ 145 | "Eq(Subs(Derivative(y(t), t), t, 0), 10)" 146 | ], 147 | "text/latex": "$\\displaystyle \\left. \\frac{d}{d t} y{\\left(t \\right)} \\right|_{\\substack{ t=0 }} = 10$" 148 | }, 149 | "metadata": {}, 150 | "execution_count": 5 151 | } 152 | ], 153 | "source": [ 154 | "sp.Eq(f(t).diff(t).subs(t,0),10)" 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "execution_count": 6, 160 | "metadata": { 161 | "id": "29QUbt_2YwlJ", 162 | "colab": { 163 | "base_uri": "https://localhost:8080/", 164 | "height": 39 165 | }, 166 | "outputId": "abd0aca6-9156-49f1-fba3-9349e0b5fe9d" 167 | }, 168 | "outputs": [ 169 | { 170 | "output_type": "execute_result", 171 | "data": { 172 | "text/plain": [ 173 | "Eq(y(0), 1)" 174 | ], 175 | "text/latex": "$\\displaystyle y{\\left(0 \\right)} = 1$" 176 | }, 177 | "metadata": {}, 178 | "execution_count": 6 179 | } 180 | ], 181 | "source": [ 182 | "sp.Eq(f(t).subs(t,0),1)" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": 7, 188 | "metadata": { 189 | "id": "r9KVq1yjYfld", 190 | "colab": { 191 | "base_uri": "https://localhost:8080/", 192 | "height": 82 193 | }, 194 | "outputId": "c8ef8212-caed-48a7-fbe2-1a0bc700570e" 195 | }, 196 | "outputs": [ 197 | { 198 | "output_type": "execute_result", 199 | "data": { 200 | "text/plain": [ 201 | "Eq(y(t), (2*pi*t*exp(t)*sin(2*pi*t) + 8*pi**3*t*exp(t)*sin(2*pi*t) - 16*pi**4*t*exp(t)*cos(2*pi*t) - 4*pi**2*t*exp(t)*cos(2*pi*t) + 16*pi**3*exp(t)*sin(2*pi*t) + exp(t)*cos(2*pi*t) + 12*pi**2*exp(t)*cos(2*pi*t) - exp(t) + 36*pi**2*exp(t) + 336*pi**4*exp(t) + 704*pi**6*exp(t) - 640*pi**6 - 304*pi**4 - 44*pi**2)*exp(-t)/(4*pi**2*(1 + 8*pi**2 + 16*pi**4)))" 202 | ], 203 | "text/latex": "$\\displaystyle y{\\left(t \\right)} = \\frac{\\left(2 \\pi t e^{t} \\sin{\\left(2 \\pi t \\right)} + 8 \\pi^{3} t e^{t} \\sin{\\left(2 \\pi t \\right)} - 16 \\pi^{4} t e^{t} \\cos{\\left(2 \\pi t \\right)} - 4 \\pi^{2} t e^{t} \\cos{\\left(2 \\pi t \\right)} + 16 \\pi^{3} e^{t} \\sin{\\left(2 \\pi t \\right)} + e^{t} \\cos{\\left(2 \\pi t \\right)} + 12 \\pi^{2} e^{t} \\cos{\\left(2 \\pi t \\right)} - e^{t} + 36 \\pi^{2} e^{t} + 336 \\pi^{4} e^{t} + 704 \\pi^{6} e^{t} - 640 \\pi^{6} - 304 \\pi^{4} - 44 \\pi^{2}\\right) e^{- t}}{4 \\pi^{2} \\cdot \\left(1 + 8 \\pi^{2} + 16 \\pi^{4}\\right)}$" 204 | }, 205 | "metadata": {}, 206 | "execution_count": 7 207 | } 208 | ], 209 | "source": [ 210 | "sp.Eq(f(t),sol)" 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": 8, 216 | "metadata": { 217 | "id": "MNVOpPyCW-GU", 218 | "colab": { 219 | "base_uri": "https://localhost:8080/", 220 | "height": 37 221 | }, 222 | "outputId": "a477b9e6-cad4-4584-e926-d3e8c9538160" 223 | }, 224 | "outputs": [ 225 | { 226 | "output_type": "execute_result", 227 | "data": { 228 | "text/plain": [ 229 | "0" 230 | ], 231 | "text/latex": "$\\displaystyle 0$" 232 | }, 233 | "metadata": {}, 234 | "execution_count": 8 235 | } 236 | ], 237 | "source": [ 238 | "#verify solution\n", 239 | "sp.simplify(-t*sp.cos(sp.pi*2*t)+sol.diff(t)+sol.diff(t,t))" 240 | ] 241 | }, 242 | { 243 | "cell_type": "markdown", 244 | "metadata": { 245 | "id": "NQ61lEQeXgrc" 246 | }, 247 | "source": [ 248 | "### Constructing the MLP" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": 9, 254 | "metadata": { 255 | "id": "Lml6PGLPZgmr", 256 | "colab": { 257 | "base_uri": "https://localhost:8080/" 258 | }, 259 | "outputId": "ad72cbc0-73f6-4a44-d384-3e2de933faf2" 260 | }, 261 | "outputs": [ 262 | { 263 | "output_type": "stream", 264 | "name": "stderr", 265 | "text": [ 266 | "WARNING:jax._src.xla_bridge:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)\n" 267 | ] 268 | } 269 | ], 270 | "source": [ 271 | "# construct data\n", 272 | "\n", 273 | "N_b = 1\n", 274 | "N_c = 100\n", 275 | "\n", 276 | "tmin, tmax = 0.0, jnp.pi\n", 277 | "\n", 278 | "\"\"\"boundary conditions\"\"\"\n", 279 | "\n", 280 | "\n", 281 | "# U[0] = 1\n", 282 | "t_0 = jnp.ones([N_b, 1], dtype=\"float32\") * 0.0\n", 283 | "ic_0 = jnp.ones_like(t_0)\n", 284 | "IC_0 = jnp.concatenate([t_0, ic_0], axis=1)\n", 285 | "\n", 286 | "# U_t[0] = 10\n", 287 | "t_b1 = jnp.zeros([N_b, 1])\n", 288 | "bc_1 = jnp.ones_like(t_b1) * 10\n", 289 | "BC_1 = jnp.concatenate([t_b1, bc_1], axis=1)\n", 290 | "\n", 291 | "conds: list[jax.Array] = [IC_0, BC_1]\n", 292 | "\n", 293 | "# collocation points\n", 294 | "\n", 295 | "key = jax.random.PRNGKey(0)\n", 296 | "\n", 297 | "t_c = jax.random.uniform(key, minval=tmin, maxval=tmax, shape=(N_c, 1))\n", 298 | "colloc = t_c" 299 | ] 300 | }, 301 | { 302 | "cell_type": "markdown", 303 | "source": [ 304 | "# Build Model" 305 | ], 306 | "metadata": { 307 | "id": "V_gR3d4AKHxJ" 308 | } 309 | }, 310 | { 311 | "cell_type": "code", 312 | "source": [ 313 | "init_func = jax.nn.initializers.glorot_uniform()\n", 314 | "\n", 315 | "\n", 316 | "class Linear(pytc.TreeClass):\n", 317 | " def __init__(\n", 318 | " self,\n", 319 | " in_features: int,\n", 320 | " out_features: int,\n", 321 | " key: jax.random.KeyArray = jax.random.PRNGKey(0),\n", 322 | " ):\n", 323 | " self.weight = init_func(key, (in_features, out_features))\n", 324 | " self.bias = jax.numpy.zeros((out_features,))\n", 325 | "\n", 326 | " def __call__(self, x: jax.Array) -> jax.Array:\n", 327 | " return x @ self.weight + self.bias\n", 328 | "\n", 329 | "\n", 330 | "class MLP(pytc.TreeClass):\n", 331 | " def __init__(self, key: jax.random.KeyArray = jax.random.PRNGKey(0)):\n", 332 | " k1, k2, k3, k4 = jax.random.split(key, 4)\n", 333 | " self.l1 = Linear(1, 20, key=k1)\n", 334 | " self.l2 = Linear(20, 20, key=k2)\n", 335 | " self.l3 = Linear(20, 20, key=k3)\n", 336 | " self.l4 = Linear(20, 1, key=k4)\n", 337 | "\n", 338 | " def __call__(self, x: jax.Array) -> jax.Array:\n", 339 | " x = self.l1(x)\n", 340 | " x = jax.nn.tanh(x)\n", 341 | " x = self.l2(x)\n", 342 | " x = jax.nn.tanh(x)\n", 343 | " x = self.l3(x)\n", 344 | " x = jax.nn.tanh(x)\n", 345 | " x = self.l4(x)\n", 346 | " return x\n", 347 | "\n", 348 | "\n", 349 | "model = MLP()\n", 350 | "print(pytc.tree_summary(model))" 351 | ], 352 | "metadata": { 353 | "id": "TD7IQp70F65_", 354 | "colab": { 355 | "base_uri": "https://localhost:8080/" 356 | }, 357 | "outputId": "0fdcd611-098e-4b46-b27f-33d0da1c725d" 358 | }, 359 | "execution_count": 10, 360 | "outputs": [ 361 | { 362 | "output_type": "stream", 363 | "name": "stdout", 364 | "text": [ 365 | "┌──────────┬──────────┬─────┬──────┐\n", 366 | "│Name │Type │Count│Size │\n", 367 | "├──────────┼──────────┼─────┼──────┤\n", 368 | "│.l1.weight│f32[1,20] │20 │80.00B│\n", 369 | "├──────────┼──────────┼─────┼──────┤\n", 370 | "│.l1.bias │f32[20] │20 │80.00B│\n", 371 | "├──────────┼──────────┼─────┼──────┤\n", 372 | "│.l2.weight│f32[20,20]│400 │1.56KB│\n", 373 | "├──────────┼──────────┼─────┼──────┤\n", 374 | "│.l2.bias │f32[20] │20 │80.00B│\n", 375 | "├──────────┼──────────┼─────┼──────┤\n", 376 | "│.l3.weight│f32[20,20]│400 │1.56KB│\n", 377 | "├──────────┼──────────┼─────┼──────┤\n", 378 | "│.l3.bias │f32[20] │20 │80.00B│\n", 379 | "├──────────┼──────────┼─────┼──────┤\n", 380 | "│.l4.weight│f32[20,1] │20 │80.00B│\n", 381 | "├──────────┼──────────┼─────┼──────┤\n", 382 | "│.l4.bias │f32[1] │1 │4.00B │\n", 383 | "├──────────┼──────────┼─────┼──────┤\n", 384 | "│Σ │MLP │901 │3.52KB│\n", 385 | "└──────────┴──────────┴─────┴──────┘\n" 386 | ] 387 | } 388 | ] 389 | }, 390 | { 391 | "cell_type": "code", 392 | "execution_count": 11, 393 | "metadata": { 394 | "id": "KoZZJl2TbI_n" 395 | }, 396 | "outputs": [], 397 | "source": [ 398 | "def mse(true, pred):\n", 399 | " return jnp.mean((true - pred) ** 2)\n", 400 | "\n", 401 | "\n", 402 | "def diff(func: Callable, *args, **kwargs):\n", 403 | " \"\"\"sum then grad\"\"\"\n", 404 | " return jax.grad(lambda *ar, **kws: jnp.sum(func(*ar, **kws)), *args, **kwargs)\n", 405 | "\n", 406 | "\n", 407 | "def ode_loss(t, u):\n", 408 | " u_t = diff(u)\n", 409 | " u_tt = diff(u_t)\n", 410 | " return -t * jnp.cos(2 * jnp.pi * t) + u_t(t) + u_tt(t)\n", 411 | "\n", 412 | "\n", 413 | "def loss_func(model, colloc, conds):\n", 414 | " t_c = colloc[:, [0]]\n", 415 | " ufunc = model\n", 416 | " ufunc_t = diff(model)\n", 417 | "\n", 418 | " loss = jnp.mean(ode_loss(t_c, ufunc) ** 2)\n", 419 | "\n", 420 | " t_ic, u_ic = conds[0][:, [0]], conds[0][:, [1]]\n", 421 | " loss += mse(u_ic, ufunc(t_ic))\n", 422 | "\n", 423 | " t_bc, u_bc = conds[1][:, [0]], conds[1][:, [1]]\n", 424 | " loss += mse(u_bc, ufunc_t(t_bc))\n", 425 | "\n", 426 | " return loss\n", 427 | "\n", 428 | "\n", 429 | "optim = optax.adam(1e-3)\n", 430 | "optim_state = optim.init(model)\n", 431 | "\n", 432 | "\n", 433 | "@jax.jit\n", 434 | "def train_step(\n", 435 | " model: MLP,\n", 436 | " optim_state: optax.OptState,\n", 437 | " colloc: jax.Array,\n", 438 | " conds: list[jax.Array],\n", 439 | "):\n", 440 | " # Get the gradient w.r.t to MLP params\n", 441 | " grads = jax.grad(loss_func)(model, colloc, conds)\n", 442 | "\n", 443 | " # Update model\n", 444 | " updates, optim_state = optim.update(grads, optim_state)\n", 445 | " model = optax.apply_updates(model, updates)\n", 446 | "\n", 447 | " return model, optim_state" 448 | ] 449 | }, 450 | { 451 | "cell_type": "code", 452 | "execution_count": 12, 453 | "metadata": { 454 | "id": "kBzGA8OVc8C6", 455 | "colab": { 456 | "base_uri": "https://localhost:8080/", 457 | "height": 1000, 458 | "referenced_widgets": [ 459 | "271df676bcac4937bada71edccf32886", 460 | "ee8a741f598f4dc7b751f21b2e975bf7", 461 | "cad59966e8754537bfb7f8ef5d8289ac", 462 | "949e74fbeb5d4892a5b3b47cacfde5c5", 463 | "8189284ea2fc475192db86f14b63580a", 464 | "2285fe8ee81e45229e30ddd255357255", 465 | "5f82eb29bbd64344b93a1f9565397184", 466 | "b47d9843e3894611a631df2b46cc9ac0", 467 | "0df7710f34444afbba03b6232de3e1fd", 468 | "e193d91f0e414ec7b527d9c0ebd47558", 469 | "43561c163e1f4dec929eac0ead24d266" 470 | ] 471 | }, 472 | "outputId": "8e5ce4f3-6102-435b-ec4b-62d519d6178d" 473 | }, 474 | "outputs": [ 475 | { 476 | "output_type": "display_data", 477 | "data": { 478 | "text/plain": [ 479 | " 0%| | 0/10000 [00:00" 640 | ] 641 | }, 642 | "metadata": {}, 643 | "execution_count": 13 644 | }, 645 | { 646 | "output_type": "display_data", 647 | "data": { 648 | "text/plain": [ 649 | "
" 650 | ], 651 | "image/png": "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\n" 652 | }, 653 | "metadata": {} 654 | } 655 | ] 656 | } 657 | ], 658 | "metadata": { 659 | "colab": { 660 | "name": "[1] ODE-PINN-ClassForm.ipynb", 661 | "provenance": [], 662 | "include_colab_link": true 663 | }, 664 | "kernelspec": { 665 | "display_name": "Python 3.8.9 64-bit", 666 | "language": "python", 667 | "name": "python3" 668 | }, 669 | "language_info": { 670 | "codemirror_mode": { 671 | "name": "ipython", 672 | "version": 3 673 | }, 674 | "file_extension": ".py", 675 | "mimetype": "text/x-python", 676 | "name": "python", 677 | "nbconvert_exporter": "python", 678 | "pygments_lexer": "ipython3", 679 | "version": "3.8.9" 680 | }, 681 | "vscode": { 682 | "interpreter": { 683 | "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" 684 | } 685 | }, 686 | "widgets": { 687 | "application/vnd.jupyter.widget-state+json": { 688 | "271df676bcac4937bada71edccf32886": { 689 | "model_module": "@jupyter-widgets/controls", 690 | "model_name": "HBoxModel", 691 | "model_module_version": "1.5.0", 692 | "state": { 693 | "_dom_classes": [], 694 | "_model_module": "@jupyter-widgets/controls", 695 | "_model_module_version": "1.5.0", 696 | "_model_name": "HBoxModel", 697 | "_view_count": null, 698 | "_view_module": "@jupyter-widgets/controls", 699 | "_view_module_version": "1.5.0", 700 | "_view_name": "HBoxView", 701 | "box_style": "", 702 | "children": [ 703 | "IPY_MODEL_ee8a741f598f4dc7b751f21b2e975bf7", 704 | "IPY_MODEL_cad59966e8754537bfb7f8ef5d8289ac", 705 | "IPY_MODEL_949e74fbeb5d4892a5b3b47cacfde5c5" 706 | ], 707 | "layout": "IPY_MODEL_8189284ea2fc475192db86f14b63580a" 708 | } 709 | }, 710 | "ee8a741f598f4dc7b751f21b2e975bf7": { 711 | "model_module": "@jupyter-widgets/controls", 712 | "model_name": "HTMLModel", 713 | "model_module_version": "1.5.0", 714 | "state": { 715 | "_dom_classes": [], 716 | "_model_module": "@jupyter-widgets/controls", 717 | "_model_module_version": "1.5.0", 718 | "_model_name": "HTMLModel", 719 | "_view_count": null, 720 | "_view_module": "@jupyter-widgets/controls", 721 | "_view_module_version": "1.5.0", 722 | "_view_name": "HTMLView", 723 | "description": "", 724 | "description_tooltip": null, 725 | "layout": "IPY_MODEL_2285fe8ee81e45229e30ddd255357255", 726 | "placeholder": "​", 727 | "style": "IPY_MODEL_5f82eb29bbd64344b93a1f9565397184", 728 | "value": "100%" 729 | } 730 | }, 731 | "cad59966e8754537bfb7f8ef5d8289ac": { 732 | "model_module": "@jupyter-widgets/controls", 733 | "model_name": "FloatProgressModel", 734 | "model_module_version": "1.5.0", 735 | "state": { 736 | "_dom_classes": [], 737 | "_model_module": "@jupyter-widgets/controls", 738 | "_model_module_version": "1.5.0", 739 | "_model_name": "FloatProgressModel", 740 | "_view_count": null, 741 | "_view_module": "@jupyter-widgets/controls", 742 | "_view_module_version": "1.5.0", 743 | "_view_name": "ProgressView", 744 | "bar_style": "success", 745 | "description": "", 746 | "description_tooltip": null, 747 | "layout": "IPY_MODEL_b47d9843e3894611a631df2b46cc9ac0", 748 | "max": 10000, 749 | "min": 0, 750 | "orientation": "horizontal", 751 | "style": "IPY_MODEL_0df7710f34444afbba03b6232de3e1fd", 752 | "value": 10000 753 | } 754 | }, 755 | "949e74fbeb5d4892a5b3b47cacfde5c5": { 756 | "model_module": "@jupyter-widgets/controls", 757 | "model_name": "HTMLModel", 758 | "model_module_version": "1.5.0", 759 | "state": { 760 | "_dom_classes": [], 761 | "_model_module": "@jupyter-widgets/controls", 762 | "_model_module_version": "1.5.0", 763 | "_model_name": "HTMLModel", 764 | "_view_count": null, 765 | "_view_module": "@jupyter-widgets/controls", 766 | "_view_module_version": "1.5.0", 767 | "_view_name": "HTMLView", 768 | "description": "", 769 | "description_tooltip": null, 770 | "layout": "IPY_MODEL_e193d91f0e414ec7b527d9c0ebd47558", 771 | "placeholder": "​", 772 | "style": "IPY_MODEL_43561c163e1f4dec929eac0ead24d266", 773 | "value": " 10000/10000 [00:29<00:00, 886.65it/s]" 774 | } 775 | }, 776 | "8189284ea2fc475192db86f14b63580a": { 777 | "model_module": "@jupyter-widgets/base", 778 | "model_name": "LayoutModel", 779 | "model_module_version": "1.2.0", 780 | "state": { 781 | "_model_module": "@jupyter-widgets/base", 782 | "_model_module_version": "1.2.0", 783 | "_model_name": "LayoutModel", 784 | "_view_count": null, 785 | "_view_module": "@jupyter-widgets/base", 786 | "_view_module_version": "1.2.0", 787 | "_view_name": "LayoutView", 788 | "align_content": null, 789 | "align_items": null, 790 | "align_self": null, 791 | "border": null, 792 | "bottom": null, 793 | "display": null, 794 | "flex": null, 795 | "flex_flow": null, 796 | "grid_area": null, 797 | "grid_auto_columns": null, 798 | "grid_auto_flow": null, 799 | "grid_auto_rows": null, 800 | "grid_column": null, 801 | "grid_gap": null, 802 | "grid_row": null, 803 | "grid_template_areas": null, 804 | "grid_template_columns": null, 805 | "grid_template_rows": null, 806 | "height": null, 807 | "justify_content": null, 808 | "justify_items": null, 809 | "left": null, 810 | "margin": null, 811 | "max_height": null, 812 | "max_width": null, 813 | "min_height": null, 814 | "min_width": null, 815 | "object_fit": null, 816 | "object_position": null, 817 | "order": null, 818 | "overflow": null, 819 | "overflow_x": null, 820 | "overflow_y": null, 821 | "padding": null, 822 | "right": null, 823 | "top": null, 824 | "visibility": null, 825 | "width": null 826 | } 827 | }, 828 | "2285fe8ee81e45229e30ddd255357255": { 829 | "model_module": "@jupyter-widgets/base", 830 | "model_name": "LayoutModel", 831 | "model_module_version": "1.2.0", 832 | "state": { 833 | "_model_module": "@jupyter-widgets/base", 834 | "_model_module_version": "1.2.0", 835 | "_model_name": "LayoutModel", 836 | "_view_count": null, 837 | "_view_module": "@jupyter-widgets/base", 838 | "_view_module_version": "1.2.0", 839 | "_view_name": "LayoutView", 840 | "align_content": null, 841 | "align_items": null, 842 | "align_self": null, 843 | "border": null, 844 | "bottom": null, 845 | "display": null, 846 | "flex": null, 847 | "flex_flow": null, 848 | "grid_area": null, 849 | "grid_auto_columns": null, 850 | "grid_auto_flow": null, 851 | "grid_auto_rows": null, 852 | "grid_column": null, 853 | "grid_gap": null, 854 | "grid_row": null, 855 | "grid_template_areas": null, 856 | "grid_template_columns": null, 857 | "grid_template_rows": null, 858 | "height": null, 859 | "justify_content": null, 860 | "justify_items": null, 861 | "left": null, 862 | "margin": null, 863 | "max_height": null, 864 | "max_width": null, 865 | "min_height": null, 866 | "min_width": null, 867 | "object_fit": null, 868 | "object_position": null, 869 | "order": null, 870 | "overflow": null, 871 | "overflow_x": null, 872 | "overflow_y": null, 873 | "padding": null, 874 | "right": null, 875 | "top": null, 876 | "visibility": null, 877 | "width": null 878 | } 879 | }, 880 | "5f82eb29bbd64344b93a1f9565397184": { 881 | "model_module": "@jupyter-widgets/controls", 882 | "model_name": "DescriptionStyleModel", 883 | "model_module_version": "1.5.0", 884 | "state": { 885 | "_model_module": "@jupyter-widgets/controls", 886 | "_model_module_version": "1.5.0", 887 | "_model_name": "DescriptionStyleModel", 888 | "_view_count": null, 889 | "_view_module": "@jupyter-widgets/base", 890 | "_view_module_version": "1.2.0", 891 | "_view_name": "StyleView", 892 | "description_width": "" 893 | } 894 | }, 895 | "b47d9843e3894611a631df2b46cc9ac0": { 896 | "model_module": "@jupyter-widgets/base", 897 | "model_name": "LayoutModel", 898 | "model_module_version": "1.2.0", 899 | "state": { 900 | "_model_module": "@jupyter-widgets/base", 901 | "_model_module_version": "1.2.0", 902 | "_model_name": "LayoutModel", 903 | "_view_count": null, 904 | "_view_module": "@jupyter-widgets/base", 905 | "_view_module_version": "1.2.0", 906 | "_view_name": "LayoutView", 907 | "align_content": null, 908 | "align_items": null, 909 | "align_self": null, 910 | "border": null, 911 | "bottom": null, 912 | "display": null, 913 | "flex": null, 914 | "flex_flow": null, 915 | "grid_area": null, 916 | "grid_auto_columns": null, 917 | "grid_auto_flow": null, 918 | "grid_auto_rows": null, 919 | "grid_column": null, 920 | "grid_gap": null, 921 | "grid_row": null, 922 | "grid_template_areas": null, 923 | "grid_template_columns": null, 924 | "grid_template_rows": null, 925 | "height": null, 926 | "justify_content": null, 927 | "justify_items": null, 928 | "left": null, 929 | "margin": null, 930 | "max_height": null, 931 | "max_width": null, 932 | "min_height": null, 933 | "min_width": null, 934 | "object_fit": null, 935 | "object_position": null, 936 | "order": null, 937 | "overflow": null, 938 | "overflow_x": null, 939 | "overflow_y": null, 940 | "padding": null, 941 | "right": null, 942 | "top": null, 943 | "visibility": null, 944 | "width": null 945 | } 946 | }, 947 | "0df7710f34444afbba03b6232de3e1fd": { 948 | "model_module": "@jupyter-widgets/controls", 949 | "model_name": "ProgressStyleModel", 950 | "model_module_version": "1.5.0", 951 | "state": { 952 | "_model_module": "@jupyter-widgets/controls", 953 | "_model_module_version": "1.5.0", 954 | "_model_name": "ProgressStyleModel", 955 | "_view_count": null, 956 | "_view_module": "@jupyter-widgets/base", 957 | "_view_module_version": "1.2.0", 958 | "_view_name": "StyleView", 959 | "bar_color": null, 960 | "description_width": "" 961 | } 962 | }, 963 | "e193d91f0e414ec7b527d9c0ebd47558": { 964 | "model_module": "@jupyter-widgets/base", 965 | "model_name": "LayoutModel", 966 | "model_module_version": "1.2.0", 967 | "state": { 968 | "_model_module": "@jupyter-widgets/base", 969 | "_model_module_version": "1.2.0", 970 | "_model_name": "LayoutModel", 971 | "_view_count": null, 972 | "_view_module": "@jupyter-widgets/base", 973 | "_view_module_version": "1.2.0", 974 | "_view_name": "LayoutView", 975 | "align_content": null, 976 | "align_items": null, 977 | "align_self": null, 978 | "border": null, 979 | "bottom": null, 980 | "display": null, 981 | "flex": null, 982 | "flex_flow": null, 983 | "grid_area": null, 984 | "grid_auto_columns": null, 985 | "grid_auto_flow": null, 986 | "grid_auto_rows": null, 987 | "grid_column": null, 988 | "grid_gap": null, 989 | "grid_row": null, 990 | "grid_template_areas": null, 991 | "grid_template_columns": null, 992 | "grid_template_rows": null, 993 | "height": null, 994 | "justify_content": null, 995 | "justify_items": null, 996 | "left": null, 997 | "margin": null, 998 | "max_height": null, 999 | "max_width": null, 1000 | "min_height": null, 1001 | "min_width": null, 1002 | "object_fit": null, 1003 | "object_position": null, 1004 | "order": null, 1005 | "overflow": null, 1006 | "overflow_x": null, 1007 | "overflow_y": null, 1008 | "padding": null, 1009 | "right": null, 1010 | "top": null, 1011 | "visibility": null, 1012 | "width": null 1013 | } 1014 | }, 1015 | "43561c163e1f4dec929eac0ead24d266": { 1016 | "model_module": "@jupyter-widgets/controls", 1017 | "model_name": "DescriptionStyleModel", 1018 | "model_module_version": "1.5.0", 1019 | "state": { 1020 | "_model_module": "@jupyter-widgets/controls", 1021 | "_model_module_version": "1.5.0", 1022 | "_model_name": "DescriptionStyleModel", 1023 | "_view_count": null, 1024 | "_view_module": "@jupyter-widgets/base", 1025 | "_view_module_version": "1.2.0", 1026 | "_view_name": "StyleView", 1027 | "description_width": "" 1028 | } 1029 | } 1030 | } 1031 | } 1032 | }, 1033 | "nbformat": 4, 1034 | "nbformat_minor": 0 1035 | } -------------------------------------------------------------------------------- /[5]_System_of_ODEs_PINN.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "view-in-github" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": 1, 16 | "metadata": { 17 | "id": "v77fdC1ZLyg1" 18 | }, 19 | "outputs": [], 20 | "source": [ 21 | "#Credits : Mahmoud Asem @Asem000 October 2021" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 2, 27 | "metadata": { 28 | "colab": { 29 | "base_uri": "https://localhost:8080/" 30 | }, 31 | "id": "vAR0swbLX_ZI", 32 | "outputId": "97823711-ee53-4921-bf97-c2f9a312e57f" 33 | }, 34 | "outputs": [ 35 | { 36 | "name": "stdout", 37 | "output_type": "stream", 38 | "text": [ 39 | "Requirement already satisfied: optax in /usr/local/lib/python3.7/dist-packages (0.0.9)\n", 40 | "Requirement already satisfied: absl-py>=0.7.1 in /usr/local/lib/python3.7/dist-packages (from optax) (0.12.0)\n", 41 | "Requirement already satisfied: jax>=0.1.55 in /usr/local/lib/python3.7/dist-packages (from optax) (0.2.21)\n", 42 | "Requirement already satisfied: numpy>=1.18.0 in /usr/local/lib/python3.7/dist-packages (from optax) (1.19.5)\n", 43 | "Requirement already satisfied: chex>=0.0.4 in /usr/local/lib/python3.7/dist-packages (from optax) (0.0.8)\n", 44 | "Requirement already satisfied: jaxlib>=0.1.37 in /usr/local/lib/python3.7/dist-packages (from optax) (0.1.71+cuda111)\n", 45 | "Requirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from absl-py>=0.7.1->optax) (1.15.0)\n", 46 | "Requirement already satisfied: toolz>=0.9.0 in /usr/local/lib/python3.7/dist-packages (from chex>=0.0.4->optax) (0.11.1)\n", 47 | "Requirement already satisfied: dm-tree>=0.1.5 in /usr/local/lib/python3.7/dist-packages (from chex>=0.0.4->optax) (0.1.6)\n", 48 | "Requirement already satisfied: opt-einsum in /usr/local/lib/python3.7/dist-packages (from jax>=0.1.55->optax) (3.3.0)\n", 49 | "Requirement already satisfied: scipy>=1.2.1 in /usr/local/lib/python3.7/dist-packages (from jax>=0.1.55->optax) (1.4.1)\n", 50 | "Requirement already satisfied: flatbuffers<3.0,>=1.12 in /usr/local/lib/python3.7/dist-packages (from jaxlib>=0.1.37->optax) (1.12)\n", 51 | "Requirement already satisfied: numba in /usr/local/lib/python3.7/dist-packages (0.51.2)\n", 52 | "Requirement already satisfied: numpy>=1.15 in /usr/local/lib/python3.7/dist-packages (from numba) (1.19.5)\n", 53 | "Requirement already satisfied: setuptools in /usr/local/lib/python3.7/dist-packages (from numba) (57.4.0)\n", 54 | "Requirement already satisfied: llvmlite<0.35,>=0.34.0.dev0 in /usr/local/lib/python3.7/dist-packages (from numba) (0.34.0)\n" 55 | ] 56 | } 57 | ], 58 | "source": [ 59 | "#Imports\n", 60 | "import jax \n", 61 | "import jax.numpy as jnp\n", 62 | "import numpy as np\n", 63 | "import matplotlib.pyplot as plt\n", 64 | "from matplotlib import cm\n", 65 | "import matplotlib as mpl\n", 66 | "!pip install optax\n", 67 | "import optax\n", 68 | "!pip install numba\n", 69 | "import numba" 70 | ] 71 | }, 72 | { 73 | "cell_type": "markdown", 74 | "metadata": { 75 | "id": "7bg4nSbsXVwD" 76 | }, 77 | "source": [ 78 | "### System of ODEs numerical solution\n", 79 | "$\\large \\frac{dx}{dt} = x$
\n", 80 | "\n", 81 | "$\\large \\frac{dy}{dt} = x - y$
\n", 82 | "\n", 83 | "$x(t=0) = 1$\n", 84 | "\n", 85 | "$y(t=0) = 2$\n", 86 | "\n", 87 | "
\n", 88 | "$\\text{analytical solution}$\n", 89 | "\n", 90 | "$x(t) = e^{t}$\n", 91 | "\n", 92 | "$y(t) = \\frac{1}{2} e^{t} + \\frac{3}{2} e^{-t}$" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": { 98 | "id": "K89DstaYpwh0" 99 | }, 100 | "source": [] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 3, 105 | "metadata": { 106 | "id": "8uW0HW1-pxl8" 107 | }, 108 | "outputs": [], 109 | "source": [ 110 | "'''\n", 111 | "\n", 112 | "solve \n", 113 | "dx/dt = x\n", 114 | "dy/dt = x-y\n", 115 | "\n", 116 | "x(0) = 1\n", 117 | "y(0) = 2\n", 118 | "\n", 119 | "solution =\n", 120 | "\n", 121 | "x(t) = exp(t)\n", 122 | "y(t) = 0.5*exp(t) +1.5*exp(-t)\n", 123 | "\n", 124 | "'''\n", 125 | "\n", 126 | "@numba.njit\n", 127 | "def RK4(odefun,ics,h,span,degree):\n", 128 | " \n", 129 | " N= int( (span[1]-span[0])/h )\n", 130 | " \n", 131 | " tY = np.zeros((N+1,degree+1))\n", 132 | " tY[0,1:] = ics\n", 133 | " \n", 134 | " \n", 135 | " for i in range(N):\n", 136 | " tY[i+1,0] = tY[i,0] + h\n", 137 | "\n", 138 | " k1= odefun(tY[i,0] , tY[i,1:])\n", 139 | " k2= odefun(tY[i,0] +(h/2), tY[i,1:] +(h*k1)/2 )\n", 140 | " k3= odefun(tY[i,0] +(h/2), tY[i,1:] +(h*k2)/2)\n", 141 | " k4= odefun(tY[i,0] +(h) , tY[i,1:] +(h*k3))\n", 142 | " \n", 143 | " tY[i+1,1:] = tY[i,1:] + h*(1/6) * (k1+2*k2+2*k3+k4)\n", 144 | " \n", 145 | " return tY[:,0],tY[:,1:]\n", 146 | "\n", 147 | "@numba.njit\n", 148 | "def system_of_ode(t,V):\n", 149 | " y1,y2 = V[0],V[1]\n", 150 | " return np.array([y1,y1-y2])\n", 151 | "\n", 152 | "t,y=RK4(system_of_ode,\n", 153 | " ics=np.array([1,2]),\n", 154 | " h=1e-3,\n", 155 | " span=np.array([1e-4,np.pi]),\n", 156 | " degree =2)" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": 4, 162 | "metadata": { 163 | "colab": { 164 | "base_uri": "https://localhost:8080/", 165 | "height": 282 166 | }, 167 | "id": "bNctv_EFp-yD", 168 | "outputId": "9ede81ec-108c-4d4b-f928-d0c2493aea0c" 169 | }, 170 | "outputs": [ 171 | { 172 | "data": { 173 | "text/plain": [ 174 | "" 175 | ] 176 | }, 177 | "execution_count": 4, 178 | "metadata": {}, 179 | "output_type": "execute_result" 180 | }, 181 | { 182 | "data": { 183 | "image/png": "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", 184 | "text/plain": [ 185 | "
" 186 | ] 187 | }, 188 | "metadata": { 189 | "needs_background": "light" 190 | }, 191 | "output_type": "display_data" 192 | } 193 | ], 194 | "source": [ 195 | "plt.plot(t,y[:,0],'-r',label='RK4[1]')\n", 196 | "plt.plot(t,np.exp(t),'--k',label='Analytical[1]')\n", 197 | "\n", 198 | "plt.plot(t,y[:,1],'-g',label='RK4[2]')\n", 199 | "plt.plot(t,0.5*np.exp(t)+1.5*np.exp(-t),'--b',label='Analytical[2]')\n", 200 | "\n", 201 | "plt.legend()" 202 | ] 203 | }, 204 | { 205 | "cell_type": "markdown", 206 | "metadata": { 207 | "id": "NQ61lEQeXgrc" 208 | }, 209 | "source": [ 210 | "### Constructing the MLP" 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": 5, 216 | "metadata": { 217 | "colab": { 218 | "base_uri": "https://localhost:8080/" 219 | }, 220 | "id": "Lml6PGLPZgmr", 221 | "outputId": "aaa25445-8e2d-4540-8cf3-20d6e5404fc8" 222 | }, 223 | "outputs": [ 224 | { 225 | "name": "stderr", 226 | "output_type": "stream", 227 | "text": [ 228 | "WARNING:absl:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)\n" 229 | ] 230 | } 231 | ], 232 | "source": [ 233 | "N_b = 1_000\n", 234 | "N_c = 10_000\n", 235 | "\n", 236 | "tmin,tmax=0. ,jnp.pi\n", 237 | "\n", 238 | "'''boundary conditions'''\n", 239 | "\n", 240 | "\n", 241 | "# y1[0] = 1\n", 242 | "y1_t0 = jnp.zeros([N_b,1],dtype='float32')\n", 243 | "y1_ic = jnp.ones_like(y1_t0) \n", 244 | "Y1_IC = jnp.concatenate([y1_t0,y1_ic],axis=1)\n", 245 | "\n", 246 | "# y2[0] = 2\n", 247 | "y2_t0 = jnp.zeros([N_b,1],dtype='float32')\n", 248 | "y2_ic = jnp.ones_like(y2_t0) * 2\n", 249 | "Y2_IC = jnp.concatenate([y2_t0,y2_ic],axis=1)\n", 250 | "\n", 251 | "conds = [Y1_IC,Y2_IC]\n", 252 | "\n", 253 | "#collocation points\n", 254 | "\n", 255 | "key=jax.random.PRNGKey(0)\n", 256 | "\n", 257 | "t_c = jax.random.uniform(key,minval=tmin,maxval=tmax,shape=(N_c,1))\n", 258 | "colloc = t_c\n", 259 | "\n", 260 | "def ODE_loss(t,y1,y2):\n", 261 | "\n", 262 | " y1_t=lambda t:jax.grad(lambda t:jnp.sum(y1(t)))(t)\n", 263 | " y2_t=lambda t:jax.grad(lambda t:jnp.sum(y2(t)))(t)\n", 264 | "\n", 265 | " return y1_t(t) - y1(t) , y2_t(t) - y1(t) + y2(t)\n" 266 | ] 267 | }, 268 | { 269 | "cell_type": "code", 270 | "execution_count": 6, 271 | "metadata": { 272 | "id": "KoZZJl2TbI_n" 273 | }, 274 | "outputs": [], 275 | "source": [ 276 | "def init_params(layers):\n", 277 | " keys = jax.random.split(jax.random.PRNGKey(0),len(layers)-1)\n", 278 | " params = list()\n", 279 | " for key,n_in,n_out in zip(keys,layers[:-1],layers[1:]):\n", 280 | " lb, ub = -(1 / jnp.sqrt(n_in)), (1 / jnp.sqrt(n_in)) # xavier initialization lower and upper bound\n", 281 | " W = lb + (ub-lb) * jax.random.uniform(key,shape=(n_in,n_out))\n", 282 | " B = jax.random.uniform(key,shape=(n_out,))\n", 283 | " params.append({'W':W,'B':B})\n", 284 | " return params\n", 285 | "\n", 286 | "def fwd(params,t):\n", 287 | " X = jnp.concatenate([t],axis=1)\n", 288 | " *hidden,last = params\n", 289 | " for layer in hidden :\n", 290 | " X = jax.nn.tanh(X@layer['W']+layer['B'])\n", 291 | " return X@last['W'] + last['B']\n", 292 | "\n", 293 | "@jax.jit\n", 294 | "def MSE(true,pred):\n", 295 | " return jnp.mean((true-pred)**2)\n", 296 | "\n", 297 | "def loss_fun(params,colloc,conds):\n", 298 | " t_c =colloc[:,[0]]\n", 299 | "\n", 300 | " y1_func = lambda t : fwd(params,t)[:,[0]]\n", 301 | " y1_func_t=lambda t:jax.grad(lambda t:jnp.sum(y1_func(t)))(t)\n", 302 | "\n", 303 | " y2_func = lambda t : fwd(params,t)[:,[1]]\n", 304 | " y2_func_t=lambda t:jax.grad(lambda t:jnp.sum(y2_func(t)))(t)\n", 305 | "\n", 306 | " loss_y1,loss_y2 =ODE_loss(t_c,y1_func,y2_func)\n", 307 | "\n", 308 | " loss = jnp.mean( loss_y1 **2) \n", 309 | " loss+= jnp.mean(loss_y2 **2)\n", 310 | "\n", 311 | " t_ic,y1_ic = conds[0][:,[0]],conds[0][:,[1]] \n", 312 | " loss += MSE(y1_ic,y1_func(t_ic))\n", 313 | "\n", 314 | " t_ic,y2_ic = conds[1][:,[0]],conds[1][:,[1]] \n", 315 | " loss += MSE(y2_ic,y2_func(t_ic))\n", 316 | "\n", 317 | " return loss\n", 318 | "\n", 319 | "@jax.jit\n", 320 | "def update(opt_state,params,colloc,conds):\n", 321 | " # Get the gradient w.r.t to MLP params\n", 322 | " grads=jax.jit(jax.grad(loss_fun,0))(params,colloc,conds)\n", 323 | " \n", 324 | " #Update params\n", 325 | " updates, opt_state = optimizer.update(grads, opt_state)\n", 326 | " params = optax.apply_updates(params, updates)\n", 327 | "\n", 328 | " #Update params\n", 329 | " # return jax.tree_multimap(lambda params,grads : params-LR*grads, params,grads)\n", 330 | " return opt_state,params\n" 331 | ] 332 | }, 333 | { 334 | "cell_type": "code", 335 | "execution_count": 7, 336 | "metadata": { 337 | "id": "ae1ZDoy0c29c" 338 | }, 339 | "outputs": [], 340 | "source": [ 341 | "# construct the MLP of 6 hidden layers of 8 neurons for each layer\n", 342 | "params = init_params([1] + [8]*2+[2])" 343 | ] 344 | }, 345 | { 346 | "cell_type": "code", 347 | "execution_count": 8, 348 | "metadata": { 349 | "id": "jySmbUwic5yk" 350 | }, 351 | "outputs": [], 352 | "source": [ 353 | "optimizer = optax.adam(1e-2)\n", 354 | "opt_state = optimizer.init(params)" 355 | ] 356 | }, 357 | { 358 | "cell_type": "code", 359 | "execution_count": 9, 360 | "metadata": { 361 | "colab": { 362 | "base_uri": "https://localhost:8080/" 363 | }, 364 | "id": "VS0bosXPg1Oo", 365 | "outputId": "258603fc-cb6e-4dcb-eb86-4560004b71e2" 366 | }, 367 | "outputs": [ 368 | { 369 | "data": { 370 | "text/plain": [ 371 | "(10000, 1)" 372 | ] 373 | }, 374 | "execution_count": 9, 375 | "metadata": {}, 376 | "output_type": "execute_result" 377 | } 378 | ], 379 | "source": [ 380 | "fwd(params,t_c)[:,[0]].shape" 381 | ] 382 | }, 383 | { 384 | "cell_type": "code", 385 | "execution_count": 10, 386 | "metadata": { 387 | "colab": { 388 | "base_uri": "https://localhost:8080/" 389 | }, 390 | "id": "kBzGA8OVc8C6", 391 | "outputId": "7dda4b83-5d7e-497c-fb98-64e7b1322528" 392 | }, 393 | "outputs": [ 394 | { 395 | "name": "stdout", 396 | "output_type": "stream", 397 | "text": [ 398 | "Epoch=0\tloss=4.391e+00\n", 399 | "Epoch=100\tloss=3.921e-01\n", 400 | "Epoch=200\tloss=3.891e-01\n", 401 | "Epoch=300\tloss=3.876e-01\n", 402 | "Epoch=400\tloss=3.866e-01\n", 403 | "Epoch=500\tloss=3.855e-01\n", 404 | "Epoch=600\tloss=3.840e-01\n", 405 | "Epoch=700\tloss=3.820e-01\n", 406 | "Epoch=800\tloss=3.788e-01\n", 407 | "Epoch=900\tloss=3.726e-01\n", 408 | "Epoch=1000\tloss=3.555e-01\n", 409 | "Epoch=1100\tloss=3.070e-01\n", 410 | "Epoch=1200\tloss=2.254e-01\n", 411 | "Epoch=1300\tloss=1.834e-01\n", 412 | "Epoch=1400\tloss=1.354e-01\n", 413 | "Epoch=1500\tloss=1.085e-01\n", 414 | "Epoch=1600\tloss=8.198e-02\n", 415 | "Epoch=1700\tloss=6.454e-02\n", 416 | "Epoch=1800\tloss=5.201e-02\n", 417 | "Epoch=1900\tloss=4.232e-02\n", 418 | "Epoch=2000\tloss=3.476e-02\n", 419 | "Epoch=2100\tloss=2.897e-02\n", 420 | "Epoch=2200\tloss=2.339e-02\n", 421 | "Epoch=2300\tloss=1.980e-02\n", 422 | "Epoch=2400\tloss=1.632e-02\n", 423 | "Epoch=2500\tloss=1.425e-02\n", 424 | "Epoch=2600\tloss=1.194e-02\n", 425 | "Epoch=2700\tloss=1.174e-02\n", 426 | "Epoch=2800\tloss=9.231e-03\n", 427 | "Epoch=2900\tloss=7.939e-03\n", 428 | "Epoch=3000\tloss=7.260e-03\n", 429 | "Epoch=3100\tloss=6.298e-03\n", 430 | "Epoch=3200\tloss=7.007e-02\n", 431 | "Epoch=3300\tloss=5.132e-03\n", 432 | "Epoch=3400\tloss=4.541e-03\n", 433 | "Epoch=3500\tloss=5.706e-03\n", 434 | "Epoch=3600\tloss=3.834e-03\n", 435 | "Epoch=3700\tloss=3.433e-03\n", 436 | "Epoch=3800\tloss=3.316e-03\n", 437 | "Epoch=3900\tloss=2.964e-03\n", 438 | "Epoch=4000\tloss=2.688e-03\n", 439 | "Epoch=4100\tloss=2.604e-03\n", 440 | "Epoch=4200\tloss=2.364e-03\n", 441 | "Epoch=4300\tloss=1.091e-01\n", 442 | "Epoch=4400\tloss=2.085e-03\n", 443 | "Epoch=4500\tloss=1.907e-03\n", 444 | "Epoch=4600\tloss=2.153e-03\n", 445 | "Epoch=4700\tloss=1.716e-03\n", 446 | "Epoch=4800\tloss=1.577e-03\n", 447 | "Epoch=4900\tloss=1.593e-03\n", 448 | "Epoch=5000\tloss=1.462e-03\n", 449 | "Epoch=5100\tloss=1.348e-03\n", 450 | "Epoch=5200\tloss=1.934e-03\n", 451 | "Epoch=5300\tloss=1.247e-03\n", 452 | "Epoch=5400\tloss=1.154e-03\n", 453 | "Epoch=5500\tloss=1.163e-03\n", 454 | "Epoch=5600\tloss=1.062e-03\n", 455 | "Epoch=5700\tloss=6.481e-03\n", 456 | "Epoch=5800\tloss=9.879e-04\n", 457 | "Epoch=5900\tloss=9.198e-04\n", 458 | "Epoch=6000\tloss=9.548e-04\n", 459 | "Epoch=6100\tloss=8.567e-04\n", 460 | "Epoch=6200\tloss=5.164e-03\n", 461 | "Epoch=6300\tloss=8.136e-04\n", 462 | "Epoch=6400\tloss=7.632e-04\n", 463 | "Epoch=6500\tloss=8.119e-04\n", 464 | "Epoch=6600\tloss=7.259e-04\n", 465 | "Epoch=6700\tloss=6.844e-04\n", 466 | "Epoch=6800\tloss=6.932e-04\n", 467 | "Epoch=6900\tloss=6.498e-04\n", 468 | "Epoch=7000\tloss=1.022e-02\n", 469 | "Epoch=7100\tloss=6.268e-04\n", 470 | "Epoch=7200\tloss=5.936e-04\n", 471 | "Epoch=7300\tloss=3.431e-03\n", 472 | "Epoch=7400\tloss=5.711e-04\n", 473 | "Epoch=7500\tloss=5.428e-04\n", 474 | "Epoch=7600\tloss=6.806e-04\n", 475 | "Epoch=7700\tloss=5.217e-04\n", 476 | "Epoch=7800\tloss=7.266e-03\n", 477 | "Epoch=7900\tloss=5.146e-04\n", 478 | "Epoch=8000\tloss=4.886e-04\n", 479 | "Epoch=8100\tloss=1.107e-03\n", 480 | "Epoch=8200\tloss=4.893e-04\n", 481 | "Epoch=8300\tloss=4.574e-04\n", 482 | "Epoch=8400\tloss=9.877e-02\n", 483 | "Epoch=8500\tloss=4.501e-04\n", 484 | "Epoch=8600\tloss=4.283e-04\n", 485 | "Epoch=8700\tloss=2.029e-03\n", 486 | "Epoch=8800\tloss=4.216e-04\n", 487 | "Epoch=8900\tloss=4.044e-04\n", 488 | "Epoch=9000\tloss=4.368e-04\n", 489 | "Epoch=9100\tloss=4.015e-04\n", 490 | "Epoch=9200\tloss=3.859e-04\n", 491 | "Epoch=9300\tloss=1.088e-03\n", 492 | "Epoch=9400\tloss=3.847e-04\n", 493 | "Epoch=9500\tloss=3.701e-04\n", 494 | "Epoch=9600\tloss=7.795e-04\n", 495 | "Epoch=9700\tloss=3.653e-04\n", 496 | "Epoch=9800\tloss=8.272e-02\n", 497 | "Epoch=9900\tloss=3.632e-04\n", 498 | "CPU times: user 1min 39s, sys: 2.21 s, total: 1min 41s\n", 499 | "Wall time: 1min 31s\n" 500 | ] 501 | } 502 | ], 503 | "source": [ 504 | "%%time\n", 505 | "epochs = 10_000\n", 506 | "for _ in range(epochs):\n", 507 | " opt_state,params = update(opt_state,params,colloc,conds)\n", 508 | "\n", 509 | " # print loss and epoch info\n", 510 | " if _ %(100) ==0:\n", 511 | " print(f'Epoch={_}\\tloss={loss_fun(params,colloc,conds):.3e}')" 512 | ] 513 | }, 514 | { 515 | "cell_type": "code", 516 | "execution_count": 11, 517 | "metadata": { 518 | "colab": { 519 | "base_uri": "https://localhost:8080/", 520 | "height": 282 521 | }, 522 | "id": "eWeNvDsdDEuI", 523 | "outputId": "3ca4560a-ca9f-451f-db9d-0b61e081cfa2" 524 | }, 525 | "outputs": [ 526 | { 527 | "data": { 528 | "text/plain": [ 529 | "" 530 | ] 531 | }, 532 | "execution_count": 11, 533 | "metadata": {}, 534 | "output_type": "execute_result" 535 | }, 536 | { 537 | "data": { 538 | "image/png": "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", 539 | "text/plain": [ 540 | "
" 541 | ] 542 | }, 543 | "metadata": { 544 | "needs_background": "light" 545 | }, 546 | "output_type": "display_data" 547 | } 548 | ], 549 | "source": [ 550 | "dT = 1e-3\n", 551 | "Tf = jnp.pi\n", 552 | "T = np.arange(0,Tf+dT,dT)\n", 553 | "\n", 554 | "plt.plot(t,np.exp(t),'-b',label='Analytical[y1]')\n", 555 | "plt.plot(T,fwd(params,T.reshape(-1,1))[:,0],'--k',label='NN[y1]',linewidth=2)\n", 556 | "\n", 557 | "plt.plot(t,0.5*np.exp(t)+1.5*np.exp(-t),'-r',label='Analytical[y2]')\n", 558 | "plt.plot(T,fwd(params,T.reshape(-1,1))[:,1],'--k',label='NN[y2]',linewidth=2)\n", 559 | "\n", 560 | "plt.legend()" 561 | ] 562 | } 563 | ], 564 | "metadata": { 565 | "colab": { 566 | "collapsed_sections": [], 567 | "include_colab_link": true, 568 | "name": "[5] System-of-ODE-PINN.ipynb", 569 | "provenance": [] 570 | }, 571 | "kernelspec": { 572 | "display_name": "Python 3.8.9 64-bit", 573 | "language": "python", 574 | "name": "python3" 575 | }, 576 | "language_info": { 577 | "codemirror_mode": { 578 | "name": "ipython", 579 | "version": 3 580 | }, 581 | "file_extension": ".py", 582 | "mimetype": "text/x-python", 583 | "name": "python", 584 | "nbconvert_exporter": "python", 585 | "pygments_lexer": "ipython3", 586 | "version": "3.8.9" 587 | }, 588 | "vscode": { 589 | "interpreter": { 590 | "hash": "31f2aee4e71d21fbe5cf8b01ff0e069b9275f58929596ceb00d14d90e3e16cd6" 591 | } 592 | } 593 | }, 594 | "nbformat": 4, 595 | "nbformat_minor": 0 596 | } 597 | -------------------------------------------------------------------------------- /[6]_ODE_PINN_finite_difference.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "id": "view-in-github", 7 | "colab_type": "text" 8 | }, 9 | "source": [ 10 | "\"Open" 11 | ] 12 | }, 13 | { 14 | "cell_type": "code", 15 | "execution_count": null, 16 | "metadata": { 17 | "id": "v77fdC1ZLyg1" 18 | }, 19 | "outputs": [], 20 | "source": [ 21 | "#Credits : Mahmoud Asem @Asem000" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": null, 27 | "metadata": { 28 | "colab": { 29 | "base_uri": "https://localhost:8080/" 30 | }, 31 | "id": "vAR0swbLX_ZI", 32 | "outputId": "dab17b4c-908d-4213-ac91-c20d0f7ef122" 33 | }, 34 | "outputs": [ 35 | { 36 | "output_type": "stream", 37 | "name": "stdout", 38 | "text": [ 39 | "Requirement already satisfied: optax in /usr/local/lib/python3.7/dist-packages (0.1.1)\n", 40 | "Requirement already satisfied: numpy>=1.18.0 in /usr/local/lib/python3.7/dist-packages (from optax) (1.21.5)\n", 41 | "Requirement already satisfied: jaxlib>=0.1.37 in /usr/local/lib/python3.7/dist-packages (from optax) (0.3.2+cuda11.cudnn805)\n", 42 | "Requirement already satisfied: absl-py>=0.7.1 in /usr/local/lib/python3.7/dist-packages (from optax) (1.0.0)\n", 43 | "Requirement already satisfied: typing-extensions>=3.10.0 in /usr/local/lib/python3.7/dist-packages (from optax) (3.10.0.2)\n", 44 | "Requirement already satisfied: jax>=0.1.55 in /usr/local/lib/python3.7/dist-packages (from optax) (0.3.4)\n", 45 | "Requirement already satisfied: chex>=0.0.4 in /usr/local/lib/python3.7/dist-packages (from optax) (0.1.1)\n", 46 | "Requirement already satisfied: six in /usr/local/lib/python3.7/dist-packages (from absl-py>=0.7.1->optax) (1.15.0)\n", 47 | "Requirement already satisfied: toolz>=0.9.0 in /usr/local/lib/python3.7/dist-packages (from chex>=0.0.4->optax) (0.11.2)\n", 48 | "Requirement already satisfied: dm-tree>=0.1.5 in /usr/local/lib/python3.7/dist-packages (from chex>=0.0.4->optax) (0.1.6)\n", 49 | "Requirement already satisfied: scipy>=1.2.1 in /usr/local/lib/python3.7/dist-packages (from jax>=0.1.55->optax) (1.4.1)\n", 50 | "Requirement already satisfied: opt-einsum in /usr/local/lib/python3.7/dist-packages (from jax>=0.1.55->optax) (3.3.0)\n", 51 | "Requirement already satisfied: flatbuffers<3.0,>=1.12 in /usr/local/lib/python3.7/dist-packages (from jaxlib>=0.1.37->optax) (2.0)\n" 52 | ] 53 | } 54 | ], 55 | "source": [ 56 | "#Imports\n", 57 | "import jax \n", 58 | "import jax.numpy as jnp\n", 59 | "import numpy as np\n", 60 | "import matplotlib.pyplot as plt\n", 61 | "from matplotlib import cm\n", 62 | "import matplotlib as mpl\n", 63 | "!pip install optax\n", 64 | "import optax" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": null, 70 | "metadata": { 71 | "id": "yoPHsh5lWvyP" 72 | }, 73 | "outputs": [], 74 | "source": [ 75 | "import sympy as sp" 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": { 81 | "id": "7bg4nSbsXVwD" 82 | }, 83 | "source": [ 84 | "### Generate a a differential equation and its solution using SymPy" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": null, 90 | "metadata": { 91 | "id": "P9664e-mVMTN" 92 | }, 93 | "outputs": [], 94 | "source": [ 95 | "t= sp.symbols('t')\n", 96 | "f = sp.Function('y')\n", 97 | "diffeq = sp.Eq(f(t).diff(t,t) + f(t).diff(t)-t*sp.cos(2*sp.pi*t),0)\n", 98 | "sol = sp.simplify(sp.dsolve(diffeq,ics={f(0):1,f(t).diff(t).subs(t,0):10}).rhs)" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": null, 104 | "metadata": { 105 | "colab": { 106 | "base_uri": "https://localhost:8080/", 107 | "height": 54 108 | }, 109 | "id": "klgFeU6bcTrC", 110 | "outputId": "5c0fc009-ce8b-472f-b98b-6da8afd6a66c" 111 | }, 112 | "outputs": [ 113 | { 114 | "output_type": "execute_result", 115 | "data": { 116 | "text/plain": [ 117 | "Eq(-t*cos(2*pi*t) + Derivative(y(t), t) + Derivative(y(t), (t, 2)), 0)" 118 | ], 119 | "text/latex": "$\\displaystyle - t \\cos{\\left(2 \\pi t \\right)} + \\frac{d}{d t} y{\\left(t \\right)} + \\frac{d^{2}}{d t^{2}} y{\\left(t \\right)} = 0$" 120 | }, 121 | "metadata": {}, 122 | "execution_count": 4 123 | } 124 | ], 125 | "source": [ 126 | "diffeq" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": null, 132 | "metadata": { 133 | "colab": { 134 | "base_uri": "https://localhost:8080/", 135 | "height": 60 136 | }, 137 | "id": "E4Uu2hbiYJtv", 138 | "outputId": "6444bdb2-9243-46c9-e801-d19960dcb233" 139 | }, 140 | "outputs": [ 141 | { 142 | "output_type": "execute_result", 143 | "data": { 144 | "text/plain": [ 145 | "Eq(Subs(Derivative(y(t), t), t, 0), 10)" 146 | ], 147 | "text/latex": "$\\displaystyle \\left. \\frac{d}{d t} y{\\left(t \\right)} \\right|_{\\substack{ t=0 }} = 10$" 148 | }, 149 | "metadata": {}, 150 | "execution_count": 5 151 | } 152 | ], 153 | "source": [ 154 | "sp.Eq(f(t).diff(t).subs(t,0),10)" 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "execution_count": null, 160 | "metadata": { 161 | "colab": { 162 | "base_uri": "https://localhost:8080/", 163 | "height": 38 164 | }, 165 | "id": "29QUbt_2YwlJ", 166 | "outputId": "0e3cce9d-29c7-4f26-c279-535093e2ad37" 167 | }, 168 | "outputs": [ 169 | { 170 | "output_type": "execute_result", 171 | "data": { 172 | "text/plain": [ 173 | "Eq(y(0), 1)" 174 | ], 175 | "text/latex": "$\\displaystyle y{\\left(0 \\right)} = 1$" 176 | }, 177 | "metadata": {}, 178 | "execution_count": 6 179 | } 180 | ], 181 | "source": [ 182 | "sp.Eq(f(t).subs(t,0),1)" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": null, 188 | "metadata": { 189 | "colab": { 190 | "base_uri": "https://localhost:8080/", 191 | "height": 81 192 | }, 193 | "id": "r9KVq1yjYfld", 194 | "outputId": "9a8437fc-c2fc-4fe7-ad9f-26ca25b974d4" 195 | }, 196 | "outputs": [ 197 | { 198 | "output_type": "execute_result", 199 | "data": { 200 | "text/plain": [ 201 | "Eq(y(t), (2*pi*t*exp(t)*sin(2*pi*t) + 8*pi**3*t*exp(t)*sin(2*pi*t) - 16*pi**4*t*exp(t)*cos(2*pi*t) - 4*pi**2*t*exp(t)*cos(2*pi*t) + 16*pi**3*exp(t)*sin(2*pi*t) + exp(t)*cos(2*pi*t) + 12*pi**2*exp(t)*cos(2*pi*t) - exp(t) + 36*pi**2*exp(t) + 336*pi**4*exp(t) + 704*pi**6*exp(t) - 640*pi**6 - 304*pi**4 - 44*pi**2)*exp(-t)/(4*pi**2*(1 + 8*pi**2 + 16*pi**4)))" 202 | ], 203 | "text/latex": "$\\displaystyle y{\\left(t \\right)} = \\frac{\\left(2 \\pi t e^{t} \\sin{\\left(2 \\pi t \\right)} + 8 \\pi^{3} t e^{t} \\sin{\\left(2 \\pi t \\right)} - 16 \\pi^{4} t e^{t} \\cos{\\left(2 \\pi t \\right)} - 4 \\pi^{2} t e^{t} \\cos{\\left(2 \\pi t \\right)} + 16 \\pi^{3} e^{t} \\sin{\\left(2 \\pi t \\right)} + e^{t} \\cos{\\left(2 \\pi t \\right)} + 12 \\pi^{2} e^{t} \\cos{\\left(2 \\pi t \\right)} - e^{t} + 36 \\pi^{2} e^{t} + 336 \\pi^{4} e^{t} + 704 \\pi^{6} e^{t} - 640 \\pi^{6} - 304 \\pi^{4} - 44 \\pi^{2}\\right) e^{- t}}{4 \\pi^{2} \\left(1 + 8 \\pi^{2} + 16 \\pi^{4}\\right)}$" 204 | }, 205 | "metadata": {}, 206 | "execution_count": 7 207 | } 208 | ], 209 | "source": [ 210 | "sp.Eq(f(t),sol)" 211 | ] 212 | }, 213 | { 214 | "cell_type": "code", 215 | "execution_count": null, 216 | "metadata": { 217 | "colab": { 218 | "base_uri": "https://localhost:8080/", 219 | "height": 37 220 | }, 221 | "id": "MNVOpPyCW-GU", 222 | "outputId": "53a70887-e440-43a8-f811-30c862b21866" 223 | }, 224 | "outputs": [ 225 | { 226 | "output_type": "execute_result", 227 | "data": { 228 | "text/plain": [ 229 | "0" 230 | ], 231 | "text/latex": "$\\displaystyle 0$" 232 | }, 233 | "metadata": {}, 234 | "execution_count": 8 235 | } 236 | ], 237 | "source": [ 238 | "#verify solution\n", 239 | "sp.simplify(-t*sp.cos(sp.pi*2*t)+sol.diff(t)+sol.diff(t,t))" 240 | ] 241 | }, 242 | { 243 | "cell_type": "markdown", 244 | "metadata": { 245 | "id": "NQ61lEQeXgrc" 246 | }, 247 | "source": [ 248 | "### Constructing the MLP" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": null, 254 | "metadata": { 255 | "id": "Lml6PGLPZgmr" 256 | }, 257 | "outputs": [], 258 | "source": [ 259 | "N_b = 1\n", 260 | "N_c = 100\n", 261 | "\n", 262 | "tmin,tmax=0. ,jnp.pi\n", 263 | "\n", 264 | "'''boundary conditions'''\n", 265 | "\n", 266 | "\n", 267 | "# U[0] = 1\n", 268 | "t_0 = jnp.ones([N_b,1],dtype='float32')*0.\n", 269 | "ic_0 = jnp.ones_like(t_0) \n", 270 | "IC_0 = jnp.concatenate([t_0,ic_0],axis=1)\n", 271 | "\n", 272 | "# U_t[0] = 10\n", 273 | "t_b1 = jnp.zeros([N_b,1])\n", 274 | "bc_1 = jnp.ones_like(t_b1) * 10\n", 275 | "BC_1 = jnp.concatenate([t_b1,bc_1],axis=1)\n", 276 | "\n", 277 | "conds = [IC_0,BC_1]\n", 278 | "\n", 279 | "#collocation points\n", 280 | "\n", 281 | "key=jax.random.PRNGKey(0)\n", 282 | "\n", 283 | "t_c = jnp.linspace(tmin,tmax,N_c).reshape(-1,1)\n", 284 | "colloc = t_c\n", 285 | "\n", 286 | "def ODE_loss(t,u):\n", 287 | " dt = 0.03173326\n", 288 | " u_t = lambda t: (-u(t+2*dt)+8*u(t+dt)-8*u(t-dt)+u(t-2*dt))/(12*dt)\n", 289 | " u_tt = lambda t: (-u(t+2*dt) + 16*u(t+dt) -30*u(t) + 16 * u(t-dt) - u(t-2*dt))/(12*dt**2)\n", 290 | " return -t*jnp.cos(2*jnp.pi*t) + u_t(t) + u_tt(t)" 291 | ] 292 | }, 293 | { 294 | "cell_type": "code", 295 | "execution_count": null, 296 | "metadata": { 297 | "id": "KoZZJl2TbI_n" 298 | }, 299 | "outputs": [], 300 | "source": [ 301 | "def init_params(layers):\n", 302 | " keys = jax.random.split(jax.random.PRNGKey(0),len(layers)-1)\n", 303 | " params = list()\n", 304 | " for key,n_in,n_out in zip(keys,layers[:-1],layers[1:]):\n", 305 | " lb, ub = -(1 / jnp.sqrt(n_in)), (1 / jnp.sqrt(n_in)) # xavier initialization lower and upper bound\n", 306 | " W = lb + (ub-lb) * jax.random.uniform(key,shape=(n_in,n_out))\n", 307 | " B = jax.random.uniform(key,shape=(n_out,))\n", 308 | " params.append({'W':W,'B':B})\n", 309 | " return params\n", 310 | "\n", 311 | "def fwd(params,t):\n", 312 | " X = jnp.concatenate([t],axis=1)\n", 313 | " *hidden,last = params\n", 314 | " for layer in hidden :\n", 315 | " X = jax.nn.tanh(X@layer['W']+layer['B'])\n", 316 | " return X@last['W'] + last['B']\n", 317 | "\n", 318 | "@jax.jit\n", 319 | "def MSE(true,pred):\n", 320 | " return jnp.mean((true-pred)**2)\n", 321 | "\n", 322 | "def loss_fun(params,colloc,conds):\n", 323 | " t_c =colloc[:,[0]]\n", 324 | " ufunc = lambda t : fwd(params,t)\n", 325 | " ufunc_t=lambda t:jax.grad(lambda t:jnp.sum(ufunc(t)))(t)\n", 326 | " loss =jnp.mean(ODE_loss(t_c,ufunc) **2)\n", 327 | "\n", 328 | " t_ic,u_ic = conds[0][:,[0]],conds[0][:,[1]] \n", 329 | " loss += MSE(u_ic,ufunc(t_ic))\n", 330 | "\n", 331 | " t_bc,u_bc = conds[1][:,[0]],conds[1][:,[1]] \n", 332 | " loss += MSE(u_bc,ufunc_t(t_bc))\n", 333 | "\n", 334 | " return loss\n", 335 | "\n", 336 | "@jax.jit\n", 337 | "def update(opt_state,params,colloc,conds):\n", 338 | " # Get the gradient w.r.t to MLP params\n", 339 | " grads=jax.jit(jax.grad(loss_fun,0))(params,colloc,conds)\n", 340 | " \n", 341 | " #Update params\n", 342 | " updates, opt_state = optimizer.update(grads, opt_state)\n", 343 | " params = optax.apply_updates(params, updates)\n", 344 | "\n", 345 | " #Update params\n", 346 | " # return jax.tree_multimap(lambda params,grads : params-LR*grads, params,grads)\n", 347 | " return opt_state,params\n" 348 | ] 349 | }, 350 | { 351 | "cell_type": "code", 352 | "execution_count": null, 353 | "metadata": { 354 | "id": "ae1ZDoy0c29c" 355 | }, 356 | "outputs": [], 357 | "source": [ 358 | "# construct the MLP of 6 hidden layers of 8 neurons for each layer\n", 359 | "params = init_params([1] + [20]*4+[1])" 360 | ] 361 | }, 362 | { 363 | "cell_type": "code", 364 | "execution_count": null, 365 | "metadata": { 366 | "id": "jySmbUwic5yk" 367 | }, 368 | "outputs": [], 369 | "source": [ 370 | "lr = optax.piecewise_constant_schedule(1e-3,{10_000:5e-3,30_000:1e-3,50_000:5e-4,70_000:1e-4})\n", 371 | "optimizer = optax.adam(1e-3)\n", 372 | "opt_state = optimizer.init(params)" 373 | ] 374 | }, 375 | { 376 | "cell_type": "code", 377 | "execution_count": null, 378 | "metadata": { 379 | "colab": { 380 | "base_uri": "https://localhost:8080/" 381 | }, 382 | "id": "kBzGA8OVc8C6", 383 | "outputId": "ed7565fa-5172-42c8-ce96-39b3cd357d5b" 384 | }, 385 | "outputs": [ 386 | { 387 | "output_type": "stream", 388 | "name": "stdout", 389 | "text": [ 390 | "Epoch=0\tloss=1.026e+02\n", 391 | "Epoch=1000\tloss=1.134e+01\n", 392 | "Epoch=2000\tloss=7.139e+00\n", 393 | "Epoch=3000\tloss=4.549e+00\n", 394 | "Epoch=4000\tloss=2.824e+00\n", 395 | "Epoch=5000\tloss=2.343e+00\n", 396 | "Epoch=6000\tloss=2.147e+00\n", 397 | "Epoch=7000\tloss=1.904e+00\n", 398 | "Epoch=8000\tloss=1.563e+00\n", 399 | "Epoch=9000\tloss=1.016e+00\n", 400 | "Epoch=10000\tloss=9.470e-01\n", 401 | "Epoch=11000\tloss=9.235e-01\n", 402 | "Epoch=12000\tloss=9.041e-01\n", 403 | "Epoch=13000\tloss=8.905e-01\n", 404 | "Epoch=14000\tloss=8.731e-01\n", 405 | "Epoch=15000\tloss=8.661e-01\n", 406 | "Epoch=16000\tloss=8.594e-01\n", 407 | "Epoch=17000\tloss=8.494e-01\n", 408 | "Epoch=18000\tloss=8.424e-01\n", 409 | "Epoch=19000\tloss=8.380e-01\n", 410 | "Epoch=20000\tloss=8.348e-01\n", 411 | "Epoch=21000\tloss=8.259e-01\n", 412 | "Epoch=22000\tloss=8.208e-01\n", 413 | "Epoch=23000\tloss=8.104e-01\n", 414 | "Epoch=24000\tloss=8.035e-01\n", 415 | "Epoch=25000\tloss=7.996e-01\n", 416 | "Epoch=26000\tloss=7.991e-01\n", 417 | "Epoch=27000\tloss=7.855e-01\n", 418 | "Epoch=28000\tloss=7.851e-01\n", 419 | "Epoch=29000\tloss=7.818e-01\n", 420 | "Epoch=30000\tloss=7.784e-01\n", 421 | "Epoch=31000\tloss=7.729e-01\n", 422 | "Epoch=32000\tloss=7.824e-01\n", 423 | "Epoch=33000\tloss=7.703e-01\n", 424 | "Epoch=34000\tloss=7.798e-01\n", 425 | "Epoch=35000\tloss=7.726e-01\n", 426 | "Epoch=36000\tloss=7.629e-01\n", 427 | "Epoch=37000\tloss=7.736e-01\n", 428 | "Epoch=38000\tloss=7.748e-01\n", 429 | "Epoch=39000\tloss=7.663e-01\n", 430 | "Epoch=40000\tloss=7.684e-01\n", 431 | "Epoch=41000\tloss=7.751e-01\n", 432 | "Epoch=42000\tloss=7.682e-01\n", 433 | "Epoch=43000\tloss=7.782e-01\n", 434 | "Epoch=44000\tloss=7.733e-01\n", 435 | "Epoch=45000\tloss=7.665e-01\n", 436 | "Epoch=46000\tloss=7.643e-01\n", 437 | "Epoch=47000\tloss=7.625e-01\n", 438 | "Epoch=48000\tloss=7.619e-01\n", 439 | "Epoch=49000\tloss=7.627e-01\n", 440 | "Epoch=50000\tloss=7.688e-01\n", 441 | "Epoch=51000\tloss=7.621e-01\n", 442 | "Epoch=52000\tloss=7.633e-01\n", 443 | "Epoch=53000\tloss=7.616e-01\n", 444 | "Epoch=54000\tloss=7.713e-01\n", 445 | "Epoch=55000\tloss=7.645e-01\n", 446 | "Epoch=56000\tloss=7.589e-01\n", 447 | "Epoch=57000\tloss=7.626e-01\n", 448 | "Epoch=58000\tloss=7.668e-01\n", 449 | "Epoch=59000\tloss=7.682e-01\n", 450 | "Epoch=60000\tloss=7.605e-01\n", 451 | "Epoch=61000\tloss=7.642e-01\n", 452 | "Epoch=62000\tloss=7.570e-01\n", 453 | "Epoch=63000\tloss=7.593e-01\n", 454 | "Epoch=64000\tloss=7.541e-01\n", 455 | "Epoch=65000\tloss=7.565e-01\n", 456 | "Epoch=66000\tloss=7.604e-01\n", 457 | "Epoch=67000\tloss=7.644e-01\n", 458 | "Epoch=68000\tloss=7.555e-01\n", 459 | "Epoch=69000\tloss=7.600e-01\n", 460 | "Epoch=70000\tloss=7.641e-01\n", 461 | "Epoch=71000\tloss=7.505e-01\n", 462 | "Epoch=72000\tloss=7.549e-01\n", 463 | "Epoch=73000\tloss=7.627e-01\n", 464 | "Epoch=74000\tloss=7.575e-01\n", 465 | "Epoch=75000\tloss=7.568e-01\n", 466 | "Epoch=76000\tloss=7.699e-01\n", 467 | "Epoch=77000\tloss=7.498e-01\n", 468 | "Epoch=78000\tloss=7.505e-01\n", 469 | "Epoch=79000\tloss=7.544e-01\n", 470 | "Epoch=80000\tloss=7.511e-01\n", 471 | "Epoch=81000\tloss=7.579e-01\n", 472 | "Epoch=82000\tloss=7.470e-01\n", 473 | "Epoch=83000\tloss=7.527e-01\n", 474 | "Epoch=84000\tloss=7.583e-01\n", 475 | "Epoch=85000\tloss=7.445e-01\n", 476 | "Epoch=86000\tloss=7.476e-01\n", 477 | "Epoch=87000\tloss=7.633e-01\n", 478 | "Epoch=88000\tloss=7.500e-01\n", 479 | "Epoch=89000\tloss=7.467e-01\n", 480 | "Epoch=90000\tloss=7.447e-01\n", 481 | "Epoch=91000\tloss=7.495e-01\n", 482 | "Epoch=92000\tloss=7.487e-01\n", 483 | "Epoch=93000\tloss=7.542e-01\n", 484 | "Epoch=94000\tloss=7.583e-01\n", 485 | "Epoch=95000\tloss=7.612e-01\n", 486 | "Epoch=96000\tloss=7.489e-01\n", 487 | "Epoch=97000\tloss=7.502e-01\n", 488 | "Epoch=98000\tloss=7.474e-01\n", 489 | "Epoch=99000\tloss=7.563e-01\n", 490 | "CPU times: user 1min 57s, sys: 256 ms, total: 1min 57s\n", 491 | "Wall time: 3min 3s\n" 492 | ] 493 | } 494 | ], 495 | "source": [ 496 | "%%time\n", 497 | "epochs = 100_000\n", 498 | "for _ in range(epochs):\n", 499 | " opt_state,params = update(opt_state,params,colloc,conds)\n", 500 | "\n", 501 | " # print loss and epoch info\n", 502 | " if _ %(1000) ==0:\n", 503 | " print(f'Epoch={_}\\tloss={loss_fun(params,colloc,conds):.3e}')" 504 | ] 505 | }, 506 | { 507 | "cell_type": "code", 508 | "execution_count": null, 509 | "metadata": { 510 | "colab": { 511 | "base_uri": "https://localhost:8080/", 512 | "height": 282 513 | }, 514 | "id": "eWeNvDsdDEuI", 515 | "outputId": "1b79ef5d-7f2d-40ee-f4a1-4d0ba1cb0edd" 516 | }, 517 | "outputs": [ 518 | { 519 | "output_type": "execute_result", 520 | "data": { 521 | "text/plain": [ 522 | "" 523 | ] 524 | }, 525 | "metadata": {}, 526 | "execution_count": 36 527 | }, 528 | { 529 | "output_type": "display_data", 530 | "data": { 531 | "text/plain": [ 532 | "
" 533 | ], 534 | "image/png": "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\n" 535 | }, 536 | "metadata": { 537 | "needs_background": "light" 538 | } 539 | } 540 | ], 541 | "source": [ 542 | "lam_sol= sp.lambdify(t,sol)\n", 543 | "\n", 544 | "dT = 1e-3\n", 545 | "Tf = jnp.pi\n", 546 | "T = np.arange(0,Tf+dT,dT)\n", 547 | "\n", 548 | "\n", 549 | "sym_sol =np.array([lam_sol(i) for i in T])\n", 550 | "\n", 551 | "plt.plot(T,sym_sol,'--r',label='sympy solution')\n", 552 | "plt.plot(T,fwd(params,T.reshape(-1,1))[:,0],'--k',label='NN solution')\n", 553 | "plt.legend()" 554 | ] 555 | } 556 | ], 557 | "metadata": { 558 | "colab": { 559 | "collapsed_sections": [], 560 | "name": "[6] ODE-PINN finite difference.ipynb", 561 | "provenance": [], 562 | "include_colab_link": true 563 | }, 564 | "kernelspec": { 565 | "display_name": "Python 3", 566 | "language": "python", 567 | "name": "python3" 568 | }, 569 | "language_info": { 570 | "codemirror_mode": { 571 | "name": "ipython", 572 | "version": 3 573 | }, 574 | "file_extension": ".py", 575 | "mimetype": "text/x-python", 576 | "name": "python", 577 | "nbconvert_exporter": "python", 578 | "pygments_lexer": "ipython3", 579 | "version": "3.9.6" 580 | } 581 | }, 582 | "nbformat": 4, 583 | "nbformat_minor": 0 584 | } --------------------------------------------------------------------------------