# Mecánica con SymPy

_Si SymPy te ha parecido hasta ahora un CAS decente e incluso interesante (nada como tener los resultados en $\LaTeX$ incrustados en el notebook y la sintaxis de Python para hacer cálculo simbólico) entonces espera a ver el paquete `mechanics`. Con él, podremos manipular velocidades y aceleraciones de sólidos expresadas en distintos sistemas de referencia con una facilidad impresionante._

_Tienes disponible la documentación de `mechanics` en http://docs.sympy.org/0.7.5/modules/physics/mechanics/index.html._

## Sistemas de referencia

El objeto primordial que vamos a manejar van a ser los sistemas de referencia. Podremos definir relaciones geométricas entre ellos y de esta forma las transformaciones de vectores entre un sistema y otro serán triviales.

La manera usual de empezar a trabajar con SymPy es importar la función `init_session`:
```
from sympy import init_session
init_session(use_latex=True)```

 Esta función ya se encarga de importar todas las funciones básicas y preparar las salidas gráficas. Sin embargo, en este momento, esta función se encuentra en mantenimiento para su uso dentro de los notebooks por lo que activaremos la salida gráfica e importaremos las funciones de la manera usual. Puedes consultar el estado de la corrección en: https://github.com/sympy/sympy/pull/13300 y https://github.com/sympy/sympy/issues/13319 .

```python
from sympy import *
init_printing(use_latex='mathjax')
```

```python
from sympy import symbols
```

Todo lo que necesitamos está en `sympy.physics.mechanics`, incluyendo la clase `ReferenceFrame`. Nada más crear un sistema de referencia podemos acceder a sus versores unitarios: `x`, `y` y `z`.

http://docs.sympy.org/0.7.5/modules/physics/vector/vectors.html

```python
from sympy.physics.mechanics import ReferenceFrame
```

```python
A = ReferenceFrame("A")
A.x
```

$\displaystyle \mathbf{\hat{a}_x}$

Y para definir vectores solo tenemos que **multiplicar cada componente por su versor**:

```python
2 * A.x - 1 * A.y
```

$\displaystyle 2\mathbf{\hat{a}_x} - \mathbf{\hat{a}_y}$

De ahora en adelante, para trabajar como si nos enfrentáramos a un problema de la escuela, vamos a hacer dos cosas:

* Definir un sistema inercial $1$ del que partir, para así poder referir todos los demás sistemas a él.
* Que los versores de ese sistema sean $i, j, k$.

```python
A = ReferenceFrame("1", latexs=['\mathbf{i}', '\mathbf{j}', '\mathbf{k}'])
A.x + A.y + A.z
```

$\displaystyle \mathbf{i} + \mathbf{j} + \mathbf{k}$

Y para no tener que hacerlo siempre, un pequeño truco de magia:

```python
# Definimos nuestra propia clase para que los versores sean IJK
# aeropython: preserve
class IJKReferenceFrame(ReferenceFrame):
    def __init__(self, name):
        super().__init__(name, latexs=['\mathbf{%s}_{%s}' % (idx, name) for idx in ("i", "j", "k")])
        self.i = self.x
        self.j = self.y
        self.k = self.z
```

```python
A = IJKReferenceFrame("1")
A.i + A.j + A.k
```

$\displaystyle \mathbf{i}_{1} + \mathbf{j}_{1} + \mathbf{k}_{1}$

### Álgebra vectorial

Nuestros vectores funcionan también con símbolos, y podemos realizar las operaciones de producto escalar y producto vectorial con ellos.

```python
R, V = symbols('R, V', positive=True)
r1 = R * (A.x + A.y + A.z)
v1 = V * (A.x - 2 * A.z)
```

```python
r1
```

$\displaystyle R\mathbf{i}_{1} + R\mathbf{j}_{1} + R\mathbf{k}_{1}$

```python
v1
```

$\displaystyle V\mathbf{i}_{1} -  2 V\mathbf{k}_{1}$

```python
from sympy.physics.mechanics import dot, cross
```

```python
# All these are ways to carry out a dot prduct between two vectors
r1.dot(v1)
dot(r1, v1)
r1 & v1
```

$\displaystyle - R V$

```python
# All these are ways to carry out a cross prduct between two vectors
r1.cross(v1)
cross(r1, v1)
r1 ^ v1

```

$\displaystyle -  2 R V\mathbf{i}_{1} + 3 R V\mathbf{j}_{1} -  R V\mathbf{k}_{1}$

Podemos hallar también la norma de los vectores con su método `magnitude` e incluso normalizarlos con `normalize`:

```python
(r1 ^ v1).magnitude()
cross(r1, v1).magnitude()
```

$\displaystyle \sqrt{14} R V$

```python
(r1 ^ v1).normalize()
```

$\displaystyle -  \frac{\sqrt{14}}{7}\mathbf{i}_{1} + \frac{3 \sqrt{14}}{14}\mathbf{j}_{1} -  \frac{\sqrt{14}}{14}\mathbf{k}_{1}$

##### Ejercicio

Usando directamente la fórmula para la derivada en ejes móviles:

$$\left(\frac{\operatorname{d}\!\mathbf{a}}{\operatorname{d}\!t}\right)_1 = \left(\frac{\operatorname{d}\!\mathbf{a}}{\operatorname{d}\!t}\right)_0 + \mathbf{\omega}_{01}\! \times \mathbf{a}$$

Calcula la derivada del vector de posición $R \mathbf{i}_0$, siendo $A_0$ un sistema de referencia que gira respecto al inercial con velocidad angular $\mathbf{\omega}_{01}=\Omega \mathbf{k}_0$. **¿Cuál es el módulo de la derivada?**

```python
R, Omega = symbols('R, Omega', positive=True)
A0 = IJKReferenceFrame('0')
```

```python
a = R * A0.i
a
```

$\displaystyle R\mathbf{i}_{0}$

```python
omega01 = Omega * A0.k
omega01
```

$\displaystyle \Omega\mathbf{k}_{0}$

```python
da = omega01 ^ a # Cross product between omega01 and a
da
```

$\displaystyle \Omega R\mathbf{j}_{0}$

```python
da.magnitude()
```

$\displaystyle \Omega R$

Si no especificaste `positive=True` vas a ver algo como $\sqrt{\Omega^2 R^2}$. Debería haber una forma de simplificar esta expresión _a posteriori_, pero de momento no funciona del todo bien. Preparando este notebook nos hemos dado cuenta y ya les hemos avisado :) https://github.com/sympy/sympy/issues/8326

### Movimiento relativo

¿A quién no le gusta multiplicar matrices de rotación? Para esa minoría que lo detesta, existe SymPy. Para ello debemos especificar la orientación de nuestros sistemas de referencia usando el método `orient`, y recuperaremos la matriz de cosenos directores usando el método `dcm`.

```python
A1 = IJKReferenceFrame("1")
A0 = IJKReferenceFrame("0")
```

```python
phi = symbols('phi')
A0.orient(A1, 'Axis', [phi, A1.z])  # Rotación phi alrededor del eje A1.z
A0.dcm(A1)  # "Direct Cosine Matrix"
```

$\displaystyle \left[\begin{matrix}\cos{\left(\phi \right)} & \sin{\left(\phi \right)} & 0\\- \sin{\left(\phi \right)} & \cos{\left(\phi \right)} & 0\\0 & 0 & 1\end{matrix}\right]$

Usando el argumento `Axis` hemos especificado que rotamos el sistema un ángulo especificado alrededor de un eje. Otros métodos son:

* `Body`: se especifican los tres ángulos de Euler.
* `Space`: igual que `Body`, pero las rotaciones se aplican en orden inverso.
* `Quaternion`: utilizando cuaternios, rotación alrededor de un vector unitario $\lambda$ una cantidad $\theta$.

¿Qué es lo bueno de usar uno de estos métodos? ¡Que **siempre** tenemos la transformación bien definida! Es imposible meter "a capón" una matriz de rotación que sea incorrecta o absurda.

#### Diferente sistema de referencia

Para expresar un vector en otro sistema de referencia, no hay más que usar los métodos `express` o `to_matrix`:

```python
A0.x.express(A1)
```

$\displaystyle \cos{\left(\phi \right)}\mathbf{i}_{1} + \sin{\left(\phi \right)}\mathbf{j}_{1}$

```python
A0.x.to_matrix(A1)
```

$\displaystyle \left[\begin{matrix}\cos{\left(\phi \right)}\\\sin{\left(\phi \right)}\\0\end{matrix}\right]$

```python
Matrix([ [A0.x.to_matrix(A1)], [A0.y.to_matrix(A1)],[A0.z.to_matrix(A1)] ])
```

$\displaystyle \left[\begin{matrix}\cos{\left(\phi \right)}\\\sin{\left(\phi \right)}\\0\\- \sin{\left(\phi \right)}\\\cos{\left(\phi \right)}\\0\\0\\0\\1\end{matrix}\right]$

#### Símbolos dinámicos

Si queremos especificar que un símbolo puede variar con el tiempo, hay que usar la función `dynamicsymbols`:

```python
from sympy.physics.mechanics import dynamicsymbols
```

```python
alpha = dynamicsymbols('alpha')
alpha
```

$\displaystyle \alpha{\left(t \right)}$

Y pedir su derivada con el método `diff`:

```python
alpha.diff()
```

$\displaystyle \frac{d}{d t} \alpha{\left(t \right)}$

##### Ejercicio

(Sacado de Cuerva et al. "Teoría de los Helicópteros")

**Obtener la matriz de rotación de la pala $B$ respecto a los ejes $A1$.**

```python
A = IJKReferenceFrame("A")
```

```python
A1 = IJKReferenceFrame("A1")
psi = dynamicsymbols('psi')
A1.orient(A, 'Axis', [psi, A.z])
A1.dcm(A)  # T_{A1A}
```

$\displaystyle \left[\begin{matrix}\cos{\left(\psi{\left(t \right)} \right)} & \sin{\left(\psi{\left(t \right)} \right)} & 0\\- \sin{\left(\psi{\left(t \right)} \right)} & \cos{\left(\psi{\left(t \right)} \right)} & 0\\0 & 0 & 1\end{matrix}\right]$

```python
A2 = IJKReferenceFrame("A2")
beta = dynamicsymbols('beta')
A2.orient(A1, 'Axis', [beta, -A1.y])
A2.dcm(A1)  # T_{A2A1}
```

$\displaystyle \left[\begin{matrix}\cos{\left(\beta{\left(t \right)} \right)} & 0 & \sin{\left(\beta{\left(t \right)} \right)}\\0 & 1 & 0\\- \sin{\left(\beta{\left(t \right)} \right)} & 0 & \cos{\left(\beta{\left(t \right)} \right)}\end{matrix}\right]$

```python
A3 = IJKReferenceFrame("A3")
zeta = dynamicsymbols('zeta')
A3.orient(A2, 'Axis', [zeta, A2.z])
A3.dcm(A1)  # T_{A3A1}
```

$\displaystyle \left[\begin{matrix}\cos{\left(\beta{\left(t \right)} \right)} \cos{\left(\zeta{\left(t \right)} \right)} & \sin{\left(\zeta{\left(t \right)} \right)} & \sin{\left(\beta{\left(t \right)} \right)} \cos{\left(\zeta{\left(t \right)} \right)}\\- \sin{\left(\zeta{\left(t \right)} \right)} \cos{\left(\beta{\left(t \right)} \right)} & \cos{\left(\zeta{\left(t \right)} \right)} & - \sin{\left(\beta{\left(t \right)} \right)} \sin{\left(\zeta{\left(t \right)} \right)}\\- \sin{\left(\beta{\left(t \right)} \right)} & 0 & \cos{\left(\beta{\left(t \right)} \right)}\end{matrix}\right]$

```python
B = IJKReferenceFrame("B")
theta = dynamicsymbols('theta')
B.orient(A3, 'Axis', [theta, A3.x])
B.dcm(A3)  # T_{BA3}
```

$\displaystyle \left[\begin{matrix}1 & 0 & 0\\0 & \cos{\left(\theta{\left(t \right)} \right)} & \sin{\left(\theta{\left(t \right)} \right)}\\0 & - \sin{\left(\theta{\left(t \right)} \right)} & \cos{\left(\theta{\left(t \right)} \right)}\end{matrix}\right]$

```python
B.dcm(A2)
```

$\displaystyle \left[\begin{matrix}\cos{\left(\zeta{\left(t \right)} \right)} & \sin{\left(\zeta{\left(t \right)} \right)} & 0\\- \sin{\left(\zeta{\left(t \right)} \right)} \cos{\left(\theta{\left(t \right)} \right)} & \cos{\left(\theta{\left(t \right)} \right)} \cos{\left(\zeta{\left(t \right)} \right)} & \sin{\left(\theta{\left(t \right)} \right)}\\\sin{\left(\theta{\left(t \right)} \right)} \sin{\left(\zeta{\left(t \right)} \right)} & - \sin{\left(\theta{\left(t \right)} \right)} \cos{\left(\zeta{\left(t \right)} \right)} & \cos{\left(\theta{\left(t \right)} \right)}\end{matrix}\right]$

```python
B.dcm(A1)
```

$\displaystyle \left[\begin{matrix}\cos{\left(\beta{\left(t \right)} \right)} \cos{\left(\zeta{\left(t \right)} \right)} & \sin{\left(\zeta{\left(t \right)} \right)} & \sin{\left(\beta{\left(t \right)} \right)} \cos{\left(\zeta{\left(t \right)} \right)}\\- \sin{\left(\beta{\left(t \right)} \right)} \sin{\left(\theta{\left(t \right)} \right)} - \sin{\left(\zeta{\left(t \right)} \right)} \cos{\left(\beta{\left(t \right)} \right)} \cos{\left(\theta{\left(t \right)} \right)} & \cos{\left(\theta{\left(t \right)} \right)} \cos{\left(\zeta{\left(t \right)} \right)} & - \sin{\left(\beta{\left(t \right)} \right)} \sin{\left(\zeta{\left(t \right)} \right)} \cos{\left(\theta{\left(t \right)} \right)} + \sin{\left(\theta{\left(t \right)} \right)} \cos{\left(\beta{\left(t \right)} \right)}\\- \sin{\left(\beta{\left(t \right)} \right)} \cos{\left(\theta{\left(t \right)} \right)} + \sin{\left(\theta{\left(t \right)} \right)} \sin{\left(\zeta{\left(t \right)} \right)} \cos{\left(\beta{\left(t \right)} \right)} & - \sin{\left(\theta{\left(t \right)} \right)} \cos{\left(\zeta{\left(t \right)} \right)} & \sin{\left(\beta{\left(t \right)} \right)} \sin{\left(\theta{\left(t \right)} \right)} \sin{\left(\zeta{\left(t \right)} \right)} + \cos{\left(\beta{\left(t \right)} \right)} \cos{\left(\theta{\left(t \right)} \right)}\end{matrix}\right]$

#### Velocidad angular

También podemos hallar la velocidad angular de un sistema respecto a otro usando el método `ang_vel_in`:

```python
B.ang_vel_in(A2)
```

$\displaystyle \frac{d}{d t} \theta{\left(t \right)}\mathbf{i}_{A3} + \frac{d}{d t} \zeta{\left(t \right)}\mathbf{k}_{A2}$

```python
B.ang_vel_in(A)
```

$\displaystyle \frac{d}{d t} \theta{\left(t \right)}\mathbf{i}_{A3} + \frac{d}{d t} \zeta{\left(t \right)}\mathbf{k}_{A2} -  \frac{d}{d t} \beta{\left(t \right)}\mathbf{j}_{A1} + \frac{d}{d t} \psi{\left(t \right)}\mathbf{k}_{A}$

```python
B.ang_vel_in(A).express(A)
```

$\displaystyle (\left(- \sin{\left(\psi{\left(t \right)} \right)} \sin{\left(\zeta{\left(t \right)} \right)} + \cos{\left(\beta{\left(t \right)} \right)} \cos{\left(\psi{\left(t \right)} \right)} \cos{\left(\zeta{\left(t \right)} \right)}\right) \frac{d}{d t} \theta{\left(t \right)} - \sin{\left(\beta{\left(t \right)} \right)} \cos{\left(\psi{\left(t \right)} \right)} \frac{d}{d t} \zeta{\left(t \right)} + \sin{\left(\psi{\left(t \right)} \right)} \frac{d}{d t} \beta{\left(t \right)})\mathbf{i}_{A} + (\left(\sin{\left(\psi{\left(t \right)} \right)} \cos{\left(\beta{\left(t \right)} \right)} \cos{\left(\zeta{\left(t \right)} \right)} + \sin{\left(\zeta{\left(t \right)} \right)} \cos{\left(\psi{\left(t \right)} \right)}\right) \frac{d}{d t} \theta{\left(t \right)} - \sin{\left(\beta{\left(t \right)} \right)} \sin{\left(\psi{\left(t \right)} \right)} \frac{d}{d t} \zeta{\left(t \right)} - \cos{\left(\psi{\left(t \right)} \right)} \frac{d}{d t} \beta{\left(t \right)})\mathbf{j}_{A} + (\sin{\left(\beta{\left(t \right)} \right)} \cos{\left(\zeta{\left(t \right)} \right)} \frac{d}{d t} \theta{\left(t \right)} + \cos{\left(\beta{\left(t \right)} \right)} \frac{d}{d t} \zeta{\left(t \right)} + \frac{d}{d t} \psi{\left(t \right)})\mathbf{k}_{A}$

En ocasiones, la representación gráfica puede fallar, pero se puede volver a desactivar y activar llamando a la función`init_printing(pretty_print=True)` con diferentes valores (True/False) para `pretty_print`

### Derivada en ejes móviles

Hacer una derivada con la fórmula lo hace cualquiera, pero SymPy puede encargarse automáticamente.

```python
v1 = A1.x
v1
```

$\displaystyle \mathbf{i}_{A1}$

```python
#v1.diff(dynamicsymbols._t, A2)
dv1 = v1.diff(symbols('t'), A)
dv1
```

$\displaystyle (\sin^{2}{\left(\psi{\left(t \right)} \right)} \frac{d}{d t} \psi{\left(t \right)} + \cos^{2}{\left(\psi{\left(t \right)} \right)} \frac{d}{d t} \psi{\left(t \right)})\mathbf{j}_{A1}$

```python
dv1.to_matrix(A1)
```

$\displaystyle \left[\begin{matrix}0\\\sin^{2}{\left(\psi{\left(t \right)} \right)} \frac{d}{d t} \psi{\left(t \right)} + \cos^{2}{\left(\psi{\left(t \right)} \right)} \frac{d}{d t} \psi{\left(t \right)}\\0\end{matrix}\right]$

```python
(dv1 & A1.j).simplify()  # dv1 & A1.j is the dot produt
```

$\displaystyle \frac{d}{d t} \psi{\left(t \right)}$

### Puntos, velocidades y la rueda que no desliza

El último paso que nos queda para completar la cinemática es la posibilidad de definir puntos en sólidos y aplicar su campo de velocidades. SymPy también permite esto, y para ello no tenemos más que importar la clase `Point`.

```python
from sympy.physics.mechanics import Point
```

```python
O = Point("O")
```

Para trabajar como lo haríamos en la escuela, vamos a especificar que $O$ es el origen de $A$, y para eso vamos a imponer que su velocidad es cero con el método `set_vel`:

```python
O.set_vel(A, 0)
```

Para definir nuevos puntos, podemos utilizar el método `locate_new`:

```python
e_b = symbols('e_b')
E_b = O.locatenew('E_b', e_b * A1.x)
```

Y para obtener vectores de un punto a otro, el método `pos_from`:

```python
E_b.pos_from(O)
```

$\displaystyle e_{b}\mathbf{i}_{A1}$

La notación de este paquete está influenciada por el libro Kane, T. R. & Levinson, D. A. "Dynamics, Theory and Applications". Es ligeramente distinto a como estudiamos nosotros en la escuela, pero ¡están abiertos a que les hagamos cualquier tipo de sugerencia! https://github.com/sympy/sympy/issues/2584#issuecomment-31552654

Por último, el **campo de velocidades de un sólido rígido** se formula usando el método `v2pt_theory`.

$$v^P_A = v^O_A + \omega_{A_1 A} \times \mathbf{OP}$$

Este método pertenece *al punto del cual queremos conocer la velocidad* y recibe tres parámetros:

* `O`, punto de velocidad conocida respecto a A
* `A`, sistema de referencia donde queremos calcular la velocidad
* `A1`, sistema de referencia donde están fijos ambos puntos (_sistema de arrastre_)

Por tanto, para hallar la velocidad del punto que acabamos de crear:

```python
E_b.v2pt_theory(O, A, A1)
```

$\displaystyle e_{b} \frac{d}{d t} \psi{\left(t \right)}\mathbf{j}_{A1}$

##### Ejercicio

(Apuntes de Óscar López Rebollal)

**¡Halla la velocidad y la aceleración de $P$!**

```python
# Creamos nuestros sistemas de referencia
A1 = IJKReferenceFrame('1')
A0 = IJKReferenceFrame('0')
A2 = IJKReferenceFrame('2')
```

```python
# Creamos los símbolos dinámicos necesarios
xi, theta = dynamicsymbols('xi, theta')
xi, theta
```

$\displaystyle \left( \xi{\left(t \right)}, \  \theta{\left(t \right)}\right)$

```python
# Orientamos los sistemas de referencia
A0.orient(A1, 'Axis', [0, A1.k])  # A0 no gira respecto a A1
A2.orient(A0, 'Axis', [theta, A0.k])
```

```python
A2.dcm(A1)
```

$\displaystyle \left[\begin{matrix}\cos{\left(\theta{\left(t \right)} \right)} & \sin{\left(\theta{\left(t \right)} \right)} & 0\\- \sin{\left(\theta{\left(t \right)} \right)} & \cos{\left(\theta{\left(t \right)} \right)} & 0\\0 & 0 & 1\end{matrix}\right]$

```python
# Creamos el punto C, centro del disco, y especificamos su velocidad
# respecto a A1
C = Point('C')
C.set_vel(A1, xi.diff() * A1.x)
```

```python
# Localizamos el punto P, punto fijo del disco, respecto a C, en
# el sistema A2 (que gira solidariamente con el disco)
R = symbols('R')
P = C.locatenew('P', -R * A2.j)
P.pos_from(C)
```

$\displaystyle -  R\mathbf{j}_{2}$

```python
# Hallamos la velocidad de P en A1, expresada en A0
# ¡Con esta llamada ya estamos diciendo que C y P son fijos en A2!
P.v2pt_theory(C, A1, A2).express(A0)
```

$\displaystyle (R \cos{\left(\theta{\left(t \right)} \right)} \frac{d}{d t} \theta{\left(t \right)} + \frac{d}{d t} \xi{\left(t \right)})\mathbf{i}_{0} + R \sin{\left(\theta{\left(t \right)} \right)} \frac{d}{d t} \theta{\left(t \right)}\mathbf{j}_{0}$

**Misión cumplida :)**

---

_Hemos hecho un repaso bastante profundo de las posibilidades del paquete `mechanics` de SymPy. Nos hemos dejado algunas cosas en el tintero pero no demasiadas: esta funcionalidad aún se está expandiendo y necesita pulir algunos detalles._

**Referencias**

* Capítulo de **aeromecánica** del libro de Cuerva y otros http://nbviewer.ipython.org/gist/Juanlu001/7711865
* Estabilidad longitudinal de un Boeing 747 http://nbviewer.ipython.org/github/AlexS12/Mecanica_Vuelo/blob/master/MVII_MatrizSistema.ipynb

_¿Serás tú el siguiente que publique un notebook usando SymPy? ;)_

Si te ha gustado esta clase:

Tweet

---

####
¡Síguenos en Twitter!

###### Follow @Pybonacci   Follow @Alex__S12   Follow @newlawrence

#####
Curso AeroPython por Juan Luis Cano Rodriguez y Alejandro Sáez Mollejo se distribuye bajo una Licencia Creative Commons Atribución 4.0 Internacional.

#####

---
_Las siguientes celdas contienen configuración del Notebook_

_Para visualizar y utlizar los enlaces a Twitter el notebook debe ejecutarse como [seguro](http://ipython.org/ipython-doc/dev/notebook/security.html)_

    File > Trusted Notebook

```python
%%html
<a href="https://twitter.com/Pybonacci" class="twitter-follow-button" data-show-count="false">Follow @Pybonacci</a>

```

Follow @Pybonacci

```python
# Esta celda da el estilo al notebook
from IPython.core.display import HTML
css_file = '../styles/aeropython.css'
HTML(open(css_file, "r").read())
```

/* This template is inspired in the one used by Lorena Barba
in the numerical-mooc repository: https://github.com/numerical-mooc/numerical-mooc
We thank her work and hope you also enjoy the look of the notobooks with this style */

<link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro|Josefin+Sans:400,700,400italic|Ubuntu+Condensed' rel='stylesheet' type='text/css'>

El estilo se ha aplicado =)


$$ \newcommand{\pd}[2]{ \frac{\partial #1}{\partial #2} }
\newcommand{\od}[2]{\frac{d #1}{d #2}}
\newcommand{\td}[2]{\frac{D #1}{D #2}}
\newcommand{\ab}[1]{\langle #1 \rangle}
\newcommand{\bss}[1]{\textsf{\textbf{#1}}}
\newcommand{\ol}{\overline}
\newcommand{\olx}[1]{\overline{#1}^x}
$$

# Hydrostatic and Geostrophic Balances

In the previous lecture, we obtained the local-tangent-plane form of the Boussinesq equations of motion. We repeat the final equations, in component form, below:

$$ \begin{align}
\td{u}{t} - f v &= -\pd{\phi}{x} + \nu \nabla^2 u \\
\td{v}{t} + f u &= -\pd{\phi}{y} + \nu \nabla^2 v \\
\td{w}{t}       &= -\pd{\phi}{z} + b + \nu \nabla^2 w  \ .
\end{align} $$

In this lecture, we ask _what are the dominant balances in these equations under common oceanographic conditions_.

## Hydrostatic Balance

We already saw hydrostatic balance for the _background pressure and density field_. For the large-scale flow, the dynamic pressure is also in hydrostatic balance:

$$ \pd{\phi}{z} = b \ . $$

To remind ourselves of the underlying physics, we can write out $\phi$ and $b$ explicitly and drop the common factor of $1/\rho_0$:

$$ \pd{}{z} \delta p = - g \delta \rho \ . $$

Hydrostatic balance can be used to define $\phi$ at any point. In order to do so, however, we must think a bit more about sea-surface height and its relation to pressure.

## Sea Surface Height, Dynamic Height, and Pressure

What is the dynamic pressure $\phi$ at an arbitrary depth $z$ for a flow in hydrostatic balance? The dynamc sea-surface $\eta$ is defined relative to the mean geoid (i.e. a surface of constant geopotential) at $z=0$.

We go back to the full hydrostatic balance with both backround and dynamic pressure:

$$ \pd{}{z} (p) = - g \rho \ . $$

We now integrate this equation in the vertical from an arbitrary $z$ up to the sea surface $\eta$:

$$ \int_z^\eta \pd{}{z'} p dz'
= p(\eta) - p(z)
= - g \int_z^\eta  \rho dz' \ . $$

$p(\eta)$ is the pressure right at the sea surface, which is given by the atmospheric pressure. Although atmospheric pressure loading can have a small effect on ocean circulation, it is generally negligible compared to the huge pressures generated internally by the ocean. We will now take $p(\eta)=0$ to simplify the bookkeeping, this gives.

$$ p(z) = g \int_z^\eta  \rho dz' \ . $$

Now let's subtract the reference pressure. It given integrating the hydrostatic balance for the background density up to $z=0$. This upper limit is important: the reference pressure is defined for a flat sea surface.

$$ p_{ref}(z) = g \int_z^0  \rho_0 dz' \ . $$

Subtracting the two equations, we obtain

$$ \begin{align}
\delta p(z) = p(z) - p_{ref}(z) &= g \int_z^\eta  \rho dz' \ - g \int_z^0  \rho_0 dz' \\
&= g \int_0^\eta  \rho  dz' + g \int_z^0 \delta \rho dz' \\
&= g \rho_0 \int_0^\eta  dz' + g \int_0^\eta  \delta \rho  dz' + g \int_z^0 \delta \rho dz'
\end{align} $$

We see there is a contribution from the density fluctuations in the interior (second term), plus the variations in the sea-surface height (first term). We can, to the usual precision of the Boussinesq approximation, neglect the density fluctuations within the depths 0 to $\eta$. Dividing through by $\rho_0$, we obtain

$$ \begin{align}
\phi(z) = g \eta  - \int_z^0 b dz'
\end{align} $$

It is common in oceanography to define a quanity known as _dynamic height_, which expresses dynamic pressure variations in terms of their effective sea-surface height. In our notation, with the Boussinesq approximation, dynamic height is defined as

$$ D = \frac{\phi}{g} \ .$$

The dynamic pressure at the ocean bottom is given by

$$ \begin{align}
\phi(-H) = g \eta  - \int_{-H}^0 b dz' \ .
\end{align} $$

The first term is related to fluctuations in the total ocean volume at each point.
The second term is called the _steric_ component.

## Rossby Number

Let's estimate the relative size of the acceleration to Coriolis terms on the left-hand side of the horizontal momentum equations.

The ratio of these terms defines the _Rossby number_.

$$ R_O =  \frac{ \left | \td{u}{t} \right | }{ | f v |} $$

The magnitude of the acceleration term can be estimated as $U^2 / L$, where $U$ is a representitive velocity scale of the flow and $L$ is a representative length scale. So we can estimate the Rossby number as

$$ R_O =  \frac{U}{f L} \ . $$

What are representative values? For the large-scale ocean circulation, U = 0.01 m/s, L = 1000 km, and f = 10$^{-4}$ s$^{-1}$. This gives $R_O = 10^{-4}$. So the _acceleration terms are often totally negligible_!

For low Rossby number conditions, we can neglect the acceleration and write the horizontal momentum equations as

$$ \begin{align} - f v &= -\pd{\phi}{x} + \nu \nabla^2 u \\
 f u &= -\pd{\phi}{y} + \nu \nabla^2 v
\end{align} $$

The _geostrophic flow_ is defined as the flow determined by the balance between the Coriolis term and and the pressure gradient:

$$ \begin{align} - f v_g &= -\pd{\phi}{x} \\
  f u_g &= -\pd{\phi}{y}
\end{align} $$

while the ageostrophic flow is defined via the balance between the Coriolis term and the friction term:

$$ \begin{align} - f v_a &= \nu \nabla^2 u \\
  f u_a &= \nu \nabla^2 v
\end{align} $$

The total flow is given by the sum of the geostrophic and ageostrophic components:

$$ \mathbf{u} = \mathbf{u}_a + \mathbf{u}_g \ .$$

## Geostrophic Flow

Away from the boundaries, Friction is weak, and the flow is, to a good approximation geostrophic. Geostrophic (or "balanced") flow is a ubiquitous feature of flows in the ocean and atmosphere. Geostrophic flow is characterized by flow along the pressure contours (i.e. _isobars_), as illustrated below.

Rotational flow around pressure minimum is called _cyclonic_. Cyclonc flow is counterclockwise in the northern hemisphere and (due to the change of sign of $f$) clockwise in the southern hemisphere.

_ [AVISO mean dynamic topography](https://www.aviso.altimetry.fr/en/applications/ocean/large-scale-circulation/mean-dynamic-topography.html) _

### Thermal Wind

The geostrophic flow is determined by the pressure and the pressure is determined by the density (via hydrostatic balance). We can see this relationship more clearly if we take the derivative in $z$ of the geostrophic equations:

$$ \begin{align} - f \pd{v_g}{z} &= -\pd{}{x}\pd{\phi}{z} = -\pd{b}{x}\\
f \pd{u_g}{z} &= -\pd{}{y} \pd{\phi}{z} = -\pd{b}{y} \ .
\end{align} $$

These equations, called _thermal wind_ relate the _vertical shear of the geostrophic flow_ to the _horizontal gradients of buoyancy_. They are very useful for interpreting hydrographic data.

[WOCE Atlantic Atlas Vol. 3](http://whp-atlas.ucsd.edu/whp_atlas/atlantic/a03/sections/printatlas/printatlas.htm)

```python
import pooch
import xarray as xr
from matplotlib import pyplot as plt

url = "ftp://ftp.spacecenter.dk/pub/DTU10/2_MIN/DTU10MDT_2min.nc"
fname = pooch.retrieve(url, known_hash="5d8eb0782514ca5f061eecc5a726f05b34a6ca34281cd644ad19c059ea8b528f")
ds = xr.open_dataset(fname)
ds
```

    Downloading data from 'ftp://ftp.spacecenter.dk/pub/DTU10/2_MIN/DTU10MDT_2min.nc' to file '/home/jovyan/.cache/pooch/cd1481012b784d34e848db69c19b022f-DTU10MDT_2min.nc'.
    SHA256 hash of downloaded file: 5d8eb0782514ca5f061eecc5a726f05b34a6ca34281cd644ad19c059ea8b528f
    Use this value as the 'known_hash' argument of 'pooch.retrieve' to ensure that the file hasn't changed if it is downloaded again in the future.

<svg style="position: absolute; width: 0; height: 0; overflow: hidden">
<defs>
<symbol id="icon-database" viewBox="0 0 32 32">
<path d="M16 0c-8.837 0-16 2.239-16 5v4c0 2.761 7.163 5 16 5s16-2.239 16-5v-4c0-2.761-7.163-5-16-5z"></path>
<path d="M16 17c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z"></path>
<path d="M16 26c-8.837 0-16-2.239-16-5v6c0 2.761 7.163 5 16 5s16-2.239 16-5v-6c0 2.761-7.163 5-16 5z"></path>
</symbol>
<symbol id="icon-file-text2" viewBox="0 0 32 32">
<path d="M28.681 7.159c-0.694-0.947-1.662-2.053-2.724-3.116s-2.169-2.030-3.116-2.724c-1.612-1.182-2.393-1.319-2.841-1.319h-15.5c-1.378 0-2.5 1.121-2.5 2.5v27c0 1.378 1.122 2.5 2.5 2.5h23c1.378 0 2.5-1.122 2.5-2.5v-19.5c0-0.448-0.137-1.23-1.319-2.841zM24.543 5.457c0.959 0.959 1.712 1.825 2.268 2.543h-4.811v-4.811c0.718 0.556 1.584 1.309 2.543 2.268zM28 29.5c0 0.271-0.229 0.5-0.5 0.5h-23c-0.271 0-0.5-0.229-0.5-0.5v-27c0-0.271 0.229-0.5 0.5-0.5 0 0 15.499-0 15.5 0v7c0 0.552 0.448 1 1 1h7v19.5z"></path>
<path d="M23 26h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z"></path>
<path d="M23 22h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z"></path>
<path d="M23 18h-14c-0.552 0-1-0.448-1-1s0.448-1 1-1h14c0.552 0 1 0.448 1 1s-0.448 1-1 1z"></path>
</symbol>
</defs>
</svg>

<xarray.Dataset>
Dimensions:  (lon: 10801, lat: 5400)
Coordinates:
  * lon      (lon) float64 0.0 0.03333 0.06667 0.1 ... 359.9 359.9 360.0 360.0
  * lat      (lat) float64 -89.98 -89.95 -89.92 -89.88 ... 89.92 89.95 89.98
Data variables:
    mdt      (lat, lon) float32 ...
Attributes:
    Conventions:  COARDS/CF-1.0
    title:        DTU10MDT_2min.mdt.nc
    source:       Danish National Space Center
    node_offset:  1

xarray.Dataset

<input id='section-174307df-cece-4c62-ab91-3d91ecf736ad' class='xr-section-summary-in' type='checkbox' disabled >Dimensions:

lon: 10801

lat: 5400

<input id='section-10a0027b-c404-484b-a129-dc848711bf6c' class='xr-section-summary-in' type='checkbox'  checked>Coordinates: (2)

lon

(lon)

float64

0.0 0.03333 0.06667 ... 360.0 360.0
<input id='attrs-02b957da-dcda-4676-8a0c-b51b0a03ecf8' class='xr-var-attrs-in' type='checkbox' ><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-6657f096-9613-4a1f-a801-11dd15b7eb90' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

long_name :

longitude

units :

degrees_east

actual_range :

[-1.66666667e-02  3.60016667e+02]

array([0.000000e+00, 3.333333e-02, 6.666667e-02, ..., 3.599333e+02,
       3.599667e+02, 3.600000e+02])

lat

(lat)

float64

-89.98 -89.95 ... 89.95 89.98
<input id='attrs-344e807a-01b8-4e4b-8e70-f0b625885f2a' class='xr-var-attrs-in' type='checkbox' ><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-8cb5590e-85d2-495b-949e-34aad4b97064' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

long_name :

latitude

units :

degrees_north

actual_range :

[-90.  90.]

array([-89.983333, -89.95    , -89.916667, ...,  89.916667,  89.95    ,
        89.983333])

<input id='section-01366bd1-6bd9-4231-a5a7-aa68bc518030' class='xr-section-summary-in' type='checkbox'  checked>Data variables: (1)

mdt

(lat, lon)

float32

...
<input id='attrs-9c2aea3c-73af-4ab1-94d8-b2498f118152' class='xr-var-attrs-in' type='checkbox' ><svg class='icon xr-icon-file-text2'><use xlink:href='#icon-file-text2'></use></svg><input id='data-f47a4624-3a2b-47ba-a320-6b73638362b4' class='xr-var-data-in' type='checkbox'><svg class='icon xr-icon-database'><use xlink:href='#icon-database'></use></svg>

long_name :

mean ocean dynamic topography

units :

m

actual_range :

[-2.26   2.155]

[58325400 values with dtype=float32]

<input id='section-708c400b-08df-4f86-aae5-fad7063cdeae' class='xr-section-summary-in' type='checkbox'  checked>Attributes: (4)

Conventions :

COARDS/CF-1.0

title :

DTU10MDT_2min.mdt.nc

source :

Danish National Space Center

node_offset :

1

```python
mdt = ds.mdt.coarsen(lon=10, lat=10, boundary='pad').mean()
```

```python
import cartopy.crs as ccrs
proj = ccrs.Robinson(central_longitude=180)

fig = plt.figure(figsize=(16, 6))
ax = plt.axes(projection=proj, facecolor='0.8')
mdt.plot(ax=ax, transform=ccrs.PlateCarree())
ax.coastlines()
```

```python

```


## Differentiation and Derivatives
So far in this course, you've learned how to evaluate limits for points on a line. Now you're going to build on that knowledge and look at a calculus technique called *differentiation*. In differentiation, we use our knowledge of limits to calculate the *derivative* of a function in order to determine the rate of change at an individual point on a line.

Let's remind ourselves of the problem we're trying to solve, here's a function:

\begin{equation}f(x) = x^{2} + x\end{equation}

We can visualize part of the line that this function defines using the folllowing Python code:

```python
%matplotlib inline

# Here's the function
def f(x):
    return x**2 + x

from matplotlib import pyplot as plt

# Create an array of x values from 0 to 10 to plot
x = list(range(0, 11))

# Use the function to get the y values
y = [f(i) for i in x]

# Set up the graph
plt.xlabel('x')
plt.ylabel('f(x)')
plt.grid()

# Plot the function
plt.plot(x,y, color='green')

plt.show()
```

Now, we know that we can calculate the average rate of change for a given interval on the line by calculating the slope for a secant line that connects two points on the line. For example, we can calculate the average change for the interval between x=4 and x=6 by dividing the change (or *delta*, indicated as Δ) in the value of *f(x)* by the change in the value of *x*:

\begin{equation}m = \frac{\Delta{f(x)}}{\Delta{x}} \end{equation}

The delta for *f(x)* is calculated by subtracting the *f(x)* values of our points, and the delta for *x* is calculated by subtracting the *x* values of our points; like this:

\begin{equation}m = \frac{f(x_{2}) - f(x_{1})}{x_{2} - x_{1}} \end{equation}

So for the interval between x=4 and x=6, that's:

\begin{equation}m = \frac{f(6) - f(4)}{6 - 4} \end{equation}

We can calculate and plot this using the following Python:

```python
%matplotlib inline

def f(x):
    return x**2 + x

from matplotlib import pyplot as plt

# Create an array of x values from 0 to 10 to plot
x = list(range(0, 11))

# Use the function to get the y values
y = [f(i) for i in x]

# Set the a values
x1 = 4
x2 = 6

# Get the corresponding f(x) values
y1 = f(x1)
y2 = f(x2)

# Calculate the slope by dividing the deltas
a = (y2 - y1)/(x2 - x1)

# Create an array of x values for the secant line
sx = [x1,x2]

# Use the function to get the y values
sy = [f(i) for i in sx]

# Set up the graph
plt.xlabel('x')
plt.ylabel('f(x)')
plt.grid()

# Plot the function
plt.plot(x,y, color='green')

# Plot the interval points
plt.scatter([x1,x2],[y1,y2], c='red')

# Plot the secant line
plt.plot(sx,sy, color='magenta')

# Display the calculated average rate of change
plt.annotate('Average change =' + str(a),(x2, (y2+y1)/2))

plt.show()
```

The average rate of change for the interval between x=4 and x=6 is 11/1 (or simply 11), meaning that for every **1** added to *x*, *f(x)* increases by **11**. Put another way, if x represents time in seconds and f(x) represents distance in meters, the average rate of change for distance over time (in other words, *velocity*) for the 4 to 6 second interval is 11 meters-per-second.

So far, this is just basic algebra; but what if instead of the average rate of change over an interval, we want to calculate the rate of change at a single point, say, where x = 4.5?

One approach we could take is to create a secant line between the point at which we want the slope and another point on the function line that is infintesimally close to it. So close in fact that the secant line is actually a tangent that goes through both points. We can then calculate the slope for the secant line as before. This would look something like the graph produced by the following code:

```python
%matplotlib inline

def f(x):
    return x**2 + x

from matplotlib import pyplot as plt

# Create an array of x values from 0 to 10 to plot
x = list(range(0, 11, 1))

# Use the function to get the y values
y = [f(i) for i in x]

# Set the x1 point, arbitrarily 5
x1 = 4.5
y1 = f(x1)

# Set the x2 point, very close to x1
x2 = 5.000000001
y2 = f(x2)

# Set up the graph
plt.xlabel('x')
plt.ylabel('f(x)')
plt.grid()

# Plot the function
plt.plot(x,y, color='green')

# Plot the point
plt.scatter(x1,y1, c='red')
plt.annotate('x' + str(x1),(x1,y1), xytext=(x1-0.5, y1+3))

# Approximate the tangent slope and plot it
m = (y2-y1)/(x2-x1)
xMin = x1 - 3
yMin = y1 - (3*m)
xMax = x1 + 3
yMax = y1 + (3*m)
plt.plot([xMin,xMax],[yMin,yMax], color='magenta')

plt.show()
```

## Calculating a Derivative
In the Python code above, we created the (almost) tangential secant line by specifying a point that is very close to the point at which we want to calculate the rate of change. This is adequate to show the line conceptually in the graph, but it's not a particularly generalizable (or accurate) way to actually calculate the line so that we can get the rate of change at any given point.

If only we knew of a way to calculate a point on the line that is as close as possible to point with a given *x* value.

Oh wait, we do! It's a *limit*.

So how do we apply a limit in this scenario? Well, let's start by examining our general approach to calculating slope in a little more detail.Our tried and tested approach is to plot a secant line between two points at different values of x, so let's plot an arbitrary (*x,y*) point, and then add an arbitrary amount to *x*, which we'll call *h*. Then we know that we can plot a secant line between (*x,f(x)*) and (*x+h,f(x+h)*) and find its slope.

Run the cell below to see these points:

```python
%matplotlib inline

def f(x):
    return x**2 + x

from matplotlib import pyplot as plt

# Create an array of x values from 0 to 10 to plot
x = list(range(0, 11))

# Use the function to get the y values
y = [f(i) for i in x]

# Set the x point
x1 = 3
y1 = f(x1)

# set the increment
h = 3

# set the x+h point
x2 = x1+h
y2 = f(x2)

# Set up the graph
plt.xlabel('x')
plt.ylabel('f(x)')
plt.grid()

# Plot the function
plt.plot(x,y, color='green')

# Plot the x point
plt.scatter(x1,y1, c='red')
plt.annotate('(x,f(x))',(x1,y1), xytext=(x1-0.5, y1+3))

# Plot the x+h point
plt.scatter(x2,y2, c='red')
plt.annotate('(x+h, f(x+h))',(x2,y2), xytext=(x2+0.5, y2))

plt.show()
```

As we saw previously, our formula to calculate slope is:

\begin{equation}m = \frac{\Delta{f(x)}}{\Delta{x}} \end{equation}

The delta for *f(x)* is calculated by subtracting the *f(x + h)* and *f(x)* values of our points, and the delta for *x* is just the difference between *x* and *x + h*; in other words, *h*:

\begin{equation}m = \frac{f(x + h) - f(x)}{h} \end{equation}

What we actually need is the slope at the shortest possible distance between x and x+h, so we're looking for the smallest possible value of *h*. In other words, we need the limit as *h* approaches 0.

\begin{equation}\lim_{h \to 0} \frac{f(x + h) - f(x)}{h} \end{equation}

This equation is generalizable, and we can use it as the definition of a function to help us find the slope at any given value of *x* on the line, and it's what we call the *derivative* of our original function (which in this case is called *f*). This is generally indicated in *Lagrange* notation like this:

\begin{equation}f'(x) = \lim_{h \to 0} \frac{f(x + h) - f(x)}{h} \end{equation}

You'll also sometimes see derivatives written in *Leibniz's* notation like this:

\begin{equation}\frac{d}{dx}f(x) = \lim_{h \to 0} \frac{f(x + h) - f(x)}{h} \end{equation}

***Note:*** *Some textbooks use **h** to symbolize the difference between **x0** and **x1**, while others use **Δx**. It makes no diffrerence which symbolic value you use.*

#### Alternate Form for a Derivative
The formula above shows the generalized form for a derivative. You can use the derivative function to get the slope at any given point, for example to get the slope at point *a* you could just plug the value for *a* into the generalized derivative function:

\begin{equation}f'(\textbf{a}) = \lim_{h \to 0} \frac{f(\textbf{a} + h) - f(\textbf{a})}{h} \end{equation}

Or you could use the alternate form, which is specific to point *a*:

\begin{equation}f'(a) = \lim_{x \to a} \frac{f(x) - f(a)}{x - a} \end{equation}

These are mathematically equivalent.

### Finding the Derivative for a Specific Point
It's easier to understand differentiation by seeing it in action, so let's use it to find the derivitive for a specific point in the function ***f***.

Here's the definition of function ***f***:

\begin{equation}f(x) = x^{2} + x\end{equation}

Let's say we want to find ***f'(2)*** (the derivative for ***f*** when ***x*** is 2); so we're trying to find the slope at the point shown by the following code:

```python
%matplotlib inline

def f(x):
    return x**2 + x

from matplotlib import pyplot as plt

# Create an array of x values from 0 to 10 to plot
x = list(range(0, 11))

# Use the function to get the y values
y = [f(i) for i in x]

# Set the point
x1 = 2
y1 = f(x1)

# Set up the graph
plt.xlabel('x')
plt.ylabel('f(x)')
plt.grid()

# Plot the function
plt.plot(x,y, color='green')

# Plot the point
plt.scatter(x1,y1, c='red')
plt.annotate('(x,f(x))',(x1,y1), xytext=(x1-0.5, y1+3))

plt.show()
```

Here's our generalized formula for finding a derivative at a specific point (*a*):

\begin{equation}f'(a) = \lim_{h \to 0} \frac{f(a + h) - f(a)}{h} \end{equation}

So let's just start by plugging our *a* value in:

\begin{equation}f'(\textbf{2}) = \lim_{h \to 0} \frac{f(\textbf{2} + h) - f(\textbf{2})}{h} \end{equation}

We know that ***f(x)*** encapsulates the equation ***x2 + x***, so we can rewrite our derivative equation as:

\begin{equation}f'(2) = \lim_{h \to 0} \frac{((2+h)^{2} + 2 + h) - (2^{2} + 2)}{h} \end{equation}

We can apply the distribution property to ***(2 + h)2*** using the rule that *(a + b)2 = a2 + b2 + 2ab*:

\begin{equation}f'(2) = \lim_{h \to 0} \frac{(4 + h^{2} + 4h + 2 + h) - (2^{2} + 2)}{h} \end{equation}

Then we can simplify 22 + 2 (22 is 4, plus 2 gives is 6):

\begin{equation}f'(2) = \lim_{h \to 0} \frac{(4 + h^{2} + 4h + 2 + h) - 6}{h} \end{equation}

We can combine like terms on the left side of the numerator to make things a little clearer:

\begin{equation}f'(2) = \lim_{h \to 0} \frac{(h^{2} + 5h + 6) - 6}{h} \end{equation}

Which combines even further to get rid of the *6*:

\begin{equation}f'(2) = \lim_{h \to 0} \frac{h^{2} + 5h}{h} \end{equation}

And finally, we can simplify the fraction:

\begin{equation}f'(2) = \lim_{h \to 0} h + 5 \end{equation}

To get the limit when *h* is approaching 0, we can use direct substitution for h:

\begin{equation}f'(2) = 0 + 5 \end{equation}

so:

\begin{equation}f'(2) = 5 \end{equation}

Let's draw a tangent line with that slope on our graph to see if it looks right:

```python
%matplotlib inline

def f(x):
    return x**2 + x

from matplotlib import pyplot as plt

# Create an array of x values from 0 to 10 to plot
x = list(range(0, 11))

# Use the function to get the y values
y = [f(i) for i in x]

# Set the point
x1 = 2
y1 = f(x1)

# Specify the derivative we calculated above
m = 5

# Set up the graph
plt.xlabel('x')
plt.ylabel('f(x)')
plt.grid()

# Plot the function
plt.plot(x,y, color='green')

# Plot the point
plt.scatter(x1,y1, c='red')
plt.annotate('(x,f(x))',(x1,y1), xytext=(x1-0.5, y1+3))

# Plot the tangent line using the derivative we calculated
xMin = x1 - 3
yMin = y1 - (3*m)
xMax = x1 + 3
yMax = y1 + (3*m)
plt.plot([xMin,xMax],[yMin,yMax], color='magenta')

plt.show()
```

### Finding a Derivative for Any Point
Now let's put it all together and define a function that we can use to find the derivative for any point in the ***f*** function:

Here's our general derivative function again:

\begin{equation}f'(x) = \lim_{h \to 0} \frac{f(x + h) - f(x)}{h} \end{equation}

We know that ***f(x)*** encapsulates the equation ***x2 + x***, so we can rewrite our derivative equation as:

\begin{equation}f'(x) = \lim_{h \to 0} \frac{((x+h)^{2} + x + h) - (x^{2} + x)}{h} \end{equation}

We can apply the distribution property to ***(x + h)2*** using the rule that *(a + b)2 = a2 + b2 + 2ab*:

\begin{equation}f'(x) = \lim_{h \to 0} \frac{(x^{2} + h^{2} + 2xh + x + h) - (x^{2} + x)}{h} \end{equation}

Then we can use the distributive property to expand ***- (x2 + x)***, which is the same thing as *-1(x2 + x)*, to ***- x2 - x***:

\begin{equation}f'(x) = \lim_{h \to 0} \frac{x^{2} + h^{2} + 2xh + x + h - x^{2} - x}{h} \end{equation}

We can combine like terms on the numerator to make things a little clearer:

\begin{equation}f'(x) = \lim_{h \to 0} \frac{h^{2} + 2xh + h}{h} \end{equation}

And finally, we can simplify the fraction:

\begin{equation}f'(x) = \lim_{h \to 0} 2x + h + 1 \end{equation}

To get the limit when *h* is approaching 0, we can use direct substitution for h:

\begin{equation}f'(x) = 2x + 0 + 1 \end{equation}

so:

\begin{equation}f'(x) = 2x + 1 \end{equation}

Now we have a function for the derivative of ***f***, which we can apply to any *x* value to find the slope of the function at ***f(x***).

For example, let's find the derivative of ***f*** with an *x* value of 5:

\begin{equation}f'(5) = 2\cdot5 + 1 = 10 + 1 = 11\end{equation}

Let's use Python to define the ***f(x)*** and ***f'(x)*** functions, plot ***f(5)*** and show the tangent line for ***f'(5)***:

```python
%matplotlib inline

# Create function f
def f(x):
    return x**2 + x

# Create derivative function for f
def fd(x):
    return (2 * x) + 1

from matplotlib import pyplot as plt

# Create an array of x values from 0 to 10 to plot
x = list(range(0, 11))

# Use the function to get the y values
y = [f(i) for i in x]

# Set the point
x1 = 5
y1 = f(x1)

# Calculate the derivative using the derivative function
m = fd(x1)

# Set up the graph
plt.xlabel('x')
plt.ylabel('f(x)')
plt.grid()

# Plot the function
plt.plot(x,y, color='green')

# Plot the point
plt.scatter(x1,y1, c='red')
plt.annotate('(x,f(x))',(x1,y1), xytext=(x1-0.5, y1+3))

# Plot the tangent line using the derivative we calculated
xMin = x1 - 3
yMin = y1 - (3*m)
xMax = x1 + 3
yMax = y1 + (3*m)
plt.plot([xMin,xMax],[yMin,yMax], color='magenta')

plt.show()
```

## Differentiability
It's important to realize that a function may not be *differentiable* at every point; that is, you might not be able to calculate the derivative for every point on the function line.

To be differentiable at a given point:
- The function must be *continuous* at that point.
- The tangent line at that point cannot be vertical
- The line must be *smooth* at that point (that is, it cannot take on a sudden change of direction at the point)

For example, consider the following (somewhat bizarre) function:

\begin{equation}
q(x) = \begin{cases}
  \frac{40,000}{x^{2}}, & \text{if } x < -4, \\
  (x^{2} -2) \cdot (x - 1), & \text{if } x \ne 0 \text{ and } x \ge -4 \text{ and } x < 8, \\
  (x^{2} -2), & \text{if } x \ne 0 \text{ and } x \ge 8
\end{cases}
\end{equation}

```python
%matplotlib inline

# Define function q
def q(x):
    if x != 0:
        if x < -4:
            return 40000 / (x**2)
        elif x < 8:
            return (x**2 - 2) * x - 1
        else:
            return (x**2 - 2)

# Plot output from function g
from matplotlib import pyplot as plt

# Create an array of x values
x = list(range(-10, -5))
x.append(-4.01)
x2 = list(range(-4,8))
x2.append(7.9999)
x2 = x2 + list(range(8,11))

# Get the corresponding y values from the function
y = [q(i) for i in x]
y2 = [q(i) for i in x2]

# Set up the graph
plt.xlabel('x')
plt.ylabel('q(x)')
plt.grid()

# Plot x against q(x)
plt.plot(x,y, color='purple')
plt.plot(x2,y2, color='purple')

plt.scatter(-4,q(-4), c='red')
plt.annotate('A (x= -4)',(-5,q(-3.9)), xytext=(-7, q(-3.9)))

plt.scatter(0,0, c='red')
plt.annotate('B (x= 0)',(0,0), xytext=(-1, 40))

plt.scatter(8,q(8), c='red')
plt.annotate('C (x= 8)',(8,q(8)), xytext=(8, 100))

plt.show()
```

The points marked on this graph are non-differentiable:
- Point **A** is non-continuous - the limit from the negative side is infinity, but the limit from the positive side ≈ -57
- Point **B** is also non-continuous - the function is not defined at x = 0.
- Point **C** is defined and continuous, but the sharp change in direction makes it non-differentiable.

## Derivatives of Equations

We've been talking about derivatves of *functions*, but it's important to remember that functions are just named operations that return a value. We can apply what we know about calculating derivatives to any equation, for example:

\begin{equation}\frac{d}{dx}(2x + 6)\end{equation}

Note that we generally switch to *Leibniz's* notation when finding derivatives of equations that are not encapsulated as functions; but the approach for solving this example is exactly the same as if we had a hypothetical function with the definition *2x + 6*:

\begin{equation}\frac{d}{dx}(2x + 6) = \lim_{h \to 0} \frac{(2(x+h) + 6) - (2x + 6)}{h} \end{equation}

After factoring out the* 2(x+h)* on the left and the *-(2x - 6)* on the right, this is:

\begin{equation}\frac{d}{dx}(2x + 6) = \lim_{h \to 0} \frac{2x + 2h + 6 - 2x - 6}{h} \end{equation}

We can simplify this to:

\begin{equation}\frac{d}{dx}(2x + 6) = \lim_{h \to 0} \frac{2h}{h} \end{equation}

Now we can factor *h* out entirely, so at any point:

\begin{equation}\frac{d}{dx}(2x + 6) = 2 \end{equation}

If you run the Python code below to plot the line created by the equation, you'll see that it does indeed have a constant slope of 2:

```python
%matplotlib inline
from matplotlib import pyplot as plt

# Create an array of x values from 0 to 10 to plot
x = list(range(1, 11))

# Use the function to get the y values
y = [(2*i) + 6 for i in x]

# Set up the graph
plt.xlabel('x')
plt.xticks(range(1,11, 1))
plt.ylabel('y')
plt.yticks(range(8,27, 1))
plt.grid()

# Plot the function
plt.plot(x,y, color='purple')

plt.show()
```

## Derivative Rules and Operations
When working with derivatives, there are some rules, or shortcuts, that you can apply to make your life easier.

### Basic Derivative Rules
Let's start with some basic rules that it's useful to know.

- If *f(x)* = *C* (where *C* is a constant), then *f'(x)* = 0

    This makes sense if you think about it for a second. No matter what value you use for *x*, the function returns the same constant value; so the graph of the function will be a horizontal line. There's no rate of change in a horiziontal line, so its slope is 0 at all points. This is true of any constant, including symbolic constants like *π* (pi).

    So, for example:

\begin{equation}f(x) = 6 \;\; \therefore \;\; f'(x) = 0 \end{equation}

    Or:

\begin{equation}f(x) = \pi \;\; \therefore \;\; f'(x) = 0 \end{equation}

- If *f(x)* = *Cg(x)*, then *f'(x)* = *Cg'(x)*

    This rule tells us that if a function is equal to a second function multiplied by a constant, then the derivative of the first function will be equal to the derivative of the second function multiplied by the same constant. For example:

\begin{equation}f(x) = 2g(x) \;\; \therefore \;\; f'(x) = 2g'(x) \end{equation}

- If *f(x)* = *g(x)* + *h(x)*, then *f'(x)* = *g'(x)* + *h'(x)*

    In other words, if a function is the sum of two other functions, then the derivative of the first function is the sum of the derivatives of the other two functions. For example:

\begin{equation}f(x) = g(x) + h(x) \;\; \therefore \;\; f'(x) = g'(x) + h'(x) \end{equation}

    Of course, this also applies to subtraction:

\begin{equation}f(x) = k(x) - l(x) \;\; \therefore \;\; f'(x) = k'(x) - l'(x) \end{equation}

As discussed previously, functions are just equations encapsulated as a named entity that return a value; and the rules can be applied to any equation. For example:

\begin{equation}\frac{d}{dx}(2x + 6) = \frac{d}{dx} 2x +  \frac{d}{dx} 6\end{equation}

So we can take advantage of the rules to make the calculation a little easier:

\begin{equation}\frac{d}{dx}(2x) = \lim_{h \to 0} \frac{2(x+h) - 2x}{h} \end{equation}

After factoring out the* 2(x+h)* on the left, this is:

\begin{equation}\frac{d}{dx}(2x) = \lim_{h \to 0} \frac{2x + 2h - 2x}{h} \end{equation}

We can simplify this to:

\begin{equation}\frac{d}{dx}(2x) = \lim_{h \to 0} \frac{2h}{h} \end{equation}

Which gives us:

\begin{equation}\frac{d}{dx}(2x) = 2 \end{equation}

Now we can turn our attention to the derivative of the constant 6 with respect to *x*, and we know that the derivative of a constant is always 0, so:

\begin{equation}\frac{d}{dx}(6) = 0\end{equation}

We add the two derivatives we calculated:

\begin{equation}\frac{d}{dx}(2x + 6) = 2 + 0\end{equation}

Which gives us our result:

\begin{equation}\frac{d}{dx}(2x + 6) = 2\end{equation}

### The Power Rule
The *power rule* is one of the most useful shortcuts in the world of differential calculus. It can be stated like this:

\begin{equation}f(x) = x^{n} \;\; \therefore \;\; f'(x) = nx^{n-1}\end{equation}

So if our function for *x* returns *x* to the power of some constant (which we'll call *n*), then the derivative of the function for *x* is *n* times *x* to the power of *n* - 1.

It's probably helpful to look at a few examples to see how this works:

\begin{equation}f(x) = x^{3} \;\; \therefore \;\; f'(x) = 3x^{2}\end{equation}

\begin{equation}f(x) = x^{-2} \;\; \therefore \;\; f'(x) = -2x^{-3}\end{equation}

\begin{equation}f(x) = x^{2} \;\; \therefore \;\; f'(x) = 2x\end{equation}

In each of these examples, the exponential of *x* in the function definition becomes the coefficient for *x* in the derivative definition, with the exponential is decremented by 1.

Here's a worked example to find the derivative of the following function:

\begin{equation}f(x) = x^{2}\end{equation}

So we start with the general derivative function:

\begin{equation}f'(x) = \lim_{h \to 0} \frac{f(x + h) - f(x)}{h} \end{equation}

We can plug in our definition for *f*:

\begin{equation}f'(x) = \lim_{h \to 0} \frac{(x + h)^{2} - x^{2}}{h} \end{equation}

Now we can factor out the perfect square binomial on the left:

\begin{equation}f'(x) = \lim_{h \to 0} \frac{x^{2} + h^{2} + 2xh - x^{2}}{h} \end{equation}

The x2 terms cancel each other out so we get to:

\begin{equation}f'(x) = \lim_{h \to 0} \frac{h^{2} + 2xh}{h} \end{equation}

Which simplifies to:

\begin{equation}f'(x) = \lim_{h \to 0} h + 2x \end{equation}

With *h* approaching 0, this is:

\begin{equation}f'(x) = 0 + 2x \end{equation}

So our answer is:

\begin{equation}f'(x) = 2x \end{equation}

Note that we could have achieved the same result by simply applying the power rule and transforming x2 to 2x1 (which is the same as 2x).

### The Product Rule
The product rule can be stated as:

\begin{equation}\frac{d}{dx}[f(x)g(x)] = f'(x)g(x) + f(x)g'(x) \end{equation}

OK, let's break that down. What it's saying is that the derivative of *f(x)* multiplied by *g(x)* is equal to the derivative of *f(x)* multiplied by the value of *g(x)* added to the value of *f(x)* multiplied by the derivative of *g(x*).

Let's see an example based on the following two functions:

\begin{equation}f(x) = 2x^{2} \end{equation}

\begin{equation}g(x) = x + 1 \end{equation}

Let's start by calculating the derivative of *f(x)*:

\begin{equation}f'(x) = \lim_{h \to 0} \frac{2(x + h)^{2} - 2x^{2}}{h} \end{equation}

This factors out to:

\begin{equation}f'(x) = \lim_{h \to 0} \frac{2x^{2} + 2h^{2} + 4xh - 2x^{2}}{h} \end{equation}

Which when we cancel out the 2x2 and -2x2 is:

\begin{equation}f'(x) = \lim_{h \to 0} \frac{2h^{2} + 4xh}{h} \end{equation}

Which simplifies to:

\begin{equation}f'(x) = \lim_{h \to 0} 2h + 4x \end{equation}

With *h* approaching 0, this is:

\begin{equation}f'(x) = 4x \end{equation}

Now let's look at *g'(x)*:

\begin{equation}g'(x) = \lim_{h \to 0} \frac{(x + h) + 1 - (x + 1)}{h} \end{equation}

We can just remove the brackets on the left and factor out the *-(x + 1)* on the right:

\begin{equation}g'(x) = \lim_{h \to 0} \frac{x + h + 1 - x - 1}{h} \end{equation}

Which can be cleaned up to:

\begin{equation}g'(x) = \lim_{h \to 0} \frac{h}{h} \end{equation}

Enabling us to factor *h* out completely to give a constant derivative of *1*:

\begin{equation}g'(x) = 1 \end{equation}

So now we can calculate the derivative for the product of these functions by plugging the functions and the derivatives we've calculated for them into the product rule equation:

\begin{equation}\frac{d}{dx}[f(x)g(x)] = f'(x)g(x) + f(x)g'(x) \end{equation}

So:

\begin{equation}\frac{d}{dx}[f(x)g(x)] = (4x \cdot (x + 1)) + (2x^{2} \cdot 1) \end{equation}

Which can be simplified to:

\begin{equation}\frac{d}{dx}[f(x)g(x)] = (4x^{2} + 4x) + 2x^{2} \end{equation}

Which can be further simplified to:

\begin{equation}\frac{d}{dx}[f(x)g(x)] = 6x^{2} + 4x \end{equation}

### The Quotient Rule
The *quotient rule* applies to functions that are defined as a quotient of one expression divided by another; for example:

\begin{equation}r(x) = \frac{s(x)}{t(x)} \end{equation}

In this situation, you can apply the following quotient rule to find the derivative of *r(x)*:

\begin{equation}r'(x) = \frac{s'(x)t(x) - s(x)t'(x)}{[t(x)]^{2}} \end{equation}

Here are our definitions for *s(x)* and *t(x)*:

\begin{equation}s(x) = 3x^{2} \end{equation}

\begin{equation}t(x) = 2x\end{equation}

Let's start with *s'(x)*:

\begin{equation}s'(x) = \lim_{h \to 0} \frac{3(x + h)^{2} - 3x^{2}}{h} \end{equation}

This factors out to:

\begin{equation}s'(x) = \lim_{h \to 0} \frac{3x^{2} + 3h^{2} + 6xh - 3x^{2}}{h} \end{equation}

Which when we cancel out the 3x2 and -3x2 is:

\begin{equation}s'(x) = \lim_{h \to 0} \frac{3h^{2} + 6xh}{h} \end{equation}

Which simplifies to:

\begin{equation}s'(x) = \lim_{h \to 0} 3h + 6x \end{equation}

With *h* approaching 0, this is:

\begin{equation}s'(x) = 6x \end{equation}

Now let's look at *t'(x)*:

\begin{equation}t'(x) = \lim_{h \to 0} \frac{2(x + h) - 2x}{h} \end{equation}

We can just factor out the *2(x + h)* on the left:

\begin{equation}t'(x) = \lim_{h \to 0} \frac{2x + 2h - 2x}{h} \end{equation}

Which can be cleaned up to:

\begin{equation}t'(x) = \lim_{h \to 0} \frac{2h}{h} \end{equation}

Enabling us to factor *h* out completely to give a constant derivative of *2*:

\begin{equation}t'(x) = 2 \end{equation}

So now we can calculate the derivative for the quotient of these functions by plugging the function definitions and the derivatives we've calculated for them into the quotient rule equation:

\begin{equation}r'(x) = \frac{(6x \cdot 2x) - (3x^{2} \cdot 2)}{[2x]^{2}} \end{equation}

We can factor out the numerator terms like this:

\begin{equation}r'(x) = \frac{12x^{2} - 6x^{2}}{[2x]^{2}} \end{equation}

Which can then be combined:

\begin{equation}r'(x) = \frac{6x^{2}}{[2x]^{2}} \end{equation}

The denominator is [2x]2 (note that this is different from 2x2. [2x]2 is 2x • 2x, whereas  2x2 is 2 • x2):

\begin{equation}r'(x) = \frac{6x^{2}}{4x^{2}} \end{equation}

Which simplifies to:

\begin{equation}r'(x) = 1\frac{1}{2} \end{equation}

So the derivative of *r(x)* is 1.5.

### The Chain Rule

The *chain rule* takes advantage of the fact that equations can be encapsulated as functions, and since functions contain equations, it's possible to nest one function within another.

For example, consider the following function:

\begin{equation}u(x) = 2x^{2} \end{equation}

We could view the definition of *u(x)* as a composite of two functions,; an *inner* function that calculates x2, and an *outer* function that multiplies the result of the inner function by 2.

\begin{equation}u(x) = \widehat{\color{blue}2\color{blue}(\underline{\color{red}x^{\color{red}2}}\color{blue})} \end{equation}

To make things simpler, we can name these inner and outer functions:

\begin{equation}i(x) = x^{2} \end{equation}

\begin{equation}o(x) = 2x \end{equation}

Note that *x* indicates the input for each function. Function *i* takes its input and squares it, and function *o* takes its input and multiplies it by 2. When we use these as a composite function, the *x* value input into the outer function will be the output from the inner function.

Let's take a look at how we can apply these functions to get back to our original *u* function:

\begin{equation}u(x) = o(i(x)) \end{equation}

So first we need to find the output of the inner *i* function so we can use at as the input value for the outer *o* function. Well, that's easy, we know the definition of *i* (square the input), so we can just plug it in:

\begin{equation}u(x) = o(x^{2}) \end{equation}

We also know the definition for the outer *o* function (multiply the input by 2), so we can just apply that to the input:

\begin{equation}u(x) = 2x^{2} \end{equation}

OK, so now we know how to form a composite function. The *chain rule* can be stated like this:

\begin{equation}\frac{d}{dx}[o(i(x))] = o'(i(x)) \cdot i'(x)\end{equation}

Alright, let's start by plugging the output of the inner *i(x)* function in:

\begin{equation}\frac{d}{dx}[o(i(x))] = o'(x^{2}) \cdot i'(x)\end{equation}

Now let's use that to calculate the derivative of *o*, replacing each *x* in the equation with the output from the *i* function (*x2*):

\begin{equation}o'(x) = \lim_{h \to 0} \frac{2(x^{2} + h) - 2x^{2}}{h} \end{equation}

This factors out to:

\begin{equation}o'(x) = \lim_{h \to 0} \frac{2x^{2} + 2h - 2x^{2}}{h} \end{equation}

Which when we cancel out the 2x2 and -2x2 is:

\begin{equation}o'(x) = \lim_{h \to 0} \frac{2h}{h} \end{equation}

Which simplifies to:

\begin{equation}o'(x) = 2 \end{equation}

Now we can calculate *i'(x)*. We know that the definition of *i(x)* is x2, and we can use the power rule to determine that *i'(x)* is therefore 2x.

So our equation at this point is:

\begin{equation}\frac{d}{dx}[o(i(x))] = 2 \cdot 2x\end{equation}

Which is:

\begin{equation}\frac{d}{dx}[o(i(x))] = 4x\end{equation}

Commonly, the chain rule is stated using a slighly different notation that you may find easier to work with. In this case, we can take our equation:

\begin{equation}\frac{d}{dx}[o(i(x))] = o'(i(x)) \cdot i'(x)\end{equation}

and rewrite it as

\begin{equation}\frac{du}{dx} = \frac{do}{di}\frac{di}{dx}\end{equation}

We can then complete the calculations like this:

\begin{equation}\frac{du}{dx} = 2 \cdot 2x = 4x\end{equation}

MathsToML/Module02-Derivatives and Optimization/02-03-Differentiation and Derivatives.ipynb


```python
from IPython.display import display, Math, Latex
import matplotlib.pyplot as plt
%matplotlib inline
#display(Math(r'F(K) = \int_{-\infty}^{\infty} f(x) e^{2\pi i k} dx'))  #exemplo
```

SymPy

Usando a biblioteca SymPy de matemática simbólica para computar:

derivadas

retas tangentes

derivadas de ordem mais altas

máximos e mínimos

```python
import sympy as sp
```

```python
sp.init_printing()
sp.var('x, y')
```

$f(x) = (x^3 - 3x + 2)e^{-x/4} - 1$

```python
f = sp.Lambda(x, (x**3 - 3*x + 2)*sp.exp(-x/4) - 1)
f
```

Derivadas

Usando a biblioteca Sympy de matemática simbólica para computar a derivada da função

$ f' = \dfrac{df}{dx} $.

```python
diff( f(x), x )
```

Para avaliar a derivada em um ponto, por exemplo, para calcular $f'(1)$:

```python
diff( f(x),x ).subs(x, 1)
```

Também podemos definir a função derivada de $f$:

```python
fl = Lambda(x, diff(f(x), x))
fl
```

Com isso, $f'(1)$ pode ser computada com:

```python
fl(1)
```

**Exercício**

Sengo $g(x) = x^2 + \dfrac{1}{2}$ calcule $g'(1)$.

```python
# Solução
g = Lambda(x, (x**2) + Rational(1, 2))
g
```

```python
gl = Lambda(x, diff(g(x), x))
gl
```

Reta Tangente

Aqui, vamos ver como computar a reta tangente ao gráfico da função $f$ no ponto $x_0 = - \dfrac{1}{2}$. Lembremos que tal reta tangente tem equação:

$y = f'(x_0)(x - x_0) + f(x_0)$

Assim sendo, podemos definir a função affim cujo gráfico é a reta tangente com o seguinte comando:

```python
x0 = -1/2
r = Lambda(x, fl(x0)*(x-x0) + f(x0))
r
```

Vejamos os gráficos de $f(x)$ e da reta tangente computada.

```python
p = plot(f(x), (x, -2,   2), line_color='blue', show=False)
q = plot(r(x), (x, -1.5, 1), line_color='red',  show=False)
p.extend(q)
p.show()
```

**Exercício**

Encontre a reta tangente ao gráfico de $y = \dfrac{1}{x}$ em $x = 1$. Faça os esboços dos gráficos e da reta tangente em um mesmo gráfico.

```python
reta_ex_y = Lambda(x, 1 / x)
reta_ex_y
```

```python
reta_ex_yl = Lambda(x, diff(reta_ex_y(x), x))
reta_ex_yl
```

```python
reta_ex_x = 1
reta_ex_r = Lambda(x, reta_ex_yl(reta_ex_x)*(x-reta_ex_x) + reta_ex_y(reta_ex_x))
reta_ex_r
```

```python
reta_ex_p = plot(reta_ex_y(x), (x, -2,   2), line_color='blue', show=False)
reta_ex_q = plot(reta_ex_r(x), (x, -1.5, 1), line_color='red',  show=False)
reta_ex_p.extend(reta_ex_q)
reta_ex_p.show()
```

```python
f = lambda x: ( ((-0.5)*(x**2)) + (2.5*x) + (4.5) )
sp.solve(((-0.5)*(x**2)) + (2.5*x) + (4.5), x)
```

```python

```


# Characterization of Systems in the Spectral Domain

*This Jupyter notebook is part of a [collection of notebooks](../index.ipynb) in the bachelors module Signals and Systems, Communications Engineering, Universität Rostock. Please direct questions and suggestions to [Sascha.Spors@uni-rostock.de](mailto:Sascha.Spors@uni-rostock.de).*

## Combination of Systems

The representation of complex systems as combination of simpler systems is often convenient for their analysis or synthesis. This section discusses three of the most common combinations, the series and parallel connection of systems as well as feedback loops.

### Concatenation

When two linear time-invariant (LTI) systems are combined in series by connecting the output of the first system to the input of a second system this is termed as *concatenation* of two systems. Denoting the impulse responses of the two systems by $h_1(t)$ and $h_2(t)$, the output signal $y(t)$ of the second system is given as

\begin{equation}
y(t) =  x(t) * h_1(t) * h_2(t)
\end{equation}

where $x(t)$ denotes the input signal of the first system. Laplace transformation of the respective signals and impulse responses, and repeated application of the convolution theorem yields

\begin{equation}
Y(s) = \underbrace{H_1(s) \cdot H_2(s)}_{H(s)} \cdot X(s)
\end{equation}

It can be concluded that the concatenation of two systems can be regarded as one LTI system with the transfer function $H(s) = H_1(s) \cdot H_2(s)$. Hence, the following structures are equivalent

The extension to a concatenation of $N$ systems is straightforward. The overall transfer function is given by multiplication of all the individual transfer functions $H_n(s)$

\begin{equation}
H(s) = \prod_{n=1}^{N} H_n(s)
\end{equation}

Applications of concatenated systems include for instance the modeling of wireless transmission systems and cascaded filters.

**Example**

Concatenation of LTI systems can be used to construct higher-order filters from lower-order prototypes. Such filters are known as *cascaded filters*. This is illustrated at the [example of the second-order low-pass filter](../laplace_transform/network_analysis.ipynb#Example:-Second-Order-Low-Pass-Filter) introduced before. The transfer function $H_0(s)$ of the low-pass is given as

\begin{equation}
H_0(s) = \frac{1}{LC s^2 + RC s + 1}
\end{equation}

where $R$, $L$ and $C$ denote the values of the resistor, capacitor and inductor. Concatenation of $N$ second-order filters leads to a filter with order $2 N$. Its transfer function reads

\begin{equation}
H_N(s) = \left( \frac{1}{LC s^2 + RC s + 1} \right)^N
\end{equation}

The resulting transfer function is illustrated by its [Bode plot](../systems_spectral_domain/transfer_function.ipynb#Bode-Plots) for a varying number of cascaded filters using the normalized values $L = .5$, $R = 1$, $C = .4$. First the transfer function $H_N(s)$ is defined

```python
%matplotlib inline
import sympy as sym
sym.init_printing()

s = sym.symbols('s', complex=True)
w, R, L, C = sym.symbols('omega R L C', real=True)
N = sym.symbols('N', integer=True)

H0 = 1/(L*C*s**2 + R*C*s + 1)
HN = H0**N
HN
```

The bode plot for the transfer function $H_N(j \omega)$ is shown for $N = \{1, 2, 3\}$ (red, green, blue line)

```python
import matplotlib.pyplot as plt
from sympy.plotting.plot import MatplotlibBackend

RLC = {R: 1, L: sym.Rational('.5'), C: sym.Rational('.4')}
HNlog = 20*sym.log(sym.Abs(HN.subs(RLC).subs(s, 2*sym.pi*w)), 10)

p1 = sym.plot(HNlog.subs(N, 1), (w, 0.1, 100), xlabel='$\omega$', ylabel='$20 \log_{10} | H_n(j \omega) | in dB$', line_color='r', show=False);
p2 = sym.plot(HNlog.subs(N, 2), (w, 0.1, 100), xlabel='$\omega$', ylabel='$20 \log_{10} | H_n(j \omega) | in dB$', line_color='g', show=False);
p3 = sym.plot(HNlog.subs(N, 3), (w, 0.1, 100), xlabel='$\omega$', ylabel='$20 \log_{10} | H_n(j \omega) | in dB$', line_color='b', show=False);
p1.extend(p2)
p1.extend(p3)

backend = MatplotlibBackend(p1)
backend.process_series()
backend.ax[0].spines['left'].set_position(('axes', 0))
backend.ax[0].spines['bottom'].set_position(('axes', 0))
plt.xscale('log')
plt.grid(which='both')
```

**Exercise**

* Derive the magnitude $|H(s)|$ and phase $\varphi(s)$ of a concatenated system.
* Using the result from the first exercise, how will the phase of the cascaded filter develop for an increasing number $N$ of cascaded filters.

### Parallel Connection

A structure where two LTI systems share the same input signal and the output signals are superimposed is called *parallel connection*. The overall output signal $y(t)$ is given as the superposition of the output signals of the individual systems

\begin{equation}
y(t) = h_1(t) * x(t) + h_2(t) * x(t)
\end{equation}

Laplace transformation of the respective signals and impulse responses, and application of the convolution theorem yields

\begin{equation}
Y(s) = \underbrace{\left( H_1(s) + H_2(s)  \right)}_{H(s)} \cdot X(s)
\end{equation}

The overall transfer function $H(s)$ of a parallel connection of two systems is given as the superposition of the transfer functions of the individual systems. Hence, the following structures are equivalent

The extension to a parallel connection of $N$ systems is straightforward. The overall transfer function is given by superposition of all individual transfer functions $H_n(s)$

\begin{equation}
H(s) = \sum_{n=1}^{N} H_n(s)
\end{equation}

A prominent application of a parallel connection of systems are [filter banks](https://en.wikipedia.org/wiki/Filter_bank) as used in signal analysis and many lossy coding schemes.

### Feedback

The connection of two LTI systems, where the input of the second system is connected to the output of the first and the output of the second system is superimposed to the input of the first is called *feedback loop*. This structure is depicted in the following illustration (upper block diagram)

The output signal $y(t)$ is given as

\begin{equation}
y(t) = x(t) * h_1(t) + y(t) * h_2(t) * h_1(t)
\end{equation}

Laplace transform of the signals and impulse responses, application of the convolution theorem and rearrangement of terms yields

\begin{equation}
Y(s) = \frac{H_1(s)}{1 - H_1(s) \cdot H_2(s)} \cdot X(s)
\end{equation}

The overall transfer function $H(s)$ of the feedback loop is then given as

\begin{equation}
H(s) = \frac{H_1(s)}{1 - H_1(s) \cdot H_2(s)}
\end{equation}

This equivalence is depicted by the lower block diagram of above structure.

Applications of feedback loops include [control systems](https://en.wikipedia.org/wiki/Control_system) and the design of amplifiers.

**Copyright**

This notebook is provided as [Open Educational Resource](https://en.wikipedia.org/wiki/Open_educational_resources). Feel free to use the notebook for your own purposes. The text is licensed under [Creative Commons Attribution 4.0](https://creativecommons.org/licenses/by/4.0/), the code of the IPython examples under the [MIT license](https://opensource.org/licenses/MIT). Please attribute the work as follows: *Sascha Spors, Continuous- and Discrete-Time Signals and Systems - Theory and Computational Examples*.


**Imports:**

```python
from types import SimpleNamespace
from copy import deepcopy

import numpy as np
from scipy import optimize

import matplotlib.pyplot as plt
plt.style.use('seaborn-whitegrid')
prop_cycle = plt.rcParams['axes.prop_cycle']
colors = prop_cycle.by_key()['color']

import ipywidgets as widgets
```

$$
\begin{align}
v(p,w,M,\overline{L}) &=\max_{L\in[0,\overline{L}]}\ln\left(\frac{M+W(L)}{p}\right)-\nu\frac{L^{1+\frac{1}{\epsilon}}}{1+\frac{1}{\epsilon}} \\
&=\max_{L\in\{0,\frac{w}{\kappa},\overline{L}\}\cup(0,\frac{w}{\kappa})\cup(\frac{w}{\kappa},\overline{L})}\ln\left(\frac{W(L)+M}{p}\right)-\nu\frac{L^{1+\frac{1}{\epsilon}}}{1+\frac{1}{\epsilon}}
\end{align}
$$

# Functions

**Basic functions:**

```python
def W_func(L,par):
    """ wage W as function of labour supply L """

    return (1-par.tau_0)*par.w*L - par.tau_1*np.fmax(par.w*L-par.kappa,0.0)

def W_prime_func(L,par):
    """ marginal wage W as function of labour supply L """

    if L < par.kappa/par.w:
        return (1-par.tau_0)*par.w
    else:
        return (1-par.tau_0-par.tau_1)*par.w

def utility(L,par):
    """ utility as function of labor supply L with maximum consumption """

    C = W_func(L,par) + par.M
    return np.log(C) - par.nu*L**(1+1/par.epsilon)/(1+1/par.epsilon)

def FOC(L,par):
    """ error in first order condition (FOC) given labor supply"""

    # a. LHS
    LHS = L

    # b. RHS
    marginal_real_wage = W_prime_func(L,par)/par.p
    marginal_utility = 1/((W_func(L,par)+par.M)/par.p)
    RHS = (1.0/par.nu*marginal_real_wage*marginal_utility)**par.epsilon

    # c. error
    return LHS-RHS
```

**Solve problem:**

```python
def solve(par,do_print=False):

    # a. L = 0.0
    u0 = utility(0.0,par)

    # b. L = Lmax
    umax = utility(par.Lmax,par)

    # c. L = kappa/w
    L_mid = par.kappa/par.w
    umid = utility(L_mid,par)

    # d. left interval
    sign_LL = np.sign(FOC(1e-8,par))
    sign_LR = np.sign(FOC(L_mid-1e-8,par))

    if not sign_LL == sign_LR:
        sol_L = optimize.bisect(FOC,1e-8,L_mid-1e-8,args=(par,))
        uL = utility(sol_L,par)
    else:
        sol_L = np.nan
        uL = np.nan

    # e. right interval
    sign_RL = np.sign(FOC(L_mid+1e-8,par))
    sign_RR = np.sign(FOC(par.Lmax-1e-8,par))

    if not sign_RL == sign_RR:
        sol_R = optimize.bisect(FOC,L_mid+1e-8,par.Lmax-1e-8,args=(par,))
        uR = utility(sol_R,par)
    else:
        sol_R = np.nan
        uR = np.nan

    # f. global maksimum
    i_opt = np.nanargmax([u0,uL,umid,uR,umax])

    if i_opt == 0:
        L_opt = 0.0
    elif i_opt == 1:
        L_opt = sol_L
    elif i_opt == 2:
        L_opt = L_mid
    elif i_opt == 3:
        L_opt = sol_R
    elif i_opt == 4:
        L_opt = par.Lmax

    return L_opt
```

**Plotting function:**

```python
def plot_solutions(pars,names,w_low=0.1,w_high=30,Nw=200):
    """ plot solution for different wage levels """

    fig = plt.figure(figsize=(6,18/1.5),dpi=100)
    ax1 = fig.add_subplot(3,1,1)
    ax2 = fig.add_subplot(3,1,2)
    ax3 = fig.add_subplot(3,1,3)

    for j,(par,name) in enumerate(zip(pars,names)):

        w_orig = par.w # for later reset

        # a. solve
        w_vec = np.linspace(w_low,w_high,Nw)
        L_vec = np.zeros(w_vec.shape)
        C_vec = np.zeros(w_vec.shape)
        for i,w in enumerate(w_vec):
            par.w = w
            L_vec[i] = solve(par)
            C_vec[i] = W_func(L_vec[i],par) + par.M

        # b. plot
        ax1.plot(w_vec,L_vec,label=name,color=colors[j])
        ax2.plot(w_vec,w_vec*L_vec,label=name,color=colors[j])
        ax2.axhline(par.kappa,ls='--',label=f'$\kappa = {par.kappa}$',color=colors[j])
        ax3.plot(w_vec,C_vec,label=name,color=colors[j])

        # c. reset
        par.w = w_orig

    ax1.set_title('Labor supply: $L$')
    ax1.legend(frameon=True)
    ax1.set_xlabel('$w$')
    ax1.set_ylabel('$L$')

    ax2.set_title('Pre-tax labor income: : $w*L$')
    ax2.legend(frameon=True)
    ax2.set_xlabel('$w$')
    ax2.set_ylabel('$w*L$')

    ax3.set_title('Consumption: : $C = W(L) + M$')
    ax3.legend(frameon=True)
    ax3.set_xlabel('$w$')
    ax3.set_ylabel('$C$')

    fig.tight_layout(pad=1.0)

```

# Solve

```python
par = SimpleNamespace()

# utility
par.epsilon = 0.1
par.nu = 0.1

# income
par.M = 2.0
par.Lmax = 2.0

# numeraire
par.p = 1.0

# taxes
par.tau_0 = 0.5
par.tau_1 = 0.4
par.kappa = 20.0

par.w = np.nan

# alternative
par_alt = deepcopy(par)
par_alt.kappa = 10.0

plot_solutions([par,par_alt],['baseline','alternative'])
```


# Introdução ao Firedrake

## Parte 2: Elasticidade Linear

Ministrante: **Diego Tavares Volpatto (LNCC/ESSS)**

Encontro Acadêmico de Modelagem Computacional - XV EAMC (2022)

<tr>
<td>  </td>
<td>  </td>
</tr>

## Sumário

* Solucionar com FEM o problema da Elasticidade Linear para os deslocamentos (primal)
* Novas dicas e funcionalidades

# Elasticidade Linear

## Problema-modelo

A elasticidade linear é um modelo que descreve algumas situações de pequenas deformações. O objetivo aqui é demonstrar como solucionar um problema em que a incógnita é um vetor (e.g., campo de deslocamento).

### Forma forte

Vamos considerar o caso de pequenas deformações elásticas isotrópicas para fins didáticos. Dessa forma, a equação do momento linear de Cauchy se resume a:

\begin{equation}
\begin{aligned}
-\nabla \cdot \sigma &=f \text { em } \Omega \\[0.5em]
\sigma(u) &:=\lambda \operatorname{tr}(\varepsilon(u)) I+2 \mu \varepsilon(u) \\[0.5em]
\varepsilon(u) &:=\frac{1}{2}\left(\nabla u+(\nabla u)^{\top}\right)
\end{aligned}
\end{equation}

Note que a equação é também vetorial, $f: \Omega \to \mathbb{R}^n$.

### Forma fraca

Após algumas manipulações (em especial, o produto interno de um tensor simétrico com um antissimétrico é nulo), temos as formas:

\begin{equation}
\begin{aligned}
a(u, v) &:=\int_{\Omega} \sigma(u): \varepsilon(u) \mathrm{~d} x \\
L(v) &:=\int_{\Omega} f \cdot v \mathrm{~d} x+\int_{\Gamma_{T}} T \cdot v \mathrm{~d} s
\end{aligned}
\end{equation}

E o problema variacional é dado por:

\begin{equation}
a(u, v) = L(v)
\end{equation}

**Note** que $u$ e $v$ são campos vetoriais! Portanto e naturalmente, pertecem a espaços de funções vetoriais.

## Implementação

Temos agora todos os requisitos para a implementação.

### Considerações do modelo

* Vamos considerar o domínio 2D alongado (barra): $\Omega = [0, L_x] \times [0, L_y]$, com $L_x = 1$ e $L_y = 0.1$ em metros.

* Condições de contorno: barra fixada nas duas extremidades. Portanto, $u_x = u_y = 0$ nas duas extremidades.

* Densidade do material $\rho = 0.01$ (kg / m$^3$) e gravidade $g = 9.8$ (m / s$^2$)

* Parâmetros do material: $\lambda = 0.4$ e $\mu = 1$.

### Importando o Firedrake

Como de costume:

```python
import os
os.environ["OMP_NUM_THREADS"] = "1"  # necessário para o Firedrake

from firedrake import *
import matplotlib.pyplot as plt
```

### Definindo a malha

Parece esse problema, podemos usar uma função built-in do Firedrake.

```python
Lx, Ly = 1.0, 0.1
num_elements_x, num_elements_y = 20, 20
mesh = RectangleMesh(num_elements_x, num_elements_y, Lx, Ly, quadrilateral=True)
```

### Funções e seu Espaço

Neste caso, o espaço de função é **vetorial**. Não há muitas diferenças, agora os graus de liberdade são para cada componente do vetor, e esses, por sua vez, pertecem ao espaço de função escalar relacionado.

```python
degree = 1
family = "Lagrange"
V = VectorFunctionSpace(mesh, family, degree)

u = TrialFunction(V)
v = TestFunction(V)
```

### Parâmetros do material

Apenas atribuindo os valores que adotamos para esse problema:

```python
rho = Constant(0.01)
g = Constant(9.8)
f = as_vector([0, -rho * g])  # poderia ser Constant([0, -rho * g])
mu = Constant(1)
lambda_ = Constant(0.4)
```

### Equações constitutivas

Vamos agora definir $\varepsilon(u)$ e $\sigma(u)$, de forma que não precisamos abrir suas contas na formulação variacional:

\begin{equation}
\begin{aligned}
\varepsilon(u) &:=\frac{1}{2}\left(\nabla u+(\nabla u)^{\top}\right) \\[0.5em]
\sigma(u) &:=\lambda \operatorname{tr}(\varepsilon(u)) I+2 \mu \varepsilon(u)
\end{aligned}
\end{equation}

```python
Id = Identity(mesh.geometric_dimension())  # tensor identidade

def epsilon(u):
    return (1. / 2.) * (grad(u) + grad(u).T)

def sigma(u):
    return lambda_ * div(u) * Id + 2 * mu * epsilon(u)
```

Note que poderíamos fazer:

```python
def epsilon(u):
    return sym(grad(u))
```

### Formulação Variacional

Agora, podemos escrever a formulação variacional sem dificuldades:

\begin{equation}
\begin{aligned}
a(u, v) &:=\int_{\Omega} \sigma(u): \varepsilon(u) \mathrm{~d} x \\
L(v) &:=\int_{\Omega} f \cdot v \mathrm{~d} x+\int_{\Gamma_{T}} T \cdot v \mathrm{~d} s
\end{aligned}
\end{equation}

```python
a = inner(sigma(u), epsilon(v)) * dx
L = dot(f, v) * dx  # note o produto interno
```

Por enquanto, vamos desconsiderar qualquer tração, temos apenas o efeito da força de corpo (gravidade).

### Condições de contorno

Temos a condição de contorno como barra fixa nas extremidades:

```python
ux_bc, uy_bc = 0.0, 0.0
bcs = DirichletBC(V, as_vector([ux_bc, uy_bc]), [1, 2])
```

### Montando o Problema Variacional e seu solver

Sem grandes diferenças para outras casos, definimos o problema variacional:

```python
u_h = Function(V)
# solve(a == L, u_h, bcs=bcs)  # não é boa prática, tem overhead
elasticity_problem = LinearVariationalProblem(a, L, u_h, bcs=bcs)
```

E seu solver associado (agora com exemplo usando o MUMPS ou GMRES):

```python
solver_parameters = {
    "ksp_monitor": None,
    "ksp_converged_reason": None,
    "ksp_view": None,
    "mat_type": "aij",
    "ksp_type": "gmres",
    "pc_type": "ilu",
    'ksp_rtol': 1e-8,
    'ksp_max_it': 2000
}
```

```python
solver_parameters = {
    "ksp_monitor": None,
    "ksp_type": "preonly",
    "pc_type": "lu",
    "pc_factor_mat_solver_type": "mumps",
}
```

```python
elasticity_solver = LinearVariationalSolver(elasticity_problem, solver_parameters=solver_parameters)
```

### Solucionado

Executando o solver:

```python
elasticity_solver.solve()
```

        Residual norms for firedrake_0_ solve.
        0 KSP Residual norm 4.715852255955e-04
        1 KSP Residual norm 1.069118219739e-14

### Visualizando alguns resultados

Primeiro de tudo, vamos verificar o campo de deslocamento e seus componentes:

```python
fig, axes = plt.subplots(figsize=(20, 2))

collection = quiver(u_h, axes=axes)
fig.colorbar(collection)
axes.set_aspect("equal")

plt.xlabel('x [L]')
plt.ylabel('y [L]')

plt.show()
```

```python
fig, axes = plt.subplots(figsize=(10, 2))

# Componente x
collection = tripcolor(u_h.sub(0), axes=axes)
fig.colorbar(collection)
axes.set_aspect("equal")

plt.xlabel('x [L]')
plt.ylabel('y [L]')

axes.set_xlim([0, 1])

plt.show()
```

```python
fig, axes = plt.subplots(figsize=(10, 2))

# Componente y
collection = tripcolor(u_h.sub(1), axes=axes)
fig.colorbar(collection)
axes.set_aspect("equal")

plt.xlabel('x [L]')
plt.ylabel('y [L]')

axes.set_xlim([0, 1])

plt.show()
```

Agora podemos ver a deformação na barra vendo a malha antes e depois.

Vamos deslocar a malha com o campo de deslocamento obtido:

```python
original_mesh = interpolate(SpatialCoordinate(mesh), V)
displaced_coordinates = interpolate(original_mesh + u_h, V)
displaced_mesh = Mesh(displaced_coordinates)
```

Antes:

Depois:

```python
fig, axes = plt.subplots(figsize=(8, 6))

triplot(mesh, axes=axes)
axes.set_aspect("equal")

# Setting the xy-labels
plt.xlabel('x [L]')
plt.ylabel('y [L]')

# Displaying in the screen
plt.tight_layout()
plt.show()
```

```python
fig, axes = plt.subplots(figsize=(8, 6))

triplot(displaced_mesh, axes=axes)
axes.set_aspect("equal")

# Setting the xy-labels
plt.xlabel('x [L]')
plt.ylabel('y [L]')

# Displaying in the screen
plt.tight_layout()
plt.show()
```

notebooks/Parte 2 - Elasticidade Linear.ipynb


## Contributions of visual and proprioceptive information to travelled distance estimation during changing sensory congruencies
Jennifer L Campos, John S Butler, Heinrich H. Bülthoff
Experimental Brain Research

__Abstract__ Recent research has provided evidence that visual and body-based cues (vestibular, proprioceptive
and efference copy) are integrated using a weighted linear sum during walking and passive transport. However, little
is known about the specific weighting of visual information when combined with proprioceptive inputs alone, in
the absence of vestibular information about forward selfmotion.

Therefore, in this study, participants walked in place on a stationary treadmill while dynamic visual information was updated in real time via a head-mounted display. The task required participants to travel a predefined distance and subsequently match this distance by adjusting an egocentric, in-depth target using a game controller. Travelled distance information was provided either through
visual cues alone, proprioceptive cues alone or both cues combined. In the combined cue condition, the relationship
between the two cues was manipulated by either changing the visual gain across trials (0.7×, 1.0×, 1.4×; Exp. 1) or
the proprioceptive gain across trials (0.7×, 1.0×, 1.4×; Exp. 2).

Results demonstrated an overall higher weighting of proprioception over vision. These weights were scaled, however, as a function of which sensory input provided more stable information across trials. Specifically, when visual gain was constantly manipulated, proprioceptive weights were higher than when proprioceptive gain was constantly manipulated. These results therefore reveal interesting characteristics of cue-weighting within the context of unfolding spatio-temporal cue dynamics.
# Introduction
In this notebook we will simulate the results of the Leaky Integrator for the visual, proprioceptive and combined (visual and proprioceptive) condtions from the paper by Campos et al. 2014 [1].

```python
## Library
import numpy as np
import math
import matplotlib.pyplot as plt
```

## Leaky Integrator
The presented distance travelled for the visual, proprioceptive and congruent combined conditions was each fitted by a leaky spatial integrator mode.
The model describes the change of presented distance travelled ($p$) with respect to the change of the adjusted target distance estimate ($x$)
\begin{equation}
\frac{d p}{dx}=-\alpha p+k
\end{equation}
for $0\leq x \leq 10m$, where $k$ and $\alpha$ are the sensory gain and the leak rate, respectively.
This model has the exact solution
\begin{equation}
p(x)=\big( \frac{k}{\alpha}\big)(1-exp(-\alpha x))
\end{equation}
In this simulation we set the parameters for the different conditions as:
* visual condition: $\alpha_{Vis}=0.05$ and $k_{Vis}=0.9$,
* proprioceptive condition: for$\alpha_{Prop}=0.04$ and $k_{Prop}=1.2$,
* combined condition: $\alpha_{Comb}=0.02$ and $k_{Comb}=0.95$.

```python
alpha_vis=0.05
k_vis=0.9
alpha_prop=0.04
k_prop=1.2
alpha_comb=0.02
k_comb=0.95
```

## Discrete Domain
To numerically approximate the solution we discretise the continuous domain using a step size, $h=1$,
which gives
\begin{equation}
x_i=0+i h,
\end{equation}
for $i=0,...10$.

The Figure below illustrate the discrete domain.

```python
h=1
x_end=10
x=np.arange(0,x_end+h/2,h)
fig = plt.figure(1,figsize=(5,4))
ax = fig.add_subplot(1,1,1)
ax.plot(x,0*x,'o:',color='k')
ax.set_xlabel('Distance Presented (m)')
plt.show()
```

```python
N=int(x_end/h) # Number of Steps
Vis_NS=np.zeros(N+1) # Numerical Solution P
Prop_NS=np.zeros(N+1) # Numerical Solution P
Comb_NS=np.zeros(N+1) # Numerical Solution P

Vis_AS=k_vis/alpha_vis*(1-np.exp(-alpha_vis*x))
Prop_AS=k_prop/alpha_prop*(1-np.exp(-alpha_prop*x))
Comb_AS=k_comb/alpha_comb*(1-np.exp(-alpha_comb*x))

# Initial Conditions
Vis_NS[0]=0
Prop_NS[0]=0
Comb_NS[0]=0
```

We numerically approximate the differential equation using Eulers method to give the difference equation
\begin{equation}
P_{i+1}=P_{i}+h \big(-\alpha P_{i}+k \big),
\end{equation}
where $h$ is the stepsize and where $P_i$ is the numerical approximation of $p(x)$ at distance $x_i$, for $i=0,...,10$

```python
for i in range (1,N+1):
    Vis_NS[i]=Vis_NS[i-1]+h*(-alpha_vis*Vis_NS[i-1]+k_vis)
    Prop_NS[i]=Prop_NS[i-1]+h*(-alpha_prop*Prop_NS[i-1]+k_prop)
    Comb_NS[i]=Comb_NS[i-1]+h*(-alpha_comb*Comb_NS[i-1]+k_comb)

```

## Results
The plot bellow shows the Numerical solution $P_i$ (left plot), the analytic solution $p(x)$ (middle plot) and the error $P(x_i)-P_i$ (right plot) as a function of presented distance $x$ for the visual condition (red), proprioceptive condition (green) and the combined condtion (blue).
The dashed black line in the left and middle plot represents perfect recall of the distance

```python
## Plotting Figure
fig = plt.figure(1,figsize=(12,4))

# --- left hand plot
ax = fig.add_subplot(1,3,1)
ax.plot(x,Vis_NS,'o:',color='red',label='Visual')
ax.plot(x,Prop_NS,'o:',color='green',label='Proprioception')
ax.plot(x,Comb_NS,'o:',color='blue',label='Combined')
ax.legend()
ax.plot(x,x,'--k',label='Perfect Recall')

ax.set_xlabel('Distance Presented (m)')
ax.set_ylabel('Response Distance (m)')
#ax.legend(loc='best')
ax.set_title('Numerical Solution')

# --- middle plot
ax = fig.add_subplot(1,3,2)
ax.plot(x,Vis_AS,'-',color='red',label='Visual')
ax.plot(x,Prop_AS,'-',color='green',label='Proprioception')
ax.plot(x,Comb_AS,'-',color='blue',label='Combined')

ax.plot(x,x,'--k',label='Perfect Recall')
ax.legend()

ax.set_xlabel('Distance Presented (m)')
ax.set_ylabel('Response Distance (m)')
ax.set_title('Analytic (exact) Solution')

# --- right hand plot
ax = fig.add_subplot(1,3,3)
ax.plot(x,Vis_AS-Vis_NS,'o:',color='red',label='VIS ERROR')
ax.plot(x,Prop_AS-Prop_NS,'o:',color='green',label='Proprioceptive ERROR')
ax.plot(x,Comb_AS-Comb_NS,'o:',color='blue',label='Combined ERROR')
ax.legend()

ax.set_title('Error')
ax.set_ylabel('Error(m)')
ax.set_xlabel('Distance Presented (m)')

# --- title, explanatory text and save
fig.suptitle('Leaky Solution', fontsize=20)
plt.tight_layout()
plt.subplots_adjust(top=0.85)
plt.show()
```

# References

[1] Campos, J. L., Butler, J. S., & Bülthoff, H. H. (2014). Contributions of visual and proprioceptive information to travelled distance estimation during changing sensory congruencies. Experimental brain research, 232(10), 3277-3289.


# The Material Derivative

## Learning outcomes

* Understand the chain rule and the material derivative

The material derivative (or the substantive derivative) is an important concept in the analysis of fluid flow so it is worth taking some time to understand it.

Consider a time invariant flow in a nozzle. The continuity equation tells us that for a given mass flow rate the velocity must increase as the area is reduced. However for an observer or a probe situated at a fixed point in the nozzle the velocity appears constant. The probe would have to move up or downstream to observe a change in the velocity — the streamwise velocity gradient.

Similarly for a time-invariant flow such as that in a bending tube the point probe measurement will not detect the curvature of the velocity field and so the change in velocity direction, or the curvature of a pathline, is only apparent when moving the probe location and comparing differences in the observations.

The material derivative is therefore a way to express this change in a quantity such a the velocity at a point in the flow. It maps the **Lagrangian trajectory** of a particle onto an **Eulerian point** in the flow.

From another perspective consider a particle of fluid with some property such as temperature $T$ traveling along its pathline at a uniform velocity. The flow field will transport (or advect) the particle, but its temperature isn't changing — the Lagrangian derivative with respect to time is zero. However the Eulerian derivative will increase or decrease as the particle is advected across our fixed measurement location in particular as you increase or decrease the uniform velocity of the flow.

Let's look at this in more detail.

If we consider again a fluid particle moving along its pathline, i.e. the location of that particle relative to our coordinate system as a function of time, that particle undergoes acceleration as it changes direction or velocity. Acceleration being the time rate of change of velocity.

For particle $p$ we can write an expression for its velocity as:

\begin{equation}
\vec{{}V_p}(r_p,t) = \vec{{}V_p}[x_p(t), y_p(t), z_p(t),t]
\label{eq1}
\tag{1}
\end{equation}

where $x_p = x_p(t)$, $y_p = y_p(t)$ and $z_p = z_p(t)$ define the Cartesian location of the particle at time $t$. As stated, a change in velocity may be due to a change in the speed of the particle or a change in the direction in which it is traveling. To take the derivative of equation \ref{eq1} to obtain the acceleration of our particle we need to use the chain rule.

## The Chain Rule

The chain rule is a formula to compute the derivative of compositions of functions, or functions within functions. In this case we have the derivative with respect to time and the derivative with respect to position which itself is dependent on time. That's why the variables in the square brackets in equation 1 all contain a $t$.

To simplify, lets consider a composite function where some variable $z$ depends on $y$ which itself depends on $x$. We can expand the derivative of z with respect to y as follows:

\begin{equation}
\frac{dz}{dx} = \frac{dz}{dy} \cdot \frac{dy}{dx}
\tag{2}
\end{equation}

For partial derivatives (where we use $\partial$) the chain rule can be understood as follows.
If some function $u = u(x,y)$ and the independent variables $x$ and $y$ are each a function of $t$ such that $x = x(t)$ and $y = y(t)$ the derivative $du/dt$ can be obtained:

\begin{equation}
\delta{u} = \frac{\partial{u}}{\partial{x}} \delta{x} +
            \frac{\partial{u}}{\partial{y}} \delta{y}
\tag{3}
\end{equation}

As $\delta{x}\rightarrow0$, $\delta{y}\rightarrow0$, and $\delta{t}\rightarrow0$ yielding:

\begin{equation}
\frac{d{u}}{d{t}} = \frac{\partial{u}}{\partial{x}} \frac{d{x}}{d{t}} +
                    \frac{\partial{u}}{\partial{y}} \frac{d{y}}{d{t}}
\tag{4}
\end{equation}

Here we have a mix of $\partial$ and $d$. This is because $x$ and $y$ are functions of only one variable $t$, while $u$ is a function of $x$ and $y$.

You can learn more about the chain rule here:

https://www.khanacademy.org/math/ap-calculus-ab/ab-differentiation-2-new/ab-3-1a/v/chain-rule-introduction

and here:

https://www.youtube.com/watch?v=YG15m2VwSjA

So to differentiate equation 1:

\begin{equation}
\vec{{}a_p}(t) = \frac{d\vec{{V_p}}}{dt} =
                 \frac{\partial\vec{{V_p}}}{\partial{t}} +
                 \frac{\partial\vec{{V_p}}}{\partial{x}}\frac{dx_p}{dt} +
                 \frac{\partial\vec{{V_p}}}{\partial{y}}\frac{dy_p}{dt} +
                 \frac{\partial\vec{{V_p}}}{\partial{z}}\frac{dz_p}{dt}
\label{eq5}
\tag{5}
\end{equation}

Since the velocity components are $u_p = dx_p/dt$, $v_p = dy_p/dt$ and $w_p = dz_p/dt$ we obtain:

\begin{equation}
\vec{{}a_p} = \frac{\partial\vec{{V_p}}}{\partial{t}} +
          u_p \frac{\partial\vec{{V_p}}}{\partial{x}} +
          v_p \frac{\partial\vec{{V_p}}}{\partial{y}} +
          w_p \frac{\partial\vec{{V_p}}}{\partial{z}}
\label{eq6}
\tag{6}
\end{equation}

or generally for any particle:

\begin{equation}
\vec{{}a} = \frac{\partial\vec{{V}}}{\partial{t}} +
          u \frac{\partial\vec{{V}}}{\partial{x}} +
          v \frac{\partial\vec{{V}}}{\partial{y}} +
          w \frac{\partial\vec{{V}}}{\partial{z}}
\label{eq7}
\tag{7}
\end{equation}

The scalar components of the vector $\vec{{}a}$ can be decomposed as:

\begin{align}
a_x &= \frac{\partial{u}}{\partial{t}} +
     u \frac{\partial{u}}{\partial{x}} +
     v \frac{\partial{u}}{\partial{y}} +
     w \frac{\partial{u}}{\partial{z}}
\tag{8}
\end{align}
\begin{align}
a_y &= \frac{\partial{v}}{\partial{t}} +
     u \frac{\partial{v}}{\partial{x}} +
     v \frac{\partial{v}}{\partial{y}} +
     w \frac{\partial{v}}{\partial{z}}
\tag{9}
\end{align}
\begin{align}
a_z &= \frac{\partial{w}}{\partial{t}} +
     u \frac{\partial{w}}{\partial{x}} +
     v \frac{\partial{w}}{\partial{y}} +
     w \frac{\partial{w}}{\partial{z}}
\tag{10}
\end{align}

We write equation \ref{eq7} in shorthand notation as:

\begin{equation}
\vec{{}a} = \frac{D \vec{{}V} }{Dt} \equiv
\frac{\partial{\vec{{}V}}}{\partial{t}} + \vec{{}V} \cdot \nabla{\vec{{}V}}
\label{eq8}
\tag{11}
\end{equation}

The symbol $\nabla$, 'nabla' is used as short hand in vector calculus to represent the **gradient**.

The Material Derivative of any variable (scalar or vector) is the rate at which that variable changes in time for a given particle in a Lagrangian frame of reference, i.e. along its pathline. We can use it to describe the temperature or momentum (or whatever we are interested in) of a particle, not just acceleration. To reiterate, it acts as a link between the Lagrangian and the Eulerian descriptions as it tells us how a property of a particle changes as it moves across the Eulerian grid.

3.2a The Material Derivative and the Chain Rule.ipynb