Source code for pibronic.plotting.plotting

""" first pass at creating plotting module """


# system imports
import json
import os
from os.path import join

# third party imports
import numpy as np
from numpy import float64 as F64
import matplotlib.pyplot as plt

# local imports
from .prepare import prepare_mpl_rc_file, load_latex_module_on_server
from .virtual import plotVirtual
from ..data import postprocessing as pp
from ..data import file_structure as fs
from ..constants import beta
from ..vibronic import vIO


[docs]def load_analytical_original(self): """ generic loading function that can be used by multiple plotting classes """ # create the list of dictionaries to hold the original analytical data self.analytical_orig_list = [{} for _ in range(len(self.FS_lst))] # load that data into each dictionary in the list for idx_FS, FS in enumerate(self.FS_lst): with open(FS.path_analytic_orig, 'r') as file: data = json.loads(file.read()) for T in self.lst_T[idx_FS]: self.analytical_orig_list[idx_FS][f"{T:.2f}"] = data[f"{T:.2f}"] return
[docs]def load_analytical_sampling(self): """ generic loading function that can be used by multiple plotting classes""" # create the list of dictionaries to hold the sampling analytical data self.analytical_rho_list = [{} for _ in range(len(self.FS_lst))] # load that data into each dictionary in the list for idx_FS, FS in enumerate(self.FS_lst): with open(FS.path_analytic_rho, 'r') as file: data = json.loads(file.read()) for T in self.lst_T[idx_FS]: self.analytical_rho_list[idx_FS][f"{T:.2f}"] = data[f"{T:.2f}"] return
[docs]def load_sos(self, basis_size=80): """ generic loading function that can be used by multiple plotting classes""" # create the list of dictionaries to hold the sum-over-states data self.sos_list = [{} for _ in range(len(self.FS_lst))] # load that data into each dictionary in the list for idx_FS, FS in enumerate(self.FS_lst): path = FS.template_sos_vib.format(B=basis_size) if os.path.isfile(path): with open(path, 'r') as file: data = json.loads(file.read()) for T in self.lst_T[idx_FS]: self.sos_list[idx_FS][f"{T:.2f}"] = data[f"{T:.2f}"] return
[docs]def load_trotter_coupled(self, basis_size=80): """ generic loading function that can be used by multiple plotting classes""" # create the list of dictionaries to hold the coupled trotter data self.trotter_coupled_list = [{} for _ in range(len(self.FS_lst))] # load that data into each dictionary in the list for idx_FS, FS in enumerate(self.FS_lst): # create the empty lists for T in self.lst_T[idx_FS]: # self.trotter_coupled_list[idx_FS][f"{T:.2f}"] = [] trotter_key_list = ["Z_trotter", "E_trotter", "SvN_trotter", "S2_trotter"] temp_lists = [[] for key in trotter_key_list] # this could be troublesome if the order of the list is changed # maybe if we used a pair object as the key for a dictionary? # but we want to maintain the functionality of being able to index all the beads for idx_P, P, in enumerate(self.lst_P[idx_FS]): path = FS.template_trotter_vib.format(P=P, B=basis_size) # check if path exists -> and if not then we should append a None? try: with open(path, 'r') as file: data = json.loads(file.read()) for idx, key in enumerate(trotter_key_list): val = data[f"{T:.2f}"].get(key, None) temp_lists[idx].append(val) except: # if path doesn't exist then we just us a None # which becomes a nan when converted into a numpy array of floats for idx, key in enumerate(trotter_key_list): temp_lists[idx].append(None) temp_dict = {} for idx, key in enumerate(trotter_key_list): temp_dict[key] = np.array(temp_lists[idx], dtype=F64) self.trotter_coupled_list[idx_FS][f"{T:.2f}"] = temp_dict return
# TODO - this function could be improved
[docs]def generate_tau_values(self, temperature, idx_FS): """ returns a numpy array of the same length as lst_P takes in one temperature and an array of P values""" tau_arr = np.full(len(self.lst_P[idx_FS]), fill_value=beta(temperature)) tau_arr /= self.lst_P[idx_FS] return tau_arr
[docs]class plot_Z_multiple_FS(plotVirtual): """ this is just an empty template at the moment, will be completed later"""
[docs] def generate_file_lists(self): """ x """ # we create a list of lists of parameters specific to each FileStructure object self.list_jackknife = [[] for _ in range(len(self.FS_lst))] for idx_FS, FS in enumerate(self.FS_lst): self.list_jackknife[idx_FS] = pp.retrive_jackknife_file_list(FS) self.list_jackknife[idx_FS] = pp.prune_results_using_hashes(FS, self.list_jackknife[idx_FS])
[docs] def generate_parameter_lists(self): """ x """ # lots of issues can arise from this lists of lists approach # especially if the order is implicit and the code relies on that! func = pp.extract_bead_value_from_thermo_file_path self.lst_P = [list(set(map(func, lst))) for lst in self.list_jackknife] func = pp.extract_temperature_value_from_thermo_file_path self.lst_T = [list(set(map(func, lst))) for lst in self.list_jackknife] func = pp.extract_sample_value_from_thermo_file_path self.lst_X = [list(set(map(func, lst))) for lst in self.list_jackknife] # sort them -- TODO - it would be nice if we could use map() here for lst in self.lst_P: lst.sort() for lst in self.lst_T: lst.sort() for lst in self.lst_X: lst.sort()
def __init__(self, list_of_FileStructure_objects): """ x """ super().__init__(list_of_FileStructure_objects) for idx_FS, FS in enumerate(self.FS_lst): if len(self.list_jackknife[idx_FS]) != 0: break else: raise Exception("All result lists are empty!! No Data to plot!")
[docs] def load_pimc_data(self): """ x """ # a list of numpy arrays, each one corresponds to a FS in the self.FS_lst self.arr = [[] for _ in range(len(self.FS_lst))] # we will store the specific dims of each array associated with a FS dims = [[] for _ in range(len(self.FS_lst))] # the data structure of a single entry of the numpy arrays in the list self.arr dicttype = np.dtype({ 'names': ["Z", "Z error", "E", "E error", "Cv", "Cv error", "jk_E", "jk_E error", "jk_Cv", "jk_Cv error"], 'formats': [F64, F64, F64, F64, F64, F64, F64, F64, F64, F64], }) # create the array where we store the data for idx_FS, FS in enumerate(self.FS_lst): dims[idx_FS] = (len(self.lst_P[idx_FS]), len(self.lst_T[idx_FS]), len(self.lst_X[idx_FS]) ) self.arr[idx_FS] = np.full(dims[idx_FS], np.nan, dtype=dicttype) for idx_FS, FS in enumerate(self.FS_lst): for path in self.list_jackknife[idx_FS]: P = pp.extract_bead_value_from_thermo_file_path(path) T = pp.extract_temperature_value_from_thermo_file_path(path) X = pp.extract_sample_value_from_thermo_file_path(path) if P not in self.lst_P[idx_FS]: continue idx_P = self.lst_P[idx_FS].index(P) idx_T = self.lst_T[idx_FS].index(T) idx_X = self.lst_X[idx_FS].index(X) # bit of a naive way to load the data? # should possibly do some validation? with open(path, 'r') as file: data = json.loads(file.read()) for key in data: if key != "hash_vib" and key != "hash_rho": self.arr[idx_FS][idx_P, idx_T, idx_X][key] = data[key] return
[docs] def load_data(self): """ x """ self.load_pimc_data() return
[docs]class plot_original_Z_test(plotVirtual): """ plotting pimc results against analytical results of original model when we only provide 1 FS object"""
[docs] def generate_file_lists(self): """ create a list of lists of parameters specific to each FileStructure object """ self.list_jackknife = [[]] for FS in self.FS_lst: self.list_jackknife[0] = pp.retrive_jackknife_file_list(FS) self.list_jackknife[0] = pp.prune_results_using_hashes(FS, self.list_jackknife[0]) return
[docs] def generate_parameter_lists(self): """ x """ # lots of issues can arise from this lists of lists approach # especially if the order is implicit and the code relies on that! func = pp.extract_bead_value_from_thermo_file_path self.lst_P = [list(set(map(func, self.list_jackknife[0])))] func = pp.extract_temperature_value_from_thermo_file_path self.lst_T = [list(set(map(func, self.list_jackknife[0])))] func = pp.extract_sample_value_from_thermo_file_path self.lst_X = [list(set(map(func, self.list_jackknife[0])))] # sort them for lst in self.lst_P: lst.sort() for lst in self.lst_T: lst.sort() for lst in self.lst_X: lst.sort() return
def __init__(self, list_of_FileStructure_objects): """ x """ assert isinstance(list_of_FileStructure_objects, fs.FileStructure), " this subclass only takes 1 FS" super().__init__(list_of_FileStructure_objects)
[docs] def load_pimc_data(self): """ x """ # create the array where we store the data dims = (len(self.lst_P[0]), len(self.lst_T[0]), len(self.lst_X[0])) dicttype = np.dtype({ 'names': ["Z", "Z error", "E", "E error", "Cv", "Cv error", "jk_E", "jk_E error", "jk_Cv", "jk_Cv error"], 'formats': [F64, F64, F64, F64, F64, F64, F64, F64, F64, F64], }) self.arr = np.full(dims, np.nan, dtype=dicttype) for path in self.list_jackknife[0]: P = pp.extract_bead_value_from_thermo_file_path(path) T = pp.extract_temperature_value_from_thermo_file_path(path) X = pp.extract_sample_value_from_thermo_file_path(path) idx_P = self.lst_P[0].index(P) idx_T = self.lst_T[0].index(T) idx_X = self.lst_X[0].index(X) # bit of a naive way to load the data? # should possibly do some validation? with open(path, 'r') as file: data = json.loads(file.read()) for key in data: if key != "hash_vib" and key != "hash_rho": self.arr[idx_P, idx_T, idx_X][key] = data[key]
[docs] def load_analytical_data(self): """ x """ # assuming we only have one FS in the list FS = self.FS_lst[0] self.analytical_orig_dict = {} self.analytical_rho_dict = {} with open(FS.path_analytic_orig, 'r') as file: data = json.loads(file.read()) for T in self.lst_T[0]: self.analytical_orig_dict[f"{T:.2f}"] = data[f"{T:.2f}"] with open(FS.path_analytic_rho, 'r') as file: data = json.loads(file.read()) for T in self.lst_T[0]: self.analytical_rho_dict[f"{T:.2f}"] = data[f"{T:.2f}"] return
[docs] def prepare_data(self): # we need to modify Z using the analytical rho (Z_rho) for T in self.lst_T[0]: Z_rho = self.analytical_rho_dict[f"{T:.2f}"]["Z_sampling"] idx_T = self.lst_T[0].index(T) self.arr[:, idx_T, :]["Z"] *= Z_rho self.arr[:, idx_T, :]["Z error"] *= Z_rho # we might also want to modify it to print the percent error self.percent_error = True if self.percent_error: for T in self.lst_T[0]: idx_T = self.lst_T[0].index(T) self.arr[:, idx_T, :]["Z"] -= self.analytical_orig_dict[f"{T:.2f}"]["Z_coupled"] self.arr[:, idx_T, :]["Z"] *= 100.0 self.arr[:, idx_T, :]["Z"] /= self.analytical_orig_dict[f"{T:.2f}"]["Z_coupled"] self.arr[:, idx_T, :]["Z error"] *= 100.0 self.arr[:, idx_T, :]["Z error"] /= self.analytical_orig_dict[f"{T:.2f}"]["Z_coupled"] return
[docs] def load_data(self): """ x """ self.load_pimc_data() self.load_analytical_data() self.prepare_data() return
# TODO - this could be improved
[docs] def generate_tau_values(self, temperature): """ returns a numpy array of the same length as lst_P takes in one temperature and an array of P values""" tau_arr = np.full(len(self.lst_P[0]), fill_value=beta(temperature)) tau_arr /= self.lst_P[0] return tau_arr
[docs] def plot_Z(self): fig, ax = plt.subplots(1, 1) # HACKY - this won't work anymore with the nested lists if len(self.lst_T[0]) is 1: ax = [ax, ] # print Z values for T in self.lst_T[0]: idx_T = self.lst_T[0].index(T) tau_values = self.generate_tau_values(T) for X in self.lst_X[0]: idx_X = self.lst_X[0].index(X) x = tau_values.view() y = self.arr[:, idx_T, idx_X]["Z"].view() yerr = self.arr[:, idx_T, idx_X]["Z error"].view() label = "Z (T={:.2f}K) (X={:.1E})".format(T, X) ax[idx_T].errorbar(x, y, xerr=None, yerr=yerr, marker='o', label=label) ax[idx_T].legend() true_answer = self.analytical_orig_dict[f"{T:.2f}"]["Z_coupled"] if self.percent_error: true_answer = 0.0 ax[idx_T].axhline(y=true_answer, linewidth=2, color='r', label='Analytically derived Z from original model' ) # x_label = r'$\tau\,(\text{eV}^{-1})$' ax[0].set_xlabel(x_label) ax[0].set_xscale('log') # plt.minorticks_off() # turns off minor ticks that are added with a log plot # points BOTH ticks inward ax[0].tick_params(which='both', direction='in', pad=2) # Remove the plot frame lines. They are unnecessary chart junk. ax[0].spines["top"].set_visible(False) ax[0].spines["right"].set_visible(False) y_label = r"$\frac{Z_g}{Z_\varrho}$" if self.percent_error: y_label = r"\% Difference $\frac{Z_g}{Z_\varrho}$" ax[0].set_ylabel(y_label) # plot title A, N = vIO.extract_dimensions_of_diagonal_model(self.FS_lst[0]) plot_title = r'$\tau$ convergence' plot_title += f"\nData Set {self.FS_lst[0].id_data:d}" plot_title += f"\n{A:d} surfaces {N:d} normal modes" fig.suptitle(plot_title) fig.set_size_inches(10, 10) filename = "Z_orig_D{:d}_R{:d}.pdf".format(self.FS_lst[0].id_data, self.FS_lst[0].id_rho) path_out = join(self.FS_lst[0].path_rho_plots, filename) fig.savefig(path_out, transparent=True, bbox_inches='tight', pad_inches=0.2) plt.close(fig) return
[docs] def plot(self): """ x """ # necessary for now prepare_mpl_rc_file(pretty_but_slow=True) load_latex_module_on_server() self.plot_Z() return
# should we rename this?
[docs]class plot_original_Z_vs_diagonal_test(plot_Z_multiple_FS): """ plotting pimc results drawn from the original_coupled_model.json vs the pimc results drawn from the diagonal of the coupled_model.json vs analytical results of the original model when we provide 2 FS objects""" def __init__(self, list_of_FileStructure_objects): """ x """ assert len(list_of_FileStructure_objects) is 2, " this subclass takes exactly 2 FS" super().__init__(list_of_FileStructure_objects)
[docs] def load_analytical_data(self): """ x """ load_analytical_original(self) load_analytical_sampling(self)
[docs] def prepare_data(self): # we need to modify Z using the analytical rho (Z_rho) for idx_FS, FS in enumerate(self.FS_lst): for T in self.lst_T[idx_FS]: Z_rho = self.analytical_rho_list[idx_FS][f"{T:.2f}"]["Z_sampling"] idx_T = self.lst_T[idx_FS].index(T) self.arr[idx_FS][:, idx_T, :]["Z"] *= Z_rho self.arr[idx_FS][:, idx_T, :]["Z error"] *= Z_rho # we might also want to modify it to print the percent error self.percent_error = True if not self.percent_error: return for idx_FS, FS in enumerate(self.FS_lst): for X in self.lst_X[idx_FS]: # don't plot more than the lowest # of samples idx_X = self.lst_X[idx_FS].index(X) for T in self.lst_T[idx_FS]: idx_T = self.lst_T[idx_FS].index(T) view = self.arr[idx_FS][:, idx_T, idx_X].view() lytical = self.analytical_orig_list[idx_FS][f"{T:.2f}"]["Z_coupled"] view["Z"] -= lytical view["Z"] *= 100.0 view["Z"] /= lytical view["Z error"] *= 100.0 view["Z error"] /= lytical return
[docs] def load_data(self): """ x """ self.load_pimc_data() self.load_analytical_data() self.prepare_data() return
# TODO - this could be improved
[docs] def generate_tau_values(self, temperature, idx_FS): """ returns a numpy array of the same length as lst_P takes in one temperature and an array of P values""" tau_arr = np.full(len(self.lst_P[idx_FS]), fill_value=beta(temperature)) tau_arr /= self.lst_P[idx_FS] return tau_arr
[docs] def plot_Z(self): fig, ax = plt.subplots(1, 1) if not isinstance(ax, list): ax = [ax, ] labels = {0: "Z (id\_rho={:d}) (X={:.1E}) diagonal of transformed matrix ", 1: "Z (id\_rho={:d}) (X={:.1E}) original coupled model ", 2: "Z (id\_rho={:d}) (X={:.1E}) iterative model ", 3: "Z (id\_rho={:d}) (X={:.1E}) wrong re-weighted iterative model", 4: "Z (id\_rho={:d}) (X={:.1E}) correct re-weighted iterative model", } # print Z values for idx_FS, FS in enumerate(self.FS_lst): for T in self.lst_T[idx_FS]: idx_T = self.lst_T[idx_FS].index(T) tau_values = self.generate_tau_values(T, idx_FS) # for X in self.lst_X[idx_FS]: # don't plot more than the lowest # of samples X = self.lst_X[idx_FS][-1] idx_X = self.lst_X[idx_FS].index(X) x = tau_values.view() y = self.arr[idx_FS][:, idx_T, idx_X]["Z"].view() yerr = self.arr[idx_FS][:, idx_T, idx_X]["Z error"].view() label = labels[FS.id_rho].format(FS.id_rho, X) ax[idx_T].errorbar(x, y, xerr=None, yerr=yerr, marker='o' if idx_FS == 0 else 'x', markerfacecolor="None", label=label) ax[idx_T].legend() true_answer = self.analytical_orig_list[idx_FS][f"{T:.2f}"]["Z_coupled"] if self.percent_error: true_answer = 0.0 ax[idx_T].axhline(y=true_answer, linewidth=2, color='r', label='Analytically derived Z from original model' ) # Add an inset to the plot! if self.FS_lst[0].id_data >= 10: from mpl_toolkits.axes_grid1.inset_locator import mark_inset from mpl_toolkits.axes_grid1.inset_locator import InsetPosition # Build and manually place the inset (for the rho_1 case ) # ax[0].xaxis.set_minor_formatter(LogFormatterSciNotation(minor_thresholds=(11, 10))) ax_ins = fig.add_axes([0, 0, 1, 1], label='inset 1') ip = InsetPosition(ax[0], [0.1, 0.3, 0.5, 0.6]) # [%left, %up, %width, %height] ax_ins.set_axes_locator(ip) # Connect the inset to its respective region mark_inset(ax[0], ax_ins, loc1=3, loc2=4, fc="none", ec="0.5") # window dressing? # ax_ins.set_xscale('log') ax_ins.get_xaxis().set_visible(False) ax_ins.tick_params(which='both', direction='in', pad=4) # ax_ins.spines['top'].set_visible(False) # HACK CONSTANTS # F_index = -1 idx_T = 0 idx_X = -1 T = 300.00 # dataView = self.arr[F_index, R_index, T_index, 0, :].view() slice_insert = np.s_[-1:-2:-1] # if np.any(np.isnan(dataView)): # first_Finite = np.where(np.isfinite(self.arr[F_index, R_index, T_index, 0, :]))[0][-1] # slice_insert = np.s_[first_Finite:first_Finite-10:-1] # -------------------------------------------------------------------------------- # Plot the first FS idx_FS = 0 tau_values = self.generate_tau_values(T, idx_FS) x = tau_values[slice_insert].view() y = self.arr[idx_FS][slice_insert, idx_T, idx_X]["Z"].view() yerr = self.arr[idx_FS][slice_insert, idx_T, idx_X]["Z error"].view() label = labels[idx_FS].format(self.FS_lst[idx_FS].id_rho, self.lst_X[idx_FS][0]) ax_ins.errorbar(x, y, xerr=None, yerr=yerr, marker='o' if idx_FS == 0 else 'x', markerfacecolor="None", label=label) # -------------------------------------------------------------------------------- # Plot the second FS idx_FS = 1 tau_values = self.generate_tau_values(T, idx_FS) x = tau_values[slice_insert].view() y = self.arr[idx_FS][slice_insert, idx_T, idx_X]["Z"].view() yerr = self.arr[idx_FS][slice_insert, idx_T, idx_X]["Z error"].view() label = labels[idx_FS].format(self.FS_lst[idx_FS].id_rho, self.lst_X[idx_FS][0]) ax_ins.errorbar(x, y, xerr=None, yerr=yerr, marker='o' if idx_FS == 0 else 'x', markerfacecolor="None", label=label) # -------------------------------------------------------------------------------- # REFERENCE / EXACT ANSWER true_answer = self.analytical_orig_list[0][f"{T:.2f}"]["Z_coupled"] if self.percent_error: true_answer = 0.0 ax_ins.axhline(y=true_answer, linewidth=2, color='r', label='Analytically derived Z from original model' ) # -------------------------------------------------------------------------------- # x_label = r'$\tau\,(\text{eV}^{-1})$' ax[0].set_xlabel(x_label) ax[0].set_xscale('log') # plt.minorticks_off() # turns off minor ticks that are added with a log plot # points BOTH ticks inward ax[0].tick_params(which='both', direction='in', pad=2) # Remove the plot frame lines. They are unnecessary chart junk. ax[0].spines["top"].set_visible(False) ax[0].spines["right"].set_visible(False) # y_label = r"$\frac{Z_g}{Z_\varrho}$" y_label = r"$Z_H$" if self.percent_error: # y_label = r"\% Difference $\frac{Z_g}{Z_\varrho}$" y_label = r"\% Difference $Z_H$" ax[0].set_ylabel(y_label) # ax[0].set_yscale('log') # plot title A, N = vIO.extract_dimensions_of_diagonal_model(self.FS_lst[0]) plot_title = r'$\tau$ convergence' plot_title += f"\nData Set {self.FS_lst[0].id_data:d}" plot_title += f"\n{A:d} surfaces {N:d} normal modes" fig.suptitle(plot_title) fig.set_size_inches(10, 10) filename = "Z_orig_D{:d}_R{:d}_R{:d}.pdf".format(self.FS_lst[0].id_data, self.FS_lst[0].id_rho, self.FS_lst[1].id_rho) path_out = join(self.FS_lst[0].path_vib_plots, filename) fig.savefig(path_out, transparent=True, bbox_inches='tight', pad_inches=0.2) plt.close(fig) return
[docs] def plot(self): """ x """ # necessary for now prepare_mpl_rc_file(pretty_but_slow=True) load_latex_module_on_server() self.plot_Z() return
[docs]class plot_sos_Z_vs_rho_n(plot_Z_multiple_FS): """ plotting pimc results drawn from the coupled_model.json vs the pimc results drawn from a rho vs sos results of the coupled model when we provide 2 FS objects""" def __init__(self, list_of_FileStructure_objects): """ x """ assert len(list_of_FileStructure_objects) is 2, " this subclass takes exactly 2 FS" super().__init__(list_of_FileStructure_objects)
[docs] def prepare_data(self): # we need to modify Z using the analytical rho (Z_rho) for idx_FS, FS in enumerate(self.FS_lst): for T in self.lst_T[idx_FS]: Z_rho = self.analytical_rho_list[idx_FS][f"{T:.2f}"]["Z_sampling"] idx_T = self.lst_T[idx_FS].index(T) self.arr[idx_FS][:, idx_T, :]["Z"] *= Z_rho self.arr[idx_FS][:, idx_T, :]["Z error"] *= Z_rho # we might also want to modify it to print the percent error self.percent_error = True if not self.percent_error: return for idx_FS, FS in enumerate(self.FS_lst): for X in self.lst_X[idx_FS]: # don't plot more than the lowest # of samples idx_X = self.lst_X[idx_FS].index(X) for T in self.lst_T[idx_FS]: idx_T = self.lst_T[idx_FS].index(T) view = self.arr[idx_FS][:, idx_T, idx_X].view() sos = self.sos_params[f"{T:.2f}"]["Z_coupled"] view["Z"] -= sos view["Z"] *= 100.0 view["Z"] /= sos view["Z error"] *= 100.0 view["Z error"] /= sos return
[docs] def load_data(self): """ x """ self.load_pimc_data() load_sos(self) load_analytical_sampling(self) self.prepare_data()
[docs] def plot_Z(self): fig, ax = plt.subplots(1, 1) if not isinstance(ax, list): ax = [ax, ] labels = {0: "Z (id\_rho={:d}) (X={:.1E}) diagonal of transformed matrix ", 1: "Z (id\_rho={:d}) (X={:.1E}) alternative sampling distribution from paper", 2: "Z (id\_rho={:d}) (X={:.1E}) 2nd alternative sampling distribution", 10: "Z (id\_rho={:d}) (X={:.1E}) iterative model", 11: "Z (id\_rho={:d}) (X={:.1E}) correct re-weighted iterative model", 12: "Z (id\_rho={:d}) (X={:.1E}) mangled stuff", } # print Z values for idx_FS, FS in enumerate(self.FS_lst): for T in self.lst_T[idx_FS]: idx_T = self.lst_T[idx_FS].index(T) tau_values = generate_tau_values(self, T, idx_FS) # for X in self.lst_X[idx_FS]: # don't plot more than the lowest # of samples # X = self.lst_X[idx_FS][0] X = int(1E4) idx_X = self.lst_X[idx_FS].index(X) x = tau_values.view() y = self.arr[idx_FS][:, idx_T, idx_X]["Z"].view() yerr = self.arr[idx_FS][:, idx_T, idx_X]["Z error"].view() label = labels[FS.id_rho].format(FS.id_rho, X) ax[idx_T].errorbar(x, y, xerr=None, yerr=yerr, marker='o' if idx_FS == 0 else 'x', markerfacecolor="None", label=label) ax[idx_T].legend() true_answer = self.sos_params[f"{T:.2f}"]["Z_coupled"] if self.percent_error: true_answer = 0.0 ax[idx_T].axhline(y=true_answer, linewidth=2, color='r', label='SOS derived Z from coupled model' ) # Add an inset to the plot! if self.FS_lst[0].id_data >= 100: print("index A") from mpl_toolkits.axes_grid1.inset_locator import mark_inset from mpl_toolkits.axes_grid1.inset_locator import InsetPosition # Build and manually place the inset (for the rho_1 case ) # ax[0].xaxis.set_minor_formatter(LogFormatterSciNotation(minor_thresholds=(11, 10))) ax_ins = fig.add_axes([0, 0, 1, 1], label='inset 1') ip = InsetPosition(ax[0], [0.1, 0.3, 0.5, 0.6]) # [%left, %up, %width, %height] ax_ins.set_axes_locator(ip) # Connect the inset to its respective region mark_inset(ax[0], ax_ins, loc1=3, loc2=4, fc="none", ec="0.5") # window dressing? # ax_ins.set_xscale('log') ax_ins.get_xaxis().set_visible(False) ax_ins.tick_params(which='both', direction='in', pad=4) # ax_ins.spines['top'].set_visible(False) # HACK CONSTANTS # F_index = -1 idx_T = 0 # idx_X = 0 T = 300.00 # dataView = self.arr[F_index, R_index, T_index, 0, :].view() slice_insert = np.s_[-1:-2:-1] # if np.any(np.isnan(dataView)): # first_Finite = np.where(np.isfinite(self.arr[F_index, R_index, T_index, 0, :]))[0][-1] # slice_insert = np.s_[first_Finite:first_Finite-10:-1] # -------------------------------------------------------------------------------- # Plot the first FS print("index B") idx_FS = 0 X = int(1E4) idx_X = self.lst_X[idx_FS].index(X) tau_values = self.generate_tau_values(T, idx_FS) x = tau_values[slice_insert].view() y = self.arr[idx_FS][slice_insert, idx_T, idx_X]["Z"].view() yerr = self.arr[idx_FS][slice_insert, idx_T, idx_X]["Z error"].view() label = labels[idx_FS].format(self.FS_lst[idx_FS].id_rho, self.lst_X[idx_FS][idx_X]) ax_ins.errorbar(x, y, xerr=None, yerr=yerr, marker='o' if idx_FS == 0 else 'x', markerfacecolor="None", label=label) # -------------------------------------------------------------------------------- # Plot the second FS print(self.arr[idx_FS].shape) idx_FS = 1 X = int(1E4) idx_X = self.lst_X[idx_FS].index(X) tau_values = self.generate_tau_values(T, idx_FS) print(self.lst_P[idx_FS]) print("tau", tau_values) x = tau_values[slice_insert].view() y = self.arr[idx_FS][slice_insert, idx_T, idx_X]["Z"].view() yerr = self.arr[idx_FS][slice_insert, idx_T, idx_X]["Z error"].view() label = labels[idx_FS].format(self.FS_lst[idx_FS].id_rho, self.lst_X[idx_FS][idx_X]) ax_ins.errorbar(x, y, xerr=None, yerr=yerr, marker='o' if idx_FS == 0 else 'x', markerfacecolor="None", label=label) # -------------------------------------------------------------------------------- # REFERENCE / EXACT ANSWER true_answer = self.sos_params[f"{T:.2f}"]["Z_coupled"] if self.percent_error: true_answer = 0.0 ax_ins.axhline(y=true_answer, linewidth=2, color='r', label='SOS derived Z from coupled model' ) # -------------------------------------------------------------------------------- # x_label = r'$\tau\,(\text{eV}^{-1})$' ax[0].set_xlabel(x_label) ax[0].set_xscale('log') # plt.minorticks_off() # turns off minor ticks that are added with a log plot # points BOTH ticks inward ax[0].tick_params(which='both', direction='in', pad=2) # Remove the plot frame lines. They are unnecessary chart junk. ax[0].spines["top"].set_visible(False) ax[0].spines["right"].set_visible(False) # y_label = r"$\frac{Z_g}{Z_\varrho}$" y_label = r"$Z_H$" if self.percent_error: # y_label = r"\% Difference $\frac{Z_g}{Z_\varrho}$" y_label = r"\% Difference $Z_H$" ax[0].set_ylabel(y_label) # ax[0].set_yscale('log') # plot title A, N = vIO.extract_dimensions_of_diagonal_model(self.FS_lst[0]) plot_title = r'$\tau$ convergence' plot_title += f"\nData Set {self.FS_lst[0].id_data:d}" plot_title += f"\n{A:d} surfaces {N:d} normal modes" fig.suptitle(plot_title) fig.set_size_inches(10, 10) filename = "Z_sos_D{:d}_R{:d}_R{:d}.pdf".format(self.FS_lst[0].id_data, self.FS_lst[0].id_rho, self.FS_lst[1].id_rho) path_out = join(self.FS_lst[0].path_vib_plots, filename) fig.savefig(path_out, transparent=True, bbox_inches='tight', pad_inches=0.2) plt.close(fig) return
[docs] def plot(self): """ x """ # necessary for now prepare_mpl_rc_file(pretty_but_slow=True) load_latex_module_on_server() self.plot_Z() return
[docs]class plot_rectangle(plot_Z_multiple_FS): def __init__(self, list_of_FileStructure_objects): """ x """ assert len(list_of_FileStructure_objects) > 1, " this subclass takes 2 or more FS" super().__init__(list_of_FileStructure_objects)
[docs] def prepare_data(self): """ x """ # we need to modify Z using the analytical rho (Z_rho) for idx_FS, FS in enumerate(self.FS_lst): for idx_T, T in enumerate(self.lst_T[idx_FS]): Z_rho = self.analytical_rho_list[idx_FS][f"{T:.2f}"]["Z_sampling"].view() self.arr[idx_FS][:, idx_T, :]["Z"] *= Z_rho self.arr[idx_FS][:, idx_T, :]["Z error"] *= Z_rho # we might also want to modify it to print the percent error self.percent_error = True if not self.percent_error: return for idx_FS, FS in enumerate(self.FS_lst): for X in self.lst_X[idx_FS]: # don't plot more than the lowest # of samples idx_X = self.lst_X[idx_FS].index(X) for T in self.lst_T[idx_FS]: idx_T = self.lst_T[idx_FS].index(T) sos = self.sos_list[idx_FS][f"{T:.2f}"] view = self.arr[idx_FS][:, idx_T, idx_X].view() view["Z"] -= sos view["Z"] *= 100.0 view["Z"] /= sos view["Z error"] *= 100.0 view["Z error"] /= sos # this isn't exactly what we want to do -- should change trotter = self.trotter_coupled_list[idx_FS][:][f"{T:.2f}"] trotter -= sos trotter *= 100.0 trotter /= sos # set the sos to zero since we are doing the percent option sos[idx_FS][f"{T:.2f}"] = 0.0 return
[docs] def load_data(self): """ x """ self.load_pimc_data() load_sos(self) load_trotter_coupled(self) load_analytical_sampling(self) self.prepare_data() return
# TODO - this could be improved
[docs] def generate_tau_values(self, temperature, idx_FS): """ returns a numpy array of the same length as lst_P takes in one temperature and an array of P values""" tau_arr = np.full(len(self.lst_P[idx_FS]), fill_value=beta(temperature)) tau_arr /= self.lst_P[idx_FS] return tau_arr
[docs] def plot_Z(self): # to be done later this week return
[docs] def plot(self): """ x """ # necessary for now prepare_mpl_rc_file(pretty_but_slow=True) load_latex_module_on_server() self.plot_Z() return
[docs]class plot_Z_test(plotVirtual): """ plotting when we only provide 1 FS object"""
[docs] def generate_file_lists(self): """ create a list of lists of parameters specific to each FileStructure object """ self.list_jackknife = [[]] for FS in self.FS_lst: self.list_jackknife[0] = pp.retrive_jackknife_file_list(FS) self.list_jackknife[0] = pp.prune_results_using_hashes(FS, self.list_jackknife[0]) return
[docs] def generate_parameter_lists(self): """ x """ # lots of issues can arise from this lists of lists approach # especially if the order is implicit and the code relies on that! func = pp.extract_bead_value_from_thermo_file_path self.lst_P = [list(set(map(func, self.list_jackknife[0])))] func = pp.extract_temperature_value_from_thermo_file_path self.lst_T = [list(set(map(func, self.list_jackknife[0])))] func = pp.extract_sample_value_from_thermo_file_path self.lst_X = [list(set(map(func, self.list_jackknife[0])))] # sort them for lst in self.lst_P: lst.sort() for lst in self.lst_T: lst.sort() for lst in self.lst_X: lst.sort() return
def __init__(self, list_of_FileStructure_objects): """ x """ assert isinstance(list_of_FileStructure_objects, fs.FileStructure), " this subclass only takes 1 FS" super().__init__(list_of_FileStructure_objects)
[docs] def load_data(self): """ x """ # create the array where we store the data dims = (len(self.lst_P[0]), len(self.lst_T[0]), len(self.lst_X[0])) dicttype = np.dtype({ 'names': ["Z", "Z error", "E", "E error", "Cv", "Cv error", "jk_E", "jk_E error", "jk_Cv", "jk_Cv error"], 'formats': [F64, F64, F64, F64, F64, F64, F64, F64, F64, F64], }) self.arr = np.full(dims, np.nan, dtype=dicttype) for path in self.list_jackknife[0]: P = pp.extract_bead_value_from_thermo_file_path(path) T = pp.extract_temperature_value_from_thermo_file_path(path) X = pp.extract_sample_value_from_thermo_file_path(path) idx_P = self.lst_P[0].index(P) idx_T = self.lst_T[0].index(T) idx_X = self.lst_X[0].index(X) # bit of a naive way to load the data? # should possibly do some validation? with open(path, 'r') as file: data = json.loads(file.read()) for key in data: if key != "hash_vib" and key != "hash_rho": self.arr[idx_P, idx_T, idx_X][key] = data[key] return
[docs] def plot_Z(self): fig, ax = plt.subplots(1, 1) # HACKY - this won't work anymore with the nested lists if len(self.lst_T[0]) is 1: ax = [ax, ] idx_FS = 0 # print Z values for T in self.lst_T[idx_FS]: idx_T = self.lst_T[idx_FS].index(T) tau_values = generate_tau_values(self, T, idx_FS) for X in self.lst_X[idx_FS]: idx_X = self.lst_X[idx_FS].index(X) x = tau_values.view() y = self.arr[:, idx_T, idx_X]["Z"].view() yerr = self.arr[:, idx_T, idx_X]["Z error"].view() label = "Z (T={:.2f}K) (X={:.1E})".format(T, X) ax[idx_T].errorbar(x, y, xerr=None, yerr=yerr, marker='o', label=label) ax[idx_T].legend() fig.suptitle("Z MC") fig.set_size_inches(10, 10) filename = "Z_D{:d}_R{:d}.pdf".format(self.FS_lst[idx_FS].id_data, self.FS_lst[idx_FS].id_rho) path_out = join(self.FS_lst[idx_FS].path_rho_plots, filename) fig.savefig(path_out, transparent=True, bbox_inches='tight', pad_inches=0.2) plt.close(fig) return
[docs] def plot_E(self): fig, ax = plt.subplots(1, 1) # HACKY - this won't work anymore with the nested lists if len(self.lst_T[0]) is 1: ax = [ax, ] idx_FS = 0 # print E values for T in self.lst_T[idx_FS]: idx_T = self.lst_T[idx_FS].index(T) tau_values = generate_tau_values(self, T, idx_FS) for X in self.lst_X[idx_FS]: idx_X = self.lst_X[idx_FS].index(X) x = tau_values.view() y = self.arr[:, idx_T, idx_X]["E"].view() yerr = self.arr[:, idx_T, idx_X]["E error"].view() label = "E (T={:.2f}K) (X={:.1E})".format(T, X) ax[idx_T].errorbar(x, y, xerr=None, yerr=yerr, marker='o', label=label) ax[idx_T].legend() fig.suptitle("Energy") fig.set_size_inches(10, 10) filename = "E_D{:d}_R{:d}.pdf".format(self.FS_lst[idx_FS].id_data, self.FS_lst[idx_FS].id_rho) path_out = join(self.FS_lst[idx_FS].path_rho_plots, filename) fig.savefig(path_out, transparent=True, bbox_inches='tight', pad_inches=0.2) plt.close(fig) return
[docs] def plot_Cv(self): fig, ax = plt.subplots(1, 1) # HACKY - this won't work anymore with the nested lists if len(self.lst_T[0]) is 1: ax = [ax, ] idx_FS = 0 # print Cv values for T in self.lst_T[idx_FS]: idx_T = self.lst_T[idx_FS].index(T) tau_values = self.generate_tau_values(T) for X in self.lst_X[idx_FS]: idx_X = self.lst_X[idx_FS].index(X) x = tau_values.view() y = self.arr[:, idx_T, idx_X]["Cv"].view() yerr = self.arr[:, idx_T, idx_X]["Cv error"].view() label = "Cv (T={:.2f}K) (X={:.1E})".format(T, X) ax[idx_T].errorbar(x, y, xerr=None, yerr=yerr, marker='o', label=label) ax[idx_T].legend() fig.suptitle("Cv") fig.set_size_inches(10, 10) filename = "Cv_D{:d}_R{:d}.pdf".format(self.FS_lst[idx_FS].id_data, self.FS_lst[idx_FS].id_rho) path_out = join(self.FS_lst[idx_FS].path_rho_plots, filename) fig.savefig(path_out, transparent=True, bbox_inches='tight', pad_inches=0.2) plt.close(fig) return
[docs] def plot(self): """ x """ # necessary for now prepare_mpl_rc_file() load_latex_module_on_server() self.plot_Z() self.plot_E() self.plot_Cv() return
if (__name__ == "__main__"): pass