# Orbyts - UCL | Stellar International School
## Histogram
```python=
plt.hist(theta_Bnhat_list, bins=5,
facecolor='#313132',
edgecolor='#e0e0e0',
linewidth=0.5,
alpha=0.7)
```
## Coplanarity Normal
```python=
def coplanarity_normal(Bu, Bd):
""" Coplanarity normal to the shock surface
derived from coplanarity analysis formula.
Args:
Bu (list, array): Upstream magnetic field vector.
Bd (list, array): Downstream magnetic field vector.
Returns:
n_cp (array): Coplanrity normal vector.
Example:
>>> Bu = [-0.2, -0.3, 0.2]
>>> Bd = [-0.5, -1, 0.4]
>>> n_cp = coplanarity_normal(Bu, Bd)
>>> print(n_cp, np.linalg.norm(n_cp))
"""
Bu = np.array(Bu)
Bd = np.array(Bd)
dB = Bd-Bu
BdXBu = np.cross(Bd, Bu)
dBXBdXBu = np.cross(dB, BdXBu)
n_cp = dBXBdXBu / np.linalg.norm(dBXBdXBu)
return n_cp
```
## Calculate coplanarity normal
```python=
n_cp_samples = []
for i in range(N_CHUNKS):
for j in range(N_CHUNKS):
Bu = B_up_mean[i][0:3] # starrting from start of B_u
Bd = B_down_mean[j][0:3] # starting from the end of B_d
n_cp = coplanarity_normal(Bu, Bd)
n_cp_samples.append(n_cp)
#print(n_cp, np.linalg.norm(n_cp))
n_cp_samples = np.array(n_cp_samples)
print(n_cp_samples.shape)
```
## Calculate shock angle relative to the coplanarity shock normal
```python=
B_up_mean_averaged = B_up_mean[:,0:3].mean(axis=0)
theta_Bncp_samples = []
# loop through each coplanarity normal and do dot product with B_u
for i in range(len(n_cp_samples)):
theta_Bncp = np.arccos(np.dot(B_up_mean_averaged, n_cp_samples[i])/np.linalg.norm(B_up_mean_averaged))*180/np.pi
if theta_Bncp > 90:
theta_Bncp = 180 - theta_Bncp
theta_Bncp_samples.append(theta_Bncp)
theta_Bncp_mean = np.mean(theta_Bncp_samples)
theta_Bncp_std = np.std(theta_Bncp_samples)
theta_Bncp_mean, theta_Bncp_std
```
## Calculate shock angle relative to coplanarity normal in a loop:
The first part is the same as the code you have before when calculating the model normal.
```python=
theta_Bncp_samples_list = []
theta_Bncp_mean_list = []
theta_Bncp_std_list = []
ncp_samples_list = []
for i in range(len(df_BS_crossings)):
print(f'BS crossing {i}:')
# Get crossing time
crossing_time = df_BS_crossings.iloc[i].TIME
# Define interval
time_start = crossing_time - pd.Timedelta(7, unit='m')
time_end = crossing_time + pd.Timedelta(7, unit='m')
df_crossing = df_1s.query("TIME > @time_start & TIME < @time_end")
# Define B_up and B_down
if df_BS_crossings.iloc[i].DIRECTION == 'I':
B_up = df_crossing.query("TIME < @crossing_time")
B_down = df_crossing.query("TIME > @crossing_time")
elif df_BS_crossings.iloc[i].DIRECTION == 'O':
B_up = df_crossing.query("TIME > @crossing_time")
B_down = df_crossing.query("TIME < @crossing_time")
# Split into 8 chunks
N_CHUNKS = 8
# Split B_up and B_down into 8 subintervals
B_up_chunks = np.array_split(B_up, N_CHUNKS)
B_down_chunks = np.array_split(B_down, N_CHUNKS)
# Calculate mean of each chunk giving 8 mean values for B_up and B_down
B_up_mean = np.zeros((N_CHUNKS, 4))
for j in range(N_CHUNKS):
B_up_mean[j] = B_up_chunks[j].mean().values
B_down_mean = np.zeros((N_CHUNKS, 4))
for j in range(N_CHUNKS):
B_down_mean[j] = B_down_chunks[j].mean().values
```
This next part is different, because we need to calculate coplanarity normal:
```python=
# Calculate the coplanarity normal (64 samples)
n_cp_samples = []
# ENTER YOUR CODE HERE
n_cp_samples = np.array(n_cp_samples)
ncp_samples_list.append(n_cp_samples)
# Calculate shock angle relative to the coplanarity shock normal
# ENTER YOUR CODE HERE
# Calculate mean
theta_Bncp_mean = np.mean(theta_Bncp_samples)
theta_Bncp_mean_list.append(theta_Bncp_mean)
theta_Bncp_samples_list.append(theta_Bncp_samples)
# Calculate errors: 1 standard deviation
theta_Bncp_std = np.std(theta_Bncp_samples)
theta_Bncp_std_list.append(theta_Bncp_std)
```
### The solution to Analysis 2
```python=
theta_Bncp_samples_list = []
theta_Bncp_mean_list = []
theta_Bncp_std_list = []
ncp_samples_list = []
for i in range(len(df_BS_crossings)):
print(f'BS crossing {i}:')
# Get crossing time
crossing_time = df_BS_crossings.iloc[i].TIME
# Define interval
time_start = crossing_time - pd.Timedelta(7, unit='m')
time_end = crossing_time + pd.Timedelta(7, unit='m')
df_crossing = df_1s.query("TIME > @time_start & TIME < @time_end")
# Define B_up and B_down
if df_BS_crossings.iloc[i].DIRECTION == 'I':
B_up = df_crossing.query("TIME < @crossing_time")
B_down = df_crossing.query("TIME > @crossing_time")
elif df_BS_crossings.iloc[i].DIRECTION == 'O':
B_up = df_crossing.query("TIME > @crossing_time")
B_down = df_crossing.query("TIME < @crossing_time")
# Split into 8 chunks
N_CHUNKS = 8
# Split B_up and B_down into 8 subintervals
B_up_chunks = np.array_split(B_up, N_CHUNKS)
B_down_chunks = np.array_split(B_down, N_CHUNKS)
# Calculate mean of each chunk giving 8 mean values for B_up and B_down
B_up_mean = np.zeros((N_CHUNKS, 4))
for j in range(N_CHUNKS):
B_up_mean[j] = B_up_chunks[j].mean().values
B_down_mean = np.zeros((N_CHUNKS, 4))
for j in range(N_CHUNKS):
B_down_mean[j] = B_down_chunks[j].mean().values
# Calculate the coplanarity shock normal (64 samples)
n_cp_samples = []
for j in range(N_CHUNKS):
for k in range(N_CHUNKS):
Bu = B_up_mean[j][0:3] # starrting from start of B_u
Bd = B_down_mean[k][0:3] # starting from the end of B_d
n_cp = coplanarity_normal(Bu, Bd)
n_cp_samples.append(n_cp)
#print(n_cp, np.linalg.norm(n_cp))
n_cp_samples = np.array(n_cp_samples)
ncp_samples_list.append(n_cp_samples)
# Calculate shock angle relative to the coplanarity shock normal
B_up_mean_averaged = B_up_mean[:,0:3].mean(axis=0)
theta_Bncp_samples = []
for j in range(len(n_cp_samples)):
theta_Bncp = np.arccos(np.dot(B_up_mean_averaged, n_cp_samples[j])/np.linalg.norm(B_up_mean_averaged))*180/np.pi
if theta_Bncp > 90:
theta_Bncp = 180 - theta_Bncp
theta_Bncp_samples.append(theta_Bncp)
theta_Bncp_mean = np.mean(theta_Bncp_samples)
theta_Bncp_mean_list.append(theta_Bncp_mean)
theta_Bncp_samples_list.append(theta_Bncp_samples)
# errors correspond to 1 standard deviation
theta_Bncp_std = np.std(theta_Bncp_samples)
theta_Bncp_std_list.append(theta_Bncp_std)
```
### Plot the results
```python=
plt.hist(theta_Bncp_mean_list, bins=5, facecolor='#002045', edgecolor='#e0e0e0', linewidth=0.5, alpha=0.7)
plt.xlim([0,90])
plt.xlabel(r'Shock angle $\theta_{Bncp}$(degree)')
plt.ylabel('Frequency')
#plt.savefig("./output/fig_shock_angle_coplanarity_distribution.jpg", dpi=300)
```
## :busts_in_silhouette: Group 1 (Yvonne, Dayana, Sachiin, Diviyesh)
You will be responsible for plotting skewness vs kurtosis of coplanarity shock angles.
The skewness tells whether the distribution of the shock angle for a particular crossing is 'normal' or not.
A skewness of 0 means normally distributed (bell curve).
Skewness > 0 means more weight in the left tail.
Skewness < 0 means more weight in the right tail.
A kurtosis of 3 means normally distributed (bell curve).
Kurtosis > 3 means heavier tail (less peaked).
Kurtosis < 3 means lighter tail (more peaked).
[Click here](https://scontent-hkg4-2.xx.fbcdn.net/v/t1.6435-9/96665492_125491382456362_2119748312570527744_n.jpg?_nc_cat=110&ccb=1-7&_nc_sid=8bfeb9&_nc_ohc=BHo_-DU9KowAX_5_YEq&_nc_ht=scontent-hkg4-2.xx&oh=00_AT-GOh1aHnR_RtiROkuztdiIrBpYW6UlBgugtyNBZeJ4Ig&oe=62E25E37) to see example distributions for different skewness and kurtosis.
```python=
# Calculate skewness and kurtosis
from scipy.stats import skew
from scipy.stats import kurtosis
theta_Bncp_skewness = [skew(ENTER CODE HERE) for i in range(len(theta_Bncp_samples_list))]
theta_Bncp_kurtosis = [kurtosis(ENTER CODE HERE, fisher=False) for i in range(len(theta_Bncp_samples_list))]
```
### Plot the results
Make the plot and save it in your colab session.
```python=
plt.scatter(theta_Bncp_kurtosis, theta_Bncp_skewness, marker='+', color='k')
plt.axvline(x=3, color='k', linestyle='--', alpha=0.5)
plt.axhline(y=0, color='k', linestyle='--', alpha=0.5)
plt.xlabel(r'Kurtosis of $\theta_{BN}$')
plt.ylabel(r'Skewness of $\theta_{BN}$')
#plt.savefig("fig_shock_angle_skewness_kurtosis.jpg", dpi=300)
```
## :busts_in_silhouette: Group 2 (Belle, Junhao, Rui, Tingyu)
You will be responsible for plotting the angle between coplanarity normal and model normal ($\theta_{CPM}$) vs coplanarity shock angle:
You will need to store the $\hat{n}$ vectors from Analysis 1 where we calculated the shock angle using the BS model.
```python=
nhat_list = []
...
nhat_list.append(nhat)
```
Now to calculate the angle between the model normal and the coplanarity normal we do the following:
```python=
# loop through the nhat and ncp, and compute the dot product
theta_cpm_samples_list = []
theta_cpm_mean_list = []
theta_cpm_std_list = []
for i in range(len(ncp_samples_list)):
nhat = nhat_list[i]
ncp_samples = ncp_samples_list[i]
theta_cpm_samples = []
for j in range(len(ncp_samples)):
theta_cpm = # ENTER CODE HERE
if theta_cpm > 90:
theta_cpm = 180 - theta_cpm
theta_cpm_samples.append(theta_cpm)
theta_cpm_samples_list.append(theta_cpm_samples)
theta_cpm_mean_list.append(np.mean(theta_cpm_samples))
theta_cpm_std_list.append(np.std(theta_cpm_samples))
```
### Plot results
Make the plot and save it in your colab session.
```python=
plt.errorbar(x=theta_Bncp_mean_list, y=theta_cpm_mean_list,
xerr=theta_Bncp_std_list, yerr=theta_cpm_std_list,
fmt='+', color='k', linewidth=1, alpha=0.5)
plt.axvline(x=45, color='k', linestyle='--', alpha=0.5)
plt.xlabel(r'Shock Angle $\theta_{BN}$ (degrees)')
plt.ylabel(r'Angle between model and coplanarity normals $\theta_{CPM}$ (degrees)')
#plt.savefig("fig_thetacpm_vs_shock_angle.jpg", dpi=300)
```
## :busts_in_silhouette: Group 3 (Angelina, Boston, Boon, Ian)
You will be responsible for plotting Shock angle deflection $\alpha$ vs field strength ratio $Bd/Bu$
Deflection angle is the angle between $B_d$ and $B_u$.
```python=
# shock deflection angle
# Do dot product of Bu vs Bd to get 64 deflection angles, calculate 1 standard deviation
# Calculate Bd/Bu to get 64 ratios, calculate 1 standard deviation
deflection_angle_samples_list = []
deflection_angle_mean_list = []
deflection_angle_std_list = []
BdToBu_samples_list = []
BdToBu_mean_list = []
BdToBu_std_list = []
for i in range(len(df_BS_crossings)):
print(f'BS crossing {i}:')
# Get crossing time
crossing_time = df_BS_crossings.iloc[i].TIME
# Define interval
time_start = crossing_time - pd.Timedelta(7, unit='m')
time_end = crossing_time + pd.Timedelta(7, unit='m')
df_crossing = df_1s.query("TIME > @time_start & TIME < @time_end")
# Define B_up and B_down
if df_BS_crossings.iloc[i].DIRECTION == 'I':
B_up = df_crossing.query("TIME < @crossing_time")
B_down = df_crossing.query("TIME > @crossing_time")
elif df_BS_crossings.iloc[i].DIRECTION == 'O':
B_up = df_crossing.query("TIME > @crossing_time")
B_down = df_crossing.query("TIME < @crossing_time")
# Split B_up and B_down into 8 subintervals
N_CHUNKS = 8
B_up_chunks = np.array_split(B_up, N_CHUNKS)
B_down_chunks = np.array_split(B_down, N_CHUNKS)
# Calculate mean of each chunk giving 8 mean values for B_up and B_down
B_up_mean = np.zeros((N_CHUNKS, 4))
for j in range(N_CHUNKS):
B_up_mean[j] = B_up_chunks[j].mean().values
B_down_mean = np.zeros((N_CHUNKS, 4))
for j in range(N_CHUNKS):
B_down_mean[j] = B_down_chunks[j].mean().values
# Deflection angle analysis STARTS HERE
BdToBu_samples = []
deflection_angle_samples = []
for j in range(N_CHUNKS):
for k in range(N_CHUNKS):
Bu = B_up_mean[j][0:3] # starting from start of B_u
Bd = B_down_mean[k][0:3] # starting from the end of B_d
# Calculate deflection angle $\alpha$
deflection_angle = #ENTER CODE HERE
if deflection_angle > 90:
deflection_angle = 180 - deflection_angle
deflection_angle_samples.append(deflection_angle)
# Calculate Bd/Bu ratio
BdToBu_samples.append(np.linalg.norm(Bd)/np.linalg.norm(Bu))
# store results in a list
deflection_angle_samples_list.append(deflection_angle_samples)
deflection_angle_mean_list.append(np.nanmean(deflection_angle_samples))
deflection_angle_std_list.append(np.nanstd(deflection_angle_samples))
BdToBu_samples_list.append(BdToBu_samples)
BdToBu_mean_list.append(np.nanmean(BdToBu_samples))
BdToBu_std_list.append(np.nanstd(BdToBu_samples))
```
### Plot results
Make the plot and save it in your colab session.
```python=
plt.errorbar(x=BdToBu_mean_list, y=deflection_angle_mean_list,
xerr=BdToBu_std_list, yerr=deflection_angle_std_list,
fmt='+', color='k', linewidth=1, alpha=0.5)
plt.xlabel(r'Downstream / Upstream Field Ratio $B_d/B_u$')
plt.ylabel(r'Shock deflection angle $\alpha$ (degrees)')
#plt.savefig("fig_shock_deflection_angle_vs_BdToBu.jpg", dpi=300)
```
# Presentation
Intro and method sections:
* Slides 4-9: Angelina, Dayana, Belle, Boston
* Slides 10-13: Divyesh, Junhao, Boon, Rui, Ian, Tingyu
Results sections:
* Results 1: Rui
* Results 2: Boon
* Results 3: Group 1
* Results 4: Group 2
* Results 5: Group 3
Conclusion:
* Slide :