```
%matplotlib inline
from IPython.display import display
from sympy import *
x = symbols('x')
i = symbols('i', integer=True)
init_printing()
```

```
sstellen = [-2, -1, 0, 1, 2]
```

```
L = [1, 1, 1, 1, 1]
for j in range(5):
  for k in range(5):
    if k != j:
      L[j] = L[j] * (x - sstellen[k])/(sstellen[j]-sstellen[k])
```

```
p = plot(L[0], (x, -2.5, 2.5), show=False, line_color='r')
display(L[0])
lc = ['r', 'b', 'g', 'r', 'y']
for j in range(1, 5):
  display(L[j])
  p.extend(plot(L[j], (x, -2.5, 2.5), show=False, line_color=lc[j]))
```

```
p.show()
```

```
L_sum = 0
for i in range(5):
    L_sum += Abs(L[i])

display(L_sum)
```

    /usr/lib/python3.3/site-packages/IPython/core/formatters.py:239: FormatterWarning: Exception in image/png formatter:
    \left\lvert{x \left(- x - 1\right) \left(x - 2\right) \left(x - 1\right)}\right\rvert / 24 + \left\lvert{x \left(x / 4 + \frac{1}{2}\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert / 6 + \left\lvert{x \left(x / 3 + \frac{2}{3}\right) \left(x - 2\right) \left(x + 1\right)}\right\rvert / 2 + \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 2\right)}\right\rvert / 6 + \left\lvert{\left(x / 2 + 1\right) \left(x - 2\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert / 2
         ^
    Expected a delimiter (at char 5), (line:1, col:6)
      FormatterWarning,

$$\frac{1}{24} \left\lvert{x \left(- x - 1\right) \left(x - 2\right) \left(x - 1\right)}\right\rvert + \frac{1}{6} \left\lvert{x \left(\frac{x}{4} + \frac{1}{2}\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert + \frac{1}{2} \left\lvert{x \left(\frac{x}{3} + \frac{2}{3}\right) \left(x - 2\right) \left(x + 1\right)}\right\rvert + \frac{1}{6} \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 2\right)}\right\rvert + \frac{1}{2} \left\lvert{\left(\frac{x}{2} + 1\right) \left(x - 2\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert$$

```
L_sum_strich = simplify(diff(L_sum, x))
L_sum_strich
```

    /usr/lib/python3.3/site-packages/IPython/core/formatters.py:239: FormatterWarning: Exception in image/png formatter:
    \frac{1}{24 \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{\left(x - 2\right) \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert} \left(4 \left(\left(\left(- 3 \left(\Re{x}\right)^{2} + 2 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \left(\Im{x}\right)^{2} + \left(\left(\Re{x}\right)^{3} - \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - 4 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \Re{x}\right) \left(\left(- 3 \left(\Re{x}\right)^{2} + 2 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \Im{x} \frac{d}{d x} \Im{x} - \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} + 2 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} - 2 \Im{x} \frac{d}{d x} \Im{x} + 4 \frac{d}{d x} \Re{x}\right) \Re{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} - 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 2 \Re{x} \frac{d}{d x} \Im{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 2 \Im{x} \frac{d}{d x} \Re{x} + 4 \frac{d}{d x} \Im{x}\right) \Im{x} + \left(\left(\Re{x}\right)^{3} - \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - 4 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \frac{d}{d x} \Re{x}\right) + \left(\left(- 3 \left(\Re{x}\right)^{2} + 2 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \Im{x} \frac{d}{d x} \Re{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} + 2 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} - 2 \Im{x} \frac{d}{d x} \Im{x} + 4 \frac{d}{d x} \Re{x}\right) \Im{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} - 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 2 \Re{x} \frac{d}{d x} \Im{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 2 \Im{x} \frac{d}{d x} \Re{x} + 4 \frac{d}{d x} \Im{x}\right) \Re{x} - \left(\left(\Re{x}\right)^{3} - \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - 4 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \frac{d}{d x} \Im{x}\right) \left(\left(- 3 \left(\Re{x}\right)^{2} + 2 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \Re{x} - \left(\Re{x}\right)^{3} + \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + 4 \Re{x} - \left(\Im{x}\right)^{2} - 4\right) \Im{x}\right) \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{\left(x - 2\right) \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert + \left(\left(\left(- 3 \left(\Re{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 1\right) \left(\Im{x}\right)^{2} + \left(\left(\Re{x}\right)^{3} - 2 \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - \Re{x} + 2 \left(\Im{x}\right)^{2} + 2\right) \Re{x}\right) \left(\left(- 3 \left(\Re{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 1\right) \Im{x} \frac{d}{d x} \Im{x} - \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} + 4 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} - 4 \Im{x} \frac{d}{d x} \Im{x} + \frac{d}{d x} \Re{x}\right) \Re{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} - 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 4 \Re{x} \frac{d}{d x} \Im{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 4 \Im{x} \frac{d}{d x} \Re{x} + \frac{d}{d x} \Im{x}\right) \Im{x} + \left(\left(\Re{x}\right)^{3} - 2 \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - \Re{x} + 2 \left(\Im{x}\right)^{2} + 2\right) \frac{d}{d x} \Re{x}\right) + \left(\left(- 3 \left(\Re{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 1\right) \Im{x} \frac{d}{d x} \Re{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} + 4 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} - 4 \Im{x} \frac{d}{d x} \Im{x} + \frac{d}{d x} \Re{x}\right) \Im{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} - 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 4 \Re{x} \frac{d}{d x} \Im{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 4 \Im{x} \frac{d}{d x} \Re{x} + \frac{d}{d x} \Im{x}\right) \Re{x} - \left(\left(\Re{x}\right)^{3} - 2 \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - \Re{x} + 2 \left(\Im{x}\right)^{2} + 2\right) \frac{d}{d x} \Im{x}\right) \left(\left(- 3 \left(\Re{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 1\right) \Re{x} - \left(\Re{x}\right)^{3} + 2 \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + \Re{x} - 2 \left(\Im{x}\right)^{2} - 2\right) \Im{x}\right) \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{\left(x - 2\right) \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert + 4 \left(\left(\left(3 \left(\Re{x}\right)^{2} + 2 \Re{x} - \left(\Im{x}\right)^{2} - 4\right) \left(\Im{x}\right)^{2} + \left(- \left(\Re{x}\right)^{3} - \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \Re{x}\right) \left(\left(3 \left(\Re{x}\right)^{2} + 2 \Re{x} - \left(\Im{x}\right)^{2} - 4\right) \Im{x} \frac{d}{d x} \Im{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} - 2 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} + 2 \Im{x} \frac{d}{d x} \Im{x} + 4 \frac{d}{d x} \Re{x}\right) \Re{x} + \left(3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 2 \Re{x} \frac{d}{d x} \Im{x} - 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 2 \Im{x} \frac{d}{d x} \Re{x} - 4 \frac{d}{d x} \Im{x}\right) \Im{x} + \left(- \left(\Re{x}\right)^{3} - \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \frac{d}{d x} \Re{x}\right) + \left(\left(3 \left(\Re{x}\right)^{2} + 2 \Re{x} - \left(\Im{x}\right)^{2} - 4\right) \Im{x} \frac{d}{d x} \Re{x} - \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} - 2 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} + 2 \Im{x} \frac{d}{d x} \Im{x} + 4 \frac{d}{d x} \Re{x}\right) \Im{x} + \left(3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 2 \Re{x} \frac{d}{d x} \Im{x} - 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 2 \Im{x} \frac{d}{d x} \Re{x} - 4 \frac{d}{d x} \Im{x}\right) \Re{x} - \left(- \left(\Re{x}\right)^{3} - \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \frac{d}{d x} \Im{x}\right) \left(\left(3 \left(\Re{x}\right)^{2} + 2 \Re{x} - \left(\Im{x}\right)^{2} - 4\right) \Re{x} + \left(\Re{x}\right)^{3} + \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - 4 \Re{x} - \left(\Im{x}\right)^{2} - 4\right) \Im{x}\right) \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{\left(x - 2\right) \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert + \left(\left(\left(3 \left(\Re{x}\right)^{2} + 4 \Re{x} - \left(\Im{x}\right)^{2} - 1\right) \left(\Im{x}\right)^{2} + \left(- \left(\Re{x}\right)^{3} - 2 \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + \Re{x} + 2 \left(\Im{x}\right)^{2} + 2\right) \Re{x}\right) \left(\left(3 \left(\Re{x}\right)^{2} + 4 \Re{x} - \left(\Im{x}\right)^{2} - 1\right) \Im{x} \frac{d}{d x} \Im{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} - 4 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} + 4 \Im{x} \frac{d}{d x} \Im{x} + \frac{d}{d x} \Re{x}\right) \Re{x} + \left(3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 4 \Re{x} \frac{d}{d x} \Im{x} - 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 4 \Im{x} \frac{d}{d x} \Re{x} - \frac{d}{d x} \Im{x}\right) \Im{x} + \left(- \left(\Re{x}\right)^{3} - 2 \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + \Re{x} + 2 \left(\Im{x}\right)^{2} + 2\right) \frac{d}{d x} \Re{x}\right) + \left(\left(3 \left(\Re{x}\right)^{2} + 4 \Re{x} - \left(\Im{x}\right)^{2} - 1\right) \Im{x} \frac{d}{d x} \Re{x} - \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} - 4 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} + 4 \Im{x} \frac{d}{d x} \Im{x} + \frac{d}{d x} \Re{x}\right) \Im{x} + \left(3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 4 \Re{x} \frac{d}{d x} \Im{x} - 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 4 \Im{x} \frac{d}{d x} \Re{x} - \frac{d}{d x} \Im{x}\right) \Re{x} - \left(- \left(\Re{x}\right)^{3} - 2 \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + \Re{x} + 2 \left(\Im{x}\right)^{2} + 2\right) \frac{d}{d x} \Im{x}\right) \left(\left(3 \left(\Re{x}\right)^{2} + 4 \Re{x} - \left(\Im{x}\right)^{2} - 1\right) \Re{x} + \left(\Re{x}\right)^{3} + 2 \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - \Re{x} - 2 \left(\Im{x}\right)^{2} - 2\right) \Im{x}\right) \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{\left(x - 2\right) \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert + 12 \left(2 \left(- 2 \left(\Re{x}\right)^{2} + 2 \left(\Im{x}\right)^{2} + 5\right) \left(- 2 \left(\Re{x}\right)^{3} \frac{d}{d x} \Im{x} - 6 \left(\Re{x}\right)^{2} \Im{x} \frac{d}{d x} \Re{x} + 6 \Re{x} \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 5 \Re{x} \frac{d}{d x} \Im{x} + 2 \left(\Im{x}\right)^{3} \frac{d}{d x} \Re{x} + 5 \Im{x} \frac{d}{d x} \Re{x}\right) \Re{x} \Im{x} + \left(2 \left(\Re{x}\right)^{3} \frac{d}{d x} \Re{x} - 6 \left(\Re{x}\right)^{2} \Im{x} \frac{d}{d x} \Im{x} - 6 \Re{x} \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} - 5 \Re{x} \frac{d}{d x} \Re{x} + 2 \left(\Im{x}\right)^{3} \frac{d}{d x} \Im{x} + 5 \Im{x} \frac{d}{d x} \Im{x}\right) \left(\left(\Re{x}\right)^{4} - 6 \left(\Re{x}\right)^{2} \left(\Im{x}\right)^{2} - 5 \left(\Re{x}\right)^{2} + \left(\Im{x}\right)^{4} + 5 \left(\Im{x}\right)^{2} + 4\right)\right) \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert\right)
                     ^
    Expected a delimiter (at char 17), (line:1, col:18)
      FormatterWarning,

$$\frac{1}{24 \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{\left(x - 2\right) \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert} \left(4 \left(\left(\left(- 3 \left(\Re{x}\right)^{2} + 2 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \left(\Im{x}\right)^{2} + \left(\left(\Re{x}\right)^{3} - \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - 4 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \Re{x}\right) \left(\left(- 3 \left(\Re{x}\right)^{2} + 2 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \Im{x} \frac{d}{d x} \Im{x} - \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} + 2 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} - 2 \Im{x} \frac{d}{d x} \Im{x} + 4 \frac{d}{d x} \Re{x}\right) \Re{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} - 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 2 \Re{x} \frac{d}{d x} \Im{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 2 \Im{x} \frac{d}{d x} \Re{x} + 4 \frac{d}{d x} \Im{x}\right) \Im{x} + \left(\left(\Re{x}\right)^{3} - \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - 4 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \frac{d}{d x} \Re{x}\right) + \left(\left(- 3 \left(\Re{x}\right)^{2} + 2 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \Im{x} \frac{d}{d x} \Re{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} + 2 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} - 2 \Im{x} \frac{d}{d x} \Im{x} + 4 \frac{d}{d x} \Re{x}\right) \Im{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} - 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 2 \Re{x} \frac{d}{d x} \Im{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 2 \Im{x} \frac{d}{d x} \Re{x} + 4 \frac{d}{d x} \Im{x}\right) \Re{x} - \left(\left(\Re{x}\right)^{3} - \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - 4 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \frac{d}{d x} \Im{x}\right) \left(\left(- 3 \left(\Re{x}\right)^{2} + 2 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \Re{x} - \left(\Re{x}\right)^{3} + \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + 4 \Re{x} - \left(\Im{x}\right)^{2} - 4\right) \Im{x}\right) \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{\left(x - 2\right) \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert + \left(\left(\left(- 3 \left(\Re{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 1\right) \left(\Im{x}\right)^{2} + \left(\left(\Re{x}\right)^{3} - 2 \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - \Re{x} + 2 \left(\Im{x}\right)^{2} + 2\right) \Re{x}\right) \left(\left(- 3 \left(\Re{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 1\right) \Im{x} \frac{d}{d x} \Im{x} - \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} + 4 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} - 4 \Im{x} \frac{d}{d x} \Im{x} + \frac{d}{d x} \Re{x}\right) \Re{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} - 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 4 \Re{x} \frac{d}{d x} \Im{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 4 \Im{x} \frac{d}{d x} \Re{x} + \frac{d}{d x} \Im{x}\right) \Im{x} + \left(\left(\Re{x}\right)^{3} - 2 \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - \Re{x} + 2 \left(\Im{x}\right)^{2} + 2\right) \frac{d}{d x} \Re{x}\right) + \left(\left(- 3 \left(\Re{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 1\right) \Im{x} \frac{d}{d x} \Re{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} + 4 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} - 4 \Im{x} \frac{d}{d x} \Im{x} + \frac{d}{d x} \Re{x}\right) \Im{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} - 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 4 \Re{x} \frac{d}{d x} \Im{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 4 \Im{x} \frac{d}{d x} \Re{x} + \frac{d}{d x} \Im{x}\right) \Re{x} - \left(\left(\Re{x}\right)^{3} - 2 \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - \Re{x} + 2 \left(\Im{x}\right)^{2} + 2\right) \frac{d}{d x} \Im{x}\right) \left(\left(- 3 \left(\Re{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 1\right) \Re{x} - \left(\Re{x}\right)^{3} + 2 \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + \Re{x} - 2 \left(\Im{x}\right)^{2} - 2\right) \Im{x}\right) \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{\left(x - 2\right) \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert + 4 \left(\left(\left(3 \left(\Re{x}\right)^{2} + 2 \Re{x} - \left(\Im{x}\right)^{2} - 4\right) \left(\Im{x}\right)^{2} + \left(- \left(\Re{x}\right)^{3} - \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \Re{x}\right) \left(\left(3 \left(\Re{x}\right)^{2} + 2 \Re{x} - \left(\Im{x}\right)^{2} - 4\right) \Im{x} \frac{d}{d x} \Im{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} - 2 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} + 2 \Im{x} \frac{d}{d x} \Im{x} + 4 \frac{d}{d x} \Re{x}\right) \Re{x} + \left(3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 2 \Re{x} \frac{d}{d x} \Im{x} - 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 2 \Im{x} \frac{d}{d x} \Re{x} - 4 \frac{d}{d x} \Im{x}\right) \Im{x} + \left(- \left(\Re{x}\right)^{3} - \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \frac{d}{d x} \Re{x}\right) + \left(\left(3 \left(\Re{x}\right)^{2} + 2 \Re{x} - \left(\Im{x}\right)^{2} - 4\right) \Im{x} \frac{d}{d x} \Re{x} - \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} - 2 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} + 2 \Im{x} \frac{d}{d x} \Im{x} + 4 \frac{d}{d x} \Re{x}\right) \Im{x} + \left(3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 2 \Re{x} \frac{d}{d x} \Im{x} - 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 2 \Im{x} \frac{d}{d x} \Re{x} - 4 \frac{d}{d x} \Im{x}\right) \Re{x} - \left(- \left(\Re{x}\right)^{3} - \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + 4 \Re{x} + \left(\Im{x}\right)^{2} + 4\right) \frac{d}{d x} \Im{x}\right) \left(\left(3 \left(\Re{x}\right)^{2} + 2 \Re{x} - \left(\Im{x}\right)^{2} - 4\right) \Re{x} + \left(\Re{x}\right)^{3} + \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - 4 \Re{x} - \left(\Im{x}\right)^{2} - 4\right) \Im{x}\right) \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{\left(x - 2\right) \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert + \left(\left(\left(3 \left(\Re{x}\right)^{2} + 4 \Re{x} - \left(\Im{x}\right)^{2} - 1\right) \left(\Im{x}\right)^{2} + \left(- \left(\Re{x}\right)^{3} - 2 \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + \Re{x} + 2 \left(\Im{x}\right)^{2} + 2\right) \Re{x}\right) \left(\left(3 \left(\Re{x}\right)^{2} + 4 \Re{x} - \left(\Im{x}\right)^{2} - 1\right) \Im{x} \frac{d}{d x} \Im{x} + \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} - 4 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} + 4 \Im{x} \frac{d}{d x} \Im{x} + \frac{d}{d x} \Re{x}\right) \Re{x} + \left(3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 4 \Re{x} \frac{d}{d x} \Im{x} - 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 4 \Im{x} \frac{d}{d x} \Re{x} - \frac{d}{d x} \Im{x}\right) \Im{x} + \left(- \left(\Re{x}\right)^{3} - 2 \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + \Re{x} + 2 \left(\Im{x}\right)^{2} + 2\right) \frac{d}{d x} \Re{x}\right) + \left(\left(3 \left(\Re{x}\right)^{2} + 4 \Re{x} - \left(\Im{x}\right)^{2} - 1\right) \Im{x} \frac{d}{d x} \Re{x} - \left(- 3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Re{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Im{x} - 4 \Re{x} \frac{d}{d x} \Re{x} + 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} + 4 \Im{x} \frac{d}{d x} \Im{x} + \frac{d}{d x} \Re{x}\right) \Im{x} + \left(3 \left(\Re{x}\right)^{2} \frac{d}{d x} \Im{x} + 6 \Re{x} \Im{x} \frac{d}{d x} \Re{x} + 4 \Re{x} \frac{d}{d x} \Im{x} - 3 \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 4 \Im{x} \frac{d}{d x} \Re{x} - \frac{d}{d x} \Im{x}\right) \Re{x} - \left(- \left(\Re{x}\right)^{3} - 2 \left(\Re{x}\right)^{2} + 3 \Re{x} \left(\Im{x}\right)^{2} + \Re{x} + 2 \left(\Im{x}\right)^{2} + 2\right) \frac{d}{d x} \Im{x}\right) \left(\left(3 \left(\Re{x}\right)^{2} + 4 \Re{x} - \left(\Im{x}\right)^{2} - 1\right) \Re{x} + \left(\Re{x}\right)^{3} + 2 \left(\Re{x}\right)^{2} - 3 \Re{x} \left(\Im{x}\right)^{2} - \Re{x} - 2 \left(\Im{x}\right)^{2} - 2\right) \Im{x}\right) \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{\left(x - 2\right) \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert + 12 \left(2 \left(- 2 \left(\Re{x}\right)^{2} + 2 \left(\Im{x}\right)^{2} + 5\right) \left(- 2 \left(\Re{x}\right)^{3} \frac{d}{d x} \Im{x} - 6 \left(\Re{x}\right)^{2} \Im{x} \frac{d}{d x} \Re{x} + 6 \Re{x} \left(\Im{x}\right)^{2} \frac{d}{d x} \Im{x} + 5 \Re{x} \frac{d}{d x} \Im{x} + 2 \left(\Im{x}\right)^{3} \frac{d}{d x} \Re{x} + 5 \Im{x} \frac{d}{d x} \Re{x}\right) \Re{x} \Im{x} + \left(2 \left(\Re{x}\right)^{3} \frac{d}{d x} \Re{x} - 6 \left(\Re{x}\right)^{2} \Im{x} \frac{d}{d x} \Im{x} - 6 \Re{x} \left(\Im{x}\right)^{2} \frac{d}{d x} \Re{x} - 5 \Re{x} \frac{d}{d x} \Re{x} + 2 \left(\Im{x}\right)^{3} \frac{d}{d x} \Im{x} + 5 \Im{x} \frac{d}{d x} \Im{x}\right) \left(\left(\Re{x}\right)^{4} - 6 \left(\Re{x}\right)^{2} \left(\Im{x}\right)^{2} - 5 \left(\Re{x}\right)^{2} + \left(\Im{x}\right)^{4} + 5 \left(\Im{x}\right)^{2} + 4\right)\right) \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 1\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x - 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 2\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert \left\lvert{x \left(x - 1\right) \left(x + 1\right) \left(x + 2\right)}\right\rvert\right)$$

```
solve(L_sum_strich)
```

```

```


# Detector simulation
In this notebook we load a track dataset generated by `edep-sim` and we calculate the ADC counts corresponding to each pixel. The result is exported to a HDF5 file.

```python
# This is need so you can import larndsim without doing python setup.py install
import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir)
```

```python
from math import ceil
from time import time

import matplotlib.pyplot as plt
from matplotlib import cm, colors
import mpl_toolkits.mplot3d.art3d as art3d

import numpy as np
import cupy as cp
import fire
import h5py

from numba import cuda
from numba.cuda.random import create_xoroshiro128p_states

import matplotlib as mpl
mpl.rcParams['figure.dpi'] = 100

from tqdm.notebook import tqdm
```

```python
from larndsim import consts
import importlib
importlib.reload(consts)
consts.load_detector_properties("../larndsim/detector_properties/module0.yaml","../larndsim/pixel_layouts/multi_tile_layout-2.2.16.yaml")

from larndsim import quenching, drifting, detsim, pixels_from_track, fee
```

### Dataset import
First of all we load the `edep-sim` output. For this sample we need to invert $z$ and $y$ axes.

```python
unique_pix = cp.empty((0,2))
pixels_signals = cp.zeros((len(unique_pix), len(consts.time_ticks)*3))
```

```python
with h5py.File('module0_corsika.h5', 'r') as f:
    tracks = np.array(f['segments'])

x_start = np.copy(tracks['x_start'] )
x_end = np.copy(tracks['x_end'])
x = np.copy(tracks['x'])

tracks['x_start'] = np.copy(tracks['z_start'])
tracks['x_end'] = np.copy(tracks['z_end'])
tracks['x'] = np.copy(tracks['z'])

tracks['z_start'] = x_start
tracks['z_end'] = x_end
tracks['z'] = x

selected_tracks = tracks[:100]
```

### Quenching and drifting
We calculate the number of electrons after recombination (`quenching` module) and the position and number of electrons after drifting (`drifting` module).

```python
TPB = 256
BPG = ceil(selected_tracks.shape[0] / TPB)
import importlib
importlib.reload(drifting)
quenching.quench[BPG,TPB](selected_tracks, consts.birks)
drifting.drift[BPG,TPB](selected_tracks)
```

We find the pixels intersected by the projection of the tracks on the anode plane using the Bresenham's algorithm. We also take into account the neighboring pixels, due to the transverse diffusion of the charges.

```python
# Here we build a map between tracks and event IDs
unique_eventIDs = cp.unique(selected_tracks['eventID'])
event_id_map = cp.searchsorted(unique_eventIDs,cp.asarray(selected_tracks['eventID']))

longest_pix = ceil(max(selected_tracks["dx"])/consts.pixel_pitch)
max_radius = ceil(max(selected_tracks["tran_diff"])*5/consts.pixel_pitch)

MAX_PIXELS = int((longest_pix*4+6)*max_radius*1.5)
MAX_ACTIVE_PIXELS = int(longest_pix*1.5)

active_pixels = cp.full((selected_tracks.shape[0], MAX_ACTIVE_PIXELS, 2), -1, dtype=np.int32)
neighboring_pixels = cp.full((selected_tracks.shape[0], MAX_PIXELS, 2), -1, dtype=np.int32)
n_pixels_list = cp.zeros(shape=(selected_tracks.shape[0]))
TPB = 128
BPG = ceil(selected_tracks.shape[0] / TPB)
pixels_from_track.get_pixels[BPG,TPB](selected_tracks,
                                      active_pixels,
                                      neighboring_pixels,
                                      n_pixels_list,
                                      max_radius+1)
```

```python
def cupy_unique_axis0(array):
    # axis is still not supported for cupy.unique, this
    # is a workaround
    if len(array.shape) != 2:
        raise ValueError("Input array must be 2D.")
    sortarr     = array[cp.lexsort(array.T[::-1])]
    mask        = cp.empty(array.shape[0], dtype=cp.bool_)
    mask[0]     = True
    mask[1:]    = cp.any(sortarr[1:] != sortarr[:-1], axis=1)
    return sortarr[mask]

shapes = neighboring_pixels.shape
joined = neighboring_pixels.reshape(shapes[0]*shapes[1],2)
this_unique_pix = cupy_unique_axis0(joined)
this_unique_pix = this_unique_pix[(this_unique_pix[:,0] != -1) & (this_unique_pix[:,1] != -1),:]
```

```python
unique_pix = cp.concatenate((unique_pix, this_unique_pix),axis=0)
```

### Charge distribution calculation
Here we calculate the current induced by each track on the pixels, taking into account longitudinal and transverse diffusion. The track segment is parametrized as:
\begin{align}
x'(r') &=x_s + \frac{\Delta x}{\Delta r}r'\\
y'(r') &=y_s + \frac{\Delta y}{\Delta r}r'\\
z'(r') &=z_s + \frac{\Delta z}{\Delta r}r',
\end{align}
where $\Delta r$ is the segment length. Here we assume $z$ as the drift direction.
The diffused charge distribution is calculated with the following integral:
\begin{equation}
\rho(x,y,z) = \frac{Q}{\sqrt{(2\pi)^3}\sigma_x\sigma_y\sigma_z\Delta r}\exp\left[-\frac{(x-x_s)^2}{2\sigma_x^2}-\frac{(y-y_s)^2}{2\sigma_y^2}-\frac{(z-z_s)^2}{2\sigma_z^2}\right]\int^{r'=\Delta r}_{r'=0}dr'\exp[-(ar'^2+br')],
\end{equation}
where
\begin{align}
a &= \left[\left(\frac{\Delta x}{\Delta r}\right)^2\frac{1}{2\sigma_x^2} + \left(\frac{\Delta y}{\Delta r}\right)^2\frac{1}{2\sigma_y^2} + \left(\frac{\Delta z}{\Delta r}\right)^2\frac{1}{2\sigma_z^2} \right]\\
b &= -\left[\frac{(x-x_s)}{\sigma_x^2}\frac{\Delta x}{\Delta r}+
\frac{(y-y_s)}{\sigma_y^2}\frac{\Delta y}{\Delta r}+
\frac{(z-z_s)}{\sigma_z^2}\frac{\Delta z}{\Delta r}\right].
\end{align}

The simmetry of the transverse diffusion along the track allows to take a slice on the $xy$ plane and solve the integral once at a fixed $z$ coordinate (e.g. at $z_{m} = (z_s+z_e)/2$) and re-use it at other $z$ coordinates away from the endpoints (where $\rho(x,y,z)$ varies along $z$ so must be calculated at each $z$).

```python
max_length = cp.array([0])
track_starts = cp.empty(selected_tracks.shape[0])
threadsperblock = 128
blockspergrid = ceil(selected_tracks.shape[0] / threadsperblock)
detsim.time_intervals[blockspergrid,threadsperblock](track_starts, max_length,  event_id_map, selected_tracks)
```

```python
signals = cp.zeros((selected_tracks.shape[0],
                    neighboring_pixels.shape[1],
                    cp.asnumpy(max_length)[0]), dtype=np.float32)
threadsperblock = (1,1,64)
importlib.reload(detsim)
blockspergrid_x = ceil(signals.shape[0] / threadsperblock[0])
blockspergrid_y = ceil(signals.shape[1] / threadsperblock[1])
blockspergrid_z = ceil(signals.shape[2] / threadsperblock[2])
blockspergrid = (blockspergrid_x, blockspergrid_y, blockspergrid_z)
detsim.tracks_current[blockspergrid,threadsperblock](signals,
                                                     neighboring_pixels,
                                                     selected_tracks)
```

```python
pixel_index_map = cp.full((selected_tracks.shape[0], neighboring_pixels.shape[1]), -1)
try:
    compare = neighboring_pixels[..., np.newaxis, :] == unique_pix
    indices = cp.where(cp.logical_and(compare[..., 0], compare[..., 1]))
except cp.cuda.memory.OutOfMemoryError:
    print("out of memory")
pixel_index_map[indices[0], indices[1]] = indices[2]
```

```python
blockspergrid_x = ceil(signals.shape[0] / threadsperblock[0])
blockspergrid_y = ceil(signals.shape[1] / threadsperblock[1])
blockspergrid_z = ceil(signals.shape[2] / threadsperblock[2])
blockspergrid = (blockspergrid_x, blockspergrid_y, blockspergrid_z)
this_pixels_signals = cp.zeros((len(this_unique_pix), len(consts.time_ticks)*3))
pixels_signals = cp.concatenate((pixels_signals, this_pixels_signals), axis=0)
detsim.sum_pixel_signals[blockspergrid,threadsperblock](pixels_signals,
                                                        signals,
                                                        track_starts,
                                                        pixel_index_map)
currents = np.sum(pixels_signals,axis=1)*consts.t_sampling/consts.e_charge
```

```python
track = selected_tracks[0]
pixel_plane = track['pixel_plane']
z_anode = consts.tpc_borders[pixel_plane][2][0]
z = (track['z_start']+track['z_end'])/2
drift_distance = abs(z - z_anode)
drift_start = abs(min(track["z_start"],track["z_end"]) - z_anode)
drift_end = abs(max(track["z_start"],track["z_end"]) - z_anode)
drift_time = drift_distance / consts.vdrift
drift_start_time = drift_start / consts.vdrift
drift_end_time = drift_end / consts.vdrift
```

### 3D event display

```python
cmap = cm.Spectral_r
norm = colors.Normalize(vmin=0, vmax=256)
m = cm.ScalarMappable(norm=norm, cmap=cmap)

cmap = cm.viridis
norm_curr = colors.LogNorm(vmin=min(currents[currents>0]), vmax=max(currents))
m_curr = cm.ScalarMappable(norm=norm_curr, cmap=cmap)
fig = plt.figure(figsize=(7,7))
ax = fig.add_subplot(111, projection='3d')

for it,t in enumerate(selected_tracks):
    if it == 0:
        ax.plot((t["x_start"], t["x_end"]),
            (t["z_start"], t["z_end"]),
            (t["y_start"], t["y_end"]),
            c='r',
            lw=1,
            alpha=1,
            zorder=10,
            label='Geant4 detector segment')
    else:
        ax.plot((t["x_start"], t["x_end"]),
                (t["z_start"], t["z_end"]),
                (t["y_start"], t["y_end"]),
                c='r',
                lw=1,
                alpha=1,
                zorder=9999)

    ax.plot((t["x_start"], t["x_end"]),
            (consts.tpc_borders[t['pixel_plane']][2][0], consts.tpc_borders[t['pixel_plane']][2][0]),
            (t["y_start"], t["y_end"]),
            c='r',
            lw=1,
            ls=':',
            alpha=1,
            zorder=9999)

for ip, p in enumerate(unique_pix):
    x_rect, y_rect = detsim.get_pixel_coordinates(p.get())
    pixel_plane = int(p[0] // consts.n_pixels[0])
    row = int(pixel_plane // 4)
    column = int(pixel_plane % 4)
    if currents[ip] > 0:
        rect = plt.Rectangle((x_rect, y_rect),
                             consts.pixel_pitch, consts.pixel_pitch,
                             linewidth=0.1, fc=m_curr.to_rgba(currents[ip].get()),
                             edgecolor='gray')
        ax.add_patch(rect)
        art3d.pathpatch_2d_to_3d(rect, z=consts.tpc_borders[pixel_plane][2][0], zdir="y")

anode1 = plt.Rectangle((consts.tpc_borders[0][0][0], consts.tpc_borders[0][1][0]),
                        consts.tpc_borders[0][0][1]-consts.tpc_borders[0][0][0],
                        consts.tpc_borders[0][1][1]-consts.tpc_borders[0][1][0],
                       linewidth=1, fc='none',
                       edgecolor='gray', label=('Pixel' if ip == 5 else ''))
ax.add_patch(anode1)
art3d.pathpatch_2d_to_3d(anode1, z=consts.tpc_borders[0][2][0], zdir="y")

anode2 = plt.Rectangle((consts.tpc_borders[0][0][0], consts.tpc_borders[0][1][0]),
                        consts.tpc_borders[0][0][1]-consts.tpc_borders[0][0][0],
                        consts.tpc_borders[0][1][1]-consts.tpc_borders[0][1][0],
                       linewidth=1, fc='none',
                       edgecolor='gray', label=('Pixel' if ip == 5 else ''))
ax.add_patch(anode2)
art3d.pathpatch_2d_to_3d(anode2, z=consts.tpc_borders[1][2][0], zdir="y")

cathode = plt.Rectangle((consts.tpc_borders[0][0][0], consts.tpc_borders[0][1][0]),
                        consts.tpc_borders[0][0][1]-consts.tpc_borders[0][0][0],
                        consts.tpc_borders[0][1][1]-consts.tpc_borders[0][1][0],
                        linewidth=1, fc='gray', alpha=0.5,
                        edgecolor='gray', label=('Pixel' if ip == 5 else ''))
ax.add_patch(cathode)
art3d.pathpatch_2d_to_3d(cathode, z=0, zdir="y")

ax.plot((consts.tpc_borders[0][0][0],consts.tpc_borders[0][0][0]),(consts.tpc_borders[0][2][0],consts.tpc_borders[1][2][0]),
        (consts.tpc_borders[0][1][0],consts.tpc_borders[0][1][0]), lw=1,color='gray')

ax.plot((consts.tpc_borders[0][0][0],consts.tpc_borders[0][0][0]),(consts.tpc_borders[0][2][0],consts.tpc_borders[1][2][0]),
        (consts.tpc_borders[0][1][1],consts.tpc_borders[0][1][1]), lw=1,color='gray')

ax.plot((consts.tpc_borders[0][0][1],consts.tpc_borders[0][0][1]),(consts.tpc_borders[0][2][0],consts.tpc_borders[1][2][0]),
        (consts.tpc_borders[0][1][0],consts.tpc_borders[0][1][0]), lw=1,color='gray')

ax.plot((consts.tpc_borders[0][0][1],consts.tpc_borders[0][0][1]),(consts.tpc_borders[0][2][0],consts.tpc_borders[1][2][0]),
        (consts.tpc_borders[0][1][1],consts.tpc_borders[0][1][1]), lw=1,color='gray')

# ax.set_ylim(consts.module_borders[pixel_plane][2][0],50)
ax.set_xlim(consts.tpc_borders[0][0][0],consts.tpc_borders[1][0][1])
ax.set_ylim(consts.tpc_borders[0][2][0],consts.tpc_borders[1][2][0])
ax.set_zlim(consts.tpc_borders[0][1][0],consts.tpc_borders[1][1][1])

ax.set_box_aspect((2,2,4))
ax.grid(False)
ax.xaxis.set_major_locator(plt.MaxNLocator(3))
ax.yaxis.set_major_locator(plt.MaxNLocator(3))
# ax.set_axis_off()
ax.w_xaxis.set_pane_color((1.0, 1.0, 1.0, 1.0))
ax.w_yaxis.set_pane_color((1.0, 1.0, 1.0, 1.0))
ax.w_zaxis.set_pane_color((1.0, 1.0, 1.0, 1.0))

ax.view_init(azim=20)
# def rotate(angle):
#     ax.view_init(azim=angle)

# from matplotlib import animation

# rot_animation = animation.FuncAnimation(fig, rotate, frames=np.arange(0,362,2),interval=50)

ax.set_ylabel("z [cm]")
ax.set_xlabel("x [cm]")
ax.set_zlabel("y [cm]")
_ = plt.colorbar(m_curr,fraction=0.035, pad=0.05,label='Induced current integral [# electrons]')

```

```python
# rot_animation.save('animation.gif', writer='imagemagick', fps=10, bitrate=10, dpi=100)
```

### Electronics response and digitization
Here we simulate the electronics response (the self-triggering cycle) and the signal digitization.

```python
time_ticks = cp.linspace(0, len(unique_eventIDs)*consts.time_interval[1]*2, pixels_signals.shape[1]+1)
integral_list = cp.zeros((pixels_signals.shape[0], fee.MAX_ADC_VALUES))
adc_ticks_list = cp.zeros((pixels_signals.shape[0], fee.MAX_ADC_VALUES))
TPB = 128
BPG = ceil(pixels_signals.shape[0] / TPB)

rng_states = create_xoroshiro128p_states(TPB * BPG, seed=0)
fee.get_adc_values[BPG,TPB](pixels_signals,
                            time_ticks,
                            integral_list,
                            adc_ticks_list,
                            0,
                            rng_states)
adc_list = fee.digitize(integral_list)
```

### 2D event display with induced current and ADC counts

```python
fig,ax = plt.subplots(1,2,figsize=(6,3.8))
importlib.reload(detsim)
for ip, p in enumerate(unique_pix):
    x_rect, y_rect = detsim.get_pixel_coordinates(p.get())
    pixel_plane = int(p[0] // consts.n_pixels[0])
    c = currents[ip].get()
    if c >= 1:
        rect = plt.Rectangle((x_rect, y_rect),
                             consts.pixel_pitch, consts.pixel_pitch,
                             linewidth=0.2, fc=m_curr.to_rgba(c),
                             edgecolor='grey')
        ax[0].add_patch(rect)

    a = adc_list[ip][adc_list[ip]>fee.digitize(0)]
    if len(a):
        rect = plt.Rectangle((x_rect, y_rect),
                             consts.pixel_pitch, consts.pixel_pitch,
                             linewidth=0.2, fc=m.to_rgba(np.sum(a.get())),
                             edgecolor='grey')
        ax[1].add_patch(rect)

for it,t in enumerate(selected_tracks):
    ax[0].plot((t["x_start"], t["x_end"]),
            (t["y_start"], t["y_end"]),
            c='r',
            lw=1.25,
            ls=':',
            alpha=1,
            zorder=10)
    ax[1].plot((t["x_start"], t["x_end"]),
            (t["y_start"], t["y_end"]),
            c='r',
            lw=0,
            ls=':',
            alpha=1,
            zorder=10)
    ax[0].scatter((t["x_start"], t["x_end"]),
                  (t["y_start"], t["y_end"]),
                  c='r', s=1, zorder=99999)
#     ax[1].scatter((t["x_start"], t["x_end"]),
#                   (t["y_start"], t["y_end"]),
#                   c='r', s=1, zorder=99999)

ax[0].set_aspect("equal")
ax[1].set_aspect("equal")
ax[0].set_xlabel("x [cm]")
ax[1].set_xlabel("x [cm]")
ax[0].set_ylabel("y [cm]")
from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable

divider0 = make_axes_locatable(ax[1])
cax0 = divider0.append_axes("right", size="7%", pad=0.07)
fig.colorbar(m, ax=ax[1], cax=cax0, label='ADC counts sum')

divider1 = make_axes_locatable(ax[0])
cax1 = divider1.append_axes("right", size="7%", pad=0.07)
fig.colorbar(m_curr, ax=ax[0], cax=cax1, label='Induced current integral [# electrons]')

plt.subplots_adjust(hspace=0.5)
fig.savefig("currentadc.pdf")
```

### Export result
As a last step we backtrack the ADC counts to the Geant4 tracks and we export the result in a HDF5 file.

```python
MAX_TRACKS_PER_PIXEL = 5

# Mapping between unique pixel array and track array index
track_pixel_map = cp.full((unique_pix.shape[0], MAX_TRACKS_PER_PIXEL), -1)
TPB = 32
BPG = ceil(unique_pix.shape[0] / TPB)
detsim.get_track_pixel_map[BPG, TPB](track_pixel_map, unique_pix, neighboring_pixels)

# Here we backtrack the ADC counts to the Geant4 tracks
TPB = 128
BPG = ceil(adc_list.shape[0] / TPB)
backtracked_id = cp.full((adc_list.shape[0], adc_list.shape[1], MAX_TRACKS_PER_PIXEL), -1)

detsim.backtrack_adcs[BPG,TPB](selected_tracks,
                               adc_list,
                               adc_ticks_list,
                               track_pixel_map,
                               event_id_map,
                               unique_eventIDs,
                               backtracked_id,
                               0)
```

```python
!rm test.h5
pc = fee.export_to_hdf5(adc_list.get(),
                        adc_ticks_list.get(),
                        unique_pix.get(),
                        backtracked_id.get(),
                        "test.h5")
```

    Writing to HDF5...: 100%|██████████| 2170/2170 [00:00<00:00, 47540.31it/s]


```python
import numpy as np
import pandas as pd
import linearsolve as ls
import matplotlib.pyplot as plt
plt.style.use('classic')
%matplotlib inline
```

# Class 16: Introduction to New-Keynesian Business Cycle Modeling

In this notebook, we will briefly explore US macroeconomic data suggesting that, contrary to the assumptions of most RBC models, there is in fact a relationship between real and nominal quantities over the business cycle. Then we will use `linearsolve` to compute impulse responses of output, inflation, and the nominal interest rate to a monetary policy shock in the New-Keynesian model.

## Data

The file `business_cycle_data_actual_trend_cycle.csv`, available at https://github.com/letsgoexploring/econ126/raw/master/Data/Csv/business_cycle_data_actual_trend_cycle.csv, contains actual and trend data for real GDP per capita, real consumption per capita, real investment per capita, real physical capital per capita, TFP, hours per capita, the rea money supply (M2), (nominal) interest rate on 3-month T-bills, the PCE inflation rate, and the unemployment rate; each at quarterly frequency. The GDP, consumption, investment, capital, and money supply data are in terms of 2012 dollars. Hours is measured as an index with the value in October 2012 set to 100.

```python
# Read business_cycle_data_actual_trend.csv into a Pandas DataFrame with the first column set as the index and parse_dates=True
data = pd.read_csv('https://github.com/letsgoexploring/econ126/raw/master/Data/Csv/business_cycle_data_actual_trend_cycle.csv',index_col=0,parse_dates=True)

# Print the last five rows of the data
data.tail()
```

      gdp
      gdp_trend
      gdp_cycle
      consumption
      consumption_trend
      consumption_cycle
      investment
      investment_trend
      investment_cycle
      hours
      ...
      real_m2_cycle
      t_bill_3mo
      t_bill_3mo_trend
      t_bill_3mo_cycle
      pce_inflation
      pce_inflation_trend
      pce_inflation_cycle
      unemployment
      unemployment_trend
      unemployment_cycle

      2017-07-01
      70.962825
      70.917497
      0.000639
      48.396808
      48.310246
      0.001790
      12.367761
      12.448772
      -0.006529
      104.125352
      ...
      0.007122
      0.010367
      0.009948
      0.000418
      0.039232
      0.043418
      -0.004186
      0.043000
      0.042239
      0.000761

      2017-10-01
      71.202896
      71.165850
      0.000520
      48.753914
      48.505150
      0.005116
      12.355945
      12.525952
      -0.013665
      104.740753
      ...
      0.000068
      0.012067
      0.011122
      0.000944
      0.044406
      0.044005
      0.000401
      0.041333
      0.040523
      0.000811

      2018-01-01
      71.316755
      71.416054
      -0.001391
      48.679327
      48.700981
      -0.000445
      12.610681
      12.603944
      0.000534
      104.926059
      ...
      -0.009734
      0.015600
      0.012315
      0.003285
      0.042216
      0.044602
      -0.002385
      0.040667
      0.038815
      0.001851

      2018-04-01
      71.901724
      71.667788
      0.003259
      48.877348
      48.897710
      -0.000417
      12.608979
      12.682658
      -0.005826
      105.232911
      ...
      -0.016489
      0.018400
      0.013518
      0.004882
      0.047405
      0.045206
      0.002200
      0.039000
      0.037112
      0.001888

      2018-07-01
      72.326256
      71.920661
      0.005624
      49.191966
      49.095294
      0.001967
      12.991636
      12.762006
      0.017833
      105.431597
      ...
      -0.018270
      0.020400
      0.014725
      0.005675
      0.050457
      0.045812
      0.004645
      0.038000
      0.035411
      0.002589

5 rows × 30 columns

### Exercise: GDP and Inflation

Construct a plot of the cyclical components of GDP and inflation.

```python
# Construct plot
plt.plot(data['pce_inflation_cycle']*100,alpha=0.75,lw=3,label='Inflation')
plt.plot(data['gdp_cycle']*100,c='r',alpha=0.5,label='GDP')
plt.grid()
plt.ylabel='Percent'
plt.title('GDP and Inflation')

# Place legend to right of figure. PROVIDED
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
```

### Exercise: GDP and the 3-Month T-Bill Rate

Construct a plot of the cyclical components of GDP and the 3-month T-bill rate.

```python
# Construct plot
plt.plot(data['t_bill_3mo_cycle']*100,alpha=0.75,lw=3,label='Inflation')
plt.plot(data['gdp_cycle']*100,c='r',alpha=0.5,label='GDP')
plt.grid()
plt.ylabel='Percent'
plt.title('GDP and 3-Month T-Bill Rate')

# Place legend to right of figure. PROVIDED
plt.legend(loc='center left', bbox_to_anchor=(1, 0.5))
```

### Correlations Between GDP, Inflation, and 3-Month T-Bill Rate

Compute the coefficients of corrrelation between GDP, inflation, and the 3-month T-bill rate.

```python
data[['gdp_cycle','pce_inflation_cycle','t_bill_3mo_cycle']].corr()
```

      gdp_cycle
      pce_inflation_cycle
      t_bill_3mo_cycle

      gdp_cycle
      1.000000
      0.553864
      0.408099

      pce_inflation_cycle
      0.553864
      1.000000
      0.242530

      t_bill_3mo_cycle
      0.408099
      0.242530
      1.000000

Strong (but not perfect!) correlations between GDP and inflation and GDP and the T-bill rate suggest link between nominal and real quantities over the business cycle that should be exaplined by business cycle theory.

## The New-Keynesian Model

The most basic version of the New-Keynesian Model can be expressed as:

\begin{align}
y_t & = E_t y_{t+1}  - \left( r_{t} - \bar{r}\right) + g_t\\
i_{t} & = r_{t} + E_t \pi_{t+1}\\
i_{t} & = \bar{r} + \pi^T + \phi_{\pi}\big(\pi_t - \pi^T\big) + \phi_{y}\big(y_t - \bar{y}\big) + v_t\\
\pi_t -\pi^T & = \beta \left( E_t\pi_{t+1} - \pi^T\right)  + \kappa (y_t -\bar{y})+ u_t,
\end{align}

where: $y_t$ is (log) output, $r_t$ is the real interest rate, $i_t$ is the nominal interest rate, $\pi_t$ is the rate of inflation between periods $t-1$ and $t$, $\bar{r}$ is the long-run average real interest rate or the *natural rate of interest*, $\beta$ is the household's subjective discount factor, and $\pi^T$ is the central bank's inflation target. The coeffieints $\phi_{\pi}$ and $\phi_{y}$ reflect the degree of intensity to which the central bank *endogenously* adjusts the nominal interest rate in response to movements in inflation and output.

The variables $g_t$, $u_t$, and $v_t$ represent exogenous shocks to aggregate demand, inflation, and monetary policy. They follow AR(1) processes:

\begin{align}
g_{t+1} & = \rho_g g_{t} + \epsilon^g_{t+1}\\
u_{t+1} & = \rho_u u_{t} + \epsilon^u_{t+1}\\
v_{t+1} & = \rho_v v_{t} + \epsilon^v_{t+1}.
\end{align}

The goal is to compute impulse responses in the model to a one percent exogenous increase in the nominal interest rate. We will use the following parameterization:

| $\bar{y}$ | $\beta$ | $\bar{r}$    | $\kappa$ | $\pi^T$ | $\phi_{\pi}$ | $\phi_y$ | $\rho_g$ | $\rho_u$ | $\rho_v$ |
|-----------|---------|--------------|----------|---------|--------------|----------|----------|----------|---------|
| 0         | 0.995    | $-\log\beta$ | 0.1      | 0.02/4    | 1.5          | 0.5/4    | 0.5      | 0.5      | 0.5     |

```python
# Create a variable called 'parameters' that stores the model parameter values in a Pandas Series
parameters = pd.Series()
parameters['y_bar'] = 0
parameters['beta'] = 0.995
parameters['r_bar'] = -np.log(parameters.beta)
parameters['kappa'] = 0.1
parameters['pi_T'] = 0.02/4
parameters['phi_pi'] = 1.5
parameters['phi_y'] = 0.5/4
parameters['rho_g'] = 0.5
parameters['rho_u'] = 0.5
parameters['rho_v'] = 0.5

# Print the model's parameters
print(parameters)
```

    y_bar     0.000000
    beta      0.995000
    r_bar     0.005013
    kappa     0.100000
    pi_T      0.005000
    phi_pi    1.500000
    phi_y     0.125000
    rho_g     0.500000
    rho_u     0.500000
    rho_v     0.500000
    dtype: float64

```python
# Create variable called 'varNames' that stores the variable names in a list with state variables ordered first
varNames = ['g','u','v','y','pi','i','r']

# Create variable called 'shockNames' that stores an exogenous shock name for each state variable.
shockNames = ['e_g','e_u','e_v']

# Define a function that evaluates the equilibrium conditions of the model solved for zero. PROVIDED
def equilibrium_equations(variables_forward,variables_current,parameters):

    # Parameters. PROVIDED
    p = parameters

    # Current variables. PROVIDED
    cur = variables_current

    # Forward variables. PROVIDED
    fwd = variables_forward

    # IS equation
    is_equation = fwd.y - (cur.r -p.r_bar) + cur.g - cur.y

    # Fisher_equation
    fisher_equation = cur.r + fwd.pi - cur.i

    # Monetary policy
    monetary_policy = p.r_bar + p.pi_T + p.phi_pi*(cur.pi - p.pi_T) + p.phi_y*cur.y + cur.v - cur.i

    # Phillips curve
    phillips_curve = p.beta*(fwd.pi- p.pi_T) + p.kappa*cur.y + cur.u - (cur.pi-p.pi_T)

    # Demand process
    demand_process = p.rho_g*cur.g - fwd.g

    # Monetary policy process
    monetary_policy_process = p.rho_v*cur.v - fwd.v

    # Inflation process
    inflation_process = p.rho_u*cur.u - fwd.u

    # Stack equilibrium conditions into a numpy array
    return np.array([
            is_equation,
            fisher_equation,
            monetary_policy,
            phillips_curve,
            demand_process,
            monetary_policy_process,
            inflation_process
        ])

# Initialize the model into a variable named 'nk_model'
nk_model = ls.model(equations = equilibrium_equations,
                 nstates=3,
                 varNames=varNames,
                 shockNames=shockNames,
                 parameters = parameters)
```

```python
# Compute the steady state numerically using .compute_ss() method of nk_model
guess = [0,0,0,0,0.01,0.01,0.01]
nk_model.compute_ss(guess)

# Print the computed steady state
print(nk_model.ss)
```

    g     1.832559e-36
    u     3.518101e-35
    v     4.196417e-36
    y    -3.184980e-20
    pi    5.000000e-03
    i     1.001254e-02
    r     5.012542e-03
    dtype: float64

```python
# Find the log-linear approximation around the non-stochastic steady state and solve using .approximate_and_solve() method of nk_model
# set argumement 'loglinear' to False
nk_model.approximate_and_solve(loglinear=False)

print(nk_model.approximated())
```

    Linear equilibrium conditions:

           y[t+1|t] = -g[t]+y[t]+r[t]

          pi[t+1|t] = i[t]-r[t]

                  0 = -v[t]-0.125·y[t]-1.5·pi[t]+i[t]

    0.995·pi[t+1|t] = -u[t]-0.1·y[t]+pi[t]

            -g[t+1] = -0.5·g[t]

            -v[t+1] = -0.5·v[t]

            -u[t+1] = -0.5·u[t]

### Impulse Responses

Compute a 21 period impulse response of the model's variables to a 0.01/4 unit shock to the exogenous component of  monetary policy ($v_t$) in period 5.

```python
# Compute impulse responses
nk_model.impulse(T=21,t0=5,shocks=[0,0,0.01/4])

# Print the first 10 rows of the computed impulse responses to the monetary policy shock
print(nk_model.irs['e_v'].head(10))
```

          e_v             g    u         v         y        pi         i         r
    0  0.0000  0.000000e+00  0.0  0.000000  0.000000  0.000000  0.000000  0.000000
    1  0.0000  0.000000e+00  0.0  0.000000  0.000000  0.000000  0.000000  0.000000
    2  0.0000  0.000000e+00  0.0  0.000000  0.000000  0.000000  0.000000  0.000000
    3  0.0000  0.000000e+00  0.0  0.000000  0.000000  0.000000  0.000000  0.000000
    4  0.0000  0.000000e+00  0.0  0.000000  0.000000  0.000000  0.000000  0.000000
    5  0.0025  0.000000e+00  0.0  0.002500 -0.003034 -0.000604  0.001215  0.001517
    6  0.0000 -3.469447e-19  0.0  0.001250 -0.001517 -0.000302  0.000608  0.000758
    7  0.0000 -3.469447e-19  0.0  0.000625 -0.000758 -0.000151  0.000304  0.000379
    8  0.0000 -2.602085e-19  0.0  0.000313 -0.000379 -0.000075  0.000152  0.000190
    9  0.0000 -1.734723e-19  0.0  0.000156 -0.000190 -0.000038  0.000076  0.000095

Plot the computed impulses responses of the nominal interest rate, the real interest rate, output, and inflation. Express inflation and interest rates in *annualized* (e.g., multiplied by 4) terms.

```python
# Create figure. PROVIDED
fig = plt.figure(figsize=(12,8))

# Create upper-left axis. PROVIDED
ax1 = fig.add_subplot(2,2,1)
(nk_model.irs['e_v']['i']*400).plot(ax=ax1,lw=3,alpha=0.75,title='Nominal Interest',grid=True)
ax1.set_ylabel('% dev from steady state')

# Create upper-right axis. PROVIDED
ax2 = fig.add_subplot(2,2,2)
(nk_model.irs['e_v']['r']*400).plot(ax=ax2,lw=3,alpha=0.75,title='Real Interest',grid=True)
ax2.set_ylabel('% dev from steady state')

# Create lower-left axis. PROVIDED
ax3 = fig.add_subplot(2,2,3)
(nk_model.irs['e_v']['y']*100).plot(ax=ax3,lw=3,alpha=0.75,title='Output',grid=True)
ax3.set_ylabel('% dev from steady state')

# Create lower-right axis. PROVIDED
ax4 = fig.add_subplot(2,2,4)
(nk_model.irs['e_v']['pi']*400).plot(ax=ax4,lw=3,alpha=0.75,title='Inflation',grid=True)
ax4.set_ylabel('% dev from steady state')

ax1.set_ylim([-0.2,0.8])
ax2.set_ylim([-0.2,0.8])
ax3.set_ylim([-0.4,0.1])
ax4.set_ylim([-0.4,0.1])

fig.tight_layout()
```


### Постановка задачи
Загрузим подготовленные данные по энергопотреблению первых 20 зданий (building_id от 0 до 19).

Соберем два набора моделей: по дате (праздники, дни недели и т.д.) и по погоде.

Проведем 10 разбиений данных на обучающие/проверочные и выявим оптимальные веса моделей для каждого часа для каждого здания.

Вычислим оптимизированную метрику качества для ансамбля моделей.

* http://video.ittensive.com/machine-learning/ashrae/building_metadata.csv.gz
* http://video.ittensive.com/machine-learning/ashrae/weather_train.csv.gz
* http://video.ittensive.com/machine-learning/ashrae/train.0.csv.gz
Соревнование: https://www.kaggle.com/c/ashrae-energy-prediction/

© ITtensive, 2020

```python
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
```

```python
energy = pd.read_csv("energy.0-20.ready.csv.gz")
```

```python
energy.info()
```

    <class 'pandas.core.frame.DataFrame'>
    RangeIndex: 175680 entries, 0 to 175679
    Data columns (total 92 columns):
     #   Column                 Non-Null Count   Dtype
    ---  ------                 --------------   -----
     0   timestamp              175680 non-null  object
     1   building_id            175680 non-null  int64
     2   meter_reading          175680 non-null  float64
     3   primary_use            175680 non-null  object
     4   air_temperature        175680 non-null  float64
     5   cloud_coverage         175680 non-null  float64
     6   dew_temperature        175680 non-null  float64
     7   precip_depth_1_hr      175680 non-null  float64
     8   sea_level_pressure     175680 non-null  float64
     9   wind_direction         175680 non-null  float64
     10  wind_speed             175680 non-null  float64
     11  air_temperature_diff1  175680 non-null  float64
     12  air_temperature_diff2  175680 non-null  float64
     13  hour                   175680 non-null  int64
     14  weekday                175680 non-null  int64
     15  week                   175680 non-null  int64
     16  month                  175680 non-null  int64
     17  date                   175680 non-null  object
     18  is_holiday             175680 non-null  int64
     19  is_wday0               175680 non-null  int64
     20  is_wday1               175680 non-null  int64
     21  is_wday2               175680 non-null  int64
     22  is_wday3               175680 non-null  int64
     23  is_wday4               175680 non-null  int64
     24  is_wday5               175680 non-null  int64
     25  is_wday6               175680 non-null  int64
     26  is_w1                  175680 non-null  int64
     27  is_w2                  175680 non-null  int64
     28  is_w3                  175680 non-null  int64
     29  is_w4                  175680 non-null  int64
     30  is_w5                  175680 non-null  int64
     31  is_w6                  175680 non-null  int64
     32  is_w7                  175680 non-null  int64
     33  is_w8                  175680 non-null  int64
     34  is_w9                  175680 non-null  int64
     35  is_w10                 175680 non-null  int64
     36  is_w11                 175680 non-null  int64
     37  is_w12                 175680 non-null  int64
     38  is_w13                 175680 non-null  int64
     39  is_w14                 175680 non-null  int64
     40  is_w15                 175680 non-null  int64
     41  is_w16                 175680 non-null  int64
     42  is_w17                 175680 non-null  int64
     43  is_w18                 175680 non-null  int64
     44  is_w19                 175680 non-null  int64
     45  is_w20                 175680 non-null  int64
     46  is_w21                 175680 non-null  int64
     47  is_w22                 175680 non-null  int64
     48  is_w23                 175680 non-null  int64
     49  is_w24                 175680 non-null  int64
     50  is_w25                 175680 non-null  int64
     51  is_w26                 175680 non-null  int64
     52  is_w27                 175680 non-null  int64
     53  is_w28                 175680 non-null  int64
     54  is_w29                 175680 non-null  int64
     55  is_w30                 175680 non-null  int64
     56  is_w31                 175680 non-null  int64
     57  is_w32                 175680 non-null  int64
     58  is_w33                 175680 non-null  int64
     59  is_w34                 175680 non-null  int64
     60  is_w35                 175680 non-null  int64
     61  is_w36                 175680 non-null  int64
     62  is_w37                 175680 non-null  int64
     63  is_w38                 175680 non-null  int64
     64  is_w39                 175680 non-null  int64
     65  is_w40                 175680 non-null  int64
     66  is_w41                 175680 non-null  int64
     67  is_w42                 175680 non-null  int64
     68  is_w43                 175680 non-null  int64
     69  is_w44                 175680 non-null  int64
     70  is_w45                 175680 non-null  int64
     71  is_w46                 175680 non-null  int64
     72  is_w47                 175680 non-null  int64
     73  is_w48                 175680 non-null  int64
     74  is_w49                 175680 non-null  int64
     75  is_w50                 175680 non-null  int64
     76  is_w51                 175680 non-null  int64
     77  is_w52                 175680 non-null  int64
     78  is_w53                 175680 non-null  int64
     79  is_m1                  175680 non-null  int64
     80  is_m2                  175680 non-null  int64
     81  is_m3                  175680 non-null  int64
     82  is_m4                  175680 non-null  int64
     83  is_m5                  175680 non-null  int64
     84  is_m6                  175680 non-null  int64
     85  is_m7                  175680 non-null  int64
     86  is_m8                  175680 non-null  int64
     87  is_m9                  175680 non-null  int64
     88  is_m10                 175680 non-null  int64
     89  is_m11                 175680 non-null  int64
     90  is_m12                 175680 non-null  int64
     91  meter_reading_log      175680 non-null  float64
    dtypes: float64(11), int64(78), object(3)
    memory usage: 123.3+ MB

```python
lr_weather_colums = ['meter_reading_log','hour','building_id','air_temperature','dew_temperature',
                     'sea_level_pressure','wind_speed','air_temperature_diff1','air_temperature_diff2','cloud_coverage']

lr_days_columns = ['meter_reading_log','hour','building_id','is_holiday']
for wday in range(0,7):
    lr_days_columns.append('is_wday' + str(wday))
for week in range(1,54):
    lr_days_columns.append('is_w' + str(week))
for month in range(1,13):
    lr_days_columns.append('is_m' + str(month))
```

```python
hours = range(0,24)
buildings = range(0,energy['building_id'].max() + 1)
```

```python
def calculate_model(x,df_lr,lr_columns):
    lr = -1
    model = df_lr[x.building_id][x.hour]
    if len(model) > 0:
        lr = np.sum([x[c] * model[i] for i,c in enumerate(lr_columns[3:])])
        lr += model[len(lr_columns) - 3]
        lr = np.exp(lr)
    if lr < 0 or lr * lr == lr:
        lr = 0
    x['meter_reading_lr_q'] = (np.log(x.meter_reading + 1) - np.log(1 + lr)) ** 2
    return x
```

```python
def train_model(df,columns):
    df_train_lr = pd.DataFrame(df,columns=columns)
    df_lr = [[]] * len(buildings)
    for building in buildings:
        df_lr[building] = [[]] * len(hours)
        df_train_b = df_train_lr[df_train_lr['building_id'] == building]
        for hour in hours:
            df_train_bh = df_train_b[df_train_b['hour'] == hour]
            y = df_train_bh['meter_reading_log']
            x = df_train_bh.drop(['meter_reading_log','hour','building_id'],axis=1)
            model = LinearRegression(fit_intercept=False).fit(x,y)
            df_lr[building][hour] = model.coef_
            df_lr[building][hour] = np.append(df_lr[building][hour],model.intercept_)
    return df_lr

def calculate_weights_model(df_test,df_train,lr_columns):
    df_test = df_test.apply(calculate_model,axis=1,result_type='expand',
                           df_lr=train_model(df_train,lr_columns),
                           lr_columns=lr_columns)
    return pd.Series(df_test.groupby(['hour','building_id']).sum()['meter_reading_lr_q'])
def calculate_weights():
    df_train,df_test = train_test_split(energy[energy['meter_reading'] > 0],test_size=0.2)
    return (calculate_weights_model(df_test,df_train,lr_weather_colums),
           calculate_weights_model(df_test,df_train,lr_days_columns))
```

```python
weights_weather = []
weights_days = []
for i in range(0,10):
    print(i)
    weights_weather_model,weights_days_model = calculate_weights()
    if len(weights_weather) > 0:
        weights_weather += weights_weather_model
    else:
        weights_weather = weights_weather_model
    if len(weights_days) > 0:
        weights_days += weights_days_model
    else:
        weights_days = weights_days_model

weights = [0] * len(buildings)
for b in buildings:

    weights[b] = [0] * len(hours)
    for h in hours:
        if weights_weather.loc[h].at[b] > weights_days.loc[h].at[b]:
            weights[b][h] = 1
print(weights)
```

    0

    <ipython-input-14-f7b5083fc8a3>:7: RuntimeWarning: overflow encountered in exp
      lr = np.exp(lr)

    1

    <ipython-input-14-f7b5083fc8a3>:7: RuntimeWarning: overflow encountered in exp
      lr = np.exp(lr)

    2

    <ipython-input-14-f7b5083fc8a3>:7: RuntimeWarning: overflow encountered in exp
      lr = np.exp(lr)

    3

    <ipython-input-14-f7b5083fc8a3>:7: RuntimeWarning: overflow encountered in exp
      lr = np.exp(lr)

    4

    <ipython-input-14-f7b5083fc8a3>:7: RuntimeWarning: overflow encountered in exp
      lr = np.exp(lr)

    5

    <ipython-input-14-f7b5083fc8a3>:7: RuntimeWarning: overflow encountered in exp
      lr = np.exp(lr)

    6

    <ipython-input-14-f7b5083fc8a3>:7: RuntimeWarning: overflow encountered in exp
      lr = np.exp(lr)

    7

    <ipython-input-14-f7b5083fc8a3>:7: RuntimeWarning: overflow encountered in exp
      lr = np.exp(lr)

    8

    <ipython-input-14-f7b5083fc8a3>:7: RuntimeWarning: overflow encountered in exp
      lr = np.exp(lr)

    9

    <ipython-input-14-f7b5083fc8a3>:7: RuntimeWarning: overflow encountered in exp
      lr = np.exp(lr)

    [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

```python
from sklearn.model_selection import train_test_split
```

```python
energy_train,energy_test = train_test_split(energy[energy['meter_reading'] > 0], test_size=0.2)
```

```python
energy_lr_days = train_model(energy_train,lr_days_columns)
energy_lr_weather = train_model(energy_train,lr_weather_colums)
```

```python
def calculate_model_ensemble(x,model,columns):
    lr = -1
    if len(model) > 0:
        lr = np.sum([x[c] * model[i] for i,c in enumerate(columns[3:])])
        lr += model[len(columns) - 3]
        lr = np.exp(lr)
    if lr < 0 or lr*lr == lr:
        lr = 0
    return lr
def calculate_models_ensemble(x):
    lr_d = calculate_model_ensemble(x,energy_lr_days[x.building_id][x.hour],lr_days_columns)
    lr_w = calculate_model_ensemble(x,energy_lr_days[x.building_id][x.hour],lr_weather_colums)
    if weights[x.building_id][x.hour] == 1:
        lr = lr_d
    else:
        lr = lr_w
    lr_sum = (lr_w + lr_d) / 2
    x['meter_reading_lr_q'] = (np.log(x.meter_reading + 1) + np.log(1 + lr)) ** 2
    x['meter_reading_sum_q'] = (np.log(x.meter_reading + 1) + np.log(1 + lr_sum)) ** 2
    return x
```

В теории, в идеальном случае, ансамбль линейной регрессии не должен давать никакого преимущества, потому что если
\begin{equation}
z_1 = Ax + By + C, z_2 = Ds + Et + F, то
\end{equation}
\begin{equation}
z = \alpha z_1 + \beta z_2 = \alpha Ax + \alpha By + \alpha C + \beta Ds + \beta Et + \beta F = A_1x + B_1y + D_1s + E_1t + F_1
\end{equation}
И по сути ансамбль линейной регрессии - это просто линейная регрессия по всем переменным. Но при использовании небольших наборов (чтобы исключить переобучение) связанных переменных для разных моделей регрессии можно получить небольшой выигрыш.

Ансамбль регрессии в нашем случае не дает никакого улучшения относительно регрессии по совокупному набору параметров.

Однако, использование усредненной суммы показателей каждой конкретной модели дало выигрыш порядка 6% относительно модели по всем показателям. В этом случае сумму моделей линейной регрессии "компенсирует" ошибки каждой конкретной модели и работает точнее.

```python
energy_test = energy_test.apply(calculate_models_ensemble,axis=1,result_type='expand')

print(np.sqrt(energy_test['meter_reading_lr_q'].sum() / len(energy_test)))
print(np.sqrt(energy_test['meter_reading_sum_q'].sum() / len(energy_test)))
```

    <ipython-input-27-f183ec8eab26>:6: RuntimeWarning: overflow encountered in exp
      lr = np.exp(lr)

    5.8755614566891925
    10.815833230914512

```python

```