```python
from math import *
from scipy.integrate import dblquad
import numpy as np
from numpy import square as sqr
import matplotlib as mpl
import matplotlib.pyplot as plt
from copy import deepcopy
#import plotly.plotly as py
import sys,os
#sys.path.append(os.path.dirname(__file__), '..','Lib')
#sys.path.append(os.path.join('..','Lib'))
#from foxlink.stylelib.ase1_styles import ase1_sims_stl, ase1_runs_stl
#plt.style.use(ase1_runs_stl)
# Solvers for first order PDEs
#from sympy.solvers.pde import pdsolve
#from sympy import Function, diff, pprint, exp
#from sympy.abc import x,y
```

```python
xlink_methods_stl = {
    "axes.titlesize": 18,
    "axes.labelsize": 15,
    "lines.linewidth": 3,
    "lines.markersize": 10,
    "xtick.labelsize": 15,
    "ytick.labelsize": 15,
    "font.size": 15
}
plt.style.use(xlink_methods_stl)
```

```python
# Set parameters for partition function integration
# Geometric parameters
r = 1 # Distance between MT centers
a = 0 # Dot product between r unit vector and MT1 direction vector
b = 0 # Dot product between r unit vector and MT2 direction vector
d = -1 # Dot product between MT1 and MT2 direction vector
# Crosslinker parameters
k = 4.562 # spring constant of motors
ho = 0. # equilibrium length
c = 40. # Crosslinker affinity * fugacity
# System parameters
bt = 1. # beta
# MT parameters
hL = 10. # Half length of filaments
fs = 1. # Stall force of motors
ko = 1. # Turnover rate of motors
vo = 1. # Base velocity of motors
default_params = []
default_params_gen = [r, a, b, d, k, ho, c, bt, hL, fs, ko, vo]
```

```python
def create_param_list(var_list, index, base_params=default_params):
    param_list = []
    for v in var_list:
        params = deepcopy(base_params) # Copy over the default parameters
        params[index] = v # Change the distance between MTs
        param_list += [params] # Add to the param list used in integration steps
    return param_list
```

```python
def create_param_list_array( index = 0, p_range = [0,1], n=100, base_params=default_params,):
    p_list = np.linspace(p_range[0], p_range[1], n).tolist()
    param_list = create_param_list(p_list, index, base_params)
    return p_list, np.array(param_list)
```

```python
def para_force21(s1, s2, bp=default_params):
    return -k*(bp[0]*bp[2]+s2-s1*bp[3])
```

```python
def para_force12(s1, s2, bp=default_params):
    return k*(bp[0]*bp[1]-s1+s2*bp[3])
```

```python
def vel_force(s1, s2, bp=default_params):# bp = base_params
    # Only for second head at the moment
    alpha = 1. + 2.*(para_force12(s1,s2,bp)/bp[9])
    return 1./(1.+exp(-2.*alpha))
```

```python
def dvel_dforce(s1, s2, bp=default_params):# bp = base_params
    # Only for second head at the moment
    alpha = 1. + 2.*(para_force12(s1,s2,bp)/bp[9])
    return -k
```

# Force-velocity relation

```python
params = deepcopy(default_params_gen)
params[0] = 0
s2 = 0
s1 = np.linspace(-1, 1, 200).tolist()
vel = [vel_force(s, s2, params) for s in s1]
force = np.array([para_force21(s, s2, params) for s in s1])
fig, ax = plt.subplots(figsize=(10,7))
lin_vel = np.piecewise(force,
                         [force <-1., (force >= -1) & (force < 0), force >= 0],
                         [0, lambda force: params[11]*(1.+force/params[9]), 1])
ax.plot(force, lin_vel, label="Linear")
ax.plot(force, vel, label="Smoothed")
ax.axvline(x=0, color='r', linestyle='--', label="Zero force")
ax.set_xlabel("Normalized parallel force ($F_{\parallel}/F_s$)")
ax.set_ylabel("Normalized motor velocity ($v_g/v_o$)")
ax.set_ylim(0, 1.2)
ax.legend()
plt.show()
```

# Spring constant compare

```python
fs = 2.0
ks = .3
ho = 52.
sep = 25.
```

```python
def get_zrl_parallel_spring_const(ks, fs, ho, sep):
    a = sep*sep
    b = (ks*ks*(ho*ho - sep*sep)) + (fs*fs)
    c = -ks*ks*fs*fs

    ks_new = np.sqrt((-1.*b + np.sqrt((b*b)-(4.*a*c)))/(2.*a))
    return ks_new
```

```python
def get_zrl_spring_const(ks, fs, ho, sep):
    return ks*fs/(fs+(ho*ks))
```

```python
def get_nzrl_parallel_force(x, ks, ho, sep):
    return -1.*ks*x*(1.-(ho/np.sqrt(x*x + sep*sep)))
```

```python
def get_nzrl_force(h, ks, ho):
    return -1.*ks*(h-ho)
```

```python
#print(ks)
ks_new1 = 0.03715512882326001
ks_new2 = get_zrl_spring_const(ks, fs, ho, sep)
#print("Matching distance along filament for parallel:", fs/ks_new1)
#print("Matching distance for parallel:", np.sqrt((fs/ks_new1)**2+sep**2))
#print(get_zrl_parallel_force(fs/ks_new1, ks, ho, sep))

x = np.linspace(0,1.5*fs/ks_new1, 50)

fig, axarr = plt.subplots(2,2,figsize=(10,10))
axarr[0,0].plot(x, -ks_new1*x, label='rest length = 0 nm')
axarr[0,0].plot(x, get_nzrl_parallel_force(x,ks,ho,sep), label="rest length = {} nm".format(ho))
axarr[0,0].axhline(y=-fs, color='r', linestyle='--', label="Stall force")
axarr[0,0].set_xlabel('Distance along filament (nm)')
axarr[0,0].set_ylabel('Force parallel to filament(pN)')
axarr[0,0].set_title('Parallel force calculation\n(Parallel force match)')
axarr[0,0].legend()

axarr[0,1].plot(x, -ks_new1*x, label='rest length = 0 nm')
axarr[0,1].plot(x, get_nzrl_force(x,ks,ho), label="rest length = {} nm".format(ho))
axarr[0,1].axhline(y=-fs, color='r', linestyle='--', label="Stall force")
axarr[0,1].set_xlabel('Protein stretch(nm)')
axarr[0,1].set_ylabel('Force (pN)')
axarr[0,1].set_title('Total force calculation\n(Parallel force match)')
axarr[0,1].set_xlim(0,1.5*fs/ks_new1)
axarr[0,1].legend()
#axarr[0].set_ylim(-5, 0)

print(ks_new2)
#print("Matching distance along filament for parallel:", np.sqrt((fs/ks_new1)**2 - sep**2))
#print("Matching distance for general:", fs/ks_new2)
#print(get_zrl_parallel_force(fs/ks_new1, ks, ho, sep))
axarr[1,0].plot(x, -ks_new2*x, label='rest length = 0 nm')
axarr[1,0].plot(x, get_nzrl_parallel_force(x,ks,ho,sep), label="rest length = {} nm".format(ho))
axarr[1,0].axhline(y=-fs, color='r', linestyle='--', label="Stall force")
axarr[1,0].set_xlabel('Distance along filament (nm)')
axarr[1,0].set_ylabel('Force parallel to filament(pN)')
axarr[1,0].set_title('Parallel force calculation\n(Total force match)')
axarr[1,0].legend()
axarr[1,1].plot(x, -ks_new2*x, label='rest length = 0 nm')
axarr[1,1].plot(x, get_nzrl_force(x,ks,ho), label="rest length = {} nm".format(ho))
axarr[1,1].axhline(y=-fs, color='r', linestyle='--', label="Stall force")
axarr[1,1].set_xlabel('Protein stretch(nm)')
axarr[1,1].set_ylabel('Force (pN)')
axarr[1,1].set_title('Total force calculation\n(Total force match)')
axarr[1,1].set_xlim(0,1.5*fs/ks_new1)
axarr[1,1].legend()
#axarr[1].set_ylim(-5, 0)
plt.tight_layout()
```

```python
#print(ks)
ks_new1 = 0.03715512882326001
ks_new2 = get_zrl_spring_const(ks, fs, ho, sep)
#print("Matching distance along filament for parallel:", fs/ks_new1)
#print("Matching distance for parallel:", np.sqrt((fs/ks_new1)**2+sep**2))
#print(get_zrl_parallel_force(fs/ks_new1, ks, ho, sep))

x = np.linspace(0,1.5*fs/ks_new1, 50)

fig, axarr = plt.subplots(1,2,figsize=(10,5))
#axarr[0,0].plot(x, -ks_new1*x)
#axarr[0,0].plot(x, get_nzrl_parallel_force(x,ks,ho,sep))
#axarr[0,0].axhline(y=-fs, color='r', linestyle='--', label="Stall force")
#axarr[0,0].set_xlabel('Distance along filament (nm)')
#axarr[0,0].set_ylabel('Force parallel to filament(pN)')
#axarr[0,0].set_title('Parallel force calculation')
#axarr[0,1].plot(x, -ks_new1*x)
#axarr[0,1].plot(x, get_nzrl_force(x,ks,ho,sep))
#axarr[0,1].axhline(y=-fs, color='r', linestyle='--', label="Parallel force")
#axarr[0,1].set_xlabel('Protein stretch(nm)')
#axarr[0,1].set_ylabel('Force (pN)')
#axarr[0,1].set_title('Total force calculation')
#axarr[0,1].set_xlim(0,1.5*fs/ks_new1)
#axarr[0].set_ylim(-5, 0)

print(ks_new2)
#print("Matching distance along filament for parallel:", np.sqrt((fs/ks_new1)**2 - sep**2))
#print("Matching distance for general:", fs/ks_new2)
#print(get_zrl_parallel_force(fs/ks_new1, ks, ho, sep))
axarr[1,0].plot(x, -ks_new2*x)
axarr[1,0].plot(x, get_nzrl_parallel_force(x,ks,ho,sep))
axarr[1,0].axhline(y=-fs, color='r', linestyle='--', label="Parallel force")
axarr[1,0].set_xlabel('Distance along filament (nm)')
axarr[1,0].set_ylabel('Force parallel to filament(pN)')
axarr[1,0].set_title('Parallel force calculation')
axarr[1,1].plot(x, -ks_new2*x)
axarr[1,1].plot(x, get_nzrl_force(x,ks,ho,sep))
axarr[1,1].axhline(y=-fs, color='r', linestyle='--', label="Parallel force")
axarr[1,1].set_xlabel('Protein stretch(nm)')
axarr[1,1].set_ylabel('Force (pN)')
axarr[1,1].set_title('Total force calculation')
axarr[1,1].set_xlim(0,1.5*fs/ks_new1)
#axarr[1].set_ylim(-5, 0)
plt.tight_layout()
```

# Solutions to steady state

```python
phi = Function('phi')
```

```python
s1_arr = np.asarray([3,5,8])
s2_arr = np.asarray([4,12,15])
print(s1_arr)
print(s2_arr)
```

    [3 5 8]
    [ 4 12 15]

```python
Y,X = np.meshgrid(s2_arr, s1_arr)
```

```python
print(X)
print(Y)
c = np.sqrt(np.power(X,2)+np.power(Y,2))

```

    [[3 3 3]
     [5 5 5]
     [8 8 8]]
    [[ 4 12 15]
     [ 4 12 15]
     [ 4 12 15]]

```python
import time
a = np.linspace(0,1,1000)
b = np.linspace(1,2,1000)
X, Y = np.meshgrid(a,b)
t0 = time.time()
c = np.sqrt(np.power(X,2)+np.power(Y,2))
t1 = time.time()
print("Total time: ", t1-t0)
```

    ('Total time: ', 0.057057857513427734)

```python
t0 = time.time()
c = np.exp(np.power(np.sqrt(np.power(X,2)+np.power(Y,2))-.1,2))
t1 = time.time()
print("Total time: ", t1-t0)
```

    ('Total time: ', 0.06903910636901855)

```python
print(c)
d = np.asarray([1,2,3])
e = np.outer(d,c)
print(e.shape)
```

    [[  2.24790799   2.24791001   2.2479161  ...,   5.60377387   5.61419277
        5.62464192]
     [  2.25196418   2.25196621   2.2519723  ...,   5.61421368   5.6246524
        5.63512141]
     [  2.25603221   2.25603425   2.25604035 ...,   5.62468382   5.6351424
        5.64563134]
     ...,
     [ 36.68604364  36.68607856  36.68618332 ...,  94.75736446  94.93847648
       95.12011845]
     [ 36.82574519  36.82578025  36.82588541 ...,  95.12020949  95.30201844
       95.48435939]
     [ 36.96605281  36.966088    36.96619357 ...,  95.48463357  95.6671425
       95.85018547]]
    (3, 1000000)

```python
s1 = np.arange(5)
s2 = np.arange(5,9)
print(s1, s2)
u1=np.asarray([1,0,0])
u2=np.asarray([0,1,0])
S2, S1 = np.meshgrid(s2,s1)
```

    (array([0, 1, 2, 3, 4]), array([5, 6, 7, 8]))

```python
hvec = S2[:,:,None]*u2[None,None,:]-S1[:,:,None]*u1[None,None,:]
print(hvec)
```

    [[[ 0  5  0]
      [ 0  6  0]
      [ 0  7  0]
      [ 0  8  0]]

     [[-1  5  0]
      [-1  6  0]
      [-1  7  0]
      [-1  8  0]]

     [[-2  5  0]
      [-2  6  0]
      [-2  7  0]
      [-2  8  0]]

     [[-3  5  0]
      [-3  6  0]
      [-3  7  0]
      [-3  8  0]]

     [[-4  5  0]
      [-4  6  0]
      [-4  7  0]
      [-4  8  0]]]

```python
A = np.linalg.norm(hvec, axis=2)
print(A)
```

    [[ 5.          6.          7.          8.        ]
     [ 5.09901951  6.08276253  7.07106781  8.06225775]
     [ 5.38516481  6.32455532  7.28010989  8.24621125]
     [ 5.83095189  6.70820393  7.61577311  8.54400375]
     [ 6.40312424  7.21110255  8.06225775  8.94427191]]

```python
B = np.ones((5,4,3))
B[:,:,1]*=2
B[:,:,2]*=3
print(B)
```

    [[[ 1.  2.  3.]
      [ 1.  2.  3.]
      [ 1.  2.  3.]
      [ 1.  2.  3.]]

     [[ 1.  2.  3.]
      [ 1.  2.  3.]
      [ 1.  2.  3.]
      [ 1.  2.  3.]]

     [[ 1.  2.  3.]
      [ 1.  2.  3.]
      [ 1.  2.  3.]
      [ 1.  2.  3.]]

     [[ 1.  2.  3.]
      [ 1.  2.  3.]
      [ 1.  2.  3.]
      [ 1.  2.  3.]]

     [[ 1.  2.  3.]
      [ 1.  2.  3.]
      [ 1.  2.  3.]
      [ 1.  2.  3.]]]

```python
C = A[:,:,None]*B[:,:,:]
```

```python
print(C)
```

    [[[  5.          10.          15.        ]
      [  6.          12.          18.        ]
      [  7.          14.          21.        ]
      [  8.          16.          24.        ]]

     [[  5.09901951  10.19803903  15.29705854]
      [  6.08276253  12.16552506  18.24828759]
      [  7.07106781  14.14213562  21.21320344]
      [  8.06225775  16.1245155   24.18677324]]

     [[  5.38516481  10.77032961  16.15549442]
      [  6.32455532  12.64911064  18.97366596]
      [  7.28010989  14.56021978  21.84032967]
      [  8.24621125  16.4924225   24.73863375]]

     [[  5.83095189  11.66190379  17.49285568]
      [  6.70820393  13.41640786  20.1246118 ]
      [  7.61577311  15.23154621  22.84731932]
      [  8.54400375  17.08800749  25.63201124]]

     [[  6.40312424  12.80624847  19.20937271]
      [  7.21110255  14.4222051   21.63330765]
      [  8.06225775  16.1245155   24.18677324]
      [  8.94427191  17.88854382  26.83281573]]]

```python
print(C.sum(axis=(0,1)))
```

    [ 138.870838    277.74167599  416.61251399]

```python
v = np.asarray([[1,0,0],[0,1,0],[0,0,1],[1,0,0]])
print(v)
```

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

```python
D = np.cross(v,C)
```

```python
print(D)
```

    [[[  0.         -15.          10.        ]
      [ 18.           0.          -6.        ]
      [-14.           7.           0.        ]
      [  0.         -24.          16.        ]]

     [[  0.         -15.29705854  10.19803903]
      [ 18.24828759   0.          -6.08276253]
      [-14.14213562   7.07106781   0.        ]
      [  0.         -24.18677324  16.1245155 ]]

     [[  0.         -16.15549442  10.77032961]
      [ 18.97366596   0.          -6.32455532]
      [-14.56021978   7.28010989   0.        ]
      [  0.         -24.73863375  16.4924225 ]]

     [[  0.         -17.49285568  11.66190379]
      [ 20.1246118    0.          -6.70820393]
      [-15.23154621   7.61577311   0.        ]
      [  0.         -25.63201124  17.08800749]]

     [[  0.         -19.20937271  12.80624847]
      [ 21.63330765   0.          -7.21110255]
      [-16.1245155    8.06225775   0.        ]
      [  0.         -26.83281573  17.88854382]]]

```python
u = np.asarray([1,2,3])
uu = np.outer(u,u)
print(uu)
```

    [[1 2 3]
     [2 4 6]
     [3 6 9]]

```python
np.power(uu,2)
```

    array([[ 1,  4,  9],
           [ 4, 16, 36],
           [ 9, 36, 81]])

```python
Iish = np.eye(3)
print(Iish)
```

    [[ 1.  0.  0.]
     [ 0.  1.  0.]
     [ 0.  0.  1.]]

# Source testing

```python
cmap = mpl.cm.ScalarMappable( mpl.colors.Normalize(0, 50), 'viridis')
fig, ax = plt.subplots()
print(cmap.to_rgba(25))
#ax.plot(np.linspace(0,10), np.linspace(0,10)*10)
fig.colorbar(cmap, ax=ax)

```

```python
mat = np.ones((200,200))
#mat = np.arange(81).reshape(9,9)
print(mat)
#mat_new = mat.reshape(3,3,3,3)
mat_new = mat.reshape(20,10,20,10)
print(mat_new)
mat_coarse = mat_new.sum(axis=(1,3))
print(mat_coarse)
print(mat_coarse.shape)
```

    [[1. 1. 1. ... 1. 1. 1.]
     [1. 1. 1. ... 1. 1. 1.]
     [1. 1. 1. ... 1. 1. 1.]
     ...
     [1. 1. 1. ... 1. 1. 1.]
     [1. 1. 1. ... 1. 1. 1.]
     [1. 1. 1. ... 1. 1. 1.]]
    [[[[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      ...

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]]

     [[[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      ...

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]]

     [[[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      ...

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]]

     ...

     [[[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      ...

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]]

     [[[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      ...

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]]

     [[[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      ...

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]

      [[1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       ...
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]
       [1. 1. 1. ... 1. 1. 1.]]]]
    [[100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]
     [100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100. 100.
      100. 100. 100. 100. 100. 100.]]
    (20, 20)

```python

```


```python
import numpy as np
import matplotlib.pyplot as plt
from data.load_from_csv import get_content_datasets
import pandas as pd
import theano
from datetime import datetime
from src.models.baselines.baseline_utils import run_baseline
import pymc3 as pm

% matplotlib inline
```

    /Users/zac/miniconda3/envs/psj/lib/python3.5/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
      from ._conv import register_converters as _register_converters

# Hierarchical linear model of responses to questions

This notebook contains a hierarchical linear model of responses over time. For each question the responses are pooled across users, so user identity is lost. Although this is clearly suboptimal, our attempts so far to make use of user identity have not succeeded. Additionally, we don't attempt to learn a covariance between slope and intercept; both are allowed to vary freely. I have tried introducing this and it decreases predictive performance.

The model is as follows:

Hyperprior:

$$
\begin{align}
\rho_{\alpha}&\sim\mathcal{N}(0.5, 2) \\
\omega_{\alpha}&\sim\textrm{HalfCauchy}(2) \\
\rho_{\beta}&\sim\mathcal{N}(0.5, 2) \\
\omega_{\beta}&\sim\textrm{HalfCauchy}(2) \\
\epsilon&\sim\textrm{HalfCauchy}(0.5)
\end{align}
$$

Question-level (for each question $q_{i}$):

$$
\begin{align}
\alpha_{i}&\sim\mathcal{N}(\rho_{\alpha},\omega_{\alpha}) \\
\beta_{i}&\sim\mathcal{N}(\rho_{\beta},\omega_{\beta})
\end{align}
$$

Observation model (linear regression with intercept $\alpha$ and slope $\beta$):

$$
y_{t}\sim\mathcal{N}(\alpha + \beta t, \epsilon)
$$

## Load and process dataset

```python
datasets = get_content_datasets(task='fermi', sparsity='unmasked')
train_dataset, val_dataset, test_dataset = datasets
```

```python
def make_df(dataset):
    users = []
    questions = []
    times = []
    opinions = []

    for datum in dataset:
        for i, rating in enumerate(datum['rating']):
            if not np.isnan(rating):
                users.append(datum['user_id'])
                questions.append(datum['item_id'])
                times.append(i)
                opinions.append(rating)

    data = pd.DataFrame(data={'user':users,
                            'question': questions,
                            'time': times,
                            'opinion': opinions})

    return data
```

```python
data = make_df(train_dataset)
val_data = make_df(val_dataset)
test_data = make_df(test_dataset)
question_ids = data.question.unique()
question_idx = data['question'].values
```

## Define and sample simple hierarchical linear model

```python
param_len = max(np.concatenate([data.question.unique(), val_data.question.unique()]))+1
with pm.Model() as hierarchical_model:
    ## Top level hyperpriors
    rho_a = pm.Normal('rho_a', mu=0.5, sd=2.)
    omega_a = pm.HalfCauchy('omega_a', beta=2.)
    rho_b = pm.Normal('rho_b', mu=0., sd=2.)
    omega_b = pm.HalfCauchy('omega_b', beta=2.)

    ## Question level hyperpriors
    a = pm.Normal('alpha', mu=rho_a, sd=omega_a, shape=param_len)
    b = pm.Normal('beta', mu=rho_b, sd=omega_b, shape=param_len)

    eps = pm.HalfCauchy('eps', beta=0.5)
    opinion_est = a[question_idx] + b[question_idx] * data.time.values

    y_like = pm.Normal('y_like', mu=opinion_est, sd=eps, observed=data.opinion)

    trace = pm.sample(100, tune=100)
```

    Only 100 samples in chain.
    Auto-assigning NUTS sampler...
    Initializing NUTS using jitter+adapt_diag...
    Multiprocess sampling (2 chains in 2 jobs)
    NUTS: [eps_log__, beta, alpha, omega_b_log__, rho_b, omega_a_log__, rho_a]
    The acceptance probability does not match the target. It is 0.9449954620658936, but should be close to 0.8. Try to increase the number of tuning steps.
    The acceptance probability does not match the target. It is 0.9517394237473361, but should be close to 0.8. Try to increase the number of tuning steps.
    The gelman-rubin statistic is larger than 1.05 for some parameters. This indicates slight problems during sampling.
    The number of effective samples is smaller than 10% for some parameters.

## Traceplot

```python
pm.traceplot(trace)
plt.show()
```

## Plot posterior mean values of parameters

```python
alpha_pm = np.mean(trace['alpha'], axis=0)
beta_pm = np.mean(trace['beta'], axis=0)
fig, axes = plt.subplots(1)
axes.scatter(alpha_pm, beta_pm, alpha=0.25)
axes.set_xlabel('Intercept')
axes.set_ylabel('Slope')
plt.show()
```

There is clearly some information here; a moderately high intercept is correlated with a positive slope (vice versa for low intercepts). However, the fact that opinions are constrained to $[0,1]$ means that very high intercepts can only have small positive slope as there's not much room left to update in. This could be used to improve inference if we were presented with a novel question where we have only quick judgements.

## Posterior mean predictions

```python
num_samples = 1000

val_questions = test_data.question.unique()

targets = []
preds = []
for q_id in val_questions:
    val_q = test_data.loc[test_data.question == q_id]

    try:
        alpha_post = trace['alpha'][:, q_id]
        beta_post = trace['beta'][:, q_id]

        to_average = []
        for i in range(num_samples):
            alpha_sample = np.random.choice(alpha_post)
            beta_sample = np.random.choice(beta_post)
            to_average.append(np.clip(alpha_sample + beta_sample * 2, 0, 1))

        preds.append(np.mean(to_average))

    except IndexError:
        preds.append(0.5)

    targets.append(val_q.opinion.values[0])
```

```python
fig, axes = plt.subplots(1)
axes.scatter(targets, preds, alpha=0.25)
axes.set_xlabel('Ground truth')
axes.set_ylabel('Prediction')
fig.suptitle('Hierarchical linear regression')
plt.show()
```

```python
preds = np.array(preds)
targets = np.array(targets)
square_errs = np.power((preds - targets), 2)
print('MSE = ', np.mean(square_errs))
```

    MSE =  0.09814238748257287

So we're doing pretty well but not outstandingly - most of our gains come from predicting very high/low confidence questions well. There's a pretty clear noise floor if we ignore user identity, as the example below shows.

## Example plot

```python
q_id = 1190 # 1190 or 634 are the 'worst' examples

fig, axes = plt.subplots(1)
axes.set_ylim([-0.1, 1.1])

alpha_post = trace['alpha'][:, q_id]
beta_post = trace['beta'][:, q_id]

for i in range(1000):
    alpha_sample = np.random.choice(alpha_post)
    beta_sample = np.random.choice(beta_post)
    x = np.linspace(0, 2)
    y = alpha_sample + beta_sample * x
    axes.plot(x,y, alpha=0.01, c='b')

q_specific = data.loc[data.question == q_id]
jitter = np.random.normal(0, 0.01, size=len(q_specific.time))
val_q_specific = val_data.loc[val_data.question == q_id]

axes.scatter(q_specific.time + jitter, q_specific.opinion, c='k')
axes.scatter(val_q_specific.time, val_q_specific.opinion, c='r')
plt.show()
```

Here we can see that the majority of the training data is completely different to the validation datapoint in a way we really can't hope to predict. It's possible that the highest quick judgement is from the same user as the validation datapoint, so that by using user id we might hope to have predicted a lower value. When we mask we will typically lose this information, however.

## MSE vs response count

```python
num_samples = 100

val_questions = test_data.question.unique()

targets = []
preds = []
square_errs = []
num_train_points = []

for q_id in val_questions:
    train_q = data.loc[data.question == q_id]
    #print(q_id)
    #print(train_q)
    #print(len(train_q))
    val_q = test_data.loc[test_data.question == q_id]

    try:
        alpha_post = trace['alpha'][:, q_id]
        beta_post = trace['beta'][:, q_id]

        to_average = []
        for i in range(num_samples):
            alpha_sample = np.random.choice(alpha_post)
            beta_sample = np.random.choice(beta_post)
            to_average.append(np.clip(alpha_sample + beta_sample * 2, 0, 1))

        preds.append(np.mean(to_average))

    except IndexError:
        preds.append(0.5)

    targets.append(val_q.opinion.values[0])
    square_errs.append((preds[-1] - targets[-1])**2)
    num_train_points.append(len(train_q))
```

```python
fig, axes = plt.subplots(1)
square_errs = np.array(square_errs)
axes.scatter(num_train_points, square_errs, alpha=0.1)

means = []
for i in np.unique(num_train_points):
    use_idx = np.argwhere(num_train_points == i).squeeze()
    means.append(np.mean(square_errs[use_idx]))

axes.plot(np.unique(num_train_points), means, c='k', ls='--')
axes.set_xlabel('Datapoints in training set')
axes.set_ylabel('Squared error')
fig.suptitle('Unmasked data')

plt.show()
```

## As above but with binning

```python
from importlib import reload
import src.demos.notebook_utils as nu
reload(nu)
#from src.demos.notebook_utils import run_baseline

train_flat = train_dataset.flatten()
val_flat = val_dataset.flatten()
test_flat = test_dataset.flatten()

baseline_alg_str = 'KNN'

fermi_unmasked = {'min_k':1,
                  'user_based': True,
                  'sim': 'MSD',
                  'k': 6}

fermi_light = {'min_k':1,
               'user_based': True,
               'sim': 'MSD',
               'k': 3}

fermi_heavy = {'min_k':1,
               'user_based': True,
               'sim': 'MSD',
               'k': 6}

pfact_unmasked = {'min_k':1,
                  'user_based': True,
                  'sim': 'pearson_baseline',
                  'k': 1}

pfact_light = {'min_k':1,
               'user_based': True,
               'sim': 'cosine',
               'k': 1}

pfact_heavy = {'min_k':1,
               'user_based': True,
               'sim': 'MSD',
               'k': 3}

cf_algo_params = fermi_heavy

ans = nu.run_baseline(train_flat,
                      test_flat,
                      baseline_alg_str,
                      calibrate=True,
                      cf_algo_params=cf_algo_params)

train_loss, val_loss, val_ratings, val_pred, KNN_num_train_points = ans

KNN_square_errs = (val_pred - val_ratings)**2

fig, axes = plt.subplots(1)
axes.scatter(KNN_num_train_points, KNN_square_errs, alpha=0.1)
```

```python
fig, axes = plt.subplots(1)

def make_bars(square_errs, num_train_points):
    heights = [[], [], [], [], []]

    for i, num_vals in enumerate(num_train_points):
        if num_vals == 0:
            heights[0].append(square_errs[i])

        elif (num_vals >= 1 and num_vals < 6):
            heights[1].append(square_errs[i])

        elif (num_vals >= 6 and num_vals < 11):
            heights[2].append(square_errs[i])

        elif (num_vals >= 11 and num_vals < 16):
            heights[3].append(square_errs[i])

        else:
            heights[4].append(square_errs[i])

    return heights

bar_width=0.35
points = np.array([0,1,2,3,4])

heights = make_bars(square_errs, num_train_points)
MSEs = [np.mean(i) for i in heights]
sems = [np.std(i)/np.sqrt(len(i)) for i in heights]
stds = [np.std(i) for i in heights]

KNN_heights = make_bars(KNN_square_errs, KNN_num_train_points)
KNN_MSEs = [np.mean(i) for i in KNN_heights]
KNN_sems = [np.std(i)/np.sqrt(len(i)) for i in KNN_heights]
KNN_stds = [np.std(i) for i in KNN_heights]

axes.bar(points, MSEs, bar_width, yerr=sems, color='b', label='Linear')
axes.bar(points + bar_width, KNN_MSEs, bar_width, yerr=KNN_sems, color='r', label='KNN')
axes.set_xticks(points + bar_width / 2)
axes.set_xticklabels(['0', '1-5', '6-10', '11-16', '> 16'])
axes.set_xlabel('Number of responses in training set')
axes.set_ylabel('MSE')
axes.legend()
fig.suptitle('Fermi heavy masking')

text = ['{}: {}'.format(i, cf_algo_params[i]) for i in cf_algo_params]
text = ' '.join(text)
print(text)
axes.set_title(text)
plt.show()
```

## Checking out anomalously high MSE questions

```python
for i, num in enumerate(num_train_points):
    err = square_errs[i]

    if err > 0.5 and num > 20:
        print(i, num, err)
        q_id = val_questions[i]
        print('\nTraining samples')
        print(data.loc[data.question == q_id])
        print('\nTest samples')
        print(val_data.loc[val_data.question == q_id])
```

    174 21 0.5819202039109389

    Training samples
           opinion  question  time  user
    220       0.30      1380     0     6
    221       0.35      1380     1     6
    222       0.00      1380     2     6
    2661      0.40      1380     0    74
    2662      0.00      1380     1    74
    2663      0.00      1380     2    74
    9795      0.25      1380     0   357
    9796      0.40      1380     1   357
    9797      0.05      1380     2   357
    11790     0.75      1380     0   453
    11791     0.85      1380     1   453
    11792     1.00      1380     2   453
    12548     0.75      1380     0   486
    12549     0.00      1380     1   486
    12550     0.00      1380     2   486
    12925     0.25      1380     0   501
    12926     0.00      1380     1   501
    12927     0.00      1380     2   501
    13239     0.50      1380     0   525
    13240     0.15      1380     1   525
    13241     0.10      1380     2   525

    Test samples
    Empty DataFrame
    Columns: [opinion, question, time, user]
    Index: []

```python
question_id = 1100

for datum in val_dataset:
    if datum['item_id'] == question_id:
        print(datum)
```

    {'item_id': 1100, 'rating': array([nan, nan,  0.]), 'user_id': 131, 'item_text': 'worldwide box office for Jurassic World in USD * Volume of a sphere with radius 1 units to nearest cubic unit * 98 - perimeter of a square with side length six < 1,920,000,000,000', 'item_metadata': array([0.])}


# Spam Filter for SMS messages using Naive Bayes

The aim of this project, to classify messages as spam or non-spam, we saw in the previous mission that the computer:

1. Learns how humans classify messages.
2. Uses that human knowledge to estimate probabilities for new messages probabilities for spam and non-spam.
3. Classifies a new message based on these probability values if the probability for spam is greater, then it classifies the message as spam. Otherwise, it classifies it as non-spam (if the two probability values are equal, then we may need a human to classify the message).

```python
import pandas as pd
sms_spam = pd.read_csv("SMSSpamCollection", sep = '\t',header = None, names = ['Label', 'SMS'])

print(sms_spam.shape)
sms_spam.head()

```

    (5572, 2)

      Label
      SMS

      0
      ham
      Go until jurong point, crazy.. Available only ...

      1
      ham
      Ok lar... Joking wif u oni...

      2
      spam
      Free entry in 2 a wkly comp to win FA Cup fina...

      3
      ham
      U dun say so early hor... U c already then say...

      4
      ham
      Nah I don't think he goes to usf, he lives aro...

"ham" means non-spam

```python
sms_spam['Label'].value_counts(normalize=True)
```

    ham     0.865937
    spam    0.134063
    Name: Label, dtype: float64

- 87% of sms are non-spam.
- 13% of sms are spam

# Randomize the dataset

For this project, our goal is to create a spam filter that classifies new messages with an accuracy greater than 80% — so we expect that more than 80% of the new messages will be classified correctly as spam or ham.

## Training and Test Dataset

- Split the dataset into a training and test dataset
- 80% training and 20% test dataset

```python
data = sms_spam.sample(random_state=1, frac=1)

# identifing index to split data
# 80% data
spliting_index = round(len(data)*0.8)

# training dataset: upto spliting index
# test dataset: from spliting index
training_set = data[:spliting_index].reset_index(drop=True)
test_set = data[spliting_index:].reset_index(drop=True)

```

```python
print(training_set.shape)
print(test_set.shape)
```

    (4458, 2)
    (1114, 2)

```python
print("Training Dataset")
print(training_set['Label'].value_counts(normalize=True))
print("\n")
print("Test dataset")
print(test_set['Label'].value_counts(normalize=True))
```

    Training Dataset
    ham     0.86541
    spam    0.13459
    Name: Label, dtype: float64

    Test dataset
    ham     0.868043
    spam    0.131957
    Name: Label, dtype: float64

------

# Data Cleaning
- To bring the data in a format that will allow us to extract easily all the information we need.

Tasks to do:

1. Letter Case and Punctuation
    Remove all the punctuation and bring every letter to lower case.
2. Creating the Vocabulary
    A list with all the unique words in our training set.
3. Final Training Set
    Use the created vocabulary to make the data transformation we want
-----
### 1. Letter Case and Punctuation

```python
# check the dataset
training_set.head()
```

      Label
      SMS

      0
      ham
      Yep, by the pretty sculpture

      1
      ham
      Yes, princess. Are you going to make me moan?

      2
      ham
      Welp apparently he retired

      3
      ham
      Havent.

      4
      ham
      I forgot 2 ask ü all smth.. There's a card on ...

```python
# use \W to detect any character that is not from a-z, A-Z or 0-9.
training_set['SMS']= training_set['SMS'].str.replace('\W',' ')

#lower case
training_set['SMS']= training_set['SMS'].str.lower()

training_set.head()

```

      Label
      SMS

      0
      ham
      yep  by the pretty sculpture

      1
      ham
      yes  princess  are you going to make me moan

      2
      ham
      welp apparently he retired

      3
      ham
      havent

      4
      ham
      i forgot 2 ask ü all smth   there s a card on ...

### 2. Creating the Vocabulary

```python
training_set['SMS'] = training_set['SMS'].str.split()

vocab = []

for sms in training_set['SMS']:
    for word in sms:
        vocab.append(word)

vocabulary = list(set(vocab))

```

```python
len(vocabulary)
```

    7783

### 3. The Final training set

```python
# create an empty dictionary named "word_counts_per_sms"
# where key --> unique word, value --> 0
# [0]* 5 i.e. [0,0,0,0,0]
# here {(uw1,0),(uw2,0),..(last uw,0)}

word_counts_per_sms = {unique_word:[0] * len(training_set['SMS']) for unique_word in vocabulary}

# loop over index and SMS to count the occurence of word
# enumerate() function to get both the index and the SMS message

for index,sms in enumerate(training_set['SMS']):
    for word in sms:
        word_counts_per_sms[word][index] +=1

```

```python
# Transform word_counts_per_sms into a DataFrame

word_counts = pd.DataFrame(word_counts_per_sms)
word_counts.head()
```

      sharing
      republic
      checkboxes
      09061702893
      line
      47per
      holla
      arrival
      tomorw
      terrible
      ...
      ga
      away
      jod
      brisk
      okay
      hell
      kids
      09066358152
      describe
      darling

      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

      2
      0
      0
      0
      0
      0
      0
      0
      0
      0
      0
      ...
      0
      0
      0
      0
      0
      0
      0
      0
      0
      0

      3
      0
      0
      0
      0
      0
      0
      0
      0
      0
      0
      ...
      0
      0
      0
      0
      0
      0
      0
      0
      0
      0

      4
      0
      0
      0
      0
      0
      0
      0
      0
      0
      0
      ...
      0
      0
      0
      0
      0
      0
      0
      0
      0
      0

5 rows × 7783 columns

```python
# Concatenate the DataFrame we just built above with the DataFrame containing the training set. This way,
# we'll also have the Label and the SMS columns.
# axis = 1 to concatenate as column

final_training_data = pd.concat([training_set,word_counts], axis =1)
final_training_data.head()
```

      Label
      SMS
      sharing
      republic
      checkboxes
      09061702893
      line
      47per
      holla
      arrival
      ...
      ga
      away
      jod
      brisk
      okay
      hell
      kids
      09066358152
      describe
      darling

      0
      ham
      [yep, by, the, pretty, sculpture]
      0
      0
      0
      0
      0
      0
      0
      0
      ...
      0
      0
      0
      0
      0
      0
      0
      0
      0
      0

      1
      ham
      [yes, princess, are, you, going, to, make, me,...
      0
      0
      0
      0
      0
      0
      0
      0
      ...
      0
      0
      0
      0
      0
      0
      0
      0
      0
      0

      2
      ham
      [welp, apparently, he, retired]
      0
      0
      0
      0
      0
      0
      0
      0
      ...
      0
      0
      0
      0
      0
      0
      0
      0
      0
      0

      3
      ham
      [havent]
      0
      0
      0
      0
      0
      0
      0
      0
      ...
      0
      0
      0
      0
      0
      0
      0
      0
      0
      0

      4
      ham
      [i, forgot, 2, ask, ü, all, smth, there, s, a,...
      0
      0
      0
      0
      0
      0
      0
      0
      ...
      0
      0
      0
      0
      0
      0
      0
      0
      0
      0

5 rows × 7785 columns

- NSpam is equal to the number of words in all the spam messages — it's not equal to the number of spam messages, and it's not equal to the total number of unique words in spam messages.
- NHam is equal to the number of words in all the non-spam messages — it's not equal to the number of non-spam messages, and it's not equal to the total number of unique words in non-spam messages.
- NVocabulary is len(vocabulary)
- alpha = 1

```python
# P(Spam) and P(Ham)--> normalised value counts
#------------------------------------
p_spam = final_training_data['Label'].value_counts(normalize=True)['spam']
p_ham = final_training_data['Label'].value_counts(normalize=True)['ham']

# N_Spam, N_Ham, and N_Vocabulary -->
#-----------------------------
n_spam = final_training_data[final_training_data['Label']=="spam"].sum(axis = 1).sum()
n_ham = final_training_data[final_training_data['Label']=="ham"].sum(axis = 1).sum()
n_vocabulary = len(vocabulary)
alpha = 1

```

The probability values that P(wi|Spam) and P(wi|Ham) will take are called **parameters**.
\begin{equation}
P(w_i|Spam) = \frac{N_{w_i|Spam} + \alpha}{N_{Spam} + \alpha \cdot N_{Vocabulary}} \\
P(w_i|Ham) = \frac{N_{w_i|Ham} + \alpha}{N_{Ham} + \alpha \cdot N_{Vocabulary}}
\end{equation}

Step 1:

- Initialize two dictionaries, where each key-value pair is a unique word (from our vocabulary) represented as a string, and the value is 0. - One dictionary to store the parameters for P(wi|Spam), and the other for P(wi|Ham).

```python

```

```python
# ['sea', 'navigate'] should look like this: {'sea': 0, 'navigate': 0}

parameters_spam = {unique_word:0 for unique_word in vocabulary}
parameters_ham = {unique_word:0 for unique_word in vocabulary}
```

Step 2:
- Isolate the spam and the ham messages in the training set into two different DataFrames. The Label column will help you isolate the messages.

```python
spam_msgs = final_training_data[final_training_data['Label']=='spam']
ham_msgs = final_training_data[final_training_data['Label']== 'ham']

```

Step 3:
- Calculate parameters using this:
\begin{equation}
P(w_i|Spam) = \frac{N_{w_i|Spam} + \alpha}{N_{Spam} + \alpha \cdot N_{Vocabulary}} \\
P(w_i|Ham) = \frac{N_{w_i|Ham} + \alpha}{N_{Ham} + \alpha \cdot N_{Vocabulary}}
\end{equation}

```python
# N(wi|Spam)--> n_word_given_spam
# P(wi|Spam)--> p_word_given_spam
n_vocabulary = len(vocabulary)

for word in vocabulary:
    n_word_given_spam = spam_msgs[word].sum()
    p_word_given_spam = (n_word_given_spam + alpha)/(n_spam+(alpha* n_vocabulary))
    parameters_spam[word] = p_word_given_spam

    n_word_given_ham = ham_msgs[word].sum()
    p_word_given_ham = (n_word_given_ham + alpha)/(n_ham+(alpha* n_vocabulary))
    parameters_ham[word] = p_word_given_ham

```

## Classifying A New Message

The spam filter can be understood as a function that:

- Takes in as input a new message (w1, w2, ..., wn).
- Calculates P(Spam|w1, w2, ..., wn) and P(Ham|w1, w2, ..., wn).
- Compares the values of P(Spam|w1, w2, ..., wn) and P(Ham|w1, w2, ..., wn), and:
    - If P(Ham|w1, w2, ..., wn) > P(Spam|w1, w2, ..., wn), then the message is classified as ham.
    - If P(Ham|w1, w2, ..., wn) < P(Spam|w1, w2, ..., wn), then the message is classified as spam.
    - If P(Ham|w1, w2, ..., wn) = P(Spam|w1, w2, ..., wn), then the algorithm may request human help.

```python
import re

def classify(message):

    message = re.sub('\W', ' ', message)
# cleaning message

    message = message.lower()
    message = message.split()

# calculating P(spam|message) and P(ham|message)

    p_spam_given_message = p_spam
    p_ham_given_message = p_ham

    for word in message:
        if word in parameters_spam:
            p_spam_given_message *= parameters_spam[word]

        if word in parameters_ham:
            p_ham_given_message *= parameters_ham[word]

    print('P(Spam|message):', p_spam_given_message)
    print('P(Ham|message):', p_ham_given_message)

# comparing values of spam and ham

    if p_ham_given_message > p_spam_given_message:
        print('Label: Ham')
    elif p_ham_given_message < p_spam_given_message:
        print('Label: Spam')
    else:
        print('Equal proabilities, have a human classify this!')

```

```python
classify('WINNER!! This is the secret code to unlock the money: C3421.')
```

    P(Spam|message): 1.3481290211300841e-25
    P(Ham|message): 1.9368049028589875e-27
    Label: Spam

## Measuring Accuracy of the Spam Filter

We will run classify() to filter the test dataset created above with 20% of actual data.

Here we will modify classify() to returns classification label instead of printing them.

```python
import re

def classify_test_set(message):

    message = re.sub('\W', ' ', message)
# cleaning message

    message = message.lower()
    message = message.split()

# calculating P(spam|message) and P(ham|message)

    p_spam_given_message = p_spam
    p_ham_given_message = p_ham

    for word in message:
        if word in parameters_spam:
            p_spam_given_message *= parameters_spam[word]

        if word in parameters_ham:
            p_ham_given_message *= parameters_ham[word]

# comparing values of spam and ham

    if p_ham_given_message > p_spam_given_message:
        return 'ham'
    elif p_ham_given_message < p_spam_given_message:
        return 'spam'
    else:
        print('need human classification')

```

#### Use classify_test_set to create a new column in our test set.

```python
test_set['filtered'] = test_set['SMS'].apply(classify_test_set)
test_set.head(10)
```

    need human classification

      Label
      SMS
      filtered

      0
      ham
      Later i guess. I needa do mcat study too.
      ham

      1
      ham
      But i haf enuff space got like 4 mb...
      ham

      2
      spam
      Had your mobile 10 mths? Update to latest Oran...
      spam

      3
      ham
      All sounds good. Fingers . Makes it difficult ...
      ham

      4
      ham
      All done, all handed in. Don't know if mega sh...
      ham

      5
      ham
      But my family not responding for anything. Now...
      ham

      6
      ham
      U too...
      ham

      7
      ham
      Boo what time u get out? U were supposed to ta...
      ham

      8
      ham
      Genius what's up. How your brother. Pls send h...
      ham

      9
      ham
      I liked the new mobile
      ham

### Fuction to measure the accuracy

```python
correct = 0
total = test_set.shape[0]

for row in test_set.iterrows():
    row = row[1]
    if row['Label'] == row['filtered']:
        correct += 1
print('Correct:', correct)
print('Incorrect:', total - correct)
print('Accuracy:', correct/total)
```

    Correct: 1100
    Incorrect: 14
    Accuracy: 0.9874326750448833

The accuracy is close to 98.74%, which is really good. Our spam filter looked at 1,114 messages that it hasn't seen in training, and classified 1,100 correctly.

```python

```

Building a Spam Filter with Naive Bayes.ipynb


```python
from decodes.core import *
from decodes.io.jupyter_out import JupyterOut
out = JupyterOut.unit_square( )
```

    http://decod.es/	v0.2.3
    io loaded

# Vector Representation and Manipulation

A vector is an object with a length and direction, typically denoted by
a letter with an arrow on top, such as $\vec{v}$. This is most often represented in diagram as an arrow.

Expanding upon this representation, as vectors merely represent length and direction (and not position), arrows with the the same length and direction are considered to describe the same vector. From this, we can further simplify the representation of a vector to be an arrow with its “tail” at a common origin which we denote by $\vec{0}$.

The basic arithmetic operations have meaning when applied to vectors. Each operation may be described purely through the graphic manipulation of arrows. Defining these without resorting to a numeric representation elevates the arrow from mere visual aid.

## Elemental Vector Operations

### Addition

The addition of two vectors $\vec{v_{1}}$ and $\vec{v_{2}}$ results in another vector $\vec{v_{1}} + \vec{v_{2}}$.

In arrows, addition is governed by the parallelogram rule which means that we can draw the parallelogram made by the two arrows and the vector $\vec{v_{1}} + \vec{v_{2}}$ is the arrow from $\vec{0}$ to the far corner of the parallelogram.

A practical way of doing this is by the head-to-tail method, placing the tail of $\vec{v_{2}}$ at the head of $\vec{v_{1}}$; the point at which the head of $\vec{v_{2}}$ ends up is the head of $\vec{v_{1}} + \vec{v_{2}}$.

```python
vec_a = Vec(1,1)
vec_b = Vec(0,3)
vec_c = vec_a + vec_b
print(vec_c)
```

    vec[1,4,0.0]

Two special cases of addition include the **degenerate parallelogram**, and the **summation of many vectors**.

### Scalar Multiplication

Next, we can define the **multiplication** of a vector by a scalar.

Multiplying a vector $\vec{v}$ by a scalar $c$ results in another vector $c\vec{v}$. This is an arrow that remains on the same line as $\vec{v}$, but is scaled by the length represented by the scalar multiplier.

When the scalar is -1, multiplication results in a vector that is equal in length but opposite in direction; this inverted vector may be more simply denoted by $-\vec{v}$.

```python
vec_a = Vec(1,1)
vec_b = vec_a * 2
print(vec_b)
```

    vec[2,2,0.0]

### Subtraction and Scalar Division

These two other basic operations can be derived from vector addition and scalar multiplication, so mathematically are thought of as less elemental operations. For instance, **vector subtraction** can be expressed as an addition and a scalar multiplication:

\begin{align}
\vec{v_{1}} - \vec{v_{2}} = \vec{v_{1}} + (-1) \vec{v_{2}}
\end{align}

In diagram, we can get this result by first drawing out $-\vec{v_{2}}$ and then adding this to $\vec{v_{1}}$ or we can simply see that the resulting vector goes from the head of $\vec{v_{2}}$ to the head of $\vec{v_{1}}$.

Similarly, **division of a vector by a scalar** can be rewritten in terms of scalar multiplication as:

\begin{align}
\frac{\vec{v}}{c} = (\frac{1}{c})\vec{v}
\end{align}

```python
vec_a = Vec(1,1)
vec_b = Vec(0,3)
vec_c = vec_a - vec_b
print(vec_c)
```

    vec[1,-2,0.0]

### A Non-Arrow

The zero-vector is not an operation per se, but a quantity that we can construct using the elemental operations already at our disposal.

This non-arrow, which we have been denoting by $\vec{0}$ and representing as a dot in our diagrams, is in fact the result of the vector subtraction $\vec{v}-\vec{v}$ or the scalar multiplication $0\vec{v}$.

Notice the distinction between $\vec{0}$ which is a zero-length vector, and $0$, which is a number.

```python
vec_zero = Vec()
print(vec_zero)
```

    vec[0.0,0.0,0.0]

The two operations of vector addition and scalar multiplication are particularly fundamental since they can be combined to yield other operations.

These two form the basis of the visual metaphor that has structured the diagrammatic language we have been using thus far, which is formally known as a **vector space**.

Many other more complex scenarios may also be described using the rules outlined here.

103 - Points, Vectors, and Coordinate Systems/072 - Vector Representation and Manipulation.ipynb


# 1. Self-Attention

### 1.1 Seq2Seq

1. 传统的基于RNN的Seq2Seq，主要有两个缺点:
    - 不方便并行计算;
    - Encoder学得的固定长度context vector无法涵盖较长的句子。

2. CNN也能实现Seq2Seq，同时可以并行计算，但是低层的Filter只能考虑有限的上下文，若要考虑全局的Context，需要叠加多层Filter。

### 1.2 Self-Attention

#### Step1

$$
a^{i} = Wx^{i}
$$

#### Step2
$q:$ query(to match others)

$k:$ key(to be matched)

$v:$ information to be extracted

$$
q^{i} = W^{q}a^{i} \\
k^{i} = W^{k}a^{i} \\
v^{i} = W^{v}a^{i} \\
$$

#### Step3: 计算Attention

$a_{ij}:~$ 第$~i~$个位置相对第$~j~$个位置的注意力Attention。

$$
\begin{align}
a_{ij} &= \frac{q^{i} \cdot k^{j}}{\sqrt{d}} \\
\hat{a_{ij}} &= \frac{ a_{ij} }{ \sum_{j}a_{ij} }
\end{align}
$$

$d: ~$ $k$的dimension，是为了梯度的稳定。

#### Step4:  对各位置的information加权平均

$$
\begin{align}
b_{i } = \sum_{j} \hat{a}_{ij} v^{j}
\end{align}
$$

可以看到，Self-Attention完全摒弃了CNN，RNN思想。

### 1.3 Selft-Attention的并行计算

### 1.4 Multi-head Self-Attention

### 1.5 Positional Encoding

截止目前为止，我们介绍的Transformer模型并没有捕捉顺序序列的能力，也就是说无论句子的结构怎么打乱，Transformer都会得到类似的结果。

为了解决这个问题，作者引入了位置编码（Position Embedding）特征，具体地说，位置编码会在词向量中加入单词的位置信息，这样Transformer就能区分不同位置的单词。

常用的模式有：
- 根据数据学习；

- 自己设计编码规则

$$
\begin{align}
PE_{(pos, 2i)} &= \sin \left(pos/10000^{2i/d_{k}} \right) \\
PE_{(pos, 2i+1)} &= \cos \left(pos/10000^{2i/d_{k}} \right)
\end{align}
$$

式中，$pos~$表示位置索引，$~i~$表示词向量的维度索引，$d_{k}$表示词向量长度。

### 1.6 Seq2Seq with Attention

# 2. Transformer

Transformer: Seq2Seq model with "Self-Attention".

### 2.1 Transformer Block

1. 蓝色的线是残差连接（residual connections），可以用来防止梯度消失或梯度爆炸；

2. Layer Normalization可以使训练更快:

$$
\hat{\pmb{a}} = \gamma \frac{\pmb{a} - \mu}{\sqrt{\sigma^{2} + \epsilon}} + \beta
$$

       $\epsilon~$用来防止分母为0，$\gamma, \beta$是可学习的参数。

3. Feed Forward层对每个输入vector，都单独使用个MLP（Multi-layer Perceptron）进行前向计算。

#### layer norm vs. batch norm

### 2.2 Application

#### 1. Sentiment Classification

#### 2. Auto-regression Generation

比如，输入"hell"，预测下一个字符为"o"，生成"hello".

在训练上面的网络时，会对输出的每一个character建立loss。但是，self-attention机制本身可以看到前面的character。因此我们在训练时有必要不让transformer不看到前面的character。

### 2.3 Full Architecture of Transformer

1. Decoder中Masked Multi-Head Attention层，防止偷窥information in the future。

2. ②处的Multi-Head Attention，其中的$~Q~$来自Decoder，而$K,V$来自Encoder的输出。

# 3. ELMO

ELMO（Embeddings from Language Model）

RNN-based language models (trained from lots of sentences).

2018年3月份，ELMo出世，该paper是NAACL18 Best Paper。在之前2013年的word2vec及2014年的GloVe的工作中，每个词对应一个vector，对多义词无能为力。在ELMo世界里，预训练好的模型不再只是向量对应关系，而是一个训练好的模型。使用时，将一句话或一段话输入模型，模型会根据上下文来推断每个词的词向量。

# 4. BERT

- General Architecture

- Masked Language Model

- Subword Units

- Pre-training and Fine-Tuning BERT

BERT (Bidirectional Encoder Representations from Transforers)

- BERT = Encoder of Transformer

### 4.1 General Architecture

其中:

- Token Embeddings是词向量，第一个单词是CLS标志，可以用于之后的分类任务；

- Segment Embeddings用来区别两种句子，因为预训练不关做LM，还要做以两个句子为输入的分类任务；

- Position Embeddings和Transformer不一样，不是三角函数而是学习出来的。

### 4.2 Masked Language Model

在fine-turning任务中，见不到\[MASK\]这个token，因此在pre-training阶段，mask是有一定技巧的:

1. 随机mask 15%的词；

2. 对于被选中的词，80%的几率用\[MASK\]替换；10%几率被替换为其它词；10%几率不做处理。

- 如果只使用\[MASK\]替换，那么模型可能更多注意到被mask调的词，而would not have to learn good Representation for other words；

- 如果只使用\[MASK\]替换或随机替换成其它的token，那么模型可能会认为当前token总是错的；

- if we only use \[MASK\] token or observed word, model would be bias to trivially copy.

### 4.3 Next Sentence Prediction

### 4.4 Pre-training and Fine-truning

#### 1. Case1——句子分类

#### 2. Case2——词性分类

#### Case3——推理

#### Case4——QA


```python
from sympy.physics.units import *
from sympy import *

# Rounding:
import decimal
from decimal import Decimal as DX
def iso_round(obj, pv, rounding=decimal.ROUND_HALF_EVEN):
    import sympy
    """
    Rounding acc. to DIN EN ISO 80000-1:2013-08
    place value = Rundestellenwert
    """
    assert pv in set([
        # place value   #  round to:
        100,            #  3rd last digit before decimal
        10,             #  2nd last
        1,              #  last
        0.1,            #  1st digit after decimal
        0.01,           #  2nd
        0.001,          #  3rd
        0.0001,         #  4th
        0.00001,        #  5th
        0.000001,       #  6th
        0.0000001,      #  7th
        0.00000001,     #  8th
        0.000000001,    #  9th
        0.0000000001,   # 10th
        ])
    try:
        tmp = DX(str(float(obj)))
        obj = tmp.quantize(DX(str(pv)), rounding=rounding)
    except:
        for i in range(len(obj)):
            tmp = DX(str(float(obj[i])))
            obj[i] = tmp.quantize(DX(str(pv)), rounding=rounding)
    return obj

# LateX:
kwargs = {}
kwargs["mat_str"] = "bmatrix"
kwargs["mat_delim"] = ""
# kwargs["symbol_names"] = {FB: "F^{\mathsf B}", }

# Units:
(k, M, G ) = ( 10**3, 10**6, 10**9 )
(mm, cm, deg) = ( m/1000, m/100, pi/180)
Newton = kg*m/s**2
Pa     = Newton/m**2
MPa    = M*Pa
GPa    = G*Pa
kN     = k*Newton

# ---

xi, eta = var("xi, eta")
a1, a2, a3, a4 = var("a1, a2, a3, a4")
b1, b2, b3, b4 = var("b1, b2, b3, b4")
c1, c2, c3, c4 = var("c1, c2, c3, a4")
d1, d2, d3, d4 = var("d1, d2, d3, d4")

N1 = a1*xi + a2*eta + a3*xi*eta + a4
N2 = b1*xi + b2*eta + b3*xi*eta + b4
N3 = c1*xi + c2*eta + c3*xi*eta + c4
N4 = d1*xi + d2*eta + d3*xi*eta + d4

pprint("\nN1:")
tmp_00 = N1.subs( [ (xi,0), (eta,0) ] )
tmp_10 = N1.subs( [ (xi,1), (eta,0) ] )
tmp_01 = N1.subs( [ (xi,0), (eta,1) ] )
tmp_11 = N1.subs( [ (xi,1), (eta,1) ] )
e1 = Eq(tmp_00, 1)
e2 = Eq(tmp_10, 0)
e3 = Eq(tmp_01, 0)
e4 = Eq(tmp_11, 0)
sol = solve([e1, e2, e3, e4], [a1, a2, a3, a4])
a1s, a2s, a3s, a4s = sol[a1], sol[a2], sol[a3], sol[a4]
N1 = N1.subs([(a1, a1s), (a2, a2s), (a3, a3s), (a4, a4s)])
pprint(N1)

pprint("\nN2:")
tmp_00 = N2.subs( [ (xi,0), (eta,0) ] )
tmp_10 = N2.subs( [ (xi,1), (eta,0) ] )
tmp_01 = N2.subs( [ (xi,0), (eta,1) ] )
tmp_11 = N2.subs( [ (xi,1), (eta,1) ] )
e1 = Eq(tmp_00, 0)
e2 = Eq(tmp_10, 1)
e3 = Eq(tmp_01, 0)
e4 = Eq(tmp_11, 0)
sol = solve([e1, e2, e3, e4], [b1, b2, b3, b4])
b1s, b2s, b3s, b4s = sol[b1], sol[b2], sol[b3], sol[b4]
N2 = N2.subs([(b1, b1s), (b2, b2s), (b3, b3s), (b4, b4s)])
pprint(N2)

pprint("\nN3:")
tmp_00 = N3.subs( [ (xi,0), (eta,0) ] )
tmp_10 = N3.subs( [ (xi,1), (eta,0) ] )
tmp_01 = N3.subs( [ (xi,0), (eta,1) ] )
tmp_11 = N3.subs( [ (xi,1), (eta,1) ] )
e1 = Eq(tmp_00, 0)
e2 = Eq(tmp_10, 0)
e3 = Eq(tmp_01, 0)
e4 = Eq(tmp_11, 1)
sol = solve([e1, e2, e3, e4], [c1, c2, c3, c4])
c1s, c2s, c3s, c4s = sol[c1], sol[c2], sol[c3], sol[c4]
N3 = N3.subs([(c1, c1s), (c2, c2s), (c3, c3s), (c4, c4s)])
pprint(N3)

pprint("\nN4:")
tmp_00 = N4.subs( [ (xi,0), (eta,0) ] )
tmp_10 = N4.subs( [ (xi,1), (eta,0) ] )
tmp_01 = N4.subs( [ (xi,0), (eta,1) ] )
tmp_11 = N4.subs( [ (xi,1), (eta,1) ] )
e1 = Eq(tmp_00, 0)
e2 = Eq(tmp_10, 0)
e3 = Eq(tmp_01, 1)
e4 = Eq(tmp_11, 0)
sol = solve([e1, e2, e3, e4], [d1, d2, d3, d4])
d1s, d2s, d3s, d4s = sol[d1], sol[d2], sol[d3], sol[d4]
N4 = N4.subs([(d1, d1s), (d2, d2s), (d3, d3s), (d4, d4s)])
pprint(N4)

x1, x2, x3, x4 = var("x1, x2, x3, x4")
y1, y2, y3, y4 = var("y1, y2, y3, y4")

pprint("\nx(xi, eta):")
x = N1*x1 + N2*x2 + N3*x3 + N4*x4
pprint(x)
pprint("\ny(xi, eta):")
y = N1*y1 + N2*y2 + N3*y3 + N4*y4
pprint(y)

dx_dxi = diff(x, xi)
dx_det = diff(x, eta)
dy_dxi = diff(y, xi)
dy_det = diff(y, eta)

pprint("\ndx / d xi:")
pprint(dx_dxi)
pprint("\ndx / d eta:")
pprint(dx_det)
pprint("\ndy / d xi:")
pprint(dy_dxi)
pprint("\ndy / d eta:")
pprint(dy_det)

Jac = Matrix([[dx_dxi, dx_det],[dy_dxi, dy_det]])

# N1:
# η⋅ξ - η - ξ + 1
#
# N2:
# -η⋅ξ + ξ
#
# N3:
# η⋅ξ
#
# N4:
# -η⋅ξ + η
#
# x(xi, eta):
# η⋅x₃⋅ξ + x₁⋅(η⋅ξ - η - ξ + 1) + x₂⋅(-η⋅ξ + ξ) + x₄⋅(-η⋅ξ + η)
#
# y(xi, eta):
# η⋅ξ⋅y₃ + y₁⋅(η⋅ξ - η - ξ + 1) + y₂⋅(-η⋅ξ + ξ) + y₄⋅(-η⋅ξ + η)
#
# dx / d xi:
# η⋅x₃ - η⋅x₄ + x₁⋅(η - 1) + x₂⋅(-η + 1)
#
# dx / d eta:
# x₁⋅(ξ - 1) - x₂⋅ξ + x₃⋅ξ + x₄⋅(-ξ + 1)
#
# dy / d xi:
# η⋅y₃ - η⋅y₄ + y₁⋅(η - 1) + y₂⋅(-η + 1)
#
# dy / d eta:
# -ξ⋅y₂ + ξ⋅y₃ + y₁⋅(ξ - 1) + y₄⋅(-ξ + 1)

```


# Deterministic point jet

```python
import matplotlib.pyplot as plt
import pandas as pd

import numpy as np
import matplotlib.pylab as pl
```

\begin{equation}
    \partial_t \zeta = \frac{\zeta_{jet}}{\tau} - \mu \zeta + \nu_\alpha \nabla^{2\alpha} - \beta \partial_x \psi - J(\psi, \zeta) \zeta
\end{equation}

Here $\zeta_{jet}$ is the profile of a prescribed jet and $\tau = 1/\mu$ is the relaxation time. Also $\beta = 2\Omega cos \theta$ and $\theta = 0$ corresponds to the equator.

Parameters

> $\Omega = 2\pi$

> $\mu = 0.05$

> $\nu = 0$

> $\nu_4 = 0$

> $\Xi = 1.0$

> $\Delta \theta = 0.1$

> $\tau$ = 20 days

```python
dn = "pointjet/8x8/"
```

```python
# Parameters: μ = 0.05, τ = 20.0, Ξ = 1.0*Ω and Δθ = 0.1
M = 8
N = 8

colors = pl.cm.nipy_spectral(np.linspace(0,1,M))
```

## NL v GQL v GCE2

```python
nl = np.load(dn+"nl.npz",allow_pickle=True)
gql = np.load(dn+"gql.npz",allow_pickle=True)
gce2 = np.load(dn+"gce2.npz",allow_pickle=True)
```

```python
# fig,ax = plt.subplots(1,2,figsize=(14,5))

# # Energy
# ax[0].plot(nl['t'],nl['Etav'],label=r'$\langle NL \rangle$')
# ax[0].plot(gql['t'],gql['Etav'],label=r'$\langle GQL(M) \rangle$')
# ax[0].plot(gce2['t'],gce2['Etav'],label=r'$\langle GCE2(M) \rangle$')

# ax[0].set_xlabel(r'$t$',fontsize=14)
# ax[0].set_ylabel(r'$E$',fontsize=14)
# # ax[0].legend(bbox_to_anchor=(1.01,0.85),fontsize=14)

# # Enstrophy
# ax[1].plot(nl['t'],nl['Ztav'],label=r'$\langle NL \rangle$')
# ax[1].plot(gql['t'],gql['Ztav'],label=r'$\langle GQL(M) \rangle$')
# ax[1].plot(gce2['t'],gce2['Ztav'],label=r'$\langle GCE2(M) \rangle$')

# ax[1].set_xlabel(r'$t$',fontsize=14)
# ax[1].set_ylabel(r'$Z$',fontsize=14)
# ax[1].legend(loc=4,fontsize=14)

# plt.show()
```

```python
fig,ax = plt.subplots(1,3,figsize=(14,5))

ax[0].set_title(f'NL')
for i,x in enumerate(nl['Emt'].T):
    ax[0].plot(nl['t'],x,label=i,c=colors[i])

ax[1].set_title(f'GQL(M)')
for i,x in enumerate(gql['Emt'].T):
    ax[1].plot(gql['t'],x,label=i,c=colors[i])

ax[2].set_title(f'GCE2(M)')
for i,x in enumerate(gce2['Emt'].T):
    ax[2].plot(gce2['t'],x,label=i,c=colors[i])

for a in ax:

    a.set_xlabel(r'$t$',fontsize=14)
    a.set_yscale('log')
    a.set_ylim(1e-12,1e2)

ax[0].set_ylabel(r'$E(m)$',fontsize=14)
ax[2].legend(bbox_to_anchor=(1.01,0.85),ncol=1)

plt.show()
```

```python
# fig,ax = plt.subplots(1,3,figsize=(16,4))

# im = ax[0].imshow((nl['Vxy'][:,:,0]),interpolation="bicubic",cmap="RdBu_r",origin="lower")
# fig.colorbar(im, ax=ax[0])
# ax[0].set_title(r'NL: $\zeta(x,y,t = 0 )$',fontsize=14)

# im = ax[1].imshow((gql['Vxy'][:,:,0]),interpolation="bicubic",cmap="RdBu_r",origin="lower")
# fig.colorbar(im, ax=ax[1])
# ax[1].set_title(r'GQL: $\zeta(x,y,t = 0 )$',fontsize=14)

# im = ax[2].imshow((gce2['Vxy'][:,:,0]),interpolation="bicubic",cmap="RdBu_r",origin="lower")
# fig.colorbar(im, ax=ax[2])
# ax[2].set_title(r'GCE2:$\zeta(x,y,t = 0 )$',fontsize=14)

# for a in ax:
#     a.set_xticks([0,M-1,2*M-2])
#     a.set_xticklabels([r'$0$',r'$\pi$',r'$2\pi$'],fontsize=14)
#     a.set_yticks([0,M-1,2*M-2])
#     a.set_yticklabels([r'$0$',r'$\pi$',r'$2\pi$'],fontsize=14)

# plt.show()
```

```python
fig,ax = plt.subplots(1,3,figsize=(16,4))

im = ax[0].imshow((nl['Vxy'][:,:,-1]),interpolation="bicubic",cmap="RdBu_r",origin="lower")
fig.colorbar(im, ax=ax[0])
ax[0].set_title(r'NL: $\zeta(x,y,t = 0 )$',fontsize=14)

im = ax[1].imshow((gql['Vxy'][:,:,-1]),interpolation="bicubic",cmap="RdBu_r",origin="lower")
fig.colorbar(im, ax=ax[1])
ax[1].set_title(r'GQL: $\zeta(x,y,t = 0 )$',fontsize=14)

im = ax[2].imshow((gce2['Vxy'][:,:,-1]),interpolation="bicubic",cmap="RdBu_r",origin="lower")
fig.colorbar(im, ax=ax[2])
ax[2].set_title(r'GCE2:$\zeta(x,y,t = 0 )$',fontsize=14)

for a in ax:

    a.set_xticks([0,M-1,2*M-2])
    a.set_xticklabels([r'$0$',r'$\pi$',r'$2\pi$'],fontsize=14)
    a.set_yticks([0,M-1,2*M-2])
    a.set_yticklabels([r'$0$',r'$\pi$',r'$2\pi$'],fontsize=14)

plt.show()
```

## QL v CE2 v GCE2(0)

```python
ql = np.load(dn+"ql.npz",allow_pickle=True)
ce2 = np.load(dn+"ce2.npz",allow_pickle=True)
gce2 = np.load(dn+"gce2_0.npz",allow_pickle=True)
```

```python
fig,ax = plt.subplots(1,3,figsize=(18,5))

# Energy
ax[0].set_title(f'QL',fontsize=14)
for i,x in enumerate(ql['Emtav'].T):
    ax[0].plot(ql['t'],x,label=i,c=colors[i])

ax[1].set_title(f'CE2',fontsize=14)
for i,x in enumerate(ce2['Emtav'].T):
    ax[1].plot(ce2['t'],x,label=i,c=colors[i])

ax[2].set_title(f'GCE2(0)',fontsize=14)
for i,x in enumerate(gce2['Emtav'].T):
    ax[2].plot(gce2['t'],x,label=i,c=colors[i])

ax[2].legend(bbox_to_anchor=(1.01,0.5),ncol=1)

for a in ax:
    a.set_xlabel(r'$t$',fontsize=14)
    a.set_ylabel(r'$E$',fontsize=14)
    a.set_yscale('log')
    a.set_ylim(1e-12,1e2)

# plt.show()
# plt.savefig(dn+"ze_tau20_qlce2gce2_0.png",bbox_inches='tight',)
```

## GQL(1) v GCE2(1)

```python
gql = np.load(dn+"gql_1.npz",allow_pickle=True)
gce2 = np.load(dn+"gce2_1.npz",allow_pickle=True)
```

```python
fig,ax = plt.subplots(1,2,figsize=(14,5))

# Energy
ax[0].set_title(f'GQL(1)',fontsize=14)
for i,x in enumerate(gql['Emtav'].T):
    ax[0].plot(gql['t'],x,label=i,c=colors[i])

ax[1].set_title(f'GCE2(1)',fontsize=14)
for i,x in enumerate(gce2['Emtav'].T):
    ax[1].plot(gce2['t'],x,label=i,c=colors[i])

for a in ax:
    a.set_xlabel(r'$t$',fontsize=14)
    a.set_ylabel(r'$E$',fontsize=14)
    a.set_yscale('log')
#     a.set_ylim(1e-1,1e0)
ax[1].legend(bbox_to_anchor=(1.01,0.85),fontsize=14)

plt.show()
```

```python
fig,ax = plt.subplots(1,2,figsize=(15,6))

ax[0].set_title(f'GQL(1)',fontsize=14)
im = ax[0].imshow((gql['Vxy'][:,:,-1]),cmap="RdBu_r",origin="lower",interpolation="bicubic")
fig.colorbar(im,ax=ax[0])

ax[1].set_title(f'GCE2(1)',fontsize=14)
im = ax[1].imshow((gce2['Vxy'][:,:,-1]),cmap="RdBu_r",origin="lower",interpolation="bicubic")
fig.colorbar(im,ax=ax[1])

for a in ax:
    a.set_xticks([0,M-1,2*M-2])
    a.set_xticklabels([r'$0$',r'$\pi$',r'$2\pi$'],fontsize=14)
    a.set_yticks([0,M-1,2*M-2])
    a.set_yticklabels([r'$0$',r'$\pi$',r'$2\pi$'],fontsize=14)

plt.show()
```

```python
fig,ax = plt.subplots(1,2,figsize=(12,6))

ax[0].set_title('GQL(1)')
im = ax[0].imshow((gql['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im)

ax[1].set_title('GCE2(1)')
im = ax[1].imshow((gce2['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im)

for a in ax:
    a.set_xticks([0,M-1,2*M-2])
    a.set_xticklabels([r'$-M$',r'$0$',r'$M$'],fontsize=14)
    a.set_yticks([0,M-1,2*M-2])
    a.set_yticklabels([r'$-M$',r'$0$',r'$M$'],fontsize=14)

plt.show()
```

```python
gql = np.load(dn+"gql_3.npz",allow_pickle=True)
gce2 = np.load(dn+"gce2_3.npz",allow_pickle=True)
```

```python
fig,ax = plt.subplots(1,2,figsize=(14,5))

# Energy
ax[0].set_title(f'GQL(3)',fontsize=14)
for i,x in enumerate(gql['Emtav'].T):
    ax[0].plot(gql['t'],x,label=i,c=colors[i])

ax[1].set_title(f'GCE2(3)',fontsize=14)
for i,x in enumerate(gce2['Emtav'].T):
    ax[1].plot(gce2['t'],x,label=i,c=colors[i])

for a in ax:
    a.set_xlabel(r'$t$',fontsize=14)
    a.set_ylabel(r'$E$',fontsize=14)
    a.set_yscale('log')
#     a.set_ylim(1e-1,1e0)

ax[1].legend(bbox_to_anchor=(1.01,0.85),fontsize=14)

plt.show()
```

```python
fig,ax = plt.subplots(1,2,figsize=(15,6))

ax[0].set_title(f'GQL(3)',fontsize=14)
im = ax[0].imshow((gql['Vxy'][:,:,-1]),cmap="RdBu_r",origin="lower",interpolation="bicubic")
fig.colorbar(im,ax=ax[0])

ax[1].set_title(f'GCE2(3)',fontsize=14)
im = ax[1].imshow((gce2['Vxy'][:,:,-1]),cmap="RdBu_r",origin="lower",interpolation="bicubic")
fig.colorbar(im,ax=ax[1])

for a in ax:
    a.set_xticks([0,M-1,2*M-2])
    a.set_xticklabels([r'$0$',r'$\pi$',r'$2\pi$'],fontsize=14)
    a.set_yticks([0,M-1,2*M-2])
    a.set_yticklabels([r'$0$',r'$\pi$',r'$2\pi$'],fontsize=14)

plt.show()
```

```python
fig,ax = plt.subplots(1,2,figsize=(12,6))

ax[0].set_title('GQL(3)')
im = ax[0].imshow((gql['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im)

ax[1].set_title('GCE2(3)')
im = ax[1].imshow((gce2['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im)

for a in ax:
    a.set_xticks([0,M-1,2*M-2])
    a.set_xticklabels([r'$-M$',r'$0$',r'$M$'],fontsize=14)
    a.set_yticks([0,M-1,2*M-2])
    a.set_yticklabels([r'$-M$',r'$0$',r'$M$'],fontsize=14)

plt.show()
```

```python
# gql = np.load(dn+"gql_5.npz",allow_pickle=True)
# gce2 = np.load(dn+"gce2_5.npz",allow_pickle=True)
```

```python
# fig,ax = plt.subplots(1,2,figsize=(14,5))

# # Energy
# ax[0].set_title(f'GQL(5)',fontsize=14)
# for i,x in enumerate(gql['Emtav'].T):
#     ax[0].plot(gql['t'],x,label=i,c=colors[i])

# ax[1].set_title(f'GCE2(5)',fontsize=14)
# for i,x in enumerate(gce2['Emtav'].T):
#     ax[1].plot(gce2['t'],x,c=colors[i])

# for a in ax:
#     a.set_xlabel(r'$t$',fontsize=14)
#     a.set_ylabel(r'$E$',fontsize=14)
#     a.set_yscale('log')
# #     a.set_ylim(1e-1,1e0)
# # ax[1].legend(bbox_to_anchor=(1.01,0.85),fontsize=14)

# plt.show()
```

```python
# fig,ax = plt.subplots(1,2,figsize=(12,6))

# ax[0].set_title('GQL(5)')
# im = ax[0].imshow((gql['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# # fig.colorbar(im)

# ax[1].set_title('GCE2(5)')
# im = ax[1].imshow((gce2['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# # fig.colorbar(im)

# for a in ax:
#     a.set_xticks([0,M-1,2*M-2])
#     a.set_xticklabels([r'$-M$',r'$0$',r'$M$'],fontsize=14)
#     a.set_yticks([0,M-1,2*M-2])
#     a.set_yticklabels([r'$-M$',r'$0$',r'$M$'],fontsize=14)

# plt.show()
```

```python
# dn = "pointjet/12x12/"
```

```python
# Parameters: μ = 0.05, τ = 20.0, Ξ = 1.0*Ω and Δθ = 0.1
Nx = 12
Ny = 12
```

```python
nl = np.load(dn+"nl.npz",allow_pickle=True)
gql = np.load(dn+"gql.npz",allow_pickle=True)
gce2 = np.load(dn+"gce2.npz",allow_pickle=True)
```

```python
# fig,ax = plt.subplots(1,2,figsize=(14,5))

# # Energy
# ax[0].plot(nl['t'],nl['Etav'],label=r'$\langle NL \rangle$')
# ax[0].plot(gql['t'],gql['Etav'],label=r'$\langle GQL(M) \rangle$')
# ax[0].plot(gce2['t'],gce2['Etav'],label=r'$\langle GCE2(M) \rangle$')

# ax[0].set_xlabel(r'$t$',fontsize=14)
# ax[0].set_ylabel(r'$E$',fontsize=14)
# # ax[0].legend(bbox_to_anchor=(1.01,0.85),fontsize=14)

# # Enstrophy
# ax[1].plot(nl['t'],nl['Ztav'],label=r'$\langle NL \rangle$')
# ax[1].plot(gql['t'],gql['Ztav'],label=r'$\langle GQL(M) \rangle$')
# ax[1].plot(gce2['t'],gce2['Ztav'],label=r'$\langle GCE2(M) \rangle$')

# ax[1].set_xlabel(r'$t$',fontsize=14)
# ax[1].set_ylabel(r'$Z$',fontsize=14)
# ax[1].legend(loc=4,fontsize=14)

# plt.show()
```

```python
# fig,ax = plt.subplots(1,3,figsize=(14,5))

# ax[0].set_title(f'NL')
# for i,x in enumerate(nl['Emt'].T):
#     ax[0].plot(nl['t'],x,label=i,c=colors[i])

# ax[1].set_title(f'GQL(M)')
# for i,x in enumerate(gql['Emt'].T):
#     ax[1].plot(gql['t'],x,label=i,c=colors[i])

# ax[2].set_title(f'GCE2(M)')
# for i,x in enumerate(gce2['Emt'].T):
#     ax[2].plot(gce2['t'],x,label=i,c=colors[i])

# for a in ax:

#     a.set_xlabel(r'$t$',fontsize=14)
#     a.set_yscale('log')
# #     a.set_ylim(1e-10,1e1)

# ax[0].set_ylabel(r'$E(m)$',fontsize=14)
# ax[2].legend(bbox_to_anchor=(1.01,0.85),ncol=1)

# plt.show()
```

```python
# fig,ax = plt.subplots(1,3,figsize=(24,6))

# ax[0].set_title(f'NL',fontsize=14)
# im = ax[0].imshow((nl['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[0])

# ax[1].set_title(f'GQL(M)',fontsize=14)
# im = ax[1].imshow((gql['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[1])

# ax[2].set_title(f'GCE2(M)',fontsize=14)
# im = ax[2].imshow((gce2['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[2])

# for a in ax:
#     a.set_xticks([0,Nx-1,2*Nx-2])
#     a.set_xticklabels([r'$-N_x$',r'$0$',r'$N_x$'],fontsize=14)
#     a.set_yticks([0,Ny-1,2*Ny-2])
#     a.set_yticklabels([r'$-N_y$',r'$0$',r'$N_y$'],fontsize=14)

# plt.show()
```

```python
# fig,ax = plt.subplots(1,3,figsize=(24,6))

# ax[0].set_title(f'NL',fontsize=14)
# im = ax[0].imshow((nl['Vxy'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[0])

# ax[1].set_title(f'GQL(M)',fontsize=14)
# im = ax[1].imshow((gql['Vxy'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[1])

# ax[2].set_title(f'GCE2(M)',fontsize=14)
# im = ax[2].imshow((gce2['Vxy'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[2])

# for a in ax:
#     a.set_xticks([0,Nx-1,2*Nx-2])
#     a.set_xticklabels([r'$-N_x$',r'$0$',r'$N_x$'],fontsize=14)
#     a.set_yticks([0,Ny-1,2*Ny-2])
#     a.set_yticklabels([r'$-N_y$',r'$0$',r'$N_y$'],fontsize=14)

# plt.show()
```

```python
ql = np.load(dn+"ql.npz",allow_pickle=True)
ce2 = np.load(dn+"ce2.npz",allow_pickle=True)
gce2 = np.load(dn+"gce2_0.npz",allow_pickle=True)
```

```python
# fig,ax = plt.subplots(1,3,figsize=(14,5))

# # Energy
# ax[0].set_title(f'QL',fontsize=14)
# for i,x in enumerate(ql['Emtav'].T):
#     ax[0].plot(ql['t'],x,label=i,c=colors[i])

# ax[1].set_title(f'CE2',fontsize=14)
# for i,x in enumerate(ce2['Emtav'].T):
#     ax[1].plot(ce2['t'],x,c=colors[i])

# ax[2].set_title(f'GCE2(0)',fontsize=14)
# for i,x in enumerate(gce2['Emtav'].T):
#     ax[2].plot(gce2['t'],x,c=colors[i])

# for a in ax:
#     a.set_xlabel(r'$t$',fontsize=14)
#     a.set_ylabel(r'$E$',fontsize=14)
#     a.set_yscale('log')
# #     a.set_ylim(1e-1,1e0)
# # ax[1].legend(bbox_to_anchor=(1.01,0.85),fontsize=14)

# plt.show()
```

```python
# fig,ax = plt.subplots(1,3,figsize=(24,6))

# ax[0].set_title(f'QL',fontsize=14)
# im = ax[0].imshow((ql['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[0])

# ax[1].set_title(f'CE2',fontsize=14)
# im = ax[1].imshow((ce2['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[1])

# ax[2].set_title(f'GCE2(0)',fontsize=14)
# im = ax[2].imshow((gce2['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[2])

# for a in ax:
#     a.set_xticks([0,Nx-1,2*Nx-2])
#     a.set_xticklabels([r'$-N_x$',r'$0$',r'$N_x$'],fontsize=14)
#     a.set_yticks([0,Ny-1,2*Ny-2])
#     a.set_yticklabels([r'$-N_y$',r'$0$',r'$N_y$'],fontsize=14)

# plt.show()
```

```python
# fig,ax = plt.subplots(1,3,figsize=(24,6))

# ax[0].set_title(f'QL',fontsize=14)
# im = ax[0].imshow((ql['Vxy'][:,:,-1]),cmap="RdBu_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[0])

# ax[1].set_title(f'CE2',fontsize=14)
# im = ax[1].imshow((ce2['Vxy'][:,:,-1]),cmap="RdBu_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[1])

# ax[2].set_title(f'GCE2(0)',fontsize=14)
# im = ax[2].imshow((gce2['Vxy'][:,:,-1]),cmap="RdBu_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[2])

# for a in ax:
#     a.set_xticks([0,Nx-1,2*Nx-2])
#     a.set_xticklabels([r'$-N_x$',r'$0$',r'$N_x$'],fontsize=14)
#     a.set_yticks([0,Ny-1,2*Ny-2])
#     a.set_yticklabels([r'$-N_y$',r'$0$',r'$N_y$'],fontsize=14)

# plt.show()
```

```python
# fig,ax = plt.subplots(1,3,figsize=(24,6))

# ax[0].set_title(f'QL',fontsize=14)
# im = ax[0].imshow((ql['Uxy'][:,:,-1]),cmap="RdBu_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[0])

# ax[1].set_title(f'CE2',fontsize=14)
# im = ax[1].imshow((ce2['Uxy'][:,:,-1]),cmap="RdBu_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[1])

# ax[2].set_title(f'GCE2(0)',fontsize=14)
# im = ax[2].imshow((gce2['Uxy'][:,:,-1]),cmap="RdBu_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[2])

# for a in ax:
#     a.set_xticks([0,Nx-1,2*Nx-2])
#     a.set_xticklabels([r'$-N_x$',r'$0$',r'$N_x$'],fontsize=14)
#     a.set_yticks([0,Ny-1,2*Ny-2])
#     a.set_yticklabels([r'$-N_y$',r'$0$',r'$N_y$'],fontsize=14)

# plt.show()
```

```python
gql = np.load(dn+"gql_3.npz",allow_pickle=True)
gce2 = np.load(dn+"gce2_3.npz",allow_pickle=True)
```

```python
# fig,ax = plt.subplots(1,2,figsize=(14,5))

# # Energy
# ax[0].set_title(f'GQL',fontsize=14)
# for i,x in enumerate(gql['Emtav'].T):
#     ax[0].plot(gql['t'],x,label=i,c=colors[i])

# ax[1].set_title(f'GCE2',fontsize=14)
# for i,x in enumerate(gce2['Emtav'].T):
#     ax[1].plot(gce2['t'],x,c=colors[i])

# for a in ax:
#     a.set_xlabel(r'$t$',fontsize=14)
#     a.set_ylabel(r'$E$',fontsize=14)
#     a.set_yscale('log')
# #     a.set_ylim(1e-1,1e0)
# # ax[1].legend(bbox_to_anchor=(1.01,0.85),fontsize=14)

# plt.show()
```

```python
# fig,ax = plt.subplots(1,2,figsize=(15,6))

# ax[0].set_title(f'GQL(1)',fontsize=14)
# im = ax[0].imshow((gql['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[0])

# ax[1].set_title(f'GCE2(1)',fontsize=14)
# im = ax[1].imshow((gce2['Emn'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[1])

# for a in ax:
#     a.set_xticks([0,Nx-1,2*Nx-2])
#     a.set_xticklabels([r'$-N_x$',r'$0$',r'$N_x$'],fontsize=14)
#     a.set_yticks([0,Ny-1,2*Ny-2])
#     a.set_yticklabels([r'$-N_y$',r'$0$',r'$N_y$'],fontsize=14)

# plt.show()
```

```python
# fig,ax = plt.subplots(1,2,figsize=(15,6))

# ax[0].set_title(f'GQL(1)',fontsize=14)
# im = ax[0].imshow((gql['Vxy'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[0])

# ax[1].set_title(f'GCE2(1)',fontsize=14)
# im = ax[1].imshow((gce2['Vxy'][:,:,-1]),cmap="nipy_spectral_r",origin="lower",interpolation="bicubic")
# fig.colorbar(im,ax=ax[1])

# for a in ax:
#     a.set_xticks([0,Nx-1,2*Nx-2])
#     a.set_xticklabels([r'$-N_x$',r'$0$',r'$N_x$'],fontsize=14)
#     a.set_yticks([0,Ny-1,2*Ny-2])
#     a.set_yticklabels([r'$-N_y$',r'$0$',r'$N_y$'],fontsize=14)

# plt.show()
```

```python

```