# Ikeda for many ships with quadratic contributions
The method developed in: ([01.03_ikeda_many_dev](06_ikeda/01.03_ikeda_many_dev.ipynb)) will now be attempted for many ships.
Instead of just calculating ikeda for one roll amplitude, it will now be calculated for 2 amplitudes to derive the quadratic part $B_2$

```python
# %load imports.py
"""
These is the standard setup for the notebooks.
"""

%matplotlib inline
%load_ext autoreload
%autoreload 2

from jupyterthemes import jtplot
jtplot.style(theme='onedork', context='notebook', ticks=True, grid=False)

import pandas as pd
pd.options.display.max_rows = 999
pd.options.display.max_columns = 999
pd.set_option("display.max_columns", None)
import numpy as np
import os
import matplotlib.pyplot as plt
from collections import OrderedDict
#plt.style.use('paper')

#import data
import copy
from mdldb.run import Run

from sklearn.pipeline import Pipeline
from rolldecayestimators.transformers import CutTransformer, LowpassFilterDerivatorTransformer, ScaleFactorTransformer, OffsetTransformer
from rolldecayestimators.direct_estimator_cubic import EstimatorQuadraticB, EstimatorCubic
from rolldecayestimators.ikeda_estimator import IkedaQuadraticEstimator
import rolldecayestimators.equations as equations
import rolldecayestimators.lambdas as lambdas
from rolldecayestimators.substitute_dynamic_symbols import lambdify
import rolldecayestimators.symbols as symbols
import sympy as sp

from sympy.physics.vector.printing import vpprint, vlatex
from IPython.display import display, Math, Latex

from sklearn.metrics import r2_score
from src.data import database
from mdldb import tables
import shipflowmotionshelpers.shipflowmotionshelpers as helpers

```

    Duplicate key in file WindowsPath('C:/Users/maa/.matplotlib/stylelib/paper.mplstyle'), line 461 ('figure.figsize   : 5, 3   ## figure size in inches')
    Duplicate key in file WindowsPath('C:/Users/maa/.matplotlib/stylelib/paper.mplstyle'), line 462 ('figure.dpi       : 100        ## figure dots per inch')

```python
from pyscores2.indata import Indata
from pyscores2.runScores2 import Calculation
from pyscores2.output import OutputFile
from pyscores2 import TDPError
import pyscores2
from rolldecayestimators.ikeda import Ikeda, IkedaR
from rolldecayestimators.simplified_ikeda_class import SimplifiedIkeda
import subprocess
from rolldecayestimators import measure
```

```python
df_all_sections_id = pd.read_csv('../data/external/all_sections.csv', sep=';')
df_all_sections_id.head()
```

      b
      area
      t
      x
      SHIP
      loading_condition_id

      0
      0.00
      0.0
      0.0
      0.00
      68
      NaN

      1
      26.86
      19.5
      6.6
      8.61
      68
      NaN

      2
      28.17
      54.7
      6.6
      17.22
      68
      NaN

      3
      28.40
      96.0
      6.6
      25.83
      68
      NaN

      4
      28.40
      129.4
      6.6
      34.44
      68
      NaN

```python
section_groups=df_all_sections_id.groupby(by='loading_condition_id')
```

```python
loading_condition_ids = df_all_sections_id['loading_condition_id'].unique()
mask=pd.notnull(loading_condition_ids)
loading_condition_ids=loading_condition_ids[mask]
```

```python
df_rolldecay = database.load(rolldecay_table_name='rolldecay_quadratic_b', limit_score=0.99,
                             exclude_table_name='rolldecay_exclude')
```

```python
mask=df_rolldecay['loading_condition_id'].isin(loading_condition_ids)
df=df_rolldecay.loc[mask].copy()
```

```python
df['BKB'].fillna(0, inplace=True)
```

```python
def add_cScores(sections):
    sections=sections.copy()
    sections['cScores']=sections['area']/(sections['b']*sections['t'])
    mask=sections['cScores']>1
    sections.loc[mask,'cScores']=1
    return sections

def cut_sections(sections, draught):
    sections=sections.copy()
    mask = sections['t']>draught
    sections.loc[mask,'t']=draught
    sections.loc[mask,'area']-=draught*sections['b'].max()  # Assuming rectangular shape
    return sections

def remove_duplicate_sections(sections):
    sections=sections.copy()
    mask=~sections['x'].duplicated()
    sections=sections.loc[mask]
    assert sections['x'].is_unique
    return sections

def too_small_sections(sections):
    sections=sections.copy()
    small = 0.1
    mask=sections['b']==0
    sections.loc[mask,'b']=small
    mask=sections['t']==0
    sections.loc[mask,'t']=small
    mask=sections['area']==0
    sections.loc[mask,'area']=small
    return sections
```

```python
from scipy.integrate import simps
def calculate_lcb(x, area, **kwargs):
    """
    Calculate lcb from AP
    """
    return simps(y=area*x,x=x)/np.trapz(y=area,x=x)

def calculate_dispacement(x, area, **kwargs):
    """
    Calculate displacement
    """
    return np.trapz(y=area,x=x)
```

```python
class DraughtError(ValueError): pass

def define_indata(row, sections, rho=1000,  g=9.81):

    indata = Indata()

    draught=(row.TA+row.TF)/2
    indata.draught=draught
    if draught<=sections['t'].max():
        sections = cut_sections(sections, draught)
    else:
        raise DraughtError('Draught is too large for sections')

    sections=add_cScores(sections)

    indata.cScores=np.array(sections['cScores'])
    indata.ts=np.array(sections['t'])
    indata.bs=np.array(sections['b'])
    indata.zbars=np.zeros_like(sections['b'])  # Guessing...

    beam=sections['b'].max()
    indata.lpp=sections['x'].max()-sections['x'].min()
    #indata.displacement=row.Volume
    indata.displacement=calculate_dispacement(**sections)

    indata.g=g
    indata.kxx=row.KXX
    indata.kyy=row.lpp*0.4
    lcb=calculate_lcb(x=sections['x'], area=sections['area'])
    indata.lcb=lcb-row.lpp/2
    indata.lpp=row.lpp
    indata.projectName='loading_condition_id_%i' % row.loading_condition_id

    indata.rho=rho
    indata.zcg=row.kg-draught
    #indata.waveFrequenciesMin=0.2
    #indata.waveFrequenciesMax=0.5
    #indata.waveFrequenciesIncrement=0.006
    w=row.omega0/np.sqrt(row.scale_factor)
    indata.waveFrequenciesMin=w*0.5
    indata.waveFrequenciesMax=w*2.0
    N=40
    indata.waveFrequenciesIncrement=(indata.waveFrequenciesMax-indata.waveFrequenciesMin)/N
    indata.runOptions["IE"].set_value(1)

    return indata,sections
```

```python
def create_ikeda(row, indata, output_file, fi_a):

    w = row.omega0
    scale_factor=row.scale_factor
    V = row.ship_speed*1.852/3.6/np.sqrt(scale_factor)
    R = 0.01*row.beam/scale_factor
    lBK=row.BKL/scale_factor
    bBK=row.BKB/scale_factor
    kg = row.kg/scale_factor

    ikeda = Ikeda.load_scoresII(V=V, w=w, fi_a=fi_a, indata=indata, output_file=output_file,
                                scale_factor=scale_factor, BKL=lBK, BKB=bBK, kg=kg)

    return ikeda
```

```python
def calculate_ikeda(ikeda):

    output = pd.DataFrame()
    output['B_44_hat']   = ikeda.calculate_B44()
    output['B_W0_hat']   = float(ikeda.calculate_B_W0())
    output['B_W_hat']    = float(ikeda.calculate_B_W())
    output['B_F_hat']    = ikeda.calculate_B_F()
    output['B_E_hat']    = ikeda.calculate_B_E()
    output['B_BK_hat']   = ikeda.calculate_B_BK()
    output['B_L_hat']    = float(ikeda.calculate_B_L())
    output['Bw_div_Bw0'] = float(ikeda.calculate_Bw_div_Bw0())
    return output
```

```python
def get_B_1_B2(s1,s2,fi_as:np.ndarray):

    # Derive linear and quadratic part for all components:

    if isinstance(s1,pd.Series):
        result=pd.Series(name=row.name)
        columns = s1.index
    elif isinstance(s1,pd.DataFrame):
        result=pd.DataFrame()
        columns = s1.columns
    else:
        raise ValueError('s1 must be pd.Series or pd.DataFrame')

    x = fi_as*8*row.omega0/(3 * np.pi)
    B_2 = (s2 - s1) / (x[1] - x[0])
    B_1 = s1 - B_2 * x[0]

    # Save all of the component as one linear term: _1 and a quadratic term: _2

    for key in columns:
        new_name_1 = '%s_1' % key
        result[new_name_1] = s1[key]

        new_name_2 = '%s_2' % key
        result[new_name_2] = s2[key]

    return result
```

```python
results = pd.DataFrame()
fi_as = np.deg2rad([1,10])
for run_name, row in df.iterrows():
    loading_condition_id=row['loading_condition_id']
    sections = section_groups.get_group(loading_condition_id)
    sections=remove_duplicate_sections(sections)
    sections=too_small_sections(sections)

    try:
        indata,sections_ = define_indata(row, sections)
    except DraughtError as e:
        print('Draught is too large for sections, this loading condition is skipped.')
        continue

    save_name='%s.in' % row.loading_condition_id
    save_path=os.path.join('scores',save_name)
    indata.save(save_path)

    calculation = Calculation(outDataDirectory='scores/result')

    # Run scoresII:
    try:
        calculation.run(indata=indata, b_div_t_max=None, timeout=1.0)
    except TDPError:
        print('Dissregarding the TDPError')
        continue
    except pyscores2.LcgError as e:
        print('Disregarded')
        print(e)
        continue
    except subprocess.TimeoutExpired:
        print('Disregarded, scoresII got stuck...')
        continue

    output_file = OutputFile(filePath=calculation.outDataPath)

    ikeda = create_ikeda(row=row, indata=indata, output_file=output_file, fi_a=fi_as)
    result_datas = ikeda.calculate()
    #result_datas = calculate_ikeda(ikeda)  # DataFrame with two roll amplitudes

    # Derive linear and quadratic part for all components:
    s1=result_datas.iloc[0]
    s2=result_datas.iloc[1]
    result = get_B_1_B2(s1=s1, s2=s2, fi_as=fi_as)

    results=results.append(result)

```

    Running Scores2 for loading_condition_id_107

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_14

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_34

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:190: RuntimeWarning: divide by zero encountered in true_divide
      So = (0.3 * pi * l * fi_a * f / bBK + 1.95) * bBK;
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:190: RuntimeWarning: invalid value encountered in multiply
      So = (0.3 * pi * l * fi_a * f / bBK + 1.95) * bBK;
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_14

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_14

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_34

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:190: RuntimeWarning: divide by zero encountered in true_divide
      So = (0.3 * pi * l * fi_a * f / bBK + 1.95) * bBK;
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:190: RuntimeWarning: invalid value encountered in multiply
      So = (0.3 * pi * l * fi_a * f / bBK + 1.95) * bBK;
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_34

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:190: RuntimeWarning: divide by zero encountered in true_divide
      So = (0.3 * pi * l * fi_a * f / bBK + 1.95) * bBK;
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:190: RuntimeWarning: invalid value encountered in multiply
      So = (0.3 * pi * l * fi_a * f / bBK + 1.95) * bBK;
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_34

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:190: RuntimeWarning: divide by zero encountered in true_divide
      So = (0.3 * pi * l * fi_a * f / bBK + 1.95) * bBK;
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:190: RuntimeWarning: invalid value encountered in multiply
      So = (0.3 * pi * l * fi_a * f / bBK + 1.95) * bBK;
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_89
    Disregarded, scoresII got stuck...
    Running Scores2 for loading_condition_id_119

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_89
    Disregarded, scoresII got stuck...
    Running Scores2 for loading_condition_id_10

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_119

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_99
    Disregarded, scoresII got stuck...
    Running Scores2 for loading_condition_id_10

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_10

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_6

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_3
    Dissregarding the TDPError
    Running Scores2 for loading_condition_id_3
    Dissregarding the TDPError
    Running Scores2 for loading_condition_id_6

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_6

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_37

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:586: RuntimeWarning: invalid value encountered in sqrt
      gamma=sqrt(pi)*f3*(rmax+2*M/H*sqrt(B0**2*A0**2))/((2*Ts*(1-OG/Ts)*sqrt(H0_prim*sigma_prim)))
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_15

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_20

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_106

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:586: RuntimeWarning: invalid value encountered in sqrt
      gamma=sqrt(pi)*f3*(rmax+2*M/H*sqrt(B0**2*A0**2))/((2*Ts*(1-OG/Ts)*sqrt(H0_prim*sigma_prim)))
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_15

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_15

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_106

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:586: RuntimeWarning: invalid value encountered in sqrt
      gamma=sqrt(pi)*f3*(rmax+2*M/H*sqrt(B0**2*A0**2))/((2*Ts*(1-OG/Ts)*sqrt(H0_prim*sigma_prim)))
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_106

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:586: RuntimeWarning: invalid value encountered in sqrt
      gamma=sqrt(pi)*f3*(rmax+2*M/H*sqrt(B0**2*A0**2))/((2*Ts*(1-OG/Ts)*sqrt(H0_prim*sigma_prim)))
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Draught is too large for sections, this loading condition is skipped.
    Running Scores2 for loading_condition_id_100

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Draught is too large for sections, this loading condition is skipped.
    Running Scores2 for loading_condition_id_8

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:586: RuntimeWarning: invalid value encountered in sqrt
      gamma=sqrt(pi)*f3*(rmax+2*M/H*sqrt(B0**2*A0**2))/((2*Ts*(1-OG/Ts)*sqrt(H0_prim*sigma_prim)))
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_8

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:586: RuntimeWarning: invalid value encountered in sqrt
      gamma=sqrt(pi)*f3*(rmax+2*M/H*sqrt(B0**2*A0**2))/((2*Ts*(1-OG/Ts)*sqrt(H0_prim*sigma_prim)))
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Draught is too large for sections, this loading condition is skipped.
    Draught is too large for sections, this loading condition is skipped.
    Running Scores2 for loading_condition_id_118
    Disregarded, scoresII got stuck...
    Running Scores2 for loading_condition_id_13

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_1

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_13

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_13

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_4

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_4

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_49
    Disregarded
    <class 'pyscores2.LcgError'>: The calculated longitudinal centre of bouyancy differ from the nomonal value ((LCB-LCG)/L max 0.5%) Calculated LCB = 4.271000 m (FWD. OF MIDSHIPS)
    Running Scores2 for loading_condition_id_22

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_7

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_7

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_7

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_107

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_78

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_32

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:586: RuntimeWarning: invalid value encountered in sqrt
      gamma=sqrt(pi)*f3*(rmax+2*M/H*sqrt(B0**2*A0**2))/((2*Ts*(1-OG/Ts)*sqrt(H0_prim*sigma_prim)))
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:190: RuntimeWarning: divide by zero encountered in true_divide
      So = (0.3 * pi * l * fi_a * f / bBK + 1.95) * bBK;
    c:\dev\rolldecay-estimators\rolldecayestimators\ikeda_speed.py:190: RuntimeWarning: invalid value encountered in multiply
      So = (0.3 * pi * l * fi_a * f / bBK + 1.95) * bBK;
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_78

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_78

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_78

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_107

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_21

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_21

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_19

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_107

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_79

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_79

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

    Running Scores2 for loading_condition_id_79

    c:\python36-64\lib\re.py:212: FutureWarning: split() requires a non-empty pattern match.
      return _compile(pattern, flags).split(string, maxsplit)
    c:\dev\prediction-of-roll-damping-using-fully-nonlinear-potential-flow-and-ikedas-method\venv\lib\site-packages\ipykernel_launcher.py:6: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.

```python
results['id']=results.index
```

```python
results
```

      B_44_hat_1
      B_44_hat_2
      B_BK_hat_1
      B_BK_hat_2
      B_E_hat_1
      B_E_hat_2
      B_F_hat_1
      B_F_hat_2
      B_L_hat_1
      B_L_hat_2
      B_W0_hat_1
      B_W0_hat_2
      B_W_hat_1
      B_W_hat_2
      Bw_div_Bw0_1
      Bw_div_Bw0_2
      id

      14848
      0.004185
      0.008983
      0.000490
      0.005110
      0.000005
      0.000053
      0.000591
      0.000722
      0.002860
      0.002860
      0.000034
      0.000034
      0.000238
      0.000238
      6.967885
      6.967885
      14848

      2570
      0.001133
      0.005699
      0.000393
      0.004544
      0.000035
      0.000352
      0.000426
      0.000525
      0.000018
      0.000018
      0.000261
      0.000261
      0.000261
      0.000261
      1.000605
      1.000605
      2570

      4620
      0.000682
      0.001005
      0.000000
      0.000000
      0.000027
      0.000266
      0.000347
      0.000430
      0.000000
      0.000000
      0.000308
      0.000308
      0.000308
      0.000308
      1.000436
      1.000436
      4620

      2573
      0.005408
      0.009717
      0.000407
      0.004519
      0.000008
      0.000078
      0.000553
      0.000680
      0.002474
      0.002474
      0.000259
      0.000259
      0.001966
      0.001966
      7.594869
      7.594869
      2573

      2574
      0.006185
      0.010625
      0.000428
      0.004681
      0.000005
      0.000050
      0.000608
      0.000750
      0.003446
      0.003446
      0.000266
      0.000266
      0.001699
      0.001699
      6.376932
      6.376932
      2574

      4629
      0.008334
      0.008492
      0.000000
      0.000000
      0.000001
      0.000012
      0.000611
      0.000758
      0.005772
      0.005772
      0.000311
      0.000311
      0.001950
      0.001950
      6.264634
      6.264634
      4629

      4630
      0.006317
      0.006465
      0.000000
      0.000000
      0.000002
      0.000022
      0.000535
      0.000663
      0.004123
      0.004123
      0.000306
      0.000306
      0.001657
      0.001657
      5.418093
      5.418093
      4630

      4631
      0.002898
      0.003068
      0.000000
      0.000000
      0.000007
      0.000071
      0.000441
      0.000547
      0.002061
      0.002061
      0.000308
      0.000308
      0.000388
      0.000388
      1.259106
      1.259106
      4631

      15923
      0.001965
      0.006245
      0.000327
      0.003988
      0.000059
      0.000586
      0.000423
      0.000515
      0.000000
      0.000000
      0.001156
      0.001156
      0.001156
      0.001156
      1.000292
      1.000292
      15923

      2104
      0.000956
      0.004896
      0.000344
      0.003948
      0.000027
      0.000267
      0.000401
      0.000497
      0.000000
      0.000000
      0.000184
      0.000184
      0.000184
      0.000184
      1.000510
      1.000510
      2104

      15929
      0.006664
      0.010606
      0.000345
      0.004041
      0.000014
      0.000141
      0.000550
      0.000670
      0.001391
      0.001391
      0.001152
      0.001152
      0.004364
      0.004364
      3.788399
      3.788399
      15929

      2164
      0.004545
      0.008299
      0.000358
      0.003937
      0.000006
      0.000056
      0.000526
      0.000651
      0.002318
      0.002318
      0.000184
      0.000184
      0.001336
      0.001336
      7.274507
      7.274507
      2164

      2165
      0.005426
      0.009264
      0.000374
      0.004042
      0.000003
      0.000033
      0.000583
      0.000723
      0.003312
      0.003312
      0.000186
      0.000186
      0.001153
      0.001153
      6.186781
      6.186781
      2165

      1168
      0.000850
      0.004020
      0.000286
      0.003154
      0.000023
      0.000235
      0.000409
      0.000500
      0.000000
      0.000000
      0.000132
      0.000132
      0.000132
      0.000132
      1.000645
      1.000645
      1168

      1180
      0.004355
      0.007372
      0.000303
      0.003157
      0.000005
      0.000047
      0.000543
      0.000663
      0.002417
      0.002417
      0.000131
      0.000131
      0.001088
      0.001088
      8.281190
      8.281190
      1180

      1181
      0.005367
      0.008439
      0.000316
      0.003229
      0.000003
      0.000028
      0.000598
      0.000732
      0.003367
      0.003367
      0.000133
      0.000133
      0.001083
      0.001083
      8.134808
      8.134808
      1181

      4789
      0.001271
      0.004528
      0.000295
      0.002417
      0.000118
      0.001178
      0.000324
      0.000400
      0.000000
      0.000000
      0.000534
      0.000534
      0.000534
      0.000534
      1.000127
      1.000127
      4789

      2742
      0.002474
      0.007986
      0.000489
      0.005106
      0.000089
      0.000890
      0.000411
      0.000506
      0.000006
      0.000006
      0.001477
      0.001477
      0.001478
      0.001478
      1.000301
      1.000301
      2742

      3255
      0.002040
      0.007302
      0.000456
      0.005147
      0.000050
      0.000503
      0.000467
      0.000585
      0.000000
      0.000000
      0.001067
      0.001067
      0.001068
      0.001068
      1.000391
      1.000391
      3255

      13504
      0.000880
      0.003656
      0.000327
      0.002632
      0.000044
      0.000443
      0.000386
      0.000460
      0.000000
      0.000000
      0.000122
      0.000122
      0.000122
      0.000122
      1.000270
      1.000270
      13504

      2753
      0.007403
      0.012452
      0.000509
      0.005143
      0.000033
      0.000334
      0.000499
      0.000614
      0.000894
      0.000894
      0.001476
      0.001476
      0.005468
      0.005468
      3.705346
      3.705346
      2753

      2754
      0.007231
      0.012227
      0.000521
      0.005199
      0.000022
      0.000215
      0.000535
      0.000658
      0.001245
      0.001245
      0.001472
      0.001472
      0.004910
      0.004910
      3.334788
      3.334788
      2754

      13521
      0.002518
      0.005022
      0.000346
      0.002650
      0.000012
      0.000118
      0.000492
      0.000586
      0.001227
      0.001227
      0.000122
      0.000122
      0.000442
      0.000442
      3.614922
      3.614922
      13521

      13524
      0.003137
      0.005644
      0.000358
      0.002698
      0.000007
      0.000072
      0.000536
      0.000639
      0.001717
      0.001717
      0.000125
      0.000125
      0.000518
      0.000518
      4.147408
      4.147408
      13524

      12528
      0.006419
      0.010997
      0.000357
      0.004611
      0.000022
      0.000219
      0.000568
      0.000696
      0.001177
      0.001177
      0.001316
      0.001316
      0.004295
      0.004295
      3.262961
      3.262961
      12528

      1779
      0.000623
      0.003270
      0.000171
      0.002166
      0.000065
      0.000651
      0.000305
      0.000372
      0.000000
      0.000000
      0.000081
      0.000081
      0.000081
      0.000081
      1.000226
      1.000226
      1779

      1780
      0.002164
      0.004375
      0.000178
      0.002180
      0.000013
      0.000135
      0.000404
      0.000493
      0.001256
      0.001256
      0.000082
      0.000082
      0.000312
      0.000312
      3.828134
      3.828134
      1780

      2320
      0.002314
      0.007410
      0.000456
      0.004762
      0.000077
      0.000771
      0.000402
      0.000498
      0.000000
      0.000000
      0.001379
      0.001379
      0.001379
      0.001379
      1.000250
      1.000250
      2320

      273
      0.011760
      0.017928
      0.004062
      0.010107
      0.000001
      0.000013
      0.000791
      0.000902
      0.003953
      0.003953
      0.000254
      0.000254
      0.002952
      0.002952
      11.618038
      11.618038
      273

      2334
      0.007048
      0.011731
      0.000475
      0.004792
      0.000028
      0.000275
      0.000491
      0.000609
      0.000925
      0.000925
      0.001377
      0.001377
      0.005129
      0.005129
      3.724342
      3.724342
      2334

      2335
      0.006952
      0.011586
      0.000487
      0.004841
      0.000017
      0.000169
      0.000531
      0.000658
      0.001321
      0.001321
      0.001374
      0.001374
      0.004596
      0.004596
      3.345958
      3.345958
      2335

      832
      0.002213
      0.007389
      0.000417
      0.004868
      0.000068
      0.000678
      0.000470
      0.000586
      0.000000
      0.000000
      0.001257
      0.001257
      0.001258
      0.001258
      1.000302
      1.000302
      832

      833
      0.007843
      0.012644
      0.000446
      0.004958
      0.000015
      0.000151
      0.000620
      0.000773
      0.001946
      0.001946
      0.001254
      0.001254
      0.004816
      0.004816
      3.840035
      3.840035
      833

      3462
      0.000764
      0.003268
      0.000207
      0.002093
      0.000060
      0.000597
      0.000355
      0.000435
      0.000000
      0.000000
      0.000142
      0.000142
      0.000142
      0.000142
      1.000291
      1.000291
      3462

      1418
      0.001979
      0.006091
      0.000383
      0.003810
      0.000065
      0.000652
      0.000429
      0.000527
      0.000000
      0.000000
      0.001101
      0.001101
      0.001101
      0.001101
      1.000255
      1.000255
      1418

      1431
      0.006212
      0.009984
      0.000403
      0.003841
      0.000024
      0.000237
      0.000523
      0.000644
      0.001100
      0.001100
      0.001100
      0.001100
      0.004161
      0.004161
      3.784522
      3.784522
      1431

      1432
      0.006233
      0.009969
      0.000414
      0.003884
      0.000015
      0.000152
      0.000562
      0.000692
      0.001533
      0.001533
      0.001097
      0.001097
      0.003710
      0.003710
      3.381571
      3.381571
      1432

      14846
      0.005139
      0.009978
      0.000502
      0.005169
      0.000004
      0.000035
      0.000633
      0.000774
      0.003740
      0.003740
      0.000034
      0.000034
      0.000260
      0.000260
      7.637408
      7.637408
      14846

      8651
      0.001302
      0.006004
      0.000439
      0.004672
      0.000039
      0.000395
      0.000469
      0.000583
      0.000000
      0.000000
      0.000355
      0.000355
      0.000355
      0.000355
      1.000370
      1.000370
      8651

      4560
      NaN
      NaN
      NaN
      NaN
      0.000065
      0.000649
      0.000311
      0.000380
      0.000000
      0.000000
      0.000050
      0.000050
      0.000050
      0.000050
      1.000184
      1.000184
      4560

      8667
      0.005120
      0.009588
      0.000457
      0.004680
      0.000011
      0.000113
      0.000590
      0.000733
      0.002055
      0.002055
      0.000355
      0.000355
      0.002007
      0.002007
      5.659547
      5.659547
      8667

      8668
      0.005571
      0.010091
      0.000470
      0.004765
      0.000008
      0.000078
      0.000630
      0.000784
      0.002687
      0.002687
      0.000356
      0.000356
      0.001776
      0.001776
      4.982959
      4.982959
      8668

      8669
      0.006057
      0.010585
      0.000478
      0.004793
      0.000006
      0.000056
      0.000667
      0.000831
      0.003320
      0.003320
      0.000357
      0.000357
      0.001586
      0.001586
      4.444776
      4.444776
      8669

      14826
      0.000984
      0.005901
      0.000470
      0.005091
      0.000022
      0.000216
      0.000459
      0.000560
      0.000000
      0.000000
      0.000034
      0.000034
      0.000034
      0.000034
      1.000551
      1.000551
      14826

      3563
      0.000682
      0.003022
      0.000187
      0.001878
      0.000064
      0.000638
      0.000335
      0.000411
      0.000000
      0.000000
      0.000096
      0.000096
      0.000096
      0.000096
      1.000272
      1.000272
      3563

      3564
      0.002390
      0.004299
      0.000201
      0.001900
      0.000012
      0.000122
      0.000451
      0.000552
      0.001302
      0.001302
      0.000097
      0.000097
      0.000424
      0.000424
      4.391239
      4.391239
      3564

      3058
      0.001196
      0.005733
      0.000380
      0.004438
      0.000041
      0.000406
      0.000441
      0.000554
      0.000016
      0.000016
      0.000319
      0.000319
      0.000319
      0.000319
      1.000455
      1.000455
      3058

      14844
      0.006026
      0.010889
      0.000510
      0.005200
      0.000002
      0.000025
      0.000674
      0.000825
      0.004620
      0.004620
      0.000034
      0.000034
      0.000219
      0.000219
      6.441421
      6.441421
      14844

      8701
      0.007547
      0.012273
      0.000524
      0.004809
      0.000035
      0.000348
      0.000535
      0.000662
      0.000818
      0.000818
      0.001544
      0.001544
      0.005635
      0.005635
      3.650424
      3.650424
      8701

      8702
      0.007095
      0.011764
      0.000533
      0.004845
      0.000025
      0.000248
      0.000564
      0.000698
      0.001070
      0.001070
      0.001541
      0.001541
      0.004903
      0.004903
      3.181547
      3.181547
      8702

      8703
      0.007307
      0.011945
      0.000542
      0.004874
      0.000018
      0.000182
      0.000592
      0.000733
      0.001322
      0.001322
      0.001539
      0.001539
      0.004833
      0.004833
      3.140677
      3.140677
      8703

```python
results.head()
```

      B_44_hat_1
      B_44_hat_2
      B_BK_hat_1
      B_BK_hat_2
      B_E_hat_1
      B_E_hat_2
      B_F_hat_1
      B_F_hat_2
      B_L_hat_1
      B_L_hat_2
      B_W0_hat_1
      B_W0_hat_2
      B_W_hat_1
      B_W_hat_2
      Bw_div_Bw0_1
      Bw_div_Bw0_2
      id

      14848
      0.004185
      0.008983
      0.000490
      0.005110
      0.000005
      0.000053
      0.000591
      0.000722
      0.002860
      0.002860
      0.000034
      0.000034
      0.000238
      0.000238
      6.967885
      6.967885
      14848

      2570
      0.001133
      0.005699
      0.000393
      0.004544
      0.000035
      0.000352
      0.000426
      0.000525
      0.000018
      0.000018
      0.000261
      0.000261
      0.000261
      0.000261
      1.000605
      1.000605
      2570

      4620
      0.000682
      0.001005
      0.000000
      0.000000
      0.000027
      0.000266
      0.000347
      0.000430
      0.000000
      0.000000
      0.000308
      0.000308
      0.000308
      0.000308
      1.000436
      1.000436
      4620

      2573
      0.005408
      0.009717
      0.000407
      0.004519
      0.000008
      0.000078
      0.000553
      0.000680
      0.002474
      0.002474
      0.000259
      0.000259
      0.001966
      0.001966
      7.594869
      7.594869
      2573

      2574
      0.006185
      0.010625
      0.000428
      0.004681
      0.000005
      0.000050
      0.000608
      0.000750
      0.003446
      0.003446
      0.000266
      0.000266
      0.001699
      0.001699
      6.376932
      6.376932
      2574

```python
df.head()
```

      model_number
      loading_condition_id
      ship_speed
      B_1A
      B_2A
      C_1A
      B_1
      B_2
      C_1
      A_44
      omega0
      omega0_fft
      score
      phi_start
      phi_stop
      id
      project_number
      series_number
      run_number
      test_number
      ship_name
      ascii_name
      comment
      file_path_ascii
      file_path_ascii_temp
      file_path_log
      file_path_hdf5
      date
      test_type
      facility
      angle1
      angle2
      Körfallstyp
      name
      project_path
      lcg
      kg
      gm
      CW
      TF
      TA
      BWL
      KXX
      KZZ
      BTT1
      CP
      Volume
      A0
      RH
      scale_factor
      lpp
      beam
      ABULB
      BKX
      TWIN
      DCLR
      VDES
      RHBL
      ASKEG
      PD
      ARH
      CFP
      AIX
      PDTDES
      RTYPE
      SFP
      BKL
      BKB
      PROT
      D
      LSKEG
      RR
      XSKEG
      NDES
      AR
      BR
      BRA
      IRUD
      PTYPE
      XRUD
      AI
      HSKEG
      RSKEG
      LOA
      ship_type_id

      run_id

      14848
      3541-A
      107
      13.0
      0.088786
      0.442492
      6.175780
      6.821454
      33.996705
      474.485974
      76.830134
      2.485112
      2.488141
      0.999477
      -0.138416
      0.006405
      14848
      20136522
      1
      32
      1
      3541-A
      20136522-ser001-k032-100hz.asc
      Kursstyrning Roll decay
      N:\Gamla_Projekt\ascii_files\20136522-ser001-k...
      None
      \\sspa.local\gbg\MDLdata\Gamla_Projekt\Gamla_P...
      None
      2014-12-29
      roll decay
      MDL
      None
      None
      Kursstyrning
      20136522_Hudong-Zhonghua 170k class LNGC
      S:\2013\20136522-Hudong-Zhonghua-170k-class-LNG
      -4.190
      18.38
      3.80
      0.847
      11.50
      11.50
      46.97
      15.5
      65.32
      3.36
      0.7669
      116472.0
      0.9899
      8.50
      55.0000
      284.00
      46.97
      5.1
      -7.665
      1.0
      8.4
      19.8
      9.2
      130.0
      0.991
      0.00
      None
      None
      20000.0
      1.0
      NaN
      92.13
      0.43
      3.0
      8.3
      28.0
      2.32
      -123.0
      67.8
      49.40
      0.0
      0.0
      2.0
      1.0
      -142.00
      None
      7.7
      58.0
      290.00
      4.0

      2570
      3239-A
      14
      0.1
      0.017279
      0.525094
      5.870454
      1.869850
      56.822711
      635.267667
      108.214410
      2.422902
      2.425310
      0.999079
      -0.151823
      0.015199
      2570
      20074477
      1
      27
      1
      3239-A
      20074477-ser001-k027-100hz.asc
      Kursstyrning Roll decay
      N:\Gamla_Projekt\ascii_files\20074477-ser001-k...
      None
      \\sspa.local\gbg\MDLdata\Gamla_Projekt\gamla_p...
      None
      2007-11-20
      roll decay
      MDL
      None
      None
      Kursstyrning
      20074477
      \\sspa.local\gbg\ProjektArkiv\2007\20074477
      -0.953
      17.40
      3.89
      0.843
      11.50
      11.50
      45.80
      15.1
      66.20
      2.44
      0.7566
      114188.0
      0.9900
      11.20
      51.1765
      288.00
      45.80
      49.0
      1.000
      0.0
      0.0
      19.5
      11.4
      120.0
      0.800
      16.66
      None
      None
      NaN
      1.0
      NaN
      90.55
      0.40
      1.0
      8.7
      24.0
      2.32
      -127.0
      78.5
      81.34
      0.0
      0.0
      1.0
      1.0
      -144.00
      None
      7.1
      8.7
      300.00
      4.0

      4620
      Aker
      34
      0.0
      0.011280
      0.102312
      4.532723
      1.524651
      13.829206
      612.671657
      135.166363
      2.129019
      2.130000
      0.999027
      -0.155755
      -0.001109
      4620
      20095111
      1
      7
      1
      Aker
      20095111-ser001-k007-100hz.asc
      Kursstyrning Roll decay
      N:\Gamla_Projekt\ascii_files\20095111-ser001-k...
      None
      \\sspa.local\gbg\MDLdata\Gamla_Projekt\gamla_p...
      None
      2009-11-02
      roll decay
      MDL
      None
      None
      Kursstyrning
      20095111
      \\sspa.local\gbg\ProjektArkiv\2009\20095111
      -1.390
      10.06
      1.86
      NaN
      8.53
      8.53
      24.38
      9.2
      27.60
      2.85
      NaN
      14648.0
      0.9940
      4.34
      25.7000
      92.66
      24.38
      0.0
      0.000
      0.0
      5.4
      16.0
      5.5
      52.0
      1.089
      0.00
      None
      None
      16946.0
      1.0
      NaN
      0.00
      0.00
      3.0
      4.6
      18.5
      2.32
      -40.5
      150.0
      15.50
      0.0
      0.0
      2.0
      1.0
      -46.33
      None
      5.9
      0.0
      109.93
      8.0

      2573
      3239-A
      14
      14.0
      0.092735
      0.593809
      5.774783
      10.201494
      65.323279
      635.267667
      110.007200
      2.403078
      2.400177
      0.997486
      0.146696
      0.012351
      2573
      20074477
      1
      30
      1
      3239-A
      20074477-ser001-k030-100hz.asc
      Kursstyrning Roll decay
      N:\Gamla_Projekt\ascii_files\20074477-ser001-k...
      None
      \\sspa.local\gbg\MDLdata\Gamla_Projekt\gamla_p...
      None
      2007-11-20
      roll decay
      MDL
      None
      None
      Kursstyrning
      20074477
      \\sspa.local\gbg\ProjektArkiv\2007\20074477
      -0.953
      17.40
      3.89
      0.843
      11.50
      11.50
      45.80
      15.1
      66.20
      2.44
      0.7566
      114188.0
      0.9900
      11.20
      51.1765
      288.00
      45.80
      49.0
      1.000
      0.0
      0.0
      19.5
      11.4
      120.0
      0.800
      16.66
      None
      None
      NaN
      1.0
      NaN
      90.55
      0.40
      1.0
      8.7
      24.0
      2.32
      -127.0
      78.5
      81.34
      0.0
      0.0
      1.0
      1.0
      -144.00
      None
      7.1
      8.7
      300.00
      4.0

      2574
      3239-A
      14
      19.5
      0.223103
      0.396531
      6.181753
      22.927161
      40.749456
      635.267667
      102.764975
      2.486313
      2.494425
      0.997824
      0.132958
      0.005539
      2574
      20074477
      1
      31
      1
      3239-A
      20074477-ser001-k031-100hz.asc
      Kursstyrning Roll decay
      N:\Gamla_Projekt\ascii_files\20074477-ser001-k...
      None
      \\sspa.local\gbg\MDLdata\Gamla_Projekt\gamla_p...
      None
      2007-11-20
      roll decay
      MDL
      None
      None
      Kursstyrning
      20074477
      \\sspa.local\gbg\ProjektArkiv\2007\20074477
      -0.953
      17.40
      3.89
      0.843
      11.50
      11.50
      45.80
      15.1
      66.20
      2.44
      0.7566
      114188.0
      0.9900
      11.20
      51.1765
      288.00
      45.80
      49.0
      1.000
      0.0
      0.0
      19.5
      11.4
      120.0
      0.800
      16.66
      None
      None
      NaN
      1.0
      NaN
      90.55
      0.40
      1.0
      8.7
      24.0
      2.32
      -127.0
      78.5
      81.34
      0.0
      0.0
      1.0
      1.0
      -144.00
      None
      7.1
      8.7
      300.00
      4.0

## Make comparison with model tests

```python
df2 = df.copy()
scale_factor = df2['scale_factor']
df2['Volume']/=(scale_factor**3)
df2['Disp']=df2['Volume']
df2['beam']/=scale_factor
df2['lpp']/=scale_factor
df2['kg']/=scale_factor
df2['BKB']/=scale_factor
df2['BKL']/=scale_factor

```

```python
df['Disp']=df2['Volume']
results['Disp']=df2.loc[results.index,'Disp']
results['omega0']=df2.loc[results.index,'omega0']

#df_compare = measure.linearized_matrix(df_rolldecay=df2, df_ikeda=results, do_hatify=False)
#mask=df_compare['B_e_hat_ikeda'].notnull()
#df_compare=df_compare.loc[mask].copy()
```

```python
def linearize_model_tests(df_rolldecay, phi_as = np.deg2rad(np.linspace(1,10,10)), g=9.81, rho=1000):

    df = pd.DataFrame()

    for phi_a in phi_as:
        df_ = measure.linearize_model_test(phi_a=phi_a, df_rolldecay=df_rolldecay, g=g, rho=rho)
        df_['phi_a']=phi_a
        df =df.append(df_, ignore_index=True)

    return df

def linearize_ikedas(df_ikeda, phi_as = np.deg2rad(np.linspace(1,10,10)), g=9.81, rho=1000,
                     components = ['B_44_hat', 'B_F_hat', 'B_W_hat', 'B_E_hat', 'B_BK_hat', 'B_L_hat']):

    df = pd.DataFrame()

    for phi_a in phi_as:
        df_ = measure.linearize_si(phi_a=phi_a, df_ikeda=df_ikeda, do_hatify=False, components=components)
        df_['phi_a']=phi_a
        df =df.append(df_, ignore_index=True)

    return df
```

```python
df_rolldecays=linearize_model_tests(df_rolldecay=df2)
df_ikedas=linearize_ikedas(df_ikeda=results)
df_ikedas.dropna(subset=['B_e_hat'], inplace=True)
```

```python
df_compare = pd.merge(left=df_rolldecays, right=df_ikedas, how='inner', left_on=('id','phi_a'), right_on=('id','phi_a'), suffixes=('','_ikeda'))
```

```python
fig,ax=plt.subplots()
df_compare.plot(x='B_e_hat', y='B_e_hat_ikeda', ax=ax, style='o', alpha=0.05, ms=20, markeredgewidth=0)
```


# Neuromatch Academy: Week 3, Day 2, Tutorial 1
# Neuronal Network Dynamics: Neural Rate Models

__Content creators:__ Qinglong Gu, Songtin Li, Arvind Kumar, John Murray, Julijana Gjorgjieva

__Content reviewers:__  Maryam Vaziri-Pashkam, Ella Batty, Lorenzo Fontolan, Richard Gao, Spiros Chavlis, Michael Waskom

---
# Tutorial Objectives

The brain is a complex system, not because it is composed of a large number of diverse types of neurons, but mainly because of how neurons are connected to each other. The brain is indeed a network of highly specialized neuronal networks.

The activity of a neural network constantly evolves in time. For this reason, neurons can be modeled as dynamical systems. The dynamical system approach is only one of the many modeling approaches that computational neuroscientists have developed (other points of view include information processing,  statistical models, etc.).

How the dynamics of neuronal networks affect the representation and processing of information in the brain is an open question. However, signatures of altered brain dynamics present in many brain diseases (e.g., in epilepsy or Parkinson's disease) tell us that it is crucial to study network activity dynamics if we want to understand the brain.

In this tutorial, we will simulate and study one of the simplest models of biological neuronal networks. Instead of modeling and simulating individual excitatory neurons (e.g., LIF models that you implemented yesterday), we will treat them as a single homogeneous population and approximate their dynamics using a single one-dimensional equation describing the evolution of their average spiking rate in time.

In this tutorial, we will learn how to build a firing rate model of a single population of excitatory neurons.

**Steps:**
- Write the equation for the firing rate dynamics of a 1D excitatory population.
- Visualize the response of the population as a function of parameters such as threshold level and gain, using the frequency-current (F-I) curve.
- Numerically simulate the dynamics of the excitatory population and find the fixed points of the system.
- Investigate the stability of the fixed points by linearizing the dynamics around them.

---
# Setup

```python
# Imports
import matplotlib.pyplot as plt
import numpy as np
import scipy.optimize as opt       # root-finding algorithm
```

```python
# @title Figure Settings
import ipywidgets as widgets       # interactive display
%config InlineBackend.figure_format = 'retina'
plt.style.use("https://raw.githubusercontent.com/NeuromatchAcademy/course-content/master/nma.mplstyle")
```

```python
# @title Helper functions

def plot_fI(x, f):
  plt.figure(figsize=(6, 4))  # plot the figure
  plt.plot(x, f, 'k')
  plt.xlabel('x (a.u.)', fontsize=14)
  plt.ylabel('F(x)', fontsize=14)
  plt.show()

def plot_dr_r(r, drdt, x_fps=None):
  plt.figure()
  plt.plot(r, drdt, 'k')
  plt.plot(r, 0. * r, 'k--')
  if x_fps is not None:
    plt.plot(x_fps, np.zeros_like(x_fps), "ko", ms=12)
  plt.xlabel(r'$r$')
  plt.ylabel(r'$\frac{dr}{dt}$', fontsize=20)
  plt.ylim(-0.1, 0.1)

def plot_dFdt(x, dFdt):
  plt.figure()
  plt.plot(x, dFdt, 'r')
  plt.xlabel('x (a.u.)', fontsize=14)
  plt.ylabel('dF(x)', fontsize=14)
  plt.show()
```

---
# Section 1: Neuronal network dynamics

```python
# @title Video 1: Dynamic networks
from IPython.display import YouTubeVideo
video = YouTubeVideo(id="p848349hPyw", width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video
```

    Video available at https://youtube.com/watch?v=p848349hPyw

## Section 1.1: Dynamics of a single excitatory population

Individual neurons respond by spiking. When we average the spikes of neurons in a population, we can define the average firing activity of the population. In this model, we are interested in how the population-averaged firing varies as a function of time and network parameters. Mathematically, we can describe the firing rate dynamic as:

\begin{align}
\tau \frac{dr}{dt} &= -r + F(w\cdot r + I_{\text{ext}})  \quad\qquad (1)
\end{align}

$r(t)$ represents the average firing rate of the excitatory population at time $t$, $\tau$ controls the timescale of the evolution of the average firing rate, $w$ denotes the strength (synaptic weight) of the recurrent input to the population, $I_{\text{ext}}$ represents the external input, and the transfer function $F(\cdot)$ (which can be related to f-I curve of individual neurons described in the next sections) represents the population activation function in response to all received inputs.

To start building the model, please execute the cell below to initialize the simulation parameters.

```python
# @markdown *Execute this cell to set default parameters for a single excitatory population model*

def default_pars_single(**kwargs):
  pars = {}

  # Excitatory parameters
  pars['tau'] = 1.     # Timescale of the E population [ms]
  pars['a'] = 1.2      # Gain of the E population
  pars['theta'] = 2.8  # Threshold of the E population

  # Connection strength
  pars['w'] = 0.  # E to E, we first set it to 0

  # External input
  pars['I_ext'] = 0.

  # simulation parameters
  pars['T'] = 20.       # Total duration of simulation [ms]
  pars['dt'] = .1       # Simulation time step [ms]
  pars['r_init'] = 0.2  # Initial value of E

  # External parameters if any
  pars.update(kwargs)

  # Vector of discretized time points [ms]
  pars['range_t'] = np.arange(0, pars['T'], pars['dt'])

  return pars

```

You can now use:
- `pars = default_pars_single()` to get all the parameters, and then you can execute `print(pars)` to check these parameters.
- `pars = default_pars_single(T=T_sim, dt=time_step)` to set new simulation time and time step
- To update an existing parameter dictionary, use `pars['New_para'] = value`

Because `pars` is a dictionary, it can be passed to a function that requires individual parameters as arguments using `my_func(**pars)` syntax.

## Section 1.2: F-I curves
In electrophysiology, a neuron is often characterized by its spike rate output in response to input currents. This is often called the **F-I** curve, denoting the output spike frequency (**F**) in response to different injected currents (**I**). We estimated this for an LIF neuron in yesterday's tutorial.

The transfer function $F(\cdot)$ in Equation $1$ represents the gain of the population as a function of the total input. The gain is often modeled as a sigmoidal function, i.e., more input drive leads to a nonlinear increase in the population firing rate. The output firing rate will eventually saturate for high input values.

A sigmoidal $F(\cdot)$ is parameterized by its gain $a$ and threshold $\theta$.

$$ F(x;a,\theta) = \frac{1}{1+\text{e}^{-a(x-\theta)}} - \frac{1}{1+\text{e}^{a\theta}}  \quad(2)$$

The argument $x$ represents the input to the population. Note that the second term is chosen so that $F(0;a,\theta)=0$.

Many other transfer functions (generally monotonic) can be also used. Examples are the rectified linear function $ReLU(x)$ or the hyperbolic tangent $tanh(x)$.

### Exercise 1: Implement F-I curve

Let's first investigate the activation functions before simulating the dynamics of the entire population.

In this exercise, you will implement a sigmoidal **F-I** curve or transfer function $F(x)$, with gain $a$ and threshold level $\theta$ as parameters.

```python
def F(x, a, theta):
  """
  Population activation function.

  Args:
    x (float): the population input
    a (float): the gain of the function
    theta (float): the threshold of the function

  Returns:
    float: the population activation response F(x) for input x
  """
  #################################################
  ## TODO for students: compute f = F(x) ##
  # Fill out function and remove
  raise NotImplementedError("Student excercise: implement the f-I function")
  #################################################

  # Define the sigmoidal transfer function f = F(x)
  f = ...

  return f

pars = default_pars_single()  # get default parameters
x = np.arange(0, 10, .1)      # set the range of input

# Uncomment below to test your function
# f = F(x, pars['a'], pars['theta'])
# plot_fI(x, f)
```

[*Click for solution*](https://github.com/NeuromatchAcademy/course-content/tree/master//tutorials/W3D2_DynamicNetworks/solutions/W3D2_Tutorial1_Solution_45ddc05f.py)

*Example output:*

### Interactive Demo: Parameter exploration of F-I curve
Here's an interactive demo that shows how the F-I curve changes for different values of the gain and threshold parameters. How do the gain and threshold parameters affect the F-I curve?

```python
# @title

# @markdown Make sure you execute this cell to enable the widget!

def interactive_plot_FI(a, theta):
  """
  Population activation function.

  Expecxts:
    a     : the gain of the function
    theta : the threshold of the function

  Returns:
    plot the F-I curve with give parameters
  """

  # set the range of input
  x = np.arange(0, 10, .1)
  plt.figure()
  plt.plot(x, F(x, a, theta), 'k')
  plt.xlabel('x (a.u.)', fontsize=14)
  plt.ylabel('F(x)', fontsize=14)
  plt.show()

_ = widgets.interact(interactive_plot_FI, a=(0.3, 3, 0.3), theta=(2, 4, 0.2))
```

[*Click for solution*](https://github.com/NeuromatchAcademy/course-content/tree/master//tutorials/W3D2_DynamicNetworks/solutions/W3D2_Tutorial1_Solution_89df88ac.py)

## Section 1.3: Simulation scheme of E dynamics

Because $F(\cdot)$ is a nonlinear function, the exact solution of Equation $1$ can not be determined via analytical methods. Therefore, numerical methods must be used to find the solution. In practice, the derivative on the left-hand side of Equation $1$ can be approximated using the Euler method on a time-grid of stepsize $\Delta t$:

\begin{align}
&\frac{dr}{dt} \approx \frac{r[k+1]-r[k]}{\Delta t}
\end{align}
where $r[k] = r(k\Delta t)$.

Thus,

$$\Delta r[k] = \frac{\Delta t}{\tau}[-r[k] + F(w\cdot r[k] + I_{\text{ext}}(k;a,\theta))]$$

Hence, Equation (1) is updated at each time step by:

$$r[k+1] = r[k] + \Delta r[k]$$

```python
# @markdown *Execute this cell to enable the single population rate model simulator: `simulate_single`*

def simulate_single(pars):
  """
  Simulate an excitatory population of neurons

  Args:
    pars   : Parameter dictionary

  Returns:
    rE     : Activity of excitatory population (array)

  Example:
    pars = default_pars_single()
    r = simulate_single(pars)
  """

  # Set parameters
  tau, a, theta = pars['tau'], pars['a'], pars['theta']
  w = pars['w']
  I_ext = pars['I_ext']
  r_init = pars['r_init']
  dt, range_t = pars['dt'], pars['range_t']
  Lt = range_t.size

  # Initialize activity
  r = np.zeros(Lt)
  r[0] = r_init
  I_ext = I_ext * np.ones(Lt)

  # Update the E activity
  for k in range(Lt - 1):
      dr = dt / tau * (-r[k] + F(w * r[k] + I_ext[k], a, theta))
      r[k+1] = r[k] + dr

  return r

help(simulate_single)
```

    Help on function simulate_single in module __main__:

    simulate_single(pars)
        Simulate an excitatory population of neurons

        Args:
          pars   : Parameter dictionary

        Returns:
          rE     : Activity of excitatory population (array)

        Example:
          pars = default_pars_single()
          r = simulate_single(pars)

### Interactive Demo: Parameter Exploration of single population dynamics

Note that $w=0$, as in the default setting, means no recurrent input to the neuron population in Equation (1). Hence, the dynamics are entirely determined by the external input $I_{\text{ext}}$. Explore these dynamics in this interactive demo.

How does $r_{\text{sim}}(t)$ change with different $I_{\text{ext}}$ values? How does it change with different $\tau$ values? Investigate the relationship between $F(I_{\text{ext}}; a, \theta)$ and the steady value of $r(t)$.

Note that, $r_{\rm ana}(t)$ denotes the analytical solution - you will learn how this is computed in the next section.

```python
# @title

# @markdown Make sure you execute this cell to enable the widget!

# get default parameters
pars = default_pars_single(T=20.)

def Myplot_E_diffI_difftau(I_ext, tau):
  # set external input and time constant
  pars['I_ext'] = I_ext
  pars['tau'] = tau

  # simulation
  r = simulate_single(pars)

  # Analytical Solution
  r_ana = (pars['r_init']
           + (F(I_ext, pars['a'], pars['theta'])
           - pars['r_init']) * (1. - np.exp(-pars['range_t'] / pars['tau'])))

  # plot
  plt.figure()
  plt.plot(pars['range_t'], r, 'b', label=r'$r_{\mathrm{sim}}$(t)', alpha=0.5,
           zorder=1)
  plt.plot(pars['range_t'], r_ana, 'b--', lw=5, dashes=(2, 2),
           label=r'$r_{\mathrm{ana}}$(t)', zorder=2)
  plt.plot(pars['range_t'],
           F(I_ext, pars['a'], pars['theta']) * np.ones(pars['range_t'].size),
           'k--', label=r'$F(I_{\mathrm{ext}})$')
  plt.xlabel('t (ms)', fontsize=16.)
  plt.ylabel('Activity r(t)', fontsize=16.)
  plt.legend(loc='best', fontsize=14.)
  plt.show()

_ = widgets.interact(Myplot_E_diffI_difftau, I_ext=(0.0, 10., 1.),
                     tau=(1., 5., 0.2))
```

[*Click for solution*](https://github.com/NeuromatchAcademy/course-content/tree/master//tutorials/W3D2_DynamicNetworks/solutions/W3D2_Tutorial1_Solution_bfdcc723.py)

## Think!
Above, we have numerically solved a system driven by a positive input and that, if $w_{EE} \neq 0$, receives an excitatory recurrent input (**extra challenge: try changing the value of $w_{EE}$ to a positive number and plotting the results of simulate_single**). Yet, $r_E(t)$ either decays to zero or reaches a fixed non-zero value.
- Why doesn't the solution of the system "explode" in a finite time? In other words, what guarantees that $r_E$(t) stays finite?
- Which parameter would you change in order to increase the maximum value of the response?

[*Click for solution*](https://github.com/NeuromatchAcademy/course-content/tree/master//tutorials/W3D2_DynamicNetworks/solutions/W3D2_Tutorial1_Solution_d28fd68a.py)

---
# Section 2: Fixed points of the single population system

```python
# @title Video 2: Fixed point
from IPython.display import YouTubeVideo
video = YouTubeVideo(id="Ox3ELd1UFyo", width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video
```

    Video available at https://youtube.com/watch?v=Ox3ELd1UFyo

As you varied the two parameters in the last Interactive Demo, you noticed that, while at first the system output quickly changes, with time, it reaches its maximum/minimum value and does not change anymore. The value eventually reached by the system is called the **steady state** of the system, or the **fixed point**. Essentially, in the steady states the derivative with respect to time of the activity ($r$) is zero, i.e. $\displaystyle \frac{dr}{dt}=0$.

We can find that the steady state of the Equation. (1) by setting $\displaystyle{\frac{dr}{dt}=0}$ and solve for $r$:

$$-r_{\text{steady}} + F(w\cdot r_{\text{steady}} + I_{\text{ext}};a,\theta) = 0, \qquad (3)$$

When it exists, the solution of Equation. (3) defines a **fixed point** of the dynamical system in Equation (1). Note that if $F(x)$ is nonlinear, it is not always possible to find an analytical solution, but the solution can be found via numerical simulations, as we will do later.

From the Interactive Demo, one could also notice that the value of $\tau$ influences how quickly the activity will converge to the steady state from its initial value.

In the specific case of $w=0$, we can also analytically compute  the solution of Equation (1) (i.e., the thick blue dashed line) and deduce the role of $\tau$ in determining the convergence to the fixed point:

$$\displaystyle{r(t) = \big{[}F(I_{\text{ext}};a,\theta) -r(t=0)\big{]} (1-\text{e}^{-\frac{t}{\tau}})} + r(t=0)$$ \\

We can now numerically calculate the fixed point with a root finding algorithm.

## Exercise 2: Visualization of the fixed points

When it is not possible to find the solution for Equation (3) analytically, a graphical approach can be taken. To that end, it is useful to plot $\displaystyle{\frac{dr}{dt}}$ as a function of $r$. The values of $r$ for which the plotted function crosses zero on the y axis correspond to fixed points.

Here, let us, for example, set $w=5.0$ and $I^{\text{ext}}=0.5$. From Equation (1), you can obtain

$$\frac{dr}{dt} = [-r + F(w\cdot r + I^{\text{ext}})]\,/\,\tau $$

Then, plot the $dr/dt$ as a function of $r$, and check for the presence of fixed points.

```python
def compute_drdt(r, I_ext, w, a, theta, tau, **other_pars):
  """Given parameters, compute dr/dt as a function of r.

  Args:
    r (1D array) : Average firing rate of the excitatory population
    I_ext, w, a, theta, tau (numbers): Simulation parameters to use
    other_pars : Other simulation parameters are unused by this function

  Returns
    drdt function for each value of r
  """
  #########################################################################
  # TODO compute drdt and disable the error
  raise NotImplementedError("Finish the compute_drdt function")
  #########################################################################

  # Calculate drdt
  drdt = ...

  return drdt

# Define a vector of r values and the simulation parameters
r = np.linspace(0, 1, 1000)
pars = default_pars_single(I_ext=0.5, w=5)

# Uncomment to test your function
# drdt = compute_drdt(r, **pars)
# plot_dr_r(r, drdt)
```

[*Click for solution*](https://github.com/NeuromatchAcademy/course-content/tree/master//tutorials/W3D2_DynamicNetworks/solutions/W3D2_Tutorial1_Solution_c5280901.py)

*Example output:*

## Exercise 3: Fixed point calculation

We will now find the fixed points numerically. To do so, we need to specif initial values ($r_{\text{guess}}$) for the root-finding algorithm to start from. From the line $\displaystyle{\frac{dr}{dt}}$ plotted above in Exercise 2, initial values can be chosen as a set of values close to where the line crosses zero on the y axis (real fixed point).

The next cell defines three helper functions that we will use:

- `my_fp_single(r_guess, **pars)` uses a root-finding algorithm to locate a fixed point near a given initial value
- `check_fp_single(x_fp, **pars)`, verifies that the values of $r_{\rm fp}$ for which $\displaystyle{\frac{dr}{dt}} = 0$ are the true fixed points
- `my_fp_finder(r_guess_vector, **pars)` accepts an array of initial values and finds the same number of fixed points, using the above two functions

```python
# @markdown *Execute this cell to enable the fixed point functions*

def my_fp_single(r_guess, a, theta, w, I_ext, **other_pars):
  """
  Calculate the fixed point through drE/dt=0

  Args:
    r_guess  : Initial value used for scipy.optimize function
    a, theta, w, I_ext : simulation parameters

  Returns:
    x_fp    : value of fixed point
  """
  # define the right hand of E dynamics
  def my_WCr(x):
    r = x
    drdt = (-r + F(w * r + I_ext, a, theta))
    y = np.array(drdt)

    return y

  x0 = np.array(r_guess)
  x_fp = opt.root(my_WCr, x0).x.item()

  return x_fp

def check_fp_single(x_fp, a, theta, w, I_ext, mytol=1e-4, **other_pars):
  """
   Verify |dr/dt| < mytol

  Args:
    fp      : value of fixed point
    a, theta, w, I_ext: simulation parameters
    mytol   : tolerance, default as 10^{-4}

  Returns :
    Whether it is a correct fixed point: True/False
  """
  # calculate Equation(3)
  y = x_fp - F(w * x_fp + I_ext, a, theta)

  # Here we set tolerance as 10^{-4}
  return np.abs(y) < mytol

def my_fp_finder(pars, r_guess_vector, mytol=1e-4):
  """
  Calculate the fixed point(s) through drE/dt=0

  Args:
    pars    : Parameter dictionary
    r_guess_vector  : Initial values used for scipy.optimize function
    mytol   : tolerance for checking fixed point, default as 10^{-4}

  Returns:
    x_fps   : values of fixed points

  """
  x_fps = []
  correct_fps = []
  for r_guess in r_guess_vector:
    x_fp = my_fp_single(r_guess, **pars)
    if check_fp_single(x_fp, **pars, mytol=mytol):
      x_fps.append(x_fp)

  return x_fps

help(my_fp_finder)
```

    Help on function my_fp_finder in module __main__:

    my_fp_finder(pars, r_guess_vector, mytol=0.0001)
        Calculate the fixed point(s) through drE/dt=0

        Args:
          pars    : Parameter dictionary
          r_guess_vector  : Initial values used for scipy.optimize function
          mytol   : tolerance for checking fixed point, default as 10^{-4}

        Returns:
          x_fps   : values of fixed points

```python
r = np.linspace(0, 1, 1000)
pars = default_pars_single(I_ext=0.5, w=5)
drdt = compute_drdt(r, **pars)

#############################################################################
# TODO for students:
# Define initial values close to the intersections of drdt and y=0
# (How many initial values? Hint: How many times do the two lines intersect?)
# Calculate the fixed point with these initial values and plot them
#############################################################################
r_guess_vector = [...]

# Uncomment to test your values
# x_fps = my_fp_finder(pars, r_guess_vector)
# plot_dr_r(r, drdt, x_fps)
```

[*Click for solution*](https://github.com/NeuromatchAcademy/course-content/tree/master//tutorials/W3D2_DynamicNetworks/solutions/W3D2_Tutorial1_Solution_0637b6bf.py)

*Example output:*

## Interactive Demo: fixed points as a function of recurrent and external inputs.

You can now explore how the previous plot changes when the recurrent coupling $w$ and the external input $I_{\text{ext}}$ take different values. How does the number of fixed points change?

```python
# @title

# @markdown Make sure you execute this cell to enable the widget!

def plot_intersection_single(w, I_ext):
  # set your parameters
  pars = default_pars_single(w=w, I_ext=I_ext)

  # find fixed points
  r_init_vector = [0, .4, .9]
  x_fps = my_fp_finder(pars, r_init_vector)

  # plot
  r = np.linspace(0, 1., 1000)
  drdt = (-r + F(w * r + I_ext, pars['a'], pars['theta'])) / pars['tau']

  plot_dr_r(r, drdt, x_fps)

_ = widgets.interact(plot_intersection_single, w=(1, 7, 0.2),
                     I_ext=(0, 3, 0.1))
```

[*Click for solution*](https://github.com/NeuromatchAcademy/course-content/tree/master//tutorials/W3D2_DynamicNetworks/solutions/W3D2_Tutorial1_Solution_efa03467.py)

---
# Summary

In this tutorial, we have investigated the dynamics of a rate-based single population of neurons.

We learned about:
- The effect of the input parameters and the time constant of the network on the dynamics of the population.
- How to find the fixed point(s) of the system.

Next, we have two Bonus, but important concepts in dynamical system analysis and simulation. If you have time left, watch the next video and proceed to solve the exercises. You will learn:

- How to determine the stability of a fixed point by linearizing the system.
- How to add realistic inputs to our model.

---
# Bonus 1: Stability of a fixed point

```python
# @title Video 3: Stability of fixed points
from IPython.display import YouTubeVideo
video = YouTubeVideo(id="KKMlWWU83Jg", width=854, height=480, fs=1)
print("Video available at https://youtube.com/watch?v=" + video.id)
video
```

    Video available at https://youtube.com/watch?v=KKMlWWU83Jg

#### Initial values and trajectories

Here, let us first set $w=5.0$ and $I_{\text{ext}}=0.5$, and investigate the dynamics of $r(t)$ starting with different initial values $r(0) \equiv r_{\text{init}}$. We will plot the trajectories of $r(t)$ with $r_{\text{init}} = 0.0, 0.1, 0.2,..., 0.9$.

```python
# @markdown Execute this cell to see the trajectories!

pars = default_pars_single()
pars['w'] = 5.0
pars['I_ext'] = 0.5

plt.figure(figsize=(8, 5))
for ie in range(10):
  pars['r_init'] = 0.1 * ie  # set the initial value
  r = simulate_single(pars)  # run the simulation

  # plot the activity with given initial
  plt.plot(pars['range_t'], r, 'b', alpha=0.1 + 0.1 * ie,
           label=r'r$_{\mathrm{init}}$=%.1f' % (0.1 * ie))

plt.xlabel('t (ms)')
plt.title('Two steady states?')
plt.ylabel(r'$r$(t)')
plt.legend(loc=[1.01, -0.06], fontsize=14)
plt.show()
```

## Interactive Demo: dynamics as a function of the initial value

Let's now set $r_{\rm init}$ to a value of your choice in this demo. How does the solution change? What do you observe?

```python
# @title

# @markdown Make sure you execute this cell to enable the widget!

pars = default_pars_single(w=5.0, I_ext=0.5)

def plot_single_diffEinit(r_init):
  pars['r_init'] = r_init
  r = simulate_single(pars)

  plt.figure()
  plt.plot(pars['range_t'], r, 'b', zorder=1)
  plt.plot(0, r[0], 'bo', alpha=0.7, zorder=2)
  plt.xlabel('t (ms)', fontsize=16)
  plt.ylabel(r'$r(t)$', fontsize=16)
  plt.ylim(0, 1.0)
  plt.show()

_ = widgets.interact(plot_single_diffEinit, r_init=(0, 1, 0.02))
```

[*Click for solution*](https://github.com/NeuromatchAcademy/course-content/tree/master//tutorials/W3D2_DynamicNetworks/solutions/W3D2_Tutorial1_Solution_71581b5a.py)

### Stability analysis via linearization of the dynamics

Just like Equation $1$ in the case ($w=0$) discussed above, a generic linear system
$$\frac{dx}{dt} = \lambda (x - b),$$
has a fixed point for $x=b$. The analytical solution of such a system can be found to be:
$$x(t) = b + \big{(} x(0) - b \big{)} \text{e}^{\lambda t}.$$
Now consider a small perturbation of the activity around the fixed point: $x(0) = b+ \epsilon$, where $|\epsilon| \ll 1$. Will the perturbation $\epsilon(t)$ grow with time or will it decay to the fixed point? The evolution of the perturbation with time can be written, using the analytical solution for $x(t)$, as:
 $$\epsilon (t) = x(t) - b = \epsilon \text{e}^{\lambda t}$$

- if $\lambda < 0$, $\epsilon(t)$ decays to zero, $x(t)$ will still converge to $b$ and the fixed point is "**stable**".

- if $\lambda > 0$, $\epsilon(t)$ grows with time, $x(t)$ will leave the fixed point $b$ exponentially, and the fixed point is, therefore, "**unstable**" .

### Compute the stability of Equation $1$

Similar to what we did in the linear system above, in order to determine the stability of a fixed point $r^{*}$ of the excitatory population dynamics, we perturb Equation (1) around $r^{*}$ by $\epsilon$, i.e. $r = r^{*} + \epsilon$. We can plug in Equation (1) and obtain the equation determining the time evolution of the perturbation $\epsilon(t)$:

\begin{align}
\tau \frac{d\epsilon}{dt} \approx -\epsilon + w F'(w\cdot r^{*} + I_{\text{ext}};a,\theta) \epsilon
\end{align}

where $F'(\cdot)$ is the derivative of the transfer function $F(\cdot)$. We can rewrite the above equation as:

\begin{align}
\frac{d\epsilon}{dt} \approx \frac{\epsilon}{\tau }[-1 + w F'(w\cdot r^* + I_{\text{ext}};a,\theta)]
\end{align}

That is, as in the linear system above, the value of

$$\lambda = [-1+ wF'(w\cdot r^* + I_{\text{ext}};a,\theta)]/\tau \qquad (4)$$

determines whether the perturbation will grow or decay to zero, i.e., $\lambda$ defines the stability of the fixed point. This value is called the **eigenvalue** of the dynamical system.

## Exercise 4: Compute $dF$

The derivative of the sigmoid transfer function is:
\begin{align}
\frac{dF}{dx} & = \frac{d}{dx} (1+\exp\{-a(x-\theta)\})^{-1}  \\
& = a\exp\{-a(x-\theta)\} (1+\exp\{-a(x-\theta)\})^{-2}. \qquad (5)
\end{align}

Let's now find the expression for the derivative $\displaystyle{\frac{dF}{dx}}$ in the following cell and plot it.

```python
def dF(x, a, theta):
  """
  Population activation function.

  Args:
    x     : the population input
    a     : the gain of the function
    theta : the threshold of the function

  Returns:
    dFdx  : the population activation response F(x) for input x
  """

  ###########################################################################
  # TODO for students: compute dFdx ##
  raise NotImplementedError("Student excercise: compute the deravitive of F")
  ###########################################################################

  # Calculate the population activation
  dFdx = ...

  return dFdx

pars = default_pars_single()  # get default parameters
x = np.arange(0, 10, .1)      # set the range of input

# Uncomment below to test your function
# df = dF(x, pars['a'], pars['theta'])
# plot_dFdt(x, df)
```

[*Click for solution*](https://github.com/NeuromatchAcademy/course-content/tree/master//tutorials/W3D2_DynamicNetworks/solutions/W3D2_Tutorial1_Solution_ce2e3bc5.py)

*Example output:*

## Exercise 5: Compute eigenvalues

As discussed above, for the case with $w=5.0$ and $I_{\text{ext}}=0.5$, the system displays **three** fixed points. However, when we simulated the dynamics and varied the initial conditions $r_{\rm init}$, we could only obtain **two** steady states. In this exercise, we will now check the stability of each of the three fixed points by calculating the corresponding eigenvalues with the function `eig_single`. Check the sign of each eigenvalue (i.e., stability of each fixed point). How many of the fixed points are stable?

Note that the expression of the eigenvalue at fixed point $r^*$
$$\lambda = [-1+ wF'(w\cdot r^* + I_{\text{ext}};a,\theta)]/\tau$$

```python
def eig_single(fp, tau, a, theta, w, I_ext, **other_pars):
  """
  Args:
    fp   : fixed point r_fp
    tau, a, theta, w, I_ext : Simulation parameters

  Returns:
    eig : eigevalue of the linearized system
  """
  #####################################################################
  ## TODO for students: compute eigenvalue and disable the error
  raise NotImplementedError("Student excercise: compute the eigenvalue")
  ######################################################################
  # Compute the eigenvalue
  eig = ...

  return eig

# Find the eigenvalues for all fixed points of Exercise 2
pars = default_pars_single(w=5, I_ext=.5)
r_guess_vector = [0, .4, .9]
x_fp = my_fp_finder(pars, r_guess_vector)

# Uncomment below lines after completing the eig_single function.

# for fp in x_fp:
#   eig_fp = eig_single(fp, **pars)
#   print(f'Fixed point1 at {fp:.3f} with Eigenvalue={eig_fp:.3f}')
```

**SAMPLE OUTPUT**

```
Fixed point1 at 0.042 with Eigenvalue=-0.583
Fixed point2 at 0.447 with Eigenvalue=0.498
Fixed point3 at 0.900 with Eigenvalue=-0.626
```

[*Click for solution*](https://github.com/NeuromatchAcademy/course-content/tree/master//tutorials/W3D2_DynamicNetworks/solutions/W3D2_Tutorial1_Solution_e285f60d.py)

## Think!
Throughout the tutorial, we have assumed $w> 0 $, i.e., we considered a single population of **excitatory** neurons. What do you think will be the behavior of a population of inhibitory neurons, i.e., where $w> 0$ is replaced by $w< 0$?

[*Click for solution*](https://github.com/NeuromatchAcademy/course-content/tree/master//tutorials/W3D2_DynamicNetworks/solutions/W3D2_Tutorial1_Solution_7b1fce0e.py)

---
# Bonus 2: Noisy input drives the transition between two stable states

## Ornstein-Uhlenbeck (OU) process

As discussed in several previous tutorials, the OU process is usually used to generate a noisy input into the neuron. The OU input $\eta(t)$ follows:

$$\tau_\eta \frac{d}{dt}\eta(t) = -\eta (t) + \sigma_\eta\sqrt{2\tau_\eta}\xi(t)$$

Execute the following function `my_OU(pars, sig, myseed=False)` to generate an OU process.

```python
# @title OU process `my_OU(pars, sig, myseed=False)`

# @markdown Make sure you execute this cell to visualize the noise!

def my_OU(pars, sig, myseed=False):
  """
  A functions that generates Ornstein-Uhlenback process

  Args:
    pars       : parameter dictionary
    sig        : noise amplitute
    myseed     : random seed. int or boolean

  Returns:
    I          : Ornstein-Uhlenbeck input current
  """

  # Retrieve simulation parameters
  dt, range_t = pars['dt'], pars['range_t']
  Lt = range_t.size
  tau_ou = pars['tau_ou']  # [ms]

  # set random seed
  if myseed:
      np.random.seed(seed=myseed)
  else:
      np.random.seed()

  # Initialize
  noise = np.random.randn(Lt)
  I_ou = np.zeros(Lt)
  I_ou[0] = noise[0] * sig

  # generate OU
  for it in range(Lt - 1):
    I_ou[it + 1] = (I_ou[it]
                    + dt / tau_ou * (0. - I_ou[it])
                    + np.sqrt(2 * dt / tau_ou) * sig * noise[it + 1])

  return I_ou

pars = default_pars_single(T=100)
pars['tau_ou'] = 1.  # [ms]
sig_ou = 0.1
I_ou = my_OU(pars, sig=sig_ou, myseed=2020)
plt.figure(figsize=(10, 4))
plt.plot(pars['range_t'], I_ou, 'r')
plt.xlabel('t (ms)')
plt.ylabel(r'$I_{\mathrm{OU}}$')
plt.show()
```

## Example: Up-Down transition

In the presence of two or more fixed points, noisy inputs can drive a transition between the fixed points! Here, we stimulate an E population for 1,000 ms applying OU inputs.

```python
# @title Simulation of an E population with OU inputs

# @markdown Make sure you execute this cell to spot the Up-Down states!

pars = default_pars_single(T=1000)
pars['w'] = 5.0
sig_ou = 0.7
pars['tau_ou'] = 1.  # [ms]
pars['I_ext'] = 0.56 + my_OU(pars, sig=sig_ou, myseed=2020)

r = simulate_single(pars)

plt.figure(figsize=(10, 4))
plt.plot(pars['range_t'], r, 'b', alpha=0.8)
plt.xlabel('t (ms)')
plt.ylabel(r'$r(t)$')
plt.show()
```