import json
import glob
import numpy as np
import os
import matplotlib.pyplot as plt
[docs]def setup_error_dict(head_directory_name):
"""
Returns a dictionary of the chi squared errors associated with each fit in the group.
Args:
head_directory_name (str): Name of the main output directory.
Returns:
dict: Error dictionary where the keys are the structurs in the fit separated by a dash, i.e. '1-2-5', and values are the chi squared error of that fit.
"""
error_dict = {}
for error_file in sorted(glob.glob('{}/*/error.dat'.format(head_directory_name))):
error = float(np.loadtxt(error_file))
structure_num = error_file.replace('/error.dat', '').replace('{}/'.format(head_directory_name), '')
error_dict.update( {structure_num:error})
return error_dict
[docs]def setup_potentials_dict(head_directory_name):
"""
Returns a dictionary of the chi squared errors associated with each fit in the group.
Args:
head_directory_name (str): Name of the main output directory.
Returns:
list(dict): Potentials dictionary where the keys are the potential parameter labels (str) and values are a tuple of the fitted structure numbers (str) and the associated parameter value (float).
"""
list_of_potential_dicts = []
for potential_file in sorted(glob.glob('{}/*/potentials.json'.format(head_directory_name))):
with open(potential_file, 'r') as f:
potentials = json.load(f)
structure_num = potential_file.replace('/potentials.json', '').replace('{}/'.format(head_directory_name), '')
potentials.update((k, (structure_num,v) ) for k,v in potentials.items()) #Remove int if directory naming system changes to include strings. This will change the order of the structures though.
list_of_potential_dicts.append(potentials)
potentials_dict = {}
for key in list_of_potential_dicts[0].keys():
potentials_dict[key] = [potentials_dict[key] for potentials_dict in list_of_potential_dicts]
return potentials_dict
[docs]def plot_errors(error_dict, output_directory, xlabel_rotation=50, title='default', save=True):
"""
Plots the chi squared errors for each fit in a sequence of fits, with the x-axis being the fit (labeled with the structure numbers in the fit) and the y-axis being the chi squared error.
Args:
error_dict (dict): Keys are the structurs in the fit separated by a dash, i.e. '1-2-5', and values are the chi squared error of that fit.
output_directory (str): Directory pathway to output directory.
xlabel_rotation (int(optional)): Rotation applied to the x-axis labels. Default=50.
title (str(optional)): plot title, default='fitted errors ($\chi^2$)'.
save (bool(optional)): True to save the plot, Flase to not save. Default=True.
Returns:
None
"""
plt.scatter(*zip(*sorted(error_dict.items())))
plt.xticks(rotation=xlabel_rotation)
plt.xlabel('fitted structure numbers')
plt.ylabel('$\chi^2$ error')
if title is 'default':
plt.title('fit errors ($\chi^2$)')
elif title is not None and title is not 'default':
plt.title('{}'.format(title))
if save is True:
plt.savefig('{}/fit_errors.png'.format(output_directory),dpi=500, bbox_inches = "tight")
plt.show()
[docs]def plot_parameters(potentials_dict, output_directory, xlabel_rotation=50, title='default', save=True):
"""
Plots the potential parameters for each fit in a sequence of fits, with the x-axis being the fit (labeled with the structure numbers in the fit) and the y-axis being the parameter value.
Args:
potentials_dict (dict): Keys are the potential parameter labels (str) and values are a tuple of the fitted structure numbers (str) and the associated parameter value (float).
output_directory (str): Directory pathway to output directory.
xlabel_rotation (int(optional)): Rotation applied to the x-axis labels. Default=50
title (str(optional)): Plot title, default=''{} fitted parameter'.format(k)'.
save (bool(optional)): True to save the plot, Flase to not save. Default=True.
Returns:
None
"""
for k,v in potentials_dict.items():
x_val = [x[0] for x in v]
y_val = [y[1] for y in v]
plt.scatter(x_val,y_val)
plt.xticks(rotation=xlabel_rotation)
plt.xlabel('fitted structure numbers')
plt.ylabel('{} value'.format(k))
if title is 'default':
plt.title('{} fitted parameter'.format(k))
elif title is not None and title is not 'default':
plt.title('{}'.format(title))
if save is True:
plt.savefig('{}/fitted_{}.png'.format(output_directory, k) ,dpi=500, bbox_inches = "tight")
plt.show()
[docs]def plot_forces(dft_forces, ip_forces, output_directory, local_directory, alpha=0.02, save=True):
"""
Plots the forces for each fit in a sequence of fits, with the x-axis being the fit (labeled with the structure numbers in the fit) and the y-axis being the forces.
Args:
dft_forces (np.array): dft forces associated with each atom (x,y,and z) in each structure fitted.
ip_forces (np.array): Fitted forces associated with each atom (x,y,and z) in each structure fitted.
output_directory (str): Directory pathway to output directory.
local_directory (str): The individual fit directory in a series of fits or the singular fit directory.
alpha (float(optional)): Degree of transprancy for the plot series. Default=0.02.
save (bool(optional)): True to save the plot, Flase to not save. Default=True.
Returns:
None
"""
x = np.arange(0, len(dft_forces.flatten()))
plt.scatter(x, dft_forces.flatten(), label='dft', alpha=alpha)
plt.scatter(x, ip_forces.flatten(), label='ip', alpha=alpha)
plt.legend()
plt.xlabel('atom number')
plt.ylabel('force')
# plt.text(0,4.5, 'error: {0:.5f}'.format(np.sum((dft_forces - ip_forces)**2)/ dft_forces.size))
if save is True:
plt.savefig('{}/{}_forces.png'.format(output_directory,local_directory),dpi=500, bbox_inches = "tight")
plt.show()
[docs]def plot_stresses(dft_stresses, ip_stresses, output_directory, local_directory, save=True):
"""
Plots the stresses for each fit in a sequence of fits, with the x-axis being the fit (labeled with the structure numbers in the fit) and the y-axis being the stresses.
Args:
dft_stresses (np.array): dft stress tensors associated with each structure fitted.
ip_stressed (np.array): Fitted stress tensors associated with each structure fitted.
output_directory (str): Directory pathway to output directory.
local_directory (str): The individual fit directory in a series of fits or the singular fit directory.
save (bool(optional)): True to save the plot, Flase to not save. Default=True.
Returns:
None
"""
x= ['XX', 'YY', 'ZZ', 'XY', 'YZ', 'ZX']
dft_y = dft_stresses.reshape(5, 6)
ip_y = ip_stresses.reshape(5,6)
for dy, iy in zip(dft_y, ip_y):
plt.scatter(x, dy, label='dft', color='tab:blue')
plt.scatter(x, iy , label='ip', color='tab:orange')
plt.ylabel('stress tensor')
plt.text(1.5,90, 'stress tensor error: {0:.5f}'.format(np.sum((dft_stresses - ip_stresses)**2)/ 6))
plt.text(4.5,90, 'DFT', color='tab:blue')
plt.text(4.5,75, 'IP', color='tab:orange')
if save is True:
plt.savefig('{}/{}_stresses.png'.format(output_directory,local_directory),dpi=500, bbox_inches = "tight")
plt.show()