{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "<h3> Soluzioni di equazioni differenziali ordinarie: cinetica chimica </h3>\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "Le equazioni differenziali ordinarie, ode, sono equazioni differenziali nella forma $y'(t)=f(y, t)$.\n",
    "Molti fenomeni chimici e fisici ubbidiscono ad equazioni di questo tipo, fra questi le equazioni della\n",
    "cinetica chimica.\n",
    "\n",
    "Nella cinetica chimica, tipicamente y(t) è il vettore delle concentrazioni di tutte le sostanze coinvolte nella reazione.\n",
    "\n",
    "Ma anche l'equazione dell'oscillazione armonica è una ODE:\n",
    "\n",
    "$$y''=-ky$$\n",
    "\n",
    "$$\n",
    "\\begin{pmatrix}\n",
    "y \\\\ y'\n",
    "\\end{pmatrix} ^\\prime = \n",
    "\\begin{pmatrix}\n",
    "y' \\\\\n",
    "- k y\n",
    "\\end{pmatrix}\n",
    "$$\n",
    "\n",
    "e come vedremo, con la stessa tecnica, anche l'equazione di Schrödinger è una ODE"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ci sono diverse librerie per la soluzione di ODE, il nostro punto d'ingresso sarà la funzione\n",
    "`scipy.odeint`:\n",
    "\n",
    "`odeint(t, ...)`,\n",
    "\n",
    "di quali parametri avrà bisogno?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "Per scaldare i muscoli consideriamo una reazione\n",
    "\n",
    "A + B <=> C,\n",
    "\n",
    "che soddisfi la seguente legge cinetica:\n",
    "\n",
    "$v= -a' = -b' = c' = k_d a b - k_i c$, con\n",
    "\n",
    "a=[A], b=[B] e c=[C].\n",
    "\n",
    "Qualunque sia il metodo che usiamo per risolvere le nostre equazioni differenziali, avrà bisogno\n",
    "delle seguenti informazioni:\n",
    "\n",
    "$[a', b', c'] = f([a, b, c], t)$; le equazioni della cinetica chimica però in genere non dipendono esplicitamente dal tempo;\n",
    "\n",
    "$[a, b, c]_{t=0}$; le condizioni iniziali\n",
    "\n",
    "$[t_i]_{i=0,n}$; i tempi a cui si vogliono avere le soluzioni.\n",
    "\n",
    "Cominciamo con il definire la funzione $f$ per la nostra cinetica chimica, dobbiamo codificare\n",
    "un vettore delle concentrazioni, per esempio:\n",
    "y=[a, b, c]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "jupyter": {
     "outputs_hidden": false
    },
    "slideshow": {
     "slide_type": "-"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import scipy.integrate as ntg\n",
    "import matplotlib.pyplot as plt\n",
    "from ipywidgets import interact, interact_manual\n",
    "import ipywidgets as wi"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "jupyter": {
     "outputs_hidden": false
    },
    "slideshow": {
     "slide_type": "-"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def cinetica(y, t, k_d, k_i):\n",
    "    q=k_d*y[0]*y[1]-k_i*y[2]    # q=k_d*a*b - k_i*c\n",
    "    return np.array([-q, -q, q])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "la funzione cinetica restituisce le velocità di variazione delle concentrazioni $a, b, c$.\n",
    "python offre diverse possibilità di soluzione per le ODE, in numpy troviamo per esempio  odeint"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "jupyter": {
     "outputs_hidden": false
    },
    "slideshow": {
     "slide_type": "-"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "7e52fce4b38b4178b23cd543466c4ba1",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(FloatText(value=1000.0, description='k_d'), FloatText(value=350.0, description='k_i'), B…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "@interact_manual(k_d=wi.FloatText(value=1.0e3), \n",
    "    k_i=wi.FloatText(value=350))\n",
    "def risolvi(k_d, k_i):\n",
    "    y0=np.array([1.0, 0.3, 1.8]) # concentrazioni iniziali\n",
    "    t=np.linspace(0.0, 0.01, 20)\n",
    "    soluzione=ntg.odeint(cinetica, y0, t, args=(k_d, k_i))\n",
    "    # print(soluzione.shape)\n",
    "    linee=plt.plot(t, soluzione)\n",
    "    plt.legend(linee, ['[A]','[B]','[C]'])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "note:\n",
    "\n",
    "1. è importante scegliere i tempi per la soluzione in maniera sensata, con la costante cinetica\n",
    "impostata la reazione si conclude in meno di 0.01 secondi, provate valori diversi\n",
    "2. odeint ci restituisce come soluzione una matrice di dimensioni n_t*n_y, è possibile interrogare una matrice sulle sue dimensioni tramite l'attributo shape\n",
    "3. odeint, ci permette di passare comodamente dei parametri aggiuntivi alla funzione differenziale, in questo caso k_d e k_i, che invece è necessario passare diversamente per esempio nella odeint di matlab.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "ein.tags": "worksheet-0",
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "Ora risolvete il problema della cinetica enzimatica, una reazione che avviene secondo lo schema:\n",
    "\n",
    "S + E <=> SE -> P + E\n",
    "\n",
    "l'enzima è in genere presente in piccole quantità e limita la massima concentrazione ottenibile [SE].\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "autoscroll": false,
    "ein.hycell": false,
    "ein.tags": "worksheet-0",
    "jupyter": {
     "outputs_hidden": false
    },
    "slideshow": {
     "slide_type": "-"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def enzimatica(c, t, k_d, k_i, k2):\n",
    "    s,e,se,p=c\n",
    "    v_d=k_d*s*e\n",
    "    v_i=k_i*se\n",
    "    v2=k2*se\n",
    "    v_s=v_i-v_d\n",
    "    v_e=v_i+v2-v_d\n",
    "    v_se=-v_e\n",
    "    v_p=v2\n",
    "    return [v_s, v_e, v_se, v_p]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "b080fcfba3ab4b0d8a1b247df34d2184",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(FloatText(value=300.0, description='k_d'), FloatText(value=700.0, description='k_i'), Fl…"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "@interact_manual(k_d=wi.FloatText(value=0.3e3), \n",
    "    k_i=wi.FloatText(value=700),\n",
    "    k2=wi.FloatText(value=100),\n",
    "    s0=wi.FloatText(value=1.0),\n",
    "    e0=wi.FloatText(value=0.05),\n",
    "    t_max=wi.FloatText(1.0))\n",
    "def risolvi(k_d, k_i, k2, s0, e0, t_max):\n",
    "    y0=np.array([s0, e0, 0.0, 0.0]) # concentrazioni iniziali\n",
    "    t=np.linspace(0.0, t_max, 50)\n",
    "    soluzione=ntg.odeint(enzimatica, y0, t, args=(k_d, k_i, k2))\n",
    "    # print(soluzione.shape)\n",
    "    linee=plt.plot(t, soluzione)\n",
    "    plt.legend(linee, ['[S]','[E]','[SE]', '[P]'])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "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"
  },
  "name": "cinetica.ipynb"
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
