```python
import numpy as np
from numpy import array
from sympy import symbols, cos, sin, pi, simplify, sqrt, atan2
from sympy.matrices import Matrix
import math
```

```python
def euler_to_quat(roll, pitch, yaw):
    cy = np.cos(yaw * 0.5)
    sy = np.sin(yaw * 0.5)
    cr = np.cos(roll * 0.5)
    sr = np.sin(roll * 0.5)
    cp = np.cos(pitch * 0.5)
    sp = np.sin(pitch * 0.5)

    qw = cy * cr * cp + sy * sr * sp
    qx = cy * sr * cp - sy * cr * sp
    qy = cy * cr * sp + sy * sr * cp
    qz = sy * cr * cp - cy * sr * sp
    return q

def quat_to_euler(x, y, z, w):
    ysqr = y * y

    t0 = +2.0 * (w * x + y * z)
    t1 = +1.0 - 2.0 * (x * x + ysqr)
    X =  math.atan2(t0, t1)

    t2 = +2.0 * (w * y - z * x)
    t2 = -1.0 if t2 < -1.0 else t2
    t2 =  1.0 if t2 >  1.0 else t2
    Y = math.asin(t2)

    t3 = +2.0 * (w * z + x * y)
    t4 = +1.0 - 2.0 * (ysqr + z * z)
    Z = math.atan2(t3, t4)

    return X, Y, Z

def quat_to_rot(qx, qy, qz, qw):
    return np.array([[1 - 2*qy**2 - 2*qz**2 ,2*qx*qy - 2*qz*qw ,2*qx*qz + 2*qy*qw],
            [2*qx*qy + 2*qz*qw ,1 - 2*qx**2 - 2*qz**2 ,2*qy*qz - 2*qx*qw],
            [2*qx*qz - 2*qy*qw ,2*qy*qz + 2*qx*qw ,1 - 2*qx**2 - 2*qy**2]])

```

#### ---------------------------------------------------------------------------------------------------------------------------------------------------------
#### *Solve Forward kinematics*
#### ---------------------------------------------------------------------------------------------------------------------------------------------------------

```python
### symbols of joint variables
q1, q2, q3, q4, q5, q6, q7 = symbols('q1:8') #theta_i
d1, d2, d3, d4, d5, d6, d7 = symbols('d1:8')
a0, a1, a2, a3, a4, a5, a6 = symbols('a0:7')
alpha0, alpha1, alpha2, alpha3, alpha4, alpha5, alpha6 = symbols('alpha0:7')

```

```python
# DH Parameters
s = {alpha0:     0, a0:      0, d1:  0.75,
     alpha1: -pi/2, a1:   0.35, d2:     0,   q2: q2 - pi/2,
     alpha2:     0, a2:   1.25, d3:     0,
     alpha3: -pi/2, a3: -0.054, d4:  1.50,
     alpha4:  pi/2, a4:      0, d5:     0,
     alpha5: -pi/2, a5:      0, d6:     0,
     alpha6:     0, a6:      0, d7: 0.303,   q7: 0}
```

```python
#### Homogeneous Transforms
# base_link to link1
T0_1 = Matrix([[             cos(q1),            -sin(q1),            0,              a0],
               [ sin(q1)*cos(alpha0), cos(q1)*cos(alpha0), -sin(alpha0), -sin(alpha0)*d1],
               [ sin(q1)*sin(alpha0), cos(q1)*sin(alpha0),  cos(alpha0),  cos(alpha0)*d1],
               [                   0,                   0,            0,               1]])
T0_1 = T0_1.subs(s)

#link1 to link2
T1_2 = Matrix([[             cos(q2),            -sin(q2),            0,              a1],
               [ sin(q2)*cos(alpha1), cos(q2)*cos(alpha1), -sin(alpha1), -sin(alpha1)*d2],
               [ sin(q2)*sin(alpha1), cos(q2)*sin(alpha1),  cos(alpha1),  cos(alpha1)*d2],
               [                   0,                   0,            0,               1]])
T1_2 = T1_2.subs(s)

T2_3 = Matrix([[             cos(q3),            -sin(q3),            0,              a2],
               [ sin(q3)*cos(alpha2), cos(q3)*cos(alpha2), -sin(alpha2), -sin(alpha2)*d3],
               [ sin(q3)*sin(alpha2), cos(q3)*sin(alpha2),  cos(alpha2),  cos(alpha2)*d3],
               [                   0,                   0,            0,               1]])
T2_3 = T2_3.subs(s)

T3_4 = Matrix([[             cos(q4),            -sin(q4),            0,              a3],
               [ sin(q4)*cos(alpha3), cos(q4)*cos(alpha3), -sin(alpha3), -sin(alpha3)*d4],
               [ sin(q4)*sin(alpha3), cos(q4)*sin(alpha3),  cos(alpha3),  cos(alpha3)*d4],
               [                   0,                   0,            0,               1]])
T3_4 = T3_4.subs(s)

T4_5 = Matrix([[             cos(q5),            -sin(q5),            0,              a4],
               [ sin(q5)*cos(alpha4), cos(q5)*cos(alpha4), -sin(alpha4), -sin(alpha4)*d5],
               [ sin(q5)*sin(alpha4), cos(q5)*sin(alpha4),  cos(alpha4),  cos(alpha4)*d5],
               [                   0,                   0,            0,               1]])
T4_5 = T4_5.subs(s)

T5_6 = Matrix([[             cos(q6),            -sin(q6),            0,              a5],
               [ sin(q6)*cos(alpha5), cos(q6)*cos(alpha5), -sin(alpha5), -sin(alpha5)*d6],
               [ sin(q6)*sin(alpha5), cos(q6)*sin(alpha5),  cos(alpha5),  cos(alpha5)*d6],
               [                   0,                   0,            0,               1]])
T5_6 = T5_6.subs(s)

T6_G = Matrix([[             cos(q7),            -sin(q7),            0,              a6],
               [ sin(q7)*cos(alpha6), cos(q7)*cos(alpha6), -sin(alpha6), -sin(alpha6)*d7],
               [ sin(q7)*sin(alpha6), cos(q7)*sin(alpha6),  cos(alpha6),  cos(alpha6)*d7],
               [                   0,                   0,            0,               1]])
T6_G = T6_G.subs(s)
```

```python
# Corerection rotation matrix for the difference between DH and urdf reference frames for the gripper link
R_z = Matrix([[     cos(np.pi), -sin(np.pi),             0,   0],
              [     sin(np.pi),  cos(np.pi),             0,   0],
              [              0,           0,             1,   0],
              [              0,           0,             0,   1]])

R_y = Matrix([[  cos(-np.pi/2),           0, sin(-np.pi/2),   0],
              [              0,           1,             0,   0],
              [ -sin(-np.pi/2),           0, cos(-np.pi/2),   0],
              [              0,           0,       0,         1]])
R_corr = R_z * R_y
```

```python
# Homogeneous transformation from base link to gripper frame
T0_G = simplify(T0_1 * T1_2 * T2_3 * T3_4 * T4_5 * T5_6 * T6_G * R_corr)
```

```python
# first test case
q1_v = -0.65
q2_v = 0.45
q3_v = -0.36
q4_v = 0.95
q5_v = 0.79
q6_v = 0.49

# substitute symbolic variables by test case values
T0_G_val = T0_G.evalf(subs={q1: q1_v, q2: q2_v, q3: q3_v, q4: q4_v, q5: q5_v, q6: q6_v})
T0_G_val = np.array(T0_G_val.tolist(), np.float)
print("Transformation Matrix from base to end effector= ")
print(T0_G_val)
print()
print("Translation = ", T0_G_val[:3,3])
print("roll = ", np.arctan2(T0_G_val[2,1], T0_G_val[2,2])) #roll
print("pitch = ", np.arctan2(-T0_G_val[2,0], np.sqrt(T0_G_val[0,0]**2 + T0_G_val[1,0]**2))) #pitch
print("yaw = ",np.arctan2(T0_G_val[1,0], T0_G_val[0,0])) #yaw

```

#### ---------------------------------------------------------------------------------------------------------------------------------------------------------
#### *Solve Inverse kinematics*
#### ---------------------------------------------------------------------------------------------------------------------------------------------------------

```python
test_cases = {1:[[[2.16135,-1.42635,1.55109],
                  [0.708611,0.186356,-0.157931,0.661967]],
                  [1.89451,-1.44302,1.69366],
                  [-0.65,0.45,-0.36,0.95,0.79,0.49]],
              2:[[[-0.56754,0.93663,3.0038],
                  [0.62073, 0.48318,0.38759,0.480629]],
                  [-0.638,0.64198,2.9988],
                  [-0.79,-0.11,-2.33,1.94,1.14,-3.68]],
              3:[[[-1.3863,0.02074,0.90986],
                  [0.01735,-0.2179,0.9025,0.371016]],
                  [-1.1669,-0.17989,0.85137],
                  [-2.99,-0.12,0.94,4.06,1.29,-4.12]],
              4:[[[-0.569, 0.572, 3.384],
                  [0.350, 0.842, 0.157, -0.378]],
                  [-0.42701, 0.42965, 3.1575],
                  [-0.788488, 0, -2.296801, 0, 0, 0]],
              5:[[[2.153, 0.000, 1.947],
                  [0.000, -0.000, 0.000, 1.000]],
                  [1.8499, 0, 1.9464],
                  [0,0,0,0,0,0]]}

ind = 1
joints = test_cases[ind][2]
position = test_cases[ind][0][0]
orientation   =  test_cases[ind][0][1]
```

```python
R = quat_to_rot(*orientation)
wc = position - (0.193 + 0.11) * R[:3,0]
print(wc)
```

```python
theta1 = np.arctan2(wc[1], wc[0])
print(theta1)
```

```python
wc_x = np.sqrt(wc[0]**2+wc[1]**2)
wc_y = wc[2]

l2_x = 0.35
l2_y = 0.33 + 0.42

l2_l3 = 1.25
l2_wc = np.sqrt((wc_x - l2_x)**2 + (wc_y - l2_y)**2)
l3_wc = np.sqrt((0.96+0.54)**2+0.054**2)
```

```python
theta2 = np.pi/2 - np.arctan2(wc_y - l2_y, wc_x - l2_x) - np.arccos((l2_wc**2+l2_l3**2-l3_wc**2)/(2*l2_wc*l2_l3))
print(theta2)
```

```python
theta3 = np.pi/2 - np.arctan2(0.054, 0.96+0.54) \
    - np.arccos((l3_wc**2+l2_l3**2-l2_wc**2)/(2*l3_wc*l2_l3))
print(theta3)
```

```python
R_z = Matrix([[   np.cos(theta1),-np.sin(theta1),             0],
              [   np.sin(theta1), np.cos(theta1),             0],
              [             0,           0,             1]])

R_y =  Matrix([[  np.cos(theta2+theta3),           0, np.sin(theta2+theta3)],
                 [              0,           1,             0],
                 [ -np.sin(theta2+theta3),           0, np.cos(theta2+theta3)]])

R_b3 = np.array((R_z * R_y).tolist(), np.float)
print(R_b3)
```

```python
R_x1 = Matrix([[   1,        0,        0],
               [   0,  cos(q4), -sin(q4)],
               [   0,  sin(q4),  cos(q4)]])

R_y =  Matrix([[  cos(q5),           0, sin(q5)],
               [        0,           1,       0],
               [ -sin(q5),           0, cos(q5)]])

R_x2 = Matrix([[   1,        0,        0],
               [   0,  cos(q6), -sin(q6)],
               [   0,  sin(q6),  cos(q6)]])

R = simplify(R_x1 * R_y * R_x2)
R
```

```python
R_n = np.array((Matrix(R_b3).T * Matrix(quat_to_rot(*orientation))).tolist(), float)
R_n
```

```python
theta5 = np.arctan2(np.sqrt(R_n[1, 0] ** 2 + R_n[2, 0] ** 2), R_n[0, 0])
print(theta5)
```

```python
theta6 = np.arctan2(R_n[0,1], R_n[0,2])
print(theta6)
```

```python
theta4 = np.arctan2(R_n[1, 0], -R_n[2, 0])
print(theta4)
```

```python
[theta1, theta2, theta3, theta4, theta5, theta6]
```

```python
joints
```


# Deflection-Profile Verification
This file verifies the Deflection-Profile implementation provided in the file "deflection_profile.py" of the bmcs_beam package.

```python
%matplotlib widget
# %matplotlib qt
```

```python
from bmcs_cross_section.api import MKappa, TShape, MKappaParamsStudy, EC2, ReinfLayer, IShape, CustomShape, EC2ConcreteMatMod
from bmcs_beam.api import BoundaryConditions, BoundaryConfig, DeflectionProfile, BeamDesign, LoadDeflectionParamsStudy
from os.path import join
import numpy as np
import pandas as pd
import sympy as sp
import matplotlib.pyplot as plt
import bmcs_utils.api as bu
```

```python
def plot(mc):
    fig, ax = plt.subplots(1, 1)
    dp = DeflectionProfile(mc=mc)
    F, w = dp.get_Fw()
    ax.plot(w, F / 1000, c= 'blue', label= 'bmcs_deflection'); ax.legend()
    ax.set_xlabel(r'$w$ [mm]')
    ax.set_ylabel(r'$F$ [kN]')
    plt.show()

def plot_fw_ver(mc, ver_data, data, L, mode, f_coef):

    # mode: 'multi' to plot multiple experiments and 'one' to plot one experiment
    # f_coef: a coeficient for the 'F' values of the experiment based on the experiment configuration;

    fig, (ax1,ax2) = plt.subplots(1,2, figsize = (10,5))
    ax1.ticklabel_format(axis="x", style="sci", scilimits=(0,0))
    dp.mc.plot_mk(ax1)
    dp.plot_fw(ax2)
    if mode == 'multi':
        for i in range(0,data.shape[1],2):
            ax2.plot(data.iloc[:, i+1],data.iloc[:, i] * f_coef, label = data.columns.tolist()[i][0:-2] , alpha=0.5)
        ax2.plot([L/250 , L/250], [0, max(data.iloc[:, 2]) * f_coef],  c='black', ls= '--' ); plt.annotate('L/500', xy=(L/500, max(data.iloc[:, 2]) * f_coef))
        ax2.plot([L/500 , L/500], [0, max(data.iloc[:, 2]) * f_coef],  c='black', ls= ':' ); plt.annotate('L/250', xy=(L/250, max(data.iloc[:, 2]) * f_coef))

    else:
        w = ver_data[0]
        f = ver_data[1]
        ax2.plot(w, f * f_coef, c= 'red', label= 'Experiment')
        ax2.plot([L/250 , L/250], [0, max(f) * f_coef],  c='black', ls= '--' ); plt.annotate('L/500', xy=(L/500, max(f) * f_coef))
        ax2.plot([L/500 , L/500], [0, max(f) * f_coef],  c='black', ls= ':' ); plt.annotate('L/250', xy=(L/250, max(f) * f_coef))
    ax2.legend()

    return fig

def plot_fw_ver_on_ax(ax, dp, ver_data):
    ax.set_xlabel('Deflection [mm]')
    ax.set_ylabel('Force [kN]')
    dp.plot_fw(ax)
    ax.plot(ver_data[0], ver_data[1])
    ax.legend()

def interact(dp):
    bu.InteractiveWindow([dp,
                      dp.beam_design,
                      dp.mc,
                      dp.mc.cs_design.cross_section_shape,
                      dp.mc.cs_design.cross_section_layout], tight_layout=True).interact()

```

## 1. Checking the model with its default parameters

```python
dp = DeflectionProfile()
bl1 = ReinfLayer(name='layer1', z=20, A=200, matmod='steel')
bl1.matmod_.trait_set(E=200000, f_sy=500)
dp.mc.cross_section_layout.add_layer(bl1)

dp.interact()
```

    VBox(children=(HBox(children=(VBox(children=(Tree(layout=Layout(align_items='stretch', border='solid 1px black…

## 2. Verification with experimental results

Verification with experimental results from multiple papers using the summarized parameters in Table 3 in [Yao_Mobasher2019](https://doi.org/10.1002/suco.201900404)

Notation in [Yao_Mobasher2019](https://doi.org/10.1002/suco.201900404) | Notation in this file
----------- | -----------
$E$      | E_ct
$E_c$   | E_cc
$E_s$ | E_j
$\varepsilon_{cr}$ | eps_cr
$\varepsilon_{cu}$ | eps_cu
$\varepsilon_{tu}$ | eps_tu
$\varepsilon_{cy}$ | eps_cy
$\mu$ | mu
$\gamma$  | E_cc/E_ct
$\omega$  | eps_cy/eps_cr
$\lambda_{cu}$  | eps_cu/eps_cr
$\beta_{tu}$  | eps_tu/eps_cr
$\psi$  | eps_sy_j/eps_cr
$n$  | E_j/E_ct
$\alpha$  | z_j/h
$r$  | A_s_c/A_s_t
$\rho_g$ | A_j[0]/A_c, where A_j[0] must be tension steel area

### Verification with Rectangluar cross sections
In the following verifications, the parameters will be taken from the parameters summary in Table 3 in [Yao_Mobasher2019](https://doi.org/10.1002/suco.201900404)
And the following functions is provided to map the params in the format used in [Yao_Mobasher2019](https://doi.org/10.1002/suco.201900404) to the format of the Deflection model

```python
def map_and_assign_params_for_rectangular_section(
        mc, # MKappa instance for which the params should be applied
        b, h, E, E_s, f_sy, eps_cr, rho, beta_tu, v_f, omega, psi, mu, alpha, lambda_cu):
    """This function map the params of the rectangular section from the type of the paper
    to the type of the model and assigns the values"""
    mc.cross_section_shape_.B=b
    mc.cross_section_shape_.H=h

    mc.cs_design.matrix_.trait_set(
        E_cc=E,
        E_ct=E, # SUPPOSED equal to E_cc
        mu=mu,
        eps_cr=eps_cr,
        eps_cy=omega * (-eps_cr),
        eps_cu=lambda_cu * (-eps_cr),
        eps_tu=beta_tu * eps_cr
    )

    bl1 = ReinfLayer(name='layer')
    mc.cross_section_layout.add_layer(bl1)
    bl1.trait_set(z=h * (1 - alpha), A=rho * b * alpha * h)
    bl1.matmod_.trait_set(E_s=E_s, f_sy=f_sy)
```

**El Ghadioui2020: Structural behaviour of CFRP reinforced concrete members under bending and shear loads**

```python
_, (ax_el) = plt.subplots()
```

    Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …

```python
# Beam B-M-C-K1 - CFRP Bars

excel_file = join('../verification_data/el_ghadioui2020', 'fig_3.xlsx')
data = pd.read_excel(excel_file, engine='openpyxl')

ver_data = [data['B-M-C-K1_deflection'], data['B-M-C-K1_load']]

# C 50/60

E = 33525

mc = MKappa(reinforcement_type= ReinforcementType.CARBON,

#             concrete_material_law = ConcreteMaterialLaw.EC2,
#             f_cm = 50, # 71.6,
#             f_cd = 50, # 71.6,

            low_kappa = 0,
            high_kappa = 0.000082,
            E_cc = E,
            E_ct = E,
            eps_cr = 0.00006,
            eps_tu = 0.00008,
            eps_cy = 0.00175, # EC2 eps_c3
            eps_cu = 0.0035, # EC2 eps_cu3
            mu = 0.0)

mc.cross_section_shape.B = 400
mc.cross_section_shape.H = 200
mc.cross_section_layout.reinforcement = [Reinforcement(eps_sy=0.014, E=135121, z=35, A=2 * 70.14)]

dp = DeflectionProfile(mc=mc)

dp.beam_design.beam_conf_name = BoundaryConfig.FOUR_PB
dp.beam_design.beam_conf_name.first_load_distance = 1925
dp.beam_design.L = 4700
# dp.beam_design.L = 5000 # This gives perfect results
dp.F_scale = 2/1000

_, (ax1) = plt.subplots()
plot_fw_ver_on_ax(ax1, dp, ver_data)

# plot_fw_ver_on_ax(ax_el, dp, ver_data)

# interact(dp)

# params_config = [
# #         ['L',      dp.beam_design, [4000, 5000]],
# #         ['B',      mc.cross_section_shape, [300, 500]],
# #         ['H',      mc.cross_section_shape, [21505, 300]],
#         ['E_ct',   mc, [33525, 34000]],
#         ['E_cc',   mc, [33525, 34000]],
#         ['eps_cr', mc, [0.00003, 0.00005, 0.00006]],
#         ['eps_cy', mc, [0.0015, 0.00175, 0.002, 0.0025]],
#         ['eps_cu', mc, [0.002, 0.0025, 0.0035, 0.004]],
#         ['eps_tu', mc, [0.00004, 0.00005, 0.00006]],
# #         ['mu',     mc, [0, 1]],
# #         ['z',      mc.cross_section_layout.reinforcement[0], [1, 29]],
#         ['A',      mc.cross_section_layout.reinforcement[0], [70.14, 2* 70.14]],
#         ['E',      mc.cross_section_layout.reinforcement[0], [130000, 135121, 140000]],
#         ['eps_sy', mc.cross_section_layout.reinforcement[0], [0.010, 0.014, 0.018]],
# #         ['n_x',    dp.beam_design, [10, 1000]],
# ]

# LoadDeflectionParamsStudy(dp).run(params_config, ver_data)
```

```python
# Beam B-M-C-K1 - CFRP Bars

excel_file = join('../verification_data/el_ghadioui2020', 'fig_3.xlsx')
data = pd.read_excel(excel_file, engine='openpyxl')

ver_data = [data['B-M-C-K1_deflection'], data['B-M-C-K1_load']]

# C 50/60

E = 33525

mc = MKappa(low_kappa = 0, high_kappa = 0.00011)
mc.cs_design.matrix='piecewise linear'
mc.cs_design.matrix_.trait_set(
        E_cc=E,
        E_ct=E,
        eps_cr=0.00006,
        eps_cy=0.00175,
        eps_cu=0.0035,
        eps_tu=0.00008,
        mu=0.0
    )

mc.cross_section_shape_.B = 400
mc.cross_section_shape_.H = 200

bl1 = ReinfLayer(name='layer1', z=35, A=2 * 70.14, matmod='carbon')
# bl1.matmod_.trait_set(E=135121, f_t=1890)
bl1.matmod_.trait_set(E=135121, f_t=1890, factor = 1.)
mc.cross_section_layout.add_layer(bl1)

dp = DeflectionProfile(mc=mc)

dp.beam_design.beam_conf_name = BoundaryConfig.FOUR_PB
dp.beam_design.beam_conf_name.first_load_distance = 1925
dp.beam_design.L = 4700
# dp.beam_design.L = 5000 # This gives perfect results
dp.F_scale = 2/1000

_, (ax1) = plt.subplots()
plot_fw_ver_on_ax(ax1, dp, ver_data)

# plot_fw_ver_on_ax(ax_el, dp, ver_data)

dp.interact()
```

    Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …

    VBox(children=(HBox(children=(VBox(children=(Tree(layout=Layout(align_items='stretch', border='solid 1px black…

```python
# Beam B-M-C-K2 - CFRP Bars

excel_file = join('../verification_data/el_ghadioui2020', 'fig_3.xlsx')
data = pd.read_excel(excel_file, engine='openpyxl')
ver_data = [data['B-M-C-K2_deflection'], data['B-M-C-K2_load']]

# C 50/60

E = 33525

mc = MKappa(reinforcement_type= ReinforcementType.CARBON,
            low_kappa = 0,
            high_kappa = 0.00015,
            E_cc = E,
            E_ct = E,
            eps_cr = 0.00006,
            eps_tu = 0.00006, # beta_tu = 20
            eps_cy = 0.00175, # EC2 eps_c3
            eps_cu = 0.0035, # EC2 eps_cu3
            mu = 0.0)

mc.cross_section_shape.B = 400
mc.cross_section_shape.H = 200
mc.cross_section_layout.reinforcement = [Reinforcement(eps_sy=0.014, E=135121, z=66, A=2 * 70.14)]

dp = DeflectionProfile(mc=mc)

dp.beam_design.beam_conf_name = BoundaryConfig.FOUR_PB
dp.beam_design.beam_conf_name.first_load_distance = 1925
dp.beam_design.L = 4700
dp.F_scale = 2/1000

# _, (ax1) = plt.subplots()
# plot_fw_ver_on_ax(ax1, dp, ver_data)

plot_fw_ver_on_ax(ax_el, dp, ver_data)

# interact(dp)
```

```python
# Beam B-M-S-K1 - Steel Bars

excel_file = join('../verification_data/el_ghadioui2020', 'fig_3.xlsx')
data = pd.read_excel(excel_file, engine='openpyxl')
ver_data = [data['B-M-S-K1_deflection'], data['B-M-S-K1_load']]

# C 50/60

E = 33525

mc = MKappa(reinforcement_type= ReinforcementType.STEEL,
            low_kappa = 0,
            high_kappa = 0.00017,
            E_cc = E,
            E_ct = E,
            eps_cr = 0.00006,
            eps_tu = 0.00006, # beta_tu = 20
            eps_cy = 0.00175, # EC2 eps_c3
            eps_cu = 0.0035, # EC2 eps_cu3
            mu = 0.0)

mc.cross_section_shape.B = 400
mc.cross_section_shape.H = 200
mc.cross_section_layout.reinforcement = [Reinforcement(eps_sy=(500/1.15)/200000, E=200000, z=19, A=4 * np.pi * (12/2)**2)]

dp = DeflectionProfile(mc=mc)

dp.beam_design.beam_conf_name = BoundaryConfig.FOUR_PB
dp.beam_design.beam_conf_name.first_load_distance = 1925
dp.beam_design.L = 4700
dp.F_scale = 2/1000

_, (ax1) = plt.subplots()
plot_fw_ver_on_ax(ax1, dp, ver_data)

# plot_fw_ver_on_ax(ax_el, dp, ver_data)

# interact(dp)

# mc.interact()

# params_config = [
#         ['eps_cr', mc, np.linspace(0.00001, 0.0001, 3)],
#      ['eps_tu', mc, np.linspace(0.00001, 0.0001, 3)],
# #         ['eps_cy', mc, [0.0015, 0.00175, 0.002, 0.0025]],
# ]

# LoadDeflectionParamsStudy(dp).run(params_config, ver_data)
```

```python
# A-M-C-K1 - CFRP grid

excel_file = join('../verification_data/el_ghadioui2020', 'fig_3.xlsx')
data = pd.read_excel(excel_file, engine='openpyxl')

ver_data = [data['A-M-C-K1_deflection'], data['A-M-C-K1_load']]

# C 40/50

f_ck = 40
f_cm = 49.2
E = 34918

f_ctm = 4

mc = MKappa(low_kappa = 0, high_kappa = 0.00022)
mc.cs_design.matrix='EC2 with plateau'
# mc.cs_design.matrix='piecewise linear'
mc.cs_design.matrix_.trait_set(
#         E_cc=E,
#         E_ct=E,
        eps_cr=f_ctm/E,
        eps_tu=f_ctm/E,
#         eps_cy=EC2.get_eps_c3(f_ck),
#         eps_cu=EC2.get_eps_cu3(f_ck),
        mu=0.0,

    f_cd = f_cm
    )

d = 85
b = 500
h = 105
mc.cross_section_shape_.B = b
mc.cross_section_shape_.H = h
A = 0.00254 * b * d

bl1 = ReinfLayer(name='layer1', z=h-d, A=A, matmod='carbon')
bl1.matmod_.trait_set(E=108616, f_t=1429, factor = 1.)
mc.cross_section_layout.add_layer(bl1)

dp = DeflectionProfile(mc=mc)

dp.beam_design.beam_conf_name = BoundaryConfig.FOUR_PB
dp.beam_design.beam_conf_name.first_load_distance = 870
dp.beam_design.L = 2200
dp.F_scale = 2/1000

_, (ax1) = plt.subplots()
plot_fw_ver_on_ax(ax1, dp, ver_data)

# plot_fw_ver_on_ax(ax_el, dp, ver_data)

dp.interact()
```

```python
# A-M-S-K1 - CFRP grid

excel_file = join('../verification_data/el_ghadioui2020', 'fig_3.xlsx')
data = pd.read_excel(excel_file, engine='openpyxl')

ver_data = [data['A-M-S-K1_deflection'], data['A-M-S-K1_load']]

# C 40/50

f_ck = 40
f_cm = 49.2
E = 34918

f_ctm = 4

mc = MKappa(low_kappa = 0, high_kappa = 0.00037)
# mc.cs_design.matrix='EC2'
mc.cs_design.matrix='EC2 with plateau'
# mc.cs_design.matrix='piecewise linear'
mc.cs_design.matrix_.trait_set(
#         E_cc=E,
#         E_ct=E,
        eps_cr=f_ctm/E,
        eps_tu=f_ctm/E,
#         eps_cy=EC2.get_eps_c3(f_ck),
#         eps_cu=EC2.get_eps_cu3(f_ck),
        mu=0.0,

    f_cd = f_cm,

    f_cm = f_cm
    )

d = 73
b = 500
h = 105
mc.cross_section_shape_.B = b
mc.cross_section_shape_.H = h
A = 0.00824 * b * d

bl1 = ReinfLayer(name='layer1', z=h-d, A=A, matmod='steel')
bl1.matmod_.trait_set(E=200000, f_sy=550, factor = 1.)
mc.cross_section_layout.add_layer(bl1)

dp = DeflectionProfile(mc=mc)

dp.beam_design.beam_conf_name = BoundaryConfig.FOUR_PB
dp.beam_design.beam_conf_name.first_load_distance = 870
dp.beam_design.L = 2200
dp.F_scale = 2/1000

_, (ax1) = plt.subplots()
plot_fw_ver_on_ax(ax1, dp, ver_data)

# plot_fw_ver_on_ax(ax_el, dp, ver_data)

dp.interact()
```

    Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …

    <lambdifygenerated-239>:2: RuntimeWarning: invalid value encountered in power
      return (-select([less(eps, varepsilon_cu),less(eps, varepsilon_cy),less(eps, 0),less(eps, varepsilon_cr),less(eps, varepsilon_tu),True], [0,f_cd,f_cd*(1 - (-eps/varepsilon_cy + 1)**n),-E_ct*eps,-E_ct*mu*varepsilon_cr,0], default=nan))

    VBox(children=(HBox(children=(VBox(children=(Tree(layout=Layout(align_items='stretch', border='solid 1px black…

#### 1. Verification with von der Heid et al. (2020), [link](https://www.heringinternational.com/fileadmin/media/archive1/downloads/architekturbeton/Bauingenieur_06_2020_S.210-219.pdf), Carbon reinforcement

HB-SU-0:

```python
#HB-SU-0
excel_file = join(../verification_data/hei20','hei20.xlsx')
data = pd.read_excel(excel_file, 'HB-SU-0', engine='openpyxl')

for i in range(0,data.shape[1],2):
    plt.plot(data.iloc[:, i+1],data.iloc[:, i], label = data.columns.tolist()[i][0:-2])
w_1= data['HB-SU-0-1_w']  ; f_1= data['HB-SU-0-1_F'] ; ver_data1 = [w_1, f_1/4];
w_2= data['HB-SU-0-2_w']  ; f_2= data['HB-SU-0-2_F'] ; ver_data2 = [w_2, f_2/4];
w_3= data['HB-SU-0-3_w']  ; f_3= data['HB-SU-0-3_F'] ; ver_data3 = [w_3, f_3/4];
w_4= data['HB-SU-0-4_w']  ; f_4= data['HB-SU-0-4_F'] ; ver_data4 = [w_4, f_4/4];
w_5= data['HB-SU-0-5_w']  ; f_5= data['HB-SU-0-5_F'] ; ver_data5 = [w_5, f_5/4];
w_6= data['HB-SU-0-6_w']  ; f_6= data['HB-SU-0-6_F'] ; ver_data6 = [w_6, f_6/4];
plt.legend(); plt.xlabel(r'$w$ [mm]'); plt.ylabel(r'$F$ [KN]');
```

```python
# HB-SU-0

# from tensile test
# eps_cr = (0.000071870052 + 0.000073223436 + 0.000076332606 + 0.000064518618)/4

# from bending test from ε_c,Riss
# eps_cr = (0.00023 + 0.00097 + 0.00047 + 0.00129 + 0.00182 + 0.00102)/6

# E = 35786.7
E = 39500

# from bending test from σ_c,Riss
eps_cr = ((6.365 + 6.306 + 5.635 + 5.627 + 5.452 + 5.627)/6)/E

mc = MKappa(reinforcement_type= ReinforcementType.CARBON,
            low_kappa = 0,
            high_kappa = 0.0007,
            E_cc = E,
            E_ct = E,
            eps_cr = eps_cr, # 0.000163
            eps_tu = 9.02/E, # beta_tu = 20
            eps_cy = 72/E, # omega = 10.0
            eps_cu = (72/E)*2, # lambda_cu = 20
            mu = 0.0)

mc.cross_section_shape.B = 45
mc.cross_section_shape.H = 30
mc.cross_section_layout.reinforcement = [Reinforcement(eps_sy=2712/240000, E=240000, z=8, A=3.62),
                                         Reinforcement(eps_sy=2712/240000, E=240000, z=22, A=3.62),]

dp = DeflectionProfile(mc=mc)

dp.beam_design.beam_conf_name = BoundaryConfig.FOUR_PB
dp.beam_design.beam_conf_name.first_load_distance = 320
dp.beam_design.L = 840

fig = plot_fw_ver(dp.mc, ver_data1 ,data, dp.beam_design.L, mode = 'multi', f_coef = 0.25)

# fig.savefig('von der Heid et al._2020_HB-SU-0.pdf')

# interact(dp)
```

HB-SU-90:

```python
# HB-SU-90
# Import data
excel_file = join(../verification_data/hei20','hei20.xlsx')
data = pd.read_excel(excel_file, 'HB-SU-90', engine='openpyxl')
w_data= [data['HB-SU-90-1_w'], data['HB-SU-90-2_w'], data['HB-SU-90-3_w'], data['HB-SU-90-4_w'], data['HB-SU-90-5_w']]
f_data= [data['HB-SU-90-1_F'], data['HB-SU-90-2_F'], data['HB-SU-90-3_F'], data['HB-SU-90-4_F'], data['HB-SU-90-5_F']]
# Dividing by 4 because in Anni test the force is F/2, also here we are taking half cross section so half that force
f_data = [data/4 for data in f_data]
```

```python
# HB-SU-90
fig, (ax1, ax2) = plt.subplots(1,2, figsize = (10,5))
ax1.set_xlabel(r'$w$ [mm]')
ax1.set_ylabel(r'$F$ [KN]')

for w, f in zip(w_data, f_data):
    ax1.plot(w, f, label= 'Exp', alpha=0.6)

ax1.legend()

# E = 35786.7
E = 39500

# from bending test from σ_c,Riss
eps_cr = ((5.84 + 6.28 + 5.72 + 4.33)/4)/E

mc = MKappa(reinforcement_type= ReinforcementType.CARBON,
            low_kappa = 0,
            high_kappa = 0.0004,
            E_cc = E,
            E_ct = E,
            eps_cr = eps_cr, # 0.000163
            eps_tu = 9.3/E, # beta_tu = 20
            eps_cy = 72/E, # omega = 10.0
            eps_cu = (72/E)*2, # lambda_cu = 20
            mu = 0.0)

mc.cross_section_shape.B = 45
mc.cross_section_shape.H = 30
mc.cross_section_layout.reinforcement = [Reinforcement(eps_sy=1385/240000, E=240000, z= 8, A=2*3.62),
                                         Reinforcement(eps_sy=1385/240000, E=240000, z=22, A=2*3.62)]

dp = DeflectionProfile(mc=mc)

dp.beam_design.beam_conf_name = BoundaryConfig.FOUR_PB
dp.beam_design.beam_conf_name.first_load_distance = 320
dp.beam_design.L = 840

# fig = plot_fw_ver(dp.mc, ver_data1 ,data, dp.beam_design.L, mode = 'multi', f_coef = 0.25)

# dp.mc.plot_mk(ax2)
# dp.plot_fw(ax1)

# interact(dp)
```

#### Ahmed et al. 2019 https://www.sciencedirect.com/science/article/abs/pii/S0950061819326376

```python
# Beam C05-GPC35

# # Import data
# excel_file = join(../verification_data/hei20','hei20.xlsx')
# data = pd.read_excel(excel_file, 'HB-SU-90', engine='openpyxl')
# w_data= [data['HB-SU-90-1_w'], data['HB-SU-90-2_w'], data['HB-SU-90-3_w'], data['HB-SU-90-4_w'], data['HB-SU-90-5_w']]
# f_data= [data['HB-SU-90-1_F'], data['HB-SU-90-2_F'], data['HB-SU-90-3_F'], data['HB-SU-90-4_F'], data['HB-SU-90-5_F']]
# # Dividing by 4 because in Anni test the force is F/2, also here we are taking half cross section so half that force
# f_data = [data/4 for data in f_data]

# fig, (ax1, ax2) = plt.subplots(1,2, figsize = (10,5))
# ax1.set_xlabel(r'$w$ [mm]')
# ax1.set_ylabel(r'$F$ [KN]')

# for w, f in zip(w_data, f_data):
#     ax1.plot(w, f, label= 'Exp', alpha=0.6)

# ax1.legend()

E = 29894

mc = MKappa(reinforcement_type= ReinforcementType.CARBON,

#             concrete_material_law = ConcreteMaterialLaw.EC2,
# #             f_cm = 33.87,
#             f_cd = 33.87,

            low_kappa = 0,
            high_kappa = 0.00006,
            E_cc = E,
            E_ct = E,
            eps_cr = 2.431/E, # 0.000163
            eps_tu = 10 * 2.431/E, # beta_tu = 20
            eps_cy = 0.002, # EC2, #33.87/E
            eps_cu = 0.0035, # EC2, # (33.87/E)*2
            mu = 0.0)

mc.cross_section_shape.B = 110
mc.cross_section_shape.H = 300
mc.cross_section_layout.reinforcement = [Reinforcement(eps_sy=2000/148000, E=148000, z= 25, A=3*np.pi*(6/2)**2)]

dp = DeflectionProfile(mc=mc)

dp.beam_design.beam_conf_name = BoundaryConfig.FOUR_PB
dp.beam_design.beam_conf_name.first_load_distance = 800
dp.beam_design.L = 2000
dp.F_scale = 2/1000
# fig = plot_fw_ver(dp.mc, ver_data1 ,data, dp.beam_design.L, mode = 'multi', f_coef = 0.25)

# dp.mc.plot_mk(ax2)
# dp.plot_fw(ax1)

interact(dp)
```

#### 2. Verification with Papanicolaou et al. (2010), [link](https://www.jstage.jst.go.jp/article/jact/8/1/8_1_35/_article), Carbon reinforcement

```python
#2Cc
excel_file = join(../verification_data/pap10','pap10.xlsx')
data = pd.read_excel(excel_file, '2Cc', engine='openpyxl')

for i in range(0,data.shape[1],2):
    plt.plot(data.iloc[:, i+1],data.iloc[:, i], label = data.columns.tolist()[i][0:-2])
w_1= data['2Cc_w']  ; f_1= data['2Cc_F'] ; ver_data1 = [w_1, f_1]; #plt.plot(w_1,f_1, label = '2Cc')
plt.legend(); plt.xlabel(r'$w$ [mm]'); plt.ylabel(r'$F$ [KN]');

```

```python
# 2Cc

mc = MKappa(n_m=100, 6.365 + 6.306 + 5.635 + 5.627 + 5.452 + 5.627)/6)/E = 100)
mc = MKappa(reinforcement_type= ReinforcementType.CARBON)
dp = DeflectionProfile(mc=mc)
dp.mc.low_kappa = 0
dp.mc.high_kappa = 0.0001

# Select the loading conditions, CONFIG_NAMES[0]: 3pb; CONFIG_NAMES[1]: 4pb
dp.beam_design.beam_conf_name = BoundaryConfig.FOUR_PB

dp.beam_design.L = 3 * 650

map_and_assign_params_for_rectangular_section(dp.mc,
            beta_tu = 2,  #  eps_tu/eps_cr
            b = 150,
            h = 100,
            rho = (0.0079 * 2 * 150 * 12) / (150 * 100),
            v_f = 0.0,
            E = 30000,
            E_s = 225000,
            f_sy = 3350 ,
            eps_cr = 0.00016, # how to calculate it?!
            omega = .68, #eps_cy/eps_cr
            psi = 0.0148/0.00016, #eps_sy_j/eps_cr
            mu = 0.0, #σp/σcr
            alpha = .94, #z_j/h
            lambda_cu = 21.93) #eps_cu/eps_cr

# dp.mc.A_j = np.array([3.62, 3.62])  # A_j[0] for tension steel / A_j[1] for compression steel
# dp.mc.z_j = np.array([8, 22])
# dp.mc.E_j = np.array([240000, 240000])
# dp.mc.eps_sy_j = np.array([0.0135, 0.0135])

plot_fw_ver(dp.mc, ver_data1 ,data, dp.beam_design.L, mode = 'one', f_coef = 0.5)

# interact(dp)
```

#### 3. Verification with Bielak (2019), https://doi.org/10.3390/app9071382, Carbon reinforcement

```python
excel_file = join(../verification_data/bie19','bie19.xlsx')
data = pd.read_excel(excel_file, engine='openpyxl')
for i in range(0,data.shape[1],2):
    plt.plot(data.iloc[:, i+1],data.iloc[:, i], label = data.columns.tolist()[i][0:-2]);plt.legend()
w_= data['C3-3-8-2_w']  ; f_= data['C3-3-8-2_F'] ; ver_data = [w_, f_]; #plt.plot(w_,f_, label = 'C3-3-8-2')
w_1= data['C3-2-8-3_w']  ; f_1= data['C3-2-8-3_F'] ; ver_data1 = [w_1, f_1]; #plt.plot(w_1,f_1, label = 'C3-2-8-3')
w_2= data['C3-1-8-3_w']  ; f_2= data['C3-1-8-3_F'] ; ver_data2 = [w_2, f_2]; #plt.plot(w_2,f_2, label = 'C3-1-8-3')

plt.legend(); plt.xlabel(r'$w$ [mm]'); plt.ylabel(r'$F$ [KN]');
```

```python
# C3-3-8-2

mc = MKappa(n_m=100, n_kappa = 100)
mc = MKappa(reinforcement_type= ReinforcementType.CARBON)
dp = DeflectionProfile(mc=mc)
dp.mc.low_kappa = 0
dp.mc.high_kappa = 0.0008
# Select the loading conditions, CONFIG_NAMES[0]: 3pb; CONFIG_NAMES[1]: 4pb
dp.beam_design.beam_conf_name = BoundaryConfig.THREE_PB

dp.beam_design.L = 2 * 320

map_and_assign_params_for_rectangular_section(dp.mc,
            beta_tu = 2,  #  eps_tu/eps_cr
            b = 200,
            h = 99,
            rho = 0.00234,
            v_f = 0.0,
            E = 44429,
            E_s = 244835, #Warp:244835, Weft:243828
            f_sy = 2737 , #Warp:3221, Weft:3334
            eps_cr = 0.0002616,
            omega = 0.28/0.2616, #eps_cy/eps_cr
            psi = 13.2/0.2616, #eps_sy_j/eps_cr
            mu = 0.2, #σp/σcr
            alpha = 0.77, #z_j/h
            lambda_cu = 2.92/0.2616) #eps_cu/eps_cr

plot_fw_ver(dp.mc, ver_data ,data, dp.beam_design.L, mode = 'one', f_coef =2 )

# interact(dp)
```

```python
# C3-2-8-3

mc = MKappa(n_m=100, n_kappa = 100)
mc = MKappa(reinforcement_type= ReinforcementType.CARBON)
dp = DeflectionProfile(mc=mc)
dp.mc.low_kappa = 0
dp.mc.high_kappa = 0.0004

# Select the loading conditions, CONFIG_NAMES[0]: 3pb; CONFIG_NAMES[1]: 4pb
dp.beam_design.beam_conf_name = BoundaryConfig.THREE_PB

dp.beam_design.L = 2 * 400

map_and_assign_params_for_rectangular_section(dp.mc,
            beta_tu = 2,  #  eps_tu/eps_cr
            b = 199,
            h = 100,
            rho = 0.00256,
            v_f = 0.0,
            E = 45346 ,
            E_s = 244835 , #Warp:244835, Weft:243828
            f_sy = 3221 , #Warp:3221, Weft:3334
            eps_cr = 0.0002616,
            omega = 0.28/0.2616, #eps_cy/eps_cr
            psi = 13.2/0.2616, #eps_sy_j/eps_cr
            mu = 0.2, #σp/σcr
            alpha = 0.71, #z_j/h
            lambda_cu = 2.92/0.2616) #eps_cu/eps_cr

plot_fw_ver(dp.mc, ver_data1 ,data, dp.beam_design.L, mode = 'one', f_coef =2)

```

```python
# C3-1-8-3

mc = MKappa(n_m=100, n_kappa = 100)
mc = MKappa(reinforcement_type= ReinforcementType.CARBON)
dp = DeflectionProfile(mc=mc)
dp.mc.low_kappa = 0
dp.mc.high_kappa = 0.0003
# Select the loading conditions, CONFIG_NAMES[0]: 3pb; CONFIG_NAMES[1]: 4pb
dp.beam_design.beam_conf_name = BoundaryConfig.THREE_PB

dp.beam_design.L = 2 * 480

map_and_assign_params_for_rectangular_section(dp.mc,
            beta_tu = 2,  #  eps_tu/eps_cr
            b = 201,
            h = 100,
            rho = 0.00233,
            v_f = 0.0,
            E = 44010 ,
            E_s = 244835 , #Warp:244835, Weft:243828
            f_sy = 3221 , #Warp:3221, Weft:3334
            eps_cr = 0.0002616,
            omega = 0.28/0.2616, #eps_cy/eps_cr
            psi = 13.2/0.2616, #eps_sy_j/eps_cr
            mu = 0.2, #σp/σcr
            alpha = 0.77, #z_j/h
            lambda_cu = 2.92/0.2616) #eps_cu/eps_cr

plot_fw_ver(dp.mc, ver_data2 ,data, dp.beam_design.L, mode = 'one', f_coef =2)

```

### Verification with I-sections

#### 1. Verification with Bielak (2020), http://dx.doi.org/10.3390/app10134625 , Carbon textiles+bars

```python
# Beam FT01 - CFRP Bars + textile
E = 38750

f_ctm = 12.29 * 0.2 # 0.2 is empirical factor
f_cm = 98.8
f_ck = f_cm - 8

mc = MKappa(low_kappa = 0, high_kappa = 0.000016, n_m=1000)

# mc.cs_design.matrix= 'piecewise linear'
# mc.cs_design.matrix_.trait_set(
#         E_cc=E,
#         E_ct=E,
#         eps_cr= f_ctm/E, # 0.000125, #12.29/E,
# #         eps_cy=EC2.get_eps_c2(f_ck),
# #         eps_cu=EC2.get_eps_cu2(f_ck),
#         eps_cy=0.00175,
#         eps_cu=0.0035,
#         eps_tu=0.002,
#         mu=0.0,
#         f_cd = f_cm
#     )

mc.cs_design.matrix= 'EC2'
mc.cs_design.matrix_.trait_set(
        eps_cr= f_ctm/E,
        eps_tu=f_ctm/E,
        mu=0.0,
        f_cm = f_cm
    )

mc.cross_section_shape = 'I-shape'
mc.cross_section_shape_.H = 900

# Reinforcement:
# ---------------
bl1 = ReinfLayer(name='carbon bars', z=30, A=5 * np.pi * (8.9/2)**2, matmod='carbon')
bl1.matmod_.trait_set(E=165515, f_t=1828)
mc.cross_section_layout.add_layer(bl1)

for z in np.linspace(25, 25 + 87, 4):
    if z == 25:
        A_g = 4 * 4.62
    else:
        A_g = 2 * 4.62
    gl = ReinfLayer(name='glass', z=z, A=A_g, matmod='carbon')
    gl.matmod_.trait_set(E=70843, f_t=1590)
    mc.cross_section_layout.add_layer(gl)

for z in np.arange(50, 850, 38):
    bl = ReinfLayer(name='carbon grid', z=z, A=2*3.62, matmod='carbon')
    bl.matmod_.trait_set(E=244835, f_t=3221)
    mc.cross_section_layout.add_layer(bl)

# TODO, all reinf layers are taking the settings of the last added layer (E=244835, f_t=3221)!!!! fix it!!

# If reinforcement would've been steel ->
# bl1 = ReinfLayer(name='layer1', z=30, A=5 * np.pi * (9.5/2)**2, matmod='steel')
# bl1.matmod_.trait_set(E_s=200000, f_sy=500)
# mc.cross_section_layout.add_layer(bl1)

dp = DeflectionProfile(mc=mc)

dp.beam_design.beam_conf_name = BoundaryConfig.SIMPLE_BEAM_DIST_LOAD
dp.beam_design.L = 7000
dp.F_scale = 1 * 7 # scale should be 1 because N/mm -> kN/m, and 7 is to get the sum of dist load along the 7m beam

dp.interact()
```

    VBox(children=(HBox(children=(VBox(children=(Tree(layout=Layout(align_items='stretch', border='solid 1px black…

```python
# Compare with experimental results
path = join('..', 'verification_data', 'Bie20', 'FT01.csv')
exp_deflection_load = np.array(pd.read_csv(path, delimiter=';', decimal='.')).T
exp_deflection = exp_deflection_load[0]
exp_load = exp_deflection_load[1]

_, (ax) = plt.subplots()
ax.plot(exp_deflection, exp_load)

Fw = dp.get_Fw()
F = Fw[0] * dp.F_scale
w = Fw[1]
ax.plot(w, F)
# ax.figure.savefig('bielak2.pdf')
```

    Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …

    [<matplotlib.lines.Line2D at 0x2c0baabea00>]

### Verification with T-sections

```python
def map_and_assign_params_for_t_section(
        mc, # MKappa instance for which the params should be applied
        b, h, E, E_s, f_sy, eps_cr, rho, beta_tu, v_f, omega, psi, mu, alpha, lambda_cu, o, zeta):
    """This function map the params of the rectangular section from the type of the paper
    to the type of the model and assigns the values"""
    t_shape = TShape(H= h, B_f = b, B_w = o*b, H_w = (1-zeta)*h)
    mc.cross_section_shape = t_shape

    mc.E_cc=E
    mc.E_ct=E # SUPPOSED equal to E_cc!!
    mc.mu=mu
    mc.eps_cr=eps_cr
    mc.eps_cy=omega * eps_cr
    mc.eps_cu=lambda_cu * eps_cr
    mc.eps_tu=beta_tu * eps_cr
    mc.eps_sy_j=[f_sy / E_s] # or eps_sy_j=psi * eps_cr,
    mc.E_j=[E_s]
    mc.z_j=[h * (1 - alpha)]
    mc.A_j=[rho * b * h]

```

#### 1. Verification with Qi et al. (2016), https://doi.org/10.1002/suco.201500191, Steel reinforcement

```python
excel_file = join(../verification_data/yao20_yao_mobasher/figure_14','qi16.xlsx') # S_1 line

data = pd.read_excel(excel_file, engine='openpyxl')
w_= data['S_1_exp_w'] ; f_= data['S_1_exp_F'] / 1000; ver_data = [w_, f_]; plt.plot(w_,f_, label = 'S-1')

plt.legend(); plt.xlabel(r'$w$ [mm]'); plt.ylabel(r'$F$ [kN]');
```

```python
# S-1

mc = MKappa(n_m=100, n_kappa = 100)
mc = MKappa(reinforcement_type= ReinforcementType.STEEL)
dp = DeflectionProfile(mc=mc)
dp.mc.low_kappa = 0
dp.mc.high_kappa = 0.00006
# Select the loading conditions, CONFIG_NAMES[0]: 3pb; CONFIG_NAMES[1]: 4pb
dp.beam_design.beam_conf_name = BoundaryConfig.THREE_PB

dp.beam_design.L = 1140

map_and_assign_params_for_t_section(dp.mc,
            beta_tu = 15,
            b = 120,
            h = 140,
            rho = 0.0496,
            v_f = 0.02,
            E = 36500,
            E_s = 200000 ,
            f_sy = 761,
            eps_cr = 0.000140,
            omega = 22.7,
            psi = 27.2,
            mu = 0.3,
            alpha = 0.81,
            o = 0.33,
            zeta = 0.25,
            lambda_cu = 25)

plot_fw_ver(dp.mc, ver_data ,data, dp.beam_design.L, mode = 'one', f_coef =2 )

```

#### 2. Verification with Abdul-Ahad and Aziz (1999), https://doi.org/10.1002/suco.201500191, Steel reinforcement

```python
excel_file = join(../verification_data/yao20_yao_mobasher/figure_14', 'abd99.xlsx') # G 23 line
data = pd.read_excel(excel_file, engine='openpyxl')
w_= data['G23_w'] ; f_= data['G23_F'] ; ver_data = [w_, f_]; plt.plot(w_,f_, label = 'G 23')
plt.legend(); plt.xlabel(r'$w$ [mm]'); plt.ylabel(r'$F$ [kN]');
```

```python
# G 23
mc = MKappa(n_m=100, n_kappa = 100)
mc = MKappa(reinforcement_type= ReinforcementType.STEEL)
dp = DeflectionProfile(mc=mc)
dp.mc.low_kappa = 0
dp.mc.high_kappa = 0.00005
# Select the loading conditions, CONFIG_NAMES[0]: 3pb; CONFIG_NAMES[1]: 4pb
dp.beam_design.beam_conf_name = BoundaryConfig.FOUR_PB

dp.beam_design.L = 1800

map_and_assign_params_for_t_section(dp.mc,
            beta_tu = 15,
            b = 250,
            h = 210,
            rho = 0.0209,
            v_f = 0.02,
            E = 20400,
            E_s = 200000,
            f_sy = 465,
            eps_cr = 0.000210,
            omega = 5.9,
            psi = 11.1,
            mu = 0.3,
            alpha = 0.81,
            o = 0.4,
            zeta = 0.29,
            lambda_cu = 40.9)

plot_fw_ver(dp.mc, ver_data ,data, dp.beam_design.L, mode = 'one', f_coef = 1 )
```


# Using Natural Gradient Descent with Variational Models

## Overview

In this notebook, we'll demonstrate how to use **natural gradient descent** when optimizing variational GPyTorch models. This will be the same as the [SVGP regression notebook](./SVGP_Regression_CUDA.ipynb), except we will be using a different optimizer.

## What is natural gradient descent (NGD)?

Without going into too much detail, using SGD or Adam isn't the best way to optimize the parameters of variational Gaussian distributions. Essentially, SGD takes steps assuming that the loss geometry of the parameters is Euclidean. This is a bad assumption for the parameters of many distributions, especially Gaussians. See [Agustinus Kristiadi's blog post](https://wiseodd.github.io/techblog/2018/03/14/natural-gradient/) for more detail.

Instead, it makes more sense to take gradient steps that have been scaled better for the geometry of the variational distribution's parameters. Specifically, if $\mathbf m$ and $\mathbf S$ are the mean and covariance of our variational Gaussian posterior approximation, then we will achieve faster convergence if we take the following steps:

\begin{align}
\begin{bmatrix} \mathbf m \\ \mathbf S \end{bmatrix}
\leftarrow
\begin{bmatrix} \mathbf m \\ \mathbf S \end{bmatrix}
-
\alpha \mathcal{\mathbf F}^{-1} \nabla \begin{bmatrix} \mathbf m \\   \mathbf S \end{bmatrix}
\end{align}

where $\alpha$ is a step size and $\mathbf F$ is the **Fisher information matrix** corresponding to this distribution. This is known as **natural gradient descent**, or **NGD**.

It turns out that for Gaussian distributions (and, more broadly, for all distributions in the exponential family), there are efficient update equations for NGD. See the following papers for more information:
- [Salimbeni, Hugh, Stefanos Eleftheriadis, and James Hensman. "Natural gradients in practice: Non-conjugate variational inference in gaussian process models." AISTATS (2018).](https://arxiv.org/abs/1803.09151)
- [Hensman, James, Magnus Rattray, and Neil D. Lawrence. "Fast variational inference in the conjugate exponential family." NeurIPS (2012).](http://papers.nips.cc/paper/4766-fast-variational-inference-in-the-conjugate-exponential-family)

## Jointly optimizing variational parameters/hyperparameters

```python
import tqdm
import math
import torch
import gpytorch
from matplotlib import pyplot as plt

# Make plots inline
%matplotlib inline
```

For this example notebook, we'll be using the `elevators` UCI dataset used in the paper. Running the next cell downloads a copy of the dataset that has already been scaled and normalized appropriately. For this notebook, we'll simply be splitting the data using the first 80% of the data as training and the last 20% as testing.

```python
import urllib.request
import os
from scipy.io import loadmat
from math import floor

# this is for running the notebook in our testing framework
smoke_test = ('CI' in os.environ)

if not smoke_test and not os.path.isfile('../elevators.mat'):
    print('Downloading \'elevators\' UCI dataset...')
    urllib.request.urlretrieve('https://drive.google.com/uc?export=download&id=1jhWL3YUHvXIaftia4qeAyDwVxo6j1alk', '../elevators.mat')

if smoke_test:  # this is for running the notebook in our testing framework
    X, y = torch.randn(1000, 3), torch.randn(1000)
else:
    data = torch.Tensor(loadmat('../elevators.mat')['data'])
    X = data[:, :-1]
    X = X - X.min(0)[0]
    X = 2 * (X / X.max(0)[0]) - 1
    y = data[:, -1]

train_n = int(floor(0.8 * len(X)))
train_x = X[:train_n, :].contiguous()
train_y = y[:train_n].contiguous()

test_x = X[train_n:, :].contiguous()
test_y = y[train_n:].contiguous()

if torch.cuda.is_available():
    train_x, train_y, test_x, test_y = train_x.cuda(), train_y.cuda(), test_x.cuda(), test_y.cuda()
```

The following steps create the dataloader objects. See the [SVGP regression notebook](./SVGP_Regression_CUDA.ipynb) for details.

```python
from torch.utils.data import TensorDataset, DataLoader
train_dataset = TensorDataset(train_x, train_y)
train_loader = DataLoader(train_dataset, batch_size=1024, shuffle=True)

test_dataset = TensorDataset(test_x, test_y)
test_loader = DataLoader(test_dataset, batch_size=1024, shuffle=False)
```

## SVGP models for NGD

There are **three** key differences between NGD-SVGP models and the standard SVGP models from the [SVGP regression notebook](./SVGP_Regression_CUDA.ipynb).

### Difference #1: NaturalVariationalDistribution

Rather than using `gpytorch.variational.CholeskyVarationalDistribution` (or other variational distribution objects), you have to use one of the two objects:

- `gpytorch.variational.NaturalVariationalDistribution` (typically faster optimization convergence, but less stable for non-conjugate likelihoods)
- `gpytorch.variational.TrilNaturalVariationalDistribution` (typically slower optimization convergence, but more stable for non-conjugate likelihoods)

```python
class GPModel(gpytorch.models.ApproximateGP):
    def __init__(self, inducing_points):
        variational_distribution = gpytorch.variational.NaturalVariationalDistribution(inducing_points.size(0))
        variational_strategy = gpytorch.variational.VariationalStrategy(
            self, inducing_points, variational_distribution, learn_inducing_locations=True
        )
        super(GPModel, self).__init__(variational_strategy)
        self.mean_module = gpytorch.means.ConstantMean()
        self.covar_module = gpytorch.kernels.ScaleKernel(gpytorch.kernels.RBFKernel())

    def forward(self, x):
        mean_x = self.mean_module(x)
        covar_x = self.covar_module(x)
        return gpytorch.distributions.MultivariateNormal(mean_x, covar_x)

inducing_points = train_x[:500, :]
model = GPModel(inducing_points=inducing_points)
likelihood = gpytorch.likelihoods.GaussianLikelihood()

if torch.cuda.is_available():
    model = model.cuda()
    likelihood = likelihood.cuda()
```

### Difference #2: Two optimizers - one for the variational parameters; one for the hyperparameters

NGD steps only update the variational parameters. Therefore, we need two separate optimizers: one for the variational parameters (using NGD) and one for the other hyperparameters (using Adam or whatever you want).

Some things to note about the NGD variational optimizer:

- **You must use `gpytorch.optim.NGD` as the variational NGD optimizer!** Adaptive gradient algorithms will mess up the natural gradient steps. (Any stochastic optimizer works for the hyperparameters.)
- **Use a large learning rate for the variational optimizer.** Typically, 0.1 is a good learning rate.

```python
variational_ngd_optimizer = gpytorch.optim.NGD(model.variational_parameters(), num_data=train_y.size(0), lr=0.1)

hyperparameter_optimizer = torch.optim.Adam([
    {'params': model.hyperparameters()},
    {'params': likelihood.parameters()},
], lr=0.01)
```

### Difference #3: The updated training loop

In the training loop, we have to update both optimizers (`variational_ngd_optimizer` and `hyperparameter_optimizer`).

```python
model.train()
likelihood.train()
mll = gpytorch.mlls.VariationalELBO(likelihood, model, num_data=train_y.size(0))

num_epochs = 1 if smoke_test else 4
epochs_iter = tqdm.notebook.tqdm(range(num_epochs), desc="Epoch")
for i in epochs_iter:
    minibatch_iter = tqdm.notebook.tqdm(train_loader, desc="Minibatch", leave=False)

    for x_batch, y_batch in minibatch_iter:
        ### Perform NGD step to optimize variational parameters
        variational_ngd_optimizer.zero_grad()
        hyperparameter_optimizer.zero_grad()
        output = model(x_batch)
        loss = -mll(output, y_batch)
        minibatch_iter.set_postfix(loss=loss.item())
        loss.backward()
        variational_ngd_optimizer.step()
        hyperparameter_optimizer.step()
```

    HBox(children=(FloatProgress(value=0.0, description='Epoch', max=4.0, style=ProgressStyle(description_width='i…

    HBox(children=(FloatProgress(value=0.0, description='Minibatch', max=13.0, style=ProgressStyle(description_wid…

    HBox(children=(FloatProgress(value=0.0, description='Minibatch', max=13.0, style=ProgressStyle(description_wid…

    HBox(children=(FloatProgress(value=0.0, description='Minibatch', max=13.0, style=ProgressStyle(description_wid…

    HBox(children=(FloatProgress(value=0.0, description='Minibatch', max=13.0, style=ProgressStyle(description_wid…

You could also modify the optimization loop to alternate between the NGD step and the hyperparameter updates:

```python
    for x_batch, y_batch in minibatch_iter:
        ### Perform NGD step to optimize variational parameters
        variational_ngd_optimizer.zero_grad()
        output = model(x_batch)
        loss = -mll(output, y_batch)
        minibatch_iter.set_postfix(loss=loss.item())
        loss.backward()
        variational_ngd_optimizer.step()

        ### Perform Adam step to optimize hyperparameters
        hyperparameter_optimizer.zero_grad()
        output = model(x_batch)
        loss = -mll(output, y_batch)
        loss.backward()
        hyperparameter_optimizer.step()
```

### Evaluation

That's it! This model should converge must faster/better than the standard SVGP model - and it can often get better performance (especially when using more inducing points).

```python
model.eval()
likelihood.eval()
means = torch.tensor([0.])
with torch.no_grad():
    for x_batch, y_batch in test_loader:
        preds = model(x_batch)
        means = torch.cat([means, preds.mean.cpu()])
means = means[1:]
print('Test MAE: {}'.format(torch.mean(torch.abs(means - test_y.cpu()))))
```

    Test MAE: 0.07514254748821259


# Differential Evolution

**TODO**
* Livre metaheuristiques p.165
* [Scipy's implementation](https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html#scipy.optimize.differential_evolution)
* https://en.wikipedia.org/wiki/Differential_evolution
* http://www.scholarpedia.org/article/Metaheuristic_Optimization#Differential_Evolution
* [Practical advises](http://www1.icsi.berkeley.edu/~storn/code.html#prac)

Differential Evolution (DE) was developed by R. Storn and K. Price in 1995 [Storn95] [Storn97].

This algorithm has been made for continuous problems.

* **[Storn95]**: Storn, R., & Price, K. (1995). *Differential evolution - a simple and efficient adaptive scheme for global optimization over continuous spaces*. Technical Report TR95-012, International Computer Science Institute, Berkeley, California. [PDF document](ftp://ftp.icsi.berkeley.edu/pub/techreports/1995/tr-95-012.pdf).
* **[Storn97]**: Storn, R., & Price, K. (1997). *Differential evolution - a simple and efficient heuristic for global optimization over continuous spaces*. Journal of global optimization, 11(4), 341-359.

## The Differential Evolution (DE) algorithm

### Simplified notations

FOREACH generation

$\quad$ FOREACH individual $i$ (a solution vector) of the population (a set)

$\quad\quad$ 1. **MUTATION**:

$\quad\quad\quad$ 1.1 Randomly choose 3 different individuals $\boldsymbol{x}_{r1}$, $\boldsymbol{x}_{r2}$ and $\boldsymbol{x}_{r3}$

$\quad\quad\quad\quad$ $\boldsymbol{x}_{r2}$ and $\boldsymbol{x}_{r3}$ are used to automatically define the direction and the amplitude of the mutation

$\quad\quad\quad\quad$ (i.e. the search amplitude and direction)

$\quad\quad\quad$ 1.2 Compute mutant $\boldsymbol{v}_{i} \leftarrow \boldsymbol{x}_{r1} + F . (\boldsymbol{x}_{r2} - \boldsymbol{x}_{r3})$

$\quad\quad$ 2. **CROSSOVER**:

$\quad\quad\quad$ Compute the "test" individual $\boldsymbol{u}_{i}$ randomly taking each of its (vector) components in either $\boldsymbol{x}_i$ or $\boldsymbol{v}_i$

$\quad\quad$ 3. **SELECTION**:

$\quad\quad\quad$ The test individual $\boldsymbol{u}_{i}$ replace $\boldsymbol{x}_{i}$ in the next generation if it has a better score.

Differential evolution consists of three main steps:
1. mutation
2. crossover
3. selection

The following sections provides more details about those three steps.

### Mutation

### Crossover

### Selection

**Notations**:
* $D$ : the dimension of input vectors, $D \in \mathbb{N}^*_+$.
* $t$ : the current iteration index (or generation index), $t \in \mathbb{N}^*_+$.
* $T$ : the total number of iteration (or generation), $T \in \mathbb{N}^*_+$.
* $N$ : the size of the population, $N > 3$.
* $F$ : the *differential weight*. In principle, $F \in [0,2]$, but in practice, a scheme with $F \in [0,1]$ is more efficient and stable ([scholarpedia](http://www.scholarpedia.org/article/Metaheuristic_Optimization#Differential_Evolution)).
* $Cr$ : the crossover probability parameter, $Cr \in [0,1]$.

---

**Algorithm's parameters:** $N$, $Cr$ and $F$

---

**Input:**
* An initial population $(\boldsymbol{x}_{1,1}, \boldsymbol{x}_{2,1}, \dots, \boldsymbol{x}_{N,1})$ with $\boldsymbol{x}_{0,i} \in \mathbb{R}^D$

---

**for all** generation $t = 1, \dots, T$ **do**

$\quad$ **for all** individuals $i = 1, \dots, N$ **do**

$\quad\quad$ **1. Mutation:**

$\quad\quad\quad$ Randomly choose 3 different individuals $\boldsymbol{x}_{r1,t}$, $\boldsymbol{x}_{r2,t}$ and $\boldsymbol{x}_{r3,t}$ in the population

$\quad\quad\quad$ Make a donor vector $\boldsymbol{v}_{i,t}$ as the following

$\quad\quad\quad \boldsymbol{v}_{i,t} \leftarrow \boldsymbol{x}_{r1,t} + F (\boldsymbol{x}_{r2,t} - \boldsymbol{x}_{r3,t})$

$\quad\quad$ **2. Crossover:** make a test individual $\boldsymbol{u}_{i,t}$ from $\boldsymbol{x}_{i,t}$ and $\boldsymbol{v}_{i,t}$

$\quad\quad\quad$ Randomly choose a dimension index $d_{r,i}$.

$\quad\quad\quad$ **for all** dimension $d = 1, \dots, D$ **do**

$$
u_{d,i,t} \leftarrow
\left\{
\begin{align}
v_{d,i,t} \quad & \text{ if } \mathcal{B}(Cr) = 1 \text{ or if } d = d_{r,i}\\
x_{d,i,t} \quad & \text{ otherwise.}
\end{align}
\right.
$$

$\quad\quad\quad\quad$ where $\mathcal{B}(Cr)$ is a Bernoulli random variable of parameter $Cr$

$\quad\quad\quad\quad$ and where $u_{d,i,t}$, $v_{d,i,t}$ and $x_{d,i,t}$ are respectively the $d^{th}$ component of $\boldsymbol{u}_{i,t}$, $\boldsymbol{v}_{i,t}$ and $\boldsymbol{x}_{i,t}$

$\quad\quad$ **3. Selection:**

$\quad\quad\quad$ **If** $f(\boldsymbol{u}_{i,t}) < f(\boldsymbol{x}_{i,t})$

$\quad\quad\quad\quad \boldsymbol{x}_{i,t+1} \leftarrow \boldsymbol{u}_{i,t}$

$\quad\quad\quad$ **Else**

$\quad\quad\quad\quad \boldsymbol{x}_{i,t+1} \leftarrow \boldsymbol{x}_{i,t}$

$\quad$ **end for**

**end for**

```python
# import python packages here...
```