# Models and Pricing of Financial Derivatives HW_03

**11510691 程远星$\DeclareMathOperator*{\argmin}{argmin}
\DeclareMathOperator*{\argmax}{argmax}
\DeclareMathOperator*{\plim}{plim}
\newcommand{\using}[1]{\stackrel{\mathrm{#1}}{=}}
\newcommand{\ffrac}{\displaystyle \frac}
\newcommand{\asim}{\overset{\text{a}}{\sim}}
\newcommand{\space}{\text{ }}
\newcommand{\bspace}{\;\;\;\;}
\newcommand{\QQQ}{\boxed{?\:}}
\newcommand{\void}{\left.\right.}
\newcommand{\Tran}[1]{{#1}^{\mathrm{T}}}
\newcommand{\d}[1]{\displaystyle{#1}}
\newcommand{\CB}[1]{\left\{ #1 \right\}}
\newcommand{\SB}[1]{\left[ #1 \right]}
\newcommand{\P}[1]{\left( #1 \right)}
\newcommand{\abs}[1]{\left| #1 \right|}
\newcommand{\norm}[1]{\left\| #1 \right\|}
\newcommand{\dd}{\mathrm{d}}
\newcommand{\Exp}{\mathrm{E}}
\newcommand{\RR}{\mathbb{R}}
\newcommand{\EE}{\mathbb{E}}
\newcommand{\II}{\mathbb{I}}
\newcommand{\NN}{\mathbb{N}}
\newcommand{\ZZ}{\mathbb{Z}}
\newcommand{\QQ}{\mathbb{Q}}
\newcommand{\PP}{\mathbb{P}}
\newcommand{\AcA}{\mathcal{A}}
\newcommand{\FcF}{\mathcal{F}}
\newcommand{\AsA}{\mathscr{A}}
\newcommand{\FsF}{\mathscr{F}}
\newcommand{\Var}[2][\,\!]{\mathrm{Var}_{#1}\left[#2\right]}
\newcommand{\Avar}[2][\,\!]{\mathrm{Avar}_{#1}\left[#2\right]}
\newcommand{\Cov}[2][\,\!]{\mathrm{Cov}_{#1}\left(#2\right)}
\newcommand{\Corr}[2][\,\!]{\mathrm{Corr}_{#1}\left(#2\right)}
\newcommand{\I}[1]{\mathrm{I}\left( #1 \right)}
\newcommand{\N}[1]{\mathcal{N} \left( #1 \right)}
\newcommand{\ow}{\text{otherwise}}
\newcommand{\FSD}{\text{FSD}}
\void^\dagger$**

## Question 1

If $S_t$ follows the *geometric Brownian motion* process as given by $\ffrac{\dd S_t}{S_t}= \mu\dd t + \sigma\dd z$, what is the process followed by

$\P{1}$ $y = 2S_t$

$\bspace Answer$

>$\begin{align}
\dd y &= \dd\P{2S_t}\\
&= \P{0 + \P{\mu S_t}\cdot 2 + \ffrac{1}{2}\P{\sigma S_t}^2  \cdot 0}\dd t + \sigma S_t \cdot 2 \dd z\\
&= 2\mu S_t \dd t + 2\sigma S_t \dd z\\
&= \mu y \dd t + \sigma y\dd z
\end{align}$

$\P{2}$ $y = S_t^2$

$\bspace Answer$

>$\begin{align}
\dd y &= \dd\P{S_t^2}\\
&= \P{0 + \P{\mu S_t}\cdot 2S_t + \ffrac{1}{2}\P{\sigma S_t}^2  \cdot 2}\dd t + \P{\sigma S_t} \cdot 2S_t \dd z\\
&= \P{2\mu S_t^2 + \sigma^2 S_t^2}\dd t + 2\sigma S_t^2 \dd z\\
&= \P{2\mu + \sigma^2}y\dd t + 2\sigma y \dd z
\end{align}$

$\P{3}$ $y=e^{S_t}$

$\bspace Answer$

>$\begin{align}
\dd y &= \dd\P{e^{S_t}}\\
&= \P{0 + \P{\mu S_t}\cdot e^{S_t} + \ffrac{1}{2}\P{\sigma S_t}^2  \cdot e^{S_t}}\dd t + \P{\sigma S_t} \cdot e^{S_t} \dd z\\
&= \P{\mu \log y + \ffrac{1}{2} \P{\sigma \log y}^2}y\dd t + \P{\sigma \log y} \cdot y\dd t
\end{align}$

$\P{4}$ $y = e^{r\P{T-t}}/S_t$

$\bspace Answer$

>$\begin{align}
\dd y &= \dd\P{\ffrac{e^{r\P{T-t}}}{S_t}}\\
&= \P{\ffrac{-re^{r\P{T-t}}}{S_t} + \P{\mu S_t}\cdot \P{-\ffrac{e^{r\P{T-t}}}{S_t^2}} + \ffrac{1}{2}\P{\sigma S_t}^2  \cdot \ffrac{2e^{r\P{T-t}}}{S_t^3}}\dd t + \P{\sigma S_t} \cdot \P{-\ffrac{e^{r\P{T-t}}}{S_t^2}} \dd z\\
&= \P{-r-\mu-\sigma^2}y\dd t - \sigma y \dd y
\end{align}$

$Remark$

>We don't need to prove Itô's formula here. Just in case, given $\dd X_t = \mu\P{t,X_t}\dd t + \sigma\P{t,X_t} \dd W_t $ it looks like
>
>$$\dd f\P{t,X_t} = \P{\ffrac{\partial f}{\partial t} + \mu\P{t,X_t}\ffrac{\partial f}{\partial X_t} + \ffrac{1}{2}\sigma^2\P{t,X_t}\ffrac{\partial^2 f}{\partial X_t^2}}\dd t + \sigma\P{t,X_t}\ffrac{\partial f}{\partial X_t} \dd W_t$$
>
>Or $\dd f\P{t,X_t} = \ffrac{\partial f}{\partial t} \dd t + \ffrac{\partial f}{\partial X_t} \dd X_t + \ffrac{1}{2}\ffrac{\partial^2 f}{\partial X_t^2}\P{\dd X_t}^2$ where $\P{\dd t}^2 = 0$, $\dd t \cdot \dd W_t =0$ and $\P{\dd W_t}^2 = \dd t$.

## Question 2

Suppose that $W_t$ and $\widetilde W_t$ are *independent Browanian motions* under the measure $\PP$ and let $\rho\in\SB{ − 1, 1}$ be a *constant*. Is the process $X_t = \rho W_t + \sqrt{1-\rho^2}\widetilde W_t$ a Brownian motion?

$\bspace Answer$

>It is a Brownian motion, the four conditions are checked correct below. We first let the drift and volatility of $W_t$ and $\widetilde W_t$ be $\mu,\sigma$ and $\check\mu,\check\sigma$, respectively. Denote $\widehat W_t$ as the standard Brownian motion, then $\forall\; t>s$, we have
>
>$$\begin{align}
X_t - X_s  &= \rho\P{W_t - W_s} + \sqrt{1-\rho^2}\P{\widetilde W_t - \widetilde W_s} \\
&= \rho\P{\mu \P{t-s} + \sigma \P{\widehat W_t-\widehat W_s}} + \sqrt{1-\rho^2}\P{\check\mu \P{t-s} + \check\sigma \P{\widehat W_t - \widehat W_s}}\\
&= \P{\rho \mu + \sqrt{1-\rho^2}\check \mu}\P{t-s} + \P{\rho\sigma + \sqrt{1-\rho^2}\check\sigma}\P{\widehat W_t - \widehat W_s}
\end{align}$$
>
>- Let $\rho \mu + \sqrt{1-\rho^2}\check \mu \equiv \dot \mu$ and $\rho\sigma + \sqrt{1-\rho^2}\check\sigma\equiv\dot\sigma$, then
>
>$$X_t - X_s = \dot\rho\P{t-s} + \dot\sigma\P{\hat W_t-\hat W_s} \sim \N{\dot\rho\P{t-s},\dot\sigma^2 \P{t-s}},\bspace\forall\; t>s$$
>
>- Consider $t$ and $s$ as two adjacent time in the interval $\SB{0,T}$. Then since $\widehat W_t$ has independent increments, so is $X_t - X_s$, judging from its expression.
>- $X_0 = \dot\rho t + \dot\sigma \widehat W_t \mid_{t=0} = \widehat W_0 = 0$
>- Still, from the expression of $X_t$, $t$ is continuous and the path $\SB{W_t:t\geq 0}$ and $\SB{\widetilde W_t:t\geq 0}$ are also continuous functions, $X_t$ is continuous.

## Question 3

Let $\CB{W_t}_{t \geq 0}$ be *standard Brownian motion* under the measure $\PP$. Which of the following are $\PP$-Brownian motions?

$\P{1}$ $\CB{-W_t}_{t \geq 0}$

$\bspace Answer$

>It is a $\PP$-Brownian motion.
>
>- $\forall\; t>s$, the increment $\P{-W_t} - \P{-W_s} = W_s - W_t$ also has the normal distribution $\N{0,t-s}$

>- The process $-W_t$ has independent increments: for any set of times $0\leq t_1<t_2<\cdots<t_n$, the $r.v.$ $-W_{t_{\void_2}} + W_{t_{\void_1}}$, $-W_{t_{\void_3}} + W_{t_{\void_2}}$, $\dots$, $-W_{t_{\void_{n}}} + W_{t_{\void_{n-1}}}$ are also independent, since their inverse are.
- $-W_0 = 0$
- The sample paths: $\SB{-W_t: t \geq 0}$ are continuous function of $t$ since $\SB{W_t: t \geq 0}$ are.

$\P{2}$ $\CB{cW_{t/c^2}}_{t \geq 0}$, where $c$ is a constant

$\bspace Answer$

>It is a $\PP$-Brownian motion.
>
>- $\forall\; t>s$, the increment $c\P{W_{t/c^{\void_2}}} - c\P{W_{s/c^{\void_2}}}$ also has the normal distribution $\N{0,c^2\P{t/c^2 - s/c^2}} = \N{0,t-s}$
- The process $cW_{t/c^{\void_2}}$ has independent increments: for any set of times $0\leq t_1<t_2<\cdots<t_n$, the $r.v.$ $-W_{t_{\void_2}} + W_{t_{\void_1}}$, $-W_{t_{\void_3}} + W_{t_{\void_2}}$, $\dots$, $-W_{t_{\void_{n}}} + W_{t_{\void_{n-1}}}$ are also independent, since they are a subset of  $r.v.$ with time range from $0$ to $c^2 t_n$
- $cW_{0/c^{\void_2}} = cW_0 = 0$
- The sample paths: $\SB{-W_{t/c^{\void_2}}: t \geq 0}$ are continuous function of $t$ since $\SB{W_t: t \geq 0}$ are, so that we can multiply a constant and rescale the time axis to its $1/c^2$ while keeping the continuity

$\P{3}$ $\CB{\sqrt{t}W_{1}}_{t \geq 0}$

$\bspace Answer$

>It's not. We next prove this process doesn't have the independent increments. Here's the covariance if taking the time $0$, $s$, and $t$.
>
>$$\begin{align}
&\Cov{\sqrt{t} W_1 - \sqrt s W_1, \sqrt s W_1}\\
=&\; \P{\sqrt t - \sqrt s}\sqrt s \cdot \Var{W_1}\\
=&\; \P{\sqrt t - \sqrt s}\sqrt s \neq 0
\end{align}$$

$\P{4}$ $\CB{W_{2t}-W_t}_{t \geq 0}$

$\bspace Answer$

>It's not. Still, let's see the covariance, taking the time $0$, $2s$ and $2t$.
>
>$$\begin{align}
   &\Cov{\P{W_{2t} - W_t}-\P{W_{2s} - W_s}, W_{2s} - W_s}\\
=\;&\Cov{\P{W_{2t} - W_{2s}}-\P{W_t - W_s}, W_{2s} - W_s}\\
=\;&\Cov{W_{2t} - W_{2s},W_{2s}} + \Cov{\P{W_t - W_s}, W_s}\\
\;&\bspace - \Cov{W_{2t} - W_{2s},W_{s}} - \Cov{\P{W_t - W_s},W_{2s}}\\
=\;& 0+2\Cov{W_{2s},W_s} - \Cov{W_{2t},W_s} - \Cov{W_{t},W_{2s}}\\
=\;& 0+2\Cov{W_{2s} - W_s,W_s}+2\Cov{W_s,W_s} - \Cov{W_{2t}-W_s,W_s} + \Cov{W_s,W_s} - \Cov{W_{t},W_{2s}}\\
=\;& \Var{W_s} - \Cov{W_{t},W_{2s}} = s - \Cov{W_{t},W_{2s}}
\end{align}$$
>
>If $t > 2s$, then the preceding equals to $s - \Var{W_{2s}} = -s \neq 0$.

## Question 4

Suppose that $X$ is *normally distributed* with mean $\mu$ and variance $\sigma^2$. Calculate $\Exp\SB{e^{\theta X}}$ and hence, $\Exp\SB{X^4}$

$\bspace Answer$

>$$\begin{align}
\Exp\SB{e^{\theta X}} &= \int^{\infty}_{-\infty} e^{\theta X}\cdot\ffrac{1}{\sqrt{2\pi}\sigma}\exp\CB{-\ffrac{ \P{x-\mu}^2}{2\sigma^2}}\;\dd x\\
&= \int^{\infty}_{-\infty} e^{\theta X}\cdot\ffrac{1}{\sqrt{2\pi}\sigma}\exp\CB{-\ffrac{ \P{x-\mu+\theta\sigma^2}^2}{2\sigma^2}} \cdot\exp\CB{\ffrac{\theta^2\sigma^2}{2} + \theta\mu}\;\dd x\\
&= \exp\CB{\ffrac{\theta^2\sigma^2}{2} + \theta\mu}
\end{align}$$
>
>And to find $\Exp\SB{X^4} = \left.\ffrac{\dd^4}{\dd \theta^4}\Exp\SB{e^{\theta X}}\right|_{\theta=0}$, we let $f\P{\theta} = \ffrac{\theta^2\sigma^2}{2} + \theta\mu$, then
>
>$$\begin{align}
\ffrac{\dd^4}{\dd \theta^4}\Exp\SB{e^{\theta X}} &= \ffrac{\dd^3}{\dd \theta^3}\P{f' e^f}\\
&= \ffrac{\dd^2}{\dd \theta^2}\P{\P{f'^2 + f''} e^f}\\
&= \ffrac{\dd}{\dd \theta}\P{\P{3f''f' + f^{\P{3}}+f'^3} e^f}\\
&= \P{\P{3f^{\P{3}}f' + f^{\P{4}}+\P{f'}^4+3\P{f''}^2+6\P{f'}^2f''} e^f}
\end{align}$$
>
>Plug in $\theta=0$ and by $f = 0 = f^{\P{3}} = f^{\P{4}}$, $f' = \mu$, $f'' = \sigma^2$, we have
>
>$$\Exp\SB{X^4} = 3\sigma^4 + 6\sigma^2\mu^2 + \mu^4$$
>***
>And actually, we can calculate it directly
>
>$$\begin{align}
\Exp\SB{X^4} &= \Exp\SB{\P{\mu + \sigma Z}^4}\\
&= \Exp\SB{\mu^4+4\mu^3\sigma Z + 6\mu^2\sigma^2Z^2+4\mu\sigma^3Z^3 + Z^4}\\
&=\mu^4 + 0 + 6\sigma^2\mu^2 + 0 + 3\sigma^4
\end{align}$$

$Remark$

>We can't use Itô's formula here cause it's not a stochastic process. And about $\Exp\SB{Z^n}$, find them using the $\text{MGF}$.

## Question 5

Let $\CB{W_t}_{t \geq 0}$ be *standard Brownian motion* under the measure $\PP$ and let $\CB{\FcF_t}_{t \geq 0}$ denote its natural filtration. Which of the following are $\P{\PP, \CB{\FcF_t}_{t \geq 0}}$-martingales?

$\P{1}$ $\exp\CB{\sigma W_t}$

$\bspace Answer$

>It's not. Whatever, for the first condition, $\Exp\SB{\abs{e^{\sigma W_t}}} = \exp\CB{\ffrac{1}{2}\sigma^2t} < \infty$. Now see the second condition.
>
>$$\begin{align}
\Exp_s\SB{e^{\sigma W_t}} &= \Exp_s\SB{e^{\sigma W_s}\cdot e^{\sigma \P{W_t-W_s}}}\\
&= e^{\sigma W_s} \Exp_s\SB{e^{\sigma \P{W_t-W_s}}} \\
&= e^{\sigma W_s} \Exp\SB{e^{\sigma W_{t-s}}}\\
&= \exp\CB{\sigma W_s +\ffrac{\sigma^2}{2}\P{t-s}} \neq e^{\sigma W_s},\bspace \text{if }\sigma\neq 0
\end{align}$$

$\P{2}$ $cW_{t/c^2}$, where $c$ is a constant

$\bspace Answer$

>$\bspace$if $\abs{c}<1$, we have $t/c^2 > t$, which is not measurable in the $\FcF_t$. If $\abs{c} = 1$, we have $cW_{t/c^2} = \pm W_t$, it's certainly a martingale. If $\abs{c} > 1$, we have
>
>$$\Exp_s\SB{cW_{t/c^2}}=\begin{cases}
cW_{t/c^2} & \text{if }t/c^2 <s\\
cW_s &\text{if } t/c^2 \geq s
\end{cases}$$
>
>Thus $cW_{t/c^2}$ is a martingale $iff$ $c = \pm1$

$\P{3}$ $tW_t - \d{\int_0^t W_s\;\dd s}$

$\bspace Answer$

>It is. For the first condition,
>
>$$\begin{align}
\Exp\SB{\abs{tW_t - \d{\int_{0}^{t} W_s\;\dd s}}} &\leq  \Exp\SB{\abs{tW_t} + \abs{\d{\int_{0}^{t} W_s\;\dd s}}}\\
&\leq t\cdot\Exp\SB{\ffrac{W_t^2 + 1}{2}} + \int_{0}^{t} \Exp\SB{\abs{W_s}}\;\dd s\\
&\leq t\cdot\ffrac{1+t}{2} + \int_{0}^{t} \ffrac{1+s}{2}\;\dd s = t + \ffrac{3}{4}t^2 <\infty
\end{align}$$
>
>And then the second one, in the review we have
>
>$$tW_t - \int_{0}^{t} W_s\;\dd s = \int_0^t s\;\dd W_s$$
>
>It's an Itô's process! Thus it's a martingale.

$Remark$

>Or prove the third one directly by checking the conditional expectation. **Goal**: try to collect the $W_t-W_s$ and then it's $0$.
>
>$$\begin{align}
\Exp_s\SB{tW_t-\int_{0}^t W_r \;\dd r} &= sW_s - \int_0^s W_r \;\dd r + \Exp_s\SB{tW_t - sW_s - \int_{s}^t W_r \;\dd r}\\
&= sW_s - \int_0^s W_r \;\dd r + \Exp_s\SB{t\P{W_t - W_s} + \int_{s}^t \P{W_s-W_r} \;\dd r}\\
&= sW_s - \int_0^s W_r \;\dd r
\end{align}$$

## Question 6

Let $\CB{\FcF_t}_{t \geq 0}$ denote the natural filtration associated to a *standard $\PP$-Brownian* motion $\CB{W_t}_{t \geq 0}$. Define the process $\CB{S_t}_{t \geq 0}$ by $S_t = f\P{t,W_t}$. What equation must $f$ satisfy if $S_t$ is to be a $\P{\PP, \CB{\FcF_t}_{t \geq 0}}$-martingale? Use your answer to check that $S_t = \exp\CB{vt + \sigma W_t}$ is a martingale if $v+\ffrac{\sigma^2}{2} = 0$

$\bspace Answer$

>Following the three conditions that define the martingale, we have
>
>$$\Exp\SB{\abs{f}}<\infty\\
\Exp_s\SB{f\P{t,W_t}} = f\P{s,W_s}$$
>
>Using Itô's formula, we have

>$$\begin{align}\dd S_t = \dd f &= \P{f_t + 0\cdot f_W + \ffrac{1}{2}\cdot 1 \cdot f_{WW}}\dd t + 1\cdot f_W \dd W_t = f_t\dd t + \ffrac{1}{2} f_{WW}\dd t + f_W \dd W_t\\
&= f_t \dd t + f_W\dd W + \ffrac{1}{2} f_{WW} \P{\dd W_t}^2 = f_t \dd t + f_W\dd W + \ffrac{1}{2} f_{WW} \dd t
\end{align}$$
>
>So that the condition here is $f_t + \ffrac{1}{2}f_{WW} = 0$.
>
>And to check this, of course, for $S_t = \exp\CB{vt + \sigma W_t}$, it's a martingale if $v + \ffrac{1}{2} \sigma^2 = 0$.

## Question 7

If $f$ is a simple function and $\CB{W_t}_{t\geq0}$ is a $\PP$-Brownian motion, prove that the process $\CB{M_t}_{t\geq 0}$ given by the Itô integral $M_t = \d{\int_0^t f\P{s,W_s}\;\dd W_s}$ is a $\P{\PP, \CB{\FcF_t}_{t \geq 0}}$-martingale.

$\bspace Answer$

>Firstly, it's adapted to $\FcF_t$ and likewise we have $\Exp\SB{\abs{M_t}} \leq \Exp\SB{\ffrac{M_t^2+1} {2}}<\infty$ by Itô's isometry. Then,
>
>$$\begin{align}
\Exp_s\SB{M_t} =& M_s + \Exp_s\SB{M_t - M_s} \\[0.6em]
&\bspace \text{partition the interval } \SB{s,t} \text{ in } n \text{ subintervals}\\[0.5em]
=& M_s + \Exp_s\SB{ \lim_{n\to\infty} \sum_{j=0}^{n-1} h\P{t_j, W_{t_{\void_{j}}}}\P{W_{t_{\void_{j+1}}} - W_{t_{\void_{j}}}} }\\[0.6em]
&\bspace \text{assume the summation is exchangable with the expectation } \\[0.5em]
=& M_s + \lim_{n\to\infty} \sum_{j=0}^{n-1} \Exp_s\SB{ h\P{t_j, W_{t_{\void_{j}}}}\P{W_{t_{\void_{j+1}}} - W_{t_{\void_{j}}}} }
\end{align}$$
>
>Then we condition on $\FcF_{t_{\void_{j}}}$ and since $\Exp_s\SB{X} = \Exp_s\SB{\Exp_t\SB{X}}$, $t>s$
>
>$$\begin{align}
\Exp_s\SB{M_t}=& M_s + \lim_{n\to\infty} \sum_{j=0}^{n-1} \Exp_s\SB{ \Exp_{t_{\void_{j}}}\SB{ h\P{t_j, W_{t_{\void_{j}}}} \P{W_{t_{\void_{j+1}}} - W_{t_{\void_{j}}}} } }\\
=& M_s + \lim_{n\to\infty} \sum_{j=0}^{n-1} \Exp_s\SB{  h\P{t_j, W_{t_{\void_{j}}}} \Exp_{t_{\void_{j}}} \SB{{W_{t_{\void_{j+1}}} - W_{t_{\void_{j}}}} }} \\[0.5em]
=& M_s
\end{align}$$

## Question 8

As usual, $\CB{W_t}_{t\geq0}$ denotes *standard Brownian* motion under $\PP$. Use Itô's formula to write down stochastic differential equations (SDE) for the following quantities.

$\P{1}$ $Y_t = W_t^3$

$\bspace Answer$

>Here $X_t = W_t$, then
>
>$$\begin{align}\dd Y_t &= \P{0 + 0 \cdot 3X_t^2 + \ffrac{1}{2}\cdot1\cdot6X_t}\dd t + 1\cdot 3 X_t^2 \dd W_t\\
&= 3X_t \dd t + 3X_t^2 \dd W_t\\
&= 3\sqrt[3]{Y_t} \dd t + 3\sqrt[3]{Y_t^2} \dd W_t
\end{align}$$
>
>It's not a martingale since
>
>$$\begin{align}
\Exp_s\SB{W_t^3} &= \Exp_s\SB{\P{W_t - W_s + W_s}^3}\\
&= \Exp_s\SB{\P{W_t - W_s}^3} + \Exp_s\SB{3\P{W_t - W_s}^2W_s} + \Exp_s\SB{3\P{W_t-W_s}W_s^2} + W_s^3\\
&= W_s^3 + 3W_s\Exp\SB{\P{W_t-W_s}^2}\\
&= W_s^3 + 3W_s\P{t-s} \neq W_s^3
\end{align}$$

$\P{2}$ $Y_t = \exp\CB{\sigma W_t - \ffrac{1}{2}\sigma^2 t}$

$\bspace Answer$

>Still $X_t = W_t$ here, then
>
>$$\begin{align}
\dd Y_t &= \dd\P{\exp\CB{-\ffrac{1}{2}\sigma^2 t} e^{\sigma W_t}}\\
&= Y_t\P{-\ffrac{1}{2}\sigma^2 \dd t - \ffrac{1}{2}\sigma^2 \dd t + \sigma\dd W_t + \ffrac{1}{2}\sigma^2 \dd t}\\
&= Y_t\P{-\ffrac{1}{2}\sigma^2 \dd t + \sigma \dd W_t}
\end{align}$$
>
>It's a martingale. We denote $M_t = \exp\CB{\sigma W_t - \ffrac{1} {2} \sigma^2 t}$. For the expectation part:
>
>$$\Exp\SB{\abs{M_t}} = \int_{-\infty}^{\infty} \exp\CB{\sigma W_t - \ffrac{1} {2} \sigma^2 t} \cdot\ffrac{1} {\sqrt{2\pi t}} \exp\CB{-\ffrac{x^2} {2t}}\dd{x} = 1 < \infty$$
>
>$$\Exp_s\SB{M_t} = \Exp_s\SB{M_s\cdot M_{t-s}} = M_s\Exp_s\SB{M_{t-s}} = M_s$$

$\P{3}$ $Y_t = tW_t$

$\bspace Answer$

>Still $X_t = W_t$, then
>
>$$\begin{align}
\dd Y_t &= \dd\P{tX_t}\\
&= \P{W_t + 0 + 0 }\dd t + 1\cdot t \dd W_t\\
&= W_t \dd t + t \dd W_t
\end{align}$$
>
>And this is NOT a martingale, since
>
>$$\begin{align}
\Exp_s\SB{Y_t} &= \Exp_S\SB{tW_t}\\
&= \Exp_s\SB{t\P{W_t-W_s} + tW_s}\\
&= tW_s \neq sW_s
\end{align}$$

$Remark$

>- $W_t -W_s \sim \N{0,t-s}$ thus $\Exp\SB{\exp\CB{\sigma\P{W_t-W_s}}} = \ffrac{1}{2}\sigma^2\P{t-s}$.
>- $\P{t-s}^{-1}\P{W_t -W_s}^2\sim\chi^2\P{1}$, thus $\Exp\SB{\P{W_t -W_s}^2} = \P{t-s}\Exp\SB{\chi^2\P{1}} = t-s$. Just remember that $\Exp\SB{\chi^2\P k} = k$ and $\Var{\chi^2\P k} = 2k$.

## Question 9

Let $\CB{W_t}_{t \geq 0}$ be *standard Brownian motion* under the measure $\PP$ and define $Z_t = \exp\CB{\alpha W_t}$. Use Itô's formula to write down a stochastic differential equation for $Z_t$, hence find an ordinary (deterministic) differential equation for $m\P t = \Exp\SB{Z_t}$, and solve to show that

$$\Exp\SB{\exp\CB{\alpha W_t}} = \exp\CB{\ffrac{\alpha^2}{2}t}$$

$\bspace Answer$

>Here let $X_t = \alpha W_t$ and we obtain
>
>$$\begin{align}
\dd Z_t &= \dd\P{e^{X_t}}\\
&= \P{0 + 0 + \ffrac{1}{2}\alpha^2 e^{X_t}}\dd t + \alpha e^{X_t} \dd W_t\\
&= Z_t\P{\ffrac{1}{2}\alpha^2 \dd t + \alpha \dd W_t}
\end{align}$$
>
>$$\begin{align}
m\P{t} &= \Exp\SB{Z_t} = \Exp\SB{e^{\alpha W_t}}\\
&= \Exp\SB{e^{\alpha W_0} + \int_0^t \alpha e^{\alpha W_s}\;\dd W_s + \int_0^t\ffrac{1}{2}\alpha^2 e^{\alpha W_s}\;\dd s}\\
&= \Exp\SB{1} + \Exp\SB{\int_0^t \alpha e^{\alpha W_s}\;\dd W_s} + \Exp\SB{\int_0^t\ffrac{1}{2}\alpha^2 e^{\alpha W_s}\;\dd s}\\
&= 1 + 0 + \int_0^t\ffrac{1}{2}\alpha^2 \Exp\SB{e^{\alpha W_s}}\;\dd s\\
&= 1 + \ffrac{1}{2}\alpha^2\int_0^tm\P{s}\;\dd s
\end{align}$$
>
>$$\begin{align}\dd m\P{t} &= \ffrac{1}{2}\alpha^2 m\P{t} + C\\
\Longrightarrow m\P{t} &= \exp\CB{\ffrac{1}{2}\alpha^2 t}-\ffrac{2C}{\alpha^2}\\
m\P{0}=1\Rightarrow m\P{t} &= \Exp\SB{e^{\alpha W_t}} = \exp\CB{\ffrac{1}{2}\alpha^2 t}
\end{align}$$

## Question 10 The Ornstein−Uhlenbeck process

Let $\CB{W_t}_{t\geq0}$ denote *standard Brownian motion* under $\PP$. The ***Ornstein-Uhlenbeck process***, $\CB{X_t}_{t\geq0}$ is unique solution to ***Langevin's equation***:

$$\dd X_t = -\alpha X_t \dd t+ \dd W_t,\bspace X_0 = x$$

This equation was originally introduced as a simple idealised model for the velocity of a particle suspended in a liquid. In finance it is a special case of the ***Vasicek model*** of interest rate. Verify that

$$X_t = e^{-\alpha t} x + e^{-\alpha t} \int_0^t e^{\alpha s} \;\dd W_s$$

and use this expression to calculate the mean and variance of $X_t$.

$\bspace Answer$

>To verify, we first rewrite the equation to $e^{\alpha t}\dd X_t = -\alpha e^{\alpha t}X_t\dd t + e^{\alpha t}\dd W_t$ and this is equivalent to
>
>$$\dd\P{e^{\alpha t}X_t} = e^{\alpha t}\dd W_t \\
\Longrightarrow e^{\alpha t}X_t - 1 \cdot X_0 = \int_0^t e^{\alpha s}\;\dd W_s\\
\Longrightarrow X_t = e^{-\alpha t}x + e^{-\alpha t}\int_0^t e^{\alpha s}\;\dd W_s
$$
>
>And about the mean
>
>$$\begin{align}
\Exp\SB{X_t} &= \Exp\SB{e^{-\alpha t}x + e^{-\alpha t}\int_0^t e^{\alpha s}\;\dd W_s}\\
&= e^{-\alpha t}x + e^{-\alpha t}\Exp\SB{\int_0^t e^{\alpha s}\;\dd W_s}\\
&= e^{-\alpha t}x + e^{-\alpha t} \cdot 0\\
&= x \cdot e^{-\alpha t}
\end{align}$$
>
>To find the variance, by $\Var{X_t}=\Exp\SB{X_t^2}-\P{\Exp\SB{X_t}}^2$, we first need to apply the Itô's isommetry to find the second moment
>
>$$\begin{align}
\Exp\SB{X_t^2} &= \Exp\SB{e^{-2\alpha t}x^2 + 2e^{-2\alpha t}x\int_0^t e^{\alpha s}\;\dd W_s + e^{-2\alpha t}\P{\int_0^t e^{\alpha s}\;\dd W_s}^2}\\
&= \Exp\SB{e^{-2\alpha t}x^2} + \Exp\SB{ 2e^{-2\alpha t}x\int_0^t e^{\alpha s}\;\dd W_s} + e^{-2\alpha t}\Exp\SB{\P{\int_0^t e^{\alpha s}\;\dd W_s}^2}\\
&= e^{-2\alpha t}x^2 + 0 + e^{-2\alpha t}\int_0^t \Exp\SB{e^{2\alpha s}}\dd s = e^{-2\alpha t}x^2 + \ffrac{1}{2\alpha}\P{1 - e^{-2\alpha t}}
\end{align}$$
>
>With this, we can compute the final variance
>
>$$
\begin{align}
\Var{X_t}&=\Exp\SB{X_t^2}-\P{\Exp\SB{X_t}}^2\\
&= e^{-2\alpha t}x^2 + \ffrac{1}{2\alpha}\P{1 - e^{-2\alpha t}} - x^2e^{-2\alpha t}\\
&= \ffrac{1}{2\alpha}\P{1-e^{-2\alpha t}}
\end{align}
$$
>***
>And a better method to find the variance
>
>$$\begin{align}
\Var{X_t}&= \Var{e^{-\alpha t}x + e^{-\alpha t}\int_0^t e^{\alpha s}\;\dd W_s}\\
&= 0 + e^{-2\alpha t}\Var{\int_0^t e^{\alpha s}\;\dd W_s}\\
&= e^{-2\alpha t}\P{\Exp\SB{\P{\int_0^t e^{\alpha s}\;\dd W_s}^2} - \P{\Exp\SB{\int_0^t e^{\alpha s}\;\dd W_s}}^2}\\
&= e^{-2\alpha t}\Exp\SB{\P{\int_0^t e^{\alpha s}\;\dd W_s}^2} \\
&= e^{-2\alpha t}\Exp\SB{\int_0^t e^{s\alpha s}\;\dd s},\bspace\text{isô's isometry}\\
&= \cdots
\end{align}$$

## Question 11

Suppose that under the probability measure $\PP$, $\CB{X_t}_{t\geq0}$ is a Brownian motion with *constant drift* $\mu$. Find a measure $\PP^*$ equivalent to $\PP$ where $\CB{X_t}_{t\geq0}$ is a Brownian motion with *constant drift* $\nu$.

$\bspace Answer$

>To make this simple, we write $\dd X_t = \mu \dd t + \sigma \dd W_t$ where $W_t$ is the standard Brownian motion under measure $\PP$. Let $\widetilde W_t$ is that under measure $\PP^*$, then we have
>
>$$\dd X_t = \nu \dd t + \sigma \dd \widetilde W_t$$
>
>So we can define $\widetilde W_t = W_t + \ffrac{\mu - \nu}{\sigma}t$. Then by Girsanov’s Theorem, we can define the measure $\PP^*$
>
>$$\left.\ffrac{\dd \PP^*}{\dd \PP}\right|_{\FcF_t} = \exp\CB{-\theta W_t - \ffrac{1}{2}\theta^2 t},\bspace \theta = \ffrac{\mu - \nu}{\sigma}$$

## Question 12

Use the Feynman-Kac stochastic representation formula to solve

$$\ffrac{\partial F\P{t,x}}{\partial t} + \ffrac{1}{2}\sigma^2 \ffrac{\partial^2 F\P{t,x}}{\partial x^2} = 0$$

subject to the *terminal value condition* $F\P{T,x} = e^x$

$\bspace Answer$

>By F-K formula, we have the solution of the corresponding stochastic differential equation
>
>$$\dd X_t = \mu_t\dd t + \sigma_t \dd W_t$$
>
>where $\mu_t = 0$, $r = 0$, and $\sigma_t = \sigma$. So that the solution is, in integral form,
>
>$$X_t = \sigma W_t + X_0$$
>
>So that the solution $F\P{t,x}$
>
>$$\begin{align}
F\P{t,x} &= \Exp\SB{e^{-r\P{T-t}} e^{X_T} \mid X_t = x} \\
&= \Exp\SB{e^{-0\P{T-t}} e^{\sigma W_T} \mid \sigma W_t = x} \\
&= \Exp\SB{e^{\sigma\P{ W_T - W_t} +x} \mid \sigma W_t = x}\\
&= e^{\sigma x}\Exp\SB{e^{\sigma\P{ W_T - W_t}}}\\
&= \exp\CB{ x + \ffrac{\sigma^2}{2}\P{T-t}}
\end{align}$$

***

FinMath/Models and Pricing of Financial Derivatives/HW/HW_03_11510691_fixed.ipynb


```python
import matplotlib.pyplot as plt
import scipy.stats as st
import seaborn as sns
import pandas as pd
from scipy.stats import norm, uniform, expon
from scipy.integrate import quad
from sympy.solvers import solve
from sympy import Symbol
import numpy as np
from pandas import Series, DataFrame
```

```python
werte = np.array([0,10,11])
ew = np.sum(werte*1/3)
ew
```

    7.0

```python
var_X = np.sum((werte-ew)**2*1/3)
var_X
```

    24.666666666666664

```python
sd_X = np.sqrt(var_X)
```

```python
sim = np.random.choice(werte, size=10, replace = True)
sim
```

    array([ 0, 11, 10, 11, 11, 11, 10,  0, 10, 10])

```python
# range: macht die Bins von 0 bis 12 mit Anstand 1
# edgecolor: zeichnet die Balkenumrandungen ein mit
# facecolor kann noch die Farbe der Balken veraendert
# werden
plt.hist(sim, bins = range(0, 13, 1), edgecolor = "black")
```

```python
# subplot: Macht 4 subplots mit 2 Reihen und 2 Spalten
# i: der i-te subplot
for i in range(1,5):
    plt.subplot(2,2,i)
    sim = np.random.choice(werte, size=10, replace = True)
    plt.hist(sim, bins=range(0,13,1), edgecolor="black")

```

```python
sim_1 = np.random.choice(werte,size=10, replace = True)
sim_1
sim_2 = np.random.choice(werte,size=10, replace = True)
sim_2
sim_mean_2 = (sim_1+sim_2)/2
sim_mean_2

```

    array([ 5.5,  5.5,  5. , 10. ,  5.5, 10. ,  5. , 10.5, 10. ,  5.5])

```python
# linspace: Spaltenbreiten 0.5 ueber das Intervall
plt.hist(sim_mean_2, bins = np.linspace(0, 11.5, 24), edgecolor = "black")
```

```python
sim_1 = np.random.choice(werte,size=10, replace = True)
sim_1
sim_2 = np.random.choice(werte,size=10, replace = True)
sim_2
sim_3 = np.random.choice(werte,size=10, replace = True)
sim_3
sim_mean_3 = (sim_1+sim_2+sim_3)/3
sim_mean_3
```

    array([ 7.        ,  7.33333333, 10.66666667, 10.33333333,  7.33333333,
           11.        , 10.        , 10.66666667,  6.66666667,  3.33333333])

```python
# linspace: Spaltenbreiten 1/3 ueber das Intervall
plt.hist(sim_mean_3, bins = np.linspace(0, 11 + 1/3, 35),
edgecolor = "black")
```

```python
for i in range(1,5):
    plt.subplot(2,2,i)
    sim_1 = np.random.choice(werte,size=10, replace = True)
    sim_2 = np.random.choice(werte,size=10, replace = True)
    sim_3 = np.random.choice(werte,size=10, replace = True)
    sim_mean_3 = (sim_1+sim_2+sim_3)/3
    plt.hist(sim_mean_3,bins=np.linspace(0,11+1/3,35),edgecolor="black")
```

```python
# Code nur fuer n=16
# 1. Subplot mit 2 Reihen und zwei Spalten

n = 1024
i = 1
for n in [16,54,256,1024]:
    plt.subplot(2,2,i)
    # es werden 1000*n zufaellige Zahlen aus werte gezogen
    sim = np.random.choice(werte,1000*n, replace = True)
    # reshape: Vektor wird in eine n x 1000-Matrix umgewandelt (1000 Spalten)
    sim = np.reshape(sim, (n,1000))
    # Mittelwert aller Spalten (axis=0)
    sim_mean = np.mean(sim, axis=0)
    # Festlegung des x-Bereiches (damit die Skizzen miteinander vergleichbar sind)
    plt.xlim(2,12)
    plt.title("n=16")
    plt.hist(sim_mean,edgecolor="black",bins="auto")
    i = i+1
```

```python
from scipy.stats import norm
plt.subplot(2,2,1)
n = 16
sim = np.reshape(np.random.choice(werte,1000*n, replace = True), (n,1000))
sim_mean = np.mean(sim, axis=0)
plt.xlim(2,12)
plt.title(f"n={n}")
# Festlegung der x-Werte: 500 Werte zwischen 2 und 12
x = np.linspace(2,12,500)
# Berechung der zugehoerigen Funktionswerte
y = norm.pdf(x, loc=7, scale=sd_X/np.sqrt(n))
plt.plot(x,y,color="orange")
#Normierung, dass die Flaeche des Histogrammes 1 ist
plt.hist(sim_mean, edgecolor="black", bins="auto", normed=True)
```

```python
from scipy.stats import uniform, expon, norm
import math
norm.cdf(x=5100, loc=5000, scale = math.sqrt(2500))
```

    0.9772498680518208

```python
from scipy.stats import uniform, expon, norm, binom
import math
binom.cdf(k=5100, n=10000, p=0.5)
```

    0.9777871004771368


# Time Evolution of Maxwell's Equations in Flat Spacetime and Curvilinear Coordinates

## Authors: Terrence Pierre Jacques, Zachariah Etienne and Ian Ruchlin

### This module constructs the evolution equations for Maxwell's equations as symbolic (SymPy) expressions, for an electromagnetic field in vacuum, as defined in [Tutorial-VacuumMaxwell_formulation_Curvilinear](Tutorial-VacuumMaxwell_formulation_Curvilinear.ipynb).

**Notebook Status:**  Validated

**Validation Notes:** All expressions generated in this here have been validated against the [VacuumMaxwell_Flat_Evol_Curvilinear_rescaled](../edit/Maxwell/VacuumMaxwell_Flat_Evol_Curvilinear_rescaled.py) module, as well as the [Maxwell/VacuumMaxwell_Flat_Evol_Cartesian](../edit/Maxwell/VacuumMaxwell_Flat_Evol_Cartesian.py) module when setting the coordinate system to Cartesian.

### NRPy+ Source Code for this module: [VacuumMaxwell_Flat_Evol_Curvilinear_rescaled](../edit/Maxwell/VacuumMaxwell_Flat_Evol_Curvilinear_rescaled.py)

$$\label{top}$$

# Table of Contents:

1. [Step 1](#step1): Set core NRPy+ parameters for numerical grids and reference metric
1. [Step 2](#step2): System II in curvilinear coordinates, using the rescaled quantities $a^i$ and $e^i$
1. [Step 3](#cart_transform): Convert $A^i$ and $E^i$ to the Cartesian basis
1. [Step 4](#step4): Code Validation
1. [Step 5](#latex_pdf_output): Output this notebook to $\LaTeX$-formatted PDF file

# Step 1: Preliminaries \[Back to [top](#top)\]
$$\label{step1}$$

Set up the needed NRPy+ infrastructure, such the number of dimensions and finite differencing order.

```python
# Import needed Python modules
import NRPy_param_funcs as par   # NRPy+: Parameter interface
import indexedexp as ixp         # NRPy+: Symbolic indexed expression (e.g., tensors, vectors, etc.) support
import reference_metric as rfm   # NRPy+: Reference metric support
import grid as gri               # NRPy+: Functions having to do with numerical grids
import sympy as sp                # SymPy: The Python computer algebra package upon which NRPy+ depends

# Set the spatial dimension parameter to 3.
par.set_parval_from_str("grid::DIM", 3)
DIM = par.parval_from_str("grid::DIM")

# Set coordinate system
# Choices are: Spherical, SinhSpherical, SinhSphericalv2, Cylindrical, SinhCylindrical,
#              SymTP, SinhSymTP

CoordSystem = "Spherical"
par.set_parval_from_str("reference_metric::CoordSystem",CoordSystem)
# Set reference metric related quantities
rfm.reference_metric()
```

# Step 2: System II in Curvilinear Coordinates, using the rescaled quantities $a^i$ and $e^i$ \[Back to [top](#top)\]
$$\label{step2}$$
(Following discussion reproduced from [Tutorial-VacuumMaxwell_formulation_Curvilinear](Tutorial-VacuumMaxwell_formulation_Curvilinear.ipynb))

Consider an arbitrary vector $\Lambda^i$, with smooth (continous) Cartesian components $\Lambda^x$, $\Lambda^y$, and $\Lambda^z$. Transforming $\Lambda^i$ to, e.g. spherical coordinates, introduces terms that spoil the smoothness of $\Lambda^i$;

$$
\Lambda^\phi = \frac{1}{r \sin \theta} \times \left[ \text{smooth part} \right].
$$

Evolving $\Lambda^\phi$ will introduce instabilities along the $z$-axis. To avoid this, we instead evolve the _rescaled_ quantity $\lambda^i$, defined by

$$
\bar{\Lambda}^i = \frac{\lambda^i}{\text{scalefactor}[i]}.
$$

where we use the [Hadamard product](https://en.wikipedia.org/w/index.php?title=Hadamard_product_(matrices)&oldid=852272177) of matrices, and no sums are implied by the repeated indices.

Thus, we evolve the smoothed variable $\lambda^i$, via

$$
\lambda^i = \bar{\Lambda}^i \text{scalefactor}[i].
$$

Within Nrpy+, ReU[i] = 1/scalefactor[i], giving

$$
\lambda^i = \frac{\bar{\Lambda}^i}{\text{ReU}[i]}.
$$

We now define the rescaled quantities $a^i$ and $e^i$ and rewrite our formulation of Maxwell's equations in curvilinear coordinates;

\begin{align}
a^i &= \frac{A^i}{\text{ReU}[i]},\\ \\
e^i &= \frac{E^i}{\text{ReU}[i]},
\end{align}

Taking a time derivative on both sides,

\begin{align}
\partial_t a^i &= \frac{\partial_t A^i}{\text{ReU}[i]} = \frac{ -E^i - \hat{g}^{ij}\partial_j \varphi}{\text{ReU}[i]} = -e^i - \frac{\hat{g}^{ij}\partial_j \varphi}{\text{ReU}[i]},\\ \\
\partial_t e^i &= \frac{\partial_t E^i}{\text{ReU}[i]} = \frac{\hat{g}^{ij}\partial_j \Gamma - \hat{g}^{jk} \hat{\nabla}_{j} \left(\hat{\nabla}_{k} A^{i}\right)}{\text{ReU}[i]} = \frac{\hat{g}^{ij}\partial_j \Gamma}{\text{ReU}[i]} - \frac{\hat{g}^{jk} \hat{\nabla}_{j} \left(\hat{\nabla}_{k} a^{i} \text{ReU}[i] \right)}{\text{ReU}[i]}.
\end{align}

Given that

$$
\partial_t E^i = {\underbrace {\textstyle \hat{g}^{ij}\partial_j \Gamma}_{\text{Term 1}}} - \hat{\gamma}^{jk} \left({\underbrace {\textstyle A^i_{,kj}}_{\text{Term 2}}} + {\underbrace {\textstyle \hat{\Gamma}^i_{mk,j} A^m + \hat{\Gamma}^i_{mk} A^m_{,j} + \hat{\Gamma}^i_{dj} A^d_{,k} - \hat{\Gamma}^d_{kj} A^i_{,d}}_{\text{Term 3}}} + {\underbrace {\textstyle \hat{\Gamma}^i_{dj}\hat{\Gamma}^d_{mk} A^m - \hat{\Gamma}^d_{kj} \hat{\Gamma}^i_{md} A^m}_{\text{Term 4}}}\right),
$$

we can make the following replacements within the above, in terms of NRPy+ code;

\begin{align}
A^i = \text{AU[i]} &\to \text{aU[i] * rfm.ReU[i]} \\
\partial_j A^i = \text{AUdD[i][j]} &\to \text{aU_dD[i][j] * rfm.ReU[i]} +\text{aU[i] * rfm.ReUdD[i][j]} \\
\partial_k \partial_j A^i = \text{AUdDD[i][j][k]} &\to
\text{aU_dDD[i][j][k] * rfm.ReU[i]} +
\text{aU_dDD[i][j] * rfm.ReUdD[i][k]} \\
&+ \text{aU_dD[i][k] * rfm.ReUdD[i][j]} +
\text{aU[i] * rfm.ReUdDD[i][j][k]}
\end{align}

The remainder of Maxwell's equations are unchanged;

$$
\partial_t \Gamma = -\hat{g}^{ij} \left(  \partial_i \partial_j \varphi - \hat{\Gamma}^k_{ji} \partial_k \varphi \right),
$$

$$
\partial_t \varphi = -\Gamma,
$$

subject to constraints

\begin{align}
\mathcal{G} &\equiv \Gamma - \partial_i A^i + \hat{\Gamma}^i_{ji} A^j &= 0,\\
\mathcal{C} &\equiv \partial_i E^i + \hat{\Gamma}^i_{ji} E^j &= 0.
\end{align}

```python
# Register gridfunctions that are needed as input.

#  Declare the rank-1 indexed expressions e^{i}, e^{i},
#  and \partial^{i} \psi, that are to be evolved in time.
#  Derivative variables like these must have an underscore
#  in them, so the finite difference module can parse
#  the variable name properly.

# e^i
eU = ixp.register_gridfunctions_for_single_rank1("EVOL", "eU")

# \partial_k ( E^i ) --> rank two tensor
eU_dD = ixp.declarerank2("eU_dD", "nosym")

# a^i
aU = ixp.register_gridfunctions_for_single_rank1("EVOL", "aU")

# \partial_k ( a^i ) --> rank two tensor
aU_dD = ixp.declarerank2("aU_dD", "nosym")

# \partial_k partial_m ( a^i ) --> rank three tensor
aU_dDD = ixp.declarerank3("aU_dDD", "sym12")

# \psi is a scalar function that is time evolved
psi = gri.register_gridfunctions("EVOL", ["psi"])

# \Gamma is a scalar function that is time evolved
Gamma = gri.register_gridfunctions("EVOL", ["Gamma"])

# \partial_i \psi
psi_dD = ixp.declarerank1("psi_dD")

# \partial_i \Gamma
Gamma_dD = ixp.declarerank1("Gamma_dD")

# partial_i \partial_j \psi
psi_dDD = ixp.declarerank2("psi_dDD", "sym01")

ghatUU = rfm.ghatUU
GammahatUDD = rfm.GammahatUDD
GammahatUDDdD = rfm.GammahatUDDdD
ReU = rfm.ReU
ReUdD = rfm.ReUdD
ReUdDD = rfm.ReUdDD

```

$$
\partial_t a^i = -e^i - \frac{\hat{g}^{ij}\partial_j \varphi}{\text{ReU}[i]},
$$

```python
# \partial_t a^i = -e^i - \frac{\hat{g}^{ij}\partial_j \varphi}{\text{ReU}[i]}
arhsU = ixp.zerorank1()
for i in range(DIM):
    arhsU[i] -= eU[i]
    for j in range(DIM):
        arhsU[i] -= (ghatUU[i][j]*psi_dD[j])/ReU[i]
```

$$
\partial_t e^i = \frac{\hat{g}^{ij}\partial_j \Gamma - \hat{g}^{jk} \hat{\nabla}_{j} \left(\hat{\nabla}_{k} A^{i}\right)}{\text{ReU}[i]} = \frac{\hat{g}^{ij}\partial_j \Gamma}{\text{ReU}[i]} - \frac{\hat{g}^{jk} \hat{\nabla}_{j} \left(\hat{\nabla}_{k} a^{i} \text{ReU}[i] \right)}{\text{ReU}[i]}.
$$

Given that

$$
\partial_t E^i = {\underbrace {\textstyle \hat{g}^{ij}\partial_j \Gamma}_{\text{Term 1}}} - \hat{\gamma}^{jk} \left({\underbrace {\textstyle A^i_{,kj}}_{\text{Term 2}}} + {\underbrace {\textstyle \hat{\Gamma}^i_{mk,j} A^m + \hat{\Gamma}^i_{mk} A^m_{,j} + \hat{\Gamma}^i_{dj} A^d_{,k} - \hat{\Gamma}^d_{kj} A^i_{,d}}_{\text{Term 3}}} + {\underbrace {\textstyle \hat{\Gamma}^i_{dj}\hat{\Gamma}^d_{mk} A^m - \hat{\Gamma}^d_{kj} \hat{\Gamma}^i_{md} A^m}_{\text{Term 4}}}\right),
$$

we can make the following replacements within the above, in terms of NRPy+ code;

\begin{align}
A^i = \text{AU[i]} &\to \text{aU[i] * rfm.ReU[i]} \\
\partial_j A^i = \text{AUdD[i][j]} &\to \text{aU_dD[i][j] * rfm.ReU[i]} +\text{aU[i] * rfm.ReUdD[i][j]} \\
\partial_k \partial_j A^i = \text{AUdDD[i][j][k]} &\to
\text{aU_dDD[i][j][k] * rfm.ReU[i]} +
\text{aU_dD[i][j] * rfm.ReUdD[i][k]} \\
&+ \text{aU_dD[i][k] * rfm.ReUdD[i][j]} +
\text{aU[i] * rfm.ReUdDD[i][j][k]}
\end{align}

```python
# A^i
AU = ixp.zerorank1()

# \partial_k ( A^i ) --> rank two tensor
AU_dD = ixp.zerorank2()

# \partial_k partial_m ( A^i ) --> rank three tensor
AU_dDD = ixp.zerorank3()

for i in range(DIM):
    AU[i] = aU[i]*ReU[i]
    for j in range(DIM):
        AU_dD[i][j] = aU_dD[i][j]*ReU[i] + aU[i]*ReUdD[i][j]
        for k in range(DIM):
            AU_dDD[i][j][k] = aU_dDD[i][j][k]*ReU[i] + aU_dD[i][j]*ReUdD[i][k] +\
                              aU_dD[i][k]*ReUdD[i][j] + aU[i]*ReUdDD[i][j][k]
```

$$
\text{Term 1} = \hat{g}^{ij}\partial_j \Gamma
$$

```python
# Term 1 = \hat{g}^{ij}\partial_j \Gamma
Term1U = ixp.zerorank1()
for i in range(DIM):
    for j in range(DIM):
        Term1U[i] += ghatUU[i][j]*Gamma_dD[j]
```

$$
\text{Term 2} = A^i_{,kj}
$$

```python
# Term 2: A^i_{,kj}
Term2UDD = ixp.zerorank3()
for i in range(DIM):
    for j in range(DIM):
        for k in range(DIM):
            Term2UDD[i][j][k] += AU_dDD[i][k][j]
```

$$
\text{Term 3} = \hat{\Gamma}^i_{mk,j} A^m + \hat{\Gamma}^i_{mk} A^m_{,j} + \hat{\Gamma}^i_{dj}A^d_{,k} - \hat{\Gamma}^d_{kj} A^i_{,d}
$$

```python
# Term 3: \hat{\Gamma}^i_{mk,j} A^m + \hat{\Gamma}^i_{mk} A^m_{,j}
#        + \hat{\Gamma}^i_{dj}A^d_{,k} - \hat{\Gamma}^d_{kj} A^i_{,d}
Term3UDD = ixp.zerorank3()
for i in range(DIM):
    for j in range(DIM):
        for k in range(DIM):
            for m in range(DIM):
                Term3UDD[i][j][k] += GammahatUDDdD[i][m][k][j]*AU[m]    \
                                      + GammahatUDD[i][m][k]*AU_dD[m][j] \
                                      + GammahatUDD[i][m][j]*AU_dD[m][k] \
                                      - GammahatUDD[m][k][j]*AU_dD[i][m]

```

$$
\text{Term 4} = \hat{\Gamma}^i_{dj}\hat{\Gamma}^d_{mk} A^m - \hat{\Gamma}^d_{kj} \hat{\Gamma}^i_{md} A^m
$$

```python
# Term 4: \hat{\Gamma}^i_{dj}\hat{\Gamma}^d_{mk} A^m -
#         \hat{\Gamma}^d_{kj} \hat{\Gamma}^i_{md} A^m
Term4UDD = ixp.zerorank3()
for i in range(DIM):
    for j in range(DIM):
        for k in range(DIM):
            for m in range(DIM):
                for d in range(DIM):
                    Term4UDD[i][j][k] += ( GammahatUDD[i][d][j]*GammahatUDD[d][m][k] \
                                           -GammahatUDD[d][k][j]*GammahatUDD[i][m][d])*AU[m]

```

Finally, we build up the RHS of $E^i$,

$$
\partial_t E^i = {\underbrace {\textstyle \hat{g}^{ij}\partial_j \Gamma}_{\text{Term 1}}} - \hat{\gamma}^{jk} \left({\underbrace {\textstyle A^i_{,kj}}_{\text{Term 2}}} + {\underbrace {\textstyle \hat{\Gamma}^i_{mk,j} A^m + \hat{\Gamma}^i_{mk} A^m_{,j} + \hat{\Gamma}^i_{dj} A^d_{,k} - \hat{\Gamma}^d_{kj} A^i_{,d}}_{\text{Term 3}}} + {\underbrace {\textstyle \hat{\Gamma}^i_{dj}\hat{\Gamma}^d_{mk} A^m - \hat{\Gamma}^d_{kj} \hat{\Gamma}^i_{md} A^m}_{\text{Term 4}}}\right),
$$

and divide through by ReU[i] to get $e^i$.

```python
# \partial_t E^i = \hat{g}^{ij}\partial_j \Gamma - \hat{\gamma}^{jk}*
#    (A^i_{,kj}
#   + \hat{\Gamma}^i_{mk,j} A^m + \hat{\Gamma}^i_{mk} A^m_{,j}
#   + \hat{\Gamma}^i_{dj} A^d_{,k} - \hat{\Gamma}^d_{kj} A^i_{,d}
#   + \hat{\Gamma}^i_{dj}\hat{\Gamma}^d_{mk} A^m
#   - \hat{\Gamma}^d_{kj} \hat{\Gamma}^i_{md} A^m)

ErhsU = ixp.zerorank1()
for i in range(DIM):
    ErhsU[i] += Term1U[i]
    for j in range(DIM):
        for k in range(DIM):
            ErhsU[i] -= ghatUU[j][k]*(Term2UDD[i][j][k] + Term3UDD[i][j][k] + Term4UDD[i][j][k])

erhsU = ixp.zerorank1()
for i in range(DIM):
    erhsU[i] = ErhsU[i]/ReU[i]
```

$$
\partial_t \Gamma = -\hat{g}^{ij} \left(  \partial_i \partial_j \varphi - \hat{\Gamma}^k_{ji} \partial_k \varphi \right)
$$

```python
# \partial_t \Gamma = -\hat{g}^{ij} (\partial_i \partial_j \varphi -
# \hat{\Gamma}^k_{ji} \partial_k \varphi)
Gamma_rhs = sp.sympify(0)
for i in range(DIM):
    for j in range(DIM):
        Gamma_rhs -= ghatUU[i][j]*psi_dDD[i][j]
        for k in range(DIM):
            Gamma_rhs += ghatUU[i][j]*GammahatUDD[k][j][i]*psi_dD[k]
```

$$
\partial_t \varphi = -\Gamma
$$

```python
# \partial_t \varphi = -\Gamma
psi_rhs = -Gamma
```

Constraints:

\begin{align}
\mathcal{G} &\equiv \Gamma - \partial_i A^i + \hat{\Gamma}^i_{ji} A^j, \\
\mathcal{C} &\equiv \partial_i E^i + \hat{\Gamma}^i_{ji} E^j.
\end{align}

```python
# \mathcal{G} \equiv \Gamma - \partial_i A^i + \hat{\Gamma}^i_{ji} A^j
G = Gamma
for i in range(DIM):
    G -= AU_dD[i][i]
    for j in range(DIM):
        G += GammahatUDD[i][j][i]*AU[j]

# E^i
EU = ixp.zerorank1()

# \partial_k ( A^i ) --> rank two tensor
EU_dD = ixp.zerorank2()
for i in range(DIM):
    EU[i] = eU[i]*ReU[i]
    for j in range(DIM):
        EU_dD[i][j] = eU_dD[i][j]*ReU[i] + eU[i]*ReUdD[i][j]

C = sp.sympify(0)
for i in range(DIM):
    C += EU_dD[i][i]
    for j in range(DIM):
        C += GammahatUDD[i][j][i]*EU[j]
```

# Step 3: Convert $A^i$ and $E^i$ to the Cartesian basis \[Back to [top](#top)\]
$$\label{cart_transform}$$

Here we convert $A^i$ and $E^i$ to the Cartesian basis, to make convergence tests within [Tutorial-Start_to_Finish-Solving_Maxwells_Equations_in_Vacuum-Curvilinear](Tutorial-Start_to_Finish-Solving_Maxwells_Equations_in_Vacuum-Curvilinear.ipynb) easier. Specifically, we will use the coordinate transformation definitions provided by [reference_metric.py](../edit/reference_metric.py) to build the Jacobian:

\begin{align}
\frac{\partial x_{\rm Cart}^i}{\partial x_{\rm Orig}^j},
\end{align}

where $x_{\rm Cart}^i \in \{x,y,z\}$. We then apply it to $A^i$ and $E^i$ to transform into Cartesian coordinates, via

\begin{align}
A^i_{\rm Cart} = \frac{\partial x_{\rm Cart}^i}{\partial x_{\rm Orig}^j} A^j_{\rm Orig}.
\end{align}

```python
def Convert_to_Cartesian_basis(VU):
    # Coordinate transformation from original basis to Cartesian
    rfm.reference_metric()

    VU_Cart = ixp.zerorank1()
    Jac_dxCartU_dxOrigD = ixp.zerorank2()
    for i in range(DIM):
        for j in range(DIM):
            Jac_dxCartU_dxOrigD[i][j] = sp.diff(rfm.xxCart[i], rfm.xx[j])

    for i in range(DIM):
        for j in range(DIM):
            VU_Cart[i] += Jac_dxCartU_dxOrigD[i][j]*VU[j]
    return VU_Cart

AU_Cart = Convert_to_Cartesian_basis(AU)
EU_Cart = Convert_to_Cartesian_basis(EU)

```

# Step 4: NRPy+ Module Code Validation \[Back to [top](#top)\]
$$\label{step4}$$

Here, as a code validation check, we verify agreement in the SymPy expressions for the RHSs of Maxwell's equations between
1. this tutorial and
2. the NRPy+ [VacuumMaxwell_Flat_Evol_Curvilinear_rescaled](../edit/Maxwell/VacuumMaxwell_Flat_Evol_Curvilinear_rescaled.py) module.

```python
# Reset the list of gridfunctions, as registering a gridfunction
#   twice will spawn an error.
gri.glb_gridfcs_list = []

#          Call the VacuumMaxwellRHSs_rescaled() function from within the
#          Maxwell/VacuumMaxwell_Flat_Evol_Curvilinear_rescaled.py module,
#          which should do exactly the same as the above.

# Set which system to use, which are defined in Maxwell/InitialData.py
par.initialize_param(par.glb_param("char","Maxwell.InitialData","System_to_use","System_II"))

import Maxwell.VacuumMaxwell_Flat_Evol_Curvilinear_rescaled as mwevol
mwevol.VacuumMaxwellRHSs_rescaled()

print("Consistency check between Tutorial-VacuumMaxwell_Curvilinear_RHS-Rescaling tutorial and NRPy+ module: ALL SHOULD BE ZERO.")

print("C - mwevol.C = " + str(C - mwevol.C))
print("G - mwevol.G = " + str(G - mwevol.G))
print("psi_rhs - mwevol.psi_rhs = " + str(psi_rhs - mwevol.psi_rhs))
print("Gamma_rhs - mwevol.Gamma_rhs = " + str(Gamma_rhs - mwevol.Gamma_rhs))

for i in range(DIM):
    print("arhsU["+str(i)+"] - mwevol.arhsU["+str(i)+"] = " + str(arhsU[i] - mwevol.arhsU[i]))
    print("erhsU["+str(i)+"] - mwevol.erhsU["+str(i)+"] = " + str(erhsU[i] - mwevol.erhsU[i]))
    print("AU_Cart["+str(i)+"] - mwevol.AU_Cart["+str(i)+"] = " + str(AU_Cart[i] - mwevol.AU_Cart[i]))
    print("EU_Cart["+str(i)+"] - mwevol.EU_Cart["+str(i)+"] = " + str(EU_Cart[i] - mwevol.EU_Cart[i]))

```

    Consistency check between Tutorial-VacuumMaxwell_Curvilinear_RHS-Rescaling tutorial and NRPy+ module: ALL SHOULD BE ZERO.
    C - mwevol.C = 0
    G - mwevol.G = 0
    psi_rhs - mwevol.psi_rhs = 0
    Gamma_rhs - mwevol.Gamma_rhs = 0
    arhsU[0] - mwevol.arhsU[0] = 0
    erhsU[0] - mwevol.erhsU[0] = 0
    AU_Cart[0] - mwevol.AU_Cart[0] = 0
    EU_Cart[0] - mwevol.EU_Cart[0] = 0
    arhsU[1] - mwevol.arhsU[1] = 0
    erhsU[1] - mwevol.erhsU[1] = 0
    AU_Cart[1] - mwevol.AU_Cart[1] = 0
    EU_Cart[1] - mwevol.EU_Cart[1] = 0
    arhsU[2] - mwevol.arhsU[2] = 0
    erhsU[2] - mwevol.erhsU[2] = 0
    AU_Cart[2] - mwevol.AU_Cart[2] = 0
    EU_Cart[2] - mwevol.EU_Cart[2] = 0

# Step 5: Output this notebook to $\LaTeX$-formatted PDF file \[Back to [top](#top)\]
$$\label{latex_pdf_output}$$

The following code cell converts this Jupyter notebook into a proper, clickable $\LaTeX$-formatted PDF file. After the cell is successfully run, the generated PDF may be found in the root NRPy+ tutorial directory, with filename
[Tutorial-VacuumMaxwell_Curvilinear_RHS-Rescaling.pdf](Tutorial-VacuumMaxwell_Curvilinear_RHS-Rescaling.pdf) (Note that clicking on this link may not work; you may need to open the PDF file through another means.)

```python
import cmdline_helper as cmd    # NRPy+: Multi-platform Python command-line interface
cmd.output_Jupyter_notebook_to_LaTeXed_PDF("Tutorial-VacuumMaxwell_Curvilinear_RHS-Rescaling")
```

    [NbConvertApp] WARNING | pattern 'Tutorial-VacuumMaxwell_Curvilinear_RHS-Rescaling.ipynb' matched no files
    Created Tutorial-VacuumMaxwell_Curvilinear_RHS-Rescaling.tex, and compiled
        LaTeX file to PDF file Tutorial-VacuumMaxwell_Curvilinear_RHS-
        Rescaling.pdf


```python
%load_ext lab_black
# Import important tools
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from scipy.io import loadmat, savemat
from mpl_toolkits.mplot3d import Axes3D
from scipy.optimize import curve_fit, minimize, least_squares
from scipy.integrate import trapz
from scipy.stats import norm, kurtosis
from matplotlib.ticker import ScalarFormatter
from matplotlib import rc
```

```python

```

```python
mpl.rcParams["xtick.direction"] = "in"
mpl.rcParams["ytick.direction"] = "in"
mpl.rcParams["lines.markeredgecolor"] = "k"
mpl.rcParams["lines.markeredgewidth"] = 1
mpl.rcParams["figure.dpi"] = 130
rc("font", family="serif")
rc("text", usetex=True)
rc("xtick", labelsize="x-small")
rc("ytick", labelsize="x-small")

def cm2inch(value):
    return value / 2.54
```

We load the data

```python
raw_data = loadmat(
    "fit_result_dur_27052020_n_r_fix_0p0513_wav_532_r_1p516_n_1.597.mat"
)["data"][:, 0:3]
r = 1.516 * 1e-6
n_part = 1.597
fps = 60
time = np.arange(0, np.shape(raw_data)[0]) / fps
dataset = {}
dataset["r"] = r
dataset["n"] = n_part
dataset["fps"] = fps
dataset["time"] = time
```

# Data exploration

```python
# We put everything in microns
raw_data_m = raw_data
raw_data_m[:, 0:3] = raw_data_m[:, 0:3] * 0.0513
plt.plot(time / fps, raw_data_m[:, 2])
x = raw_data_m[:, 0]
y = raw_data_m[:, 1]
z = raw_data_m[:, 2]

plt.xlabel("$t$ (minutes)")
plt.ylabel("$z$ ($\mathrm{\mu m}$)")
plt.show()
```

```python
plt.plot(time / fps, raw_data_m[:, 0], label="x")
plt.plot(time / fps, raw_data_m[:, 1], label="y")
plt.xlabel("$t$ (minutes)")
plt.ylabel("$x$ ($\mathrm{\mu m}$)")
plt.show()
```

# MSD

We compute the MSD using the formula:

\begin{equation}
	\langle\Delta r_i(t)^2 \rangle_t = \langle[r_i(t+\Delta t) - r_i(t)]^2\rangle_t\ .
	\label{MSDdef}
\end{equation}

```python
def MSD(x, t):
    MSD = np.zeros(len(t))
    for n, i in enumerate(t):
        MSD[n] = np.nanmean((x[0:-i] - x[i:]) ** 2)
    return MSD
```

```python
t = np.array(
    [
        *np.arange(1, 10, 1),
        *np.arange(10, 100, 10),
        *np.arange(100, 1000, 100),
        *np.arange(1000, 40000, 1000),
    ]
)
MSD_x = MSD(x * 1e-6, t)  # m² conversion
MSD_y = MSD(y * 1e-6, t)
MSD_z = MSD(z * 1e-6, t)

plt.loglog(time[t], MSD_x, "o", label="$x$")
plt.plot(time[t], MSD_y, "o", label="$y$")
plt.plot(time[t], MSD_z, "o", label="$z$")
plt.ylabel("MSD ($\mathrm{m^2}$)")
plt.xlabel("$\Delta t$ (s)")

plt.legend()

dataset["MSD_x_tot"] = MSD_x
dataset["MSD_y_tot"] = MSD_y
dataset["MSD_z_tot"] = MSD_z
dataset["MSD_time_tot"] = time[t]
```

We fit the short time MSD with and average diffusion coefficient such as:

\begin{equation}
	\langle\Delta r_i(t)^2 \rangle_t = 2 \langle D_i \rangle \Delta t\ ,
	\label{averagediff}
\end{equation}

```python
Do = 4e-21 / (6 * np.pi * 0.001 * r)
f = lambda x, a, noiselevel: 2 * Do * a * x + (noiselevel * 1e-9) ** 2
popt_1, pcov_1 = curve_fit(f, time[t[0:5]], MSD_x[0:5], p0=[1, 30])
popt_2, pcov_1 = curve_fit(f, time[t[0:5]], MSD_y[0:5], p0=[1, 30])
popt_3, pcov_1 = curve_fit(f, time[t[0:5]], MSD_z[0:5], p0=[1, 30])

dataset["x_MSD_fit"] = time[t[0:5]]

dataset["MSD_x"] = MSD_x[0:5]
dataset["MSD_y"] = MSD_y[0:5]
dataset["MSD_z"] = MSD_z[0:5]
```

    C:\Users\m.lavaud\.conda\envs\analyse\lib\site-packages\scipy\optimize\minpack.py:828: OptimizeWarning: Covariance of the parameters could not be estimated
      warnings.warn('Covariance of the parameters could not be estimated',

```python
print(
    "We measure a reduced mean diffusion coefficient of {:.3f} for the perpendicular motion and of {:.3f} for the parallel motion".format(
        (popt_1[0] + popt_2[0]) / 2, popt_3[0]
    )
)
```

    We measure a reduced mean diffusion coefficient of 0.522 for the perpendicular motion and of 0.243 for the parallel motion

```python
plt.loglog(time[t], MSD_x, "o", label="$x$")
plt.plot(time[t], MSD_y, "o", label="$y$")
plt.plot(time[t], MSD_z, "o", label="$z$")
plt.ylabel("MSD ($\mathrm{m^2}$)")
plt.xlabel("$\Delta t$ (s)")
tt = np.linspace(1e-2, 1e3)
plt.plot(tt, f(tt, *popt_1), color="k")
plt.plot(tt, f(tt, *popt_3), color="k")

plt.xlim((1e-2, 1e3))
plt.legend()
```

# Displacement distributions

## $\Delta x$ distributions

```python
def pdf(data, bins=10, density=True):
    """
    function to automatize the computations of experimental probability density functions.
    """

    pdf, bins_edge = np.histogram(data, bins=bins, density=density)
    bins_center = (bins_edge[0:-1] + bins_edge[1:]) / 2

    return pdf, bins_center
```

```python
I = [2, 5, 10, 50, 100, 500, 1000, 2000]

for i in I:

    Dezs = x[0:-i] - x[i:]
    hist, bins_center = pdf(Dezs, bins=50)

    plt.plot(bins_center, hist, label=" t = {:.2f} s".format(time[i]))

plt.legend()
plt.ylabel("$P(\Delta x)$ [a.u.]")
plt.xlabel("$\Delta x$ [$\mathrm{\mu m}$]")
```

If we now normalize by the standard deviation

```python
def gauss_function(x, a, x0, sigma):
    return a * np.exp(-((x - x0) ** 2) / (2 * sigma ** 2))
```

```python
for n, i in enumerate(I):

    Dezs = x[0:-i] - x[i:]
    Dezs = Dezs / np.sqrt(2 * Do * time[i])
    hist, bins_center = pdf(Dezs, bins=30)

    # if i == I[0]:
    #    popt, pcov = curve_fit(gauss_function, bins_center/np.max(bins_center), hist, p0 = [1, np.mean(hist), np.std(hist)])
    #    plt.plot(bins_center/np.max(bins_center), gauss_function(bins_center, *popt), label = "fit at t = {:.2f} s".format(time[i]))
    #    plt.plot(bins_center/np.max(bins_center), hist, "x",label = " t = {:.2f} s".format(time[i]),color = "tab:blue")
    #    continue

    plt.plot(
        bins_center / np.max(bins_center),
        hist,
        ".",
        label=" $Delta$t = {:.2f} s".format(time[i]),
    )

plt.ylabel("$P(\Delta x)$ [a.u.]")
plt.xlabel("normalized $\Delta x$ [a.u.]")
```

```python
(3.5e-22) ** (1 / 3)
```

    7.047298732064899e-08

We can see a clear change but we would need to average on different trajectectories to have consitant results.

## $\Delta z$ distributions

```python
I = [2, 5, 10, 50, 100, 500, 1000, 2000, 5000, 10000]

for i in I:

    Dezs = z[0:-i] - z[i:]
    hist, bins_center = pdf(Dezs[~np.isnan(Dezs)], bins=50)

    plt.plot(bins_center, hist, label=" t = {:.2f} s".format(time[i]))

plt.legend()
plt.ylabel("$P(\Delta x)$ [a.u.]")
plt.xlabel("$\Delta x$ [$\mathrm{\mu m}$]")
```

```python
for i in I:

    Dezs = z[0:-i] - z[i:]
    Dezs = Dezs / np.nanstd(Dezs)
    hist, bins_center = pdf(Dezs[~np.isnan(Dezs)], bins=30)

    plt.plot(bins_center, hist, label=" t = {:.2f} s".format(time[i]))

plt.legend()
plt.ylabel("$P(\Delta x)$ [a.u.]")
plt.xlabel("$\Delta x$ [$\mathrm{\mu m}$]")
```

### Short time distributions

```python
I = [1, 2, 5, 6, 9, 10]

for i in I:

    Dezs = z[0:-i] - z[i:]
    Dezs = Dezs / np.std(Dezs)
    hist, bins_center = pdf(Dezs[~np.isnan(Dezs)], bins=100)

    if i == I[0]:
        popt, pcov = curve_fit(
            gauss_function, bins_center, hist, p0=[1, np.mean(hist), np.std(hist)]
        )
        plt.plot(bins_center, gauss_function(bins_center, *popt))
        plt.plot(
            bins_center,
            hist,
            ".",
            label=" t = {:.2f} s".format(time[i]),
            color="tab:blue",
        )
        continue
    plt.semilogy(bins_center, hist, ".", label=" t = {:.2f} s".format(time[i]))

plt.legend()
plt.ylabel("$P(\Delta r_z)$ [a.u.]")
plt.xlabel("$\Delta r_z$ [$\mathrm{\mu m}$]")
axes = plt.gca()
axes.set_ylim([1e-5, 1])
```

The non-Gaussianity is due to the hindered mobility. Taking into account the hindered mobility the PDF of displacement writes:

\begin{equation} P(\Delta r_i , \Delta t) = \int_0 ^\infty \mathrm{d}DP(D_i) \frac{1}{\sqrt{4 \pi D_i \Delta t}} \exp\left[ \frac{-\Delta_i r_i ^2}{4D_i\Delta t} \right]~. \end{equation}

This non-Gaussianity can be fitted as done at the end of this appendix and shown in the manuscript.

## Long time distributions

```python
I = [2000, 5000, 10000]

color_long_time = ["tab:gray", "tab:olive", "tab:cyan"]
for n, i in enumerate(I):

    Dezs = z[0:-i] - z[i:]
    hist, bins_center = pdf(Dezs[~np.isnan(Dezs)], bins=10)

    plt.semilogy(
        bins_center,
        hist,
        "o",
        label=" $t = {:.2f}$ s".format(time[i]),
        color=color_long_time[n],
    )

plt.legend()

plt.ylabel("$P(\Delta r_z)$ [a.u.]")
plt.xlabel("$\Delta r_z$ [$\mathrm{\mu m}$]")
```

Indeed at long time it becomes exponential and it's no longer dependent on $\Delta t$
At very long time intervals $\Delta t$ each position measurement can be seen as random measurement on the Boltzmann distribution. Thus, one can write the probability distribution as a convolution of two PDF: \begin{equation} P(\Delta z) = \int ^ \infty _{- \infty} dz P_B (z)P_B (z + \Delta z), \end{equation} with : \begin{equation} P_B(z) = Ae^{\left(Bexp\left(-\frac{z}{l_d}\right) - \frac{z}{l_b}\right)} \end{equation}
Also, $P_B(z < 0)$ giving at long time step : \begin{equation} P(\Delta z) = A'exp \left[Bexp\left[-\frac{z}{l_d}\right] (1 + exp[- \frac{\Delta z}{ l_d}]) - \frac{ 2z + \Delta z}{l_b} \right] \end{equation}

## Analysis of pdf of the $\Delta z$ at large time step

To have a better measurement we average the PDF of displacement $\Delta r_z$ over different time-step $\Delta t$ . But, first of all, we need to get rid of the drifts at long time. We do that by taking a moving minimum.

## Dedrifting the z trajectory

```python
def movmin(datas, k):
    result = np.empty_like(datas)
    start_pt = 0
    end_pt = int(np.ceil(k / 2))

    for i in range(len(datas)):
        if i < int(np.ceil(k / 2)):
            start_pt = 0
        if i > len(datas) - int(np.ceil(k / 2)):
            end_pt = len(datas)
        result[i] = np.min(datas[start_pt:end_pt])
        start_pt += 1
        end_pt += 1

    return result
```

```python
z_dedrift = z - movmin(z, 10000)
```

```python
# Fig for comparing the two

plt.plot(time, z - np.min(z), label="raw")
plt.plot(time, z_dedrift, label="dedrifted")
plt.legend()

plt.xlabel("t [s]")
plt.ylabel("z [$\mathrm{\mu m}$]")
```

###  Measuring pdf at large $\Delta t$  with the dedrifted trajectory and analysing it

```python
t_start = 25
t_end = 30
I = np.arange(t_start * fps, t_end * fps)
bins = 50

hists = np.zeros((bins, len(I)))
bins_centers = np.zeros((bins, len(I)))

for n, i in enumerate(I):

    Dezs = z_dedrift[0:-i] - z_dedrift[i:]
    hist, bins_center = pdf(Dezs[~np.isnan(Dezs)], bins=bins)

    hists[:, n] = hist
    bins_centers[:, n] = bins_center

pdf_long_t = np.mean(hists, axis=1)
bins_centers_long_t = np.mean(bins_centers, axis=1)
err_long_t = np.std(hists, axis=1)
err_bins_centers = np.std(bins_centers, axis=1)
```

```python
plt.plot(bins_centers_long_t, pdf_long_t)
plt.fill_between(
    bins_centers_long_t, pdf_long_t - err_long_t, pdf_long_t + err_long_t, alpha=0.3
)
plt.ylabel("$P(\Delta x)$ ($m^{-1}$)")
plt.xlabel("$\Delta x$ ($\mathrm{\mu m}$)")
```

We are now going to code the function
\begin{equation} P(\Delta z) = \int ^ \infty _{- \infty}A'exp \left[Bexp\left[-\frac{z}{l_d}\right] (1 + exp[- \frac{\Delta z}{ l_d}]) - \frac{ 2z + \Delta z}{l_b} \right] \end{equation}

Noting that coding the form :
\begin{equation} P(\Delta z) = \int ^ \infty _{- \infty} dz P_B (z)P_B (z + \Delta z), \end{equation}

Will be easier and $P_B$ will be reused later on. Also since $P_B(z < 0) = 0$ :
\begin{equation} P(\Delta z) = \int ^ \infty _{0} dz P_B (z)P_B (z + \Delta z), \end{equation}

with :
\begin{equation} P_B(z) = Ae^{\left(Bexp\left(-\frac{z}{l_d}\right) - \frac{z}{l_b}\right)} \end{equation}

```python
def P_b(z, A, B, ld, lb):
    P_b = A * np.exp(-B * np.exp(-z / (ld)) - z / lb)
    P_b[z < 0] = 0
    return P_b

def dPdeltaz_long(z, DZ, A, B, ld, lb):
    return P_b(z, A, B, ld, lb) * P_b(z + DZ, A, B, ld, lb)

def P_computation(DZ, A, B, ld, lb):
    z = np.linspace(0, 20e-6, 1000)
    dP = dPdeltaz_long(z, DZ, A, B, ld, lb)
    P = trapz(dP, z)
    return P

def Pdeltaz_long(DZ, B, ld, lb):
    if type(DZ) == float:
        return P_computation(i, 1, B, ld, lb)

    pdf = np.array([P_computation(i, 1, B, ld * 1e-9, lb * 1e-9) for i in DZ])

    # normalisation of the PDF to not use A

    A = trapz(pdf, DZ * 1e6)

    return np.array([P_computation(i, 1, B, ld * 1e-9, lb * 1e-9) for i in DZ]) / A
```

```python
A = 0.14e8
B = 4
ld = 70
lb = 500
p1 = [B, ld, lb]

# Normalisation fo the pdf

pdf_long_t = pdf_long_t / trapz(pdf_long_t, bins_centers_long_t)

popt, pcov = curve_fit(Pdeltaz_long, bins_centers_long_t * 1e-6, pdf_long_t, p0=p1)
dataset["pdf_longtime"] = pdf_long_t
dataset["x_pdf_longtime"] = bins_centers_long_t * 1e-6
```

    <ipython-input-25-d08630fe76fc>:2: RuntimeWarning: overflow encountered in exp
      P_b = A * np.exp(-B * np.exp(-z / (ld)) - z / lb)

```python
A = 0.14e8
B = 400
ld = 70
lb = 500
p0 = [B, ld, lb]

plt.semilogy(bins_centers_long_t, pdf_long_t, label="$P_z(\Delta r_z)$")
plt.fill_between(
    bins_centers_long_t, pdf_long_t - err_long_t, pdf_long_t + err_long_t, alpha=0.3
)

zz = np.linspace(-4, 4, 1000)
plt.plot(zz, Pdeltaz_long(zz * 1e-6, *popt), label="fit", color="k")
plt.xlim(-4, 4)
plt.legend()
plt.ylabel("$P(\Delta z)$")
plt.xlabel("$\Delta z$ [$\mathrm{\mu m}$]")
```

```python
print("We measure, B = {:.2f}, ld = {:.2f} nm, lb = {:.2f} nm".format(*popt))
B, ld, lb = popt
```

    We measure, B = 20.71, ld = 71.84 nm, lb = 504.78 nm

## Analyse of the MSD z plateau

```python
t = np.concatenate(
    (
        np.arange(1, 10, 1),
        np.arange(10, 100, 10),
        np.arange(100, 1000, 100),
        np.arange(1000, 10000, 1000),
        np.arange(10000, 50000, 5000),
    )
)

MSD_z_dedrift = MSD(z_dedrift * 1e-6, t)

plt.loglog(time[t], MSD_z_dedrift, "o", label="MSDz undrifted", color="tab:green")
plt.legend()
plt.ylabel("MSD (m$^2$)")
plt.xlabel("$\Delta$t (s)")
```

```python
plateau = np.mean(MSD_z_dedrift[time[t] > 1e2])
```

```python
plt.loglog(time[t], MSD_z_dedrift, "o", label="$z$", color="tab:green")
plt.plot(tt, [plateau] * len(tt), "k")
plt.plot(tt, f(tt, *popt_3), color="k")
plt.xlim((1e-2, 1e3))
plt.ylim((None, 1e-12))
plt.legend()
plt.ylabel("MSD (m$^2$)")
plt.xlabel("$\Delta$t (s)")
```

```python
np.mean(MSD_z_dedrift[time[t] > 1e2])
```

    5.348018604759325e-13

```python
# dataset["plateau_MSD"] = popt[0]
dataset["plateau_MSD"] = np.mean(MSD_z_dedrift[time[t] > 1e2])
print("Measured plateau : {:e}".format(popt[0]))
```

    Measured plateau : 2.070536e+01

The MSD plateau is theoritically given by:

\begin{equation}
Plateau = \int _{-\infty} ^{+\infty} \Delta z ^ 2 P_{\Delta z, t \rightarrow +\infty}(\Delta z,B,l_d,l_b) d\Delta z
\end{equation}

```python
x_Th_Plateau = bins_centers_long_t * 1e-6

def Theoritical_Plateau(B, ld, lb):
    x = dataset["x_pdf_longtime"]
    P = Pdeltaz_long(x, B, ld, lb) / trapz(Pdeltaz_long(x, B, ld, lb), x)

    res = trapz((x ** 2) * P, x)
    return res
```

```python
def minimize_plateau(x):
    B = x[0]
    ld = x[1]
    lb = x[2]
    return (
        np.log(Theoritical_Plateau(B, ld, lb)) - np.log(dataset["plateau_MSD"])
    ) ** 2 / np.log(Theoritical_Plateau(B, ld, lb)) ** 2
```

```python
res_plateau = minimize(minimize_plateau, x0=[B, ld, lb])
print("We measure, B = {:.2f}, ld = {:.2f} nm, lb = {:.2f} nm".format(*res_plateau.x))
```

    We measure, B = 20.71, ld = 71.84 nm, lb = 504.78 nm

## PDF of heights

```python
def logarithmic_hist(data, begin, stop, num=50, base=2):

    if begin == 0:
        beg = stop / num
        bins = np.logspace(
            np.log(beg) / np.log(base), np.log(stop) / np.log(base), num - 1, base=base
        )
        widths = bins[1:] - bins[:-1]
        bins = np.cumsum(widths[::-1])
        bins = np.concatenate(([0], bins))
        widths = bins[1:] - bins[:-1]

    else:
        bins = np.logspace(
            np.log(begin) / np.log(base), np.log(stop) / np.log(base), num, base=base
        )
        widths = bins[1:] - bins[:-1]

    hist, bins = np.histogram(data, bins=bins, density=True)
    # normalize by bin width
    bins_center = (bins[1:] + bins[:-1]) / 2

    return bins_center, widths, hist
```

```python
pdf_z, bins_center_pdf_z = pdf(z_dedrift[z_dedrift < 1.5], bins=150)
plt.plot(bins_center_pdf_z, pdf_z, "o")
plt.xlabel("z ($\mathrm{\mu m}$)")
plt.ylabel("$P_z(z)$")
```

The idea now is to find where the substrate is, to do this we will use a first method which consist to adjust the PDF with an offset to make it fit with the measured mean Diffusion coefficient. With :
\begin{equation}
< D_i > = \int _{-\infty} ^{\infty} dz D_i(z)P(z)
\end{equation}

For z we are going to use the Padé approx :
\begin{equation} D_z (z) \approx D_0 \left( \frac{6z^2 + 2rz}{6z^2 + 9rz + 2r^2} \right) \end{equation}

For x we are going to use the Faxen formula :
\begin{equation} D_x (z) \approx D_0 \left[ 1 - \frac{9}{16} \left(\frac{r}{z}\right) + \frac{1}{8} \left(\frac{r}{z}\right)^3 - \frac{45}{236} \left(\frac{r}{z}\right)^4 - \frac{1}{16} \left(\frac{r}{z}\right)^5 \right] \end{equation}

To do this we will fit the PDF with an offset, adjust it with the mean value of z. Let's first do it over z

```python
def P_b_off(z, z_off, B, ld, lb):
    z_off = z_off * 1e-6
    lb = lb * 1e-9
    ld = ld * 1e-9
    z = z - z_off
    P_b = np.exp(-B * np.exp(-z / (ld)) - z / lb)
    P_b[z < 0] = 0

    # Normalization of P_b

    A = trapz(P_b, z * 1e6)
    P_b = P_b / A

    return P_b
```

```python
# Normalization of the PDF

pdf_z = pdf_z / trapz(pdf_z, bins_center_pdf_z)

p2 = [0, B, ld, lb]

popt, pcov = curve_fit(P_b_off, bins_center_pdf_z * 1e-6, pdf_z, p0=p2)
```

    <ipython-input-39-f5e0b340e678>:6: RuntimeWarning: overflow encountered in exp
      P_b = np.exp(-B * np.exp(-z / (ld)) - z / lb)
    <ipython-input-39-f5e0b340e678>:12: RuntimeWarning: invalid value encountered in true_divide
      P_b = P_b / A

```python
plt.semilogy(bins_center_pdf_z, pdf_z, "o")
plt.plot(bins_center_pdf_z, P_b_off(bins_center_pdf_z * 1e-6, *popt), "k")

plt.xlabel("z $\mathrm{(\mu m)}$")
plt.ylabel("P(z)")
plt.grid()
```

```python
mean_Dx = (popt_1[0] + popt_2[0]) / 2
mean_Dz = popt_3[0]
print(
    "We measure a mean diffusion coefficient of {:.3f}D0 for the perpendicular motion and of {:.3f}D0 for the parallel motion".format(
        (popt_1[0] + popt_2[0]) / 2, popt_3[0]
    )
)

dataset["D_para"] = mean_Dx
dataset["D_perp"] = mean_Dz
```

    We measure a mean diffusion coefficient of 0.522D0 for the perpendicular motion and of 0.243D0 for the parallel motion

```python
Do = 4e-21 / (6 * np.pi * 0.001 * r)

def Dz_z(z):
    result = (6 * z * z + 2 * r * z) / (6 * z * z + 9 * r * z + 2 * r * r)
    return result

def Dx_z(z):
    result = (
        1
        - 9 / 16 * (r / (z + r))
        + 1 / 8 * (r / (z + r)) ** 3
        - 45 / 256 * (r / (z + r)) ** 4
        - 1 / 16 * (r / (z + r)) ** 5
    )
    return result
```

```python
def minimizer(z_off):
    Dx_pdf = trapz(
        Dx_z(bins_center_pdf_z * 1e-6)
        * P_b_off(bins_center_pdf_z * 1e-6, z_off, *popt[1:]),
        bins_center_pdf_z,
    )
    Dz_pdf = trapz(
        Dz_z(bins_center_pdf_z * 1e-6)
        * P_b_off(bins_center_pdf_z * 1e-6, z_off, *popt[1:]),
        bins_center_pdf_z,
    )

    return np.abs((1 - mean_Dx / Dx_pdf) + (1 - mean_Dx / Dx_pdf))

res = minimize(minimizer, 0, method="nelder-mead")
```

```python
offset = res
```

```python
offset = np.mean(res["final_simplex"][0])
print(
    "From the measurement of the mean diffusion coefficient, we measure an offset of {:.3f} um".format(
        offset
    )
)
```

    From the measurement of the mean diffusion coefficient, we measure an offset of 0.005 um

```python
def logarithmic_hist(data, begin, stop, num=50, base=2):
    """
    Function to make logarithmic histograms to have more points
    near the surface and where the particle spend the most of its time.
    """
    if begin == 0:
        beg = stop / num
        bins = np.logspace(
            np.log(beg) / np.log(base), np.log(stop) / np.log(base), num - 1, base=base
        )
        widths = bins[1:] - bins[:-1]
        bins = np.cumsum(widths[::-1])
        bins = np.concatenate(([0], bins))
        widths = bins[1:] - bins[:-1]

    else:
        bins = np.logspace(
            np.log(begin) / np.log(base), np.log(stop) / np.log(base), num, base=base
        )
        widths = bins[1:] - bins[:-1]

    hist, a = np.histogram(data, bins=bins, density=True)
    # normalize by bin width
    bins_center = (bins[1:] + bins[:-1]) / 2

    return bins_center, widths, hist

bins_center_pdf_z, widths, pdf_z = logarithmic_hist(z_dedrift, 0.01, 2, num=50, base=12)

p2 = [0, B, ld, lb]
popt_pdf, pcov_pdf = curve_fit(P_b_off, bins_center_pdf_z * 1e-6, pdf_z, p0=p2)
dataset["pdf_z"] = pdf_z
dataset["x_pdf_z"] = bins_center_pdf_z * 1e-6

plt.semilogy(bins_center_pdf_z, pdf_z, "o")
plt.plot(bins_center_pdf_z, P_b_off(bins_center_pdf_z * 1e-6, *popt_pdf), color="black")

plt.xlabel("z ($\mathrm{\mu m}$)")
plt.ylabel("P(z)  ($m^{-1}$)")
```

```python
offset_pdf, B_pdf, ld_offset, lb_offset = popt_pdf
```

We write the diffusion function.

```python
def Dz_z(z, off):
    off = off * 1e-6
    z = z - off
    result = (6 * z * z + 2 * r * z) / (6 * z * z + 9 * r * z + 2 * r * r)
    return result

def Dx_z_off(z, offset):
    offset = offset * 1e-6
    z = z + offset
    result = (
        1
        - 9 / 16 * (r / (z + r))
        + 1 / 8 * (r / (z + r)) ** 3
        - 45 / 256 * (r / (z + r)) ** 4
        - 1 / 16 * (r / (z + r)) ** 5
    )
    return result
```

## Measuring the diffusion coefficient using the Frishman and Ronceray's method

```python
from scipy.io import loadmat

dataset["D_0"] = 4e-21 / (6 * np.pi * 0.001 * dataset["r"])
D = loadmat("diffusionAnalysis.mat")["diffusion"]
dataset["z_D"] = D[:, 0]
dataset["z_D_x"] = (D[:, 1] + D[:, 2]) / 2
dataset["z_D_z"] = D[:, 3]
```

```python
plt.plot(dataset["z_D"], dataset["z_D_x"] / dataset["D_0"], "o")
plt.loglog(dataset["z_D"], dataset["z_D_z"] / dataset["D_0"], "o")

zz = np.linspace(1e-8, 1e-5)
plt.plot(zz, Dz_z(zz, 0), "k")

plt.plot(zz, Dx_z_off(zz, 0), "k")
```

```python
def c_P_D(B, ld, lb, offset=None):
    if offset == None:
        offset = 0

    z = np.linspace(1e-9, 15e-6, 1000)

    P_D = Dz_z(z, offset) * Do * P_b_off(z, offset, B, ld, lb)

    return Dz_z(z, offset) * Do, P_D / np.trapz(P_D, z)

def _P_Dz_short_time(Dz, Dt, B, ld, lb, offset=None):
    if offset == None:
        offset = 0

    D_z, P_D = c_P_D(B, ld, lb, offset)

    P = np.trapz(
        P_D / np.sqrt(4 * np.pi * D_z * Dt) * np.exp(-(Dz ** 2) / (4 * D_z * Dt)), D_z
    )

    return P

def P_Dz_short_time(Dz, Dt, B, ld, lb, offset=None):
    if offset == None:
        offset = 0

    P = [_P_Dz_short_time(i, Dt, B, ld, lb, offset=offset) for i in Dz]
    P = np.array(P)
    P = P / np.trapz(P, Dz)

    return P
```

# Fit everything in the same time !

Finaly we can fit everything in the same time to recap we have :

   - MSD x and MSD y => $< D >$
   - MSD z => $< D >$
   - mean $< D >$ with the pdf
   - Long time pdf $\Delta z$ => $l_d,l_b,B$
   - Pdf z => $offset,l_d,l_b, B$
   - D parallel, perp => offset

The minimizer $\chi ^2$ we are going to optimize can be written as :
\begin{equation} \chi^2 = \sum _{n = 1} ^{N} \chi_n^2 \end{equation}\begin{equation} \chi_n^2 = \sum^A(n) _i = 1 \frac{1}{\sigma_{ni}}(y_{ni} - y_n(x_{ni},\boldsymbol{a}))^2 \end{equation}

with $\sigma_{ni}$ the uncertainty (can be set to 1), A the number of point in the dataset for each function, $y_n$, nth equation, $\boldsymbol{a}$ the fit parameters

We have nonlinear functions so we can use the Marquardt to optimize or Nelder-Mead methods to optimize the minimizer.

```python
def minimizer_diffusion_coeff(mean_D_para, mean_D_perp, z_off, B, ld, lb):
    # minimization of the mean diffusion coefficient measurement with the PDF and MSD
    a = trapz(
        Dx_z_off(bins_center_pdf_z * 1e-6, z_off)
        * P_b_off(bins_center_pdf_z * 1e-6, z_off, B, ld, lb),
        bins_center_pdf_z,
    )
    b = trapz(
        Dz_z(bins_center_pdf_z * 1e-6, z_off)
        * P_b_off(bins_center_pdf_z * 1e-6, z_off, B, ld, lb),
        bins_center_pdf_z,
    )
    at = mean_Dx
    bt = mean_Dz
    return (a - at) ** 2 / at ** 2 + (b - bt) ** 2 / bt ** 2

dataset["z"] = z_dedrift
dataset["x"] = x
dataset["y"] = y

def minimizer_Dz_small_t(B, ld, lb):
    xi = 0

    for n, i in enumerate([1, 2, 3]):
        Dezs = (dataset["z"][0:-i] - dataset["z"][i:]) * 1e-6
        Dezs = Dezs  # - np.mean(Dezs)

        hist, bins_center = pdf(Dezs[~np.isnan(Dezs)], bins=30)
        hist = hist / np.trapz(hist, bins_center)

        Dz_th = bins_center
        PPP = P_Dz_short_time(Dz_th, time[i], B, ld, lb)

        # xi = xi + np.nanmean((((np.abs(hist) - (PPP) ) ) ** 2) / ((np.abs(hist)**2)))
        xi = xi + np.nanmean(
            ((hist[hist > 0] - PPP[hist > 0]) ** 2) / hist[hist > 0] ** 2
        )
    return xi
```

```python
dataset["D_para"] = mean_Dx
dataset["D_perp"] = mean_Dz

def minimizer(x, *args):
    data = dataset
    ld = x[0]
    lb = x[1]
    B = x[2]
    offset_dif = x[3]

    chi_mean_D_pdf = minimizer_diffusion_coeff(
        dataset["D_para"], dataset["D_perp"], 0, B, ld, lb
    )
    chi_MSD_plateau = minimize_plateau([B, ld, lb])

    E_longtime_pdf = (Pdeltaz_long(data["x_pdf_longtime"], B, ld, lb)) - (
        data["pdf_longtime"]
    )
    chi_longtime_pdf = np.mean(
        (E_longtime_pdf[E_longtime_pdf > -np.inf] ** 2)
        / (((Pdeltaz_long(data["x_pdf_longtime"], B, ld, lb))) ** 2)
    )

    E_chi_pdf_z = P_b_off(data["x_pdf_z"], 0, B, ld, lb) - data["pdf_z"]
    chi_pdf_z = np.nanmean(
        (E_chi_pdf_z[E_chi_pdf_z > -np.inf] ** 2)
        / ((P_b_off(data["x_pdf_z"], 0, B, ld, lb)) ** 2)
    )

    E_D_z = (Dz_z(data["z_D"], offset_dif)) - (data["z_D_z"] / Do)
    chi_D_z = np.mean(
        (E_D_z[E_D_z > -np.inf] ** 2) / ((Dz_z(data["z_D"], offset_dif)) ** 2)
    )

    E_D_x = (Dx_z_off(data["z_D"], offset_dif)) - (data["z_D_x"] / Do)
    chi_D_x = np.mean(
        (E_D_x[E_D_x > -np.inf] ** 2) / ((Dx_z_off(data["z_D"], offset_dif)) ** 2)
    )

    chi_Dz_small_t = minimizer_Dz_small_t(B, ld, lb)

    summ = (
        chi_mean_D_pdf
        + chi_MSD_plateau
        + chi_longtime_pdf
        + chi_pdf_z
        + chi_D_z
        + chi_D_x
        + chi_Dz_small_t
    )

    return summ
```

```python
B = 5
ld = ld_offset
x0 = [ld, 550, B, 0, offset_pdf]
```

```python
from scipy.optimize import leastsq

options = {
    "maxc1or": 30,
    "ftol": 2.2e-10,
    "gtol": 1e-5,
    "eps": 1e-08,
    "maxfun": 15000,
    "maxiter": 15000,
    "maxls": 20,
    "finite_diff_rel_step": None,
}

res = minimize(
    minimizer,
    x0,
    method="BFGS",
    tol=1e-1,
)
```

```python
res.x
results = {
    "ld": res.x[0],
    "lb": res.x[1],
    "B": res.x[2],
    "offset_diffusion": res.x[3],
}

results
```

    {'ld': 25.53322987706852,
     'lb': 549.9956782843908,
     'B': 4.856896668800334,
     'offset_diffusion': 0.0019089236000464675}

This final result has been used to plot theories along the manuscript.


```python
import numpy as np
np.random.seed(100) # Set the seed for reproducibility

import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams["font.family"] = "serif"
rcParams["font.serif"] = "Times New Roman"
%matplotlib inline
rcParams['text.usetex'] = True
rcParams['text.latex.preamble'] = [r'\usepackage{amsmath} \usepackage{bm} \usepackage{physics}']
%config InlineBackend.figure_format = 'retina' # For high quality figures
```

# $\chi^2$ (chi-squared) minimization

## Week 4, Intro-to-Astro 2020
### Written by Joey Murphy, June 2020
### Adapted from lecture notes by Ian Czekala

## Statistics and astronomy
* Astronomers rely heavily on statistical techniques for data analysis
* *But* physics/astronomy curricula usually neglect foundational courses in statistics and probability theory
* Highly recommend taking courses in these areas if available at your school!
* List of useful references at the end

## $\chi^2$ minimization
* In the *Methods* sections of any astronomy/astrophysics paper, there is almost always some model being fit to noisy data (physical or simulated)
* After reading a couple of papers, you'll likely run into the phrase "the best-fitting model..."
* Sometimes authors report something like "the best-fitting model has $\chi^2 = \:$ xyz" or say that the *minimum* $\chi^2$ value is xyz (where $\chi$ is the Greek letter "chi")

## What is $\chi^2$ and why is it being minimized?

What does "best-fitting" actually mean? "Best" as measured how?

* First we need to talk about
    * Measurement errors (uncertainties)
    * Probability density functions
    * Likelihood

## Measurement errors (uncertainties)

* Any measurement (whether it's your height, the voltage across a resistor, or the position of a star) has inherent error
* The size and source of this error is related to how the measurement was made
    * *Question:* What's one source of error you might encounter when measuring your height?
    * *Question:* What's one source of error you might encounter when measuring the poisition of a star on the sky? (like Gaia)

## Measurement errors (uncertainties)
* Let's consider the task of measuring the length (in cm!) of a house key using a ruler
* The ruler has tick marks for milimeters and centimeters

## Measurement errors (uncertainties)
* For this example, let's assume the error on each measurement is about 0.05 cm (i.e. half of the width between the finest tick marks)
* You take a handful of measurements of the key and get a collection of values that are similar, but not exactly the same
* Why different values?
    * Maybe the key isn't always lined up at the edge of the ruler
    * Maybe you're looking at the ruler from a different angle
    * etc...

**What is the best-fitting value for the true length of the key, given our measurements?**

## Measurement errors (uncertainties)
* Let's "take" some measurements and then make a plot to visualize their scatter

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

# Generate the measurement data
mu_key    = 6.0  # cm. The *actual* length of the key (unknown to us)
sigma_key = 0.05 # cm. Uncertainty on each measurement, based on the tick marks on our ruler
n_measure = 100  # Take 100 measurements
X = np.random.normal(mu_key, sigma_key, n_measure) # Generate the "measurements"
```

```python
# Plot the data
plt.plot(np.arange(n_measure), X, '.', label='Measured value')
plt.plot(np.arange(n_measure), mu_key * np.ones(n_measure), '--', alpha=0.5, label='True value')

plt.xlabel('Measurement number', fontsize=14)
plt.ylabel('Length [cm]', fontsize=14)
plt.legend(fontsize=14, framealpha=0.3)

plt.show()
```

Let's look back at how the "measurements" were generated in the previous plot.

Here's the line we used to create the data:

```python
X = np.random.normal(mu_key, sigma_key, n_measure) # Generate the "measurements"
```

The call to np.random.normal "draws" n_measure values randomly from a *Gaussian* (i.e. "Normal") probability distribution, centered at value mu_key and of width sigma_key.

In probability theory, this is written as

\begin{align}
X & \sim \mathcal{N}(\mu_\mathrm{key}, \sigma^2_\mathrm{key})
\end{align}

where the tilde ($\sim$) says that the data, $X$, is *drawn from* a Normal distribution ($\mathcal{N}$) with *mean* $\mu_\mathrm{key}$ and *standard deviation* $\sigma_\mathrm{key}$.

(n.b. $\sigma^2$ is referred to as the *variance*, and can sometimes be more convenient to use than $\sigma$ itself.)

Here we are *assuming* our measurements to be *Gaussian random variables*. In many cases, this is usually a reasonable assumption.

## Probability density functions
* How do we describe a probability distribution with a mathematical function?
* A *probability density function* (sometimes abbreviated as pdf) describes the relative likelihood of observing data at different locations in the domain
* For $\mathcal{N}(\mu, \sigma^2)$, the mathematical form of the probability density function is

\begin{align}
p(x | \mu, \sigma^2) & = \frac{1}{\sigma \sqrt{2 \pi}} \mathrm{exp}\Big[-\frac{1}{2} \big(\frac{x-\mu}{\sigma}\big)^2  \Big]
\end{align}

The left-hand side of the equation reads: the likelihood of observing the datum, $x$, *given* (vertical bar) mean, $\mu$, and variance $\sigma^2$. i.e. if we *know* the mean and variance of the Normal distribution that describes the data, we can calculate the relatively probability of observing $x$ using the righ-hand side of the equation.

## Probability density functions

Let's make a plot of the probability density function for the distribution that describes our measurements of the house key. On the same plot, let's show the histogram of the data we actually observered.

```python
def gaussian_pdf(x, mu=0, sigma=1):
    '''
    A gaussian pdf. Units of 1/x.

    Args
    ----------
    x (float): Location to evaluate the gaussian pdf.
    mu (float): Optional, default = 0. Mean of the gaussian.
    sigma (float): Optional, default = 1. Standard deviation.

    Returns
    ----------
    float: N(mu, sigma) evaluated at x.
    '''
    assert sigma > 0, "Standard deviation must be positive."
    return (1 / np.sqrt(2 * np.pi) / sigma) * np.exp(-0.5 * ((x - mu)/sigma)**2)
```

```python
x = np.linspace(5.75, 6.25, 100)
pdf = gaussian_pdf(x, mu = mu_key, sigma = sigma_key)

fig, ax = plt.subplots()
pdf_label = '$\mu = \:$' + f'{mu_key} cm' + '\n' + '$\sigma = \:$' + f'{sigma_key} cm'
pdf_line = ax.plot(x, pdf, '--', label=pdf_label)
ax1 = ax.twinx() # Different y-axes but same x-axis for pdf plot and histogram
hist_label = 'Data'
hist = ax1.hist(X, label=hist_label, color='orange', alpha=0.6, bins=15)

ax.set_xlabel('Length [cm]', fontsize=14)
ax.set_ylabel('PDF [cm$^{-1}$]', fontsize=14)
ax1.set_ylabel('N', fontsize=14)
ax.legend(fontsize=14, loc='upper left')
ax1.legend(fontsize=14, loc='upper right')
plt.show()
```

## Likelihood

* So now that we have a probabilistic distribution, $\mathcal{N}(\mu_\mathrm{key}, \sigma^2_\mathrm{key})$, that we think describes the data, $X$, we might ask ourselves:
    * What is the *likelihood* (i.e. probability) of observing our *collection* of measurements, given  $\mu_\mathrm{key}$ and $\sigma^2_\mathrm{key}$?

If the measurements are *independent* (i.e. One measurement has no impact on the outcome of another. Think flipping a coin) then the likelihood of the data is

\begin{align}
\mathcal{L} = \Pi_i^N p(x_i | \mu_\mathrm{key}, \sigma^2_\mathrm{key})
\end{align}

where $\Pi$ means product. i.e. Multiply together all of the individual probabilities for each measurement.

## Likelihood

Often, it's convenient to work with the natural logarithm of the likelihood, since the logarithm of a product is the sum of the logarithms of each factor. The "log-likelihood" is then

\begin{align}
\mathrm{ln} \mathcal{L} & = \Sigma_i^N \mathrm{ln}\Big[ p(x_i | \mu_\mathrm{key}, \sigma^2_\mathrm{key}) \Big]
\end{align}

Plugging in for $p(x_i | \mu_\mathrm{key}, \sigma^2_\mathrm{key})$ and doing some algebra, we have

\begin{align}
\mathrm{ln} \mathcal{L} & = \Sigma_i^N \mathrm{ln}\Big[ \frac{1}{\sigma_\mathrm{key} \sqrt{2 \pi}} \mathrm{exp}\Big[-\frac{1}{2} \big(\frac{x_i-\mu_\mathrm{key}}{\sigma_\mathrm{key}}\big)^2  \Big] \Big] \\
& = \Sigma_i^N \mathrm{ln}\Big[ \frac{1}{\sigma_\mathrm{key} \sqrt{2 \pi}} \Big] + \mathrm{ln}\Big[ \mathrm{exp}\Big[-\frac{1}{2} \big(\frac{x_i-\mu_\mathrm{key}}{\sigma_\mathrm{key}}\big)^2  \Big] \Big] \\
& = \Sigma_i^N \mathrm{ln}\Big[ \frac{1}{\sigma_\mathrm{key} \sqrt{2 \pi}} \Big] + \Big[-\frac{1}{2} \big(\frac{x_i-\mu_\mathrm{key}}{\sigma_\mathrm{key}}\big)^2  \Big]
\end{align}

## Likelihood

\begin{align}
\mathrm{ln} \mathcal{L} & = \Sigma_i^N \mathrm{ln}\Big[ \frac{1}{\sigma_\mathrm{key} \sqrt{2 \pi}} \Big] + \Big[-\frac{1}{2} \big(\frac{x_i-\mu_\mathrm{key}}{\sigma_\mathrm{key}}\big)^2  \Big]
\end{align}

Notice that the first term in the sum doesn't depend on the summation index, $i$, so we can get rid of it and replace the equality with proportionality:

\begin{align}
\mathrm{ln} \mathcal{L} & \propto \Sigma_i^N \Big[-\frac{1}{2} \big(\frac{x_i-\mu_\mathrm{key}}{\sigma_\mathrm{key}}\big)^2  \Big]
\end{align}

Let's define $\chi^2 \equiv \Sigma_i^N \big(\frac{x_i - \mu_\mathrm{key}}{\sigma_\mathrm{key}}\big)^2$. Then we have

\begin{align}
\mathrm{ln} \mathcal{L} & \propto -\frac{1}{2} \chi^2
\end{align}

$\chi^2$ is related to the log-likelihood of our data!

## $\chi^2$ minimization

Finally we've found out what $\chi^2$ is
\begin{align}
\chi^2 & \equiv \Sigma_i^N \big(\frac{x_i - \mu_\mathrm{key}}{\sigma_\mathrm{key}}\big)^2
\end{align}

and how it's related to the (log) likelihood of our data

\begin{align}
\mathrm{ln} \mathcal{L} & \propto -\frac{1}{2} \chi^2
\end{align}

after we made some assumptions about the underlying probability distribution that describes our measurements.

**What is the best-fitting value for the true length of the key, given our data?**

We want to *maximize* the log-likelihood of observing our data with respect to $\mu_\mathrm{key}$ (since, after all, it's what we observed). This corresponds to *minimizing* the $\chi^2$ metric.

## $\chi^2$ minimization

How to find the extremum? Take the derivative and set it equal to zero!

\begin{align}
\frac{d \mathrm{ln}\mathcal{L}}{d \mu_\mathrm{key}} \Big|_{\hat{\mu}_\mathrm{key}} = \Sigma_i^N \frac{x_i - \hat{\mu}_\mathrm{key}}{\sigma_\mathrm{key}^2} = 0,
\end{align}

where $\hat{\mu}_\mathrm{key}$ is the most likely or best-fitting value for our estimate of the true length of the key, given our data. Rearranging, we have

\begin{align}
\hat{\mu}_\mathrm{key} & = \frac{1}{N} \Sigma_i^N x_i.
\end{align}

In other words, in this special case where $\sigma^2_\mathrm{key}$ was the same for every measurement, the best-fitting value of $\mu_\mathrm{key}$ is the average of all of our measurement values!

```python
# If we didn't do all of this analysis by hand, and just wanted to minimize chi^2 in code, what would that look like?
from scipy.optimize import minimize

def chi_squared(mu, sigma, data):
    '''
    Args
    ----------
    mu (float): Underlying mean of distribution (unknown to us).
    sigma (float): Measurement error.
    data (ndarray): Vector of observed data

    Returns
    ----------
    float: chi-squared value
    '''
    return np.sum(((data - mu)/sigma)**2)

mu_0 = 4.0 # cm. Our initial guess at the true length of the key, just from eye-balling it.
min_results = minimize(chi_squared, mu_0, args=(sigma_key, X)) # Minimize chi-squared with respect to mu

print(f"Best-fitting value of mu_key from chi-squared minimization = {min_results.x[0]:.3f} cm")
print(f"Average of the data = {np.average(X):.3f} cm")
```

    Best-fitting value of mu_key from chi-squared minimization = 5.996 cm
    Average of the data = 5.996 cm

## $\chi^2$ minimization

* Minimizing $\chi^2$ gave us the result we were expecting from the analysis we did by hand!
* If you remember how we generated the synthetic data, we gave the key a true length of 6.0 cm, so our estimate is right on target

## Conclusion

What did we just do?

* We wanted to estimate the true length of a house key, given some (uncertain) measurements
* Acquired the data (which had **uniform measurement errors**)
* Assumed that the **underlying distribution** that described the data was a **Gaussian**
* Assumed that the **measurements were independent**
* Wrote down an analytic form for the (log) likelihood of the data observed
* Minimized the $\chi^2$ metric (i.e. maximimized the likelihood of the observed data) with respect to the parameter of interest ($\mu_\mathrm{key}$)

## External resources

(List originally compiled by Ian Czekala)

* *Data Analysis: A Bayesian Tutorial*, by Sivia and Skilling [(link)](https://www.amazon.com/Data-Analysis-Bayesian-Devinderjit-Sivia/dp/0198568320/ref=sr_1_1?ie=UTF8&qid=1500081454&sr=8-1&keywords=data+analysis+a+bayesian+tutorial). This is a very useful “handbook” to work through as an introduction to Bayesian data analysis. I highly recommend this as a first text if you can access it through your school's online library.

* Hogg et al. 2010: *Fitting a line*. [(link)](https://arxiv.org/abs/1008.4686) An applied example of Bayesian analysis for the simple example of line fitting. The simple title belies how dense this paper actually is... beware!

* Hogg et al. 2012: *Probability calculus* [(link)](https://arxiv.org/abs/1205.4446) Good notes about what you can and cannot do with probability calculus.

* *Doing Bayesian Data Analysis*, by Kruschke [(link)](https://sites.google.com/site/doingbayesiandataanalysis/). A nice introductory text to Bayesian Analysis (with puppies!)

* *Bayesian Data Analysis*, by Gelman et al. [(link)](http://www.stat.columbia.edu/~gelman/book/) The definitive reference book on Bayesian analysis and hierarchical Bayesian analysis. A dense but worthwhile book.

```python

```