# **Optimization - Homework 1**

**Prof. Elías D. Niño-Ruiz, Ph.D.**

*   Nombre del Estudiante: Alejandro Jesús Manotas Marmolejo
*   Código del Estudiante: 200108289

Datasets to employ in this homework:

1.   $u$ wind component (zonal wind component) - [download here](ftp://ftp2.psl.noaa.gov/Datasets/ncep.reanalysis2/pressure/uwnd.2020.nc)
2.   $v$ wind component (meridional wind component) - [download here](ftp://ftp2.psl.noaa.gov/Datasets/ncep.reanalysis2/pressure/vwnd.2020.nc)

Recall that, wind speed reads $w_s = \sqrt{u^2 + v^2}$.

**Note.** *You can make use of all Jupyter Notebooks, from classes, as needed.*

**High-Order Derivatives for Wind Acceleration**

---

We employed a forward difference approximation for the estimation of wind acceleration in the globe for the NOAA data set, this is:
$$a_{i} = \frac{v_{i+1}-v_i}{h}\,,$$
where $v_i$ is the wind speed at time $i$, and $a_i$ denotes an estimation of the wind acceleration. Note that, by using this formula, we couldn't estimate the acceleration of the last time (because there is no $v_{i+1}$). However, we could do that by using a different formula, for instance, a backward difference approximation could make the work for the last time:
$$a_{i} = \frac{v_{i}-v_{i-1}}{h}\,,$$
in this homework you must:

---

**Exercise 1**

Propose two finite difference approximations for $f'(a)$ as follows:

1.   in the first one, only forward differences can be employed (i.e., $f(a+k\cdot h)$ for $k>0$), and
2.   in the last one, only backward differences can be employed (i.e., $f(a+k\cdot h)$ for $k<0$)

both of them, must be of order $\mathcal{O}(h^5)$. You can use the `sympy` module to make your life easier regarding computations. Show all equations! you can make use of the `Latex` and `display` commands to accomplish this.

**Answer.**

1. Forward differences $(k > 0)$

```
from IPython.display import display, Latex
import sympy as sp
from sympy.parsing.sympy_parser import parse_expr
```

```
def showEquation(s,eqn):
  display(Latex('(Eq. '+str(eqn)+'). \,'+sp.latex(s)+'=0'));
```

```
x = parse_expr('x');
fx = parse_expr('f(x)');
a, h = parse_expr('a, h');

eq1 = fx.subs(x,a+h)-sp.series(fx,x=x,x0=a,n=5).subs(x,a+h)
showEquation(eq1,1)

eq2 = fx.subs(x,a+2*h)-sp.series(fx,x=x,x0=a,n=5).subs(x,a+2*h)
showEquation(eq2,2)

eq3 = eq2 - 16*eq1
showEquation(eq3,3)
```

(Eq. 1). \,f{\left (a + h \right )} - f{\left (a \right )} - h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{h^{2}}{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{h^{3}}{6} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{h^{4}}{24} \left. \frac{d^{4}}{d \xi_{1}^{4}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 2). \,f{\left (a + 2 h \right )} - f{\left (a \right )} - 2 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 2 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{4 h^{3}}{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{2 h^{4}}{3} \left. \frac{d^{4}}{d \xi_{1}^{4}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 3). \,f{\left (a + 2 h \right )} - 16 f{\left (a + h \right )} + 15 f{\left (a \right )} + 14 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + 6 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \frac{4 h^{3}}{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

```
eq4 = fx.subs(x,a+3*h)-sp.series(fx,x=x,x0=a,n=5).subs(x,a+3*h)
showEquation(eq4,4)

eq5 = fx.subs(x,a+6*h)-sp.series(fx,x=x,x0=a,n=5).subs(x,a+6*h)
showEquation(eq5,5)

eq6 = (1/16)*eq5 - eq4
showEquation(eq6,6)

eq7 = eq6 - (27/16)*eq3
showEquation(eq7,7)
```

(Eq. 4). \,f{\left (a + 3 h \right )} - f{\left (a \right )} - 3 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{9 h^{2}}{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{9 h^{3}}{2} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{27 h^{4}}{8} \left. \frac{d^{4}}{d \xi_{1}^{4}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 5). \,f{\left (a + 6 h \right )} - f{\left (a \right )} - 6 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 18 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 36 h^{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 54 h^{4} \left. \frac{d^{4}}{d \xi_{1}^{4}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 6). \,0.0625 f{\left (a + 6 h \right )} - f{\left (a + 3 h \right )} + 0.9375 f{\left (a \right )} + 2.625 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + 3.375 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + 2.25 h^{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 7). \,0.0625 f{\left (a + 6 h \right )} - f{\left (a + 3 h \right )} - 1.6875 f{\left (a + 2 h \right )} + 27.0 f{\left (a + h \right )} - 24.375 f{\left (a \right )} - 21.0 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 6.75 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

```
eq8 = fx.subs(x,a+4*h)-sp.series(fx,x=x,x0=a,n=5).subs(x,a+4*h)
showEquation(eq8,8)

eq9 = fx.subs(x,a+8*h)-sp.series(fx,x=x,x0=a,n=5).subs(x,a+8*h)
showEquation(eq9,9)

eq10 = eq9 - 16*eq8
showEquation(eq10,10)

eq11 = eq10 - 64*eq3
showEquation(eq11,11)
```

(Eq. 8). \,f{\left (a + 4 h \right )} - f{\left (a \right )} - 4 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 8 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{32 h^{3}}{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{32 h^{4}}{3} \left. \frac{d^{4}}{d \xi_{1}^{4}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 9). \,f{\left (a + 8 h \right )} - f{\left (a \right )} - 8 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 32 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{256 h^{3}}{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{512 h^{4}}{3} \left. \frac{d^{4}}{d \xi_{1}^{4}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 10). \,f{\left (a + 8 h \right )} - 16 f{\left (a + 4 h \right )} + 15 f{\left (a \right )} + 56 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + 96 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \frac{256 h^{3}}{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 11). \,f{\left (a + 8 h \right )} - 16 f{\left (a + 4 h \right )} - 64 f{\left (a + 2 h \right )} + 1024 f{\left (a + h \right )} - 945 f{\left (a \right )} - 840 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 288 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

```
eq12 = eq11 - (128/3)*eq7
showEquation(eq12,12)
```

(Eq. 12). \,f{\left (a + 8 h \right )} - 2.66666666666667 f{\left (a + 6 h \right )} - 16 f{\left (a + 4 h \right )} + 42.6666666666667 f{\left (a + 3 h \right )} + 8.0 f{\left (a + 2 h \right )} - 128.0 f{\left (a + h \right )} + 95.0 f{\left (a \right )} + 56.0 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

$f'(a)=\frac{-f(a+8h)+2.66666666666667f(a+6h)+16f(a+4h)-42.6666666666667f(a+3h)-8.0f(a+2h)+128.0f(a+h)-95.0f(a)-O(h^5)}{56.0h}$

> Bloque con sangría

2. Backward differences $(k < 0)$

```
fx = parse_expr('f(x)');
a, h = parse_expr('a, h');

eq1 = fx.subs(x,a-h)-sp.series(fx,x=x,x0=a,n=5).subs(x,a-h)
showEquation(eq1,1)

eq2 = fx.subs(x,a-2*h)-sp.series(fx,x=x,x0=a,n=5).subs(x,a-2*h)
showEquation(eq2,2)

eq3 = eq2 - 16*eq1
showEquation(eq3,3)
```

(Eq. 1). \,f{\left (a - h \right )} - f{\left (a \right )} + h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{h^{2}}{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \frac{h^{3}}{6} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{h^{4}}{24} \left. \frac{d^{4}}{d \xi_{1}^{4}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 2). \,f{\left (a - 2 h \right )} - f{\left (a \right )} + 2 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 2 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \frac{4 h^{3}}{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{2 h^{4}}{3} \left. \frac{d^{4}}{d \xi_{1}^{4}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 3). \,- 16 f{\left (a - h \right )} + f{\left (a - 2 h \right )} + 15 f{\left (a \right )} - 14 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + 6 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{4 h^{3}}{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

```
eq4 = fx.subs(x,a-3*h)-sp.series(fx,x=x,x0=a,n=5).subs(x,a-3*h)
showEquation(eq4,4)

eq5 = fx.subs(x,a-6*h)-sp.series(fx,x=x,x0=a,n=5).subs(x,a-6*h)
showEquation(eq5,5)

eq6 = (1/16)*eq5 - eq4
showEquation(eq6,6)

eq7 = eq6 - (27/16)*eq3
showEquation(eq7,7)
```

(Eq. 4). \,f{\left (a - 3 h \right )} - f{\left (a \right )} + 3 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{9 h^{2}}{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \frac{9 h^{3}}{2} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{27 h^{4}}{8} \left. \frac{d^{4}}{d \xi_{1}^{4}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 5). \,f{\left (a - 6 h \right )} - f{\left (a \right )} + 6 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 18 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + 36 h^{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 54 h^{4} \left. \frac{d^{4}}{d \xi_{1}^{4}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 6). \,- f{\left (a - 3 h \right )} + 0.0625 f{\left (a - 6 h \right )} + 0.9375 f{\left (a \right )} - 2.625 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + 3.375 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 2.25 h^{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 7). \,27.0 f{\left (a - h \right )} - 1.6875 f{\left (a - 2 h \right )} - f{\left (a - 3 h \right )} + 0.0625 f{\left (a - 6 h \right )} - 24.375 f{\left (a \right )} + 21.0 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 6.75 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

```
eq8 = fx.subs(x,a-4*h)-sp.series(fx,x=x,x0=a,n=5).subs(x,a-4*h)
showEquation(eq8,8)

eq9 = fx.subs(x,a-8*h)-sp.series(fx,x=x,x0=a,n=5).subs(x,a-8*h)
showEquation(eq9,9)

eq10 = eq9 - 16*eq8
showEquation(eq10,10)

eq11 = eq10 - 64*eq3
showEquation(eq11,11)
```

(Eq. 8). \,f{\left (a - 4 h \right )} - f{\left (a \right )} + 4 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 8 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \frac{32 h^{3}}{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{32 h^{4}}{3} \left. \frac{d^{4}}{d \xi_{1}^{4}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 9). \,f{\left (a - 8 h \right )} - f{\left (a \right )} + 8 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 32 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \frac{256 h^{3}}{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{512 h^{4}}{3} \left. \frac{d^{4}}{d \xi_{1}^{4}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 10). \,- 16 f{\left (a - 4 h \right )} + f{\left (a - 8 h \right )} + 15 f{\left (a \right )} - 56 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + 96 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - \frac{256 h^{3}}{3} \left. \frac{d^{3}}{d \xi_{1}^{3}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

(Eq. 11). \,1024 f{\left (a - h \right )} - 64 f{\left (a - 2 h \right )} - 16 f{\left (a - 4 h \right )} + f{\left (a - 8 h \right )} - 945 f{\left (a \right )} + 840 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} - 288 h^{2} \left. \frac{d^{2}}{d \xi_{1}^{2}}  f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

```
eq12 = eq11 - (128/3)*eq7
showEquation(eq12,12)
```

(Eq. 12). \,- 128.0 f{\left (a - h \right )} + 8.0 f{\left (a - 2 h \right )} + 42.6666666666667 f{\left (a - 3 h \right )} - 16 f{\left (a - 4 h \right )} - 2.66666666666667 f{\left (a - 6 h \right )} + f{\left (a - 8 h \right )} + 95.0 f{\left (a \right )} - 56.0 h \left. \frac{d}{d \xi_{1}} f{\left (\xi_{1} \right )} \right|_{\substack{ \xi_{1}=a }} + \mathcal{O}\left(h^{5}\right)=0

$f'(a)=\frac{128.0f(a−h)+8.0f(a−2h)-42.6666666666667f(a−3h)+16f(a−4h)+2.66666666666667f(a−6h)-f(a−8h)-95.0f(a)-O(h^5)}{-56.0h}$

**Exercise 2.**

Employ the previous formulas accordingly to estimate the acceleration at **all times** in the first numerical layer (the position 0, the one we choose in classes, this height corresponds to 10 hPa). Compute the mean of accelerations (in the globe) and plot that by using BaseMap (as we done, in classes). You may need to connect Google Drive with your Jupyter Notebook. Set $h=0.25$. Comment as needed.

**Answer.**

```
!apt-get install libgeos-3.5.0
!apt-get install libgeos-dev
!pip install https://github.com/matplotlib/basemap/archive/master.zip
```

    Reading package lists... Done
    Building dependency tree
    Reading state information... Done
    E: Unable to locate package libgeos-3.5.0
    E: Couldn't find any package by glob 'libgeos-3.5.0'
    E: Couldn't find any package by regex 'libgeos-3.5.0'
    Reading package lists... Done
    Building dependency tree
    Reading state information... Done
    libgeos-dev is already the newest version (3.6.2-1build2).
    The following package was automatically installed and is no longer required:
      libnvidia-common-440
    Use 'apt autoremove' to remove it.
    0 upgraded, 0 newly installed, 0 to remove and 39 not upgraded.
    Collecting https://github.com/matplotlib/basemap/archive/master.zip
      Using cached https://github.com/matplotlib/basemap/archive/master.zip
    Requirement already satisfied (use --upgrade to upgrade): basemap==1.2.1 from https://github.com/matplotlib/basemap/archive/master.zip in /usr/local/lib/python3.6/dist-packages
    Requirement already satisfied: matplotlib!=3.0.1,>=1.0.0 in /usr/local/lib/python3.6/dist-packages (from basemap==1.2.1) (3.2.2)
    Requirement already satisfied: numpy>=1.2.1 in /usr/local/lib/python3.6/dist-packages (from basemap==1.2.1) (1.18.5)
    Requirement already satisfied: pyproj>=1.9.3 in /usr/local/lib/python3.6/dist-packages (from basemap==1.2.1) (2.6.1.post1)
    Requirement already satisfied: pyshp>=1.2.0 in /usr/local/lib/python3.6/dist-packages (from basemap==1.2.1) (2.1.0)
    Requirement already satisfied: six in /usr/local/lib/python3.6/dist-packages (from basemap==1.2.1) (1.15.0)
    Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.6/dist-packages (from matplotlib!=3.0.1,>=1.0.0->basemap==1.2.1) (0.10.0)
    Requirement already satisfied: python-dateutil>=2.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib!=3.0.1,>=1.0.0->basemap==1.2.1) (2.8.1)
    Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib!=3.0.1,>=1.0.0->basemap==1.2.1) (1.2.0)
    Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.1 in /usr/local/lib/python3.6/dist-packages (from matplotlib!=3.0.1,>=1.0.0->basemap==1.2.1) (2.4.7)
    Building wheels for collected packages: basemap
      Building wheel for basemap (setup.py) ... done
      Created wheel for basemap: filename=basemap-1.2.1-cp36-cp36m-linux_x86_64.whl size=121756181 sha256=53a16ce292491e2474f9b96413b900a03836f3b4d9b0d067d22daccf78aa918c
      Stored in directory: /tmp/pip-ephem-wheel-cache-b7f25zsb/wheels/98/4a/fc/ce719b75d97e646645c225f3332b1b217536100314922e9572
    Successfully built basemap

```
pip install netcdf4
```

    Collecting netcdf4
      Downloading https://files.pythonhosted.org/packages/09/39/3687b2ba762a709cd97e48dfaf3ae36a78ae603ec3d1487f767ad58a7b2e/netCDF4-1.5.4-cp36-cp36m-manylinux1_x86_64.whl (4.3MB)
         |████████████████████████████████| 4.3MB 3.5MB/s
    Requirement already satisfied: numpy>=1.9 in /usr/local/lib/python3.6/dist-packages (from netcdf4) (1.18.5)
    Collecting cftime
      Downloading https://files.pythonhosted.org/packages/81/f4/31cb9b65f462ea960bd334c5466313cb7b8af792f272546b68b7868fccd4/cftime-1.2.1-cp36-cp36m-manylinux1_x86_64.whl (287kB)
         |████████████████████████████████| 296kB 35.0MB/s
    Installing collected packages: cftime, netcdf4
    Successfully installed cftime-1.2.1 netcdf4-1.5.4

```
from google.colab import drive
drive.mount('/content/drive')
import pandas as pd
import numpy as np
from netCDF4 import Dataset
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import seaborn as sns
```

    Go to this URL in a browser: https://accounts.google.com/o/oauth2/auth?client_id=947318989803-6bn6qk8qdgf4n4g3pfee6491hc0brc4i.apps.googleusercontent.com&redirect_uri=urn%3aietf%3awg%3aoauth%3a2.0%3aoob&scope=email%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdocs.test%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive%20https%3a%2f%2fwww.googleapis.com%2fauth%2fdrive.photos.readonly%20https%3a%2f%2fwww.googleapis.com%2fauth%2fpeopleapi.readonly&response_type=code

    Enter your authorization code:
    ··········
    Mounted at /content/drive

    /usr/local/lib/python3.6/dist-packages/statsmodels/tools/_testing.py:19: FutureWarning: pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
      import pandas.util.testing as tm

```
u_wnd = Dataset('/content/drive/My Drive/uwnd.2020.nc','r');
v_wnd = Dataset('/content/drive/My Drive/vwnd.2020.nc','r');
```

```
lon = u_wnd['lon'][:];
lat = v_wnd['lat'][:];
u = u_wnd['uwnd'];
v = v_wnd['vwnd'];
u = u[:,0,:,:];
v = v[:,0,:,:];
ws = np.sqrt(np.power(u,2)+np.power(v,2))
times, nlat, nlon = np.shape(ws);
ac = np.zeros((times-1,nlat,nlon));
n_ws=len(ws)
```

```
def fwd_diff(f8, f6, f4, f3, f2, f1, f0, h): #Approach from the right
  return (-f8+2.66666666666667*f6+16*f4-42.6666666666667*f3-8.0*f2+128.0*f1-95.0*f0)/(56.0*h)
```

```
def fbwd_diff(f8, f6, f4, f3, f2, f1, f0, h): #Approach from the left
  return (128.0*f1+8.0*f2-42.6666666666667*f3+16*f4+2.66666666666667*f6-f8-95.0*f0)/(-56.0*h)
```

```
for i in range (0,n_ws-8):
  ac[i,:,:] = fwd_diff(ws[i+8,:,:],ws[i+6,:,:],ws[i+4,:,:],ws[i+3,:,:],ws[i+2,:,:],ws[i+1,:,:],ws[i,:,:],0.25);
for i in range (n_ws-7,n_ws-1):
  ac[i,:,:] = fbwd_diff(ws[i-8,:,:],ws[i-6,:,:],ws[i-4,:,:],ws[i-3,:,:],ws[i-2,:,:],ws[i-1,:,:],ws[i,:,:],0.25);
```

```
ac_mean = np.mean(ac,0); #Average accelerations
lonM,latM = np.meshgrid(lon, lat);
fig = plt.figure(figsize=(10,8));
m = Basemap(resolution='l',projection='robin',lat_0=lat[0],lon_0=lon[0]);
m.shadedrelief(scale=0.5);
m.drawcoastlines(linewidth=1);
m.drawcountries(linewidth=1);
m.drawparallels(np.arange(-90,90,20));
m.drawmeridians(np.arange(0,357.5,20));
m.contourf(lonM,latM,np.abs(ac_mean),latlon=True,cmap='jet',alpha=0.6);
cbar = m.colorbar(location='bottom');
cbar.set_label(label='W');
cbar.set_label(label='Wind Acceleration in $m/s^2$', size=25);
plt.show();
```

**Recuerde:** En este curso no se tolerará el plagio. Sin excepción, en caso de presentarse esta situación, a los estudiantes involucrados se les iniciará proceso de investigación, y se actuará en conformidad con el Reglamento de Estudiantes de la Universidad del Norte. El plagio incluye: usar contenidos sin la debida referencia, de manera literal o con mínimos cambios que no alteren el espíritu del texto/código; adquirir con o sin intención, trabajos de terceros y presentarlos parcial o totalmente como propios; presentar trabajos en grupo donde alguno de los integrantes no trabajó o donde no hubo trabajo demostrable en equipo; entre otras situaciones definidas en el manual de fraude académico de la Universidad del Norte:

(https://guayacan.uninorte.edu.co/normatividad_interna/upload/File/Guia_Prevencion_Fraude%20estudiantes(5).pdf ).


Text provided under a Creative Commons Attribution license, CC-BY.  All code is made available under the FSF-approved MIT license.  (c) Lorena A. Barba, Gilbert F. Forsyth 2015. Thanks to NSF for support via CAREER award #1149784.
[@LorenaABarba](https://twitter.com/LorenaABarba)

12 steps to Navier-Stokes
=====
***

We continue our journey to solve the Navier-Stokes equation with Step 4. But don't continue unless you have completed the previous steps! In fact, this next step will be a combination of the two previous ones. The wonders of *code reuse*!

Step 4: Burgers' Equation
----
***

You can read about Burgers' Equation on its [wikipedia page](http://en.wikipedia.org/wiki/Burgers'_equation).

Burgers' equation in one spatial dimension looks like this:

$$\frac{\partial u}{\partial t} + u \frac{\partial u}{\partial x} = \nu \frac{\partial ^2u}{\partial x^2}$$

As you can see, it is a combination of non-linear convection and diffusion. It is surprising how much you learn from this neat little equation!

We can discretize it using the methods we've already detailed in Steps [1](http://nbviewer.ipython.org/urls/github.com/barbagroup/aCFDPython/blob/master/lessons/01_Step_1.ipynb) to [3](http://nbviewer.ipython.org/urls/github.com/barbagroup/CFDPython/blob/master/lessons/04_Step_3.ipynb).  Using forward difference for time, backward difference for space and our 2nd-order method for the second derivatives yields:

$$\frac{u_i^{n+1}-u_i^n}{\Delta t} + u_i^n \frac{u_i^n - u_{i-1}^n}{\Delta x} = \nu \frac{u_{i+1}^n - 2u_i^n + u_{i-1}^n}{\Delta x^2}$$

As before, once we have an initial condition, the only unknown is $u_i^{n+1}$. We will step in time as follows:

$$u_i^{n+1} = u_i^n - u_i^n \frac{\Delta t}{\Delta x} (u_i^n - u_{i-1}^n) + \nu \frac{\Delta t}{\Delta x^2}(u_{i+1}^n - 2u_i^n + u_{i-1}^n)$$

###Initial and Boundary Conditions

To examine some interesting properties of Burgers' equation, it is helpful to use different initial and boundary conditions than we've been using for previous steps.

Our initial condition for this problem is going to be:

\begin{eqnarray}
u &=& -\frac{2 \nu}{\phi} \frac{\partial \phi}{\partial x} + 4 \\\
\phi &=& \exp \bigg(\frac{-x^2}{4 \nu} \bigg) + \exp \bigg(\frac{-(x-2 \pi)^2}{4 \nu} \bigg)
\end{eqnarray}

This has an analytical solution, given by:

\begin{eqnarray}
u &=& -\frac{2 \nu}{\phi} \frac{\partial \phi}{\partial x} + 4 \\\
\phi &=& \exp \bigg(\frac{-(x-4t)^2}{4 \nu (t+1)} \bigg) + \exp \bigg(\frac{-(x-4t -2 \pi)^2}{4 \nu(t+1)} \bigg)
\end{eqnarray}

Our boundary condition will be:

$$u(0) = u(2\pi)$$

This is called a *periodic* boundary condition. Pay attention! This will cause you a bit of headache if you don't tread carefully.

###Saving Time with SymPy

The initial condition we're using for Burgers' Equation can be a bit of a pain to evaluate by hand.  The derivative $\frac{\partial \phi}{\partial x}$ isn't too terribly difficult, but it would be easy to drop a sign or forget a factor of $x$ somewhere, so we're going to use SymPy to help us out.

[SymPy](http://sympy.org/en/) is the symbolic math library for Python.  It has a lot of the same symbolic math functionality as Mathematica with the added benefit that we can easily translate its results back into our Python calculations (it is also free and open source).

Start by loading the SymPy library, together with our favorite library, NumPy.

```python
import numpy
import sympy
```

We're also going to tell SymPy that we want all of its output to be rendered using $\LaTeX$. This will make our Notebook beautiful!

```python
from sympy import init_printing
init_printing(use_latex=True)
```

Start by setting up symbolic variables for the three variables in our initial condition and then type out the full equation for $\phi$.  We should get a nicely rendered version of our $\phi$ equation.

```python
x, nu, t = sympy.symbols('x nu t')
phi = sympy.exp(-(x-4*t)**2/(4*nu*(t+1))) + sympy.exp(-(x-4*t-2*numpy.pi)**2/(4*nu*(t+1)))
phi
```

It's maybe a little small, but that looks right.  Now to evaluate our partial derivative $\frac{\partial \phi}{\partial x}$ is a trivial task.

```python
phiprime = phi.diff(x)
phiprime
```

If you want to see the unrendered version, just use the Python print command.

```python
print(phiprime)
```

    -(-8*t + 2*x)*exp(-(-4*t + x)**2/(4*nu*(t + 1)))/(4*nu*(t + 1)) - (-8*t + 2*x - 12.5663706143592)*exp(-(-4*t + x - 6.28318530717959)**2/(4*nu*(t + 1)))/(4*nu*(t + 1))

###Now what?

Now that we have the Pythonic version of our derivative, we can finish writing out the full initial condition equation and then translate it into a usable Python expression.  For this, we'll use the *lambdify* function, which takes a SymPy symbolic equation and turns it into a callable function.

```python
from sympy.utilities.lambdify import lambdify

u = -2*nu*(phiprime/phi)+4
print(u)
```

    -2*nu*(-(-8*t + 2*x)*exp(-(-4*t + x)**2/(4*nu*(t + 1)))/(4*nu*(t + 1)) - (-8*t + 2*x - 12.5663706143592)*exp(-(-4*t + x - 6.28318530717959)**2/(4*nu*(t + 1)))/(4*nu*(t + 1)))/(exp(-(-4*t + x - 6.28318530717959)**2/(4*nu*(t + 1))) + exp(-(-4*t + x)**2/(4*nu*(t + 1)))) + 4

###Lambdify

To lambdify this expression into a useable function, we tell lambdify which variables to request and the function we want to plug them in to.

```python
ufunc = lambdify((t, x, nu), u)
print(ufunc(1,4,3))
```

    3.4917066420644494

###Back to Burgers' Equation

Now that we have the initial conditions set up, we can proceed and finish setting up the problem.  We can generate the plot of the initial condition using our lambdify-ed function.

```python
from matplotlib import pyplot
%matplotlib inline

###variable declarations
nx = 101
nt = 100
dx = 2*numpy.pi/(nx-1)
nu = .07
dt = dx*nu

x = numpy.linspace(0, 2*numpy.pi, nx)
#u = numpy.empty(nx)
un = numpy.empty(nx)
t = 0

u = numpy.asarray([ufunc(t, x0, nu) for x0 in x])
u
```

    array([ 4.        ,  4.06283185,  4.12566371,  4.18849556,  4.25132741,
            4.31415927,  4.37699112,  4.43982297,  4.50265482,  4.56548668,
            4.62831853,  4.69115038,  4.75398224,  4.81681409,  4.87964594,
            4.9424778 ,  5.00530965,  5.0681415 ,  5.13097336,  5.19380521,
            5.25663706,  5.31946891,  5.38230077,  5.44513262,  5.50796447,
            5.57079633,  5.63362818,  5.69646003,  5.75929189,  5.82212374,
            5.88495559,  5.94778745,  6.0106193 ,  6.07345115,  6.136283  ,
            6.19911486,  6.26194671,  6.32477856,  6.38761042,  6.45044227,
            6.51327412,  6.57610598,  6.63893783,  6.70176967,  6.76460125,
            6.82742866,  6.89018589,  6.95176632,  6.99367964,  6.72527549,
            4.        ,  1.27472451,  1.00632036,  1.04823368,  1.10981411,
            1.17257134,  1.23539875,  1.29823033,  1.36106217,  1.42389402,
            1.48672588,  1.54955773,  1.61238958,  1.67522144,  1.73805329,
            1.80088514,  1.863717  ,  1.92654885,  1.9893807 ,  2.05221255,
            2.11504441,  2.17787626,  2.24070811,  2.30353997,  2.36637182,
            2.42920367,  2.49203553,  2.55486738,  2.61769923,  2.68053109,
            2.74336294,  2.80619479,  2.86902664,  2.9318585 ,  2.99469035,
            3.0575222 ,  3.12035406,  3.18318591,  3.24601776,  3.30884962,
            3.37168147,  3.43451332,  3.49734518,  3.56017703,  3.62300888,
            3.68584073,  3.74867259,  3.81150444,  3.87433629,  3.93716815,  4.        ])

```python
pyplot.figure(figsize=(11,7), dpi=100)
pyplot.plot(x,u, marker='o', lw=2)
pyplot.xlim([0,2*numpy.pi])
pyplot.ylim([0,10]);
```

This is definitely not the hat function we've been dealing with until now. We call it a "saw-tooth function".  Let's proceed forward and see what happens.

### Periodic Boundary Conditions

One of the big differences between Step 4 and the previous lessons is the use of *periodic* boundary conditions.  If you experiment with Steps 1 and 2 and make the simulation run longer (by increasing `nt`) you will notice that the wave will keep moving to the right until it no longer even shows up in the plot.

With periodic boundary conditions, when a point gets to the right-hand side of the frame, it *wraps around* back to the front of the frame.

Recall the discretization that we worked out at the beginning of this notebook:

$$u_i^{n+1} = u_i^n - u_i^n \frac{\Delta t}{\Delta x} (u_i^n - u_{i-1}^n) + \nu \frac{\Delta t}{\Delta x^2}(u_{i+1}^n - 2u_i^n + u_{i-1}^n)$$

What does $u_{i+1}^n$ *mean* when $i$ is already at the end of the frame?

Think about this for a minute before proceeding.

```python
for n in range(nt):
    un = u.copy()
    for i in range(1, nx-1):
        u[i] = un[i] - un[i] * dt/dx *(un[i] - un[i-1]) + nu*dt/dx**2*\
                (un[i+1]-2*un[i]+un[i-1])
    u[0] = un[0] - un[0] * dt/dx * (un[0] - un[-2]) + nu*dt/dx**2*\
                (un[1]-2*un[0]+un[-2])
    u[-1] = un[-1] - un[-1] * dt/dx * (un[-1] - un[-2]) + nu*dt/dx**2*\
                (un[0]-2*un[-1]+un[-2])

u_analytical = numpy.asarray([ufunc(nt*dt, xi, nu) for xi in x])
```

```python
pyplot.figure(figsize=(11,7), dpi=100)
pyplot.plot(x,u, marker='o', lw=2, label='Computational')
pyplot.plot(x, u_analytical, label='Analytical')
pyplot.xlim([0,2*numpy.pi])
pyplot.ylim([0,10])
pyplot.legend();
```

***

What next?
----

The subsequent steps, from 5 to 12, will be in two dimensions. But it is easy to extend the 1D finite-difference formulas to the partial derivatives in 2D or 3D. Just apply the definition — a partial derivative with respect to $x$ is the variation in the $x$ direction *while keeping $y$ constant*.

Before moving on to [Step 5](http://nbviewer.ipython.org/urls/github.com/barbagroup/CFDPython/blob/master/lessons/07_Step_5.ipynb), make sure you have completed your own code for steps 1 through 4 and you have experimented with the parameters and thought about what is happening. Also, we recommend that you take a slight break to learn about [array operations with NumPy](http://nbviewer.ipython.org/urls/github.com/barbagroup/CFDPython/blob/master/lessons/07_Step_5.ipynb).

```python
from IPython.core.display import HTML
def css_styling():
    styles = open("../styles/custom.css", "r").read()
    return HTML(styles)
css_styling()
```

<link href='http://fonts.googleapis.com/css?family=Fenix' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Alegreya+Sans:100,300,400,500,700,800,900,100italic,300italic,400italic,500italic,700italic,800italic,900italic' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Source+Code+Pro:300,400' rel='stylesheet' type='text/css'>
<style>
    @font-face {
        font-family: "Computer Modern";
        src: url('http://mirrors.ctan.org/fonts/cm-unicode/fonts/otf/cmunss.otf');
    }
    div.cell{
        width:800px;
        margin-left:16% !important;
        margin-right:auto;
    }
    h1 {
        font-family: 'Alegreya Sans', sans-serif;
    }
    h2 {
        font-family: 'Fenix', serif;
    }
    h3{
		font-family: 'Fenix', serif;
        margin-top:12px;
        margin-bottom: 3px;
       }
	h4{
		font-family: 'Fenix', serif;
       }
    h5 {
        font-family: 'Alegreya Sans', sans-serif;
    }
    div.text_cell_render{
        font-family: 'Alegreya Sans',Computer Modern, "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
        line-height: 135%;
        font-size: 120%;
        width:600px;
        margin-left:auto;
        margin-right:auto;
    }
    .CodeMirror{
            font-family: "Source Code Pro";
			font-size: 90%;
    }
/*    .prompt{
        display: None;
    }*/
    .text_cell_render h1 {
        font-weight: 200;
        font-size: 50pt;
		line-height: 100%;
        color:#CD2305;
        margin-bottom: 0.5em;
        margin-top: 0.5em;
        display: block;
    }
    .text_cell_render h5 {
        font-weight: 300;
        font-size: 16pt;
        color: #CD2305;
        font-style: italic;
        margin-bottom: .5em;
        margin-top: 0.5em;
        display: block;
    }

    .warning{
        color: rgb( 240, 20, 20 )
        }
</style>


# Múltiples Capas

## Objetivo
El **objetivo** de esta libreta es dar a conocer el esquema básico bajo el cual se pueden manipular diferentes
capas en `TensorFlow`. Una vez hecho esto se podrá visualizar todo el _grafo de computación_ mediante
`TensorBoard` para analizar con detalle todos los pasos que se siguen al realizar operaciones más complicadas.

## Procedimiento
El procedimiento a seguir en esta libreta es el siguiente:

1. Se crea una imagen de 8 pixeles de forma aleatoria y se le implementa un simple filtro de promedio.
En particular este filtro como funciona es que toma un tamaño de la imagen y promedia el número de pixeles
que se defina, por lo que resultará en una imagen más pequeña. En este caso será un promedio simple, por lo
tanto resultará una imagen de 4 pixeles.

2. Después se creará una capa personalizada donde se harán algunas de las operaciones que ya se conocen
para demostrar cómo es que `TensorFlow` permite la conexión y comunicación de datos entre capas.

3. Por último, se pretende guardar todas estas operaciones tal que posteriormente se puedan visualizar como un grafo
de computación utilizando `TensorBoard`.

```python
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

session = tf.Session()
```

## Promedio móvil (Filtro espacial)
El tipo de _filtro_ que se implementará aquí es una operación conocida coloquialmente como _promedio móvil_, sin embargo su nombre
formal es **filtro espacial.** Esto es en general el campo de estudio del _procesamiento digital de imágenes_ y como tal no está
dentro del alcance de esta libreta; como referencia se deja el libro de [González & Woods](http://www.imageprocessingplace.com/)
que es el estándar para esta área.

Básicamente, se tendrá una matriz y se le aplicará el promedio mediante una operación matemática llamada _convolución,_ sin embargo
el término correcto es una _correlación_ dado que es un filtro _móvil_ y se define por la siguiente operación:
$$ w(x, y) \star f(x, y) = \sum_{s=-a}^{a} \sum_{t=-b}^{b} w(s, t) f(x+s, y+t).$$
Por el momento no es necesario darle tanto detalle a esta operación, por lo pronto se utilizará como una caja negra.
En particular esta operación está definida en `TensorFlow` como `conv2d` por lo que no hay necesidad de implementarla, de hecho es una
operación muy común en el área de imágenes, visión por computadora e inteligencia artificial.

## Detalles del ejemplo presentado
Para crear la imagen aleatoria y poder realizar la _correlación_ con el filtro entonces se debe crear una imagen con un tamaño muy
característico, donde cada elemento de la lista de dimensión corresponde a los siguientes elementos:

1. Número de la imagen

2. Altura

3. Ancho

4. Número de canales de color

De esta forma se creará una imagen aleatoria con `numpy` y con esta información se trabajará durante toda la libreta.

```python
# Definir el tamaño de la imagen como se ha mencionado
x_shape = [1, 4, 4, 1]
x_val = np.random.uniform(size=x_shape)
x_val
```

    array([[[[0.15611847],
             [0.31895929],
             [0.88520538],
             [0.544918  ]],

            [[0.24391134],
             [0.9904592 ],
             [0.63431371],
             [0.62491614]],

            [[0.05575135],
             [0.94048611],
             [0.61008244],
             [0.47641165]],

            [[0.03910864],
             [0.92118179],
             [0.18467528],
             [0.39812862]]]])

```python
# Se puede observar la imagen cambiando el tamaño del arreglo
plt.imshow(x_val.reshape(4, 4))
```

```python
# Para operar con la imagen, se crea un placeholder de TensorFlow
x_data = tf.placeholder(tf.float32, shape=x_shape)
```

```python
# El tamaño del promedio, es 1/4
filtro = tf.constant(0.25, shape=[2, 2, 1, 1])
# Esta lista es la forma cómo se mueve el filtro
strides = [1, 2, 2, 1]
# Capa de promedio móvil
prom_movil = tf.nn.conv2d(x_data, filtro, strides, padding='SAME',
name='Promedio_Movil')
```

## Sobre la _convolución_ en `TensorFlow`
La [convolución en TensorFlow](https://www.tensorflow.org/versions/r1.9/api_guides/python/nn#Convolution) tiene una forma de
implementación diferente y única que se debe leer la documentación con cuidado. Aquí se mencionan algunos detalles importantes:

1. El _filtro_ aplicado debe de tener el mismo tamaño que los datos de la imagen.

2. Los _strides_ son la forma cómo se mueve el filtro. Según la [documentación](https://www.tensorflow.org/versions/r1.9/api_docs/python/tf/nn/conv2d?hl=en#args)
se tiene que corresponde a los mismos valores que los datos originales, es decir a la lista que se tiene en la celda anterior donde se describen por primera
vez estos datos.

3. La opción de `padding` es un término del área de _procesamiento digital de imágenes_ lo cual es algo análogo a un _margen_ en imágenes
y esto se hace para no perder información en las orillas de la imagen. En particular, `SAME` viene descrito con mucho más detalle en la
[documentación](https://www.tensorflow.org/versions/r1.9/api_guides/python/nn#Notes_on_SAME_Convolution_Padding).

```python
# Producir la imagen filtrada y mostrar los datos
img_prom = session.run(prom_movil, feed_dict={x_data: x_val})
img_prom
```

    array([[[[0.42736205],
             [0.6723383 ]],

            [[0.48913196],
             [0.41732448]]]], dtype=float32)

```python
# Mostrar ahora la imagen encontrada que corresponde a estos datos
plt.imshow(img_prom.reshape(2, 2))
```

Esta siguiente parte consta de crear una capa personalizada con operaciones diversas, es importante
notar que en realidad no significa nada como tal, no tiene un fundamento matemático o riguroso, la idea es simplemente
ilustrar lo que se puede llevar a cabo cuando se tienen múltiples capas.

En particular, lo que se pretende ahora es tomar la matriz resultado de las operaciones anteriores y realizar las
siguientes operaciones matemáticas:

\begin{equation}
\vec{b} = \mathbf{A} \cdot \vec{x} + \vec{b}, \text{y después aplicar la función sigmoide} \\
\vec{c} = \frac{1}{1 + e^{-\vec{b}}} .
\end{equation}

Con esto se tienen dos capas de cómputo donde el resultado de una capa tiene que ser la entrada de la otra capa, por lo
que en `TensorFlow` deben de existir algunos ajustes a los datos originales de la imagen.

```python
def capa_personalizada(input_matrix):
    # Reducir dimensiones redundantes en los datos
    input_matrix_squeezed = tf.squeeze(input_matrix)
    # Crear una "matriz" dummy, los valores son inventados
    a_mat = tf.constant([[1.0, 2.0], [3.0, 4.0]])
    # Así como los valores de b
    b = tf.constant(1.0, shape = [2, 2])
    # Realizar la multiplicación de arreglos
    temp1 = tf.matmul(a_mat, input_matrix_squeezed)
    # Y sumar el vector adicional
    temp2 = tf.add(temp1, b)

    # Regresar el resultado aplicando la función sigmoide
    return tf.sigmoid(temp2)
```

```python
# Se tiene que realizar una entrada en el grafo basándose en la función
# personalizada que se acaba de crear
with tf.name_scope('Custom_Layer') as scope:
    customlayer1 = capa_personalizada(prom_movil)
```

```python
# Estas linea permite guardar los resultados de todo el grafo computacional
writer = tf.summary.FileWriter("multiples-capas", session.graph)
# Asignar el valor resultante
img_sigm = session.run(customlayer1, feed_dict={x_data: x_val})
# Terminar de escribir y cerrar archivos
writer.close()
```

Esta última celda permite guardar los datos obtenidos del grafo en un directorio, con nombre `multiples-capas` que después
podrá ser visualizado con `TensorBoard`.

`TensorBoard` ya viene instalado por default cuando se install `TensorFlow` por lo que no debe haber problemas de
compatibilidad en esta parte. Para poder visualizar la parte del grafo sólo basta ejecutar el siguiente comando en la
terminal:
```bash
tensorboard --logdir="multiples-capas"
```
y para que funcione se debe estar posicionado en el directorio que contenga a `multiples-capas`.

```python
# Mostrar los resultados obtenidos como números
img_sigm
```

    array([[0.9172553, 0.9246302],
           [0.9857777, 0.9908636]], dtype=float32)

```python
# Y mostrar los mismos resultados como imagen
plt.imshow(img_sigm.reshape(2, 2))
```


# Solution {-}

PVA Markov model

```python
from sympy import Matrix, symbols, sqrt, eye, integrate, inverse_laplace_transform

s, dt, beta, q = symbols('s dt beta q', positive=True)

F = Matrix([[0, 1, 0],
            [0, 0, 1],
            [0, 0, -beta]])

G = Matrix([[0],
            [0],
            [sqrt(q)]])

phi = inverse_laplace_transform((s*eye(3) - F).inv(), s, dt)
phi
```

$\displaystyle \left[\begin{matrix}1 & dt & \frac{dt}{\beta} - \frac{1}{\beta^{2}} + \frac{e^{- \beta dt}}{\beta^{2}}\\0 & 1 & \frac{1}{\beta} - \frac{e^{- \beta dt}}{\beta}\\0 & 0 & e^{- \beta dt}\end{matrix}\right]$

```python
# Process noise
Q = integrate(phi@G@G.T@phi.T, dt)
Q
```

$\displaystyle \left[\begin{matrix}\frac{dt^{3} q}{3 \beta^{2}} - \frac{dt^{2} q}{\beta^{3}} + \frac{dt q}{\beta^{4}} + \frac{- 4 \beta^{5} dt q e^{- \beta dt} - \beta^{4} q e^{- 2 \beta dt}}{2 \beta^{9}} & \frac{dt^{2} q}{2 \beta^{2}} - \frac{dt q}{\beta^{3}} + \frac{\beta^{4} q e^{- 2 \beta dt} + \left(2 \beta^{5} dt q - 2 \beta^{4} q\right) e^{- \beta dt}}{2 \beta^{8}} & \frac{- 2 \beta^{3} dt q e^{- \beta dt} - \beta^{2} q e^{- 2 \beta dt}}{2 \beta^{5}}\\\frac{dt^{2} q}{2 \beta^{2}} - \frac{dt q}{\beta^{3}} + \frac{\beta^{4} q e^{- 2 \beta dt} + \left(2 \beta^{5} dt q - 2 \beta^{4} q\right) e^{- \beta dt}}{2 \beta^{8}} & \frac{dt q}{\beta^{2}} + \frac{4 \beta^{3} q e^{- \beta dt} - \beta^{3} q e^{- 2 \beta dt}}{2 \beta^{6}} & \frac{- 2 \beta^{2} q e^{- \beta dt} + \beta^{2} q e^{- 2 \beta dt}}{2 \beta^{4}}\\\frac{- 2 \beta^{3} dt q e^{- \beta dt} - \beta^{2} q e^{- 2 \beta dt}}{2 \beta^{5}} & \frac{- 2 \beta^{2} q e^{- \beta dt} + \beta^{2} q e^{- 2 \beta dt}}{2 \beta^{4}} & - \frac{q e^{- 2 \beta dt}}{2 \beta}\end{matrix}\right]$

```python
from numpy import array, sqrt
from lib.vanloan import numeval

# System conditions
dt = 0.1
beta = 0.2
q = 10

F = array([[0, 1, 0],
           [0, 0, 1],
           [0, 0, -beta]])

G = array([[0],
           [0],
           [sqrt(q)]])

# Numerical evaulation
[phi, Q] = numeval(F, G, dt)

# Transition matrix
print(phi)

# Process noise covariance matrix
print(Q)
```

    [[1.         0.1        0.00496683]
     [0.         1.         0.09900663]
     [0.         0.         0.98019867]]
    [[4.94483906e-06 1.23347134e-04 1.63369713e-03]
     [1.23347134e-04 3.28379669e-03 4.90115674e-02]
     [1.63369713e-03 4.90115674e-02 9.80264021e-01]]