Effective-Gravity Regressor Demo

Contents

Effective-Gravity Regressor Demo#

Essential Libraries#

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from matplotlib.ticker import ScalarFormatter
from matplotlib.ticker import FuncFormatter
from matplotlib.tri import Triangulation, LinearTriInterpolator
import ipywidgets as widgets
from ipywidgets import interactive, FloatSlider
from IPython.display import display

from sklearn.metrics import explained_variance_score, max_error, mean_absolute_error
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_percentage_error

import UR_utils
from UR_utils import *

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
from DNN import Regressor

import os
import re
import time
from zipfile import ZipFile

# Orthogonal Legendre and Hermite polynomials
from scipy import special
from scipy.interpolate import griddata

from matplotlib import rc
rc('mathtext', fontset='cm')

Global variables#

device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')

if torch.cuda.is_available():
    torch.cuda.set_device(device)


selected_columns = ['cos(theta)', 'R_surf', 'dlogR_dtheta', 'g_surf', 'Rpole_num', 'Req_num', 
                    'Rpol/Req', 'ellipticity', 'eccentricity', 'rho_c', 'r_ratio', 'M', 'M(km)',
                    'Req', 'C', 'K', 'g_0(km^(-1))', 'Ibar', 'f(Hz)', 'f_tilde', 'Jgeom(km^2)',
                    'x', 'sigma', 'T/W', 'Mxf_tilde', 'Rxf_tilde', 'Qbar', 'S3bar', 'EoS']

selected_features = ['|cos(theta)|', 'C', 'sigma', 'eccentricity']

abs_mu_min, abs_mu_max = 0., 1. 
C_min, C_max = 0.0876346858172578, 0.3094541325480277
sigma_min, sigma_max = 0., 0.9612274013913829
eccentricity_min, eccentricity_max = 0., 0.7797886226038347

min_values = np.array([abs_mu_min, C_min, sigma_min, eccentricity_min])
max_values = np.array([abs_mu_max, C_max, sigma_max, eccentricity_max])

feature_scaler = lambda data: (data - min_values) / (max_values - min_values)

N_MU = 521

Read Star Data#

def read_zip(file_name, spin, test_percentage=0.2):
    # random seed for 'freezing' randomness
    SEED = 42
    rng = np.random.default_rng(SEED)
    
    # specifying the zip file name
    columns_names = ['cos(theta)', 'R_surf', 'dlogR_dtheta', 'g_surf', 'Rpole_num', 'Req_num', 'Rpol/Req',
                    'ellipticity', 'eccentricity', 'P_c', 'rho_c', 'r_ratio', 'r_e', 'M', 'M(km)',
                    'Req', 'C', 'K', 'g_0(km^(-1))', 'I(kgkm^2)', 'I(km^3)', 'Ibar', 'Z_p', 'Z_b',
                    'Z_f', 'Ω(Hz)', 'f(Hz)', 'f_tilde', 'Jgeom(km^2)', 'x', 'sigma', 'T/W',
                    'Mxf_tilde', 'Rxf_tilde', 'conv_rad', 'conv_plus', 'conv_minus', 'h_plus',
                    'h_minus', 'r_plus', 'r_minus', 'Q(km^3)', 'Qbar', 'S3(km^4)', 'S3bar', 'M4_geom',
                    'M4_asy^GH_geom', 'M4_asy_geom', 'M4_geom_2points', 'M4_geom_3points',
                    'M4_geom_4points', 'S5_geom', 'S5_asy_geom', 'EoS']
    
    g_scaling = lambda g_mu, g_pole, g_eq: (g_mu - g_pole) / (g_eq - g_pole)
    
    df_train, df_test = pd.DataFrame(), pd.DataFrame()
    # opening the zip file in READ mode
    with ZipFile(file_name, 'r') as zip:
        # Pop the folder from the list of stars
        zip.infolist().pop(0)
        
        star_train, star_test = list(), list()
        n_stars = len(zip.infolist())
        n_test_stars = int(n_stars * test_percentage)
        test_indexes = rng.choice(n_stars, n_test_stars, replace=False)
        
        for index, star in enumerate(zip.infolist()):
            star = zip.extract(star)
            df_star = pd.read_csv(star, sep=' ', names=columns_names, skiprows=1)
            
            # Keep stars that only with r_ratio >= 0.6
            if df_star['r_ratio'].iloc[0] < 0.6: continue
            repeat_values = df_star.iloc[0].values
            df_star.iloc[1:, 4:] = repeat_values[4:]
            
            # Select only this columns to save memory
            df_star = df_star[selected_columns]
              
            # Output normalization
            if np.all(df_star[spin] == 0.0):
                # Avoid zero division to static case
                df_star['g_scaled'] = df_star['g_surf']
            else:
                # Min max scaling at star level
                df_star['g_scaled'] = g_scaling(df_star['g_surf'], df_star['g_surf'].iloc[-1], df_star['g_surf'].iloc[0])

            if index in test_indexes:
                star_test.append(df_star)
            else:
                star_train.append(df_star)
                
        # Concat the dataframes to train and test
        if star_train: df_train = pd.concat(star_train, ignore_index=True)
        if star_test: df_test = pd.concat(star_test, ignore_index=True)
        
    return df_train, df_test
def load_stars(df, batch_size=4096, shuffle=True):
    df_target = df['g_scaled']
    
    # Z_2 Symmetry constrain
    df['|cos(theta)|'] = np.abs(df['cos(theta)'])

    np_features = df[selected_features].to_numpy()    
    np_targets = df_target.to_numpy()
    np_targets = np.reshape(np_targets, (np_targets.shape[0], 1))
    
    tr_features = torch.Tensor(feature_scaler(np_features))
    input_dimension = tr_features.shape[1]
    
    tr_targets = torch.Tensor(np_targets)
    final_dataset = TensorDataset(tr_features, tr_targets)

    # pin_memory=True, num_workers >= 1 if data is not already on device and model is training
    dataloader = DataLoader(final_dataset, batch_size=batch_size, shuffle=shuffle, num_workers=1, pin_memory=True)

    return dataloader, input_dimension, np_features, np_targets
def Surface_plot(df, x,y,w, z, xlabel,ylabel,wlabel,zlabel, view2, n_col,
                         border_axes, X,Y,W, Z, l_w):
    
    fig = plt.figure(figsize=(20 ,16)) 
    labels_text_size = 40
    ax = fig.add_subplot(111, projection='3d')

    dot_size = 40
    font_size = 40
    label_pad = 40
    label_size = 30
    
    #######################################################################################################
    mu_values = [0.000,0.45769231,0.78461538,1.000]
    colors = ['green', 'pink', 'cyan', 'purple']
    
    for i in range(0,len(mu_values)):
        scatter = ax.scatter(df[df['mu']==mu_values[i]][x].to_numpy(), df[df['mu']==mu_values[i]][y].to_numpy(),df[df['mu']==mu_values[i]][z].to_numpy(),
                   c = df[df['mu']==mu_values[i]][w].to_numpy(), s = dot_size, cmap='coolwarm', marker='o', alpha = 0.8)    


        triang = Triangulation(df[df['mu']==mu_values[i]][x].to_numpy(), df[df['mu']==mu_values[i]][y].to_numpy())
        interpolator = LinearTriInterpolator(triang, df[df['mu']==mu_values[i]][z].to_numpy())
        grid_x, grid_y = np.mgrid[0.0901155694351282:0.3062042574717896:500j, 0.0329041860812303:0.9416722276120412:500j]
        grid_z = interpolator(grid_x, grid_y)
        ax.plot_surface(grid_x, grid_y, grid_z, color = colors[i], alpha = 0.8, label = f'Interpolated surface with $\mu_\star$ = {np.round(mu_values[i],3)}', zorder = 5)

    # Add colorbar
    cbar = plt.colorbar(scatter,  shrink=0.5)
    cbar.set_label(wlabel, fontsize=font_size, rotation = 0)
    cbar.ax.tick_params(labelsize=23)

    ax.view_init(30, view2)   
    ax.set_xlabel(xlabel, fontsize=font_size,labelpad=label_pad) 
    ax.set_ylabel(ylabel, fontsize=font_size,labelpad=label_pad) 
    
    ax.zaxis.set_rotate_label(False)
    ax.set_zlabel(zlabel, fontsize=font_size,labelpad=label_pad,rotation = 90) 
    #ax.yaxis._axinfo['label']['space_factor'] = 3.0   

    ax.yaxis.labelpad = 30
    ax.zaxis.labelpad = 20
    
    ax.xaxis.set_tick_params(labelsize=label_size)
    ax.yaxis.set_tick_params(labelsize=label_size)
    ax.zaxis.set_tick_params(labelsize=label_size)
    
    for axis in [ax.xaxis, ax.yaxis, ax.zaxis]:
        axis.line.set_linewidth(3)
    
    ax.grid(False)


    leg = plt.legend(loc="best",ncol=n_col, borderaxespad=border_axes, prop={'size': 20}, shadow=True, fontsize="large")    #,bbox_to_anchor=(1,1)
    leg.get_frame().set_linewidth(3.0)
    leg.get_frame().set_edgecolor('black')
    
    plt.tight_layout()
    
    plt.show()

Evaluation: statistical evaluation measures#

Evaluation of the total Regression ANN model performance to the whole NSs Dataset test set#

df_eval_dataset = pd.read_csv('./Experimental Results/Effective-Gravity/dataset_measures.csv')
df_eval_dataset
explained_variance max_error mean_absolute_error mean_squared_error r2_score mean_absolute_percentage_error eval_eos_type eval_eos_name
0 0.999992 0.00773 0.000338 4.512352e-07 0.999992 0.000344 NaN NaN

Evaluation of the trained ANN model to the whole NS’s data (per EOS level) [test dataset]#

df_eval_eos = pd.read_csv('./Experimental Results/Effective-Gravity/EOS_measures.csv')
df_eval_eos = df_eval_eos.sort_values(by = ['eval_eos_type', 'eval_eos_name'])
df_eval_eos.reset_index(drop = True, inplace = True)
df_eval_eos
explained_variance max_error mean_absolute_error mean_squared_error r2_score mean_absolute_percentage_error eval_eos_type eval_eos_name
0 0.999997 0.003323 0.000239 1.905879e-07 0.999997 0.000244 Hadronic BL_2018
1 0.999995 0.003844 0.000303 3.420295e-07 0.999995 0.000305 Hadronic BSK22
2 0.999993 0.005413 0.000318 4.496382e-07 0.999993 0.000322 Hadronic BSK24
3 0.999990 0.006004 0.000446 7.214546e-07 0.999988 0.000444 Hadronic BSK25
4 0.999995 0.005449 0.000316 3.506700e-07 0.999993 0.000326 Hadronic BSK26
... ... ... ... ... ... ... ... ...
65 0.999993 0.004464 0.000407 4.830259e-07 0.999992 0.000402 Hyperonic DS(CMF)-3
66 0.999998 0.002719 0.000195 1.279006e-07 0.999998 0.000196 Hyperonic DS(CMF)-5
67 0.999998 0.002712 0.000191 1.061575e-07 0.999998 0.000193 Hyperonic DS(CMF)-7
68 0.999997 0.003194 0.000238 1.983635e-07 0.999997 0.000240 Hyperonic GM1 Y5
69 0.999997 0.003433 0.000247 1.821897e-07 0.999997 0.000248 Hyperonic GM1 Y6

70 rows × 8 columns

Evaluation measures for the trained ANN model to the star level [NSs at test dataset]#

#note: follow the ./Experimental Results/Effective-Gravity/ path and unzip the perc_error_star_level.zip file
df = pd.read_csv('./Experimental Results/Effective-Gravity/perc_error_star_level.csv')
C_min = df[df['sigma'] != 0]['C'].min(); C_max = df[df['sigma'] != 0]['C'].max();
sigma_min = df[df['sigma'] != 0]['sigma'].min(); sigma_max = df[df['sigma'] != 0]['sigma'].max()
df_new = df[df['sigma'] !=0].copy()
g_min_max = df_new['g_scaled']

mu_var = df_new['mu']
e_var = df_new['eccentricity']
z_1 = df_new['percentange_error']
C_var = df_new['C']
sigma_var = df_new['sigma']
df_new
percentange_error residual star_id mu g_surf g_0 g_scaled C sigma eccentricity eval_eos_type eval_eos_name
0 0.041721 0.000149 0 0.000000 0.005974 0.016730 1.000000 0.207095 0.735137 0.730157 Hyperonic DS(CMF)-5
1 0.046917 0.000168 0 0.001923 0.005975 0.016730 0.999981 0.207095 0.735137 0.730157 Hyperonic DS(CMF)-5
2 0.047352 0.000169 0 0.003846 0.005975 0.016730 0.999941 0.207095 0.735137 0.730157 Hyperonic DS(CMF)-5
3 0.041759 0.000149 0 0.005769 0.005977 0.016730 0.999872 0.207095 0.735137 0.730157 Hyperonic DS(CMF)-5
4 0.029527 0.000106 0 0.007692 0.005979 0.016730 0.999770 0.207095 0.735137 0.730157 Hyperonic DS(CMF)-5
... ... ... ... ... ... ... ... ... ... ... ... ...
4447251 0.002284 0.000029 121 0.992308 0.026326 0.020671 0.010611 0.223218 0.329564 0.555045 Hybrid OOS(DD2-FRG)-2 flavors
4447252 -0.006433 -0.000082 121 0.994231 0.026354 0.020671 0.007906 0.223218 0.329564 0.555045 Hybrid OOS(DD2-FRG)-2 flavors
4447253 -0.003755 -0.000048 121 0.996154 0.026383 0.020671 0.005195 0.223218 0.329564 0.555045 Hybrid OOS(DD2-FRG)-2 flavors
4447254 -0.001670 -0.000021 121 0.998077 0.026410 0.020671 0.002549 0.223218 0.329564 0.555045 Hybrid OOS(DD2-FRG)-2 flavors
4447255 -0.010952 -0.000140 121 1.000000 0.026437 0.020671 -0.000000 0.223218 0.329564 0.555045 Hybrid OOS(DD2-FRG)-2 flavors

4189361 rows × 12 columns

Universal description for fixed \(\mu\) values#

x = 'C'; y = 'sigma'; w = 'eccentricity' ;z = 'g_scaled' ; z_model = '';
Surface_plot(df_new, x,y,w,z, xlabel=r'$C$',ylabel='$\sigma$',
                     wlabel = r'$e$',zlabel=r'$(g(\mu_\star) - g_{\mathrm{pole}})/(g_{\mathrm{eq}} - g_{\mathrm{pole}})$', 
                     view2=200, n_col=2, border_axes=1, X=None,Y=None,W = None,Z=None, l_w=1.5)
../../_images/82b86287d7ffb4c362298755e31a044cc7178c40261555ce5a09e78edc455795.png

Universal description for each \(\mu\) value#

fig = plt.figure(figsize=(20, 16))
labels_text_size = 40
ax = fig.add_subplot(111, projection='3d')
dot_size = 60
font_size = 35
label_pad = 35
label_size = 35



# 3D scatter plot with q encoded as color
scatter = ax.scatter(mu_var, sigma_var, g_min_max, c=C_var, cmap='magma', s=60)  # q affects color and size

cbar = plt.colorbar(scatter,  shrink=0.5, )
cbar.set_label(r'$C$', fontsize=font_size,rotation = 0)
cbar.ax.tick_params(labelsize=23)

ax.view_init(30, 255)   
    

ax.set_xlabel(r'$\mu = \cos(\theta)$', fontsize=font_size,labelpad=label_pad) 
ax.set_ylabel(r'$\sigma$', fontsize=font_size,labelpad=label_pad) 

ax.zaxis.set_rotate_label(False)
ax.set_zlabel(r'$(g(\mu) - g_{\mathrm{pole}})/(g_{\mathrm{eq}} - g_{\mathrm{pole}})$', fontsize=font_size,labelpad=label_pad,rotation = 90) 

ax.zaxis.labelpad = 25  
ax.xaxis.set_tick_params(labelsize=label_size)
ax.yaxis.set_tick_params(labelsize=label_size)
ax.zaxis.set_tick_params(labelsize=label_size)
    
for axis in [ax.xaxis, ax.yaxis, ax.zaxis]:
    axis.line.set_linewidth(3)
    
ax.grid(False)
plt.tight_layout()
plt.show()
../../_images/3bcda7105a0ce5c271ea28d259710251958eaed2b908309771d99f215c0bc8da.png

Percentage error histogram in the test set for the suggested ANN model’s optimal weights#

fig,ax = plt.subplots(figsize=(14, 10),)
labels_text_size = 40
plt.xticks(fontsize=30) #fontweight="bold"
plt.yticks(fontsize=30)

xlabel = r'Absolute Relative Error  $[\%]$'
ylabel = r'Test Dataset PDF '

plt.xlabel(xlabel,size=labels_text_size)
plt.ylabel(ylabel,size=labels_text_size)

bins = 50
alpha = 0.8

# Histogram of errors aoociated with the proposed ANN Regression Model for at all sigma
y_reg_errors = abs(df['percentange_error']).hist(
                density = True,
                lw = 3,
                bins=bins-20,
                edgecolor ='maroon', 
                 histtype='step',
                zorder = 1,
                alpha = alpha, 
                label = 'ANN model (this work) for $\sigma \in [0.000,0.961]$.', color = 'maroon').autoscale(enable = True, axis = 'both', tight = True)

vertical_lines = [abs(df['percentange_error']).max(), None]  
plt.scatter(vertical_lines[0], 1.4e-7, color='maroon', marker='^', s=300, zorder=2, label=r'Max rel error: $0.91\%$')  # Star marker

# Histogram of errors aoociated with the proposed ANN Regression Model for sigma<=0.1
y_reg_errors_2 = abs(df[df['sigma']<=0.1]['percentange_error']).hist(
                density = True,
                lw = 3,
                bins=bins-20,
                edgecolor ='coral', 
                 histtype='step',
                zorder = 1,
                alpha = alpha, 
                label = 'ANN model (this work) for $\sigma \leq 0.1$.', color = 'coral').autoscale(enable = True, axis = 'both', tight = True)


vertical_lines = [abs(df[df['sigma']<=0.1]['percentange_error']).max(), None]  
plt.scatter(vertical_lines[0], 1.4e-7, color='coral', marker='^', s=300, zorder=2, label=r'Max rel error: $0.11\%$')



# Customize plot appearance
for axis in ['top', 'bottom', 'left', 'right']:
    ax.spines[axis].set_linewidth(3.0)

# Set logarithmic scale 
plt.xscale('log')
plt.yscale('log')

# Adjust x,y-axis limits (optional, based on log scale)
plt.xlim(1.7e-2,5)
plt.ylim(1.e-7,1000)


# Grid, legend, and layout
plt.grid(False)
leg = plt.legend(loc="upper right",ncol=1, borderaxespad=1, prop={'size': 17}, shadow=True, fontsize="large")    #,bbox_to_anchor=(1,1)
leg.get_frame().set_linewidth(3.0)
leg.get_frame().set_edgecolor('black')


plt.tight_layout()
plt.show()
../../_images/5db5fd768211f8ee8414090bdd09816cce5aa2bc4e544ffce1e27aaa5cda6782.png

Distribution of absolute Relative Errors for each EoS category in the test set#

eos_categories = ['Hadronic', 'Hyperonic', 'Hybrid']

EoS_categories_violin_plots(
    eos_categories = eos_categories, 
    df = df, 
    eval_metric = 'percentange_error', 
    color_map = 'viridis', 
    label = r'$g(\mu)$ model (this work): Max Relative Error $[\%]$ for each EoS Category utilized.', 
    scale = 'log',
    y_max = 5,
    y_label = r"Absolute Relative Error $[\%]$")
../../_images/2a60a425ee80344f50e89e20ec2cebfef780d65e797931670453d84b9d455cce.png

Distribution of absolute Relative Errors for Hadronic EoSs in the test set#

eos_names = [ 'BL_2018', 'BSK22', 'BSK24', 'BSK25', 'BSK26', 'D1M*', 'DDHδ','DS(CMF)-2', 'DS(CMF)-4', 'DS(CMF)-6', 'DS(CMF)-8', 'FSU2R',
       'KDE0v', 'KDE0v1', 'MTVTC', 'PCSB1', 'PCSB2', 'QMC-RMF2','QMC-RMF3', 'QMC-RMF4', 'Rs', 'SK255', 'SK272', 'SKI2', 'SKI3',
       'SKI4', 'SKI5', 'SKI6', 'SKa', 'SKb', 'SLY2', 'SLY230a', 'SLY4', 'SLY9', 'SkMp', 'SkOp', 'TM1e', 'TW', 'TW99']


EoS_class_violin_plots(eos_names = eos_names, 
                 df = df, 
                 eval_metric = 'percentange_error', 
                 eos_class = 'Hadronic EoSs', 
                 color_map = 'coolwarm', 
                 label = r'$g(\mu)$ model (this work): Max Relative Error [$\%$] for each Hadronic EoS utilized.', 
                 scale = 'log',      
                 y_max = 50, 
                 y_label = r"Absolute Relative Error $[\%]$")
../../_images/5be5db24a160791a746a0c2f4f591dcb8c9eb9de9ae5a651078a0c991cce2dad.png

Distribution of absolute Relative Errors for Hyperonic EoSs in the test set#

eos_names = [ 'DDHδ Υ4', 'DNS', 'DS(CMF)-1', 'DS(CMF)-3', 'DS(CMF)-5','DS(CMF)-7', 'GM1 Y5', 'GM1 Y6']

EoS_class_violin_plots(eos_names = eos_names, 
                 df = df, 
                 eval_metric = 'percentange_error', 
                 eos_class = 'Hyperonic EoSs', 
                 color_map = 'plasma', 
                 label = r'$g(\mu)$ model (this work): Max Relative Error [$\%$] for each Hyperonic EoS utilized.', 
                 scale = 'log',      
                 y_max = 50, 
                 y_label = r"Absolute Relative Error $[\%]$")
../../_images/2add5960fdd93bd3b93150d8dbf569c6485dd139629573f55e5161509f742d62.png

Distribution of absolute Relative Errors for Hybrid EoSs in the test set#

eos_names = ['DS(CMF)-1 Hybrid', 'DS(CMF)-2 Hybrid', 'DS(CMF)-3 Hybrid','DS(CMF)-4 Hybrid', 'DS(CMF)-5 Hybrid', 'DS(CMF)-6 Hybrid',
       'DS(CMF)-7 Hybrid', 'DS(CMF)-8 Hybrid','JJ(VQCD(APR)), intermediate', 'JJ(VQCD(APR)), soft','KBH(QHC21_A)', 'KBH(QHC21_AT)', 'KBH(QHC21_B)', 'KBH(QHC21_BT)',
       'KBH(QHC21_C)', 'KBH(QHC21_CT)', 'KBH(QHC21_DT)','OOS(DD2)-vect interaction 2 flavors', 'OOS(DD2-FRG)-2 flavors',
       'QHC18', 'QHC19-B', 'QHC19-C', 'QHC19-D']

EoS_class_violin_plots(eos_names = eos_names, 
                 df = df, 
                 eval_metric = 'percentange_error', 
                 eos_class = 'Hybrid EoSs', 
                 color_map = 'viridis', 
                 label = r'$g(\mu)$ model (this work): Max Relative Error [$\%$] for each Hybrid EoS utilized.',
                 scale = 'log',      
                 y_max = 300, 
                 y_label = r"Absolute Relative Error $[\%]$")
../../_images/fdbc7be37e71eda212aaec17624fee03eb55b54c1d985176a65228f181d0c8de.png

ANN Regression Model for star’s effective gravity: Evaluation on singular EOS#

# Choose the case/EoS of your preference
# In this demo we provide indicatively for demonstration 3 EoS: 1 per star's category investigated

# Hadronic case
#file_name = './Surface models for Hadronic EOS/SLY4/'

# Hyperonic case
#file_name = './Surface models for Hyperonic EOS/DNS/'

# Hybrid case
file_name = './Surface models for Hybrid EOS/KBH(QHC21_AT)/'
spin = 'sigma' 
test_percentage = 0.2

rotational_path = os.path.join(file_name, 'rotational_models.zip')
static_path = os.path.join(file_name, 'static_models.zip')

df_rot_train, df_rot_test = read_zip(rotational_path, spin=spin, test_percentage=test_percentage)
df_stat_train, df_stat_test = read_zip(static_path, spin=spin, test_percentage=test_percentage)

df_train = pd.concat([df_rot_train, df_stat_train], ignore_index=True)
df_test = pd.concat([df_rot_test, df_stat_test], ignore_index=True)

# Free the memory space
del df_rot_train, df_rot_test, df_stat_train, df_stat_test

Load the Trained Regression Model optimal weights to estimate for star’s effective gravity#

batch_size = 4096
model_path = './Model/Effective-Gravity/Effective-Gravity-model.pth'

dataloader_tr, input_dimension, np_features_tr, np_targets_tr = load_stars(df_train, batch_size=batch_size)
dataloader_ts, _, np_features_ts, np_targets_ts = load_stars(df_test, batch_size=batch_size)

regressor = Regressor(input_dimension=input_dimension, feature_scaler=feature_scaler).to(device)
regressor.set_device(device)
regressor.load_state_dict(torch.load(model_path, map_location=torch.device(device)))
regressor.eval()
Regressor(
  (MLP): Sequential(
    (0): Linear(in_features=4, out_features=200, bias=True)
    (1): LeakyReLU(negative_slope=0.1, inplace=True)
    (2): Linear(in_features=200, out_features=100, bias=True)
    (3): LeakyReLU(negative_slope=0.1, inplace=True)
    (4): Linear(in_features=100, out_features=50, bias=True)
    (5): LeakyReLU(negative_slope=0.1, inplace=True)
    (6): Linear(in_features=50, out_features=25, bias=True)
    (7): LeakyReLU(negative_slope=0.1, inplace=True)
    (8): Linear(in_features=25, out_features=10, bias=True)
    (9): LeakyReLU(negative_slope=0.1, inplace=True)
    (10): Linear(in_features=10, out_features=1, bias=True)
    (11): Sigmoid()
  )
)

Plot functions associated with residual and percentage errors#

def plot_residuals(residual_error, percentage_error):
    witdh, height = 16, 6
    fontsize = 20
    labelsize = 15
    lw = 5
    
    fig, ax = plt.subplots(1, 2, figsize=(witdh, height))
    # Residual error subplot 
    ax[0].plot(residual_error, lw=lw)
    ax[0].set_xlabel(r'Data', fontsize=fontsize)
    ax[0].set_ylabel(r'Residual', fontsize=fontsize)
    ax[0].tick_params(axis='both', which='both', labelsize=labelsize)

    # Percentage error subplot 
    ax[1].plot(percentage_error, lw=lw)
    ax[1].set_xlabel(r'Data', fontsize=fontsize)
    ax[1].set_ylabel(r'Percentage Error$\ [\%]$', fontsize=fontsize)
    ax[1].tick_params(axis='both', which='both', labelsize=labelsize)

    plt.tight_layout()
    plt.show()
    
    fig, ax = plt.subplots(1, 2, figsize=(16, 6))
    fontsize = 20
    labelsize = 15
    lw = 5

    # Residula error histogram
    ax[0].hist(residual_error, lw=lw)
    ax[0].set_ylabel(r'Data', fontsize=fontsize)
    ax[0].set_xlabel(r'Residual', fontsize=fontsize)
    ax[0].tick_params(axis='both', which='both', labelsize=labelsize)

    # Percentage error histogram
    ax[1].hist(percentage_error, lw=lw)
    ax[1].set_ylabel(r'Data', fontsize=fontsize)
    ax[1].set_xlabel(r'Percentage Error$\  [\%]$', fontsize=fontsize)
    ax[1].tick_params(axis='both', which='both', labelsize=labelsize)

    plt.tight_layout()
    plt.show()
def plot_surface_effective_gravity(mu, model_estimation, real_targets, C, sigma):
    witdh, height = 10, 6
    fontsize = 20
    labelsize = 20
    lw = 5

    fig, ax = plt.subplots(figsize=(witdh, height))
    ax.plot(mu, model_estimation, lw=lw, c='maroon', label='ANN model (this work)')
    ax.scatter(mu, real_targets, c='black', s=20, marker='o', label='Numerical Data')

    plt.xlim(0,1)
    plt.ylim(real_targets.min()-0.05, real_targets.max()+0.05)
    plt.xlabel(r'$\mu = \cos(\theta)$', fontsize=fontsize)
    plt.ylabel(r'$g(\mu)/g_0$', fontsize=fontsize)
    
    plt.title(f'NS model with C={round(C,3)}, $\sigma$ = {round(sigma,3)}')

    plt.legend(loc='best', prop={'size':fontsize}, shadow=True, fontsize='large')
    ax.tick_params(axis='both', which='both', labelsize=labelsize)
    leg = plt.legend(loc="upper right", ncol=2, borderaxespad=1, prop={'size': 15.},  shadow=True, fontsize="large")
    leg.get_frame().set_linewidth(3.0)
    leg.get_frame().set_edgecolor('black')
    plt.tight_layout()
    plt.show()

Universal relations suggested in this work for the parameters \(e\), \(g_p/g_0\) and \(g_e/g_0\)#

#def eccentricity(C, sigma):
#    return (
#        -99.173162625833 * C**5 +68.055729822908 * C**4 * sigma + 137.191420602024 * C**4 +12.9349885313244 * C**3 * sigma**2 -
#        57.474308297241 * C**3 * sigma -67.7948794729071 * C**3 -9.03315944594535 * C**2 * sigma**3 + 8.08346062523145 * C**2 * sigma**2 +
#        9.19713339469957 * C**2 * sigma + 14.9006458417145 * C**2 + 4.84885244516378 * C * sigma**4 -
#        6.44626099699536 * C * sigma**3 +2.75499036217858 * C * sigma**2 -
#        1.3329369261108 * C * sigma - 1.52533604289959 * C + 4.71450473450295 * sigma**5 -
#        13.8547513636472 * sigma**4 + 15.4712200610891 * sigma**3 - 8.71280504897915 * sigma**2 +
#        3.0422989983075 * sigma + 0.182560763719325
#    )

#def g_pole(g_0, C, sigma):
#    return (
#        g_0*(-62.8045467352441 * C**4 -23.2577694998269 * C**3 * sigma +
#        52.068673220798 * C**3 + 1.1160287935608 * C**2 * sigma**2 +
#        11.9714816462282 * C**2 * sigma - 15.6899254468899 * C**2 +
#        1.46606081557891 * C * sigma**3 - 1.46935053803789 * C * sigma**2 -
#        2.79057152330358 * C * sigma + 2.0186963881549 * C +
#        0.488086658631048 * sigma**4 - 0.800025443187691 * sigma**3 +
#        0.553202313363468 * sigma**2 + 1.08421869564885 * sigma + 0.908110925704064)
#    )


#def g_eq(g_0, C, sigma, e):
#    return (
#        g_0*(0.338070419688185 * C**3 +1.20592155663027 * C**2 * sigma +
#        0.12888785718781 * C**2 * e - 0.28467956062336 * C**2 -
#        4.03577574275211 * C * sigma**2 + 2.63090429234693 * C * sigma * e +
#        2.33122575049246 * C * sigma - 2.03273805025503 * C * e**2 +
#        0.141317760072598 * C * e + 0.0686633222621117 * C -
#        0.221009453432669 * sigma**3 + 0.36927602815501 * sigma**2 * e +
#        0.532800911941034 * sigma**2 + 0.230730659632592 * sigma * e**2 -
#        0.758366940518704 * sigma * e - 1.6917578234362 * sigma +
#        0.289040948522073 * e**3 + 0.83218178966767 * e**2 -
#        0.0297671570402102 * e + 0.995124108230518)
#    )

Select NS model for estimating the effective gravity at surface as well as the corresponding residual errors#

# Select Set (Train/Test)
is_train = True # True or False

# Select your favorite Star
star_index = 0

# Do not change
low = star_index * N_MU
high = (star_index + 1) * N_MU

select_set = lambda is_train, df_train, df_test: df_train if is_train else df_test
select_features = lambda is_train, np_features_tr, np_features_ts: np_features_tr if is_train else np_features_ts
select_targets = lambda is_train, np_targets_tr, np_targets_ts: np_targets_tr if is_train else np_targets_ts
    
# Select Set (Train/Test)
df_set = select_set(is_train, df_train, df_test)
features = select_features(is_train, np_features_tr, np_features_ts)
targets = select_targets(is_train, np_targets_tr, np_targets_ts)

# Estimate the star's effective gravity at surface using the ANN model
estimation = regressor.predict(features[low:high])

g_0 = df_set['g_0(km^(-1))'].iloc[low]
max_ = df_set['g_surf'].iloc[high - 1]
min_ = df_set['g_surf'].iloc[low]
minmax_diff = min_ - max_

#using parameter results coming from the universal realtions proposed

#g_0 = df_set['g_0(km^(-1))'].iloc[low]
C = df_set['C'].iloc[low]
sigma = df_set['sigma'].iloc[low]
#e = eccentricity(C, sigma)
#max_ = g_pole(g_0, C, sigma)
#min_ = g_eq(g_0, C, sigma, e)
#minmax_diff = min_ - max_
#############################################################################

# Static case
if np.all(df_set['sigma'].iloc[low:high] == 0):
    model_estimation = (estimation * min_)  / g_0 
    real_targets = (targets[low:high] * min_) / g_0
# Rotational case
else:
    model_estimation = (estimation * (minmax_diff) + max_)  / g_0
    real_targets = (targets[low:high] * (minmax_diff) + max_)  / g_0

mu = df_set['cos(theta)'].iloc[low:high]

Residual and Percentage error computations#

residual_error = model_estimation - real_targets
percentage_error = (residual_error / real_targets) * 100

Error distributions for a singular NS configuration#

plot_residuals(residual_error, percentage_error)
../../_images/2b2ae7a443a6b202e675059ffeacb6f449bc2ed62871ad4724c8126bac33900e.png ../../_images/741eef58feb94250a0f7ab843b517af4b93b48ad81f3bdf5ba788afe54dea304.png

Effective gravity at surface for an indicative NS configuration#

plot_surface_effective_gravity(mu, model_estimation, real_targets, df_set['C'].iloc[star_index * N_MU], df_set['sigma'].iloc[star_index * N_MU])
../../_images/835344b096f37276a5642b681dc8a13b9e8645cd20eb4167892eb56c4ff58a8a.png

Visualization of the all the effective gravity curves in the selected set (Train/Test) dataset for the specific EOS loaded#

def calculate_model_estimation(C, sigma, R_pole, R_eq, g_pole_scaled, g_eq_scaled, g_0):
    num = 50
    mu = np.linspace(0, 1, num=num, dtype=np.float32)
    C_np = np.array([C for _ in range(0, num)], dtype=np.float32)
    sigma_np = np.array([sigma for _ in range(0, num)], dtype=np.float32)
    e_np = np.array([np.sqrt(1 - np.square(R_pole / R_eq)) for _ in range(0, num)], dtype=np.float32)
    x = torch.tensor(np.array([mu, C_np, sigma_np, e_np])).T.to(device) # Convert the argument list to array for optimization 

    #############################################################################################
    #Convert the estimation list to 1-d array with dtype float 32 in order 
    #to have the same dimenensions and dtype with mu = cos(theta)
    model_estimation = regressor(x).cpu().detach().numpy().ravel().astype(np.float32)
    model_estimation = (model_estimation * (g_eq_scaled - g_pole_scaled) + g_pole_scaled) / g_0
    #############################################################################################
    return mu, model_estimation
# Select Training or test set
is_train = True # True or False

select_set = lambda is_train, df_train, df_test: df_train if is_train else df_test
select_features = lambda is_train, np_features_tr, np_features_ts: np_features_tr if is_train else np_features_ts
select_targets = lambda is_train, np_targets_tr, np_targets_ts: np_targets_tr if is_train else np_targets_ts
    
# Select Set (Train/Test)
df_set = select_set(is_train, df_train, df_test)
features = select_features(is_train, np_features_tr, np_features_ts)
targets = select_targets(is_train, np_targets_tr, np_targets_ts)
    
for star_index in range(0, 150):
    # Do not change
    low = star_index * N_MU
    high = (star_index + 1) * N_MU
    mu = df_set['cos(theta)'].iloc[low:high]
    ############# C and sigma for each star ######################################
    C = df_set['C'].iloc[low]
    sigma = df_set['sigma'].iloc[low]
    
    #################### ANN results #########################################
    estimation = regressor.predict(features[low:high])
    #Convert the estimation list to 1-d array with dtype float 64 in order 
    #to have the same dimenensions and dtype with mu = cos(theta)
    estimation = estimation.ravel().astype(np.float64) 
    ##########################################################################
    
    g_0 = df_set['g_0(km^(-1))'].iloc[low]
    max_ = df_set['g_surf'].iloc[high - 1]
    min_ = df_set['g_surf'].iloc[low]
    minmax_diff = min_ - max_
    
    # Results coming from the suggested universal relation 
    #g_0 = df_set['g_0(km^(-1))'].iloc[low]
    #e = eccentricity(C, sigma)
    #max_ = g_pole(g_0, C, sigma)
    #min_ = g_eq(g_0, C, sigma, e)
    #minmax_diff = min_ - max_
    #############################################################################
    
    if np.all(df_set['sigma'].iloc[low:high] == 0):
        model_estimation = (estimation * min_) / g_0 
        real_targets = (targets[low:high] * min_) / g_0
    else:
        model_estimation = (estimation * (minmax_diff) + max_)  / g_0
        real_targets = (targets[low:high] * (minmax_diff) + max_)  / g_0
    
    real_targets = real_targets.ravel()
    

    ANN_fract_diff = 100*(model_estimation - real_targets)/real_targets
    
    # Create subplots side by side
    fig, axs = plt.subplots(1, 2, figsize=(14, 6))
        
    axs[0].plot(mu, model_estimation, lw=2, c='maroon', label='ANN model (this work)')

    
    axs[0].scatter(mu, real_targets, lw=3, c='black', label='Numerical Data')
    axs[0].set_title(f'NS with C={round(C,3)}, sigma = {round(sigma,3)}')
    
    axs[0].set_xlabel(r'$\mu = \cos(\theta)$', fontsize=20)
    axs[0].set_ylabel(r'$g(\mu)/g_0$', fontsize=20)
    
    axs[0].set_title(f'NS model with $C$={round(C,3)}, $\sigma$ = {round(sigma,3)}')
    axs[0].legend(loc='best', prop={'size': 15}, shadow=True, fontsize='large')
    axs[0].tick_params(axis='both', which='both', labelsize=15)
    
    axs[0].set_xlim(0,None)

    for axis in ['top','bottom','left','right']:
        axs[0].spines[axis].set_linewidth(2.0)

    leg = axs[0].legend(loc="best",ncol=1, borderaxespad=1, prop={'size': 14}, shadow=True, fontsize="large") 
    leg.get_frame().set_linewidth(2.0)
    leg.get_frame().set_edgecolor('black')
    

    axs[1].scatter(mu, ANN_fract_diff , lw=1, alpha = 0.8, c='maroon', label = 'The proposed ANN model.')   

    axs[1].set_xlabel(r'$ \mu = \cos(\theta)$', fontsize=20)
    axs[1].set_ylabel(r'$\Delta g(\mu)/ g(\mu) \ [\%]$', fontsize=20)

    for axis in ['top','bottom','left','right']:
        axs[1].spines[axis].set_linewidth(2.0)
    
    plt.tight_layout()
    plt.show()
../../_images/fc6bf9a547e4ec5d8f2f022915a904609b6404e933dc4f5e28f329c5ec7e4930.png ../../_images/456f4932d4a06c72b5f8ea9c143681e2c733cc06701d3c708a59f29278a6fbfb.png ../../_images/530b1606f886e1bbe7a81f7a1fb0e088b7f8e493ca4c4d06b0f7588f1ec73a21.png ../../_images/9bfa8cc6624670e4f273c65e746f166861f01716aae0da5ebca3a6fce507f3dd.png ../../_images/aa3582dc54747560918095d58eb2ab0078c0f0e0f33087163cca0e0df1d27520.png ../../_images/64e08e20bb5b04ff9694791de3cffd4f10df41320ad645a4de5fdd65185a399d.png ../../_images/9ae7cb14d118c8d17e941b058d4892ede2eaf68b03ba9bd54c12d0486721195a.png ../../_images/fd6b7b1ca5a11e561c1218ee4528476a088968b2ff31a95855e5b40e8d5c6095.png ../../_images/cab57933e30ea815db8ae7f585adc0e27ba316580a823145951e0b7d77a2a0f3.png ../../_images/16c21236e11ffdc820fe9b14ce630f6cb59dba1c79ee60e96a39e673fdde6e8a.png ../../_images/ef99e97a4dc2f08e958f49809b8769d3ef2550e9a07ffef8be5dacb8f2d882a4.png ../../_images/b6966efa216b775e9b8ea8b0b19b6ff749c2fda3c2273348b646f1cfa6bc9705.png ../../_images/48a05c3fb91c5a1835358e3a1d5805d37128405fc3f8333417d1a76c39cd0d92.png ../../_images/9c2c3412be2996ba46f8c2e469b2c66b21939a3a62656ebec56d8ceba62b2952.png ../../_images/ebdf238b175c15f417369faa8dba28510eaca643987bac3e7f6f6863ae0eb93c.png ../../_images/0a769ff6e26792b380d9161fba49e6b512bd4ba3f7f559cb2dae1daad6df4b7d.png ../../_images/5d6ea6574ce7ae4fd47a1a5820b8192ede080998dbb03613260501547d94bad1.png ../../_images/0d28d6d5410bfa93a5d56496470bcea74b876ec9d5af848256b59e2fdf5c7acc.png ../../_images/bee05f3564563807f7faeb8ddd93f344e1089a0a2117f527c55071eb68330b16.png ../../_images/80bcc44612ab14f5b0e7acccc5c97002db4013e90ddc7d8c15433aa64148625c.png ../../_images/94cca86941601bde89a826ed3d4207dc6192778e95dc9627f0190d9d2e9d6f28.png ../../_images/640636fe7b168e89d9abde2c6430202fe0b3ecee2f7d3c5d7aaafbae2ea3410c.png ../../_images/78ba813143954d4172a8924a75d3a6570808194bfa1a1a848a7a81f765bb860e.png ../../_images/f856bcb08e49ec7567d78fb2859cd3f7f36e79fbeddb5fec042a24946a8f5bd2.png ../../_images/d125aac6094b5dd934f0c491bd9449646830efbcac4c692996f695d35e3226b3.png ../../_images/8a7996e003e33b648ae00357a9c6a024ac33fddae2160ef1266b7c1ffbcecbd9.png ../../_images/3974ff44abbc6921090204f8fd9b07d326678b13c5a4f139cc98dce60e348105.png ../../_images/b58773bf69d877fcc6f5b3cc09b7023892f1d6fd8f0a198c7448e2c7c752cb88.png ../../_images/42054f4cff00825d08a39657a1eb8da87292338e83930da441c63e106c446f7c.png ../../_images/cd3c32279b309fb313aa73b1b131a78d57cb65ddbaaf77832473210c0bef6f87.png ../../_images/62dedcae88972d8e5acb16b47c181a236617602481b8937411b9e4481b159d71.png ../../_images/1edf65ea5e6da747d0ccdb145fddf67cf348febc45845b226210014538566820.png ../../_images/f3bedda4a81503354d849b3cfa9c764fca432701312e06cd02748ee8b0251c06.png ../../_images/7287dd6b3163bcb4abf3f91b44ce88b96b5e138fafc0c39a2abb40e088e57050.png ../../_images/97d778c9b8d9f51afd3a2f375718d32a95dfb39b84c52de9ec937e4f761cac66.png ../../_images/65da048dfc09515c45448ea39a9219953a9ccf42e01ac1cf11736b4fc81fd90a.png ../../_images/175d1f873f3c9e22579faf3360a7529c8d449960f9b59efa7b0144f08b0a1d7d.png ../../_images/918b294de10ce3c7a2e0b149b09e9fffa51130f083abdae2c4d849a2d71779e4.png ../../_images/fb0e1eb1382ef44694858563a78a339eb998c66309bc55d5aebaa5243d5cca04.png
Exception ignored in: <function WeakMethod.__new__.<locals>._cb at 0x70fa8f7cede0>
Traceback (most recent call last):
  File "/home/gregory/anaconda3/lib/python3.11/weakref.py", line 53, in _cb
    def _cb(arg):

KeyboardInterrupt: 
../../_images/abd21d983f580df25f1760d8f52693d384f714f8f2dba4edca77f14c5e3799c8.png ../../_images/14a867967fd4615e26f1ed392f6397a64bacd8584bcf3a44600711d32d1fed20.png ../../_images/88ed17c75d3c286805d851a8bf524bc43591f5f5327d1ee82f05144580870748.png ../../_images/f858f99ddb181bf34a39b3f7d13c3a2eddaba6eb2f795717f44e8b3eaf5990dd.png ../../_images/fc1e9a5fce8ca417280d72b3351f4748ed5422fcb16275f02246e26ee0488021.png ../../_images/bb61c05e7e8df202ce61ed485c804f685705a3833b3f7a5febffc6cbae58badc.png ../../_images/464d7ab061d056f33de2c9e02b7acbf080f6b9fc47c0322bee885fc508212f11.png ../../_images/72454580cfee3ebeacb0eee5c3f3fd1e06e51283e82c0759fcec2c4ebe7e2c57.png ../../_images/62664d58429092a8699e76caaa898600aae3257bfab7eddadd21a40d0c035ed5.png ../../_images/d62e778151f8faf45f6634b438ef348e226819490438f7e14fb1ae6761d899f9.png ../../_images/dfd8254c0785027d9c3f6e5d2e46d7a1969f953870054601b6919937673ea700.png ../../_images/782f6c1dff9b1f16c5e228494a4fd345e95699f19931d905a0145d44985bc29e.png ../../_images/602d1366cad88095d1f8e89888e66882456b06927cc10bc0130645d316ace2c8.png ../../_images/11d535c8292bf6992fa4a910ad29dc57f44ea93263b5327f1bf086befe9c6389.png ../../_images/dea694512b7e8c8d3b75a3a20261dbda3b04f0c7ca2fbc9d124f20e64ee02e55.png ../../_images/854db688fdd6b5d9e035179f6261b49b6e52e47226443ca6a74a41632f85f1f8.png ../../_images/3c4724cc9b70a45a9feaeed440f0c36dfabc07bceaf551d962266f259b40171f.png ../../_images/ad935d02acd9ab8729f8cfc9b015544ab44fc4fa30e6aede50a7e9cf4e9beb58.png ../../_images/3cd733abb35b0ef7cd10a2dcc34d801f5ddc7d75ae417983e9f0f8e00f8b97ac.png ../../_images/c750081097af69db000ada1ff2fd841b53f6a751f03bc561e1eedf59a2dd6949.png ../../_images/8e802c65158bf454a7d62f4a570c5148261ec459085c62e55f8f6670e5285a86.png ../../_images/5c51c2657a1fe130132dede40778bed1f2f51a78370d22cd4e37e9cfe2bf1413.png ../../_images/63b5ee483e98884224b51d4e55af5e706dd799b99611070905ca273a0ced30e7.png ../../_images/25dd7e0469fec407b65b4ee54c57b3ab8447937f0838eafbc73561699c829239.png ../../_images/e53808483239e2a6a34a98435fc52c4f85afcbeb9a8dc1db4870c8e466bcda0e.png ../../_images/a19318b365f3351ad632a94c9497cf4725a148652fa30f3711b0e7f2f764d259.png ../../_images/961a7c449511400d7e0246626ca24ed71363b9a0a68ab6b041031450f4ab178d.png ../../_images/cd7a64d7af06cb95ee99567bc9a8288aab052c0aa3601c6804e848b773f55e7e.png ../../_images/0e4e1e32df296740576ac66874cf219f5791f654441a5382da528ff4dc7f1ebe.png ../../_images/ba8dbc8bb8b4393840f6070d1e98c27055565c26fa7829b367152a45e45b99f9.png ../../_images/e1bf6feeb507f9fb5f6db27aebb0dccbeafb4b706e92be667008b442779b91c7.png ../../_images/1e2fbcc58a20b491f74c0513b2d3abf68616d7b7c997672bfa8d1390edf1ad60.png ../../_images/0ad8161ff80450068756c78cd67212a682ab522fe0a9e40a07de283780602b45.png ../../_images/7f9903c20e91d188aefff06127b580e10da573b987ff0aab839e5e48c8ba8098.png ../../_images/d68c12920d596bf87c894778c1e153c533224fa2d22f035f0ac15e890d26088b.png ../../_images/45770e4a8e047d00f5139745f634cf4719e38e0402ce253ef96e67357fd1b512.png ../../_images/f64c5026196273bf1cb2cc58292db163404521a557bfa665b3166ed698990a9f.png ../../_images/20fc1263b1b418d81267026703a159c4f736a77805b8865176b6c300eae0dcb2.png ../../_images/b37f58c4109ea893ea2b46d3fc2edea5f5a5075e64a1d7a39c999142e8c4936d.png ../../_images/eea54e81ea628b498822553aeef7aa88c32febff95e309267222dd2be964dae8.png ../../_images/8ad7a515fa608285f9eef2f96acf71a7bfeac92e67a2ce0c378b54ebe7026ef7.png ../../_images/ca3b7e5515d9136fc4bfbd724584685fd13e0d741fcf04988a6882ac709736a8.png ../../_images/f556603f8dd28ec575ef004bd963b019bf186e596fdc458140d9e7b002f56262.png ../../_images/12143f2d281c505224b9b08ba731ffa529abb5871a827e7f3d5ef58347868068.png ../../_images/2bc4def1ea8dc23c3ffac34762c564ccaab2b544a8831fde57e64897d447245f.png ../../_images/671c0e088f5b3215857bba57deaf50ab46c09c95f78b6c7aa732be1034cfc697.png ../../_images/648b9db0ba05dfc0cb622423f3b62d4c272a0dca99e94028443cdf0f28eee1af.png ../../_images/46399db77d33f10441154e5127dcb4a238cf6f5bf87b81ea4602e84420299d11.png ../../_images/0864330a7d2bc70903b06810796d161eabb5aae6b4181009839adb5d66112f19.png ../../_images/a1342e9c5baa5205c29ad530a011424d9373a299949df790de21f41a4c5503f9.png ../../_images/5366f6bb81282a608d261d4bb0a907d0c29fcfc9692a935002cf20568a3e2a19.png ../../_images/e9d1086e6affc8a71754253cbb413e0ad02fc772941329ce8e3394cebbfe71e9.png ../../_images/c42d7712fc2c9ae9765bb1033d90a0221daea1b4feba92a1b8f3aed6d664f033.png ../../_images/01e3f5d7e7067d5c6ae821c1b8d9e619fea1e480ca5854137924a30f99d1a04b.png ../../_images/e1f8bd12744b227cf2f50d38932d185b4ea072d208ad59d48f0e7febfcda4720.png ../../_images/68497b99a4d60be0fa5e43d42163283c6fa9b419b94a44558bc85d74ba3eae8f.png ../../_images/42973c3c696a6ed85ab141514d45c0e4783cd070000c95238c2dc0a6e40857c3.png ../../_images/702040eaff38cbce5ed752a3213bc06c306f788c1bff0a9ade963334f4f6db46.png ../../_images/0cd38b20adb4cab4e877ebbb352f99b494cd194260cef7be68e422afe216d669.png ../../_images/5fad40fe1132f6acdb24f19c6923c692ef401f705573965fca37bd507015d225.png ../../_images/ccb84411096cbb5d08f8a360e19b34d44fdcb9181e43662f39851093dab07ae4.png ../../_images/411d648b78090bc38e4b264adb4edd8efd2b34018d14d062fae7606edc5eb7d7.png ../../_images/5dfc4a5344904cb26fc321eb1c21cd4fa913e499d3808137ba03c34376c6c4ac.png ../../_images/bcd960c3ae2ad30501df9f345bad72a4d71f1242d65438716af5419f5ed6b5da.png ../../_images/6823ca07b503b34cd2f9b58f57f3c83bc493dcf608e4c68f8e63888403d562a2.png ../../_images/64c82d51fb500b8961743fa003482d7bfa005a471210899ad12ea6cdcf6d73dc.png ../../_images/c5fb5adb977091725cd924a5a908b035a307aa7be46878a77ea7d3c0cc698ae1.png ../../_images/f9b399d890055f88ba5c20009e5f6bbf017d41e4c935adf4079d3128726759f0.png ../../_images/8f09dc6ed37ca4d8a585ae3ee5bc4540249eecb8bb36085f9b8a9026d45fabb8.png ../../_images/3f3eccb3c79e6b43d1a193160fda0536fa8e5a2cdc5abf8948c46dffc236ee5a.png ../../_images/7758a3eca8c93c0d673e3688ab669b0d1e71ace388297c6a8058fc25436d5762.png ../../_images/6006f663521cc560e50dda190d17b4682f8808150c962bbeeb82eec43c81de31.png ../../_images/af06f9c17743d217a6419e564f5a1b7b153547403d4b8f51b454c0cef67f00a9.png ../../_images/08796c83f617b6532dd71111a5c4cab3f27bf2d4ae87be763091a17fc554a36b.png ../../_images/7ee04ec288ad7234fdfc0aea0f6e532e451099e2abfe2993bf1bb70ce9853298.png ../../_images/75637bf8e9894e696167d00d3b07ae5b2a38acbd11d2a0e7a81afbf2a97c2b2a.png ../../_images/84a32aa145a278048f3e5ce15c39df50888f23e019469e91f91445de5b3d6e3a.png ../../_images/f7e10f0cc7bad887b55015328ebc44f01f8792a9a766984009be4d514295849d.png ../../_images/db007751054efa9d4bab50e05942046d8f79bb30827e138c8a26e7e7ac604ec9.png ../../_images/ba8ceb8d136311bf55c80fee42ae3c8c9074e5f4c21882b16a51bf82148efc2a.png ../../_images/75ee8c6334240f04f8703ba16247a85f7fef0a62939f0cc779e3018ba242ceda.png ../../_images/c7894a4505a539814ec1bb9fe0e7b254f26ac7e272248fb57e7d60ff4f2d7954.png ../../_images/9aa822086809ea889279ea46bc9fddb1170b5323659d4b21e263dcee7ab80438.png ../../_images/1d21be2bad2666e0a2bb5a436973f48d09a20a099e33403e4f92907eb80993f7.png ../../_images/ada484b0ffba253b55fb3477b2b863ea945d1d1a218f898a10ae5d374bcb246b.png ../../_images/f421cb0a2e04dc686951499108430be89a465ef4f6420b2a4746c03060d96168.png ../../_images/8d592bf00dd983b347ec6a83c0d454c04d366b0d4543b255da84ac9227783efb.png ../../_images/d3f1024e071fce9f12b96cbabf2632df4c4b4bae388bbabeadc225b7484aed85.png ../../_images/eb86e5693b14cdeb2f08f6021855748f801b81bdb27998a05458261c325f4043.png ../../_images/4964cc45d86614f4acc5b4907318f6d34d5021bfb42e8e832be76ac31f6827a8.png ../../_images/cd2f332e4ae0ad13a88786baf975a130982875ce3168f2ca20be592cea6a032a.png ../../_images/0715b2f417c04f7a9f3516bc53052ecf57dd34daf9d9204c922cd257641612bf.png ../../_images/87743df9d55474dc301eee9d048422571768582c84062e7ade278c217a737a80.png ../../_images/d68fbcaf31f979a2c847258f890ae179ef1fd7afa31f3e791f6d1f88ea93193b.png ../../_images/331832bb4cea74ca1dd8a68d628a05e18bfb289f5bbc3f2a8f4972a21df8d1c7.png ../../_images/76a85ee439a30e052d232499923e76806dc9962cf19b5cb50858d20834024306.png ../../_images/be88bb0d925bfac6d4e0c7422fea6acafa2d1c1e004bad03e05bec79815f3f8c.png ../../_images/df894447506799b326a556721f84e00ed3abbb86b3d547238d841e196adc6d63.png ../../_images/82026a4d4527b853b58481aafef9573aac865011ab089e30996da481000cda10.png ../../_images/690e45682c4fcdc82d0d4a3b653eafd0e85c48cf8e80a5e03049b7de3ddee762.png ../../_images/da73dc0b322f8327cdca1407a6445d4dd96f37c713a66726ddc1a6870d1b831e.png ../../_images/673474e5615412849dc0e28bd8e99082f74d6000b4df8885e9ebf777790784c0.png ../../_images/f6e01fc9517282ef58fb9164544226189d5acfed08ff8c125d8c0c12cc753318.png ../../_images/20b3f1ef1252e11b0fdd35ccb1edbed2e2e3966d73b22b3f2cc1ffb9efb9668e.png ../../_images/e7f94018fefef9bf019287422c3161ed8c37c896bf4172f536f3a012ae7b531a.png ../../_images/91b0017ed5513c6e197d098e46f784b2f6146428eeb133490f2b78f4b71d7fb2.png ../../_images/5d4666824901c8dc67ed1ab7ecd48590bb57347173dd8dd4db69d30ad7ee5f38.png ../../_images/f2e891f4b710f15bacbce020aeb18be5e0987dc521ca821f4f37ce561dda339e.png ../../_images/b975ec1085dae2f577217743b228d0635cc81d48c8671027258fbb3b1b02a7ab.png ../../_images/0c1f6ba64dd1358e646d3df7ca2a381a3e08acc481e6e5f48723998135cb9693.png ../../_images/6b10d0d1f80283b7ea95eabd91a4162d76d3c20657336d54ed2abdd9b524600b.png