From 436423ff58974ebc77390576bda75b8ffbc4e23b Mon Sep 17 00:00:00 2001 From: raulf2012 Date: Sun, 14 Jul 2019 11:16:04 -0700 Subject: [PATCH 01/16] Refactoring oxr classes --- orr_reaction/orr_fed_plot.py | 1 + oxr_reaction/__init__.py | 0 oxr_reaction/adsorbate_scaling.py | 339 ++++ oxr_reaction/oxr_methods.py | 550 ++++++ .../oxr_plot_2d_volcano.py | 561 ++++++ .../oxr_plotting_classes/oxr_plot_fed.py | 847 +++++++++ .../oxr_plotting_classes/oxr_plot_scaling.py | 711 ++++++++ .../oxr_plotting_classes/oxr_plot_volcano.py | 607 +++++++ oxr_reaction/oxr_rxn.py | 1522 +++++++++++++++++ oxr_reaction/oxr_series.py | 631 +++++++ 10 files changed, 5769 insertions(+) create mode 100644 oxr_reaction/__init__.py create mode 100644 oxr_reaction/adsorbate_scaling.py create mode 100644 oxr_reaction/oxr_methods.py create mode 100644 oxr_reaction/oxr_plotting_classes/oxr_plot_2d_volcano.py create mode 100644 oxr_reaction/oxr_plotting_classes/oxr_plot_fed.py create mode 100644 oxr_reaction/oxr_plotting_classes/oxr_plot_scaling.py create mode 100644 oxr_reaction/oxr_plotting_classes/oxr_plot_volcano.py create mode 100644 oxr_reaction/oxr_rxn.py create mode 100644 oxr_reaction/oxr_series.py diff --git a/orr_reaction/orr_fed_plot.py b/orr_reaction/orr_fed_plot.py index 2c37cc3..88873fc 100644 --- a/orr_reaction/orr_fed_plot.py +++ b/orr_reaction/orr_fed_plot.py @@ -2203,6 +2203,7 @@ class Free_Energy_Plot(): Development Notes: Take the FED methods out of the ORR_Free_E_Plot class and into this one """ + #| - Free_Energy_Plot ***************************************************** def __init__(self, diff --git a/oxr_reaction/__init__.py b/oxr_reaction/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/oxr_reaction/adsorbate_scaling.py b/oxr_reaction/adsorbate_scaling.py new file mode 100644 index 0000000..072e1ef --- /dev/null +++ b/oxr_reaction/adsorbate_scaling.py @@ -0,0 +1,339 @@ +#!/usr/bin/env python + +"""ORR/OER adsorbate energy scaling class and methods. + +Author: Raul A. Flores +""" + + +#| - IMPORT MODULES +# import numpy as np +# +# import pandas as pd +# pd.options.mode.chained_assignment = None +# +# from sklearn.linear_model import LinearRegression +# +# # import plotly.plotly as py +# import plotly.graph_objs as go +# +# +# from orr_reaction.orr_series import ORR_Free_E_Series +#__| + + +class Adsorbate_Scaling: + """ORR/OER adsorbates' dG/E of adsorption scaling. + + Development Notes: + """ + + #| - Adsorbate_Scaling **************************************************** + + def __init__(self, + tmp=42 + ): + """ + """ + #| - __init__ + self.tmp = tmp + + #__| + + def tmp_meth(self, + ): + """ + """ + #| - tmp + tmp = 42 + return(tmp) + #__| + + #__| ********************************************************************** + + +def get_g_ooh(m_ooh, b_ooh, g_oh): + """ + """ + #| - get_g_ooh + g_ooh = m_ooh * g_oh + b_ooh + return(g_ooh) + #__| + +def get_g_o(m_o, b_o, g_oh): + """ + """ + #| - get_g_o + g_o = m_o * g_oh + b_o + return(g_o) + #__| + +def get_g_oh(m_oh, b_oh, g_oh): + """ + """ + #| - get_g_oh + g_oh = m_oh * g_oh + b_oh + return(g_oh) + #__| + +def lim_U_i( + g_oh=None, + g_o_minus_g_oh=None, + + mech_step=None, # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' + gas_molec_dict=None, + scaling_dict=None, + rxn_direction="forward", + ): + """ + Calculate the following mechanistic step of the OER/ORR: + O2 + (H+ + e-) --> *OOH + + Args: + g_oh: + gas_molec_dict: + scaling_dict: + rxn_direction: + """ + #| - lim_U_i + + #| - Checking Input Types + if g_oh is None and g_o_minus_g_oh is None: + raise ValueError("Need to provide either g_oh or g_o_minus_g_oh") + + if g_oh is not None and g_o_minus_g_oh is not None: + raise ValueError("Please don't provide both g_oh and g_o_minus_g_oh") + + assert gas_molec_dict is not None, "Please provide gas_molec_dict" + assert scaling_dict is not None, "Please provide the scaling_dict" + assert mech_step is not None, "Please provide the step to calculate" + #__| + + #| - linear fit and gas molecule data + m_ooh = scaling_dict["ooh"]["m"] + b_ooh = scaling_dict["ooh"]["b"] + + m_o = scaling_dict["o"]["m"] + b_o = scaling_dict["o"]["b"] + + m_oh = scaling_dict["oh"]["m"] + b_oh = scaling_dict["oh"]["b"] + + + g_o2 = gas_molec_dict["o2"] + g_h2 = gas_molec_dict["h2"] + g_h2o = gas_molec_dict["h2o"] + #__| + + if g_o_minus_g_oh is not None: + """ + (G_O-G_OH) = m_o*G_OH + b_o - (G_OH) + (G_O-G_OH) - b_o = G_OH*(m_o - 1) + G_OH = [(G_O-G_OH) - b_o] / (m_o - 1) + """ + g_oh = (g_o_minus_g_oh - b_o) / (m_o - 1) + + elif g_oh is not None: + g_oh = g_oh + + #| - Calculating Limiting Potential for all legs + if mech_step == "o2_to_ooh": + lim_U_out = get_g_ooh(m_ooh, b_ooh, g_oh) + \ + - g_o2 + + elif mech_step == "ooh_to_o": + lim_U_out = get_g_o(m_o, b_o, g_oh) + \ + g_h2o + \ + - get_g_ooh(m_ooh, b_ooh, g_oh) + + elif mech_step == "o_to_oh": + lim_U_out = get_g_oh(m_oh, b_oh, g_oh) + \ + - get_g_o(m_o, b_o, g_oh) + + elif mech_step == "oh_to_h2o": + lim_U_out = g_h2o + \ + - get_g_oh(m_oh, b_oh, g_oh) + else: + raise ValueError("Woops, error here (9sdfijsd9)") + #__| + + if rxn_direction == "forward": + lim_U_out = - lim_U_out + elif rxn_direction == "reverse": + lim_U_out = + lim_U_out + + return(lim_U_out) + #__| + + + + +#| - __old__ + +# def lim_U_o2_to_ooh(g_oh, +# gas_molec_dict, scaling_dict, rxn_direction="forward"): +# """ +# Calculate the following mechanistic step of the OER/ORR: +# O2 + (H+ + e-) --> *OOH +# +# Args: +# g_oh: +# gas_molec_dict: +# scaling_dict: +# rxn_direction: +# """ +# #| - lim_U_o2_to_ooh +# +# #| - linear fit and gas molecule data +# m_ooh = scaling_dict["ooh"]["m"] +# b_ooh = scaling_dict["ooh"]["b"] +# +# m_o = scaling_dict["o"]["m"] +# b_o = scaling_dict["o"]["b"] +# +# m_oh = scaling_dict["oh"]["m"] +# b_oh = scaling_dict["oh"]["b"] +# +# +# g_o2 = gas_molec_dict["o2"] +# g_h2 = gas_molec_dict["h2"] +# g_h2o = gas_molec_dict["h2o"] +# #__| +# +# +# if False: +# +# g_oh = (TMP - b_o) / (m_o - 1) +# +# lim_U_out = get_g_ooh(m_ooh, b_ooh, g_oh) - g_o2 +# +# if rxn_direction == "forward": +# lim_U_out = - lim_U_out +# elif rxn_direction == "reverse": +# lim_U_out = + lim_U_out +# +# return(lim_U_out) +# #__| +# +# def lim_U_ooh_to_o(g_oh, +# gas_molec_dict, scaling_dict, rxn_direction="forward"): +# """ +# Calculate the following mechanistic step of the OER/ORR: +# *OOH + (H+ + e-) --> *O + H2O +# +# Args: +# g_oh: +# gas_molec_dict: +# scaling_dict: +# rxn_direction: +# """ +# #| - lim_U_ooh_to_o +# +# #| - linear fit and gas molecule data +# m_ooh = scaling_dict["ooh"]["m"] +# b_ooh = scaling_dict["ooh"]["b"] +# +# m_o = scaling_dict["o"]["m"] +# b_o = scaling_dict["o"]["b"] +# +# m_oh = scaling_dict["oh"]["m"] +# b_oh = scaling_dict["oh"]["b"] +# +# +# g_o2 = gas_molec_dict["o2"] +# g_h2 = gas_molec_dict["h2"] +# g_h2o = gas_molec_dict["h2o"] +# #__| +# +# lim_U_out = get_g_o(m_o, +# b_o, g_oh) + g_h2o - get_g_ooh(m_ooh, b_ooh, g_oh) +# +# if rxn_direction == "forward": +# lim_U_out = - lim_U_out +# elif rxn_direction == "reverse": +# lim_U_out = + lim_U_out +# +# return(lim_U_out) +# #__| +# +# def lim_U_o_to_oh(g_oh, +# gas_molec_dict, scaling_dict, rxn_direction="forward"): +# """ +# Calculate the following mechanistic step of the OER/ORR: +# O* + (H+ + e-) --> *OH +# +# Args: +# g_oh: +# gas_molec_dict: +# scaling_dict: +# rxn_direction: +# """ +# #| - lim_U_o_to_oh +# +# #| - linear fit and gas molecule data +# m_ooh = scaling_dict["ooh"]["m"] +# b_ooh = scaling_dict["ooh"]["b"] +# +# m_o = scaling_dict["o"]["m"] +# b_o = scaling_dict["o"]["b"] +# +# m_oh = scaling_dict["oh"]["m"] +# b_oh = scaling_dict["oh"]["b"] +# +# +# g_o2 = gas_molec_dict["o2"] +# g_h2 = gas_molec_dict["h2"] +# g_h2o = gas_molec_dict["h2o"] +# #__| +# +# lim_U_out = get_g_oh(m_oh, b_oh, g_oh) - get_g_o(m_o, b_o, g_oh) +# +# if rxn_direction == "forward": +# lim_U_out = - lim_U_out +# elif rxn_direction == "reverse": +# lim_U_out = + lim_U_out +# +# return(lim_U_out) +# #__| +# +# def lim_U_oh_to_h2o(g_oh, +# gas_molec_dict, scaling_dict, rxn_direction="forward"): +# """ +# Calculate the following mechanistic step of the OER/ORR: +# *OH + (H+ + e-) --> H2O +# +# Args: +# g_oh: +# gas_molec_dict: +# scaling_dict: +# rxn_direction: +# """ +# #| - lim_U_oh_to_h2o +# +# #| - linear fit and gas molecule data +# m_ooh = scaling_dict["ooh"]["m"] +# b_ooh = scaling_dict["ooh"]["b"] +# +# m_o = scaling_dict["o"]["m"] +# b_o = scaling_dict["o"]["b"] +# +# m_oh = scaling_dict["oh"]["m"] +# b_oh = scaling_dict["oh"]["b"] +# +# +# g_o2 = gas_molec_dict["o2"] +# g_h2 = gas_molec_dict["h2"] +# g_h2o = gas_molec_dict["h2o"] +# #__| +# +# lim_U_out = g_h2o - get_g_oh(m_oh, b_oh, g_oh) +# +# if rxn_direction == "forward": +# lim_U_out = - lim_U_out +# elif rxn_direction == "reverse": +# lim_U_out = + lim_U_out +# +# return(lim_U_out) +# #__| +# +#__| diff --git a/oxr_reaction/oxr_methods.py b/oxr_reaction/oxr_methods.py new file mode 100644 index 0000000..7f56a15 --- /dev/null +++ b/oxr_reaction/oxr_methods.py @@ -0,0 +1,550 @@ +#!/usr/bin/env python + +"""ORR energetics classes and methods. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import copy +import numpy as np +import pandas as pd + +from plotly.graph_objs import Scatter + +pd.options.mode.chained_assignment = None + +from oxr_reaction.oxr_series import ORR_Free_E_Series +#__| + +#| - __old__ +def plotly_fed_layout( + plot_title="FED", + plot_title_size=18, + tick_lab_size=16, + axes_lab_size=18, + legend_size=18, + ): + """ + """ + #| - plotly_fed_layout + xax_labels = ["O2", "OOH", "O", "OH", "H2O"] + layout = { + + "title": plot_title, + + "font": { + "family": "Courier New, monospace", + "size": plot_title_size, + "color": "black", + }, + + #| - Axes -------------------------------------------------------------- + "yaxis": { + "title": "Free Energy [eV]", + "zeroline": True, + "titlefont": dict(size=axes_lab_size), + "showgrid": False, + "tickfont": dict( + size=tick_lab_size, + ), + }, + + "xaxis": { + "title": "Reaction Coordinate", + "zeroline": True, + "titlefont": dict(size=axes_lab_size), + "showgrid": False, + + # "showticklabels": False, + + "ticktext": xax_labels, + "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], + + "tickfont": dict( + size=tick_lab_size, + ), + }, + #__| ------------------------------------------------------------------- + + #| - Legend ------------------------------------------------------------ + "legend": { + "traceorder": "normal", + "font": dict(size=legend_size) + }, + #__| ------------------------------------------------------------------- + + #| - Plot Size + # "width": 200 * 4., + # "height": 200 * 3., + #__| + + } + + return(layout) + + #__| + +#__| + + +def calc_ads_e( + df_row, + bare_raw_e, + correction=0., + oxy_ref_e=-443.70964, + hyd_ref_e=-16.46018, + ): + """Calculate adsorption energies from raw DFT energetics. + + Default oxygen reference energy is based on water + + Args: + df_row: Pandas dataframe row + bare_raw_e: Bare slab raw DFT energy + correction: Energy correction (ZPE, entropy, solvation, etc.) + oxy_ref_e: + hyd_ref_e: + """ + #| - calc_ads_e + row = df_row + bare_slab = bare_raw_e + oxy_ref = oxy_ref_e + hyd_ref = hyd_ref_e + + #| - Oxygen & Hydrogen Atom Count + atoms_col = "atom_type_num_dict" + if atoms_col in list(row.index): + try: + num_O = row[atoms_col][0]["O"] + except: + num_O = 0 + + try: + num_H = row[atoms_col][0]["H"] + except: + num_H = 0 + + else: + + if row["adsorbate"] == "ooh": + num_O = 2 + num_H = 1 + elif row["adsorbate"] == "o": + num_O = 1 + num_H = 0 + elif row["adsorbate"] == "oh": + num_O = 1 + num_H = 1 + elif row["adsorbate"] == "bare": + num_O = 0 + num_H = 0 + #__| + + # print("oxy_ref: ", oxy_ref) + # print("hyd_ref:", hyd_ref) + + try: + raw_e = row["elec_energy"] + ads_e_i = raw_e - (bare_slab + num_O * oxy_ref + num_H * hyd_ref) + ads_e_i += correction + + # ads_e_i = raw_e - bare_slab - num_O * oxy_ref - num_H * hyd_ref + # ads_e_i += correction + except: + ads_e_i = None + + return(ads_e_i) + #__| + +def df_calc_adsorption_e( + df, + + oxy_ref, + hyd_ref, + + bare_slab_e, + bare_slab_var=None, + + corrections_mode="df_column", # 'corr_dict', 'df_column', None + corrections_column="gibbs_correction", + + corrections_dict=None, + ): + """Calculate and add adsorption energy column to data_frame. + + Args: + df: + """ + #| - df_calc_adsorption_e + ads_e_list = [] + for index, row in df.iterrows(): + bare_e = bare_slab_e + + #| - Correction + corr = 0. + # corr = fe_corr_dict[row["adsorbate"]] + + if corrections_mode == "df_column": + corr = row[corrections_column] + + # If "df_column" method return 0. then try to use correction_dict + if corr == 0.: + if corrections_dict is not None: + corr = corrections_dict[row["adsorbate"]] + + elif corrections_mode == "corr_dict" and corrections_dict is not None: + corr = corrections_dict[row["adsorbate"]] + else: + print("No correction being applied") + corr = 0. + #__| + + if type(bare_slab_e) == dict: + bare_e = bare_slab_e[row[bare_slab_var]] + + elif type(bare_slab_e) == float: + bare_e = bare_slab_e + + ads_e_i = calc_ads_e( + row, + # bare_slab, + bare_e, + correction=corr, + oxy_ref_e=oxy_ref, + hyd_ref_e=hyd_ref, + ) + ads_e_list.append(ads_e_i) + + df["ads_e"] = np.array(ads_e_list) + #__| + +def lowest_e_path( + df, + jobs_variables, + color_list, + create_ideal_series=True, + opt_name=None, + bias=0., + manual_props="*TEMP*", + plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", + smart_format=None, + ): + """Find the lowest energy pathway FED. + + COMBAK + + From a set of FE pathways corresponding to different sites, the lowest + energy states will be selected to construct a new FED. + + Args: + df: + jobs_variables: + Result of Jobs.tree_level_labels + color_list: + bias: + + """ + #| - lowest_e_path + + #| - Grouping By Adsorbate Type + df = copy.deepcopy(df) + groupby = copy.deepcopy(jobs_variables) + + groupby.remove("site") + groupby.remove("adsorbate") + + data_master = {} + if groupby == []: + series_list = [] + for ads_i in df.groupby("adsorbate"): + + min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] + series_list.append(min_e_row) + + df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T + data_master[manual_props] = df_i + + else: + for group_i in df.groupby(groupby): + series_list = [] + for ads_i in group_i[1].groupby("adsorbate"): + + min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] + series_list.append(min_e_row) + + df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T + data_master[group_i[0]] = df_i + + #__| + + #| - Creating Data Sets + + #| - Creating FED Datasets + data_list = [] + # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): + for i_cnt, (key, fe_dict) in enumerate(data_master.items()): + + ORR = ORR_Free_E_Plot( + free_energy_df=fe_dict, + ) + + dat_lst = ORR.plot_fed_series( + bias=bias, + opt_name=opt_name, + properties=key, + color_list=color_list, + i_cnt=i_cnt, + hover_text_col="site", + smart_format=smart_format, + ) + + data_list.extend(dat_lst) + #__| + + #| - Creating Ideal FED Dataset + if create_ideal_series: + e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) + + dat_ideal = ORR.create_plotly_series( + e_list_ideal, + group="Ideal", + name="Ideal", + color=color_list[-1], + plot_mode="full_lines", + ) + + dat_lst = data_list + dat_ideal + + else: + + dat_lst = data_list + + + #__| + + # dat_lst = data_list + dat_ideal + + #__| + + #| - Plotting + + #| - Plot Settings + plot_title_size = 18 + tick_lab_size = 16 + axes_lab_size = 18 + legend_size = 18 + #__| + + #| - Plot Layout + # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] + # layout = { + # + # "title": plot_title, + # + # "font": { + # "family": "Courier New, monospace", + # "size": plot_title_size, + # "color": "black", + # }, + # + # #| - Axes -------------------------------------------------------------- + # "yaxis": { + # "title": "Free Energy [eV]", + # "zeroline": True, + # "titlefont": dict(size=axes_lab_size), + # "showgrid": False, + # "tickfont": dict( + # size=tick_lab_size, + # ), + # }, + # + # "xaxis": { + # "title": "Reaction Coordinate", + # "zeroline": True, + # "titlefont": dict(size=axes_lab_size), + # "showgrid": False, + # + # # "showticklabels": False, + # + # "ticktext": xax_labels, + # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], + # + # "tickfont": dict( + # size=tick_lab_size, + # ), + # }, + # #__| ------------------------------------------------------------------- + # + # #| - Legend ------------------------------------------------------------ + # "legend": { + # "traceorder": "normal", + # "font": dict(size=legend_size) + # }, + # #__| ------------------------------------------------------------------- + # + # #| - Plot Size + # # "width": 200 * 4., + # # "height": 200 * 3., + # #__| + # + # } + #__| + + layout = plotly_fed_layout(plot_title=plot_title) + + #__| + + return(dat_lst, layout) + + #__| + +def plot_all_states( + df, + jobs_variables, + color_list, + bias=0., + hover_text_col="site", + create_ideal_series=True, + plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", + smart_format=None, + ): + """ + + Args: + df: + jobs_variables: + color_list: + bias: + plot_title: + """ + #| - plot_all_states + + #| - Grouping By Adsorbate Type + + groupby = copy.deepcopy(jobs_variables) + # groupby = copy.deepcopy(Jojobs_variablesbs.tree_level_labels) + groupby.remove("adsorbate") + + data_master = {} + for group_i in df.groupby(groupby): + + data_master[group_i[0]] = group_i[1] + #__| + + #| - Creating Data Sets + + #| - Creating FED Datasets + data_list = [] + # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): + for i_cnt, (key, fe_dict) in enumerate(data_master.items()): + ORR = ORR_Free_E_Plot( + free_energy_df=fe_dict, + ) + + dat_lst = ORR.plot_fed_series( + bias=bias, + properties=key, + color_list=color_list, + i_cnt=i_cnt, + # hover_text_col="site" + hover_text_col=hover_text_col, + plot_mode="states_only", + smart_format=smart_format, + ) + + data_list.extend(dat_lst) + #__| + + #| - Creating Ideal FED Dataset + if create_ideal_series: + + e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) + + dat_ideal = ORR.create_plotly_series( + e_list_ideal, + group="Ideal", + name="Ideal", + color="red", + plot_mode="full_lines", + ) + + dat_lst = data_list + dat_ideal + #__| + + else: + dat_lst = data_list + + #__| + + #| - Plotting + + #| - Plot Settings + plot_title_size = 18 + tick_lab_size = 16 + axes_lab_size = 18 + legend_size = 12 + #__| + + #| - Plot Layout + # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] + # layout = { + # + # "title": plot_title, + # + # "font": { + # "family": "Courier New, monospace", + # "size": plot_title_size, + # "color": "black", + # }, + # + # #| - Axes -------------------------------------------------------------- + # "yaxis": { + # "title": "Free Energy [eV]", + # "zeroline": True, + # "titlefont": dict(size=axes_lab_size), + # "showgrid": False, + # "tickfont": dict( + # size=tick_lab_size, + # ), + # }, + # + # "xaxis": { + # "title": "Reaction Coordinate", + # "zeroline": True, + # "titlefont": dict(size=axes_lab_size), + # "showgrid": False, + # + # # "showticklabels": False, + # + # "ticktext": xax_labels, + # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], + # + # "tickfont": dict( + # size=tick_lab_size, + # ), + # }, + # #__| ------------------------------------------------------------------- + # + # #| - Legend ------------------------------------------------------------ + # "legend": { + # "traceorder": "normal", + # "font": dict(size=legend_size) + # }, + # #__| ------------------------------------------------------------------- + # + # #| - Plot Size + # "width": 200 * 4., + # "height": 200 * 3., + # #__| + # + # } + #__| + + layout = plotly_fed_layout(plot_title=plot_title) + + return(dat_lst, layout) + + #__| + + #__| diff --git a/oxr_reaction/oxr_plotting_classes/oxr_plot_2d_volcano.py b/oxr_reaction/oxr_plotting_classes/oxr_plot_2d_volcano.py new file mode 100644 index 0000000..28fdcec --- /dev/null +++ b/oxr_reaction/oxr_plotting_classes/oxr_plot_2d_volcano.py @@ -0,0 +1,561 @@ +# ██ ██ ██████ ██ ██████ ██████ ██ ██████ ████████ +# ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +# ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ +# ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +# ████ ██████ ███████ ██████ ███████ ██ ███████ ██████ ██ + +class Volcano_Plot_2D(): + """Class to plot OER/ORR volcano plots. + + Development Notes: + TEMP + """ + + #| - Volcano_Plot ********************************************************* + + def __init__(self, + ORR_Free_E_Plot, + ): + """ + """ + #| - __init__ + self.ORR_Free_E_Plot = ORR_Free_E_Plot + #__| + + def create_volcano_relations_plot(self, + show_data_labels=False, + # smart_format_dict=None, + ): + """Create ORR/OER volcano plot. + + Args: + smart_format_dict: + Optional dictionary that will format data points + """ + #| - create_volcano_relations_plot + + #| - Default Smart Format Dict + smart_format_dict = self.smart_format_dict + + if smart_format_dict is None: + print("No smart format given!") + smart_format_dict = [ + [{"bulk_system": "IrO3"}, {self.marker_color_key: "green"}], + [{"bulk_system": "IrO2"}, {self.marker_color_key: "yellow"}], + + [{"coverage_type": "o_covered"}, {"symbol": "s"}], + [{"coverage_type": "h_covered"}, {"symbol": "^"}], + + [{"facet": "110"}, {"color1": "red"}], + [{"facet": "211"}, {"color1": "green"}], + [{"facet": "100"}, {"color1": "black"}], + ] + #__| + + #| - Processing Data Points + x_data_list = [] + y_data_list = [] + + for series_i in self.ORR_Free_E_Plot.series_list: + + #| - x-axis energy + x_spec = self.x_ax_species + if x_spec == "o-oh": + e_o = series_i.energy_states_dict["o"] + e_oh = series_i.energy_states_dict["oh"] + x_ax_energy = e_o - e_oh + else: + x_ax_energy = series_i.energy_states_dict[x_spec] + #__| + + #| - y-axis limiting potential + if self.ORR_Free_E_Plot.rxn_type == "ORR": + lim_pot_i = 1.23 - series_i.overpotential + + elif self.ORR_Free_E_Plot.rxn_type == "OER": + lim_pot_i = 1.23 + series_i.overpotential_OER + else: + print("LSDJFlksdj") + #__| + + #| - Process series_i + x_data_list.append(x_ax_energy) + y_data_list.append(lim_pot_i) + + smart_format_i = self.ORR_Free_E_Plot.__create_smart_format_dict__( + series_i.properties, + smart_format_dict, + ) + + name_i = series_i.series_name + + if series_i.color is not None: + smart_format_i[self.marker_color_key] = series_i.color + + + format_i = smart_format_i + + if series_i.format_dict: + # print(10 * "format_dict is here | ") + # print(series_i.format_dict) + + format_i = series_i.format_dict + + # x_energy, + # y_energy, + # smart_format_i, + # name_i, + # # legendgroup=None, + # group=None, + + trace_i = self.__create_trace_i__( + x_ax_energy, + lim_pot_i, + # smart_format_i, + format_i, + name_i, + group=series_i.group, + show_data_labels=show_data_labels, + ) + + self.data_points.append(trace_i) + #__| + + #__| + + #| - Finding plot axis limits + if self.plot_range is None: + y_axis_range = [min(y_data_list) - 0.2, max(y_data_list) + 0.2] + if self.ORR_Free_E_Plot.rxn_type == "OER": + y_axis_range.reverse() + else: + pass + + plot_range = { + "y": y_axis_range, + "x": [min(x_data_list) - 0.2, max(x_data_list) + 0.2], + } + + self.plot_range = plot_range + #__| + + #__| + + def create_volcano_lines(self, + gas_molec_dict=None, + scaling_dict=None, + plot_all_legs=True, + plot_min_max_legs=False, + trace_priority="top", # 'top' or 'bottom' + legs_to_plot=[ + "o2_to_ooh", + "ooh_to_o", + "o_to_oh", + "oh_to_h2o", + ], + line_color="black", + ): + """Create volcano data traces. + + Args: + gas_molec_dict: + scaling_dict: + plot_all_legs: + plot_min_max_legs: + trace_priority: + if 'top', the volcano lines will be placed on the top of the + plot, if 'bottom' then the data points will by on top of the + volcano + """ + #| - create_volcano_lines + out_data = [] + x_range = self.plot_range["x"] + + #| - Volcano Legs + volc_legs = [ + 'o2_to_ooh', + 'ooh_to_o', + 'o_to_oh', + 'oh_to_h2o', + ] + + energy_dict = { + 'o2_to_ooh': [], + 'ooh_to_o': [], + 'o_to_oh': [], + 'oh_to_h2o': [], + } + + #| - Create Volcano Legs (LOOP) + x_axis = np.linspace(x_range[0], x_range[1], num=500) + for leg_i in volc_legs: + for x_energy_i in x_axis: + + if self.x_ax_species == "oh": + g_oh = x_energy_i + g_o_minus_g_oh = None + + elif self.x_ax_species == "o-oh": + g_oh = None + g_o_minus_g_oh = x_energy_i + + energy_dict[leg_i].append( + lim_U_i( + g_oh=g_oh, + g_o_minus_g_oh=g_o_minus_g_oh, + # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' + mech_step=leg_i, + gas_molec_dict=gas_molec_dict, + scaling_dict=scaling_dict, + rxn_direction="forward", + ), + ) + #__| + + if plot_all_legs: + + #| - plot_all_legs + # hoverinfo_type = "none" + hoverinfo_type = "name" + + trace_o2_to_ooh = go.Scatter( + x=x_axis, + y=energy_dict["o2_to_ooh"], + name="O2->*OOH", + hoverinfo=hoverinfo_type, + line=dict( + color="#e7b8bc", + width=2, + dash="solid", + ) + ) + + trace_ooh_to_o = go.Scatter( + x=x_axis, + y=energy_dict["ooh_to_o"], + name="*OOH->*O", + hoverinfo=hoverinfo_type, + line=dict( + color="#afd7c3", + width=2, + dash="solid", + ) + ) + + trace_o_to_oh = go.Scatter( + x=x_axis, + y=energy_dict["o_to_oh"], + name="*O->*OH", + hoverinfo=hoverinfo_type, + line=dict( + color="#b5c4e2", + width=2, + dash="solid", + ) + ) + + trace_oh_to_h2o = go.Scatter( + x=x_axis, + y=energy_dict["oh_to_h2o"], + name="*OH->H2O", + hoverinfo=hoverinfo_type, + line=dict( + color="#dbcdab", + width=2, + dash="solid", + ) + ) + + if trace_priority == "top": + out_data.append(trace_o2_to_ooh) + out_data.append(trace_ooh_to_o) + out_data.append(trace_o_to_oh) + out_data.append(trace_oh_to_h2o) + + elif trace_priority == "bottom": + out_data.insert(0, trace_o2_to_ooh) + out_data.insert(0, trace_ooh_to_o) + out_data.insert(0, trace_o_to_oh) + out_data.insert(0, trace_oh_to_h2o) + #__| + + #__| + + #| - Minimum Energy Legs + energy_lists= [] + for leg_i in legs_to_plot: + energy_lists.append(energy_dict[leg_i]) + + min_max_e_list = [] + for legs in zip(*energy_lists): + if self.ORR_Free_E_Plot.rxn_type == "ORR": + energy_i = min(*legs) + + elif self.ORR_Free_E_Plot.rxn_type == "OER": + energy_i = max(*legs) + + min_max_e_list.append(energy_i) + + trace_volcano = go.Scatter( + x=x_axis, + y=min_max_e_list, + name="activity volcano", + hoverinfo="skip", + line=dict( + color=line_color, + width=2, + # dash="dash", + dash="5px,2px,5px,2px", + ) + ) + + if plot_min_max_legs: + if trace_priority == "top": + out_data.append(trace_volcano) + + elif trace_priority == "bottom": + out_data.insert(0, trace_volcano) + #__| + + return(out_data) + #__| + + def __create_trace_i__(self, + x_energy, + y_energy, + smart_format_i, + name_i, + # legendgroup=None, + group=None, + show_data_labels=False, + ): + """ + """ + #| - __create_trace_i__ + + if show_data_labels is True: + mode_i = "markers+text" + elif show_data_labels is False: + mode_i = "markers" + else: + print("TEMP TEMP TEMP | __create_trace_i__") + + # print(mode_i) + + trace_i = go.Scatter( + x=[x_energy], + y=[y_energy], + + mode=mode_i, + # mode="markers+text", + # mode="markers", + + name=name_i, + text=[name_i], + # text=["TEMP"], + + legendgroup=group, + + hoverinfo="text", + + # hoverinfo=None, + # hoverinfosrc=None, + # hoverlabel=None, + # hoveron=None, + # hovertext=None, + # hovertextsrc=None, + + # textposition='top right', + textposition='middle left', + textfont={ + # "family": "Courier New, monospace", + # "family": font_family, + "size": 10, + "color": "black", + }, + + marker=dict( + size=smart_format_i.get("marker_size", 9), + color=smart_format_i.get(self.marker_color_key, "red"), + symbol=smart_format_i.get( + self.marker_shape_key, "circle"), + line=dict( + width=smart_format_i.get("marker_border_width", 1.), + color=smart_format_i.get( + self.marker_border_color_key, "black"), + ), + ), + ) + + return(trace_i) + #__| + + def get_plotly_layout(self, + showlegend=False, + width=9. * 37.795275591, + height=9. * 37.795275591, + layout_dict=None, + ): + """ + """ + #| - get_plotly_layout + + #| - Properties + # plot_title="FED" + plot_title = None + # plot_title_size = 18 + # tick_lab_size = 9 * (4. / 3.) + tick_lab_size = 8 * (4. / 3.) + axes_lab_size = 9 * (4. / 3.) + legend_size = 18 + # font_family="Computer Modern" # "Courier New, monospace" + font_family = "Arial" # "Courier New, monospace" + #__| + + # self.x_ax_spec + + if self.x_ax_species == "oh": + # xaxis_title = "dG_*OH (eV)" + xaxis_title = "dGOH (eV)" + elif self.x_ax_species == "o-oh": + # xaxis_title = "dG_*OH - dG_*O (eV)" + xaxis_title = "dGO - dGOH (eV)" + + # layout["margin"] = go.layout.Margin( + # b=50., + # l=50., + # r=50., + # t=50., + # # pad=20., + # ) + + layout = { + "title": plot_title, + + "font": { + "family": font_family, + "color": "black", + }, + + #| - Axes ----------------------------------------------------- + + #| - yaxis + "yaxis": { + "title": "Limiting Potential (V)", + # "title": "$\\Delta G (ev)$", + + "range": self.plot_range["y"], + "zeroline": False, + "showline": True, + "mirror": 'ticks', + # "linecolor": 'red', + "linecolor": 'black', + "showgrid": False, + + "titlefont": dict(size=axes_lab_size), + + "tickfont": dict( + size=tick_lab_size, + ), + "ticks": 'inside', + "tick0": 0, + "tickcolor": 'black', + "dtick": 0.1, + "ticklen": 2, + "tickwidth": 1, + }, + #__| + + #| - xaxis + "xaxis": { + # "title": "$\\Delta G_{OH} (ev)$", + "title": xaxis_title, + "range": self.plot_range["x"], + "zeroline": False, + "showline": True, + "mirror": True, + # "linecolor": 'red', + "linecolor": 'black', + "showgrid": False, + "titlefont": dict(size=axes_lab_size), + "showticklabels": True, + "ticks": 'inside', + "tick0": 0, + "dtick": 0.2, + "ticklen": 2, + "tickwidth": 1, + "tickcolor": 'black', + "tickfont": dict( + size=tick_lab_size, + ), + }, + #__| + + #__| + + "margin": go.layout.Margin( + b=50., + l=50., + r=50., + t=50., + ), + + # "paper_bgcolor": 'rgba(0,0,0,0)', + "plot_bgcolor": 'rgba(0,0,0,0)', + + #| - Legend --------------------------------------------------- + "legend": { + "traceorder": "normal", + "font": dict(size=legend_size), + "x": 0., + "y": -0.1, + # "xanchor": "left", + "yanchor": "top", + }, + + # "showlegend": False, + "showlegend": showlegend, + + #__| + + } + + #| - Plot Size Settings + # bottom_margin_size = 2.5 * 9. * 37.795275591 + plot_size_settings = { + "width": width, + "height": height, + + # "width": 9. * 37.795275591, + # "height": 9 * 37.795275591, + + # "margin": go.layout.Margin({ + # "l": 50, + # "r": 50, + # # "b": bottom_margin_size, + # # "b": 100, + # "b": 1200, + # "t": 10, + # "pad": 4, + # }), + } + + #__| + + layout = {**layout, **plot_size_settings} + + #| - Applying Layout override dict + if layout_dict is not None: + from misc_modules.misc_methods import dict_merge + dict_merge(layout, layout_dict) + + # layout_i = {**layout_i, **layout_dict} + + #__| + + return(layout) + + #__| + + + #__| ********************************************************************** diff --git a/oxr_reaction/oxr_plotting_classes/oxr_plot_fed.py b/oxr_reaction/oxr_plotting_classes/oxr_plot_fed.py new file mode 100644 index 0000000..49448c2 --- /dev/null +++ b/oxr_reaction/oxr_plotting_classes/oxr_plot_fed.py @@ -0,0 +1,847 @@ +#!/usr/bin/env python + +"""ORR FED plotting class. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import numpy as np +import pandas as pd +import copy + +from sklearn.linear_model import LinearRegression + +import plotly.graph_objs as go + +pd.options.mode.chained_assignment = None + +from oxr_reaction.oxr_series import ORR_Free_E_Series +from oxr_reaction.adsorbate_scaling import lim_U_i + +# from orr_reaction.orr_series import ORR_Free_E_Series +# from orr_reaction.adsorbate_scaling import lim_U_i +#__| + + +# ███████ ███████ ██████ ██ ██████ ████████ +# ██ ██ ██ ██ ██ ██ ██ ██ +# █████ █████ ██████ ██ ██ ██ ██ +# ██ ██ ██ ██ ██ ██ ██ +# ██ ███████ ███████ ██ ███████ ██████ ██ + +class Free_Energy_Plot(): + """ + Development Notes: + Take the FED methods out of the ORR_Free_E_Plot class and into this one + """ + + #| - Free_Energy_Plot ***************************************************** + + def __init__(self, + ORR_Free_E_Plot, + + + bias=0., + opt_name=None, + properties=None, + color_list=None, + i_cnt=0, + hover_text_col=None, + plot_mode="all", + smart_format=None, + rxn_type="ORR", + show_legend=True, + show_H_e_pairs_annotations=True, + ): + """ + Input variables to class instance. + + Args: + ORR_Free_E_Plot: + mode: + "all", "ooh_vs_oh", "o_vs_oh" + """ + #| - __init__ + self.bias = bias + self.opt_name = opt_name + self.properties = properties + self.color_list = color_list + self.i_cnt = i_cnt + self.hover_text_col = hover_text_col + self.plot_mode = plot_mode + self.smart_format = smart_format + self.rxn_type = rxn_type + self.show_H_e_pairs_annotations = show_H_e_pairs_annotations + + self.ORR_Free_E_Plot = ORR_Free_E_Plot + + # ##################################################################### + self.plot_states_sep = 0.3 + self.plot_states_width = 1. + + self.show_legend = show_legend + + self.rxn_x_coord_array = self.create_rxn_coord_array( + self.ORR_Free_E_Plot.num_states, + spacing=self.plot_states_sep, + step_size=self.plot_states_width, + ) + + self.mid_state_x_array = self.create_mid_state_x_array() + #__| + + def create_fed_plot(self, + + ): + """ + """ + #| - create_fed_plot + plot_data = [] + for series_i in self.ORR_Free_E_Plot.series_list: + + data_i = self.plot_fed_series( + series_i, + + bias=self.bias, + opt_name=self.opt_name, + properties=self.properties, + color_list=self.color_list, + i_cnt=self.i_cnt, + hover_text_col=self.hover_text_col, + plot_mode=self.plot_mode, + smart_format=self.smart_format, + overpotential_type=self.rxn_type, + ) + + # plot_data.append(data_i) + plot_data += data_i + + return(plot_data) + #__| + + def ideal_ORR_series(self): + """ + """ + #| - ideal_ORR_series + # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] + + ideal_data_list = [ + + { + "adsorbate": "ooh", + "ads_e": 3.69, + }, + + { + "adsorbate": "o", + "ads_e": 2.46, + }, + + { + "adsorbate": "oh", + "ads_e": 1.23, + }, + + ] + + df_ideal = pd.DataFrame(ideal_data_list) + + self.ORR_Free_E_Plot.add_series( + df_ideal, + plot_mode="full_lines", # ########## + opt_name="Ideal ORR Catalyst", + smart_format=False, + color=None, + ) + + #__| + + def create_rxn_coord_array(self, + rxn_steps, + spacing=0, + step_size=1, + ): + """ + Create a reaction coordinate array ([0, 1, 1, 2, 2, 3]) for plotting. + + Args: + rxn_steps: + Number of steps in reaction coordinate including initial + and final state. + Ex. A -> Intermediate -> C has 3 steps/states + + spacing: + Spacing inbetween the energy levels. The default of 0 creates + a free energy diagram that looks like steps + """ + #| - create_rxn_coord_array + lst = [] + for i in range(1, rxn_steps): + if i == 1: + lst.append(step_size) + lst.append(step_size + spacing) + if i != 1: + lst.append(lst[-1] + step_size) + lst.append(lst[-2] + step_size + spacing) + + lst.insert(0, 0) + lst.append(lst[-1] + step_size) + + return(lst) + #__| + + + def plot_fed_series(self, + series_i, + + bias=0., + opt_name=None, + properties=None, + color_list=None, + i_cnt=0, + hover_text_col=None, + plot_mode="all", + smart_format=None, + overpotential_type="ORR", + ): + """ + Process data for FED plot. + + Args: + bias: + opt_name + properties: + color_list: + i_cnt: + hover_text_col: + Dataframe column name to be used for hover text + + #FIXME | This is fairly rough as of right now + """ + #| - plot_fed_series + e_list = series_i.energy_lst + e_list = series_i.apply_bias(bias, e_list) + + + for n, i in enumerate(e_list): + if np.isnan(i) is True: + e_list[n] = None + + if color_list is None: + color_list = ["red"] + + # name_i = self.series_name + name_i = series_i.series_name + + #| - Hover Text + if hover_text_col is not None: + if type(hover_text_col) is not list: + hover_text_list = self.property_list(hover_text_col) + + else: + hover_text_lists = [] + for col_i in hover_text_col: + + # replacing nan with "" + tmp = self.property_list(col_i) + hover_text_i = ["" if x is np.nan else x for x in tmp] + hover_text_lists.append(hover_text_i) + + # TODO Removed last trailing " | " + hover_text_list = [] + for items in zip(*hover_text_lists): + + if all([True if i == "" else False for i in items]) is True: + hover_col_state_i = "" + else: + hover_col_state_i = " | ".join(items) + + hover_text_list.append(hover_col_state_i) + + else: + hover_text_list = [np.nan for j_cnt in list(range(5))] + #__| + + #| - TEMP Picking color from "color_list" or "color" variable + if series_i.color is not None: + color_i = self.color + else: + color_i = color_list[i_cnt - 1] + #__| + + dat_lst = self.__create_plotly_series__( + series_i, + e_list, + group=name_i, + name=name_i, + hover_text=hover_text_list, + # color=color_list[i_cnt - 1], + color=color_i, + plot_mode=plot_mode, + smart_format=smart_format, + ) + + return(dat_lst) + + #__| + + + def __create_plotly_series__(self, + series_i, + energy_lst, + name="TEMP", + group="group1", + hover_text=None, + color="rgb(22, 96, 167)", + plot_mode="all", + smart_format=None, + ): + """ + Create a plotly series for the current instance. + + Args: + energy_lst: + name: + group: + color: + plot_mode: + "all" + "states_only" + "full_lines" + """ + #| - create_plotly_series + y_dat = self.__convert_to_plotting_list__(energy_lst) + + if hover_text is None: + hover_text = [np.nan for i_ind in range(5)] + + + #| - Parameters + if plot_mode == "all": + show_leg_2 = False + elif plot_mode == "states_only": + show_leg_2 = False + elif plot_mode == "full_lines": + show_leg_2 = True + #__| + + #| - Adding Breaks in Data + x_dat = self.rxn_x_coord_array + + new_x_dat = copy.copy(x_dat) + new_y_dat = copy.copy(y_dat) + + cnt = 2 + for i_ind in range(int(len(x_dat) / 2 - 1)): + fill = new_x_dat[cnt - 1] + new_x_dat.insert(cnt, fill) + new_y_dat.insert(cnt, None) + cnt += 3 + #__| + + #| - Creating x-data in middle of states + short_y = np.array(y_dat)[::2] + + xdat = list(set(new_x_dat)) + xdat.sort() + + cnt = 0 + short_x = [] + for i_ind in range(int(len(xdat) / 2)): + short_x.append(xdat[cnt] + 0.5) # FIXME Replace 0.5 with variable + cnt += 2 + #__| + + #| - Smart Format Dict ************************************************ + + #| - DICTS + plot_parameter_dict = { + "dash": None, + } + + # smart_format = [ + # + # # [ + # # {"spinpol": True}, + # # {"dash": "dot"}, + # # ], + # + # [ + # {"system": "Fe_slab"}, + # {"dash": "dashdot"}, + # ], + # + # [ + # {"system": "N_graph_Fe"}, + # {"dash": "dot"}, + # ], + # + # [ + # {"system": "graph_Fe"}, + # {"dash": "dash"}, + # ], + # + # [ + # {"system": "graphene"}, + # {"dash": None}, + # ], + # + # ] + + #__| + + # if self.fe_df is not None and smart_format is not None: + if series_i.fe_df is not None and smart_format is not None: + for format_i in smart_format: + + # format_i key:values + df_col_name = list(format_i[0])[0] + value_i = list(format_i[0].values())[0] + setting_name = list(format_i[1])[0] + setting_value = list(format_i[1].values())[0] + + + if df_col_name in list(self.fe_df): + + # *OOH, *O, *OH entries must have value_i as the + # column entries in the column df_col_name + + df = self.fe_df + df_wo_bulk = df[df["adsorbate"] != "bulk"] + + if all(df_wo_bulk[df_col_name] == value_i): + plot_parameter_dict.update( + {setting_name: setting_value}, + ) + + else: + print("Dataframe column " + df_col_name + " not present") + + #__| ****************************************************************** + + #| - Series Color + if "color" in list(plot_parameter_dict): + color_out = plot_parameter_dict["color"] + else: + plot_parameter_dict["color"] = color + #__| + + if series_i.format_dict: + format_i = series_i.format_dict + print(format_i) + else: + format_i = plot_parameter_dict + + #| - Plotly Scatter Plot Instances + + #| - Thick horizontal state lines + data_1 = go.Scatter( + x=new_x_dat, + y=new_y_dat, + legendgroup=group, + showlegend=True, + name=name, + hoverinfo="none", # TEMP - 180317 + + # text=hover_text, + + connectgaps=False, + line=dict( + # color=color, + # color=plot_parameter_dict["color"], + # color=format_i["color_2"], + color=format_i.get("color_2", "red"), + + # COMBAK + # width=2, + width=4, + + # dash="dot", # TEMP + dash=plot_parameter_dict["dash"], # TEMP + ), + mode="lines", + ) + #__| + + #| - Full, thin line + data_2 = go.Scatter( + x=new_x_dat, + y=new_y_dat, + legendgroup=group, + name=name, + connectgaps=True, + showlegend=show_leg_2, + hoverinfo="none", + text=hover_text, + line=dict( + color=format_i.get("color_2", "red"), + width=1, + ), + mode="lines", + ) + #__| + + #| - Points in middle of energy states (For convienient hover) + # 'color_1': 'black', 'color_2': 'blue', 'symbol_i': 'circle', 'symbol_i__matplotlib': 'o', 'marker_size': 18 + + format_i.get("color_2", "black") + + data_3 = go.Scatter( + x=short_x, + y=short_y, + legendgroup=group, + name=name, + showlegend=False, + hoverinfo="y+text", + text=hover_text, + marker=dict( + size=format_i.get("marker_size", 10), + color=format_i.get("color_2", "black"), + # opacity=0., + opacity=0.8, + symbol=format_i.get("symbol_i", "circle"), + line=dict( + # color=smart_format_i[marker_border_color_key], + color=format_i.get("color_1", "black"), + width=1., + ) + + ), + mode="markers", + ) + #__| + + #__| + + #| - Plot Mode (which data series to plot) + if plot_mode == "all": + data_lst = [data_1, data_2, data_3] + elif plot_mode == "states_only": + data_lst = [data_1, data_3] + elif plot_mode == "full_lines": + data_lst = [data_2, data_3] + #__| + + return(data_lst) + #__| + + def __convert_to_plotting_list__(self, + energy_lst, + spacing=0.5, + step_size=1, + ): + """Repeat entries in energy list to conform to FED plot. + + Modifies an energy list for plotting by repeating each entry + Ex. [4.92, 3.69, ... ] -> [4.92, 4.92, 3.69, 3.69, ... ] + + Args: + energy_lst: + spacing: + step_size: + """ + #| - __convert_to_plotting_list__ + tmp_list = range(len(energy_lst) * 2) + energy_dupl_lst = [energy_lst[i // 2] for i in tmp_list] + + # rxn_coord_steps = self.create_rxn_coord_array( + # len(energy_lst), + # spacing=spacing, + # step_size=step_size, + # ) + # out_list = [rxn_coord_steps, energy_dupl_lst] + + return(energy_dupl_lst) + #__| + + def max_y_value_per_step(self): + """ + """ + #| - max_y_value_per_step + fe_matrix = [] + + # for series_i in self.series_list: + for series_i in self.ORR_Free_E_Plot.series_list: + fe_matrix.append( + np.array(series_i.energy_lst), + ) + fe_matrix = np.array(fe_matrix) + + max_y_val_list = [] + for step_i in range(fe_matrix.shape[1]): + max_y_val_list.append(fe_matrix[:, step_i].max()) + + return(max_y_val_list) + #__| + + + def H_e_pairs_annotations(self, + font_size=18, + ): + """ + + Args: + font_size: + """ + #| - H_e_pairs_annotations + # ann_font_size = 18 + # states_sep = self.plot_states_sep + # states_width = self.plot_states_width + + + mid_state_x_array = self.mid_state_x_array + + rxn_x_array = self.rxn_x_coord_array + max_y_val_list = self.max_y_value_per_step() + + def add_annot( + ind, + rxn_x_array, + step, + annotations, + y=5.5, + font_size=18, + text="TEMP", + mid_state_x_array=None, + ): + """Append annotation object to annotations list. + + Args: + ind: + rxn_x_array: + step: + annotations: + y: + font_size: + text: + """ + #| - add_annot + ann_i = dict( + # x=(rxn_x_array[ind] + rxn_x_array[ind + step]) / 2., + x=mid_state_x_array[ind], + y=y + 0.4, + xref='x', + yref='y', + text=text, + showarrow=False, + font=dict( + color="black", + size=font_size + ), + ), + annotations += ann_i + #__| + + annotations = [] + + add_annot( + 0, rxn_x_array, 1, annotations, + y=max_y_val_list[0], font_size=font_size, + text="4(H+ + e-)", + mid_state_x_array=mid_state_x_array, + ) + + add_annot( + 1, rxn_x_array, 2, annotations, + y=max_y_val_list[1], font_size=font_size, + text="3(H+ + e-)", + mid_state_x_array=mid_state_x_array, + ) + + add_annot( + # 3, rxn_x_array, 2, annotations, + 2, rxn_x_array, 2, annotations, + y=max_y_val_list[2], font_size=font_size, + text="2(H+ + e-)", + mid_state_x_array=mid_state_x_array, + ) + + add_annot( + # 5, rxn_x_array, 2, annotations, + 3, rxn_x_array, 2, annotations, + y=max_y_val_list[3], font_size=font_size, + text="1(H+ + e-)", + mid_state_x_array=mid_state_x_array, + ) + + add_annot( + # 7, rxn_x_array, 2, annotations, + 4, rxn_x_array, 2, annotations, + y=max_y_val_list[4], font_size=font_size, + text="0(H+ + e-)", + mid_state_x_array=mid_state_x_array, + ) + + return(annotations) + #__| + + + def create_mid_state_x_array(self): + """ + """ + #| - create_mid_state_x_array + x_array_data = self.rxn_x_coord_array + state_width = self.plot_states_width + + xdat = list(set(x_array_data)) + xdat.sort() + + cnt = 0 + short_x = [] + for i_ind in range(int(len(xdat) / 2)): + short_x.append(xdat[cnt] + state_width / 2.) + cnt += 2 + + return(short_x) + #__| + + + def plotly_fed_layout(self, + plot_title="FED", + plot_title_size=18, + tick_lab_size=16, + axes_lab_size=18, + legend_size=18, + # font_family="Computer Modern" # "Courier New, monospace" + font_family="Arial, Courier New, monospace", + plot_width=680, + plot_height=510, + annotation_size=12, + ): + """ + + Development notes: + Move all plot parameters to this method, since the user will call + this method to obtain the layout. + """ + #| - plotly_fed_layout + + if self.rxn_type == "ORR": + # xax_labels = ["$O_{2}$", "$*OOH$", "$*O$", "$*OH$", "$H_{2}O$"] + # xax_labels = ["O2", "*OOH", "*O", "*OH", "H2O"] + + xax_labels = [ + "O2", + "*OOH", + "*O", + "*OH", + "H2O", + ] + + elif self.rxn_type == "OER": + # xax_labels = ["$H_{2}O$", "$*OH$", "$*O$", "$*OOH$", "$O_{2}$"] + xax_labels = ["H2O", "*OH", "*O", "*OOH", "O2"] + + # "font":dict( + # family='Arial', + # # size=18, + # color='black', + # ), + + layout = { + # "title": plot_title, + + "font": { + # "family": "Courier New, monospace", + "family": font_family, + "size": plot_title_size, + "color": "black", + }, + + + #| - Axes --------------------------------------------------------- + "yaxis": { + "title": "Free Energy (eV)", + # "title": "$\\Delta G (ev)$", + + "zeroline": False, + "linecolor": 'black', + "showline": True, + "mirror": 'ticks', + "showgrid": False, + + "titlefont": dict(size=axes_lab_size), + + "tickfont": dict( + size=tick_lab_size, + ), + + # "autotick": False, + "ticks": 'inside', + "tick0": 0, + "dtick": 1.0, + "ticklen": 2, + "tickwidth": 1, + "tickcolor": 'black', + + }, + + "xaxis": { + "title": "Reaction Coordinate", + + "zeroline": False, + "linecolor": 'black', + "showline": True, + "mirror": 'ticks', + "showgrid": False, + + # "zeroline": True, + # "showgrid": False, + "titlefont": dict(size=axes_lab_size), + + "showticklabels": True, + + "ticks": "", + "ticktext": xax_labels, + # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], + # "tickvals": [self.plot_states_width * i + 0.5 + # for i in range(len(xax_labels))], + "tickvals": self.mid_state_x_array, + "tickcolor": 'black', + "tickfont": dict( + size=tick_lab_size, + ), + }, + #__| -------------------------------------------------------------- + + #| - Legend ------------------------------------------------------- + "legend": { + "traceorder": "normal", + "font": dict(size=legend_size), + "x": -0.1, + "y": -1.2, + }, + + "showlegend": self.show_legend, + + #__| -------------------------------------------------------------- + + #| - Plot Size + # "width": 200 * 4., + # "height": 200 * 3., + #__| + + # "paper_bgcolor": 'rgba(0,0,0,0)', + "plot_bgcolor": 'rgba(0,0,0,0)', + + # "width": 9. * 37.795275591, + # "height": 9 * 37.795275591, + + "width": plot_width, + "height": plot_height, + } + + if self.show_H_e_pairs_annotations: + annotations = self.H_e_pairs_annotations(font_size=annotation_size) + + if "annotations" in list(layout): + layout["annotations"] += annotations + else: + layout["annotations"] = annotations + + return(layout) + #__| + + + #__| ********************************************************************** diff --git a/oxr_reaction/oxr_plotting_classes/oxr_plot_scaling.py b/oxr_reaction/oxr_plotting_classes/oxr_plot_scaling.py new file mode 100644 index 0000000..50479cd --- /dev/null +++ b/oxr_reaction/oxr_plotting_classes/oxr_plot_scaling.py @@ -0,0 +1,711 @@ +#!/usr/bin/env python + +"""ORR energetics classes and methods. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import numpy as np +import pandas as pd + +from sklearn.linear_model import LinearRegression + +import plotly.graph_objs as go + +pd.options.mode.chained_assignment = None + +from oxr_reaction.oxr_series import ORR_Free_E_Series +from oxr_reaction.adsorbate_scaling import lim_U_i + +# from orr_reaction.orr_series import ORR_Free_E_Series +# from orr_reaction.adsorbate_scaling import lim_U_i +#__| + + +# ███████ ██████ ██████ ██ ██████ ████████ +# ██ ██ ██ ██ ██ ██ ██ ██ ██ +# ███████ ██████ ██████ ██ ██ ██ ██ +# ██ ██ ██ ██ ██ ██ ██ ██ +# ███████ ██ ██ ███████ ██ ███████ ██████ ██ + +class Scaling_Relations_Plot(): + """Plot scaling relations and some simple fitting schemes. + + Development Notes: + IDEA: Add vertical lines to connect *O, *OH, and *OOH data points + """ + + #| - Scaling_Relations_Plot *********************************************** + + def __init__(self, + ORR_Free_E_Plot, + mode="all", + + plot_range={ + "y": [1., 5.], + "x": [-2., 4.], + }, + + x_ax_species="oh", + + marker_color_key="color2", + marker_border_color_key="color1", + marker_shape_key="symbol", + ): + """ + Input variables to class instance. + + Args: + ORR_Free_E_Plot: + mode: + "all", "ooh_vs_oh", "o_vs_oh" + """ + #| - __init__ + self.ORR_Free_E_Plot = ORR_Free_E_Plot + + assert (x_ax_species == "oh"), "Only *OH as the x-axis is allowed now" + self.x_ax_species = x_ax_species + self.marker_color_key = marker_color_key + self.marker_border_color_key = marker_border_color_key + self.marker_shape_key = marker_shape_key + + # ################################################################# + + self.data_points = { + "ooh_vs_oh": [], + "o_vs_oh": [], + "oh_vs_oh": [], + } + self.data_lines = [] + + self.x_range = plot_range["x"] + self.y_range = plot_range["y"] + + # self.layout = self.__create_layout__( + # title="Scaling Relations", + # showlegend=True, + # ) + + self.scaling_dict = { + "ooh": { + "m": None, + "b": None, + }, + + "o": { + "m": None, + "b": None, + }, + + "oh": { + "m": 1., + "b": 0., + }, + + } + + self.annotations_list = [] + + #__| + + def create_scaling_relations_plot(self, + smart_format_dict=None, + ): + """Return plotly data and layout objects for scaling relations. + + Args: + y_ax_spec: + x_ax_spec: + """ + #| - create_scaling_relations_plot + + #| - Default Smart Format Dict + if smart_format_dict is None: + print("No smart format given!") + smart_format_dict = [ + [{"bulk_system": "IrO3"}, {self.marker_color_key: "green"}], + [{"bulk_system": "IrO2"}, {self.marker_color_key: "yellow"}], + + [{"coverage_type": "o_covered"}, {self.marker_shape_key: "s"}], + [{"coverage_type": "h_covered"}, {self.marker_shape_key: "^"}], + + [{"facet": "110"}, {self.marker_border_color_key: "red"}], + [{"facet": "211"}, {self.marker_border_color_key: "green"}], + [{"facet": "100"}, {self.marker_border_color_key: "black"}], + ] + #__| + + #| - Processing Data Points + for series_i in self.ORR_Free_E_Plot.series_list: + + e_oh = series_i.energy_states_dict["oh"] + e_ooh = series_i.energy_states_dict["ooh"] + e_o = series_i.energy_states_dict["o"] + + + # Change self.__create_smart_format_dict__ to, + # self.ORR_Free_E_Plot.__create_smart_format_dict__ + # TODO + + smart_format_i = self.ORR_Free_E_Plot.__create_smart_format_dict__( + series_i.properties, + smart_format_dict, + ) + + # This is the old way of getting the name + # name_i = self.ORR_Free_E_Plot.__create_series_name__(series_i) + + name_i = series_i.series_name + + if series_i.color is not None: + smart_format_i[self.marker_color_key] = series_i.color + + # NEW, if series has format attached just use that + if series_i.format_dict: + smart_format_i = series_i.format_dict + + + #| - ooh_vs_oh + trace_i = self.__create_trace_i__( + e_oh, + e_ooh, + smart_format_i, + name_i, + legendgroup="ooh_vs_oh", + ) + # self.data_ooh_oh.append(trace_i) + self.data_points["ooh_vs_oh"].append(trace_i) + #__| + + #| - o_vs_oh + trace_i = self.__create_trace_i__( + e_oh, + e_o, + smart_format_i, + name_i, + legendgroup="o_vs_oh", + ) + # self.data_o_oh.append(trace_i) + self.data_points["o_vs_oh"].append(trace_i) + #__| + + #| - oh_vs_oh + trace_i = self.__create_trace_i__( + e_oh, + e_oh, + smart_format_i, + name_i, + legendgroup="oh_vs_oh", + ) + # self.data_oh_oh.append(trace_i) + self.data_points["oh_vs_oh"].append(trace_i) + #__| + + #__| + + #__| + + # Deprecated, delete this later + def __create_smart_format_dict__(self, property_dict, smart_format_dict): + """Create smart format dictionary. + + Args: + property_dict: + smart_format_dict: + """ + #| - __create_smart_format_dict__ + format_dict = {} + for key_i, value_i in property_dict.items(): + for format_i in smart_format_dict: + if list(format_i[0])[0] == key_i: + if list(format_i[0].values())[0] == value_i: + format_dict.update(format_i[1]) + + return(format_dict) + #__| + + def __create_series_name__(self, series_i): + """ + """ + #| - create_series_name + name_i = "" + for key, value in series_i.properties.items(): + if key == "coverage": + continue + + name_i += str(key) + ": " + str(value) + " | " + + return(name_i) + #__| + + def __create_trace_i__(self, + x_energy, + y_energy, + smart_format_i, + name_i, + legendgroup=None, + ): + """ + """ + #| - create_trace_i + # NOTE Looks like I need to put these in a list here + x_energy = [x_energy] + y_energy = [y_energy] + + trace_i = go.Scatter( + x=x_energy, + y=y_energy, + text=name_i, + name=name_i, + mode="markers", + legendgroup=legendgroup, + marker=dict( + size=smart_format_i.get("marker_size", 9), + symbol=smart_format_i.get( + self.marker_shape_key, "circle"), + color=smart_format_i.get( + self.marker_color_key, "pink"), + line=dict( + # color=smart_format_i[marker_border_color_key], + color=smart_format_i.get( + self.marker_border_color_key, "black"), + width=1., + ) + ) + ) + + return(trace_i) + #__| + + # NOTE | This shouldn't be an internal method + def __create_layout__(self, + # x_ax_spec="oh", + title="Scaling Relations", + showlegend=True, + layout_dict=None, + ): + """Create plotly layout dict. + + Args: + x_ax_spec: + title: + showlegend: + """ + #| - create_layout + + # if x_ax_spec == "" + if self.x_ax_species == "oh": + x_ax_title = "Gads,*OH (eV)" + else: + x_ax_title = "TEMP" + + y_ax_title = "Gads,*OH, " + \ + "Gads,*O, " + \ + "Gads,*OOH (eV)" + + tick_lab_size = 12 * (4. / 3.) + axes_lab_size = 14 * (4. / 3.) + + # legend_size = 18 + + #| - Common Axis Dict + common_axis_dict = { + + # "range": y_axis_range, + "zeroline": False, + "showline": True, + "mirror": 'ticks', + "linecolor": 'black', + "showgrid": False, + + "titlefont": dict(size=axes_lab_size), + "tickfont": dict( + size=tick_lab_size, + ), + "ticks": 'inside', + "tick0": 0, + "tickcolor": 'black', + # "dtick": 0.25, + "ticklen": 2, + "tickwidth": 1, + } + #__| + + #| - __old__ + # x_range_ooh_vs_oh=[0., 3.5], + # y_range_ooh_vs_oh=[0., 5.], + # x_range_o_vs_oh=[0., 3.5], + # y_range_o_vs_oh=[0., 5.], + + # if y_ax_spec == "ooh": + # x_range = self.x_range_ooh_vs_oh + # elif y_ax_spec == "o": + # x_range = self.x_range_o_vs_oh + # elif y_ax_spec == "oh": + # x_range = self.x_range_oh_vs_oh + # else: + # print("Woops - create_layout") + # + # if y_ax_spec == "ooh": + # y_range = self.y_range_ooh_vs_oh + # elif y_ax_spec == "o": + # y_range = self._range_o_vs_oh + # elif y_ax_spec == "oh": + # y_range = self.y_range_oh_vs_oh + # else: + # print("Woops - create_layout") + #__| + + x_range = self.x_range + y_range = self.y_range + + layout_i = { + "title": title, + "titlefont": go.layout.title.Font(size=24), + # "titlefont": go.layout.Titlefont(size=24), + + "xaxis": dict( + common_axis_dict, + **{ + "title": x_ax_title, + "range": x_range, + }, + ), + + "yaxis": dict( + common_axis_dict, + **{ + "title": y_ax_title, + "range": y_range, + }, + ), + + # Margin + "margin": go.layout.Margin( + b=50., + l=50., + r=50., + t=50., + ), + + "font": dict( + family='Arial', + # size=18, + color='black', + ), + + "width": 1.5 * 18.7 * 37.795275591, + "height": 18.7 * 37.795275591, + + "showlegend": showlegend, + + "legend": dict( + font=dict( + size=10, + ), + ), + } + + if layout_dict is not None: + from misc_modules.misc_methods import dict_merge + dict_merge(layout_i, layout_dict) + # layout_i = {**layout_i, **layout_dict} + + return(layout_i) + #__| + + def __series_excluded__(self, + properties_i, + exclude_dict, + ): + """Whether to exclude series_i from fitting. + + Takes an 'exclude_dict' and the series properties_dict and compares + them key-by-key. If there is a match, then that series is excluded + (and the function evaluates to True) + + Args: + properties_i: + exclude_dict: + """ + #| - series_excluded + exclude_dict_keys = list(exclude_dict.keys()) + properties_i_keys = list(properties_i.keys()) + + shared_keys = list( + set(exclude_dict_keys).intersection(set(properties_i_keys)), + ) + + if len(shared_keys) < len(exclude_dict_keys): + print("series_i doesn't have a specific key!") + + value_match_list = [] + for key_i in shared_keys: + value_match_i = exclude_dict[key_i] == properties_i[key_i] + value_match_list.append(value_match_i) + + + all_props_match = all(value_match_list) + + # if all_props_match: + # print("Ignoring this series for fitting") + # + # else: + # print("Series not excluded, will include in fitting set") + + + return(all_props_match) + + #__| + + def fit_scaling_lines(self, + dependent_species, # 'ooh', 'o', 'oh' + exclude_dict=None, + ): + """Linear fit of either *O or *OOH to *OH + + Args: + dependent_species: + y-axis species 'ooh' or 'o' + """ + #| - fit_scaling_lines + + #| - LOOP + oh_list = [] + dependent_e_list = [] + for series_i in self.ORR_Free_E_Plot.series_list: + + #| - Excluding series from fitting + if exclude_dict is not None: + properties_i = series_i.properties + exclude_series = self.__series_excluded__( + properties_i, + exclude_dict, + ) + if exclude_series: + continue + #__| + + energy_i = series_i.energy_states_dict[dependent_species] + dependent_e_list.append(energy_i) + oh_list.append(series_i.energy_states_dict["oh"]) + + #__| + + X = np.array([[i] for i in oh_list]) + y = np.array(dependent_e_list) + + reg = LinearRegression().fit(X, y) + + slope_i = reg.coef_[0] + intercept_i = reg.intercept_ + + print("Scaling fit for ", dependent_species) + print("intercept_i: ", str(intercept_i)) + print("slope_i: ", str(slope_i)) + print("") + + out = {"slope": slope_i, "intercept": intercept_i} + + self.scaling_dict[dependent_species] = { + "m": slope_i, + "b": intercept_i, + } + # print("_------__)_Z(*XF(8))") + + #| - Equation Annotations + if dependent_species == "ooh": + eqn_str_i = ("" + + "GOOH=" + + str(round(slope_i, 4)) + + " GOH+" + + str(round(intercept_i, 4)) + + "" + ) + + elif dependent_species == "o": + eqn_str_i = ("" + + "GO = " + + str(round(slope_i, 4)) + + " GOH+" + + str(round(intercept_i, 4)) + + "" + ) + + elif dependent_species == "oh": + eqn_str_i = ("" + + "GOH = " + + str(round(slope_i, 4)) + + " GOH+" + + str(round(intercept_i, 4)) + + "" + ) + + else: + eqn_str_i = "TEMP TEMP TEMP TEMP | 190213 | RF" + raise ValueError('A very specific bad thing happened.') + + annotation_i = dict( + x=0., + y=1., + xref="paper", + yref="paper", + text=eqn_str_i, + font=dict( + color="red", + family="Droid Sans Mono,Overpass", + size=9. * (4. / 3.), + ), + showarrow=False, + xanchor="left", + yshift=-11. * (4. / 3.) * len(self.annotations_list), + xshift=5., + ) + + self.annotations_list.append(annotation_i) + #__| + + + return(out) + #__| + + def add_ideal_lines(self): + """Add ideal scaling liknes to plot.""" + #| - add_ideal_lines + self.add_line({"slope": 1, "intercept": 3.2}, + name="*OOH vs *OH Scaling", + color="black", + width=1, + dash="dash", + ) + + self.add_line({"slope": 2, "intercept": 0.}, + name="*O vs *OH Scaling", + color="black", + width=1, + dash="dash", + ) + + self.add_line({"slope": 1, "intercept": 0.}, + name="*OH vs *OH Scaling", + color="black", + width=1, + dash="dash", + ) + #__| + + def add_line(self, + slope_intercept_dict, + name="add_lines - TEMP", + color="black", + width=1, + dash="dash", + ): + """Add line of form y=mx+b to plot. + + Args: + slope_intercept_dict: + name: + color: + width: + dash: + """ + #| - add_line + + # print(slope_intercept_dict) + + slope = slope_intercept_dict["slope"] + intercept = slope_intercept_dict["intercept"] + + def scaling_meth(E_OH): + """ + """ + #| - scaling_meth + out = slope * E_OH + intercept + + return(out) + #__| + + LH_bound = self.x_range[0] + RH_bound = self.x_range[1] + + scaling_trace = go.Scatter( + # x=[self.x_range_ooh_vs_oh[0], self.x_range_ooh_vs_oh[1]], + x=[LH_bound, RH_bound], + y=[ + scaling_meth(LH_bound), + scaling_meth(RH_bound), + ], + # name='Fitted scaling', + name=name, + mode='lines', + line=dict( + dash=dash, + color=color, + width=width, + ), + ) + # self.data_ooh_oh.append(scaling_trace) + self.data_lines.append(scaling_trace) + + # + # # Annotation + # ooh_vs_oh_eqn = ("" + + # "G_*OOH = " + + # str(round(SC_PLT.scaling_dict["ooh"]["m"], 5)) + + # " G_*OH + " + + # str(round(SC_PLT.scaling_dict["ooh"]["b"], 5)) + + # "" + # ) + # + # o_vs_oh_eqn = ("" + + # "G_*O = " + + # str(round(SC_PLT.scaling_dict["o"]["m"], 5)) + + # " G_*OH + " + + # str(round(SC_PLT.scaling_dict["o"]["b"], 5)) + + # "" + # ) + + #__| + + + + + + #| - __old__ + # def __ideal_ooh_oh_scaling__(self, E_OH): + # """Return the *OOH adsorption energy given DG_*OH by scaling. + # + # Args: + # E_OH:DG_*OH energy of adsorption + # """ + # #| - __ideal_ooh_oh_scaling__ + # return(E_OH + 3.2) + # #__| + # + # def __ideal_h_oh_scaling__(self, E_OH): + # """Return the *OOH adsorption energy given DG_*OH by scaling. + # + # Args: + # E_OH: DG_*OH energy of adsorption. + # """ + # #| - __ideal_h_oh_scaling__ + # return(2 * E_OH) + # #__| + # + # def __ideal_oh_oh_scaling__(self, E_OH): + # """Return the *OH adsorption energy given DG_*OH by scaling. + # + # NOTE: TRIVIAL QUANTITY!!!!!!!!!!!!!!!!!!! + # + # Args: + # E_OH: DG_*OH energy of adsorption. + # """ + # #| - __ideal_oh_oh_scaling__ + # return(E_OH) + # #__| + # + #__| + +#__| ********************************************************************** diff --git a/oxr_reaction/oxr_plotting_classes/oxr_plot_volcano.py b/oxr_reaction/oxr_plotting_classes/oxr_plot_volcano.py new file mode 100644 index 0000000..cd4dfaf --- /dev/null +++ b/oxr_reaction/oxr_plotting_classes/oxr_plot_volcano.py @@ -0,0 +1,607 @@ +#!/usr/bin/env python + +"""ORR energetics classes and methods. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import numpy as np +import pandas as pd + +from sklearn.linear_model import LinearRegression + +import plotly.graph_objs as go + +pd.options.mode.chained_assignment = None + +from oxr_reaction.oxr_series import ORR_Free_E_Series +# from orr_reaction.orr_series import ORR_Free_E_Series + +from oxr_reaction.adsorbate_scaling import lim_U_i +# from orr_reaction.adsorbate_scaling import lim_U_i +#__| + + +# ██ ██ ██████ ██ ██████ ██████ ██ ██████ ████████ +# ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +# ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ +# ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +# ████ ██████ ███████ ██████ ███████ ██ ███████ ██████ ██ + +class Volcano_Plot(): + """Class to plot OER/ORR volcano plots. + + Development Notes: + TEMP + """ + + #| - Volcano_Plot ********************************************************* + + def __init__(self, + ORR_Free_E_Plot, + x_ax_species="o-oh", # 'o-oh' or 'oh' + smart_format_dict=None, + plot_range=None, + marker_color_key="color2", + marker_border_color_key="color1", + marker_shape_key="symbol", + ): + """ + Input variables to class instance. + + Args: + ORR_Free_E_Plot: + mode: + "all", "ooh_vs_oh", "o_vs_oh" + plot_range: + Ex.) + plot_range={ + "y": [1., 5.], + "x": [-2., 4.], + } + + """ + #| - __init__ + self.ORR_Free_E_Plot = ORR_Free_E_Plot + self.x_ax_species = x_ax_species + self.plot_range = plot_range + self.smart_format_dict = smart_format_dict + + self.data_points = [] + self.data_lines = [] + + self.marker_color_key = marker_color_key + self.marker_border_color_key = marker_border_color_key + self.marker_shape_key = marker_shape_key + + #__| + + # NOTE | Rename this create_volcano_plot + def create_volcano_relations_plot(self, + show_data_labels=False, + # smart_format_dict=None, + ): + """Create ORR/OER volcano plot. + + Args: + smart_format_dict: + Optional dictionary that will format data points + """ + #| - create_volcano_relations_plot + + #| - Default Smart Format Dict + smart_format_dict = self.smart_format_dict + + if smart_format_dict is None: + print("No smart format given!") + smart_format_dict = [ + [{"bulk_system": "IrO3"}, {self.marker_color_key: "green"}], + [{"bulk_system": "IrO2"}, {self.marker_color_key: "yellow"}], + + [{"coverage_type": "o_covered"}, {"symbol": "s"}], + [{"coverage_type": "h_covered"}, {"symbol": "^"}], + + [{"facet": "110"}, {"color1": "red"}], + [{"facet": "211"}, {"color1": "green"}], + [{"facet": "100"}, {"color1": "black"}], + ] + #__| + + #| - Processing Data Points + x_data_list = [] + y_data_list = [] + + for series_i in self.ORR_Free_E_Plot.series_list: + + #| - x-axis energy + x_spec = self.x_ax_species + if x_spec == "o-oh": + e_o = series_i.energy_states_dict["o"] + e_oh = series_i.energy_states_dict["oh"] + x_ax_energy = e_o - e_oh + else: + x_ax_energy = series_i.energy_states_dict[x_spec] + #__| + + #| - y-axis limiting potential + if self.ORR_Free_E_Plot.rxn_type == "ORR": + lim_pot_i = 1.23 - series_i.overpotential + + elif self.ORR_Free_E_Plot.rxn_type == "OER": + lim_pot_i = 1.23 + series_i.overpotential_OER + else: + print("LSDJFlksdj") + #__| + + #| - Process series_i + x_data_list.append(x_ax_energy) + y_data_list.append(lim_pot_i) + + smart_format_i = self.ORR_Free_E_Plot.__create_smart_format_dict__( + series_i.properties, + smart_format_dict, + ) + + name_i = series_i.series_name + + if series_i.color is not None: + smart_format_i[self.marker_color_key] = series_i.color + + + format_i = smart_format_i + + if series_i.format_dict: + format_i = series_i.format_dict + + trace_i = self.__create_trace_i__( + x_ax_energy, + lim_pot_i, + # smart_format_i, + format_i, + name_i, + group=series_i.group, + show_data_labels=show_data_labels, + ) + + self.data_points.append(trace_i) + #__| + + #__| + + #| - Finding plot axis limits + if self.plot_range is None: + y_axis_range = [min(y_data_list) - 0.2, max(y_data_list) + 0.2] + if self.ORR_Free_E_Plot.rxn_type == "OER": + y_axis_range.reverse() + else: + pass + + plot_range = { + "y": y_axis_range, + "x": [min(x_data_list) - 0.2, max(x_data_list) + 0.2], + } + + self.plot_range = plot_range + #__| + + #__| + + def create_volcano_lines(self, + gas_molec_dict=None, + scaling_dict=None, + plot_all_legs=True, + plot_min_max_legs=False, + trace_priority="top", # 'top' or 'bottom' + legs_to_plot=[ + "o2_to_ooh", + "ooh_to_o", + "o_to_oh", + "oh_to_h2o", + ], + line_color="black", + ): + """Create volcano data traces. + + Args: + gas_molec_dict: + scaling_dict: + plot_all_legs: + plot_min_max_legs: + trace_priority: + if 'top', the volcano lines will be placed on the top of the + plot, if 'bottom' then the data points will by on top of the + volcano + """ + #| - create_volcano_lines + out_data = [] + x_range = self.plot_range["x"] + + #| - Volcano Legs + volc_legs = [ + 'o2_to_ooh', + 'ooh_to_o', + 'o_to_oh', + 'oh_to_h2o', + ] + + energy_dict = { + 'o2_to_ooh': [], + 'ooh_to_o': [], + 'o_to_oh': [], + 'oh_to_h2o': [], + } + + #| - Create Volcano Legs (LOOP) + x_axis = np.linspace(x_range[0], x_range[1], num=500) + for leg_i in volc_legs: + for x_energy_i in x_axis: + + if self.x_ax_species == "oh": + g_oh = x_energy_i + g_o_minus_g_oh = None + + elif self.x_ax_species == "o-oh": + g_oh = None + g_o_minus_g_oh = x_energy_i + + energy_dict[leg_i].append( + lim_U_i( + g_oh=g_oh, + g_o_minus_g_oh=g_o_minus_g_oh, + # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' + mech_step=leg_i, + gas_molec_dict=gas_molec_dict, + scaling_dict=scaling_dict, + rxn_direction="forward", + ), + ) + #__| + + if plot_all_legs: + + #| - plot_all_legs + # hoverinfo_type = "none" + hoverinfo_type = "name" + + trace_o2_to_ooh = go.Scatter( + x=x_axis, + y=energy_dict["o2_to_ooh"], + name="O2->*OOH", + hoverinfo=hoverinfo_type, + line=dict( + color="#e7b8bc", + width=2, + dash="solid", + ) + ) + + trace_ooh_to_o = go.Scatter( + x=x_axis, + y=energy_dict["ooh_to_o"], + name="*OOH->*O", + hoverinfo=hoverinfo_type, + line=dict( + color="#afd7c3", + width=2, + dash="solid", + ) + ) + + trace_o_to_oh = go.Scatter( + x=x_axis, + y=energy_dict["o_to_oh"], + name="*O->*OH", + hoverinfo=hoverinfo_type, + line=dict( + color="#b5c4e2", + width=2, + dash="solid", + ) + ) + + trace_oh_to_h2o = go.Scatter( + x=x_axis, + y=energy_dict["oh_to_h2o"], + name="*OH->H2O", + hoverinfo=hoverinfo_type, + line=dict( + color="#dbcdab", + width=2, + dash="solid", + ) + ) + + if trace_priority == "top": + out_data.append(trace_o2_to_ooh) + out_data.append(trace_ooh_to_o) + out_data.append(trace_o_to_oh) + out_data.append(trace_oh_to_h2o) + + elif trace_priority == "bottom": + out_data.insert(0, trace_o2_to_ooh) + out_data.insert(0, trace_ooh_to_o) + out_data.insert(0, trace_o_to_oh) + out_data.insert(0, trace_oh_to_h2o) + #__| + + #__| + + #| - Minimum Energy Legs + energy_lists= [] + for leg_i in legs_to_plot: + energy_lists.append(energy_dict[leg_i]) + + min_max_e_list = [] + for legs in zip(*energy_lists): + if self.ORR_Free_E_Plot.rxn_type == "ORR": + energy_i = min(*legs) + + elif self.ORR_Free_E_Plot.rxn_type == "OER": + energy_i = max(*legs) + + min_max_e_list.append(energy_i) + + trace_volcano = go.Scatter( + x=x_axis, + y=min_max_e_list, + name="activity volcano", + hoverinfo="skip", + line=dict( + color=line_color, + width=2, + # dash="dash", + dash="5px,2px,5px,2px", + ) + ) + + if plot_min_max_legs: + if trace_priority == "top": + out_data.append(trace_volcano) + + elif trace_priority == "bottom": + out_data.insert(0, trace_volcano) + #__| + + return(out_data) + #__| + + def __create_trace_i__(self, + x_energy, + y_energy, + smart_format_i, + name_i, + # legendgroup=None, + group=None, + show_data_labels=False, + ): + """ + """ + #| - __create_trace_i__ + + if show_data_labels is True: + mode_i = "markers+text" + elif show_data_labels is False: + mode_i = "markers" + else: + print("TEMP TEMP TEMP | __create_trace_i__") + + # print(mode_i) + + trace_i = go.Scatter( + x=[x_energy], + y=[y_energy], + + mode=mode_i, + # mode="markers+text", + # mode="markers", + + name=name_i, + text=[name_i], + # text=["TEMP"], + + legendgroup=group, + + hoverinfo="text", + + # hoverinfo=None, + # hoverinfosrc=None, + # hoverlabel=None, + # hoveron=None, + # hovertext=None, + # hovertextsrc=None, + + # textposition='top right', + textposition='middle left', + textfont={ + # "family": "Courier New, monospace", + # "family": font_family, + "size": 10, + "color": "black", + }, + + marker=dict( + size=smart_format_i.get("marker_size", 9), + color=smart_format_i.get(self.marker_color_key, "red"), + symbol=smart_format_i.get( + self.marker_shape_key, "circle"), + line=dict( + width=smart_format_i.get("marker_border_width", 1.), + color=smart_format_i.get( + self.marker_border_color_key, "black"), + ), + ), + ) + + return(trace_i) + #__| + + def get_plotly_layout(self, + showlegend=False, + width=9. * 37.795275591, + height=9. * 37.795275591, + layout_dict=None, + ): + """ + """ + #| - get_plotly_layout + + #| - Properties + # plot_title="FED" + plot_title = None + # plot_title_size = 18 + # tick_lab_size = 9 * (4. / 3.) + tick_lab_size = 8 * (4. / 3.) + axes_lab_size = 9 * (4. / 3.) + legend_size = 18 + # font_family="Computer Modern" # "Courier New, monospace" + font_family = "Arial" # "Courier New, monospace" + #__| + + # self.x_ax_spec + + if self.x_ax_species == "oh": + # xaxis_title = "dG_*OH (eV)" + xaxis_title = "dGOH (eV)" + elif self.x_ax_species == "o-oh": + # xaxis_title = "dG_*OH - dG_*O (eV)" + xaxis_title = "dGO - dGOH (eV)" + + # layout["margin"] = go.layout.Margin( + # b=50., + # l=50., + # r=50., + # t=50., + # # pad=20., + # ) + + layout = { + "title": plot_title, + + "font": { + "family": font_family, + "color": "black", + }, + + #| - Axes ----------------------------------------------------- + + #| - yaxis + "yaxis": { + "title": "Limiting Potential (V)", + # "title": "$\\Delta G (ev)$", + + "range": self.plot_range["y"], + "zeroline": False, + "showline": True, + "mirror": 'ticks', + # "linecolor": 'red', + "linecolor": 'black', + "showgrid": False, + + "titlefont": dict(size=axes_lab_size), + + "tickfont": dict( + size=tick_lab_size, + ), + "ticks": 'inside', + "tick0": 0, + "tickcolor": 'black', + "dtick": 0.1, + "ticklen": 2, + "tickwidth": 1, + }, + #__| + + #| - xaxis + "xaxis": { + # "title": "$\\Delta G_{OH} (ev)$", + "title": xaxis_title, + "range": self.plot_range["x"], + "zeroline": False, + "showline": True, + "mirror": True, + # "linecolor": 'red', + "linecolor": 'black', + "showgrid": False, + "titlefont": dict(size=axes_lab_size), + "showticklabels": True, + "ticks": 'inside', + "tick0": 0, + "dtick": 0.2, + "ticklen": 2, + "tickwidth": 1, + "tickcolor": 'black', + "tickfont": dict( + size=tick_lab_size, + ), + }, + #__| + + #__| + + "margin": go.layout.Margin( + b=50., + l=50., + r=50., + t=50., + ), + + # "paper_bgcolor": 'rgba(0,0,0,0)', + "plot_bgcolor": 'rgba(0,0,0,0)', + + #| - Legend --------------------------------------------------- + "legend": { + "traceorder": "normal", + "font": dict(size=legend_size), + "x": 0., + "y": -0.1, + # "xanchor": "left", + "yanchor": "top", + }, + + # "showlegend": False, + "showlegend": showlegend, + + #__| + + } + + #| - Plot Size Settings + # bottom_margin_size = 2.5 * 9. * 37.795275591 + plot_size_settings = { + "width": width, + "height": height, + + # "width": 9. * 37.795275591, + # "height": 9 * 37.795275591, + + # "margin": go.layout.Margin({ + # "l": 50, + # "r": 50, + # # "b": bottom_margin_size, + # # "b": 100, + # "b": 1200, + # "t": 10, + # "pad": 4, + # }), + } + + #__| + + layout = {**layout, **plot_size_settings} + + #| - Applying Layout override dict + if layout_dict is not None: + from misc_modules.misc_methods import dict_merge + dict_merge(layout, layout_dict) + + # layout_i = {**layout_i, **layout_dict} + + #__| + + return(layout) + + #__| + + + #__| ********************************************************************** diff --git a/oxr_reaction/oxr_rxn.py b/oxr_reaction/oxr_rxn.py new file mode 100644 index 0000000..ec8e56c --- /dev/null +++ b/oxr_reaction/oxr_rxn.py @@ -0,0 +1,1522 @@ +#!/usr/bin/env python + +"""ORR energetics classes and methods. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import numpy as np +import pandas as pd + +from sklearn.linear_model import LinearRegression + +import plotly.graph_objs as go + +pd.options.mode.chained_assignment = None + +from oxr_reaction.oxr_series import ORR_Free_E_Series +from oxr_reaction.adsorbate_scaling import lim_U_i +#__| + + +class ORR_Free_E_Plot: + """ORR free energy diagram class. + + ACTUALLY THIS IS GOING TO BE A GENERAL ORR/OER CLASS NOW!!!!!!!!!!!!!!!!!!! + + Development Notes: + # TODO Should we consider the case where the bulk energy is not 0, and + we have to normalize all of the species energies by it? + """ + + #| - ORR_Free_E_Plot ****************************************************** + + def __init__(self, + free_energy_df=None, + ORR_Free_E_series_list=None, + state_title="adsorbate", + free_e_title="ads_e", + num_states=5, + smart_format=None, + bias=0., + color_list=None, + hover_text_col=None, + rxn_type="ORR", # ORR and OER + + # system_properties=None, + # opt_name=None, + # properties=None, + # i_cnt=0, + # plot_mode="all", + # smart_format=None, + # Plotting ************************************************************ + # show_H_e_pairs_annotations=True, + # show_legend=True, + ): + """ + Input variables to class instance. + + Args: + free_energy_df: + Pandas dataframe containing the adsorbates as rows + Required columns, adsorbate, free energy + system_properties: + state_title: + free_e_title: + + rxn_type: + ORR or OER + """ + #| - __init__ + + #| - Setting Instance Attributes + self.fe_df = free_energy_df + # self.sys_props = system_properties + self.state_title = state_title + self.fe_title = free_e_title + self.num_states = num_states + + # self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] + # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] #COMBAK Is this being used anymore + + self.bias = bias + self.color_list = color_list + self.hover_text_col = hover_text_col + self.smart_format = smart_format + + # self.show_H_e_pairs_annotations = show_H_e_pairs_annotations + # self.show_legend = show_legend + + # *********************************** + # COMBAK, moving to FED class, remove later + self.plot_states_sep = 0.3 + self.plot_states_width = 1. + + self.rxn_type = rxn_type + #__| + + + if self.rxn_type == "ORR": + self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] + self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] + + elif self.rxn_type == "OER": + self.rxn_mech_states = ["bulk", "oh", "o", "ooh", "bulk"] + self.ideal_energy = [0, 1.23, 2.46, 3.69, 4.92] + + # self.rxn_x_coord_array = self.create_rxn_coord_array( + # self.num_states, + # spacing=self.plot_states_sep, + # step_size=self.plot_states_width, + # ) + # + # self.mid_state_x_array = self.create_mid_state_x_array() + # # x_array_data = self.rxn_x_coord_array + + if ORR_Free_E_series_list is None: + self.series_list = [] + else: + self.series_list = ORR_Free_E_series_list + + #| - __old__ + # if free_energy_df is not None: + # self.add_bulk_entry() + # self.fill_missing_data() + # + # self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk + # self.energy_lst = self.rxn_energy_lst() + # self.num_of_elec = range(self.num_of_states)[::-1] + # self.overpotential = self.calc_overpotential()[0] + # self.limiting_step = self.calc_overpotential()[1] + # # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] + # self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() + # self.overpotential_h2o2 = self.calc_overpotential_h2o2() + #__| + + #__| + + def __create_series_name__(self, series_i): + """ + """ + #| - __create_series_name__ + + if series_i.properties is not None: + name_i = "" + for key, value in series_i.properties.items(): + + # TODO | This is an old feature, get rid of it + if key == "coverage": + continue + + name_i += str(key) + ": " + str(value) + " | " + + else: + name_i = "" + + return(name_i) + #__| + + def __create_smart_format_dict__(self, property_dict, smart_format_dict): + """Create smart format dictionary. + + Args: + property_dict: + smart_format_dict: + """ + #| - __create_smart_format_dict__ + if property_dict is None: + return({}) + + format_dict = {} + for key_i, value_i in property_dict.items(): + for format_i in smart_format_dict: + if list(format_i[0])[0] == key_i: + if list(format_i[0].values())[0] == value_i: + format_dict.update(format_i[1]) + + return(format_dict) + #__| + + def add_series(self, + fe_df, + plot_mode="all", + name_i=None, + group=None, + opt_name=None, + smart_format=True, + format_dict=None, + overpotential_type="ORR", + system_properties=None, + property_key_list=None, + add_overpot=True, + color=None, + overpotential_given=False, + ): + """Add ORR_Free_E_Series instance to ORR_Free_E_Plot.series_list. + + Note: It would be much better to simply take all of the + ORR_Free_E_Series arguments as a **kwargs term. + + Args: + TEMP + """ + #| - add_series + if smart_format: + smart_format_i = self.smart_format + else: + smart_format_i = None + + ORR_Series = ORR_Free_E_Series( + free_energy_df=fe_df, + properties=system_properties, + property_key_list=property_key_list, + state_title=self.state_title, + free_e_title=self.fe_title, + group=group, + bias=self.bias, + # rxn_x_coord_array=self.rxn_x_coord_array, + name_i=name_i, + opt_name=opt_name, # ####### + + color_list=self.color_list, + color=color, + hover_text_col=self.hover_text_col, + plot_mode=plot_mode, # ########## + smart_format=smart_format_i, + format_dict=format_dict, + add_overpot=add_overpot, + rxn_type=self.rxn_type, + overpotential_given=overpotential_given, + + # properties=opt_name, + # overpotential_type=self.rxn_type, + # i_cnt=0, # ########## + ) + + self.series_list.append(ORR_Series) + #__| + + #__| ********************************************************************** + + + + + + +#| - __old__ + +# +# # ███████ ██████ ██████ ██ ██████ ████████ +# # ██ ██ ██ ██ ██ ██ ██ ██ ██ +# # ███████ ██████ ██████ ██ ██ ██ ██ +# # ██ ██ ██ ██ ██ ██ ██ ██ +# # ███████ ██ ██ ███████ ██ ███████ ██████ ██ +# +# class Scaling_Relations_Plot(): +# """Plot scaling relations and some simple fitting schemes. +# +# Development Notes: +# IDEA: Add vertical lines to connect *O, *OH, and *OOH data points +# """ +# +# #| - Scaling_Relations_Plot *********************************************** +# +# def __init__(self, +# ORR_Free_E_Plot, +# mode="all", +# +# plot_range={ +# "y": [1., 5.], +# "x": [-2., 4.], +# }, +# +# x_ax_species="oh", +# +# marker_color_key="color2", +# marker_border_color_key="color1", +# marker_shape_key="symbol", +# ): +# """ +# Input variables to class instance. +# +# Args: +# ORR_Free_E_Plot: +# mode: +# "all", "ooh_vs_oh", "o_vs_oh" +# """ +# #| - __init__ +# self.ORR_Free_E_Plot = ORR_Free_E_Plot +# +# assert (x_ax_species == "oh"), "Only *OH as the x-axis is allowed now" +# self.x_ax_species = x_ax_species +# self.marker_color_key = marker_color_key +# self.marker_border_color_key = marker_border_color_key +# self.marker_shape_key = marker_shape_key +# +# # ################################################################# +# +# self.data_points = { +# "ooh_vs_oh": [], +# "o_vs_oh": [], +# "oh_vs_oh": [], +# } +# self.data_lines = [] +# +# self.x_range = plot_range["x"] +# self.y_range = plot_range["y"] +# +# # self.layout = self.__create_layout__( +# # title="Scaling Relations", +# # showlegend=True, +# # ) +# +# self.scaling_dict = { +# "ooh": { +# "m": None, +# "b": None, +# }, +# +# "o": { +# "m": None, +# "b": None, +# }, +# +# "oh": { +# "m": 1., +# "b": 0., +# }, +# +# } +# +# self.annotations_list = [] +# +# #__| +# +# def create_scaling_relations_plot(self, +# smart_format_dict=None, +# ): +# """Return plotly data and layout objects for scaling relations. +# +# Args: +# y_ax_spec: +# x_ax_spec: +# """ +# #| - create_scaling_relations_plot +# +# #| - Default Smart Format Dict +# if smart_format_dict is None: +# print("No smart format given!") +# smart_format_dict = [ +# [{"bulk_system": "IrO3"}, {self.marker_color_key: "green"}], +# [{"bulk_system": "IrO2"}, {self.marker_color_key: "yellow"}], +# +# [{"coverage_type": "o_covered"}, {self.marker_shape_key: "s"}], +# [{"coverage_type": "h_covered"}, {self.marker_shape_key: "^"}], +# +# [{"facet": "110"}, {self.marker_border_color_key: "red"}], +# [{"facet": "211"}, {self.marker_border_color_key: "green"}], +# [{"facet": "100"}, {self.marker_border_color_key: "black"}], +# ] +# #__| +# +# #| - Processing Data Points +# for series_i in self.ORR_Free_E_Plot.series_list: +# +# e_oh = series_i.energy_states_dict["oh"] +# e_ooh = series_i.energy_states_dict["ooh"] +# e_o = series_i.energy_states_dict["o"] +# +# +# # Change self.__create_smart_format_dict__ to, +# # self.ORR_Free_E_Plot.__create_smart_format_dict__ +# # TODO +# +# smart_format_i = self.ORR_Free_E_Plot.__create_smart_format_dict__( +# series_i.properties, +# smart_format_dict, +# ) +# +# # This is the old way of getting the name +# # name_i = self.ORR_Free_E_Plot.__create_series_name__(series_i) +# +# name_i = series_i.series_name +# +# if series_i.color is not None: +# smart_format_i[self.marker_color_key] = series_i.color +# +# # NEW, if series has format attached just use that +# if series_i.format_dict: +# smart_format_i = series_i.format_dict +# +# +# #| - ooh_vs_oh +# trace_i = self.__create_trace_i__( +# e_oh, +# e_ooh, +# smart_format_i, +# name_i, +# legendgroup="ooh_vs_oh", +# ) +# # self.data_ooh_oh.append(trace_i) +# self.data_points["ooh_vs_oh"].append(trace_i) +# #__| +# +# #| - o_vs_oh +# trace_i = self.__create_trace_i__( +# e_oh, +# e_o, +# smart_format_i, +# name_i, +# legendgroup="o_vs_oh", +# ) +# # self.data_o_oh.append(trace_i) +# self.data_points["o_vs_oh"].append(trace_i) +# #__| +# +# #| - oh_vs_oh +# trace_i = self.__create_trace_i__( +# e_oh, +# e_oh, +# smart_format_i, +# name_i, +# legendgroup="oh_vs_oh", +# ) +# # self.data_oh_oh.append(trace_i) +# self.data_points["oh_vs_oh"].append(trace_i) +# #__| +# +# #__| +# +# #__| +# +# # Deprecated, delete this later +# def __create_smart_format_dict__(self, property_dict, smart_format_dict): +# """Create smart format dictionary. +# +# Args: +# property_dict: +# smart_format_dict: +# """ +# #| - __create_smart_format_dict__ +# format_dict = {} +# for key_i, value_i in property_dict.items(): +# for format_i in smart_format_dict: +# if list(format_i[0])[0] == key_i: +# if list(format_i[0].values())[0] == value_i: +# format_dict.update(format_i[1]) +# +# return(format_dict) +# #__| +# +# def __create_series_name__(self, series_i): +# """ +# """ +# #| - create_series_name +# name_i = "" +# for key, value in series_i.properties.items(): +# if key == "coverage": +# continue +# +# name_i += str(key) + ": " + str(value) + " | " +# +# return(name_i) +# #__| +# +# def __create_trace_i__(self, +# x_energy, +# y_energy, +# smart_format_i, +# name_i, +# legendgroup=None, +# ): +# """ +# """ +# #| - create_trace_i +# # NOTE Looks like I need to put these in a list here +# x_energy = [x_energy] +# y_energy = [y_energy] +# +# trace_i = go.Scatter( +# x=x_energy, +# y=y_energy, +# text=name_i, +# name=name_i, +# mode="markers", +# legendgroup=legendgroup, +# marker=dict( +# size=smart_format_i.get("marker_size", 9), +# symbol=smart_format_i.get( +# self.marker_shape_key, "circle"), +# color=smart_format_i.get( +# self.marker_color_key, "pink"), +# line=dict( +# # color=smart_format_i[marker_border_color_key], +# color=smart_format_i.get( +# self.marker_border_color_key, "black"), +# width=1., +# ) +# ) +# ) +# +# return(trace_i) +# #__| +# +# # NOTE | This shouldn't be an internal method +# def __create_layout__(self, +# # x_ax_spec="oh", +# title="Scaling Relations", +# showlegend=True, +# layout_dict=None, +# ): +# """Create plotly layout dict. +# +# Args: +# x_ax_spec: +# title: +# showlegend: +# """ +# #| - create_layout +# +# # if x_ax_spec == "" +# if self.x_ax_species == "oh": +# x_ax_title = "Gads,*OH (eV)" +# else: +# x_ax_title = "TEMP" +# +# y_ax_title = "Gads,*OH, " + \ +# "Gads,*O, " + \ +# "Gads,*OOH (eV)" +# +# tick_lab_size = 12 * (4. / 3.) +# axes_lab_size = 14 * (4. / 3.) +# +# # legend_size = 18 +# +# #| - Common Axis Dict +# common_axis_dict = { +# +# # "range": y_axis_range, +# "zeroline": False, +# "showline": True, +# "mirror": 'ticks', +# "linecolor": 'black', +# "showgrid": False, +# +# "titlefont": dict(size=axes_lab_size), +# "tickfont": dict( +# size=tick_lab_size, +# ), +# "ticks": 'inside', +# "tick0": 0, +# "tickcolor": 'black', +# # "dtick": 0.25, +# "ticklen": 2, +# "tickwidth": 1, +# } +# #__| +# +# #| - __old__ +# # x_range_ooh_vs_oh=[0., 3.5], +# # y_range_ooh_vs_oh=[0., 5.], +# # x_range_o_vs_oh=[0., 3.5], +# # y_range_o_vs_oh=[0., 5.], +# +# # if y_ax_spec == "ooh": +# # x_range = self.x_range_ooh_vs_oh +# # elif y_ax_spec == "o": +# # x_range = self.x_range_o_vs_oh +# # elif y_ax_spec == "oh": +# # x_range = self.x_range_oh_vs_oh +# # else: +# # print("Woops - create_layout") +# # +# # if y_ax_spec == "ooh": +# # y_range = self.y_range_ooh_vs_oh +# # elif y_ax_spec == "o": +# # y_range = self._range_o_vs_oh +# # elif y_ax_spec == "oh": +# # y_range = self.y_range_oh_vs_oh +# # else: +# # print("Woops - create_layout") +# #__| +# +# x_range = self.x_range +# y_range = self.y_range +# +# layout_i = { +# "title": title, +# "titlefont": go.layout.title.Font(size=24), +# # "titlefont": go.layout.Titlefont(size=24), +# +# "xaxis": dict( +# common_axis_dict, +# **{ +# "title": x_ax_title, +# "range": x_range, +# }, +# ), +# +# "yaxis": dict( +# common_axis_dict, +# **{ +# "title": y_ax_title, +# "range": y_range, +# }, +# ), +# +# # Margin +# "margin": go.layout.Margin( +# b=50., +# l=50., +# r=50., +# t=50., +# ), +# +# "font": dict( +# family='Arial', +# # size=18, +# color='black', +# ), +# +# "width": 1.5 * 18.7 * 37.795275591, +# "height": 18.7 * 37.795275591, +# +# "showlegend": showlegend, +# +# "legend": dict( +# font=dict( +# size=10, +# ), +# ), +# } +# +# if layout_dict is not None: +# from misc_modules.misc_methods import dict_merge +# dict_merge(layout_i, layout_dict) +# # layout_i = {**layout_i, **layout_dict} +# +# return(layout_i) +# #__| +# +# def __series_excluded__(self, +# properties_i, +# exclude_dict, +# ): +# """Whether to exclude series_i from fitting. +# +# Takes an 'exclude_dict' and the series properties_dict and compares +# them key-by-key. If there is a match, then that series is excluded +# (and the function evaluates to True) +# +# Args: +# properties_i: +# exclude_dict: +# """ +# #| - series_excluded +# exclude_dict_keys = list(exclude_dict.keys()) +# properties_i_keys = list(properties_i.keys()) +# +# shared_keys = list( +# set(exclude_dict_keys).intersection(set(properties_i_keys)), +# ) +# +# if len(shared_keys) < len(exclude_dict_keys): +# print("series_i doesn't have a specific key!") +# +# value_match_list = [] +# for key_i in shared_keys: +# value_match_i = exclude_dict[key_i] == properties_i[key_i] +# value_match_list.append(value_match_i) +# +# +# all_props_match = all(value_match_list) +# +# # if all_props_match: +# # print("Ignoring this series for fitting") +# # +# # else: +# # print("Series not excluded, will include in fitting set") +# +# +# return(all_props_match) +# +# #__| +# +# def fit_scaling_lines(self, +# dependent_species, # 'ooh', 'o', 'oh' +# exclude_dict=None, +# ): +# """Linear fit of either *O or *OOH to *OH +# +# Args: +# dependent_species: +# y-axis species 'ooh' or 'o' +# """ +# #| - fit_scaling_lines +# +# #| - LOOP +# oh_list = [] +# dependent_e_list = [] +# for series_i in self.ORR_Free_E_Plot.series_list: +# +# #| - Excluding series from fitting +# if exclude_dict is not None: +# properties_i = series_i.properties +# exclude_series = self.__series_excluded__( +# properties_i, +# exclude_dict, +# ) +# if exclude_series: +# continue +# #__| +# +# energy_i = series_i.energy_states_dict[dependent_species] +# dependent_e_list.append(energy_i) +# oh_list.append(series_i.energy_states_dict["oh"]) +# +# #__| +# +# X = np.array([[i] for i in oh_list]) +# y = np.array(dependent_e_list) +# +# reg = LinearRegression().fit(X, y) +# +# slope_i = reg.coef_[0] +# intercept_i = reg.intercept_ +# +# print("Scaling fit for ", dependent_species) +# print("intercept_i: ", str(intercept_i)) +# print("slope_i: ", str(slope_i)) +# print("") +# +# out = {"slope": slope_i, "intercept": intercept_i} +# +# self.scaling_dict[dependent_species] = { +# "m": slope_i, +# "b": intercept_i, +# } +# # print("_------__)_Z(*XF(8))") +# +# #| - Equation Annotations +# if dependent_species == "ooh": +# eqn_str_i = ("" + +# "GOOH=" + +# str(round(slope_i, 4)) + +# " GOH+" + +# str(round(intercept_i, 4)) + +# "" +# ) +# +# elif dependent_species == "o": +# eqn_str_i = ("" + +# "GO = " + +# str(round(slope_i, 4)) + +# " GOH+" + +# str(round(intercept_i, 4)) + +# "" +# ) +# +# elif dependent_species == "oh": +# eqn_str_i = ("" + +# "GOH = " + +# str(round(slope_i, 4)) + +# " GOH+" + +# str(round(intercept_i, 4)) + +# "" +# ) +# +# else: +# eqn_str_i = "TEMP TEMP TEMP TEMP | 190213 | RF" +# raise ValueError('A very specific bad thing happened.') +# +# annotation_i = dict( +# x=0., +# y=1., +# xref="paper", +# yref="paper", +# text=eqn_str_i, +# font=dict( +# color="red", +# family="Droid Sans Mono,Overpass", +# size=9. * (4. / 3.), +# ), +# showarrow=False, +# xanchor="left", +# yshift=-11. * (4. / 3.) * len(self.annotations_list), +# xshift=5., +# ) +# +# self.annotations_list.append(annotation_i) +# #__| +# +# +# return(out) +# #__| +# +# def add_ideal_lines(self): +# """Add ideal scaling liknes to plot.""" +# #| - add_ideal_lines +# self.add_line({"slope": 1, "intercept": 3.2}, +# name="*OOH vs *OH Scaling", +# color="black", +# width=1, +# dash="dash", +# ) +# +# self.add_line({"slope": 2, "intercept": 0.}, +# name="*O vs *OH Scaling", +# color="black", +# width=1, +# dash="dash", +# ) +# +# self.add_line({"slope": 1, "intercept": 0.}, +# name="*OH vs *OH Scaling", +# color="black", +# width=1, +# dash="dash", +# ) +# #__| +# +# def add_line(self, +# slope_intercept_dict, +# name="add_lines - TEMP", +# color="black", +# width=1, +# dash="dash", +# ): +# """Add line of form y=mx+b to plot. +# +# Args: +# slope_intercept_dict: +# name: +# color: +# width: +# dash: +# """ +# #| - add_line +# +# # print(slope_intercept_dict) +# +# slope = slope_intercept_dict["slope"] +# intercept = slope_intercept_dict["intercept"] +# +# def scaling_meth(E_OH): +# """ +# """ +# #| - scaling_meth +# out = slope * E_OH + intercept +# +# return(out) +# #__| +# +# LH_bound = self.x_range[0] +# RH_bound = self.x_range[1] +# +# scaling_trace = go.Scatter( +# # x=[self.x_range_ooh_vs_oh[0], self.x_range_ooh_vs_oh[1]], +# x=[LH_bound, RH_bound], +# y=[ +# scaling_meth(LH_bound), +# scaling_meth(RH_bound), +# ], +# # name='Fitted scaling', +# name=name, +# mode='lines', +# line=dict( +# dash=dash, +# color=color, +# width=width, +# ), +# ) +# # self.data_ooh_oh.append(scaling_trace) +# self.data_lines.append(scaling_trace) +# +# # +# # # Annotation +# # ooh_vs_oh_eqn = ("" + +# # "G_*OOH = " + +# # str(round(SC_PLT.scaling_dict["ooh"]["m"], 5)) + +# # " G_*OH + " + +# # str(round(SC_PLT.scaling_dict["ooh"]["b"], 5)) + +# # "" +# # ) +# # +# # o_vs_oh_eqn = ("" + +# # "G_*O = " + +# # str(round(SC_PLT.scaling_dict["o"]["m"], 5)) + +# # " G_*OH + " + +# # str(round(SC_PLT.scaling_dict["o"]["b"], 5)) + +# # "" +# # ) +# +# #__| +# +# +# +# +# +# #| - __old__ +# # def __ideal_ooh_oh_scaling__(self, E_OH): +# # """Return the *OOH adsorption energy given DG_*OH by scaling. +# # +# # Args: +# # E_OH:DG_*OH energy of adsorption +# # """ +# # #| - __ideal_ooh_oh_scaling__ +# # return(E_OH + 3.2) +# # #__| +# # +# # def __ideal_h_oh_scaling__(self, E_OH): +# # """Return the *OOH adsorption energy given DG_*OH by scaling. +# # +# # Args: +# # E_OH: DG_*OH energy of adsorption. +# # """ +# # #| - __ideal_h_oh_scaling__ +# # return(2 * E_OH) +# # #__| +# # +# # def __ideal_oh_oh_scaling__(self, E_OH): +# # """Return the *OH adsorption energy given DG_*OH by scaling. +# # +# # NOTE: TRIVIAL QUANTITY!!!!!!!!!!!!!!!!!!! +# # +# # Args: +# # E_OH: DG_*OH energy of adsorption. +# # """ +# # #| - __ideal_oh_oh_scaling__ +# # return(E_OH) +# # #__| +# # +# #__| +# +# #__| ********************************************************************** + + + + +# # ██ ██ ██████ ██ ██████ ██████ ██ ██████ ████████ +# # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +# # ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ +# # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +# # ████ ██████ ███████ ██████ ███████ ██ ███████ ██████ ██ +# +# class Volcano_Plot(): +# """Class to plot OER/ORR volcano plots. +# +# Development Notes: +# TEMP +# """ +# +# #| - Volcano_Plot ********************************************************* +# +# def __init__(self, +# ORR_Free_E_Plot, +# x_ax_species="o-oh", # 'o-oh' or 'oh' +# smart_format_dict=None, +# plot_range=None, +# marker_color_key="color2", +# marker_border_color_key="color1", +# marker_shape_key="symbol", +# ): +# """ +# Input variables to class instance. +# +# Args: +# ORR_Free_E_Plot: +# mode: +# "all", "ooh_vs_oh", "o_vs_oh" +# plot_range: +# Ex.) +# plot_range={ +# "y": [1., 5.], +# "x": [-2., 4.], +# } +# +# """ +# #| - __init__ +# self.ORR_Free_E_Plot = ORR_Free_E_Plot +# self.x_ax_species = x_ax_species +# self.plot_range = plot_range +# self.smart_format_dict = smart_format_dict +# +# self.data_points = [] +# self.data_lines = [] +# +# self.marker_color_key = marker_color_key +# self.marker_border_color_key = marker_border_color_key +# self.marker_shape_key = marker_shape_key +# +# #__| +# +# # NOTE | Rename this create_volcano_plot +# def create_volcano_relations_plot(self, +# show_data_labels=False, +# # smart_format_dict=None, +# ): +# """Create ORR/OER volcano plot. +# +# Args: +# smart_format_dict: +# Optional dictionary that will format data points +# """ +# #| - create_volcano_relations_plot +# +# #| - Default Smart Format Dict +# smart_format_dict = self.smart_format_dict +# +# if smart_format_dict is None: +# print("No smart format given!") +# smart_format_dict = [ +# [{"bulk_system": "IrO3"}, {self.marker_color_key: "green"}], +# [{"bulk_system": "IrO2"}, {self.marker_color_key: "yellow"}], +# +# [{"coverage_type": "o_covered"}, {"symbol": "s"}], +# [{"coverage_type": "h_covered"}, {"symbol": "^"}], +# +# [{"facet": "110"}, {"color1": "red"}], +# [{"facet": "211"}, {"color1": "green"}], +# [{"facet": "100"}, {"color1": "black"}], +# ] +# #__| +# +# #| - Processing Data Points +# x_data_list = [] +# y_data_list = [] +# +# for series_i in self.ORR_Free_E_Plot.series_list: +# +# #| - x-axis energy +# x_spec = self.x_ax_species +# if x_spec == "o-oh": +# e_o = series_i.energy_states_dict["o"] +# e_oh = series_i.energy_states_dict["oh"] +# x_ax_energy = e_o - e_oh +# else: +# x_ax_energy = series_i.energy_states_dict[x_spec] +# #__| +# +# #| - y-axis limiting potential +# if self.ORR_Free_E_Plot.rxn_type == "ORR": +# lim_pot_i = 1.23 - series_i.overpotential +# +# elif self.ORR_Free_E_Plot.rxn_type == "OER": +# lim_pot_i = 1.23 + series_i.overpotential_OER +# else: +# print("LSDJFlksdj") +# #__| +# +# #| - Process series_i +# x_data_list.append(x_ax_energy) +# y_data_list.append(lim_pot_i) +# +# smart_format_i = self.ORR_Free_E_Plot.__create_smart_format_dict__( +# series_i.properties, +# smart_format_dict, +# ) +# +# name_i = series_i.series_name +# +# if series_i.color is not None: +# smart_format_i[self.marker_color_key] = series_i.color +# +# +# format_i = smart_format_i +# +# if series_i.format_dict: +# format_i = series_i.format_dict +# +# trace_i = self.__create_trace_i__( +# x_ax_energy, +# lim_pot_i, +# # smart_format_i, +# format_i, +# name_i, +# group=series_i.group, +# show_data_labels=show_data_labels, +# ) +# +# self.data_points.append(trace_i) +# #__| +# +# #__| +# +# #| - Finding plot axis limits +# if self.plot_range is None: +# y_axis_range = [min(y_data_list) - 0.2, max(y_data_list) + 0.2] +# if self.ORR_Free_E_Plot.rxn_type == "OER": +# y_axis_range.reverse() +# else: +# pass +# +# plot_range = { +# "y": y_axis_range, +# "x": [min(x_data_list) - 0.2, max(x_data_list) + 0.2], +# } +# +# self.plot_range = plot_range +# #__| +# +# #__| +# +# def create_volcano_lines(self, +# gas_molec_dict=None, +# scaling_dict=None, +# plot_all_legs=True, +# plot_min_max_legs=False, +# trace_priority="top", # 'top' or 'bottom' +# legs_to_plot=[ +# "o2_to_ooh", +# "ooh_to_o", +# "o_to_oh", +# "oh_to_h2o", +# ], +# line_color="black", +# ): +# """Create volcano data traces. +# +# Args: +# gas_molec_dict: +# scaling_dict: +# plot_all_legs: +# plot_min_max_legs: +# trace_priority: +# if 'top', the volcano lines will be placed on the top of the +# plot, if 'bottom' then the data points will by on top of the +# volcano +# """ +# #| - create_volcano_lines +# out_data = [] +# x_range = self.plot_range["x"] +# +# #| - Volcano Legs +# volc_legs = [ +# 'o2_to_ooh', +# 'ooh_to_o', +# 'o_to_oh', +# 'oh_to_h2o', +# ] +# +# energy_dict = { +# 'o2_to_ooh': [], +# 'ooh_to_o': [], +# 'o_to_oh': [], +# 'oh_to_h2o': [], +# } +# +# #| - Create Volcano Legs (LOOP) +# x_axis = np.linspace(x_range[0], x_range[1], num=500) +# for leg_i in volc_legs: +# for x_energy_i in x_axis: +# +# if self.x_ax_species == "oh": +# g_oh = x_energy_i +# g_o_minus_g_oh = None +# +# elif self.x_ax_species == "o-oh": +# g_oh = None +# g_o_minus_g_oh = x_energy_i +# +# energy_dict[leg_i].append( +# lim_U_i( +# g_oh=g_oh, +# g_o_minus_g_oh=g_o_minus_g_oh, +# # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' +# mech_step=leg_i, +# gas_molec_dict=gas_molec_dict, +# scaling_dict=scaling_dict, +# rxn_direction="forward", +# ), +# ) +# #__| +# +# if plot_all_legs: +# +# #| - plot_all_legs +# # hoverinfo_type = "none" +# hoverinfo_type = "name" +# +# trace_o2_to_ooh = go.Scatter( +# x=x_axis, +# y=energy_dict["o2_to_ooh"], +# name="O2->*OOH", +# hoverinfo=hoverinfo_type, +# line=dict( +# color="#e7b8bc", +# width=2, +# dash="solid", +# ) +# ) +# +# trace_ooh_to_o = go.Scatter( +# x=x_axis, +# y=energy_dict["ooh_to_o"], +# name="*OOH->*O", +# hoverinfo=hoverinfo_type, +# line=dict( +# color="#afd7c3", +# width=2, +# dash="solid", +# ) +# ) +# +# trace_o_to_oh = go.Scatter( +# x=x_axis, +# y=energy_dict["o_to_oh"], +# name="*O->*OH", +# hoverinfo=hoverinfo_type, +# line=dict( +# color="#b5c4e2", +# width=2, +# dash="solid", +# ) +# ) +# +# trace_oh_to_h2o = go.Scatter( +# x=x_axis, +# y=energy_dict["oh_to_h2o"], +# name="*OH->H2O", +# hoverinfo=hoverinfo_type, +# line=dict( +# color="#dbcdab", +# width=2, +# dash="solid", +# ) +# ) +# +# if trace_priority == "top": +# out_data.append(trace_o2_to_ooh) +# out_data.append(trace_ooh_to_o) +# out_data.append(trace_o_to_oh) +# out_data.append(trace_oh_to_h2o) +# +# elif trace_priority == "bottom": +# out_data.insert(0, trace_o2_to_ooh) +# out_data.insert(0, trace_ooh_to_o) +# out_data.insert(0, trace_o_to_oh) +# out_data.insert(0, trace_oh_to_h2o) +# #__| +# +# #__| +# +# #| - Minimum Energy Legs +# energy_lists= [] +# for leg_i in legs_to_plot: +# energy_lists.append(energy_dict[leg_i]) +# +# min_max_e_list = [] +# for legs in zip(*energy_lists): +# if self.ORR_Free_E_Plot.rxn_type == "ORR": +# energy_i = min(*legs) +# +# elif self.ORR_Free_E_Plot.rxn_type == "OER": +# energy_i = max(*legs) +# +# min_max_e_list.append(energy_i) +# +# trace_volcano = go.Scatter( +# x=x_axis, +# y=min_max_e_list, +# name="activity volcano", +# hoverinfo="skip", +# line=dict( +# color=line_color, +# width=2, +# # dash="dash", +# dash="5px,2px,5px,2px", +# ) +# ) +# +# if plot_min_max_legs: +# if trace_priority == "top": +# out_data.append(trace_volcano) +# +# elif trace_priority == "bottom": +# out_data.insert(0, trace_volcano) +# #__| +# +# return(out_data) +# #__| +# +# def __create_trace_i__(self, +# x_energy, +# y_energy, +# smart_format_i, +# name_i, +# # legendgroup=None, +# group=None, +# show_data_labels=False, +# ): +# """ +# """ +# #| - __create_trace_i__ +# +# if show_data_labels is True: +# mode_i = "markers+text" +# elif show_data_labels is False: +# mode_i = "markers" +# else: +# print("TEMP TEMP TEMP | __create_trace_i__") +# +# # print(mode_i) +# +# trace_i = go.Scatter( +# x=[x_energy], +# y=[y_energy], +# +# mode=mode_i, +# # mode="markers+text", +# # mode="markers", +# +# name=name_i, +# text=[name_i], +# # text=["TEMP"], +# +# legendgroup=group, +# +# hoverinfo="text", +# +# # hoverinfo=None, +# # hoverinfosrc=None, +# # hoverlabel=None, +# # hoveron=None, +# # hovertext=None, +# # hovertextsrc=None, +# +# # textposition='top right', +# textposition='middle left', +# textfont={ +# # "family": "Courier New, monospace", +# # "family": font_family, +# "size": 10, +# "color": "black", +# }, +# +# marker=dict( +# size=smart_format_i.get("marker_size", 9), +# color=smart_format_i.get(self.marker_color_key, "red"), +# symbol=smart_format_i.get( +# self.marker_shape_key, "circle"), +# line=dict( +# width=smart_format_i.get("marker_border_width", 1.), +# color=smart_format_i.get( +# self.marker_border_color_key, "black"), +# ), +# ), +# ) +# +# return(trace_i) +# #__| +# +# def get_plotly_layout(self, +# showlegend=False, +# width=9. * 37.795275591, +# height=9. * 37.795275591, +# layout_dict=None, +# ): +# """ +# """ +# #| - get_plotly_layout +# +# #| - Properties +# # plot_title="FED" +# plot_title = None +# # plot_title_size = 18 +# # tick_lab_size = 9 * (4. / 3.) +# tick_lab_size = 8 * (4. / 3.) +# axes_lab_size = 9 * (4. / 3.) +# legend_size = 18 +# # font_family="Computer Modern" # "Courier New, monospace" +# font_family = "Arial" # "Courier New, monospace" +# #__| +# +# # self.x_ax_spec +# +# if self.x_ax_species == "oh": +# # xaxis_title = "dG_*OH (eV)" +# xaxis_title = "dGOH (eV)" +# elif self.x_ax_species == "o-oh": +# # xaxis_title = "dG_*OH - dG_*O (eV)" +# xaxis_title = "dGO - dGOH (eV)" +# +# # layout["margin"] = go.layout.Margin( +# # b=50., +# # l=50., +# # r=50., +# # t=50., +# # # pad=20., +# # ) +# +# layout = { +# "title": plot_title, +# +# "font": { +# "family": font_family, +# "color": "black", +# }, +# +# #| - Axes ----------------------------------------------------- +# +# #| - yaxis +# "yaxis": { +# "title": "Limiting Potential (V)", +# # "title": "$\\Delta G (ev)$", +# +# "range": self.plot_range["y"], +# "zeroline": False, +# "showline": True, +# "mirror": 'ticks', +# # "linecolor": 'red', +# "linecolor": 'black', +# "showgrid": False, +# +# "titlefont": dict(size=axes_lab_size), +# +# "tickfont": dict( +# size=tick_lab_size, +# ), +# "ticks": 'inside', +# "tick0": 0, +# "tickcolor": 'black', +# "dtick": 0.1, +# "ticklen": 2, +# "tickwidth": 1, +# }, +# #__| +# +# #| - xaxis +# "xaxis": { +# # "title": "$\\Delta G_{OH} (ev)$", +# "title": xaxis_title, +# "range": self.plot_range["x"], +# "zeroline": False, +# "showline": True, +# "mirror": True, +# # "linecolor": 'red', +# "linecolor": 'black', +# "showgrid": False, +# "titlefont": dict(size=axes_lab_size), +# "showticklabels": True, +# "ticks": 'inside', +# "tick0": 0, +# "dtick": 0.2, +# "ticklen": 2, +# "tickwidth": 1, +# "tickcolor": 'black', +# "tickfont": dict( +# size=tick_lab_size, +# ), +# }, +# #__| +# +# #__| +# +# "margin": go.layout.Margin( +# b=50., +# l=50., +# r=50., +# t=50., +# ), +# +# # "paper_bgcolor": 'rgba(0,0,0,0)', +# "plot_bgcolor": 'rgba(0,0,0,0)', +# +# #| - Legend --------------------------------------------------- +# "legend": { +# "traceorder": "normal", +# "font": dict(size=legend_size), +# "x": 0., +# "y": -0.1, +# # "xanchor": "left", +# "yanchor": "top", +# }, +# +# # "showlegend": False, +# "showlegend": showlegend, +# +# #__| +# +# } +# +# #| - Plot Size Settings +# # bottom_margin_size = 2.5 * 9. * 37.795275591 +# plot_size_settings = { +# "width": width, +# "height": height, +# +# # "width": 9. * 37.795275591, +# # "height": 9 * 37.795275591, +# +# # "margin": go.layout.Margin({ +# # "l": 50, +# # "r": 50, +# # # "b": bottom_margin_size, +# # # "b": 100, +# # "b": 1200, +# # "t": 10, +# # "pad": 4, +# # }), +# } +# +# #__| +# +# layout = {**layout, **plot_size_settings} +# +# #| - Applying Layout override dict +# if layout_dict is not None: +# from misc_modules.misc_methods import dict_merge +# dict_merge(layout, layout_dict) +# +# # layout_i = {**layout_i, **layout_dict} +# +# #__| +# +# return(layout) +# +# #__| +# +# +# #__| ********************************************************************** +#__| diff --git a/oxr_reaction/oxr_series.py b/oxr_reaction/oxr_series.py new file mode 100644 index 0000000..4312a1b --- /dev/null +++ b/oxr_reaction/oxr_series.py @@ -0,0 +1,631 @@ +#!/usr/bin/env python + +"""ORR energetics classes and methods. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import copy + +import numpy as np +import pandas as pd + +from plotly.graph_objs import Scatter +pd.options.mode.chained_assignment = None +#__| + +class ORR_Free_E_Series(): + """ORR free energy diagram series class. + + Still a work in progress + + Take a 2nd look at how the bulk/bare state is being taken care of + + # TODO | The color_list approach is not good + """ + + #| - ORR_Free_E_Series **************************************************** + + def __init__(self, + free_energy_df=None, + state_title="adsorbate", + free_e_title="ads_e", + bias=0., + group=None, + name_i=None, + opt_name=None, + properties=None, + property_key_list=None, + color_list=None, + color=None, + hover_text_col=None, + plot_mode="all", + smart_format=None, + format_dict=None, + add_overpot=True, + rxn_type="ORR", + fill_missing_data_w_scaling=True, + overpotential_given=False, + ): + """ + Input variables to class instance. + + TODO: Make sure that format_dict is used if it's supplied by user + + Args: + free_energy_df: + Pandas dataframe containing the adsorbates as rows + Required columns, adsorbate, free energy + state_title: + free_e_title: + bias: + opt_name: + Optional name + string to append to the beginning of the plot series name + properties: + color_list: + hover_text_col: + plot_mode: + smart_format: + format_dict: + overpotential_given: + If true then the overpotential is given explicitely in the + input dataframe with name "overpotential" + """ + #| - __init__ + + #| - Setting Instance Attributes + self.fe_df = free_energy_df + # self.sys_props = system_properties + + self.group = group + self.state_title = state_title + self.fe_title = free_e_title + + self.bias = bias + + # self.rxn_x_coord_array = rxn_x_coord_array + # print(self.rxn_x_coord_array) # TEMP | PRINT + + self.name_i = name_i + self.opt_name = opt_name + + self.properties = properties + + self.color_list = color_list + self.color = color + self.hover_text_col = hover_text_col + self.plot_mode = plot_mode + self.smart_format = smart_format + self.format_dict = format_dict + + # self.overpotential_type = overpotential_type + self.rxn_type = rxn_type + + self.add_overpot = add_overpot + self.overpotential_given = overpotential_given + + # self.i_cnt = i_cnt + #__| + + if self.rxn_type == "ORR": + self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] + self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] + + elif self.rxn_type == "OER": + self.rxn_mech_states = ["bulk", "oh", "o", "ooh", "bulk"] + self.ideal_energy = [0, 1.23, 2.46, 3.69, 4.92] + + self.property_key_list = property_key_list + + # Doing this with a class method instead of in the analysis script + if properties is None: + self.properties = self.__create_property_dict__() + + if free_energy_df is not None: + self.add_bulk_entry() + self.fill_missing_data() + + # TEMP | Active Development + self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk + self.num_of_states_new = self.__num_of_states__() + + self.energy_lst = self.rxn_energy_lst() + # self.energy_lst_new = self.rxn_energy_lst_new() + + self.num_of_elec = range(self.num_of_states)[::-1] + self.overpotential = self.calc_overpotential()[0] + self.limiting_step = self.calc_overpotential()[1] + # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] + self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() + self.overpotential_h2o2 = self.calc_overpotential_h2o2() + self.overpotential_OER = self.calc_overpotential_OER()[0] + + self.energy_states_dict = self.__energy_states_dict__() + + if fill_missing_data_w_scaling: + self.__fill_nan_values__() + + # TODO | Put this outside of the if-statement + self.series_name = self.__series_plot_name__( + opt_name=self.opt_name, + properties=self.properties, + overpotential_type=self.rxn_type, + add_overpot=self.add_overpot, + ) + #__| + + def __fill_nan_values__(self): + """Fill nan adsorption energy values from scaling relations.""" + #| - tmp + energy_dict = self.energy_states_dict + if True in list(np.isnan(list(energy_dict.values()))): + + print("There is a nan in the energy dict!!!") + + if np.isnan(energy_dict["ooh"]): + if not np.isnan(energy_dict["oh"]): + print("*OOH energy set by *OH and standard scaling") + ooh_new = 1 * energy_dict["oh"] + 3.2 + energy_dict["ooh"] = ooh_new + + if np.isnan(energy_dict["o"]): + if not np.isnan(energy_dict["oh"]): + print("*O energy set by *OH and standard scaling") + o_new = 2 * energy_dict["oh"] + 0. + energy_dict["o"] = o_new + + if np.isnan(energy_dict["oh"]): + if not np.isnan(energy_dict["ooh"]): + print("*OH energy set by *OOH and standard scaling") + oh_new = energy_dict["ooh"] - 3.2 + energy_dict["oh"] = oh_new + + self.energy_states_dict = energy_dict + #__| + + def __num_of_states__(self): + """Return number of unique states. + + Looks at the uniqe number of entries in the 'adsorbate' column of the + data frame. The correct number of states for the OER and/or ORR + reaction are 4, only 2 states are needed for the peroxide reaction. + """ + #| - __num_of_states + df_i = self.fe_df + + num_of_states = len(set(df_i["adsorbate"].tolist())) + + err_mess = "There are not enough unique calcs (less than 4)" + assert num_of_states >= 4, err_mess + + return(num_of_states) + #__| + + def __energy_states_dict__(self): + """ + """ + #| - __energy_states_dict__ + + energy_lst = self.energy_lst + rxn_mech_states = self.rxn_mech_states + + energy_states_dict = dict(zip(rxn_mech_states, energy_lst)) + energy_states_dict.pop("bulk", None) + + return(energy_states_dict) + # energy_states_dict + #__| + + def __create_property_dict__(self): + """ + """ + #| - __create_property_dict__ + df_i = self.fe_df + + def all_same_val(df_i, prop_i, val_1): + """ + """ + #| - all_same_val + out_list = [] + for i in df_i[prop_i].tolist(): + if i == val_1: + out_list.append(True) + else: + out_list.append(False) + + out_i = all(out_list) + return(out_i) + + # [True if i == val_1 else False for i in + # df_i[prop_i].tolist()], + #__| + + if self.property_key_list is not None: + prop_dict_i = {} + for prop_i in self.property_key_list: + val_1 = df_i[prop_i].tolist()[0] + + all_same_value = all_same_val(df_i, prop_i, val_1) + # all_same_value = all( + # [True if i == val_1 else False for i in + # df_i[prop_i].tolist()], + # ) + + if all_same_value: + prop_dict_i[prop_i] = str(val_1) + else: + prop_dict_i[prop_i] = str(None) + + return(prop_dict_i) + else: + return({}) + #__| + + def add_bulk_entry(self, + bulk_e=0.0, + ): + """ + Append a row entry to data frame corresponding to bulk state. + + Args: + bulk_e: + """ + #| - add_bulk_entry + df = self.fe_df + bulk_df = pd.DataFrame([{ + "adsorbate": "bulk", + "ads_e": bulk_e, + }]) + + # TEMP + # df = df.append(bulk_df, ignore_index=True) + df = df.append(bulk_df, ignore_index=True, sort=True) + + self.fe_df = df + #__| + + def rxn_energy_lst_h2o2(self): + """Construct energy list of h2o2 FED.""" + #| - rxn_energy_lst_h2o2 + # h2o2_e = 3.52 + + df = self.fe_df + + free_energy_list = [] + for index, row in df.iterrows(): + if row["adsorbate"] == "bulk" or row["adsorbate"] == "ooh": + free_energy_list.append(row["ads_e"]) + + # TODO | Make this parse the reaction array instead of reaction list + # Checking length of energy list + if len(free_energy_list) != 2: + # raise ValueError("Not the correct # of steps for H2O2") + print("Not the correct # of steps for H2O2") + + free_energy_list[0] += 4.92 + free_energy_list.append(3.52) + + return(free_energy_list) + #__| + + def property_list(self, column_name): + """General method to create a list from a column in the dataframe. + + The length of the list will correspond to the steps in the ORR + mechanism. + + Args: + column_name: + """ + #| - property_list + df = self.fe_df + + property_list = [] + for state in self.rxn_mech_states: + tmp = df.loc[df[self.state_title] == state] + tmp1 = tmp.iloc[0][column_name] + property_list.append(tmp1) + + # free_energy_list[0] += 4.92 + + return(property_list) + #__| + + def fill_missing_data(self): + """ + """ + #| - fill_missing_data + df = self.fe_df + df_missing_data = pd.DataFrame() + for state in self.rxn_mech_states: + df_state = df.loc[df[self.state_title] == state] + + #| - If df is missing state fill in row with NaN for energy + if df_state.empty: + df_state = pd.DataFrame([{ + self.state_title: state, + self.fe_title: np.nan, + }]) + df_missing_data = df_missing_data.append(df_state) + #__| + + self.fe_df = self.fe_df.append(df_missing_data, sort=True) + #__| + + def rxn_energy_lst(self): + """List corresponding to the steps of ORR. + + (1. O2, 2. *OOH, 3. *O, 4. *OH, 5. 2H2O) + """ + #| - rxn_energy_lst + df = self.fe_df + + free_energy_list = [] + for state in self.rxn_mech_states: + df_state = df.loc[df[self.state_title] == state] + + # print(df_state) + + #| - __old__ + # Not sure what this was trying to accomplish + # if len(df_state) == 2: + # state_energy_list = [] + # for j_cnt, row_j in df_state.iterrows(): + # energy_j = row_j[self.fe_title] + # state_energy_list.append(energy_j) + #__| + + #| - If df is missing state fill in row with NaN for energy + if df_state.empty: + df_state = pd.DataFrame([{ + self.state_title: state, + self.fe_title: np.nan, + }]) + #__| + + # This just takes the first species + # If you feed a df with more than one entry per species, then + # this will stupidly choose the first one + state_energy_1 = df_state.iloc[0][self.fe_title] + + #| - __old__ + # if type(state_energy_1) != float: + # print(type(state_energy_1)) + # print("DSKFJKLSDJFSjk_d--_d-d-_D_D_d-d-d-d-d___D_D_D_") + # print( + # "state_energy_1: ", + # str(state_energy_1), + # ) + # + # print( + # "type: ", + # str(type(state_energy_1)) + # ) + # + # print(isinstance(state_energy_1, np.float)) + # print(float(state_energy_1)) + # print(type(float(state_energy_1))) + # print(np.isnan(state_energy_1)) + # if isinstance(state_energy_1, np.float) is False: + # print("lkjfksjd") + #__| + + free_energy_list.append(state_energy_1) + + if self.rxn_type == "ORR": + free_energy_list[0] += 4.92 + elif self.rxn_type == "OER": + free_energy_list[-1] += 4.92 + else: + free_energy_list[0] += 4.92 + + return(free_energy_list) + #__| + + def rxn_energy_lst_new(self): + """ + """ + #| - rxn_energy_lst_new + df = self.fe_df + free_energy_list = [] + for state in self.rxn_mech_states: + df_state = df.loc[df[self.state_title] == state] + + #| - If df is missing state fill in row with NaN for energy + if df_state.empty: + df_state = pd.DataFrame([{ + self.state_title: state, + self.fe_title: np.nan, + }]) + #__| + + state_energy_list = [] + for j_cnt, row_j in df_state.iterrows(): + energy_j = row_j[self.fe_title] + state_energy_list.append(energy_j) + + free_energy_list.append(state_energy_list) + + # tmp1 = df_state.iloc[0][self.fe_title] + # free_energy_list.append(tmp1) + + if self.rxn_type == "ORR": + free_energy_list_0_new = [i + 4.92 for i in free_energy_list[0]] + free_energy_list[0] = free_energy_list_0_new + + # free_energy_list[0] += 4.92 + + elif self.rxn_type == "OER": + # free_energy_list[-1] += 4.92 + free_energy_list_new = [i + 4.92 for i in free_energy_list[-1]] + free_energy_list[-1] = free_energy_list_new + + else: + free_energy_list[0] += 4.92 + + return(free_energy_list) + #__| + + def apply_bias(self, bias, energy_list): + """Apply bias to free energies. + + Applies a potential to every species in the 4 and 2-electron process + and adjusts their free energies accordingly + """ + #| - apply_bias + mod_free_e_lst = [] # Free energy reaction path at applied bias + for energy, elec in zip(energy_list, range(len(energy_list))[::-1]): + mod_free_e_lst.append(energy - elec * bias) + + return(mod_free_e_lst) + #__| + + def calc_overpotential(self): + """ + Calculate overpotential for 4e- process. + + Returns the limiting overpotential for the given species and the + limiting reaction step in the form of a list, species_A -> species_B is + [species_A, species_B] + """ + #| - calc_overpotential + if self.overpotential_given: + out_list = [None, None] + if "overpotential" in list(self.fe_df): + overpot_i = self.fe_df["overpotential"].tolist()[0] + out_list[0] = overpot_i + else: + print("No 'overpotential' column in df") + + else: + rxn_spec = self.rxn_mech_states + + overpotential_lst = [] + for energy_i in enumerate(self.energy_lst[:-1]): + energy_i_plus1 = self.energy_lst[energy_i[0] + 1] + overpotential_i = 1.23 + energy_i_plus1 - energy_i[1] + overpotential_lst.append(overpotential_i) + + overpotential = max(overpotential_lst) + # overpotential = min(overpotential_lst) + + lim_step_index = overpotential_lst.index(overpotential) + + limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] + out_list = [overpotential, limiting_step] + + return(out_list) + #__| + + def calc_overpotential_OER(self): + """Calculate the OER overpotential of a ORR series.""" + #| - calc_overpotential_OER + rxn_spec = self.rxn_mech_states + + overpotential_lst = [] + for energy_i in enumerate(self.energy_lst[:-1]): + energy_i_plus1 = self.energy_lst[energy_i[0] + 1] + overpotential_i = energy_i_plus1 - energy_i[1] - 1.23 + overpotential_lst.append(overpotential_i) + + overpotential = max(overpotential_lst) + lim_step_index = overpotential_lst.index(overpotential) + + limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] + out_list = [overpotential, limiting_step] + + return(out_list) + #__| + + def calc_overpotential_h2o2(self): + """ + Calculate overpotential for 2e- process. + + The overpotential for the 2e- process depends only on the energy of the + *OOH intermediate + """ + #| - calc_overpotential_h2o2 + df = self.fe_df + ooh_row = df[df["adsorbate"] == "ooh"] + ooh_ads_e = ooh_row.iloc[0]["ads_e"] + + op_4e = ooh_ads_e - 4.22 + + return(op_4e) + #__| + + def __series_plot_name__(self, + opt_name=None, + properties=None, + overpotential_type="ORR", + add_overpot=True, + use_key_in_name=False, + ): + """Create name for series. + + Args: + bias: + opt_name: + properties: + color_list: + hover_text_col: + plot_mode: + smart_format: + overpotential_type: + """ + #| - __series_plot_name__ + + #| - Getting appropriate Overpotential + if add_overpot: + if overpotential_type == "ORR": + overpot_i = self.overpotential + elif overpotential_type == "OER": + overpot_i = self.overpotential_OER + elif overpotential_type == "H2O2": + overpot_i = self.overpotential_h2o2 + else: + overpot_i = self.overpotential + else: + overpot_i = "" + #__| + + #| - Connecting properties key: values into string + if properties is not None: + properties_string_name = "" + for key_i, value_i in properties.items(): + + if use_key_in_name is True: + properties_string_name += str(key_i) + properties_string_name += "_" + properties_string_name += str(value_i) + + properties_string_name += " | " + + # Removing the trailig ' | ' + properties_string_name = properties_string_name[0:-3] + else: + properties_string_name = "" + #__| + + #| - Data Series Name + if opt_name is not None: + name_i = opt_name + ": " + properties_string_name + + else: + name_i = properties_string_name + + if add_overpot: + name_i += " (OP: " + str(round(overpot_i, 2)) + ")" + + #__| + + # NEW | If name_i given, then just use that + if self.name_i is not None: + return(self.name_i) + + return(name_i) + #__| + + #__| From 26789c6f6497ec46a8d519120aca31429b06f235 Mon Sep 17 00:00:00 2001 From: raulf2012 Date: Sun, 14 Jul 2019 11:16:46 -0700 Subject: [PATCH 02/16] Refactoring oxr classes - part 2 --- orr_reaction/__init__.py | 0 orr_reaction/__old__/old_orr_methods.py | 2572 ----------------- ...odhi-dell's conflicted copy 2018-07-13).py | 740 ----- orr_reaction/adsorbate_scaling.py | 335 --- orr_reaction/orr_fed_plot.py | 2231 -------------- orr_reaction/orr_methods.py | 547 ---- orr_reaction/orr_series.py | 1071 ------- 7 files changed, 7496 deletions(-) delete mode 100644 orr_reaction/__init__.py delete mode 100644 orr_reaction/__old__/old_orr_methods.py delete mode 100644 orr_reaction/__old__/orr_fed_plot (raulf-bodhi-dell's conflicted copy 2018-07-13).py delete mode 100644 orr_reaction/adsorbate_scaling.py delete mode 100644 orr_reaction/orr_fed_plot.py delete mode 100644 orr_reaction/orr_methods.py delete mode 100644 orr_reaction/orr_series.py diff --git a/orr_reaction/__init__.py b/orr_reaction/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/orr_reaction/__old__/old_orr_methods.py b/orr_reaction/__old__/old_orr_methods.py deleted file mode 100644 index 678e586..0000000 --- a/orr_reaction/__old__/old_orr_methods.py +++ /dev/null @@ -1,2572 +0,0 @@ -#!/usr/bin/env python - -"""ORR energetics classes and methods. - -Author: Raul A. Flores -""" - -#| - IMPORT MODULES -import copy -import numpy as np -import pandas as pd - -from plotly.graph_objs import Scatter - -pd.options.mode.chained_assignment = None -#__| - -class ORR_Free_E_Plot: - """ORR free energy diagram class. - - Development Notes: - # TODO Should we consider the case where the bulk energy is not 0, and - we have to normalize all of the species energies by it? - """ - - #| - ORR_Free_E_Plot ******************************************************* - - def __init__(self, - free_energy_df=None, - system_properties=None, - state_title="adsorbate", - free_e_title="ads_e" - ): - """ - Input variables to class instance. - - Args: - free_energy_df: - Pandas dataframe containing the adsorbates as rows - Required columns, adsorbate, free energy - system_properties: - state_title: - free_e_title: - """ - #| - __init__ - - #| - Setting Instance Attributes - self.fe_df = free_energy_df - self.sys_props = system_properties - self.state_title = state_title - self.fe_title = free_e_title - - self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] - self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - #__| - - if free_energy_df is not None: - self.add_bulk_entry() - self.fill_missing_data() - - self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk - self.energy_lst = self.rxn_energy_lst() - self.num_of_elec = range(self.num_of_states)[::-1] - self.overpotential = self.calc_overpotential()[0] - self.limiting_step = self.calc_overpotential()[1] - # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() - self.overpotential_h2o2 = self.calc_overpotential_h2o2() - #__| - - # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - - #| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - def add_bulk_entry(self, - bulk_e=0.0, - ): - """ - Append a row entry to data frame corresponding to bulk state. - - Args: - bulk_e: - """ - #| - add_bulk_entry - df = self.fe_df - bulk_df = pd.DataFrame([{ - "adsorbate": "bulk", - "ads_e": bulk_e, - }]) - - df = df.append(bulk_df, ignore_index=True) - - self.fe_df = df - #__| - - def rxn_energy_lst_h2o2(self): - """Construct energy list of h2o2 FED.""" - #| - rxn_energy_lst_h2o2 - # h2o2_e = 3.52 - - df = self.fe_df - - free_energy_list = [] - for index, row in df.iterrows(): - if row["adsorbate"] == "bulk" or row["adsorbate"] == "ooh": - free_energy_list.append(row["ads_e"]) - - # Checking length of energy list - if len(free_energy_list) != 2: - raise ValueError("Not the correct # of steps for H2O2") - - free_energy_list[0] += 4.92 - free_energy_list.append(3.52) - - return(free_energy_list) - #__| - - def property_list(self, column_name): - """General method to create a list from a column in the dataframe. - - The length of the list will correspond to the steps in the ORR - mechanism. - - Args: - column_name: - """ - #| - property_list - df = self.fe_df - - property_list = [] - for state in self.rxn_mech_states: - tmp = df.loc[df[self.state_title] == state] - tmp1 = tmp.iloc[0][column_name] - property_list.append(tmp1) - - # free_energy_list[0] += 4.92 - - return(property_list) - #__| - - def fill_missing_data(self): - """ - """ - #| - fill_missing_data - df = self.fe_df - df_missing_data = pd.DataFrame() - for state in self.rxn_mech_states: - df_state = df.loc[df[self.state_title] == state] - - #| - If df is missing state fill in row with NaN for energy - if df_state.empty: - df_state = pd.DataFrame([{ - self.state_title: state, - self.fe_title: np.nan, - }]) - df_missing_data = df_missing_data.append(df_state) - #__| - - self.fe_df = self.fe_df.append(df_missing_data) - #__| - - def rxn_energy_lst(self): - """List corresponding to the steps of ORR. - - (1. O2, 2. *OOH, 3. *O, 4. *OH, 5. 2H2O) - """ - #| - rxn_energy_lst - df = self.fe_df - free_energy_list = [] - for state in self.rxn_mech_states: - - df_state = df.loc[df[self.state_title] == state] - - #| - If df is missing state fill in row with NaN for energy - if df_state.empty: - df_state = pd.DataFrame([{ - self.state_title: state, - self.fe_title: np.nan, - }]) - #__| - - tmp1 = df_state.iloc[0][self.fe_title] - free_energy_list.append(tmp1) - - free_energy_list[0] += 4.92 - - return(free_energy_list) - #__| - - def apply_bias(self, bias, energy_list): - """Apply bias to free energies. - - Applies a potential to every species in the 4 and 2-electron process - and adjusts their free energies accordingly - """ - #| - apply_bias - mod_free_e_lst = [] # Free energy reaction path at applied bias - for energy, elec in zip(energy_list, range(len(energy_list))[::-1]): - mod_free_e_lst.append(energy - elec * bias) - - return(mod_free_e_lst) - #__| - - def calc_overpotential(self): - """ - Calculate overpotential for 4e- process. - - Returns the limiting overpotential for the given species and the - limiting reaction step in the form of a list, species_A -> species_B is - [species_A, species_B] - """ - #| - calc_overpotential - rxn_spec = self.rxn_mech_states - - overpotential_lst = [] - for energy_i in enumerate(self.energy_lst[:-1]): - energy_i_plus1 = self.energy_lst[energy_i[0] + 1] - overpotential_i = 1.23 + energy_i_plus1 - energy_i[1] - overpotential_lst.append(overpotential_i) - - overpotential = max(overpotential_lst) - lim_step_index = overpotential_lst.index(overpotential) - - limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] - out_list = [overpotential, limiting_step] - - return(out_list) - #__| - - def calc_overpotential_h2o2(self): - """ - Calculate overpotential for 2e- process. - - The overpotential for the 2e- process depends only on the energy of the - *OOH intermediate - """ - #| - calc_overpotential_h2o2 - df = self.fe_df - ooh_row = df[df["adsorbate"] == "ooh"] - ooh_ads_e = ooh_row.iloc[0]["ads_e"] - - op_4e = ooh_ads_e - 4.22 - - return(op_4e) - #__| - - def create_rxn_coord_array(self, - rxn_steps, - spacing=0, - step_size=1, - ): - """ - Create a reaction coordinate array ([0, 1, 1, 2, 2, 3]) for plotting. - - Args: - rxn_steps: - Number of steps in reaction coordinate including initial - and final state. - Ex. A -> Intermediate -> C has 3 steps/states - - spacing: - Spacing inbetween the energy levels. The default of 0 creates - a free energy diagram that looks like steps - """ - #| - create_rxn_coord_array - lst = [] - for i in range(1, rxn_steps): - if i == 1: - lst.append(step_size) - lst.append(step_size + spacing) - if i != 1: - lst.append(lst[-1] + step_size) - lst.append(lst[-2] + step_size + spacing) - - lst.insert(0, 0) - lst.append(lst[-1] + step_size) - - return(lst) - #__| - - #__| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # - - #| - Plotting @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - - def convert_to_plotting_list(self, - energy_lst, - spacing=0.5, - step_size=1, - ): - """ - Repeat entries in energy list to conform to FED plot. - - Modifies an energy list for plotting by repeating each entry - Ex. [4.92, 3.69, ... ] -> [4.92, 4.92, 3.69, 3.69, ... ] - - Args: - energy_lst: - spacing: - step_size: - """ - #| - convert_to_plotting_list - tmp_list = range(len(energy_lst) * 2) - energy_dupl_lst = [energy_lst[i // 2] for i in tmp_list] - - rxn_coord_steps = self.create_rxn_coord_array( - len(energy_lst), - spacing=spacing, - step_size=step_size, - ) - out_list = [rxn_coord_steps, energy_dupl_lst] - - return(out_list) - #__| - - def plot_fed_series(self, - bias=0., - opt_name=None, - properties=None, - color_list=None, - i_cnt=0, - hover_text_col=None, - plot_mode="all", - smart_format=None, - ): - """ - Process data for FED plot. - - Args: - bias: - opt_name - properties: - color_list: - i_cnt: - hover_text_col: - Dataframe column name to be used for hover text - - #FIXME | This is fairly rough as of right now - """ - #| - plot_fed_series - key = properties - if type(key) == tuple: - pass - - elif key is None: - key = None - else: - key = (key,) - - e_list = self.energy_lst - e_list = self.apply_bias(bias, e_list) - - overpot_i = self.overpotential - - for n, i in enumerate(e_list): - if np.isnan(i) is True: - e_list[n] = None - - if color_list is None: - color_list = ["red"] - - - if key is None: - prop_name = "" - else: - prop_name = "_".join([str(i) for i in key]) - - if opt_name is not None: - name_i = opt_name + ": " + prop_name + \ - " (OP: " + str(round(overpot_i, 2)) + ")" - - else: - name_i = prop_name + \ - " (OP: " + str(round(overpot_i, 2)) + ")" - - #| - Hover Text - if hover_text_col is not None: - - if type(hover_text_col) is not list: - hover_text_list = self.property_list(hover_text_col) - - else: - - hover_text_lists = [] - for col_i in hover_text_col: - - # replacing nan with "" - tmp = self.property_list(col_i) - hover_text_i = ["" if x is np.nan else x for x in tmp] - hover_text_lists.append(hover_text_i) - - # TODO Removed last trailing " | " - hover_text_list = [] - for items in zip(*hover_text_lists): - - if all([True if i == "" else False for i in items]) is True: - hover_col_state_i = "" - else: - hover_col_state_i = " | ".join(items) - - hover_text_list.append(hover_col_state_i) - - else: - hover_text_list = [np.nan for j_cnt in list(range(5))] - #__| - - dat_lst = self.create_plotly_series( - e_list, - group=name_i, - name=name_i, - hover_text=hover_text_list, - color=color_list[i_cnt - 1], - plot_mode=plot_mode, - smart_format=smart_format, - ) - - return(dat_lst) - #__| - - def create_plotly_series(self, - energy_lst, - name="TEMP", - group="group1", - hover_text=None, - color="rgb(22, 96, 167)", - plot_mode="all", - smart_format=None, - ): - """ - Create a plotly series for the current instance. - - Args: - energy_lst: - name: - group: - color: - plot_mode: - "all" - "states_only" - "full_lines" - """ - #| - create_plotly_series - e_list = self.convert_to_plotting_list(energy_lst) - x_dat = e_list[0] - y_dat = e_list[1] - - if hover_text is None: - hover_text = [np.nan for i_ind in range(5)] - - #| - Parameters - if plot_mode == "all": - show_leg_2 = False - elif plot_mode == "states_only": - show_leg_2 = False - elif plot_mode == "full_lines": - show_leg_2 = True - #__| - - #| - Adding Breaks in Data - new_x_dat = copy.copy(x_dat) - new_y_dat = copy.copy(y_dat) - - cnt = 2 - for i_ind in range(int(len(x_dat) / 2 - 1)): - fill = new_x_dat[cnt - 1] - new_x_dat.insert(cnt, fill) - new_y_dat.insert(cnt, None) - cnt += 3 - #__| - - #| - Creating x-data in middle of states - short_y = np.array(y_dat)[::2] - - xdat = list(set(new_x_dat)) - xdat.sort() - - cnt = 0 - short_x = [] - for i_ind in range(int(len(xdat) / 2)): - short_x.append(xdat[cnt] + 0.5) # FIXME Replace 0.5 with variable - cnt += 2 - #__| - - - #| - Smart Format Dict ************************************************ - - #| - DICTS - plot_parameter_dict = { - "dash": None, - } - - # smart_format = [ - # - # # [ - # # {"spinpol": True}, - # # {"dash": "dot"}, - # # ], - # - # [ - # {"system": "Fe_slab"}, - # {"dash": "dashdot"}, - # ], - # - # [ - # {"system": "N_graph_Fe"}, - # {"dash": "dot"}, - # ], - # - # [ - # {"system": "graph_Fe"}, - # {"dash": "dash"}, - # ], - # - # [ - # {"system": "graphene"}, - # {"dash": None}, - # ], - # - # ] - - #__| - - if self.fe_df is not None and smart_format is not None: - for format_i in smart_format: - - # format_i key:values - df_col_name = list(format_i[0])[0] - value_i = list(format_i[0].values())[0] - setting_name = list(format_i[1])[0] - setting_value = list(format_i[1].values())[0] - - - if df_col_name in list(self.fe_df): - - # *OOH, *O, *OH entries must have value_i as the - # column entries in the column df_col_name - - df = self.fe_df - df_wo_bulk = df[df["adsorbate"] != "bulk"] - - if all(df_wo_bulk[df_col_name] == value_i): - plot_parameter_dict.update({setting_name: setting_value}) - - else: - print("Dataframe column " + df_col_name + " not present") - - #__| ****************************************************************** - - #| - Series Color - if "color" in list(plot_parameter_dict): - color_out = plot_parameter_dict["color"] - else: - plot_parameter_dict["color"] = color - #__| - - #| - Plotly Scatter Plot Instances - - #| - Thick horizontal state lines - data_1 = Scatter( - x=new_x_dat, - y=new_y_dat, - legendgroup=group, - showlegend=True, - name=name, - hoverinfo="none", # TEMP - 180317 - # text=hover_text, - - connectgaps=False, - line=dict( - # color=color, - color=plot_parameter_dict["color"], - width=6, - # dash="dot", # TEMP - dash=plot_parameter_dict["dash"], # TEMP - ), - mode="lines", - ) - #__| - - #| - Full, thin line - data_2 = Scatter( - x=new_x_dat, - y=new_y_dat, - legendgroup=group, - name=name, - connectgaps=True, - showlegend=show_leg_2, - hoverinfo="none", - text=hover_text, - - line=dict( - # color=color, - color=plot_parameter_dict["color"], - width=1, - ), - mode="lines", - ) - #__| - - #| - Points in middle of energy states - data_3 = Scatter( - x=short_x, - y=short_y, - legendgroup=group, - name=name, - showlegend=False, - hoverinfo="y+text", - text=hover_text, - marker=dict( - size=14, - color=color, - opacity=0., - ), - mode="markers", - ) - #__| - - #__| - - #| - Plot Mode (which data series to plot) - if plot_mode == "all": - data_lst = [data_1, data_2, data_3] - elif plot_mode == "states_only": - data_lst = [data_1, data_3] - elif plot_mode == "full_lines": - data_lst = [data_2, data_3] - #__| - - return(data_lst) - #__| - - - #__| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - - #__| ********************************************************************** - - -#| - MISC Methods - -def plotly_fed_layout( - plot_title="FED", - plot_title_size=18, - tick_lab_size=16, - axes_lab_size=18, - legend_size=18, - ): - """ - """ - #| - plotly_fed_layout - - xax_labels = ["O2", "OOH", "O", "OH", "H2O"] - layout = { - - "title": plot_title, - - "font": { - "family": "Courier New, monospace", - "size": plot_title_size, - "color": "black", - }, - - #| - Axes -------------------------------------------------------------- - "yaxis": { - "title": "Free Energy [eV]", - "zeroline": True, - "titlefont": dict(size=axes_lab_size), - "showgrid": False, - "tickfont": dict( - size=tick_lab_size, - ), - }, - - "xaxis": { - "title": "Reaction Coordinate", - "zeroline": True, - "titlefont": dict(size=axes_lab_size), - "showgrid": False, - - # "showticklabels": False, - - "ticktext": xax_labels, - "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - - "tickfont": dict( - size=tick_lab_size, - ), - }, - #__| ------------------------------------------------------------------- - - #| - Legend ------------------------------------------------------------ - "legend": { - "traceorder": "normal", - "font": dict(size=legend_size) - }, - #__| ------------------------------------------------------------------- - - #| - Plot Size - # "width": 200 * 4., - # "height": 200 * 3., - #__| - - } - - return(layout) - - #__| - -def calc_ads_e( - df_row, - bare_raw_e, - correction=0., - oxy_ref_e=-443.70964, - hyd_ref_e=-16.46018, - ): - """Calculate adsorption energies from raw DFT energetics. - - Default oxygen reference energy is based on water - - Args: - df_row: Pandas dataframe row - bare_raw_e: Bare slab raw DFT energy - correction: Energy correction (ZPE, entropy, solvation, etc.) - oxy_ref_e: - hyd_ref_e: - """ - #| - calc_ads_e - row = df_row - bare_slab = bare_raw_e - oxy_ref = oxy_ref_e - hyd_ref = hyd_ref_e - - #| - Oxygen & Hydrogen Atom Count - - atoms_col = "atom_type_num_dict" - if atoms_col in list(row): - try: - num_O = row[atoms_col][0]["O"] - except: - num_O = 0 - - try: - num_H = row[atoms_col][0]["H"] - except: - num_H = 0 - - else: - - if row["adsorbate"] == "ooh": - num_O = 2 - num_H = 1 - elif row["adsorbate"] == "o": - num_O = 1 - num_H = 0 - elif row["adsorbate"] == "oh": - num_O = 1 - num_H = 1 - - #__| - - try: - raw_e = row["elec_energy"] - ads_e_i = raw_e - (bare_slab + num_O * oxy_ref + num_H * hyd_ref) - ads_e_i += correction - - # ads_e_i = raw_e - bare_slab - num_O * oxy_ref - num_H * hyd_ref - # ads_e_i += correction - except: - ads_e_i = None - - return(ads_e_i) - #__| - -def df_calc_adsorption_e( - df, - - oxy_ref, - hyd_ref, - - bare_slab_e, - bare_slab_var=None, - - corrections_mode="df_column", # corr_dict - corrections_column="gibbs_correction", - - corrections_dict=None, - ): - """Calculate and add adsorption energy column to data_frame. - - Args: - df: - """ - #| - df_calc_adsorption_e - ads_e_list = [] - for index, row in df.iterrows(): - bare_e = bare_slab_e - - - #| - Correction - corr = 0. - # corr = fe_corr_dict[row["adsorbate"]] - - if corrections_mode == "df_column": - corr = row[corrections_column] - - # If "df_column" method return 0. then try to use correction_dict - if corr == 0.: - if corrections_dict is not None: - corr = corrections_dict[row["adsorbate"]] - - elif corrections_mode == "corr_dict" and corrections_dict is not None: - corr = corrections_dict[row["adsorbate"]] - else: - print("No correction being applied") - corr = 0. - #__| - - if type(bare_slab_e) == dict: - bare_e = bare_slab_e[row[bare_slab_var]] - - elif type(bare_slab_e) == float: - bare_e = bare_slab_e - - ads_e_i = calc_ads_e( - row, - # bare_slab, - bare_e, - correction=corr, - oxy_ref_e=oxy_ref, - hyd_ref_e=hyd_ref, - ) - ads_e_list.append(ads_e_i) - - df["ads_e"] = np.array(ads_e_list) - #__| - -def lowest_e_path( - df, - jobs_variables, - color_list, - create_ideal_series=True, - opt_name=None, - bias=0., - manual_props="*TEMP*", - plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", - smart_format=None, - ): - """Find the lowest energy pathway FED. - - COMBAK - - From a set of FE pathways corresponding to different sites, the lowest - energy states will be selected to construct a new FED. - - Args: - df: - jobs_variables: - Result of Jobs.tree_level_labels - color_list: - bias: - - """ - #| - lowest_e_path - - #| - Grouping By Adsorbate Type - df = copy.deepcopy(df) - groupby = copy.deepcopy(jobs_variables) - - groupby.remove("site") - groupby.remove("adsorbate") - - data_master = {} - if groupby == []: - series_list = [] - for ads_i in df.groupby("adsorbate"): - - min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] - series_list.append(min_e_row) - - df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T - data_master[manual_props] = df_i - - else: - for group_i in df.groupby(groupby): - series_list = [] - for ads_i in group_i[1].groupby("adsorbate"): - - min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] - series_list.append(min_e_row) - - df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T - data_master[group_i[0]] = df_i - - #__| - - #| - Creating Data Sets - - #| - Creating FED Datasets - data_list = [] - # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): - for i_cnt, (key, fe_dict) in enumerate(data_master.items()): - - ORR = ORR_Free_E_Plot( - free_energy_df=fe_dict, - ) - - dat_lst = ORR.plot_fed_series( - bias=bias, - opt_name=opt_name, - properties=key, - color_list=color_list, - i_cnt=i_cnt, - hover_text_col="site", - smart_format=smart_format, - ) - - data_list.extend(dat_lst) - #__| - - #| - Creating Ideal FED Dataset - if create_ideal_series: - e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) - - dat_ideal = ORR.create_plotly_series( - e_list_ideal, - group="Ideal", - name="Ideal", - color=color_list[-1], - plot_mode="full_lines", - ) - - dat_lst = data_list + dat_ideal - - else: - - dat_lst = data_list - - - #__| - - # dat_lst = data_list + dat_ideal - - #__| - - #| - Plotting - - #| - Plot Settings - plot_title_size = 18 - tick_lab_size = 16 - axes_lab_size = 18 - legend_size = 18 - #__| - - #| - Plot Layout - # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] - # layout = { - # - # "title": plot_title, - # - # "font": { - # "family": "Courier New, monospace", - # "size": plot_title_size, - # "color": "black", - # }, - # - # #| - Axes -------------------------------------------------------------- - # "yaxis": { - # "title": "Free Energy [eV]", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # - # "xaxis": { - # "title": "Reaction Coordinate", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # - # # "showticklabels": False, - # - # "ticktext": xax_labels, - # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - # - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Legend ------------------------------------------------------------ - # "legend": { - # "traceorder": "normal", - # "font": dict(size=legend_size) - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Plot Size - # # "width": 200 * 4., - # # "height": 200 * 3., - # #__| - # - # } - #__| - - layout = plotly_fed_layout(plot_title=plot_title) - - #__| - - return(dat_lst, layout) - - #__| - -def plot_all_states( - df, - jobs_variables, - color_list, - bias=0., - hover_text_col="site", - create_ideal_series=True, - plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", - smart_format=None, - ): - """ - - Args: - df: - jobs_variables: - color_list: - bias: - plot_title: - """ - #| - plot_all_states - - #| - Grouping By Adsorbate Type - - groupby = copy.deepcopy(jobs_variables) - # groupby = copy.deepcopy(Jojobs_variablesbs.tree_level_labels) - groupby.remove("adsorbate") - - data_master = {} - for group_i in df.groupby(groupby): - - data_master[group_i[0]] = group_i[1] - #__| - - #| - Creating Data Sets - - #| - Creating FED Datasets - data_list = [] - # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): - for i_cnt, (key, fe_dict) in enumerate(data_master.items()): - ORR = ORR_Free_E_Plot( - free_energy_df=fe_dict, - ) - - dat_lst = ORR.plot_fed_series( - bias=bias, - properties=key, - color_list=color_list, - i_cnt=i_cnt, - # hover_text_col="site" - hover_text_col=hover_text_col, - plot_mode="states_only", - smart_format=smart_format, - ) - - data_list.extend(dat_lst) - #__| - - #| - Creating Ideal FED Dataset - if create_ideal_series: - - e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) - - dat_ideal = ORR.create_plotly_series( - e_list_ideal, - group="Ideal", - name="Ideal", - color="red", - plot_mode="full_lines", - ) - - dat_lst = data_list + dat_ideal - #__| - - else: - dat_lst = data_list - - #__| - - #| - Plotting - - #| - Plot Settings - plot_title_size = 18 - tick_lab_size = 16 - axes_lab_size = 18 - legend_size = 12 - #__| - - #| - Plot Layout - # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] - # layout = { - # - # "title": plot_title, - # - # "font": { - # "family": "Courier New, monospace", - # "size": plot_title_size, - # "color": "black", - # }, - # - # #| - Axes -------------------------------------------------------------- - # "yaxis": { - # "title": "Free Energy [eV]", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # - # "xaxis": { - # "title": "Reaction Coordinate", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # - # # "showticklabels": False, - # - # "ticktext": xax_labels, - # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - # - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Legend ------------------------------------------------------------ - # "legend": { - # "traceorder": "normal", - # "font": dict(size=legend_size) - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Plot Size - # "width": 200 * 4., - # "height": 200 * 3., - # #__| - # - # } - #__| - - layout = plotly_fed_layout(plot_title=plot_title) - - return(dat_lst, layout) - - #__| - - #__| - -#__| - - - - - -#| - __old__ - - -#| - __old__ - -# class ORR_Free_E_Plot: -# """ORR free energy diagram class. -# -# Development Notes: -# # TODO Should we consider the case where the bulk energy is not 0, and -# we have to normalize all of the species energies by it? -# """ -# -# #| - ORR_Free_E_Plot ******************************************************* -# -# def __init__(self, -# free_energy_df=None, -# ORR_Free_E_series_list=None, -# # system_properties=None, -# state_title="adsorbate", -# free_e_title="ads_e", -# -# smart_format=None, -# -# bias=0., -# -# # opt_name=None, -# # properties=None, -# -# color_list=None, -# -# # i_cnt=0, -# -# hover_text_col=None, -# -# # plot_mode="all", -# # smart_format=None, -# ): -# """ -# Input variables to class instance. -# -# Args: -# free_energy_df: -# Pandas dataframe containing the adsorbates as rows -# Required columns, adsorbate, free energy -# system_properties: -# state_title: -# free_e_title: -# """ -# #| - __init__ -# -# #| - Setting Instance Attributes -# self.fe_df = free_energy_df -# # self.sys_props = system_properties -# self.state_title = state_title -# self.fe_title = free_e_title -# -# self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] -# self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] -# -# self.smart_format = smart_format -# -# self.bias = bias -# # self.opt_name = opt_name -# # self.properties = properties -# self.color_list = color_list -# # self.i_cnt = i_cnt -# self.hover_text_col = hover_text_col -# # self.plot_mode = plot_mode -# self.smart_format = smart_format -# -# #__| -# -# if ORR_Free_E_series_list is None: -# self.series_list = [] -# else: -# self.series_list = ORR_Free_E_series_list -# -# #| - __old__ -# # if free_energy_df is not None: -# # self.add_bulk_entry() -# # self.fill_missing_data() -# # -# # self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk -# # self.energy_lst = self.rxn_energy_lst() -# # self.num_of_elec = range(self.num_of_states)[::-1] -# # self.overpotential = self.calc_overpotential()[0] -# # self.limiting_step = self.calc_overpotential()[1] -# # # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] -# # self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() -# # self.overpotential_h2o2 = self.calc_overpotential_h2o2() -# #__| -# -# #__| -# -# -# -# -# #| - NEW METHODS - 180621 -# -# def ideal_ORR_series(self, -# ): -# """ -# """ -# #| - ideal_ORR_series -# -# # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] -# -# ideal_data_list = [ -# -# { -# "adsorbate": "ooh", -# "ads_e": 3.69, -# }, -# -# { -# "adsorbate": "o", -# "ads_e": 2.46, -# }, -# -# { -# "adsorbate": "oh", -# "ads_e": 1.23, -# }, -# -# ] -# -# df_ideal = pd.DataFrame(ideal_data_list) -# -# -# self.add_series( -# df_ideal, -# plot_mode="full_lines", # ########## -# opt_name="Ideal ORR Catalyst", -# smart_format=False, -# -# # state_title=self.state_title, -# # free_e_title=self.fe_title, -# # bias=self.bias, -# # -# # # opt_name=None, # ####### -# # # properties=opt_name, -# # # color_list=self.color_list, -# # # i_cnt=0, # ########## -# # hover_text_col=self.hover_text_col, -# # -# # # smart_format=self.smart_format, -# ) -# -# #__| -# -# -# def add_series(self, -# fe_df, -# plot_mode="all", -# opt_name=None, -# -# smart_format=True, -# ): -# """ -# """ -# #| - add_series -# if smart_format: -# smart_format_i = self.smart_format -# else: -# smart_format_i = None -# -# ORR_Series = ORR_Free_E_Series( -# free_energy_df=fe_df, -# # system_properties=None, -# state_title=self.state_title, -# free_e_title=self.fe_title, -# -# bias=self.bias, -# opt_name=opt_name, # ####### -# # properties=opt_name, -# color_list=self.color_list, -# i_cnt=0, # ########## -# hover_text_col=self.hover_text_col, -# plot_mode=plot_mode, # ########## -# smart_format=smart_format_i, -# ) -# -# self.series_list.append(ORR_Series) -# #__| -# -# #__| -# -# -# def plotly_data(self): -# """ -# """ -# #| - plotly_data -# master_data_list = [] -# for series_i in self.series_list: -# master_data_list += series_i.series_plot -# -# return(master_data_list) -# #__| -# -# def plotly_fed_layout(self, -# plot_title="FED", -# plot_title_size=18, -# tick_lab_size=16, -# axes_lab_size=18, -# legend_size=18, -# ): -# """ -# """ -# #| - plotly_fed_layout -# -# xax_labels = ["O2", "OOH", "O", "OH", "H2O"] -# layout = { -# -# "title": plot_title, -# -# "font": { -# "family": "Courier New, monospace", -# "size": plot_title_size, -# "color": "black", -# }, -# -# #| - Axes -------------------------------------------------------------- -# "yaxis": { -# "title": "Free Energy [eV]", -# "zeroline": True, -# "titlefont": dict(size=axes_lab_size), -# "showgrid": False, -# "tickfont": dict( -# size=tick_lab_size, -# ), -# }, -# -# "xaxis": { -# "title": "Reaction Coordinate", -# "zeroline": True, -# "titlefont": dict(size=axes_lab_size), -# "showgrid": False, -# -# # "showticklabels": False, -# -# "ticktext": xax_labels, -# "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], -# -# "tickfont": dict( -# size=tick_lab_size, -# ), -# }, -# #__| ------------------------------------------------------------------- -# -# #| - Legend ------------------------------------------------------------ -# "legend": { -# "traceorder": "normal", -# "font": dict(size=legend_size) -# }, -# #__| ------------------------------------------------------------------- -# -# #| - Plot Size -# # "width": 200 * 4., -# # "height": 200 * 3., -# #__| -# -# } -# -# return(layout) -# -# #__| -# -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# -# #| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# -# # def add_bulk_entry(self, -# # bulk_e=0.0, -# # ): -# # """ -# # Append a row entry to data frame corresponding to bulk state. -# # -# # Args: -# # bulk_e: -# # """ -# # #| - add_bulk_entry -# # df = self.fe_df -# # bulk_df = pd.DataFrame([{ -# # "adsorbate": "bulk", -# # "ads_e": bulk_e, -# # }]) -# # -# # df = df.append(bulk_df, ignore_index=True) -# # -# # self.fe_df = df -# # #__| -# # -# # def rxn_energy_lst_h2o2(self): -# # """Construct energy list of h2o2 FED.""" -# # #| - rxn_energy_lst_h2o2 -# # # h2o2_e = 3.52 -# # -# # df = self.fe_df -# # -# # free_energy_list = [] -# # for index, row in df.iterrows(): -# # if row["adsorbate"] == "bulk" or row["adsorbate"] == "ooh": -# # free_energy_list.append(row["ads_e"]) -# # -# # # Checking length of energy list -# # if len(free_energy_list) != 2: -# # raise ValueError("Not the correct # of steps for H2O2") -# # -# # free_energy_list[0] += 4.92 -# # free_energy_list.append(3.52) -# # -# # return(free_energy_list) -# # #__| -# # -# # def property_list(self, column_name): -# # """General method to create a list from a column in the dataframe. -# # -# # The length of the list will correspond to the steps in the ORR -# # mechanism. -# # -# # Args: -# # column_name: -# # """ -# # #| - property_list -# # df = self.fe_df -# # -# # property_list = [] -# # for state in self.rxn_mech_states: -# # tmp = df.loc[df[self.state_title] == state] -# # tmp1 = tmp.iloc[0][column_name] -# # property_list.append(tmp1) -# # -# # # free_energy_list[0] += 4.92 -# # -# # return(property_list) -# # #__| -# # -# # def fill_missing_data(self): -# # """ -# # """ -# # #| - fill_missing_data -# # df = self.fe_df -# # df_missing_data = pd.DataFrame() -# # for state in self.rxn_mech_states: -# # df_state = df.loc[df[self.state_title] == state] -# # -# # #| - If df is missing state fill in row with NaN for energy -# # if df_state.empty: -# # df_state = pd.DataFrame([{ -# # self.state_title: state, -# # self.fe_title: np.nan, -# # }]) -# # df_missing_data = df_missing_data.append(df_state) -# # #__| -# # -# # self.fe_df = self.fe_df.append(df_missing_data) -# # #__| -# # -# # def rxn_energy_lst(self): -# # """List corresponding to the steps of ORR. -# # -# # (1. O2, 2. *OOH, 3. *O, 4. *OH, 5. 2H2O) -# # """ -# # #| - rxn_energy_lst -# # df = self.fe_df -# # free_energy_list = [] -# # for state in self.rxn_mech_states: -# # -# # df_state = df.loc[df[self.state_title] == state] -# # -# # #| - If df is missing state fill in row with NaN for energy -# # if df_state.empty: -# # df_state = pd.DataFrame([{ -# # self.state_title: state, -# # self.fe_title: np.nan, -# # }]) -# # #__| -# # -# # tmp1 = df_state.iloc[0][self.fe_title] -# # free_energy_list.append(tmp1) -# # -# # free_energy_list[0] += 4.92 -# # -# # return(free_energy_list) -# # #__| -# # -# # def apply_bias(self, bias, energy_list): -# # """Apply bias to free energies. -# # -# # Applies a potential to every species in the 4 and 2-electron process -# # and adjusts their free energies accordingly -# # """ -# # #| - apply_bias -# # mod_free_e_lst = [] # Free energy reaction path at applied bias -# # for energy, elec in zip(energy_list, range(len(energy_list))[::-1]): -# # mod_free_e_lst.append(energy - elec * bias) -# # -# # return(mod_free_e_lst) -# # #__| -# # -# # def calc_overpotential(self): -# # """ -# # Calculate overpotential for 4e- process. -# # -# # Returns the limiting overpotential for the given species and the -# # limiting reaction step in the form of a list, species_A -> species_B is -# # [species_A, species_B] -# # """ -# # #| - calc_overpotential -# # rxn_spec = self.rxn_mech_states -# # -# # overpotential_lst = [] -# # for energy_i in enumerate(self.energy_lst[:-1]): -# # energy_i_plus1 = self.energy_lst[energy_i[0] + 1] -# # overpotential_i = 1.23 + energy_i_plus1 - energy_i[1] -# # overpotential_lst.append(overpotential_i) -# # -# # overpotential = max(overpotential_lst) -# # lim_step_index = overpotential_lst.index(overpotential) -# # -# # limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] -# # out_list = [overpotential, limiting_step] -# # -# # return(out_list) -# # #__| -# # -# # def calc_overpotential_h2o2(self): -# # """ -# # Calculate overpotential for 2e- process. -# # -# # The overpotential for the 2e- process depends only on the energy of the -# # *OOH intermediate -# # """ -# # #| - calc_overpotential_h2o2 -# # df = self.fe_df -# # ooh_row = df[df["adsorbate"] == "ooh"] -# # ooh_ads_e = ooh_row.iloc[0]["ads_e"] -# # -# # op_4e = ooh_ads_e - 4.22 -# # -# # return(op_4e) -# # #__| -# # -# # def create_rxn_coord_array(self, -# # rxn_steps, -# # spacing=0, -# # step_size=1, -# # ): -# # """ -# # Create a reaction coordinate array ([0, 1, 1, 2, 2, 3]) for plotting. -# # -# # Args: -# # rxn_steps: -# # Number of steps in reaction coordinate including initial -# # and final state. -# # Ex. A -> Intermediate -> C has 3 steps/states -# # -# # spacing: -# # Spacing inbetween the energy levels. The default of 0 creates -# # a free energy diagram that looks like steps -# # """ -# # #| - create_rxn_coord_array -# # lst = [] -# # for i in range(1, rxn_steps): -# # if i == 1: -# # lst.append(step_size) -# # lst.append(step_size + spacing) -# # if i != 1: -# # lst.append(lst[-1] + step_size) -# # lst.append(lst[-2] + step_size + spacing) -# # -# # lst.insert(0, 0) -# # lst.append(lst[-1] + step_size) -# # -# # return(lst) -# # #__| -# # -# #__| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -# -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# -# #| - Plotting @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -# -# def convert_to_plotting_list(self, -# energy_lst, -# spacing=0.5, -# step_size=1, -# ): -# """ -# Repeat entries in energy list to conform to FED plot. -# -# Modifies an energy list for plotting by repeating each entry -# Ex. [4.92, 3.69, ... ] -> [4.92, 4.92, 3.69, 3.69, ... ] -# -# Args: -# energy_lst: -# spacing: -# step_size: -# """ -# #| - convert_to_plotting_list -# tmp_list = range(len(energy_lst) * 2) -# energy_dupl_lst = [energy_lst[i // 2] for i in tmp_list] -# -# rxn_coord_steps = self.create_rxn_coord_array( -# len(energy_lst), -# spacing=spacing, -# step_size=step_size, -# ) -# out_list = [rxn_coord_steps, energy_dupl_lst] -# -# return(out_list) -# #__| -# -# def plot_fed_series(self, -# bias=0., -# opt_name=None, -# properties=None, -# color_list=None, -# i_cnt=0, -# hover_text_col=None, -# plot_mode="all", -# smart_format=None, -# ): -# """ -# Process data for FED plot. -# -# Args: -# bias: -# opt_name -# properties: -# color_list: -# i_cnt: -# hover_text_col: -# Dataframe column name to be used for hover text -# -# #FIXME | This is fairly rough as of right now -# """ -# #| - plot_fed_series -# key = properties -# if type(key) == tuple: -# pass -# -# elif key is None: -# key = None -# else: -# key = (key,) -# -# e_list = self.energy_lst -# e_list = self.apply_bias(bias, e_list) -# -# overpot_i = self.overpotential -# -# for n, i in enumerate(e_list): -# if np.isnan(i) is True: -# e_list[n] = None -# -# if color_list is None: -# color_list = ["red"] -# -# -# if key is None: -# prop_name = "" -# else: -# prop_name = "_".join([str(i) for i in key]) -# -# if opt_name is not None: -# name_i = opt_name + ": " + prop_name + \ -# " (OP: " + str(round(overpot_i, 2)) + ")" -# -# else: -# name_i = prop_name + \ -# " (OP: " + str(round(overpot_i, 2)) + ")" -# -# #| - Hover Text -# if hover_text_col is not None: -# -# if type(hover_text_col) is not list: -# hover_text_list = self.property_list(hover_text_col) -# -# else: -# -# hover_text_lists = [] -# for col_i in hover_text_col: -# -# # replacing nan with "" -# tmp = self.property_list(col_i) -# hover_text_i = ["" if x is np.nan else x for x in tmp] -# hover_text_lists.append(hover_text_i) -# -# # TODO Removed last trailing " | " -# hover_text_list = [] -# for items in zip(*hover_text_lists): -# -# if all([True if i == "" else False for i in items]) is True: -# hover_col_state_i = "" -# else: -# hover_col_state_i = " | ".join(items) -# -# hover_text_list.append(hover_col_state_i) -# -# else: -# hover_text_list = [np.nan for j_cnt in list(range(5))] -# #__| -# -# dat_lst = self.create_plotly_series( -# e_list, -# group=name_i, -# name=name_i, -# hover_text=hover_text_list, -# color=color_list[i_cnt - 1], -# plot_mode=plot_mode, -# smart_format=smart_format, -# ) -# -# return(dat_lst) -# #__| -# -# def create_plotly_series(self, -# energy_lst, -# name="TEMP", -# group="group1", -# hover_text=None, -# color="rgb(22, 96, 167)", -# plot_mode="all", -# smart_format=None, -# ): -# """ -# Create a plotly series for the current instance. -# -# Args: -# energy_lst: -# name: -# group: -# color: -# plot_mode: -# "all" -# "states_only" -# "full_lines" -# """ -# #| - create_plotly_series -# e_list = self.convert_to_plotting_list(energy_lst) -# x_dat = e_list[0] -# y_dat = e_list[1] -# -# if hover_text is None: -# hover_text = [np.nan for i_ind in range(5)] -# -# #| - Parameters -# if plot_mode == "all": -# show_leg_2 = False -# elif plot_mode == "states_only": -# show_leg_2 = False -# elif plot_mode == "full_lines": -# show_leg_2 = True -# #__| -# -# #| - Adding Breaks in Data -# new_x_dat = copy.copy(x_dat) -# new_y_dat = copy.copy(y_dat) -# -# cnt = 2 -# for i_ind in range(int(len(x_dat) / 2 - 1)): -# fill = new_x_dat[cnt - 1] -# new_x_dat.insert(cnt, fill) -# new_y_dat.insert(cnt, None) -# cnt += 3 -# #__| -# -# #| - Creating x-data in middle of states -# short_y = np.array(y_dat)[::2] -# -# xdat = list(set(new_x_dat)) -# xdat.sort() -# -# cnt = 0 -# short_x = [] -# for i_ind in range(int(len(xdat) / 2)): -# short_x.append(xdat[cnt] + 0.5) # FIXME Replace 0.5 with variable -# cnt += 2 -# #__| -# -# -# #| - Smart Format Dict ************************************************ -# -# #| - DICTS -# plot_parameter_dict = { -# "dash": None, -# } -# -# # smart_format = [ -# # -# # # [ -# # # {"spinpol": True}, -# # # {"dash": "dot"}, -# # # ], -# # -# # [ -# # {"system": "Fe_slab"}, -# # {"dash": "dashdot"}, -# # ], -# # -# # [ -# # {"system": "N_graph_Fe"}, -# # {"dash": "dot"}, -# # ], -# # -# # [ -# # {"system": "graph_Fe"}, -# # {"dash": "dash"}, -# # ], -# # -# # [ -# # {"system": "graphene"}, -# # {"dash": None}, -# # ], -# # -# # ] -# -# #__| -# -# if self.fe_df is not None and smart_format is not None: -# for format_i in smart_format: -# -# # format_i key:values -# df_col_name = list(format_i[0])[0] -# value_i = list(format_i[0].values())[0] -# setting_name = list(format_i[1])[0] -# setting_value = list(format_i[1].values())[0] -# -# -# if df_col_name in list(self.fe_df): -# -# # *OOH, *O, *OH entries must have value_i as the -# # column entries in the column df_col_name -# -# df = self.fe_df -# df_wo_bulk = df[df["adsorbate"] != "bulk"] -# -# if all(df_wo_bulk[df_col_name] == value_i): -# plot_parameter_dict.update({setting_name: setting_value}) -# -# else: -# print("Dataframe column " + df_col_name + " not present") -# -# #__| ****************************************************************** -# -# #| - Series Color -# if "color" in list(plot_parameter_dict): -# color_out = plot_parameter_dict["color"] -# else: -# plot_parameter_dict["color"] = color -# #__| -# -# #| - Plotly Scatter Plot Instances -# -# #| - Thick horizontal state lines -# data_1 = Scatter( -# x=new_x_dat, -# y=new_y_dat, -# legendgroup=group, -# showlegend=True, -# name=name, -# hoverinfo="none", # TEMP - 180317 -# # text=hover_text, -# -# connectgaps=False, -# line=dict( -# # color=color, -# color=plot_parameter_dict["color"], -# width=6, -# # dash="dot", # TEMP -# dash=plot_parameter_dict["dash"], # TEMP -# ), -# mode="lines", -# ) -# #__| -# -# #| - Full, thin line -# data_2 = Scatter( -# x=new_x_dat, -# y=new_y_dat, -# legendgroup=group, -# name=name, -# connectgaps=True, -# showlegend=show_leg_2, -# hoverinfo="none", -# text=hover_text, -# -# line=dict( -# # color=color, -# color=plot_parameter_dict["color"], -# width=1, -# ), -# mode="lines", -# ) -# #__| -# -# #| - Points in middle of energy states -# data_3 = Scatter( -# x=short_x, -# y=short_y, -# legendgroup=group, -# name=name, -# showlegend=False, -# hoverinfo="y+text", -# text=hover_text, -# marker=dict( -# size=14, -# color=color, -# opacity=0., -# ), -# mode="markers", -# ) -# #__| -# -# #__| -# -# #| - Plot Mode (which data series to plot) -# if plot_mode == "all": -# data_lst = [data_1, data_2, data_3] -# elif plot_mode == "states_only": -# data_lst = [data_1, data_3] -# elif plot_mode == "full_lines": -# data_lst = [data_2, data_3] -# #__| -# -# return(data_lst) -# #__| -# -# -# #__| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ -# -# #__| ********************************************************************** - -#__| - - -#| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -# def add_bulk_entry(self, -# bulk_e=0.0, -# ): -# """ -# Append a row entry to data frame corresponding to bulk state. -# -# Args: -# bulk_e: -# """ -# #| - add_bulk_entry -# df = self.fe_df -# bulk_df = pd.DataFrame([{ -# "adsorbate": "bulk", -# "ads_e": bulk_e, -# }]) -# -# df = df.append(bulk_df, ignore_index=True) -# -# self.fe_df = df -# #__| -# -# def rxn_energy_lst_h2o2(self): -# """Construct energy list of h2o2 FED.""" -# #| - rxn_energy_lst_h2o2 -# # h2o2_e = 3.52 -# -# df = self.fe_df -# -# free_energy_list = [] -# for index, row in df.iterrows(): -# if row["adsorbate"] == "bulk" or row["adsorbate"] == "ooh": -# free_energy_list.append(row["ads_e"]) -# -# # Checking length of energy list -# if len(free_energy_list) != 2: -# raise ValueError("Not the correct # of steps for H2O2") -# -# free_energy_list[0] += 4.92 -# free_energy_list.append(3.52) -# -# return(free_energy_list) -# #__| -# -# def property_list(self, column_name): -# """General method to create a list from a column in the dataframe. -# -# The length of the list will correspond to the steps in the ORR -# mechanism. -# -# Args: -# column_name: -# """ -# #| - property_list -# df = self.fe_df -# -# property_list = [] -# for state in self.rxn_mech_states: -# tmp = df.loc[df[self.state_title] == state] -# tmp1 = tmp.iloc[0][column_name] -# property_list.append(tmp1) -# -# # free_energy_list[0] += 4.92 -# -# return(property_list) -# #__| -# -# def fill_missing_data(self): -# """ -# """ -# #| - fill_missing_data -# df = self.fe_df -# df_missing_data = pd.DataFrame() -# for state in self.rxn_mech_states: -# df_state = df.loc[df[self.state_title] == state] -# -# #| - If df is missing state fill in row with NaN for energy -# if df_state.empty: -# df_state = pd.DataFrame([{ -# self.state_title: state, -# self.fe_title: np.nan, -# }]) -# df_missing_data = df_missing_data.append(df_state) -# #__| -# -# self.fe_df = self.fe_df.append(df_missing_data) -# #__| -# -# def rxn_energy_lst(self): -# """List corresponding to the steps of ORR. -# -# (1. O2, 2. *OOH, 3. *O, 4. *OH, 5. 2H2O) -# """ -# #| - rxn_energy_lst -# df = self.fe_df -# free_energy_list = [] -# for state in self.rxn_mech_states: -# -# df_state = df.loc[df[self.state_title] == state] -# -# #| - If df is missing state fill in row with NaN for energy -# if df_state.empty: -# df_state = pd.DataFrame([{ -# self.state_title: state, -# self.fe_title: np.nan, -# }]) -# #__| -# -# tmp1 = df_state.iloc[0][self.fe_title] -# free_energy_list.append(tmp1) -# -# free_energy_list[0] += 4.92 -# -# return(free_energy_list) -# #__| -# -# def apply_bias(self, bias, energy_list): -# """Apply bias to free energies. -# -# Applies a potential to every species in the 4 and 2-electron process -# and adjusts their free energies accordingly -# """ -# #| - apply_bias -# mod_free_e_lst = [] # Free energy reaction path at applied bias -# for energy, elec in zip(energy_list, range(len(energy_list))[::-1]): -# mod_free_e_lst.append(energy - elec * bias) -# -# return(mod_free_e_lst) -# #__| -# -# def calc_overpotential(self): -# """ -# Calculate overpotential for 4e- process. -# -# Returns the limiting overpotential for the given species and the -# limiting reaction step in the form of a list, species_A -> species_B is -# [species_A, species_B] -# """ -# #| - calc_overpotential -# rxn_spec = self.rxn_mech_states -# -# overpotential_lst = [] -# for energy_i in enumerate(self.energy_lst[:-1]): -# energy_i_plus1 = self.energy_lst[energy_i[0] + 1] -# overpotential_i = 1.23 + energy_i_plus1 - energy_i[1] -# overpotential_lst.append(overpotential_i) -# -# overpotential = max(overpotential_lst) -# lim_step_index = overpotential_lst.index(overpotential) -# -# limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] -# out_list = [overpotential, limiting_step] -# -# return(out_list) -# #__| -# -# def calc_overpotential_h2o2(self): -# """ -# Calculate overpotential for 2e- process. -# -# The overpotential for the 2e- process depends only on the energy of the -# *OOH intermediate -# """ -# #| - calc_overpotential_h2o2 -# df = self.fe_df -# ooh_row = df[df["adsorbate"] == "ooh"] -# ooh_ads_e = ooh_row.iloc[0]["ads_e"] -# -# op_4e = ooh_ads_e - 4.22 -# -# return(op_4e) -# #__| -# -# def create_rxn_coord_array(self, -# rxn_steps, -# spacing=0, -# step_size=1, -# ): -# """ -# Create a reaction coordinate array ([0, 1, 1, 2, 2, 3]) for plotting. -# -# Args: -# rxn_steps: -# Number of steps in reaction coordinate including initial -# and final state. -# Ex. A -> Intermediate -> C has 3 steps/states -# -# spacing: -# Spacing inbetween the energy levels. The default of 0 creates -# a free energy diagram that looks like steps -# """ -# #| - create_rxn_coord_array -# lst = [] -# for i in range(1, rxn_steps): -# if i == 1: -# lst.append(step_size) -# lst.append(step_size + spacing) -# if i != 1: -# lst.append(lst[-1] + step_size) -# lst.append(lst[-2] + step_size + spacing) -# -# lst.insert(0, 0) -# lst.append(lst[-1] + step_size) -# -# return(lst) -# #__| -# -#__| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -#| - Plotting @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - -# def convert_to_plotting_list(self, -# energy_lst, -# spacing=0.5, -# step_size=1, -# ): -# """ -# Repeat entries in energy list to conform to FED plot. -# -# Modifies an energy list for plotting by repeating each entry -# Ex. [4.92, 3.69, ... ] -> [4.92, 4.92, 3.69, 3.69, ... ] -# -# Args: -# energy_lst: -# spacing: -# step_size: -# """ -# #| - convert_to_plotting_list -# tmp_list = range(len(energy_lst) * 2) -# energy_dupl_lst = [energy_lst[i // 2] for i in tmp_list] -# -# rxn_coord_steps = self.create_rxn_coord_array( -# len(energy_lst), -# spacing=spacing, -# step_size=step_size, -# ) -# out_list = [rxn_coord_steps, energy_dupl_lst] -# -# return(out_list) -# #__| -# -# def plot_fed_series(self, -# bias=0., -# opt_name=None, -# properties=None, -# color_list=None, -# i_cnt=0, -# hover_text_col=None, -# plot_mode="all", -# smart_format=None, -# ): -# """ -# Process data for FED plot. -# -# Args: -# bias: -# opt_name -# properties: -# color_list: -# i_cnt: -# hover_text_col: -# Dataframe column name to be used for hover text -# -# #FIXME | This is fairly rough as of right now -# """ -# #| - plot_fed_series -# key = properties -# if type(key) == tuple: -# pass -# -# elif key is None: -# key = None -# else: -# key = (key,) -# -# e_list = self.energy_lst -# e_list = self.apply_bias(bias, e_list) -# -# overpot_i = self.overpotential -# -# for n, i in enumerate(e_list): -# if np.isnan(i) is True: -# e_list[n] = None -# -# if color_list is None: -# color_list = ["red"] -# -# -# if key is None: -# prop_name = "" -# else: -# prop_name = "_".join([str(i) for i in key]) -# -# if opt_name is not None: -# name_i = opt_name + ": " + prop_name + \ -# " (OP: " + str(round(overpot_i, 2)) + ")" -# -# else: -# name_i = prop_name + \ -# " (OP: " + str(round(overpot_i, 2)) + ")" -# -# #| - Hover Text -# if hover_text_col is not None: -# -# if type(hover_text_col) is not list: -# hover_text_list = self.property_list(hover_text_col) -# -# else: -# -# hover_text_lists = [] -# for col_i in hover_text_col: -# -# # replacing nan with "" -# tmp = self.property_list(col_i) -# hover_text_i = ["" if x is np.nan else x for x in tmp] -# hover_text_lists.append(hover_text_i) -# -# # TODO Removed last trailing " | " -# hover_text_list = [] -# for items in zip(*hover_text_lists): -# -# if all([True if i == "" else False for i in items]) is True: -# hover_col_state_i = "" -# else: -# hover_col_state_i = " | ".join(items) -# -# hover_text_list.append(hover_col_state_i) -# -# else: -# hover_text_list = [np.nan for j_cnt in list(range(5))] -# #__| -# -# dat_lst = self.create_plotly_series( -# e_list, -# group=name_i, -# name=name_i, -# hover_text=hover_text_list, -# color=color_list[i_cnt - 1], -# plot_mode=plot_mode, -# smart_format=smart_format, -# ) -# -# return(dat_lst) -# #__| -# -# def create_plotly_series(self, -# energy_lst, -# name="TEMP", -# group="group1", -# hover_text=None, -# color="rgb(22, 96, 167)", -# plot_mode="all", -# smart_format=None, -# ): -# """ -# Create a plotly series for the current instance. -# -# Args: -# energy_lst: -# name: -# group: -# color: -# plot_mode: -# "all" -# "states_only" -# "full_lines" -# """ -# #| - create_plotly_series -# e_list = self.convert_to_plotting_list(energy_lst) -# x_dat = e_list[0] -# y_dat = e_list[1] -# -# if hover_text is None: -# hover_text = [np.nan for i_ind in range(5)] -# -# #| - Parameters -# if plot_mode == "all": -# show_leg_2 = False -# elif plot_mode == "states_only": -# show_leg_2 = False -# elif plot_mode == "full_lines": -# show_leg_2 = True -# #__| -# -# #| - Adding Breaks in Data -# new_x_dat = copy.copy(x_dat) -# new_y_dat = copy.copy(y_dat) -# -# cnt = 2 -# for i_ind in range(int(len(x_dat) / 2 - 1)): -# fill = new_x_dat[cnt - 1] -# new_x_dat.insert(cnt, fill) -# new_y_dat.insert(cnt, None) -# cnt += 3 -# #__| -# -# #| - Creating x-data in middle of states -# short_y = np.array(y_dat)[::2] -# -# xdat = list(set(new_x_dat)) -# xdat.sort() -# -# cnt = 0 -# short_x = [] -# for i_ind in range(int(len(xdat) / 2)): -# short_x.append(xdat[cnt] + 0.5) # FIXME Replace 0.5 with variable -# cnt += 2 -# #__| -# -# -# #| - Smart Format Dict ************************************************ -# -# #| - DICTS -# plot_parameter_dict = { -# "dash": None, -# } -# -# # smart_format = [ -# # -# # # [ -# # # {"spinpol": True}, -# # # {"dash": "dot"}, -# # # ], -# # -# # [ -# # {"system": "Fe_slab"}, -# # {"dash": "dashdot"}, -# # ], -# # -# # [ -# # {"system": "N_graph_Fe"}, -# # {"dash": "dot"}, -# # ], -# # -# # [ -# # {"system": "graph_Fe"}, -# # {"dash": "dash"}, -# # ], -# # -# # [ -# # {"system": "graphene"}, -# # {"dash": None}, -# # ], -# # -# # ] -# -# #__| -# -# if self.fe_df is not None and smart_format is not None: -# for format_i in smart_format: -# -# # format_i key:values -# df_col_name = list(format_i[0])[0] -# value_i = list(format_i[0].values())[0] -# setting_name = list(format_i[1])[0] -# setting_value = list(format_i[1].values())[0] -# -# -# if df_col_name in list(self.fe_df): -# -# # *OOH, *O, *OH entries must have value_i as the -# # column entries in the column df_col_name -# -# df = self.fe_df -# df_wo_bulk = df[df["adsorbate"] != "bulk"] -# -# if all(df_wo_bulk[df_col_name] == value_i): -# plot_parameter_dict.update({setting_name: setting_value}) -# -# else: -# print("Dataframe column " + df_col_name + " not present") -# -# #__| ****************************************************************** -# -# #| - Series Color -# if "color" in list(plot_parameter_dict): -# color_out = plot_parameter_dict["color"] -# else: -# plot_parameter_dict["color"] = color -# #__| -# -# #| - Plotly Scatter Plot Instances -# -# #| - Thick horizontal state lines -# data_1 = Scatter( -# x=new_x_dat, -# y=new_y_dat, -# legendgroup=group, -# showlegend=True, -# name=name, -# hoverinfo="none", # TEMP - 180317 -# # text=hover_text, -# -# connectgaps=False, -# line=dict( -# # color=color, -# color=plot_parameter_dict["color"], -# width=6, -# # dash="dot", # TEMP -# dash=plot_parameter_dict["dash"], # TEMP -# ), -# mode="lines", -# ) -# #__| -# -# #| - Full, thin line -# data_2 = Scatter( -# x=new_x_dat, -# y=new_y_dat, -# legendgroup=group, -# name=name, -# connectgaps=True, -# showlegend=show_leg_2, -# hoverinfo="none", -# text=hover_text, -# -# line=dict( -# # color=color, -# color=plot_parameter_dict["color"], -# width=1, -# ), -# mode="lines", -# ) -# #__| -# -# #| - Points in middle of energy states -# data_3 = Scatter( -# x=short_x, -# y=short_y, -# legendgroup=group, -# name=name, -# showlegend=False, -# hoverinfo="y+text", -# text=hover_text, -# marker=dict( -# size=14, -# color=color, -# opacity=0., -# ), -# mode="markers", -# ) -# #__| -# -# #__| -# -# #| - Plot Mode (which data series to plot) -# if plot_mode == "all": -# data_lst = [data_1, data_2, data_3] -# elif plot_mode == "states_only": -# data_lst = [data_1, data_3] -# elif plot_mode == "full_lines": -# data_lst = [data_2, data_3] -# #__| -# -# return(data_lst) -# #__| -# - -#__| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - -#__| diff --git a/orr_reaction/__old__/orr_fed_plot (raulf-bodhi-dell's conflicted copy 2018-07-13).py b/orr_reaction/__old__/orr_fed_plot (raulf-bodhi-dell's conflicted copy 2018-07-13).py deleted file mode 100644 index 5d325b1..0000000 --- a/orr_reaction/__old__/orr_fed_plot (raulf-bodhi-dell's conflicted copy 2018-07-13).py +++ /dev/null @@ -1,740 +0,0 @@ -#!/usr/bin/env python -# TEMP TEMP TEMP -"""ORR energetics classes and methods. - -Author: Raul A. Flores -""" - -#| - IMPORT MODULES -# import copy -import numpy as np -import pandas as pd - -# from plotly.graph_objs import Scatter - -import plotly.plotly as py -import plotly.graph_objs as go - -pd.options.mode.chained_assignment = None - -from orr_reaction.orr_series import ORR_Free_E_Series -#__| - -class ORR_Free_E_Plot: - """ORR free energy diagram class. - - ACTUALLY THIS IS GOING TO BE A GENERAL ORR/OER CLASS NOW!!!!!!!!!!!!!!!!!!! - - - - Development Notes: - # TODO Should we consider the case where the bulk energy is not 0, and - we have to normalize all of the species energies by it? - """ - - #| - ORR_Free_E_Plot ******************************************************* - - def __init__(self, - free_energy_df=None, - ORR_Free_E_series_list=None, - # system_properties=None, - state_title="adsorbate", - free_e_title="ads_e", - - num_states=5, - - smart_format=None, - - bias=0., - - # opt_name=None, - # properties=None, - - color_list=None, - - # i_cnt=0, - - hover_text_col=None, - - # plot_mode="all", - # smart_format=None, - - # Plotting ************************************************************ - show_H_e_pairs_annotations=True, - show_legend=True, - rxn_type="ORR", # ORR and OER - ): - """ - Input variables to class instance. - - Args: - free_energy_df: - Pandas dataframe containing the adsorbates as rows - Required columns, adsorbate, free energy - system_properties: - state_title: - free_e_title: - - rxn_type: - ORR or OER - """ - #| - __init__ - - #| - Setting Instance Attributes - self.fe_df = free_energy_df - # self.sys_props = system_properties - self.state_title = state_title - self.fe_title = free_e_title - self.num_states = num_states - - # self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] - # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] #COMBAK Is this being used anymore - - self.bias = bias - self.color_list = color_list - self.hover_text_col = hover_text_col - self.smart_format = smart_format - - self.show_H_e_pairs_annotations = show_H_e_pairs_annotations - self.show_legend = show_legend - - # *********************************** - self.plot_states_sep = 0.3 - self.plot_states_width = 1. - - self.rxn_type = rxn_type - #__| - - - if self.rxn_type == "ORR": - self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] - self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - - elif self.rxn_type == "OER": - self.rxn_mech_states = ["bulk", "oh", "o", "ooh", "bulk"] - self.ideal_energy = [0, 1.23, 2.46, 3.69, 4.92] - - self.rxn_x_coord_array = self.create_rxn_coord_array( - self.num_states, - spacing=self.plot_states_sep, - step_size=self.plot_states_width, - ) - - self.mid_state_x_array = self.create_mid_state_x_array() - # x_array_data = self.rxn_x_coord_array - - if ORR_Free_E_series_list is None: - self.series_list = [] - else: - self.series_list = ORR_Free_E_series_list - - #| - __old__ - # if free_energy_df is not None: - # self.add_bulk_entry() - # self.fill_missing_data() - # - # self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk - # self.energy_lst = self.rxn_energy_lst() - # self.num_of_elec = range(self.num_of_states)[::-1] - # self.overpotential = self.calc_overpotential()[0] - # self.limiting_step = self.calc_overpotential()[1] - # # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - # self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() - # self.overpotential_h2o2 = self.calc_overpotential_h2o2() - #__| - - #__| - - def ideal_ORR_series(self, - ): - """ - """ - #| - ideal_ORR_series - - # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - - ideal_data_list = [ - - { - "adsorbate": "ooh", - "ads_e": 3.69, - }, - - { - "adsorbate": "o", - "ads_e": 2.46, - }, - - { - "adsorbate": "oh", - "ads_e": 1.23, - }, - - ] - - df_ideal = pd.DataFrame(ideal_data_list) - - - self.add_series( - df_ideal, - plot_mode="full_lines", # ########## - opt_name="Ideal ORR Catalyst", - smart_format=False, - - # state_title=self.state_title, - # free_e_title=self.fe_title, - # bias=self.bias, - # - # # opt_name=None, # ####### - # # properties=opt_name, - # # color_list=self.color_list, - # # i_cnt=0, # ########## - # hover_text_col=self.hover_text_col, - # - # # smart_format=self.smart_format, - ) - - #__| - - def add_series(self, - fe_df, - plot_mode="all", - opt_name=None, - smart_format=True, - overpotential_type="ORR", - system_properties=None, - ): - """ - """ - #| - add_series - if smart_format: - smart_format_i = self.smart_format - else: - smart_format_i = None - - # free_energy_df=None, - # # system_properties=None, - # state_title="adsorbate", - # free_e_title="ads_e", - # - # bias=0., - # rxn_x_coord_array=None, - # opt_name=None, - # properties=None, - # color_list=None, - # i_cnt=0, - # hover_text_col=None, - # plot_mode="all", - # smart_format=None, - # overpotential_type="ORR", - # rxn_type="ORR", - - ORR_Series = ORR_Free_E_Series( - free_energy_df=fe_df, - properties=system_properties, - state_title=self.state_title, - free_e_title=self.fe_title, - bias=self.bias, - rxn_x_coord_array=self.rxn_x_coord_array, - opt_name=opt_name, # ####### - - # properties=opt_name, - color_list=self.color_list, - i_cnt=0, # ########## - hover_text_col=self.hover_text_col, - plot_mode=plot_mode, # ########## - smart_format=smart_format_i, - - # overpotential_type=self.rxn_type, - rxn_type=self.rxn_type, - ) - - self.series_list.append(ORR_Series) - #__| - - def plotly_data(self): - """ - """ - #| - plotly_data - master_data_list = [] - for series_i in self.series_list: - master_data_list += series_i.series_plot - - return(master_data_list) - #__| - - def plotly_fed_layout(self, - plot_title="FED", - plot_title_size=18, - tick_lab_size=16, - axes_lab_size=18, - legend_size=18, - # font_family="Computer Modern" # "Courier New, monospace" - font_family="Courier New, monospace", # "Courier New, monospace" - ): - """ - - Development notes: - Move all plot parameters to this method, since the user will call - this method to obtain the layout. - """ - #| - plotly_fed_layout - - if self.rxn_type == "ORR": - # xax_labels = ["$O_{2}$", "$*OOH$", "$*O$", "$*OH$", "$H_{2}O$"] - xax_labels = ["O2", "*OOH", "*O", "*OH", "H2O"] - - # xax_labels = ["O2", "*OOH", "*O", "*OH", "H2O"] - - elif self.rxn_type == "OER": - # xax_labels = ["$H_{2}O$", "$*OH$", "$*O$", "$*OOH$", "$O_{2}$"] - xax_labels = ["H2O", "*OH", "*O", "*OOH", "O2"] - - layout = { - "title": plot_title, - - "font": { - # "family": "Courier New, monospace", - "family": font_family, - "size": plot_title_size, - "color": "black", - }, - - #| - Axes -------------------------------------------------------------- - "yaxis": { - "title": "Free Energy (eV)", - # "title": "$\\Delta G (ev)$", - - "zeroline": True, - "showline": True, - "mirror": 'ticks', - "showgrid": False, - - "titlefont": dict(size=axes_lab_size), - - "tickfont": dict( - size=tick_lab_size, - ), - - "autotick": False, - "ticks": 'inside', - "tick0": 0, - "dtick": 0.5, - "ticklen": 8, - "tickwidth": 2, - # "tickcolor": '#000' - - }, - - "xaxis": { - # "title": "Reaction Coordinate", - - "zeroline": True, - "showline": True, - "mirror": 'ticks', - "showgrid": False, - - # "zeroline": True, - # "showgrid": False, - "titlefont": dict(size=axes_lab_size), - - "showticklabels": True, - - "ticktext": xax_labels, - # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - # "tickvals": [self.plot_states_width * i + 0.5 - # for i in range(len(xax_labels))], - "tickvals": self.mid_state_x_array, - - "tickfont": dict( - size=tick_lab_size, - ), - }, - #__| ------------------------------------------------------------------- - - #| - Legend ------------------------------------------------------------ - "legend": { - "traceorder": "normal", - "font": dict(size=legend_size) - }, - #__| ------------------------------------------------------------------- - - #| - Plot Size - # "width": 200 * 4., - # "height": 200 * 3., - #__| - - "showlegend": self.show_legend, - - } - - if self.show_H_e_pairs_annotations: - annotations = self.H_e_pairs_annotations() - - if "annotations" in list(layout): - layout["annotations"] += annotations - else: - layout["annotations"] = annotations - - return(layout) - #__| - - - def max_y_value_per_step(self): - """ - """ - #| - max_y_value_per_step - fe_matrix = [] - for series_i in self.series_list: - fe_matrix.append( - np.array(series_i.energy_lst), - ) - fe_matrix = np.array(fe_matrix) - - max_y_val_list = [] - for step_i in range(fe_matrix.shape[1]): - max_y_val_list.append(fe_matrix[:, step_i].max()) - - return(max_y_val_list) - #__| - - def H_e_pairs_annotations(self, - font_size=18, - ): - """ - - Args: - font_size: - """ - #| - H_e_pairs_annotations - # ann_font_size = 18 - # states_sep = self.plot_states_sep - # states_width = self.plot_states_width - - - mid_state_x_array = self.mid_state_x_array - - rxn_x_array = self.rxn_x_coord_array - max_y_val_list = self.max_y_value_per_step() - - def add_annot( - ind, - rxn_x_array, - step, - annotations, - y=5.5, - font_size=18, - text="TEMP", - mid_state_x_array=None, - ): - """Append annotation object to annotations list. - - Args: - ind: - rxn_x_array: - step: - annotations: - y: - font_size: - text: - """ - #| - add_annot - ann_i = dict( - # x=(rxn_x_array[ind] + rxn_x_array[ind + step]) / 2., - x=mid_state_x_array[ind], - y=y + 0.4, - xref='x', - yref='y', - text=text, - showarrow=False, - font=dict( - color="black", - size=font_size - ), - ), - annotations += ann_i - #__| - - annotations = [] - - add_annot( - 0, rxn_x_array, 1, annotations, - y=max_y_val_list[0], font_size=font_size, - text="4(H+ + e-)", - mid_state_x_array=mid_state_x_array, - ) - - add_annot( - 1, rxn_x_array, 2, annotations, - y=max_y_val_list[1], font_size=font_size, - text="3(H+ + e-)", - mid_state_x_array=mid_state_x_array, - ) - - add_annot( - # 3, rxn_x_array, 2, annotations, - 2, rxn_x_array, 2, annotations, - y=max_y_val_list[2], font_size=font_size, - text="2(H+ + e-)", - mid_state_x_array=mid_state_x_array, - ) - - add_annot( - # 5, rxn_x_array, 2, annotations, - 3, rxn_x_array, 2, annotations, - y=max_y_val_list[3], font_size=font_size, - text="1(H+ + e-)", - mid_state_x_array=mid_state_x_array, - ) - - add_annot( - # 7, rxn_x_array, 2, annotations, - 4, rxn_x_array, 2, annotations, - y=max_y_val_list[4], font_size=font_size, - text="0(H+ + e-)", - mid_state_x_array=mid_state_x_array, - ) - - return(annotations) - #__| - - def create_rxn_coord_array(self, - rxn_steps, - spacing=0, - step_size=1, - ): - """ - Create a reaction coordinate array ([0, 1, 1, 2, 2, 3]) for plotting. - - Args: - rxn_steps: - Number of steps in reaction coordinate including initial - and final state. - Ex. A -> Intermediate -> C has 3 steps/states - - spacing: - Spacing inbetween the energy levels. The default of 0 creates - a free energy diagram that looks like steps - """ - #| - create_rxn_coord_array - lst = [] - for i in range(1, rxn_steps): - if i == 1: - lst.append(step_size) - lst.append(step_size + spacing) - if i != 1: - lst.append(lst[-1] + step_size) - lst.append(lst[-2] + step_size + spacing) - - lst.insert(0, 0) - lst.append(lst[-1] + step_size) - - return(lst) - #__| - - - def create_mid_state_x_array(self): - """ - """ - #| - create_mid_state_x_array - x_array_data = self.rxn_x_coord_array - state_width = self.plot_states_width - - xdat = list(set(x_array_data)) - xdat.sort() - - cnt = 0 - short_x = [] - for i_ind in range(int(len(xdat) / 2)): - short_x.append(xdat[cnt] + state_width / 2.) - cnt += 2 - - return(short_x) - #__| - - def create_scaling_relations_plot(self, - y_ax_spec, - x_ax_spec="oh", - smart_format_dict=None, - x_range=[0, 1.5] - ): - """Return plotly data and layout objects for scaling relations. - - Args: - y_ax_spec: - x_ax_spec: - """ - #| - create_scaling_relations_plot - - #| - Internal Methods - # TODO Should put these in a more accesible place - - def create_smart_format_dict(property_dict, smart_format_dict): - """Create smart format dictionary. - - Args: - property_dict: - smart_format_dict: - """ - format_dict = {} - for key_i, value_i in property_dict.items(): - for format_i in smart_format_dict: - if list(format_i[0])[0] == key_i: - if list(format_i[0].values())[0] == value_i: - format_dict.update(format_i[1]) - - return(format_dict) - - def create_series_name(series): - name_i = "" - for key, value in series_i.properties.items(): - if key == "coverage": - continue - - name_i += str(key) + ": " + str(value) + " | " - - return(name_i) - - def ooh_oh_scaling(E_OH): - return(E_OH + 3.2) - - def o_oh_scaling(E_OH): - return(2 * E_OH) - #__| - - #| - Default Smart Format Dict - if smart_format_dict is None: - smart_format_dict = [ - [{"bulk_system": "IrO3"}, {"color2": "green"}], - [{"bulk_system": "IrO2"}, {"color2": "yellow"}], - - [{"coverage_type": "o_covered"}, {"symbol": "s"}], - [{"coverage_type": "h_covered"}, {"symbol": "^"}], - - [{"facet": "110"}, {"color1": "red"}], - [{"facet": "211"}, {"color1": "green"}], - [{"facet": "100"}, {"color1": "black"}], - ] - #__| - - assert (x_ax_spec == "oh"), "Only *OH as the x-axis is allowed now" - - #| - Processing Data Points - data_ooh_oh = [] - data_o_oh = [] - for series_i in self.series_list: - e_oh = series_i.energy_states_dict["oh"] - e_ooh = series_i.energy_states_dict["ooh"] - e_o = series_i.energy_states_dict["o"] - - smart_format_i = create_smart_format_dict( - series_i.properties, - smart_format_dict, - ) - - name_i = create_series_name(series_i) - - #| - OOH vs. O - trace_i = go.Scatter( - x=e_oh, - y=e_ooh, - name=name_i, - mode='markers', - marker=dict( - size=10, - color=smart_format_i["color2"], - line=dict( - width=2, - ) - ) - ) - data_ooh_oh.append(trace_i) - #__| - - #| - OH vs. O Data Trace - trace_i = go.Scatter( - x=e_oh, - y=e_o, - name=name_i, - mode="markers", - marker=dict( - size=10, - color=smart_format_i["color2"], - line=dict( - width=2, - ) - ) - ) - data_o_oh.append(trace_i) - #__| - - #__| - - #| - Ideal Scaling Lines - # x_range = [0, 1.5] - - scaling_trace = go.Scatter( - x=[x_range[0], x_range[1]], - y=[ooh_oh_scaling(x_range[0]), ooh_oh_scaling(x_range[1])], - name='OOH_OH Scaling', - mode='line', - ) - data_ooh_oh.append(scaling_trace) - - - scaling_trace = go.Scatter( - x=[x_range[0], x_range[1]], - y=[o_oh_scaling(x_range[0]), o_oh_scaling(x_range[1])], - name='O_OH Scaling', - mode='line', - ) - data_o_oh.append(scaling_trace) - #__| - - #| - Plot Layout Settings - layout_ooh_oh = dict( - title="OOH vs OH Scaling", - xaxis=dict( - title='G_OH', - zeroline=False, - ), - yaxis=dict( - title='G_OOH', - zeroline=False, - ), - legend=dict( - x=-.1, - y=1.6, - font=dict( - size=10, - ), - ), - ) - - layout_o_oh = dict( - title="O vs OH Scaling", - xaxis=dict( - title='G_OH', - zeroline=False, - ), - yaxis=dict( - title='G_O', - zeroline=False, - ), - legend=dict( - x=-.1, - y=1.6, - font=dict( - size=10, - ), - ), - ) - #__| - - if y_ax_spec == "ooh": - return(data_ooh_oh, layout_ooh_oh) - elif y_ax_spec == "o": - return(data_o_oh, layout_o_oh) - #__| - - #__| ********************************************************************** diff --git a/orr_reaction/adsorbate_scaling.py b/orr_reaction/adsorbate_scaling.py deleted file mode 100644 index 65e890d..0000000 --- a/orr_reaction/adsorbate_scaling.py +++ /dev/null @@ -1,335 +0,0 @@ -#!/usr/bin/env python - -"""ORR/OER adsorbate energy scaling class and methods. - -Author: Raul A. Flores -""" - - -#| - IMPORT MODULES -# import numpy as np -# -# import pandas as pd -# pd.options.mode.chained_assignment = None -# -# from sklearn.linear_model import LinearRegression -# -# # import plotly.plotly as py -# import plotly.graph_objs as go -# -# -# from orr_reaction.orr_series import ORR_Free_E_Series -#__| - - -class Adsorbate_Scaling: - """ORR/OER adsorbates' dG/E of adsorption scaling. - - Development Notes: - """ - - #| - Adsorbate_Scaling **************************************************** - - def __init__(self, - tmp=42 - ): - """ - """ - #| - __init__ - self.tmp = tmp - - #__| - - def tmp_meth(self, - ): - """ - """ - #| - tmp - tmp = 42 - return(tmp) - #__| - - #__| ********************************************************************** - - -def get_g_ooh(m_ooh, b_ooh, g_oh): - """ - """ - #| - get_g_ooh - g_ooh = m_ooh * g_oh + b_ooh - return(g_ooh) - #__| - -def get_g_o(m_o, b_o, g_oh): - """ - """ - #| - get_g_o - g_o = m_o * g_oh + b_o - return(g_o) - #__| - -def get_g_oh(m_oh, b_oh, g_oh): - """ - """ - #| - get_g_oh - g_oh = m_oh * g_oh + b_oh - return(g_oh) - #__| - -def lim_U_i( - g_oh=None, - g_o_minus_g_oh=None, - - mech_step=None, # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' - gas_molec_dict=None, - scaling_dict=None, - rxn_direction="forward", - ): - """ - Calculate the following mechanistic step of the OER/ORR: - O2 + (H+ + e-) --> *OOH - - Args: - g_oh: - gas_molec_dict: - scaling_dict: - rxn_direction: - """ - #| - lim_U_i - - #| - Checking Input Types - if g_oh is None and g_o_minus_g_oh is None: - raise ValueError("Need to provide either g_oh or g_o_minus_g_oh") - - if g_oh is not None and g_o_minus_g_oh is not None: - raise ValueError("Please don't provide both g_oh and g_o_minus_g_oh") - - assert gas_molec_dict is not None, "Please provide gas_molec_dict" - assert scaling_dict is not None, "Please provide the scaling_dict" - assert mech_step is not None, "Please provide the step to calculate" - #__| - - - #| - linear fit and gas molecule data - m_ooh = scaling_dict["ooh"]["m"] - b_ooh = scaling_dict["ooh"]["b"] - - m_o = scaling_dict["o"]["m"] - b_o = scaling_dict["o"]["b"] - - m_oh = scaling_dict["oh"]["m"] - b_oh = scaling_dict["oh"]["b"] - - - g_o2 = gas_molec_dict["o2"] - g_h2 = gas_molec_dict["h2"] - g_h2o = gas_molec_dict["h2o"] - #__| - - if g_o_minus_g_oh is not None: - g_oh = (g_o_minus_g_oh - b_o) / (m_o - 1) - - elif g_oh is not None: - g_oh = g_oh - - #| - Calculating Limiting Potential for all legs - if mech_step == "o2_to_ooh": - lim_U_out = get_g_ooh(m_ooh, b_ooh, g_oh) + \ - - g_o2 - - elif mech_step == "ooh_to_o": - lim_U_out = get_g_o(m_o, b_o, g_oh) + \ - g_h2o + \ - - get_g_ooh(m_ooh, b_ooh, g_oh) - - elif mech_step == "o_to_oh": - lim_U_out = get_g_oh(m_oh, b_oh, g_oh) + \ - - get_g_o(m_o, b_o, g_oh) - - elif mech_step == "oh_to_h2o": - lim_U_out = g_h2o + \ - - get_g_oh(m_oh, b_oh, g_oh) - else: - raise ValueError("Woops, error here (9sdfijsd9)") - #__| - - if rxn_direction == "forward": - lim_U_out = - lim_U_out - elif rxn_direction == "reverse": - lim_U_out = + lim_U_out - - return(lim_U_out) - #__| - - - - -#| - __old__ - -# def lim_U_o2_to_ooh(g_oh, -# gas_molec_dict, scaling_dict, rxn_direction="forward"): -# """ -# Calculate the following mechanistic step of the OER/ORR: -# O2 + (H+ + e-) --> *OOH -# -# Args: -# g_oh: -# gas_molec_dict: -# scaling_dict: -# rxn_direction: -# """ -# #| - lim_U_o2_to_ooh -# -# #| - linear fit and gas molecule data -# m_ooh = scaling_dict["ooh"]["m"] -# b_ooh = scaling_dict["ooh"]["b"] -# -# m_o = scaling_dict["o"]["m"] -# b_o = scaling_dict["o"]["b"] -# -# m_oh = scaling_dict["oh"]["m"] -# b_oh = scaling_dict["oh"]["b"] -# -# -# g_o2 = gas_molec_dict["o2"] -# g_h2 = gas_molec_dict["h2"] -# g_h2o = gas_molec_dict["h2o"] -# #__| -# -# -# if False: -# -# g_oh = (TMP - b_o) / (m_o - 1) -# -# lim_U_out = get_g_ooh(m_ooh, b_ooh, g_oh) - g_o2 -# -# if rxn_direction == "forward": -# lim_U_out = - lim_U_out -# elif rxn_direction == "reverse": -# lim_U_out = + lim_U_out -# -# return(lim_U_out) -# #__| -# -# def lim_U_ooh_to_o(g_oh, -# gas_molec_dict, scaling_dict, rxn_direction="forward"): -# """ -# Calculate the following mechanistic step of the OER/ORR: -# *OOH + (H+ + e-) --> *O + H2O -# -# Args: -# g_oh: -# gas_molec_dict: -# scaling_dict: -# rxn_direction: -# """ -# #| - lim_U_ooh_to_o -# -# #| - linear fit and gas molecule data -# m_ooh = scaling_dict["ooh"]["m"] -# b_ooh = scaling_dict["ooh"]["b"] -# -# m_o = scaling_dict["o"]["m"] -# b_o = scaling_dict["o"]["b"] -# -# m_oh = scaling_dict["oh"]["m"] -# b_oh = scaling_dict["oh"]["b"] -# -# -# g_o2 = gas_molec_dict["o2"] -# g_h2 = gas_molec_dict["h2"] -# g_h2o = gas_molec_dict["h2o"] -# #__| -# -# lim_U_out = get_g_o(m_o, -# b_o, g_oh) + g_h2o - get_g_ooh(m_ooh, b_ooh, g_oh) -# -# if rxn_direction == "forward": -# lim_U_out = - lim_U_out -# elif rxn_direction == "reverse": -# lim_U_out = + lim_U_out -# -# return(lim_U_out) -# #__| -# -# def lim_U_o_to_oh(g_oh, -# gas_molec_dict, scaling_dict, rxn_direction="forward"): -# """ -# Calculate the following mechanistic step of the OER/ORR: -# O* + (H+ + e-) --> *OH -# -# Args: -# g_oh: -# gas_molec_dict: -# scaling_dict: -# rxn_direction: -# """ -# #| - lim_U_o_to_oh -# -# #| - linear fit and gas molecule data -# m_ooh = scaling_dict["ooh"]["m"] -# b_ooh = scaling_dict["ooh"]["b"] -# -# m_o = scaling_dict["o"]["m"] -# b_o = scaling_dict["o"]["b"] -# -# m_oh = scaling_dict["oh"]["m"] -# b_oh = scaling_dict["oh"]["b"] -# -# -# g_o2 = gas_molec_dict["o2"] -# g_h2 = gas_molec_dict["h2"] -# g_h2o = gas_molec_dict["h2o"] -# #__| -# -# lim_U_out = get_g_oh(m_oh, b_oh, g_oh) - get_g_o(m_o, b_o, g_oh) -# -# if rxn_direction == "forward": -# lim_U_out = - lim_U_out -# elif rxn_direction == "reverse": -# lim_U_out = + lim_U_out -# -# return(lim_U_out) -# #__| -# -# def lim_U_oh_to_h2o(g_oh, -# gas_molec_dict, scaling_dict, rxn_direction="forward"): -# """ -# Calculate the following mechanistic step of the OER/ORR: -# *OH + (H+ + e-) --> H2O -# -# Args: -# g_oh: -# gas_molec_dict: -# scaling_dict: -# rxn_direction: -# """ -# #| - lim_U_oh_to_h2o -# -# #| - linear fit and gas molecule data -# m_ooh = scaling_dict["ooh"]["m"] -# b_ooh = scaling_dict["ooh"]["b"] -# -# m_o = scaling_dict["o"]["m"] -# b_o = scaling_dict["o"]["b"] -# -# m_oh = scaling_dict["oh"]["m"] -# b_oh = scaling_dict["oh"]["b"] -# -# -# g_o2 = gas_molec_dict["o2"] -# g_h2 = gas_molec_dict["h2"] -# g_h2o = gas_molec_dict["h2o"] -# #__| -# -# lim_U_out = g_h2o - get_g_oh(m_oh, b_oh, g_oh) -# -# if rxn_direction == "forward": -# lim_U_out = - lim_U_out -# elif rxn_direction == "reverse": -# lim_U_out = + lim_U_out -# -# return(lim_U_out) -# #__| -# -#__| diff --git a/orr_reaction/orr_fed_plot.py b/orr_reaction/orr_fed_plot.py deleted file mode 100644 index 88873fc..0000000 --- a/orr_reaction/orr_fed_plot.py +++ /dev/null @@ -1,2231 +0,0 @@ -#!/usr/bin/env python - -"""ORR energetics classes and methods. - -Author: Raul A. Flores -""" - -#| - IMPORT MODULES -import numpy as np -import pandas as pd - -# import itertools - -from sklearn.linear_model import LinearRegression - -# import plotly.plotly as py -import plotly.graph_objs as go - -pd.options.mode.chained_assignment = None - -from orr_reaction.orr_series import ORR_Free_E_Series -from orr_reaction.adsorbate_scaling import lim_U_i -#__| - -class ORR_Free_E_Plot: - """ORR free energy diagram class. - - ACTUALLY THIS IS GOING TO BE A GENERAL ORR/OER CLASS NOW!!!!!!!!!!!!!!!!!!! - - Development Notes: - # TODO Should we consider the case where the bulk energy is not 0, and - we have to normalize all of the species energies by it? - """ - - #| - ORR_Free_E_Plot ****************************************************** - - def __init__(self, - free_energy_df=None, - ORR_Free_E_series_list=None, - # system_properties=None, - state_title="adsorbate", - free_e_title="ads_e", - num_states=5, - smart_format=None, - bias=0., - # opt_name=None, - # properties=None, - color_list=None, - # i_cnt=0, - hover_text_col=None, - # plot_mode="all", - # smart_format=None, - - # Plotting ************************************************************ - show_H_e_pairs_annotations=True, - show_legend=True, - rxn_type="ORR", # ORR and OER - ): - """ - Input variables to class instance. - - Args: - free_energy_df: - Pandas dataframe containing the adsorbates as rows - Required columns, adsorbate, free energy - system_properties: - state_title: - free_e_title: - - rxn_type: - ORR or OER - """ - #| - __init__ - - #| - Setting Instance Attributes - self.fe_df = free_energy_df - # self.sys_props = system_properties - self.state_title = state_title - self.fe_title = free_e_title - self.num_states = num_states - - # self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] - # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] #COMBAK Is this being used anymore - - self.bias = bias - self.color_list = color_list - self.hover_text_col = hover_text_col - self.smart_format = smart_format - - self.show_H_e_pairs_annotations = show_H_e_pairs_annotations - self.show_legend = show_legend - - # *********************************** - self.plot_states_sep = 0.3 - self.plot_states_width = 1. - - self.rxn_type = rxn_type - #__| - - - if self.rxn_type == "ORR": - self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] - self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - - elif self.rxn_type == "OER": - self.rxn_mech_states = ["bulk", "oh", "o", "ooh", "bulk"] - self.ideal_energy = [0, 1.23, 2.46, 3.69, 4.92] - - self.rxn_x_coord_array = self.create_rxn_coord_array( - self.num_states, - spacing=self.plot_states_sep, - step_size=self.plot_states_width, - ) - - self.mid_state_x_array = self.create_mid_state_x_array() - # x_array_data = self.rxn_x_coord_array - - if ORR_Free_E_series_list is None: - self.series_list = [] - else: - self.series_list = ORR_Free_E_series_list - - #| - __old__ - # if free_energy_df is not None: - # self.add_bulk_entry() - # self.fill_missing_data() - # - # self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk - # self.energy_lst = self.rxn_energy_lst() - # self.num_of_elec = range(self.num_of_states)[::-1] - # self.overpotential = self.calc_overpotential()[0] - # self.limiting_step = self.calc_overpotential()[1] - # # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - # self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() - # self.overpotential_h2o2 = self.calc_overpotential_h2o2() - #__| - - #__| - - def ideal_ORR_series(self, - ): - """ - """ - #| - ideal_ORR_series - # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - - ideal_data_list = [ - - { - "adsorbate": "ooh", - "ads_e": 3.69, - }, - - { - "adsorbate": "o", - "ads_e": 2.46, - }, - - { - "adsorbate": "oh", - "ads_e": 1.23, - }, - - ] - - df_ideal = pd.DataFrame(ideal_data_list) - - self.add_series( - df_ideal, - plot_mode="full_lines", # ########## - opt_name="Ideal ORR Catalyst", - smart_format=False, - color=None, - ) - - #| - __old__ - - # state_title=self.state_title, - # free_e_title=self.fe_title, - # bias=self.bias, - # - # # opt_name=None, # ####### - # # properties=opt_name, - # # color_list=self.color_list, - # # i_cnt=0, # ########## - # hover_text_col=self.hover_text_col, - # - # # smart_format=self.smart_format, - - #__| - - #__| - - def __create_series_name__(self, series_i): - """ - """ - #| - __create_series_name__ - - if series_i.properties is not None: - name_i = "" - for key, value in series_i.properties.items(): - - # TODO | This is an old feature, get rid of it - if key == "coverage": - continue - - name_i += str(key) + ": " + str(value) + " | " - - else: - name_i = "" - - return(name_i) - #__| - - def __create_smart_format_dict__(self, property_dict, smart_format_dict): - """Create smart format dictionary. - - Args: - property_dict: - smart_format_dict: - """ - #| - __create_smart_format_dict__ - if property_dict is None: - return({}) - - format_dict = {} - for key_i, value_i in property_dict.items(): - for format_i in smart_format_dict: - if list(format_i[0])[0] == key_i: - if list(format_i[0].values())[0] == value_i: - format_dict.update(format_i[1]) - - return(format_dict) - #__| - - def add_series(self, - fe_df, - plot_mode="all", - name_i=None, - group=None, - opt_name=None, - smart_format=True, - overpotential_type="ORR", - system_properties=None, - property_key_list=None, - add_overpot=True, - color=None, - ): - """Add ORR_Free_E_Series instance to ORR_Free_E_Plot.series_list. - - Note: It would be much better to simply take all of the - ORR_Free_E_Series arguments as a **kwargs term. - - Args: - TEMP - """ - #| - add_series - if smart_format: - smart_format_i = self.smart_format - else: - smart_format_i = None - - #| - __old__ - # free_energy_df=None, - # # system_properties=None, - # state_title="adsorbate", - # free_e_title="ads_e", - # - # bias=0., - # rxn_x_coord_array=None, - # opt_name=None, - # properties=None, - # color_list=None, - # i_cnt=0, - # hover_text_col=None, - # plot_mode="all", - # smart_format=None, - # overpotential_type="ORR", - # rxn_type="ORR", - - # print(system_properties) - #__| - - ORR_Series = ORR_Free_E_Series( - free_energy_df=fe_df, - properties=system_properties, - property_key_list=property_key_list, - state_title=self.state_title, - free_e_title=self.fe_title, - group=group, - bias=self.bias, - rxn_x_coord_array=self.rxn_x_coord_array, - name_i=name_i, - opt_name=opt_name, # ####### - - # properties=opt_name, - color_list=self.color_list, - color=color, - i_cnt=0, # ########## - hover_text_col=self.hover_text_col, - plot_mode=plot_mode, # ########## - smart_format=smart_format_i, - add_overpot=add_overpot, - # overpotential_type=self.rxn_type, - rxn_type=self.rxn_type, - ) - - self.series_list.append(ORR_Series) - #__| - - def plotly_data(self): - """ - """ - #| - plotly_data - master_data_list = [] - for series_i in self.series_list: - master_data_list += series_i.series_plot - - return(master_data_list) - #__| - - def plotly_fed_layout(self, - plot_title="FED", - plot_title_size=18, - tick_lab_size=16, - axes_lab_size=18, - legend_size=18, - # font_family="Computer Modern" # "Courier New, monospace" - font_family="Arial, Courier New, monospace", - plot_width=680, - plot_height=510, - annotation_size=12, - ): - """ - - Development notes: - Move all plot parameters to this method, since the user will call - this method to obtain the layout. - """ - #| - plotly_fed_layout - - if self.rxn_type == "ORR": - # xax_labels = ["$O_{2}$", "$*OOH$", "$*O$", "$*OH$", "$H_{2}O$"] - # xax_labels = ["O2", "*OOH", "*O", "*OH", "H2O"] - - xax_labels = [ - "O2", - "*OOH", - "*O", - "*OH", - "H2O", - ] - - elif self.rxn_type == "OER": - # xax_labels = ["$H_{2}O$", "$*OH$", "$*O$", "$*OOH$", "$O_{2}$"] - xax_labels = ["H2O", "*OH", "*O", "*OOH", "O2"] - # "font":dict( - # family='Arial', - # # size=18, - # color='black', - # ), - - layout = { - "title": plot_title, - - "font": { - # "family": "Courier New, monospace", - "family": font_family, - "size": plot_title_size, - "color": "black", - }, - - - #| - Axes --------------------------------------------------------- - "yaxis": { - "title": "Free Energy (eV)", - # "title": "$\\Delta G (ev)$", - - "zeroline": False, - "linecolor": 'black', - "showline": True, - "mirror": 'ticks', - "showgrid": False, - - "titlefont": dict(size=axes_lab_size), - - "tickfont": dict( - size=tick_lab_size, - ), - - # "autotick": False, - "ticks": 'inside', - "tick0": 0, - "dtick": 1.0, - "ticklen": 2, - "tickwidth": 1, - "tickcolor": 'black', - - }, - - "xaxis": { - "title": "Reaction Coordinate", - - "zeroline": False, - "linecolor": 'black', - "showline": True, - "mirror": 'ticks', - "showgrid": False, - - # "zeroline": True, - # "showgrid": False, - "titlefont": dict(size=axes_lab_size), - - "showticklabels": True, - - "ticks": "", - "ticktext": xax_labels, - # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - # "tickvals": [self.plot_states_width * i + 0.5 - # for i in range(len(xax_labels))], - "tickvals": self.mid_state_x_array, - "tickcolor": 'black', - "tickfont": dict( - size=tick_lab_size, - ), - }, - #__| -------------------------------------------------------------- - - #| - Legend ------------------------------------------------------- - "legend": { - "traceorder": "normal", - "font": dict(size=legend_size), - "x": -0.1, - "y": -1.2, - }, - - "showlegend": self.show_legend, - - #__| -------------------------------------------------------------- - - #| - Plot Size - # "width": 200 * 4., - # "height": 200 * 3., - #__| - - # "paper_bgcolor": 'rgba(0,0,0,0)', - "plot_bgcolor": 'rgba(0,0,0,0)', - - # "width": 9. * 37.795275591, - # "height": 9 * 37.795275591, - - "width": plot_width, - "height": plot_height, - } - - if self.show_H_e_pairs_annotations: - annotations = self.H_e_pairs_annotations(font_size=annotation_size) - - if "annotations" in list(layout): - layout["annotations"] += annotations - else: - layout["annotations"] = annotations - - return(layout) - #__| - - - def max_y_value_per_step(self): - """ - """ - #| - max_y_value_per_step - fe_matrix = [] - for series_i in self.series_list: - fe_matrix.append( - np.array(series_i.energy_lst), - ) - fe_matrix = np.array(fe_matrix) - - max_y_val_list = [] - for step_i in range(fe_matrix.shape[1]): - max_y_val_list.append(fe_matrix[:, step_i].max()) - - return(max_y_val_list) - #__| - - def H_e_pairs_annotations(self, - font_size=18, - ): - """ - - Args: - font_size: - """ - #| - H_e_pairs_annotations - # ann_font_size = 18 - # states_sep = self.plot_states_sep - # states_width = self.plot_states_width - - - mid_state_x_array = self.mid_state_x_array - - rxn_x_array = self.rxn_x_coord_array - max_y_val_list = self.max_y_value_per_step() - - def add_annot( - ind, - rxn_x_array, - step, - annotations, - y=5.5, - font_size=18, - text="TEMP", - mid_state_x_array=None, - ): - """Append annotation object to annotations list. - - Args: - ind: - rxn_x_array: - step: - annotations: - y: - font_size: - text: - """ - #| - add_annot - ann_i = dict( - # x=(rxn_x_array[ind] + rxn_x_array[ind + step]) / 2., - x=mid_state_x_array[ind], - y=y + 0.4, - xref='x', - yref='y', - text=text, - showarrow=False, - font=dict( - color="black", - size=font_size - ), - ), - annotations += ann_i - #__| - - annotations = [] - - add_annot( - 0, rxn_x_array, 1, annotations, - y=max_y_val_list[0], font_size=font_size, - text="4(H+ + e-)", - mid_state_x_array=mid_state_x_array, - ) - - add_annot( - 1, rxn_x_array, 2, annotations, - y=max_y_val_list[1], font_size=font_size, - text="3(H+ + e-)", - mid_state_x_array=mid_state_x_array, - ) - - add_annot( - # 3, rxn_x_array, 2, annotations, - 2, rxn_x_array, 2, annotations, - y=max_y_val_list[2], font_size=font_size, - text="2(H+ + e-)", - mid_state_x_array=mid_state_x_array, - ) - - add_annot( - # 5, rxn_x_array, 2, annotations, - 3, rxn_x_array, 2, annotations, - y=max_y_val_list[3], font_size=font_size, - text="1(H+ + e-)", - mid_state_x_array=mid_state_x_array, - ) - - add_annot( - # 7, rxn_x_array, 2, annotations, - 4, rxn_x_array, 2, annotations, - y=max_y_val_list[4], font_size=font_size, - text="0(H+ + e-)", - mid_state_x_array=mid_state_x_array, - ) - - return(annotations) - #__| - - def create_rxn_coord_array(self, - rxn_steps, - spacing=0, - step_size=1, - ): - """ - Create a reaction coordinate array ([0, 1, 1, 2, 2, 3]) for plotting. - - Args: - rxn_steps: - Number of steps in reaction coordinate including initial - and final state. - Ex. A -> Intermediate -> C has 3 steps/states - - spacing: - Spacing inbetween the energy levels. The default of 0 creates - a free energy diagram that looks like steps - """ - #| - create_rxn_coord_array - lst = [] - for i in range(1, rxn_steps): - if i == 1: - lst.append(step_size) - lst.append(step_size + spacing) - if i != 1: - lst.append(lst[-1] + step_size) - lst.append(lst[-2] + step_size + spacing) - - lst.insert(0, 0) - lst.append(lst[-1] + step_size) - - return(lst) - #__| - - - def create_mid_state_x_array(self): - """ - """ - #| - create_mid_state_x_array - x_array_data = self.rxn_x_coord_array - state_width = self.plot_states_width - - xdat = list(set(x_array_data)) - xdat.sort() - - cnt = 0 - short_x = [] - for i_ind in range(int(len(xdat) / 2)): - short_x.append(xdat[cnt] + state_width / 2.) - cnt += 2 - - return(short_x) - #__| - - - # Deprecated ************************************************************** - def create_scaling_relations_plot(self, - y_ax_spec, - x_ax_spec="oh", - smart_format_dict=None, - - x_range_ooh_vs_oh=[-1., 3.5], - y_range_ooh_vs_oh=[0., 5.], - x_range_o_vs_oh=[-1., 3.5], - y_range_o_vs_oh=[0., 5.], - x_range_oh_vs_oh=[-1., 4.], - y_range_oh_vs_oh=[-1., 4.], - ): - """Return plotly data and layout objects for scaling relations. - - Args: - y_ax_spec: - x_ax_spec: - """ - #| - create_scaling_relations_plot - - print("#########################################") - print("DEPRECATED!!!!!!!!!!!!!") - print("Use the new class Scaling_Relations_Plot") - print("#########################################") - - #| - Internal Methods - # TODO Should put these in a more accesible place - - def create_smart_format_dict(property_dict, smart_format_dict): - """Create smart format dictionary. - - Args: - property_dict: - smart_format_dict: - """ - format_dict = {} - for key_i, value_i in property_dict.items(): - for format_i in smart_format_dict: - if list(format_i[0])[0] == key_i: - if list(format_i[0].values())[0] == value_i: - format_dict.update(format_i[1]) - - return(format_dict) - - def create_series_name(series): - """ - """ - #| - create_series_name - name_i = "" - for key, value in series_i.properties.items(): - if key == "coverage": - continue - - name_i += str(key) + ": " + str(value) + " | " - - return(name_i) - #__| - - def ooh_oh_scaling(E_OH): - """Return the *OOH adsorption energy given DG_*OH by scaling. - - Args: - E_OH:DG_*OH energy of adsorption - """ - #| - ooh_oh_scaling - return(E_OH + 3.2) - - #__| - - def o_oh_scaling(E_OH): - """Return the *OOH adsorption energy given DG_*OH by scaling. - - Args: - E_OH: DG_*OH energy of adsorption. - """ - #| - o_oh_scaling - return(2 * E_OH) - #__| - - def oh_oh_scaling(E_OH): - """Return the *OH adsorption energy given DG_*OH by scaling. - - NOTE: TRIVIAL QUANTITY!!!!!!!!!!!!!!!!!!! - - Args: - E_OH: DG_*OH energy of adsorption. - """ - #| - oh_oh_scaling - return(E_OH) - #__| - - - def create_trace_i( - x_energy, - y_energy, - smart_format_i - ): - """ - """ - #| - create_trace_i - # NOTE Looks like I need to put these in a list here - x_energy = [x_energy] - y_energy = [y_energy] - - trace_i = go.Scatter( - x=x_energy, - y=y_energy, - text=name_i, - name=name_i, - mode='markers', - marker=dict( - size=14, - symbol=smart_format_i.get("symbol", "circle"), - color=smart_format_i.get("color2", "pink"), - line=dict( - # color=smart_format_i["color1"], - color=smart_format_i.get("color1", "black"), - width=2, - ) - ) - ) - - return(trace_i) - #__| - - def create_layout( - y_ax_spec, - x_ax_spec, - title="Scaling Relations", - ): - """ - """ - #| - create_layout - if y_ax_spec == "ooh": - y_ax_title = "Gads,*OOH (eV)" - elif y_ax_spec == "o": - y_ax_title = "Gads,*O (eV)" - elif y_ax_spec == "oh": - y_ax_title = "Gads,*OH (eV)" - - - if x_ax_spec == "oh": - x_ax_title = "Gads,*OH (eV)" - else: - print("Only 'oh' is supported as the x-axis variable") - - tick_lab_size = 12 * (4. / 3.) - axes_lab_size = 14 * (4. / 3.) - # legend_size = 18 - - #| - Common Axis Dict - common_axis_dict = { - - # "range": y_axis_range, - "zeroline": False, - "showline": True, - "mirror": 'ticks', - "linecolor": 'black', - "showgrid": False, - - "titlefont": dict(size=axes_lab_size), - "tickfont": dict( - size=tick_lab_size, - ), - "ticks": 'inside', - "tick0": 0, - "tickcolor": 'black', - # "dtick": 0.25, - "ticklen": 2, - "tickwidth": 1, - } - #__| - - # x_range_ooh_vs_oh=[0., 3.5], - # y_range_ooh_vs_oh=[0., 5.], - # x_range_o_vs_oh=[0., 3.5], - # y_range_o_vs_oh=[0., 5.], - - if y_ax_spec == "ooh": - x_range = x_range_ooh_vs_oh - elif y_ax_spec == "o": - x_range = x_range_o_vs_oh - elif y_ax_spec == "oh": - x_range = x_range_oh_vs_oh - else: - print("Woops - create_layout") - - if y_ax_spec == "ooh": - y_range = y_range_ooh_vs_oh - elif y_ax_spec == "o": - y_range = y_range_o_vs_oh - elif y_ax_spec == "oh": - y_range = y_range_oh_vs_oh - else: - print("Woops - create_layout") - - - layout_i = { - "title": title, - "titlefont": go.layout.Titlefont(size=24), - - "xaxis": dict( - common_axis_dict, - **{ - "title": x_ax_title, - "range": x_range, - }, - ), - - "yaxis": dict( - common_axis_dict, - **{ - "title": y_ax_title, - "range": y_range, - }, - ), - - "font": dict( - family='Arial', - # size=18, - color='black', - ), - - "width": 1.5 * 18.7 * 37.795275591, - "height": 18.7 * 37.795275591, - - "showlegend": True, - - "legend": dict( - # x=0., - # y=1.8, - font=dict( - size=10, - ), - ), - } - - return(layout_i) - #__| - - #__| - - #| - Default Smart Format Dict - if smart_format_dict is None: - print("No smart format given!") - smart_format_dict = [ - [{"bulk_system": "IrO3"}, {"color2": "green"}], - [{"bulk_system": "IrO2"}, {"color2": "yellow"}], - - [{"coverage_type": "o_covered"}, {"symbol": "s"}], - [{"coverage_type": "h_covered"}, {"symbol": "^"}], - - [{"facet": "110"}, {"color1": "red"}], - [{"facet": "211"}, {"color1": "green"}], - [{"facet": "100"}, {"color1": "black"}], - ] - #__| - - assert (x_ax_spec == "oh"), "Only *OH as the x-axis is allowed now" - - #| - Processing Data Points - data_ooh_oh = [] - data_o_oh = [] - data_oh_oh = [] - for series_i in self.series_list: - e_oh = series_i.energy_states_dict["oh"] - e_ooh = series_i.energy_states_dict["ooh"] - e_o = series_i.energy_states_dict["o"] - - smart_format_i = create_smart_format_dict( - series_i.properties, - smart_format_dict, - ) - - name_i = create_series_name(series_i) - - if series_i.color is not None: - smart_format_i["color2"] = series_i.color - - trace_i = create_trace_i(e_oh, e_ooh, smart_format_i) - data_ooh_oh.append(trace_i) - - trace_i = create_trace_i(e_oh, e_o, smart_format_i) - data_o_oh.append(trace_i) - - trace_i = create_trace_i(e_oh, e_oh, smart_format_i) - data_oh_oh.append(trace_i) - - #__| - - #| - Ideal Scaling Lines - scaling_trace = go.Scatter( - x=[x_range_ooh_vs_oh[0], x_range_ooh_vs_oh[1]], - y=[ - ooh_oh_scaling(x_range_ooh_vs_oh[0]), - ooh_oh_scaling(x_range_ooh_vs_oh[1]), - ], - name='*OOH vs *OH Scaling', - mode='lines', - line=dict( - color="black", - width=1, - ), - ) - data_ooh_oh.append(scaling_trace) - - scaling_trace = go.Scatter( - x=[x_range_o_vs_oh[0], x_range_o_vs_oh[1]], - y=[ - o_oh_scaling(x_range_o_vs_oh[0]), - o_oh_scaling(x_range_o_vs_oh[1]), - ], - name='*O vs *OH Scaling', - mode='lines', - line=dict( - color="black", - width=1, - ), - ) - data_o_oh.append(scaling_trace) - - scaling_trace = go.Scatter( - x=[x_range_oh_vs_oh[0], x_range_oh_vs_oh[1]], - y=[ - oh_oh_scaling(x_range_oh_vs_oh[0]), - oh_oh_scaling(x_range_oh_vs_oh[1]), - ], - name='*OH vs *OH Scaling', - mode='lines', - line=dict( - color="black", - width=1, - ), - ) - data_oh_oh.append(scaling_trace) - - #__| - - #| - Plot Layout Settings - - layout_ooh_oh = create_layout( - y_ax_spec, - x_ax_spec, - title="*OOH vs *OH Scaling", - ) - - layout_o_oh = create_layout( - y_ax_spec, - x_ax_spec, - title="*O vs *OH Scaling", - ) - - layout_oh_oh = create_layout( - y_ax_spec, - x_ax_spec, - title="*OH vs *OH Scaling", - ) - #__| - - if y_ax_spec == "ooh": - return(data_ooh_oh, layout_ooh_oh) - elif y_ax_spec == "o": - return(data_o_oh, layout_o_oh) - elif y_ax_spec == "oh": - return(data_oh_oh, layout_oh_oh) - #__| - - #__| ********************************************************************** - - -class Scaling_Relations_Plot(): - """Plot scaling relations and some simple fitting schemes. - - Development Notes: - TEMP - """ - - #| - Scaling_Relations_Plot *********************************************** - - def __init__(self, - ORR_Free_E_Plot, - mode="all", - - plot_range={ - "y": [1., 5.], - "x": [-2., 4.], - }, - - x_ax_species="oh", - ): - """ - Input variables to class instance. - - Args: - ORR_Free_E_Plot: - mode: - "all", "ooh_vs_oh", "o_vs_oh" - """ - #| - __init__ - self.ORR_Free_E_Plot = ORR_Free_E_Plot - - - assert (x_ax_species == "oh"), "Only *OH as the x-axis is allowed now" - self.x_ax_species = x_ax_species - - self.data_points = { - "ooh_vs_oh": [], - "o_vs_oh": [], - "oh_vs_oh": [], - } - self.data_lines = [] - - self.x_range = plot_range["x"] - self.y_range = plot_range["y"] - - # self.layout = self.__create_layout__( - # title="Scaling Relations", - # showlegend=True, - # ) - - self.scaling_dict = { - "ooh": { - "m": None, - "b": None, - }, - - "o": { - "m": None, - "b": None, - }, - - "oh": { - "m": 1., - "b": 0., - }, - - } - - self.annotations_list = [] - - #__| - - def create_scaling_relations_plot(self, - smart_format_dict=None, - ): - """Return plotly data and layout objects for scaling relations. - - Args: - y_ax_spec: - x_ax_spec: - """ - #| - create_scaling_relations_plot - - #| - Default Smart Format Dict - if smart_format_dict is None: - print("No smart format given!") - smart_format_dict = [ - [{"bulk_system": "IrO3"}, {"color2": "green"}], - [{"bulk_system": "IrO2"}, {"color2": "yellow"}], - - [{"coverage_type": "o_covered"}, {"symbol": "s"}], - [{"coverage_type": "h_covered"}, {"symbol": "^"}], - - [{"facet": "110"}, {"color1": "red"}], - [{"facet": "211"}, {"color1": "green"}], - [{"facet": "100"}, {"color1": "black"}], - ] - #__| - - #| - Processing Data Points - for series_i in self.ORR_Free_E_Plot.series_list: - - e_oh = series_i.energy_states_dict["oh"] - e_ooh = series_i.energy_states_dict["ooh"] - e_o = series_i.energy_states_dict["o"] - - - # Change self.__create_smart_format_dict__ to, - # self.ORR_Free_E_Plot.__create_smart_format_dict__ - # TODO - - smart_format_i = self.ORR_Free_E_Plot.__create_smart_format_dict__( - series_i.properties, - smart_format_dict, - ) - - # This is the old way of getting the name - # name_i = self.ORR_Free_E_Plot.__create_series_name__(series_i) - - name_i = series_i.series_name - - if series_i.color is not None: - smart_format_i["color2"] = series_i.color - - #| - ooh_vs_oh - trace_i = self.__create_trace_i__( - e_oh, - e_ooh, - smart_format_i, - name_i, - legendgroup="ooh_vs_oh", - ) - # self.data_ooh_oh.append(trace_i) - self.data_points["ooh_vs_oh"].append(trace_i) - #__| - - #| - o_vs_oh - trace_i = self.__create_trace_i__( - e_oh, - e_o, - smart_format_i, - name_i, - legendgroup="o_vs_oh", - ) - # self.data_o_oh.append(trace_i) - self.data_points["o_vs_oh"].append(trace_i) - #__| - - #| - oh_vs_oh - trace_i = self.__create_trace_i__( - e_oh, - e_oh, - smart_format_i, - name_i, - legendgroup="oh_vs_oh", - ) - # self.data_oh_oh.append(trace_i) - self.data_points["oh_vs_oh"].append(trace_i) - #__| - - #__| - - #__| - - # Deprecated, delete this later - def __create_smart_format_dict__(self, property_dict, smart_format_dict): - """Create smart format dictionary. - - Args: - property_dict: - smart_format_dict: - """ - #| - __create_smart_format_dict__ - format_dict = {} - for key_i, value_i in property_dict.items(): - for format_i in smart_format_dict: - if list(format_i[0])[0] == key_i: - if list(format_i[0].values())[0] == value_i: - format_dict.update(format_i[1]) - - return(format_dict) - #__| - - def __create_series_name__(self, series_i): - """ - """ - #| - create_series_name - name_i = "" - for key, value in series_i.properties.items(): - if key == "coverage": - continue - - name_i += str(key) + ": " + str(value) + " | " - - return(name_i) - #__| - - def __create_trace_i__(self, - x_energy, - y_energy, - smart_format_i, - name_i, - legendgroup=None, - ): - """ - """ - #| - create_trace_i - # NOTE Looks like I need to put these in a list here - x_energy = [x_energy] - y_energy = [y_energy] - - trace_i = go.Scatter( - x=x_energy, - y=y_energy, - text=name_i, - name=name_i, - mode="markers", - legendgroup=legendgroup, - marker=dict( - size=9, - symbol=smart_format_i.get("symbol", "circle"), - color=smart_format_i.get("color2", "pink"), - line=dict( - # color=smart_format_i["color1"], - color=smart_format_i.get("color1", "black"), - width=2, - ) - ) - ) - - return(trace_i) - #__| - - # NOTE | This shouldn't be an internal method - def __create_layout__(self, - # x_ax_spec="oh", - title="Scaling Relations", - showlegend=True, - layout_dict=None, - ): - """Create plotly layout dict. - - Args: - x_ax_spec: - title: - showlegend: - """ - #| - create_layout - - # if x_ax_spec == "" - if self.x_ax_species == "oh": - x_ax_title = "Gads,*OH (eV)" - else: - x_ax_title = "TEMP" - - y_ax_title = "Gads,*OH, " + \ - "Gads,*O, " + \ - "Gads,*OOH (eV)" - - tick_lab_size = 12 * (4. / 3.) - axes_lab_size = 14 * (4. / 3.) - # legend_size = 18 - - #| - Common Axis Dict - common_axis_dict = { - - # "range": y_axis_range, - "zeroline": False, - "showline": True, - "mirror": 'ticks', - "linecolor": 'black', - "showgrid": False, - - "titlefont": dict(size=axes_lab_size), - "tickfont": dict( - size=tick_lab_size, - ), - "ticks": 'inside', - "tick0": 0, - "tickcolor": 'black', - # "dtick": 0.25, - "ticklen": 2, - "tickwidth": 1, - } - #__| - - #| - __old__ - # x_range_ooh_vs_oh=[0., 3.5], - # y_range_ooh_vs_oh=[0., 5.], - # x_range_o_vs_oh=[0., 3.5], - # y_range_o_vs_oh=[0., 5.], - - # if y_ax_spec == "ooh": - # x_range = self.x_range_ooh_vs_oh - # elif y_ax_spec == "o": - # x_range = self.x_range_o_vs_oh - # elif y_ax_spec == "oh": - # x_range = self.x_range_oh_vs_oh - # else: - # print("Woops - create_layout") - # - # if y_ax_spec == "ooh": - # y_range = self.y_range_ooh_vs_oh - # elif y_ax_spec == "o": - # y_range = self._range_o_vs_oh - # elif y_ax_spec == "oh": - # y_range = self.y_range_oh_vs_oh - # else: - # print("Woops - create_layout") - #__| - - x_range = self.x_range - y_range = self.y_range - - layout_i = { - "title": title, - "titlefont": go.layout.Titlefont(size=24), - - "xaxis": dict( - common_axis_dict, - **{ - "title": x_ax_title, - "range": x_range, - }, - ), - - "yaxis": dict( - common_axis_dict, - **{ - "title": y_ax_title, - "range": y_range, - }, - ), - - # Margin - "margin": go.layout.Margin( - b=50., - l=50., - r=50., - t=50., - ), - - "font": dict( - family='Arial', - # size=18, - color='black', - ), - - "width": 1.5 * 18.7 * 37.795275591, - "height": 18.7 * 37.795275591, - - "showlegend": showlegend, - - "legend": dict( - font=dict( - size=10, - ), - ), - } - - if layout_dict is not None: - from misc_modules.misc_methods import dict_merge - dict_merge(layout_i, layout_dict) - # layout_i = {**layout_i, **layout_dict} - - return(layout_i) - #__| - - def __series_excluded__(self, - properties_i, - exclude_dict, - ): - """Whether to exclude series_i from fitting. - - Takes an 'exclude_dict' and the series properties_dict and compares - them key-by-key. If there is a match, then that series is excluded - (and the function evaluates to True) - - Args: - properties_i: - exclude_dict: - """ - #| - series_excluded - exclude_dict_keys = list(exclude_dict.keys()) - properties_i_keys = list(properties_i.keys()) - - shared_keys = list( - set(exclude_dict_keys).intersection(set(properties_i_keys)), - ) - - if len(shared_keys) < len(exclude_dict_keys): - print("series_i doesn't have a specific key!") - - value_match_list = [] - for key_i in shared_keys: - value_match_i = exclude_dict[key_i] == properties_i[key_i] - value_match_list.append(value_match_i) - - - all_props_match = all(value_match_list) - - # if all_props_match: - # print("Ignoring this series for fitting") - # - # else: - # print("Series not excluded, will include in fitting set") - - - return(all_props_match) - - #__| - - def fit_scaling_lines(self, - dependent_species, # 'ooh', 'o', 'oh' - exclude_dict=None, - ): - """Linear fit of either *O or *OOH to *OH - - Args: - dependent_species: - y-axis species 'ooh' or 'o' - """ - #| - fit_scaling_lines - - #| - LOOP - oh_list = [] - dependent_e_list = [] - for series_i in self.ORR_Free_E_Plot.series_list: - - #| - Excluding series from fitting - if exclude_dict is not None: - properties_i = series_i.properties - exclude_series = self.__series_excluded__( - properties_i, - exclude_dict, - ) - if exclude_series: - continue - #__| - - energy_i = series_i.energy_states_dict[dependent_species] - dependent_e_list.append(energy_i) - oh_list.append(series_i.energy_states_dict["oh"]) - - #__| - - X = np.array([[i] for i in oh_list]) - y = np.array(dependent_e_list) - - reg = LinearRegression().fit(X, y) - - slope_i = reg.coef_[0] - intercept_i = reg.intercept_ - - print("Scaling fit for ", dependent_species) - print("intercept_i: ", str(intercept_i)) - print("slope_i: ", str(slope_i)) - print("") - - out = {"slope": slope_i, "intercept": intercept_i} - - self.scaling_dict[dependent_species] = { - "m": slope_i, - "b": intercept_i, - } - # print("_------__)_Z(*XF(8))") - - #| - Equation Annotations - if dependent_species == "ooh": - eqn_str_i = ("" + - "GOOH=" + - str(round(slope_i, 4)) + - " GOH+" + - str(round(intercept_i, 4)) + - "" - ) - - elif dependent_species == "o": - eqn_str_i = ("" + - "GO = " + - str(round(slope_i, 4)) + - " GOH+" + - str(round(intercept_i, 4)) + - "" - ) - - annotation_i = dict( - x=0., - y=1., - xref="paper", - yref="paper", - text=eqn_str_i, - font=dict( - color="red", - family="Droid Sans Mono,Overpass", - size=9. * (4. / 3.), - ), - showarrow=False, - xanchor="left", - yshift=-11. * (4. / 3.) * len(self.annotations_list), - xshift=5., - ) - - self.annotations_list.append(annotation_i) - #__| - - - return(out) - #__| - - def add_ideal_lines(self): - """Add ideal scaling liknes to plot.""" - #| - add_ideal_lines - self.add_line({"slope": 1, "intercept": 3.2}, - name="*OOH vs *OH Scaling", - color="black", - width=1, - dash="dash", - ) - - self.add_line({"slope": 2, "intercept": 0.}, - name="*O vs *OH Scaling", - color="black", - width=1, - dash="dash", - ) - - self.add_line({"slope": 1, "intercept": 0.}, - name="*OH vs *OH Scaling", - color="black", - width=1, - dash="dash", - ) - #__| - - def add_line(self, - slope_intercept_dict, - name="add_lines - TEMP", - color="black", - width=1, - dash="dash", - ): - """Add line of form y=mx+b to plot. - - Args: - slope_intercept_dict: - name: - color: - width: - dash: - """ - #| - add_line - slope = slope_intercept_dict["slope"] - intercept = slope_intercept_dict["intercept"] - - def scaling_meth(E_OH): - """ - """ - #| - scaling_meth - out = slope * E_OH + intercept - - return(out) - #__| - - LH_bound = self.x_range[0] - RH_bound = self.x_range[1] - - scaling_trace = go.Scatter( - # x=[self.x_range_ooh_vs_oh[0], self.x_range_ooh_vs_oh[1]], - x=[LH_bound, RH_bound], - y=[ - scaling_meth(LH_bound), - scaling_meth(RH_bound), - ], - # name='Fitted scaling', - name=name, - mode='lines', - line=dict( - dash=dash, - color=color, - width=width, - ), - ) - # self.data_ooh_oh.append(scaling_trace) - self.data_lines.append(scaling_trace) - - # - # # Annotation - # ooh_vs_oh_eqn = ("" + - # "G_*OOH = " + - # str(round(SC_PLT.scaling_dict["ooh"]["m"], 5)) + - # " G_*OH + " + - # str(round(SC_PLT.scaling_dict["ooh"]["b"], 5)) + - # "" - # ) - # - # o_vs_oh_eqn = ("" + - # "G_*O = " + - # str(round(SC_PLT.scaling_dict["o"]["m"], 5)) + - # " G_*OH + " + - # str(round(SC_PLT.scaling_dict["o"]["b"], 5)) + - # "" - # ) - - #__| - - - - - - #| - __old__ - # def __ideal_ooh_oh_scaling__(self, E_OH): - # """Return the *OOH adsorption energy given DG_*OH by scaling. - # - # Args: - # E_OH:DG_*OH energy of adsorption - # """ - # #| - __ideal_ooh_oh_scaling__ - # return(E_OH + 3.2) - # #__| - # - # def __ideal_h_oh_scaling__(self, E_OH): - # """Return the *OOH adsorption energy given DG_*OH by scaling. - # - # Args: - # E_OH: DG_*OH energy of adsorption. - # """ - # #| - __ideal_h_oh_scaling__ - # return(2 * E_OH) - # #__| - # - # def __ideal_oh_oh_scaling__(self, E_OH): - # """Return the *OH adsorption energy given DG_*OH by scaling. - # - # NOTE: TRIVIAL QUANTITY!!!!!!!!!!!!!!!!!!! - # - # Args: - # E_OH: DG_*OH energy of adsorption. - # """ - # #| - __ideal_oh_oh_scaling__ - # return(E_OH) - # #__| - # - #__| - - #__| ********************************************************************** - - -class Volcano_Plot(): - """Class to plot OER/ORR volcano plots. - - Development Notes: - TEMP - """ - - #| - Volcano_Plot ********************************************************* - - def __init__(self, - ORR_Free_E_Plot, - x_ax_species="o-oh", # 'o-oh' or 'oh' - smart_format_dict=None, - plot_range=None, - ): - """ - Input variables to class instance. - - Args: - ORR_Free_E_Plot: - mode: - "all", "ooh_vs_oh", "o_vs_oh" - plot_range: - Ex.) - plot_range={ - "y": [1., 5.], - "x": [-2., 4.], - } - - """ - #| - __init__ - self.ORR_Free_E_Plot = ORR_Free_E_Plot - self.x_ax_species = x_ax_species - self.plot_range = plot_range - self.smart_format_dict = smart_format_dict - - self.data_points = [] - self.data_lines = [] - #__| - - # NOTE | Rename this create_volcano_plot - def create_volcano_relations_plot(self, - # smart_format_dict=None, - ): - """Create ORR/OER volcano plot. - - Args: - smart_format_dict: - Optional dictionary that will format data points - """ - #| - create_volcano_relations_plot - - #| - Default Smart Format Dict - smart_format_dict = self.smart_format_dict - - if smart_format_dict is None: - print("No smart format given!") - smart_format_dict = [ - [{"bulk_system": "IrO3"}, {"color2": "green"}], - [{"bulk_system": "IrO2"}, {"color2": "yellow"}], - - [{"coverage_type": "o_covered"}, {"symbol": "s"}], - [{"coverage_type": "h_covered"}, {"symbol": "^"}], - - [{"facet": "110"}, {"color1": "red"}], - [{"facet": "211"}, {"color1": "green"}], - [{"facet": "100"}, {"color1": "black"}], - ] - #__| - - #| - Processing Data Points - x_data_list = [] - y_data_list = [] - - for series_i in self.ORR_Free_E_Plot.series_list: - - #| - x-axis energy - x_spec = self.x_ax_species - if x_spec == "o-oh": - e_o = series_i.energy_states_dict["o"] - e_oh = series_i.energy_states_dict["oh"] - x_ax_energy = e_o - e_oh - else: - x_ax_energy = series_i.energy_states_dict[x_spec] - #__| - - #| - y-axis limiting potential - if self.ORR_Free_E_Plot.rxn_type == "ORR": - lim_pot_i = 1.23 - series_i.overpotential - - elif self.ORR_Free_E_Plot.rxn_type == "OER": - lim_pot_i = 1.23 + series_i.overpotential_OER - else: - print("LSDJFlksdj") - #__| - - #| - Process series_i - x_data_list.append(x_ax_energy) - y_data_list.append(lim_pot_i) - - smart_format_i = self.ORR_Free_E_Plot.__create_smart_format_dict__( - series_i.properties, - smart_format_dict, - ) - - name_i = series_i.series_name - - if series_i.color is not None: - smart_format_i["color2"] = series_i.color - - trace_i = self.__create_trace_i__( - x_ax_energy, - lim_pot_i, - smart_format_i, - name_i, - group=series_i.group, - ) - - self.data_points.append(trace_i) - #__| - - #__| - - #| - Finding plot axis limits - if self.plot_range is None: - y_axis_range = [min(y_data_list) - 0.2, max(y_data_list) + 0.2] - if self.ORR_Free_E_Plot.rxn_type == "OER": - y_axis_range.reverse() - else: - pass - - plot_range = { - "y": y_axis_range, - "x": [min(x_data_list) - 0.2, max(x_data_list) + 0.2], - } - - self.plot_range = plot_range - #__| - - #__| - - def create_volcano_lines(self, - gas_molec_dict=None, - scaling_dict=None, - plot_all_legs=True, - plot_min_max_legs=False, - trace_priority="top", # 'top' or 'bottom' - legs_to_plot=[ - "o2_to_ooh", - "ooh_to_o", - "o_to_oh", - "oh_to_h2o", - ], - line_color="black", - ): - """Create volcano data traces. - - Args: - gas_molec_dict: - scaling_dict: - plot_all_legs: - plot_min_max_legs: - trace_priority: - if 'top', the volcano lines will be placed on the top of the - plot, if 'bottom' then the data points will by on top of the - volcano - """ - #| - create_volcano_lines - out_data = [] - x_range = self.plot_range["x"] - - #| - Volcano Legs - volc_legs = [ - 'o2_to_ooh', - 'ooh_to_o', - 'o_to_oh', - 'oh_to_h2o', - ] - - energy_dict = { - 'o2_to_ooh': [], - 'ooh_to_o': [], - 'o_to_oh': [], - 'oh_to_h2o': [], - } - - #| - Create Volcano Legs (LOOP) - x_axis = np.linspace(x_range[0], x_range[1], num=500) - for leg_i in volc_legs: - for x_energy_i in x_axis: - - if self.x_ax_species == "oh": - g_oh = x_energy_i - g_o_minus_g_oh = None - - elif self.x_ax_species == "o-oh": - g_oh = None - g_o_minus_g_oh = x_energy_i - - energy_dict[leg_i].append( - lim_U_i( - g_oh=g_oh, - g_o_minus_g_oh=g_o_minus_g_oh, - # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' - mech_step=leg_i, - gas_molec_dict=gas_molec_dict, - scaling_dict=scaling_dict, - rxn_direction="forward", - ), - ) - #__| - - if plot_all_legs: - - #| - plot_all_legs - trace_o2_to_ooh = go.Scatter( - x=x_axis, - y=energy_dict["o2_to_ooh"], - name="O2->*OOH", - line=dict( - color="#e7b8bc", - width=2, - dash="solid", - ) - ) - - trace_ooh_to_o = go.Scatter( - x=x_axis, - y=energy_dict["ooh_to_o"], - name="*OOH->*O", - line=dict( - color="#afd7c3", - width=2, - dash="solid", - ) - ) - - trace_o_to_oh = go.Scatter( - x=x_axis, - y=energy_dict["o_to_oh"], - name="*O->*OH", - line=dict( - color="#b5c4e2", - width=2, - dash="solid", - ) - ) - - trace_oh_to_h2o = go.Scatter( - x=x_axis, - y=energy_dict["oh_to_h2o"], - name="*OH->H2O", - line=dict( - color="#dbcdab", - width=2, - dash="solid", - ) - ) - - if trace_priority == "top": - out_data.append(trace_o2_to_ooh) - out_data.append(trace_ooh_to_o) - out_data.append(trace_o_to_oh) - out_data.append(trace_oh_to_h2o) - - elif trace_priority == "bottom": - out_data.insert(0, trace_o2_to_ooh) - out_data.insert(0, trace_ooh_to_o) - out_data.insert(0, trace_o_to_oh) - out_data.insert(0, trace_oh_to_h2o) - #__| - - #__| - - #| - Minimum Energy Legs - energy_lists= [] - for leg_i in legs_to_plot: - energy_lists.append(energy_dict[leg_i]) - - min_max_e_list = [] - for legs in zip(*energy_lists): - if self.ORR_Free_E_Plot.rxn_type == "ORR": - energy_i = min(*legs) - - elif self.ORR_Free_E_Plot.rxn_type == "OER": - energy_i = max(*legs) - - min_max_e_list.append(energy_i) - - trace_volcano = go.Scatter( - x=x_axis, - y=min_max_e_list, - name="activity volcano", - - line=dict( - color=line_color, - width=2, - # dash="dash", - dash="5px,2px,5px,2px", - ) - ) - - if plot_min_max_legs: - if trace_priority == "top": - out_data.append(trace_volcano) - - elif trace_priority == "bottom": - out_data.insert(0, trace_volcano) - #__| - - return(out_data) - #__| - - def __create_trace_i__(self, - x_energy, - y_energy, - smart_format_i, - name_i, - # legendgroup=None, - group=None, - ): - """ - """ - #| - __create_trace_i__ - - # print(":LKJSDF_-d__D-d-d_D-D__D") - # print(list(smart_format_i.keys())) - - trace_i = go.Scatter( - x=[x_energy], - y=[y_energy], - # mode="markers+text", - mode="markers", - name=name_i, - text=name_i, - - legendgroup=group, - - hoverinfo="text", - - # hoverinfo=None, - # hoverinfosrc=None, - # hoverlabel=None, - # hoveron=None, - # hovertext=None, - # hovertextsrc=None, - - # textposition='top right', - textposition='middle left', - textfont={ - # "family": "Courier New, monospace", - # "family": font_family, - "size": 10, - "color": "black", - }, - - marker=dict( - size=smart_format_i.get("marker_size", 9), - color=smart_format_i.get("color2", "red"), - symbol=smart_format_i.get("symbol", "circle"), - line=dict( - width=smart_format_i.get("marker_border_width", 1.), - color=smart_format_i.get("color1", "black"), - ), - ), - ) - - return(trace_i) - #__| - - def get_plotly_layout(self, - showlegend=False, - width=9. * 37.795275591, - height=9. * 37.795275591, - layout_dict=None, - ): - """ - """ - #| - get_plotly_layout - - #| - Properties - # plot_title="FED" - plot_title = None - # plot_title_size = 18 - # tick_lab_size = 9 * (4. / 3.) - tick_lab_size = 8 * (4. / 3.) - axes_lab_size = 9 * (4. / 3.) - legend_size = 18 - # font_family="Computer Modern" # "Courier New, monospace" - font_family = "Arial" # "Courier New, monospace" - #__| - - # self.x_ax_spec - - if self.x_ax_species == "oh": - # xaxis_title = "dG_*OH (eV)" - xaxis_title = "dGOH (eV)" - elif self.x_ax_species == "o-oh": - # xaxis_title = "dG_*OH - dG_*O (eV)" - xaxis_title = "dGO - dGOH (eV)" - - # layout["margin"] = go.layout.Margin( - # b=50., - # l=50., - # r=50., - # t=50., - # # pad=20., - # ) - - layout = { - "title": plot_title, - - "font": { - "family": font_family, - "color": "black", - }, - - #| - Axes ----------------------------------------------------- - - #| - yaxis - "yaxis": { - "title": "Limiting Potential (V)", - # "title": "$\\Delta G (ev)$", - - "range": self.plot_range["y"], - "zeroline": False, - "showline": True, - "mirror": 'ticks', - # "linecolor": 'red', - "linecolor": 'black', - "showgrid": False, - - "titlefont": dict(size=axes_lab_size), - - "tickfont": dict( - size=tick_lab_size, - ), - "ticks": 'inside', - "tick0": 0, - "tickcolor": 'black', - "dtick": 0.1, - "ticklen": 2, - "tickwidth": 1, - }, - #__| - - #| - xaxis - "xaxis": { - # "title": "$\\Delta G_{OH} (ev)$", - "title": xaxis_title, - "range": self.plot_range["x"], - "zeroline": False, - "showline": True, - "mirror": True, - # "linecolor": 'red', - "linecolor": 'black', - "showgrid": False, - "titlefont": dict(size=axes_lab_size), - "showticklabels": True, - "ticks": 'inside', - "tick0": 0, - "dtick": 0.2, - "ticklen": 2, - "tickwidth": 1, - "tickcolor": 'black', - "tickfont": dict( - size=tick_lab_size, - ), - }, - #__| - - #__| - - "margin": go.layout.Margin( - b=50., - l=50., - r=50., - t=50., - ), - - # "paper_bgcolor": 'rgba(0,0,0,0)', - "plot_bgcolor": 'rgba(0,0,0,0)', - - #| - Legend --------------------------------------------------- - "legend": { - "traceorder": "normal", - "font": dict(size=legend_size), - "x": 0., - "y": -0.1, - # "xanchor": "left", - "yanchor": "top", - }, - - # "showlegend": False, - "showlegend": showlegend, - - #__| - - } - - #| - Plot Size Settings - # bottom_margin_size = 2.5 * 9. * 37.795275591 - plot_size_settings = { - "width": width, - "height": height, - - # "width": 9. * 37.795275591, - # "height": 9 * 37.795275591, - - # "margin": go.layout.Margin({ - # "l": 50, - # "r": 50, - # # "b": bottom_margin_size, - # # "b": 100, - # "b": 1200, - # "t": 10, - # "pad": 4, - # }), - } - - #__| - - layout = {**layout, **plot_size_settings} - - #| - Applying Layout override dict - if layout_dict is not None: - from misc_modules.misc_methods import dict_merge - dict_merge(layout, layout_dict) - - # layout_i = {**layout_i, **layout_dict} - - #__| - - return(layout) - - #__| - - - #__| ********************************************************************** - - -class Free_Energy_Plot(): - """ - Development Notes: - Take the FED methods out of the ORR_Free_E_Plot class and into this one - """ - - #| - Free_Energy_Plot ***************************************************** - - def __init__(self, - ORR_Free_E_Plot, - ): - """ - Input variables to class instance. - - Args: - ORR_Free_E_Plot: - mode: - "all", "ooh_vs_oh", "o_vs_oh" - """ - #| - __init__ - tmp = 42 - - self.ORR_Free_E_Plot = ORR_Free_E_Plot - - # self.x_ax_species = x_ax_species - # self.smart_format_dict = smart_format_dict - # self.data_points = [] - # self.data_lines = [] - #__| - - #__| ********************************************************************** diff --git a/orr_reaction/orr_methods.py b/orr_reaction/orr_methods.py deleted file mode 100644 index c460064..0000000 --- a/orr_reaction/orr_methods.py +++ /dev/null @@ -1,547 +0,0 @@ -#!/usr/bin/env python - -"""ORR energetics classes and methods. - -Author: Raul A. Flores -""" - -#| - IMPORT MODULES -import copy -import numpy as np -import pandas as pd - -from plotly.graph_objs import Scatter - -pd.options.mode.chained_assignment = None - -from orr_reaction.orr_series import ORR_Free_E_Series -#__| - -#| - __old__ -def plotly_fed_layout( - plot_title="FED", - plot_title_size=18, - tick_lab_size=16, - axes_lab_size=18, - legend_size=18, - ): - """ - """ - #| - plotly_fed_layout - xax_labels = ["O2", "OOH", "O", "OH", "H2O"] - layout = { - - "title": plot_title, - - "font": { - "family": "Courier New, monospace", - "size": plot_title_size, - "color": "black", - }, - - #| - Axes -------------------------------------------------------------- - "yaxis": { - "title": "Free Energy [eV]", - "zeroline": True, - "titlefont": dict(size=axes_lab_size), - "showgrid": False, - "tickfont": dict( - size=tick_lab_size, - ), - }, - - "xaxis": { - "title": "Reaction Coordinate", - "zeroline": True, - "titlefont": dict(size=axes_lab_size), - "showgrid": False, - - # "showticklabels": False, - - "ticktext": xax_labels, - "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - - "tickfont": dict( - size=tick_lab_size, - ), - }, - #__| ------------------------------------------------------------------- - - #| - Legend ------------------------------------------------------------ - "legend": { - "traceorder": "normal", - "font": dict(size=legend_size) - }, - #__| ------------------------------------------------------------------- - - #| - Plot Size - # "width": 200 * 4., - # "height": 200 * 3., - #__| - - } - - return(layout) - - #__| - -#__| - - -def calc_ads_e( - df_row, - bare_raw_e, - correction=0., - oxy_ref_e=-443.70964, - hyd_ref_e=-16.46018, - ): - """Calculate adsorption energies from raw DFT energetics. - - Default oxygen reference energy is based on water - - Args: - df_row: Pandas dataframe row - bare_raw_e: Bare slab raw DFT energy - correction: Energy correction (ZPE, entropy, solvation, etc.) - oxy_ref_e: - hyd_ref_e: - """ - #| - calc_ads_e - row = df_row - bare_slab = bare_raw_e - oxy_ref = oxy_ref_e - hyd_ref = hyd_ref_e - - #| - Oxygen & Hydrogen Atom Count - atoms_col = "atom_type_num_dict" - if atoms_col in list(row.index): - try: - num_O = row[atoms_col][0]["O"] - except: - num_O = 0 - - try: - num_H = row[atoms_col][0]["H"] - except: - num_H = 0 - - else: - - if row["adsorbate"] == "ooh": - num_O = 2 - num_H = 1 - elif row["adsorbate"] == "o": - num_O = 1 - num_H = 0 - elif row["adsorbate"] == "oh": - num_O = 1 - num_H = 1 - elif row["adsorbate"] == "bare": - num_O = 0 - num_H = 0 - #__| - - try: - raw_e = row["elec_energy"] - ads_e_i = raw_e - (bare_slab + num_O * oxy_ref + num_H * hyd_ref) - ads_e_i += correction - - # ads_e_i = raw_e - bare_slab - num_O * oxy_ref - num_H * hyd_ref - # ads_e_i += correction - except: - ads_e_i = None - - return(ads_e_i) - #__| - -def df_calc_adsorption_e( - df, - - oxy_ref, - hyd_ref, - - bare_slab_e, - bare_slab_var=None, - - corrections_mode="df_column", # 'corr_dict', 'df_column', None - corrections_column="gibbs_correction", - - corrections_dict=None, - ): - """Calculate and add adsorption energy column to data_frame. - - Args: - df: - """ - #| - df_calc_adsorption_e - ads_e_list = [] - for index, row in df.iterrows(): - bare_e = bare_slab_e - - #| - Correction - corr = 0. - # corr = fe_corr_dict[row["adsorbate"]] - - if corrections_mode == "df_column": - corr = row[corrections_column] - - # If "df_column" method return 0. then try to use correction_dict - if corr == 0.: - if corrections_dict is not None: - corr = corrections_dict[row["adsorbate"]] - - elif corrections_mode == "corr_dict" and corrections_dict is not None: - corr = corrections_dict[row["adsorbate"]] - else: - print("No correction being applied") - corr = 0. - #__| - - if type(bare_slab_e) == dict: - bare_e = bare_slab_e[row[bare_slab_var]] - - elif type(bare_slab_e) == float: - bare_e = bare_slab_e - - ads_e_i = calc_ads_e( - row, - # bare_slab, - bare_e, - correction=corr, - oxy_ref_e=oxy_ref, - hyd_ref_e=hyd_ref, - ) - ads_e_list.append(ads_e_i) - - df["ads_e"] = np.array(ads_e_list) - #__| - -def lowest_e_path( - df, - jobs_variables, - color_list, - create_ideal_series=True, - opt_name=None, - bias=0., - manual_props="*TEMP*", - plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", - smart_format=None, - ): - """Find the lowest energy pathway FED. - - COMBAK - - From a set of FE pathways corresponding to different sites, the lowest - energy states will be selected to construct a new FED. - - Args: - df: - jobs_variables: - Result of Jobs.tree_level_labels - color_list: - bias: - - """ - #| - lowest_e_path - - #| - Grouping By Adsorbate Type - df = copy.deepcopy(df) - groupby = copy.deepcopy(jobs_variables) - - groupby.remove("site") - groupby.remove("adsorbate") - - data_master = {} - if groupby == []: - series_list = [] - for ads_i in df.groupby("adsorbate"): - - min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] - series_list.append(min_e_row) - - df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T - data_master[manual_props] = df_i - - else: - for group_i in df.groupby(groupby): - series_list = [] - for ads_i in group_i[1].groupby("adsorbate"): - - min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] - series_list.append(min_e_row) - - df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T - data_master[group_i[0]] = df_i - - #__| - - #| - Creating Data Sets - - #| - Creating FED Datasets - data_list = [] - # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): - for i_cnt, (key, fe_dict) in enumerate(data_master.items()): - - ORR = ORR_Free_E_Plot( - free_energy_df=fe_dict, - ) - - dat_lst = ORR.plot_fed_series( - bias=bias, - opt_name=opt_name, - properties=key, - color_list=color_list, - i_cnt=i_cnt, - hover_text_col="site", - smart_format=smart_format, - ) - - data_list.extend(dat_lst) - #__| - - #| - Creating Ideal FED Dataset - if create_ideal_series: - e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) - - dat_ideal = ORR.create_plotly_series( - e_list_ideal, - group="Ideal", - name="Ideal", - color=color_list[-1], - plot_mode="full_lines", - ) - - dat_lst = data_list + dat_ideal - - else: - - dat_lst = data_list - - - #__| - - # dat_lst = data_list + dat_ideal - - #__| - - #| - Plotting - - #| - Plot Settings - plot_title_size = 18 - tick_lab_size = 16 - axes_lab_size = 18 - legend_size = 18 - #__| - - #| - Plot Layout - # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] - # layout = { - # - # "title": plot_title, - # - # "font": { - # "family": "Courier New, monospace", - # "size": plot_title_size, - # "color": "black", - # }, - # - # #| - Axes -------------------------------------------------------------- - # "yaxis": { - # "title": "Free Energy [eV]", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # - # "xaxis": { - # "title": "Reaction Coordinate", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # - # # "showticklabels": False, - # - # "ticktext": xax_labels, - # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - # - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Legend ------------------------------------------------------------ - # "legend": { - # "traceorder": "normal", - # "font": dict(size=legend_size) - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Plot Size - # # "width": 200 * 4., - # # "height": 200 * 3., - # #__| - # - # } - #__| - - layout = plotly_fed_layout(plot_title=plot_title) - - #__| - - return(dat_lst, layout) - - #__| - -def plot_all_states( - df, - jobs_variables, - color_list, - bias=0., - hover_text_col="site", - create_ideal_series=True, - plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", - smart_format=None, - ): - """ - - Args: - df: - jobs_variables: - color_list: - bias: - plot_title: - """ - #| - plot_all_states - - #| - Grouping By Adsorbate Type - - groupby = copy.deepcopy(jobs_variables) - # groupby = copy.deepcopy(Jojobs_variablesbs.tree_level_labels) - groupby.remove("adsorbate") - - data_master = {} - for group_i in df.groupby(groupby): - - data_master[group_i[0]] = group_i[1] - #__| - - #| - Creating Data Sets - - #| - Creating FED Datasets - data_list = [] - # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): - for i_cnt, (key, fe_dict) in enumerate(data_master.items()): - ORR = ORR_Free_E_Plot( - free_energy_df=fe_dict, - ) - - dat_lst = ORR.plot_fed_series( - bias=bias, - properties=key, - color_list=color_list, - i_cnt=i_cnt, - # hover_text_col="site" - hover_text_col=hover_text_col, - plot_mode="states_only", - smart_format=smart_format, - ) - - data_list.extend(dat_lst) - #__| - - #| - Creating Ideal FED Dataset - if create_ideal_series: - - e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) - - dat_ideal = ORR.create_plotly_series( - e_list_ideal, - group="Ideal", - name="Ideal", - color="red", - plot_mode="full_lines", - ) - - dat_lst = data_list + dat_ideal - #__| - - else: - dat_lst = data_list - - #__| - - #| - Plotting - - #| - Plot Settings - plot_title_size = 18 - tick_lab_size = 16 - axes_lab_size = 18 - legend_size = 12 - #__| - - #| - Plot Layout - # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] - # layout = { - # - # "title": plot_title, - # - # "font": { - # "family": "Courier New, monospace", - # "size": plot_title_size, - # "color": "black", - # }, - # - # #| - Axes -------------------------------------------------------------- - # "yaxis": { - # "title": "Free Energy [eV]", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # - # "xaxis": { - # "title": "Reaction Coordinate", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # - # # "showticklabels": False, - # - # "ticktext": xax_labels, - # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - # - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Legend ------------------------------------------------------------ - # "legend": { - # "traceorder": "normal", - # "font": dict(size=legend_size) - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Plot Size - # "width": 200 * 4., - # "height": 200 * 3., - # #__| - # - # } - #__| - - layout = plotly_fed_layout(plot_title=plot_title) - - return(dat_lst, layout) - - #__| - - #__| diff --git a/orr_reaction/orr_series.py b/orr_reaction/orr_series.py deleted file mode 100644 index 453aa95..0000000 --- a/orr_reaction/orr_series.py +++ /dev/null @@ -1,1071 +0,0 @@ -#!/usr/bin/env python - -"""ORR energetics classes and methods. - -Author: Raul A. Flores -""" - -#| - IMPORT MODULES -import copy - -import numpy as np -import pandas as pd - -from plotly.graph_objs import Scatter -pd.options.mode.chained_assignment = None -#__| - -class ORR_Free_E_Series(): - """ORR free energy diagram series class. - - Still a work in progress - - Take a 2nd look at how the bulk/bare state is being taken care of - - # TODO | The color_list approach is not good - """ - - #| - ORR_Free_E_Series **************************************************** - - def __init__(self, - free_energy_df=None, - # system_properties=None, - state_title="adsorbate", - free_e_title="ads_e", - bias=0., - rxn_x_coord_array=None, - group=None, - name_i=None, - opt_name=None, - - properties=None, - property_key_list=None, - - color_list=None, - color=None, - i_cnt=0, - hover_text_col=None, - plot_mode="all", - smart_format=None, - add_overpot=True, - # overpotential_type="ORR", - rxn_type="ORR", - fill_missing_data_w_scaling=True, - ): - """ - Input variables to class instance. - - Args: - free_energy_df: - Pandas dataframe containing the adsorbates as rows - Required columns, adsorbate, free energy - state_title: - free_e_title: - bias: - rxn_x_coord_array: - opt_name: - Optional name - string to append to the beginning of the plot series name - properties: - color_list: - i_cnt: - hover_text_col: - plot_mode: - smart_format: - - """ - #| - __init__ - - #| - Setting Instance Attributes - self.fe_df = free_energy_df - # self.sys_props = system_properties - - self.group = group - self.state_title = state_title - self.fe_title = free_e_title - - self.bias = bias - self.rxn_x_coord_array = rxn_x_coord_array - self.name_i = name_i - self.opt_name = opt_name - - self.properties = properties - - self.color_list = color_list - self.color = color - self.i_cnt = i_cnt - self.hover_text_col = hover_text_col - self.plot_mode = plot_mode - self.smart_format = smart_format - # self.overpotential_type = overpotential_type - self.rxn_type = rxn_type - - self.add_overpot = add_overpot - #__| - - if self.rxn_type == "ORR": - self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] - self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - - elif self.rxn_type == "OER": - self.rxn_mech_states = ["bulk", "oh", "o", "ooh", "bulk"] - self.ideal_energy = [0, 1.23, 2.46, 3.69, 4.92] - - - self.property_key_list = property_key_list - - # Doing this with a class method instead of in the analysis script - if properties is None: - self.properties = self.__create_property_dict__() - - if free_energy_df is not None: - self.add_bulk_entry() - self.fill_missing_data() - - # TEMP | Active Development - self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk - self.num_of_states_new = self.__num_of_states__() - - self.energy_lst = self.rxn_energy_lst() - # self.energy_lst_new = self.rxn_energy_lst_new() - - self.num_of_elec = range(self.num_of_states)[::-1] - self.overpotential = self.calc_overpotential()[0] - self.limiting_step = self.calc_overpotential()[1] - # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() - self.overpotential_h2o2 = self.calc_overpotential_h2o2() - self.overpotential_OER = self.calc_overpotential_OER()[0] - - self.energy_states_dict = self.__energy_states_dict__() - - if fill_missing_data_w_scaling: - self.__fill_nan_values__() - - # TODO | Put this outside of the if-statement - self.series_name = self.__series_plot_name__( - opt_name=self.opt_name, - properties=self.properties, - overpotential_type=self.rxn_type, - add_overpot=self.add_overpot, - ) - - # print("__-____*9dfs") - # print(self.series_name) - - self.series_plot = self.plot_fed_series( - bias=self.bias, - opt_name=self.opt_name, - properties=self.properties, - color_list=self.color_list, - i_cnt=self.i_cnt, - hover_text_col=self.hover_text_col, - plot_mode=self.plot_mode, - smart_format=self.smart_format, - overpotential_type=self.rxn_type, - ) - - #__| - - def __fill_nan_values__(self): - """Fill nan adsorption energy values from scaling relations.""" - #| - tmp - energy_dict = self.energy_states_dict - if True in list(np.isnan(list(energy_dict.values()))): - print("There is a nan in the energy dict!!!") - - if np.isnan(energy_dict["ooh"]): - if not np.isnan(energy_dict["oh"]): - print("*OOH energy set by *OH and standard scaling") - ooh_new = 1 * energy_dict["oh"] + 3.2 - energy_dict["ooh"] = ooh_new - - if np.isnan(energy_dict["o"]): - if not np.isnan(energy_dict["oh"]): - print("*O energy set by *OH and standard scaling") - o_new = 2 * energy_dict["oh"] + 0. - energy_dict["o"] = o_new - - if np.isnan(energy_dict["oh"]): - if not np.isnan(energy_dict["ooh"]): - print("*OH energy set by *OOH and standard scaling") - oh_new = energy_dict["ooh"] - 3.2 - energy_dict["oh"] = oh_new - - self.energy_states_dict = energy_dict - #__| - - def __num_of_states__(self): - """Return number of unique states. - - Looks at the uniqe number of entries in the 'adsorbate' column of the - data frame. The correct number of states for the OER and/or ORR - reaction are 4, only 2 states are needed for the peroxide reaction. - """ - #| - __num_of_states - df_i = self.fe_df - - num_of_states = len(set(df_i["adsorbate"].tolist())) - - err_mess = "There are not enough unique calcs (less than 4)" - assert num_of_states >= 4, err_mess - - return(num_of_states) - #__| - - def __energy_states_dict__(self): - """ - """ - #| - __energy_states_dict__ - energy_lst = self.energy_lst - rxn_mech_states = self.rxn_mech_states - - energy_states_dict = dict(zip(rxn_mech_states, energy_lst)) - energy_states_dict.pop("bulk", None) - - return(energy_states_dict) - # energy_states_dict - #__| - - def __create_property_dict__(self): - """ - """ - #| - __create_property_dict__ - df_i = self.fe_df - - def all_same_val(df_i, prop_i, val_1): - """ - """ - #| - all_same_val - out_list = [] - for i in df_i[prop_i].tolist(): - if i == val_1: - out_list.append(True) - else: - out_list.append(False) - - out_i = all(out_list) - return(out_i) - - # [True if i == val_1 else False for i in - # df_i[prop_i].tolist()], - #__| - - if self.property_key_list is not None: - prop_dict_i = {} - for prop_i in self.property_key_list: - val_1 = df_i[prop_i].tolist()[0] - - all_same_value = all_same_val(df_i, prop_i, val_1) - # all_same_value = all( - # [True if i == val_1 else False for i in - # df_i[prop_i].tolist()], - # ) - - if all_same_value: - prop_dict_i[prop_i] = str(val_1) - else: - prop_dict_i[prop_i] = str(None) - - return(prop_dict_i) - else: - return({}) - #__| - - def add_bulk_entry(self, - bulk_e=0.0, - ): - """ - Append a row entry to data frame corresponding to bulk state. - - Args: - bulk_e: - """ - #| - add_bulk_entry - df = self.fe_df - bulk_df = pd.DataFrame([{ - "adsorbate": "bulk", - "ads_e": bulk_e, - }]) - - # TEMP - # df = df.append(bulk_df, ignore_index=True) - df = df.append(bulk_df, ignore_index=True, sort=True) - - self.fe_df = df - #__| - - def rxn_energy_lst_h2o2(self): - """Construct energy list of h2o2 FED.""" - #| - rxn_energy_lst_h2o2 - # h2o2_e = 3.52 - - df = self.fe_df - - free_energy_list = [] - for index, row in df.iterrows(): - if row["adsorbate"] == "bulk" or row["adsorbate"] == "ooh": - free_energy_list.append(row["ads_e"]) - - # TODO | Make this parse the reaction array instead of reaction list - # Checking length of energy list - if len(free_energy_list) != 2: - # raise ValueError("Not the correct # of steps for H2O2") - print("Not the correct # of steps for H2O2") - - free_energy_list[0] += 4.92 - free_energy_list.append(3.52) - - return(free_energy_list) - #__| - - def property_list(self, column_name): - """General method to create a list from a column in the dataframe. - - The length of the list will correspond to the steps in the ORR - mechanism. - - Args: - column_name: - """ - #| - property_list - df = self.fe_df - - property_list = [] - for state in self.rxn_mech_states: - tmp = df.loc[df[self.state_title] == state] - tmp1 = tmp.iloc[0][column_name] - property_list.append(tmp1) - - # free_energy_list[0] += 4.92 - - return(property_list) - #__| - - def fill_missing_data(self): - """ - """ - #| - fill_missing_data - df = self.fe_df - df_missing_data = pd.DataFrame() - for state in self.rxn_mech_states: - df_state = df.loc[df[self.state_title] == state] - - #| - If df is missing state fill in row with NaN for energy - if df_state.empty: - df_state = pd.DataFrame([{ - self.state_title: state, - self.fe_title: np.nan, - }]) - df_missing_data = df_missing_data.append(df_state) - #__| - - self.fe_df = self.fe_df.append(df_missing_data, sort=True) - #__| - - def rxn_energy_lst(self): - """List corresponding to the steps of ORR. - - (1. O2, 2. *OOH, 3. *O, 4. *OH, 5. 2H2O) - """ - #| - rxn_energy_lst - df = self.fe_df - free_energy_list = [] - for state in self.rxn_mech_states: - df_state = df.loc[df[self.state_title] == state] - - #| - __old__ - # Not sure what this was trying to accomplish - # if len(df_state) == 2: - # state_energy_list = [] - # for j_cnt, row_j in df_state.iterrows(): - # energy_j = row_j[self.fe_title] - # state_energy_list.append(energy_j) - #__| - - #| - If df is missing state fill in row with NaN for energy - if df_state.empty: - df_state = pd.DataFrame([{ - self.state_title: state, - self.fe_title: np.nan, - }]) - #__| - - # This just takes the first species - # If you feed a df with more than one entry per species, then - # this will stupidly choose the first one - state_energy_1 = df_state.iloc[0][self.fe_title] - - #| - __old__ - # if type(state_energy_1) != float: - # print(type(state_energy_1)) - # print("DSKFJKLSDJFSjk_d--_d-d-_D_D_d-d-d-d-d___D_D_D_") - # print( - # "state_energy_1: ", - # str(state_energy_1), - # ) - # - # print( - # "type: ", - # str(type(state_energy_1)) - # ) - # - # print(isinstance(state_energy_1, np.float)) - # print(float(state_energy_1)) - # print(type(float(state_energy_1))) - # print(np.isnan(state_energy_1)) - # if isinstance(state_energy_1, np.float) is False: - # print("lkjfksjd") - #__| - - free_energy_list.append(state_energy_1) - - if self.rxn_type == "ORR": - free_energy_list[0] += 4.92 - elif self.rxn_type == "OER": - free_energy_list[-1] += 4.92 - else: - free_energy_list[0] += 4.92 - - return(free_energy_list) - #__| - - def rxn_energy_lst_new(self): - """ - """ - #| - rxn_energy_lst_new - df = self.fe_df - free_energy_list = [] - for state in self.rxn_mech_states: - df_state = df.loc[df[self.state_title] == state] - - #| - If df is missing state fill in row with NaN for energy - if df_state.empty: - df_state = pd.DataFrame([{ - self.state_title: state, - self.fe_title: np.nan, - }]) - #__| - - state_energy_list = [] - for j_cnt, row_j in df_state.iterrows(): - energy_j = row_j[self.fe_title] - state_energy_list.append(energy_j) - - free_energy_list.append(state_energy_list) - - # tmp1 = df_state.iloc[0][self.fe_title] - # free_energy_list.append(tmp1) - - if self.rxn_type == "ORR": - free_energy_list_0_new = [i + 4.92 for i in free_energy_list[0]] - free_energy_list[0] = free_energy_list_0_new - - # free_energy_list[0] += 4.92 - - elif self.rxn_type == "OER": - # free_energy_list[-1] += 4.92 - free_energy_list_new = [i + 4.92 for i in free_energy_list[-1]] - free_energy_list[-1] = free_energy_list_new - - else: - free_energy_list[0] += 4.92 - - return(free_energy_list) - #__| - - def apply_bias(self, bias, energy_list): - """Apply bias to free energies. - - Applies a potential to every species in the 4 and 2-electron process - and adjusts their free energies accordingly - """ - #| - apply_bias - mod_free_e_lst = [] # Free energy reaction path at applied bias - for energy, elec in zip(energy_list, range(len(energy_list))[::-1]): - mod_free_e_lst.append(energy - elec * bias) - - return(mod_free_e_lst) - #__| - - def calc_overpotential(self): - """ - Calculate overpotential for 4e- process. - - Returns the limiting overpotential for the given species and the - limiting reaction step in the form of a list, species_A -> species_B is - [species_A, species_B] - """ - #| - calc_overpotential - rxn_spec = self.rxn_mech_states - - overpotential_lst = [] - for energy_i in enumerate(self.energy_lst[:-1]): - energy_i_plus1 = self.energy_lst[energy_i[0] + 1] - overpotential_i = 1.23 + energy_i_plus1 - energy_i[1] - overpotential_lst.append(overpotential_i) - - overpotential = max(overpotential_lst) - lim_step_index = overpotential_lst.index(overpotential) - - limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] - out_list = [overpotential, limiting_step] - - return(out_list) - #__| - - def calc_overpotential_OER(self): - """Calculate the OER overpotential of a ORR series.""" - #| - calc_overpotential_OER - rxn_spec = self.rxn_mech_states - - overpotential_lst = [] - for energy_i in enumerate(self.energy_lst[:-1]): - energy_i_plus1 = self.energy_lst[energy_i[0] + 1] - - overpotential_i = energy_i_plus1 - energy_i[1] - 1.23 - overpotential_lst.append(overpotential_i) - - overpotential = max(overpotential_lst) - lim_step_index = overpotential_lst.index(overpotential) - - limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] - - out_list = [overpotential, limiting_step] - - return(out_list) - #__| - - def calc_overpotential_h2o2(self): - """ - Calculate overpotential for 2e- process. - - The overpotential for the 2e- process depends only on the energy of the - *OOH intermediate - """ - #| - calc_overpotential_h2o2 - df = self.fe_df - ooh_row = df[df["adsorbate"] == "ooh"] - ooh_ads_e = ooh_row.iloc[0]["ads_e"] - - op_4e = ooh_ads_e - 4.22 - - return(op_4e) - #__| - - - #| - Plotting @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - def __convert_to_plotting_list__(self, - energy_lst, - spacing=0.5, - step_size=1, - ): - """Repeat entries in energy list to conform to FED plot. - - Modifies an energy list for plotting by repeating each entry - Ex. [4.92, 3.69, ... ] -> [4.92, 4.92, 3.69, 3.69, ... ] - - Args: - energy_lst: - spacing: - step_size: - """ - #| - __convert_to_plotting_list__ - tmp_list = range(len(energy_lst) * 2) - energy_dupl_lst = [energy_lst[i // 2] for i in tmp_list] - - # rxn_coord_steps = self.create_rxn_coord_array( - # len(energy_lst), - # spacing=spacing, - # step_size=step_size, - # ) - # out_list = [rxn_coord_steps, energy_dupl_lst] - - return(energy_dupl_lst) - #__| - - def __series_plot_name__(self, - opt_name=None, - properties=None, - overpotential_type="ORR", - add_overpot=True, - ): - """Create name for series. - - Args: - bias: - opt_name: - properties: - color_list: - i_cnt: - hover_text_col: - plot_mode: - smart_format: - overpotential_type: - """ - #| - __series_plot_name__ - - #| - Getting appropriate Overpotential - if add_overpot: - if overpotential_type == "ORR": - overpot_i = self.overpotential - elif overpotential_type == "OER": - overpot_i = self.overpotential_OER - elif overpotential_type == "H2O2": - overpot_i = self.overpotential_h2o2 - else: - overpot_i = self.overpotential - else: - overpot_i = "" - #__| - - #| - Connecting properties key: values into string - if properties is not None: - properties_string_name = "" - for key_i, value_i in properties.items(): - - properties_string_name += str(key_i) - properties_string_name += "_" - properties_string_name += str(value_i) - - properties_string_name += " | " - - properties_string_name = properties_string_name[0:-3] - else: - properties_string_name = "" - #__| - - #| - Data Series Name - if opt_name is not None: - # name_i = opt_name + ": " + properties_string_name + \ - # " (OP: " + str(round(overpot_i, 2)) + ")" - - name_i = opt_name + ": " + properties_string_name - - else: - # name_i = properties_string_name + \ - # " (OP: " + str(round(overpot_i, 2)) + ")" - - name_i = properties_string_name - - if add_overpot: - name_i += " (OP: " + str(round(overpot_i, 2)) + ")" - - #__| - - # NEW | If name_i given, then just use that - if self.name_i is not None: - return(self.name_i) - - return(name_i) - #__| - - def plot_fed_series(self, - bias=0., - opt_name=None, - properties=None, - color_list=None, - i_cnt=0, - hover_text_col=None, - plot_mode="all", - smart_format=None, - overpotential_type="ORR", - ): - """ - Process data for FED plot. - - Args: - bias: - opt_name - properties: - color_list: - i_cnt: - hover_text_col: - Dataframe column name to be used for hover text - - #FIXME | This is fairly rough as of right now - """ - #| - plot_fed_series - - - e_list = self.energy_lst - e_list = self.apply_bias(bias, e_list) - - - for n, i in enumerate(e_list): - if np.isnan(i) is True: - e_list[n] = None - - if color_list is None: - color_list = ["red"] - - name_i = self.series_name - - #| - Hover Text - if hover_text_col is not None: - if type(hover_text_col) is not list: - hover_text_list = self.property_list(hover_text_col) - - else: - hover_text_lists = [] - for col_i in hover_text_col: - - # replacing nan with "" - tmp = self.property_list(col_i) - hover_text_i = ["" if x is np.nan else x for x in tmp] - hover_text_lists.append(hover_text_i) - - # TODO Removed last trailing " | " - hover_text_list = [] - for items in zip(*hover_text_lists): - - if all([True if i == "" else False for i in items]) is True: - hover_col_state_i = "" - else: - hover_col_state_i = " | ".join(items) - - hover_text_list.append(hover_col_state_i) - - else: - hover_text_list = [np.nan for j_cnt in list(range(5))] - #__| - - #| - TEMP Picking color from "color_list" or "color" variable - if self.color is not None: - color_i = self.color - else: - color_i = color_list[i_cnt - 1] - #__| - - dat_lst = self.__create_plotly_series__( - e_list, - group=name_i, - name=name_i, - hover_text=hover_text_list, - # color=color_list[i_cnt - 1], - color=color_i, - plot_mode=plot_mode, - smart_format=smart_format, - ) - - return(dat_lst) - - #| - Delete this - - # 181101 Delete this - # key = properties - # if type(key) == tuple: - # pass - # - # elif key is None: - # key = None - # else: - # key = (key,) - # 181101 Delete this - # if overpotential_type == "ORR": - # overpot_i = self.overpotential - # elif overpotential_type == "OER": - # overpot_i = self.overpotential_OER - # elif overpotential_type == "H2O2": - # overpot_i = self.overpotential_h2o2 - # else: - # overpot_i = self.overpotential - - # if key is None: - # prop_name = "" - # else: - # prop_name = "_".join([str(i) for i in key]) - # - # if opt_name is not None: - # name_i = opt_name + ": " + prop_name + \ - # " (OP: " + str(round(overpot_i, 2)) + ")" - # - # else: - # name_i = prop_name + \ - # " (OP: " + str(round(overpot_i, 2)) + ")" - #__| - - #__| - - def __create_plotly_series__(self, - energy_lst, - name="TEMP", - group="group1", - hover_text=None, - color="rgb(22, 96, 167)", - plot_mode="all", - smart_format=None, - ): - """ - Create a plotly series for the current instance. - - Args: - energy_lst: - name: - group: - color: - plot_mode: - "all" - "states_only" - "full_lines" - """ - #| - create_plotly_series - # e_list = self.__convert_to_plotting_list__(energy_lst) - # x_dat = e_list[0] - # y_dat = e_list[1] - - # e_list = self.__convert_to_plotting_list__(energy_lst) - # x_dat = e_list[0] - y_dat = self.__convert_to_plotting_list__(energy_lst) - - if hover_text is None: - hover_text = [np.nan for i_ind in range(5)] - - #| - Parameters - if plot_mode == "all": - show_leg_2 = False - elif plot_mode == "states_only": - show_leg_2 = False - elif plot_mode == "full_lines": - show_leg_2 = True - #__| - - #| - Adding Breaks in Data - x_dat = self.rxn_x_coord_array - - new_x_dat = copy.copy(x_dat) - new_y_dat = copy.copy(y_dat) - - cnt = 2 - for i_ind in range(int(len(x_dat) / 2 - 1)): - fill = new_x_dat[cnt - 1] - new_x_dat.insert(cnt, fill) - new_y_dat.insert(cnt, None) - cnt += 3 - #__| - - #| - Creating x-data in middle of states - short_y = np.array(y_dat)[::2] - - xdat = list(set(new_x_dat)) - xdat.sort() - - cnt = 0 - short_x = [] - for i_ind in range(int(len(xdat) / 2)): - short_x.append(xdat[cnt] + 0.5) # FIXME Replace 0.5 with variable - cnt += 2 - #__| - - #| - Smart Format Dict ************************************************ - - #| - DICTS - plot_parameter_dict = { - "dash": None, - } - - # smart_format = [ - # - # # [ - # # {"spinpol": True}, - # # {"dash": "dot"}, - # # ], - # - # [ - # {"system": "Fe_slab"}, - # {"dash": "dashdot"}, - # ], - # - # [ - # {"system": "N_graph_Fe"}, - # {"dash": "dot"}, - # ], - # - # [ - # {"system": "graph_Fe"}, - # {"dash": "dash"}, - # ], - # - # [ - # {"system": "graphene"}, - # {"dash": None}, - # ], - # - # ] - - #__| - - if self.fe_df is not None and smart_format is not None: - for format_i in smart_format: - - # format_i key:values - df_col_name = list(format_i[0])[0] - value_i = list(format_i[0].values())[0] - setting_name = list(format_i[1])[0] - setting_value = list(format_i[1].values())[0] - - - if df_col_name in list(self.fe_df): - - # *OOH, *O, *OH entries must have value_i as the - # column entries in the column df_col_name - - df = self.fe_df - df_wo_bulk = df[df["adsorbate"] != "bulk"] - - if all(df_wo_bulk[df_col_name] == value_i): - plot_parameter_dict.update( - {setting_name: setting_value}, - ) - - else: - print("Dataframe column " + df_col_name + " not present") - - #__| ****************************************************************** - - #| - Series Color - if "color" in list(plot_parameter_dict): - color_out = plot_parameter_dict["color"] - else: - plot_parameter_dict["color"] = color - #__| - - #| - Plotly Scatter Plot Instances - - #| - Thick horizontal state lines - data_1 = Scatter( - x=new_x_dat, - y=new_y_dat, - legendgroup=group, - showlegend=True, - name=name, - hoverinfo="none", # TEMP - 180317 - # text=hover_text, - - connectgaps=False, - line=dict( - # color=color, - color=plot_parameter_dict["color"], - - # COMBAK - # width=2, - width=4, - - # dash="dot", # TEMP - dash=plot_parameter_dict["dash"], # TEMP - ), - mode="lines", - ) - #__| - - #| - Full, thin line - data_2 = Scatter( - x=new_x_dat, - y=new_y_dat, - legendgroup=group, - name=name, - connectgaps=True, - showlegend=show_leg_2, - hoverinfo="none", - text=hover_text, - - line=dict( - # color=color, - color=plot_parameter_dict["color"], - width=1, - ), - mode="lines", - ) - #__| - - #| - Points in middle of energy states - data_3 = Scatter( - x=short_x, - y=short_y, - legendgroup=group, - name=name, - showlegend=False, - hoverinfo="y+text", - text=hover_text, - marker=dict( - size=14, - color=color, - opacity=0., - ), - mode="markers", - ) - #__| - - #__| - - #| - Plot Mode (which data series to plot) - - if plot_mode == "all": - data_lst = [data_1, data_2, data_3] - elif plot_mode == "states_only": - data_lst = [data_1, data_3] - elif plot_mode == "full_lines": - data_lst = [data_2, data_3] - #__| - - return(data_lst) - #__| - - - #__| @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - - #__| - - - - -#| - __old__ - - #| - __old__ - # bias=0., - # opt_name=None, - # properties=None, - # color_list=None, - # i_cnt=0, - # hover_text_col=None, - # plot_mode="all", - # smart_format=None, - #__| - - #| - __old__ - # def create_rxn_coord_array(self, - # rxn_steps, - # spacing=0, - # step_size=1, - # ): - # """ - # Create a reaction coordinate array ([0, 1, 1, 2, 2, 3]) for plotting. - # - # Args: - # rxn_steps: - # Number of steps in reaction coordinate including initial - # and final state. - # Ex. A -> Intermediate -> C has 3 steps/states - # - # spacing: - # Spacing inbetween the energy levels. The default of 0 creates - # a free energy diagram that looks like steps - # """ - # #| - create_rxn_coord_array - # lst = [] - # for i in range(1, rxn_steps): - # if i == 1: - # lst.append(step_size) - # lst.append(step_size + spacing) - # if i != 1: - # lst.append(lst[-1] + step_size) - # lst.append(lst[-2] + step_size + spacing) - # - # lst.insert(0, 0) - # lst.append(lst[-1] + step_size) - # - # return(lst) - # #__| - #__| - -#__| From f1b7092ee62ff1c3523ee5fbf457ac62feb0c945 Mon Sep 17 00:00:00 2001 From: raulf2012 Date: Sun, 14 Jul 2019 11:16:59 -0700 Subject: [PATCH 03/16] Update .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 3a601dc..373489e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ # My additions # ################ *.pyc +* conflicted copy * +*__pycache__* + # Compiled source # ################### From a364b8b29728aae755199f9f1b3208ef43af79ef Mon Sep 17 00:00:00 2001 From: raulf2012 Date: Tue, 6 Aug 2019 17:12:33 -0700 Subject: [PATCH 04/16] Whole file shown as diffed because of line endings or something --- .gitignore | 100 +- .idea/00_PythonModules.iml | 20 +- .idea/misc.xml | 6 +- .idea/modules.xml | 14 +- .idea/vcs.xml | 10 +- .idea/workspace.xml | 276 +- __misc__/sc_temp_methods.py | 144 +- ase_modules/dft_params.py | 1108 +- ase_modules/get_G.py | 1604 +- atoms_objects/slab_generation.py | 262 +- bader_charge/bader.py | 616 +- classical_methods/lennard_jones.py | 348 +- dft_job_automat/compute_env.py | 351 +- dft_job_automat/job_setup.py | 2840 +-- dft_post_analysis/charge_density.py | 918 +- dft_post_analysis/wf.py | 230 +- docs/Makefile | 38 +- docs/all-about-me.rst | 22 +- docs/index.rst | 80 +- energetics/formation_energy.py | 216 +- oxr_reaction/adsorbate_scaling.py | 678 +- oxr_reaction/oxr_methods.py | 1100 +- oxr_reaction/oxr_rxn.py | 1764 +- oxr_reaction/oxr_series.py | 1274 +- periodic_table.json | 19270 ++++++++-------- .../lennard_jones_regress/lj_regression.py | 1344 +- .../old.lj_regression_180724.py | 1306 +- 27 files changed, 17249 insertions(+), 18690 deletions(-) diff --git a/.gitignore b/.gitignore index 373489e..5a74899 100644 --- a/.gitignore +++ b/.gitignore @@ -1,50 +1,50 @@ -# My additions # -################ -*.pyc -* conflicted copy * -*__pycache__* - - -# Compiled source # -################### -*.com -*.class -*.dll -*.exe -*.o -*.so - -# Packages # -############ -# it's better to unpack these files and commit the raw source -# git has its own built in compression methods -*.7z -*.dmg -*.gz -*.iso -*.jar -*.rar -*.tar -*.zip - -# Logs and databases # -###################### -*.log -*.sql -*.sqlite - -# OS generated files # -###################### -.DS_Store -.DS_Store? -._* -.Spotlight-V100 -.Trashes -ehthumbs.db -Thumbs.db - -# readthedocs Documentation # -############################# -_build -_static -_templates +# My additions # +################ +*.pyc +* conflicted copy * +*__pycache__* + + +# Compiled source # +################### +*.com +*.class +*.dll +*.exe +*.o +*.so + +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Logs and databases # +###################### +*.log +*.sql +*.sqlite + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# readthedocs Documentation # +############################# +_build +_static +_templates diff --git a/.idea/00_PythonModules.iml b/.idea/00_PythonModules.iml index 6711606..9c88284 100644 --- a/.idea/00_PythonModules.iml +++ b/.idea/00_PythonModules.iml @@ -1,11 +1,11 @@ - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 1650565..9c1a2cb 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 9252079..b0a0b8b 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -1,8 +1,8 @@ - - - - - - - + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 94a25f7..9661ac7 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 48cacfb..701c272 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -1,139 +1,139 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + 1523863445926 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/__misc__/sc_temp_methods.py b/__misc__/sc_temp_methods.py index be06545..69344dc 100644 --- a/__misc__/sc_temp_methods.py +++ b/__misc__/sc_temp_methods.py @@ -1,72 +1,72 @@ -#/usr/bin/env python - -"""Temporary storage location for methods. - -Methods here should be fleshed out and included somewhere in 00_PythonModules -""" - -def color_scale_interp( - input_num, - max_num, - min_num, - color_mesh_size=80, - hex_mode=True, - ): - """ - """ - #| - color_scale_interp -# cl.scales["8"]["seq"]["Purples"] - - black_white_cs = [ - 'rgb(0,0,0)', - 'rgb(255,255,255)', - ] - - black_red_cs = [ - 'rgb(0,0,0)', - 'rgb(255,0,0)', - ] - - color_scale_i = black_red_cs - - color_scale_i = cl.scales["8"]["seq"]["Greys"][::-1] -# color_scale_i = cl.scales["8"]["seq"]["Purples"] -# color_scale_i = cl.scales['3']['div']['RdYlBu'] - - color_scale = cl.interp( - color_scale_i, - color_mesh_size, - ) - - color_scale = cl.to_rgb(color_scale) - - # Converting RGB string representatino to tuple - color_scale = cl.to_numeric(color_scale) - - input_norm = ((input_num - min_num)/ (max_num - min_num)) - - cs_index = round(input_norm * len(color_scale)) - 1 - if cs_index == -1: - cs_index = 0 - color_out = color_scale[cs_index] - - if hex_mode: - def rgb_to_hex(rgb_tuple): - """ - """ - r = int(rgb_tuple[0]) - g = int(rgb_tuple[1]) - b = int(rgb_tuple[2]) - - def clamp(x): - return max(0, min(x, 255)) - - hex_rep = "#{0:02x}{1:02x}{2:02x}".format(clamp(r), clamp(g), clamp(b)) - return(hex_rep) - - color_out = rgb_to_hex(color_out) - - - return(color_out) - - #__| +#/usr/bin/env python + +"""Temporary storage location for methods. + +Methods here should be fleshed out and included somewhere in 00_PythonModules +""" + +def color_scale_interp( + input_num, + max_num, + min_num, + color_mesh_size=80, + hex_mode=True, + ): + """ + """ + #| - color_scale_interp +# cl.scales["8"]["seq"]["Purples"] + + black_white_cs = [ + 'rgb(0,0,0)', + 'rgb(255,255,255)', + ] + + black_red_cs = [ + 'rgb(0,0,0)', + 'rgb(255,0,0)', + ] + + color_scale_i = black_red_cs + + color_scale_i = cl.scales["8"]["seq"]["Greys"][::-1] +# color_scale_i = cl.scales["8"]["seq"]["Purples"] +# color_scale_i = cl.scales['3']['div']['RdYlBu'] + + color_scale = cl.interp( + color_scale_i, + color_mesh_size, + ) + + color_scale = cl.to_rgb(color_scale) + + # Converting RGB string representatino to tuple + color_scale = cl.to_numeric(color_scale) + + input_norm = ((input_num - min_num)/ (max_num - min_num)) + + cs_index = round(input_norm * len(color_scale)) - 1 + if cs_index == -1: + cs_index = 0 + color_out = color_scale[cs_index] + + if hex_mode: + def rgb_to_hex(rgb_tuple): + """ + """ + r = int(rgb_tuple[0]) + g = int(rgb_tuple[1]) + b = int(rgb_tuple[2]) + + def clamp(x): + return max(0, min(x, 255)) + + hex_rep = "#{0:02x}{1:02x}{2:02x}".format(clamp(r), clamp(g), clamp(b)) + return(hex_rep) + + color_out = rgb_to_hex(color_out) + + + return(color_out) + + #__| diff --git a/ase_modules/dft_params.py b/ase_modules/dft_params.py index c0f36c3..0d18c89 100644 --- a/ase_modules/dft_params.py +++ b/ase_modules/dft_params.py @@ -1,554 +1,554 @@ -#!/usr/bin/env python - -"""DFT calculator's default parameters. - -User Notes: - Must set COMPENV environment variable - (actually not a big deal if not using AWS cluster) - -Development Notes: - TODO Automatically scale bands with system size - TODO Call test_check in the write method or something so that I won't have - to call it manually - -""" - -#| - Import Modules -import os -import json - -# My Modules -from dft_job_automat.compute_env import ComputerCluster -#__| - -class DFT_Params: - """Base class for DFT parameters encapsulation.""" - - #| - DFT_Params ************************************************************ - - def __init__(self): - """Initialize base class.""" - #| - __init__ - self.file_name = "dft-params" - self.compute_env = os.environ.get("COMPENV") - - self.submission_params = self.load_submission_params() - #__| - - # def load_submission_params(self, filename=".submission_params.json"): - def load_submission_params(self, filename=".submission_params_2.json"): - """Attempt to load submission parameters from file. - - Args: - filename: - Name of file containing submission parameters in a json - file format. The file is created automatically from my - comp_env module when used in conjuction witht he job - submission script. - """ - #| - load_submission_params - submission_params = None - if os.path.isfile(filename): - with open(filename, "r") as fle: - submission_params = json.load(fle) - - elif os.path.isfile(".submission_params.json"): - with open(filename, "r") as fle: - submission_params = json.load(fle) - else: - print("Couldn't read submission_params file") - - return(submission_params) - #__| - - def load_params(self, dir=".", update_params=True): - """Import JSON file containing parameters in dictionary. - - Args: - dir: - update_params: - """ - #| - load_params - try: - data = open(dir + "/dft-params.json").read() - data = json.loads(data) - - if update_params is True: - self.update_params(data) - else: - self.params = data - - except: - pass - #__| - - def PythonPath(self): - """Return PYTHONPATH system variable_lst. - - Checks dir is checked for default_espresso_params file - """ - #| - PythonPath - pyth_paths = os.environ["PYTHONPATH"].split(os.pathsep) - - - pyth_path = [x for x in pyth_paths if "00_PythonModules" in x] - - #FIX | Assertion breaks whenver .bashrc is source multiple times, b.c. - # redundant paths are duplicated in the PYTHONPATH variable - - # assert len(pyth_path) == 1, "Unique PYTHONPATH dir not found" - - return pyth_path[0] - - #__| - - def update_params(self, new_params, user_update=True): - """Update parameter dict with new keys or new values for old keys. - - Args: - new_params: - user_update: - """ - #| - update_params - self.params.update(new_params) - - if user_update: - mod_d_new = {x: True for x in new_params} - self.mod_dict.update(mod_d_new) - #__| - - def write_params(self, path_i=".", overwrite=False): - """Write parameters to file in getcwd. - - TODO Do not create higher versions _1, _2, _3 if they are identical - - Args: - path: - overwrite:s - """ - #| - write_params - - def json_dump_command(params, file): - #| - json_dump_command - json.dump(params, file, indent=2, skipkeys=True) - #__| - - num_files = [fle for fle in os.listdir(path_i) if "dft-params" in fle] - num_files = len(num_files) - - if overwrite is False: - if not os.path.exists(self.file_name + ".json"): - with open(path_i + "/" + self.file_name + ".json", "w") as fle: - json_dump_command(self.params, fle) - else: - fle_name = path_i + "/" + self.file_name + "_" + \ - str(num_files) + ".json" - with open(fle_name, "w") as fle: - json_dump_command(self.params, fle) - else: - with open(path_i + "/" + self.file_name + ".json", "w+") as fle: - json_dump_command(self.params, fle) - #__| - - #__| *********************************************************************** - -class VASP_Params(DFT_Params): - """Useful method to define VASP parameters for DFT job.""" - - #| - VASP_Params *********************************************************** - def __init__(self, load_defaults=True): - """Class encapsulating VASP job parameters. - - Args: - load_defaults: - """ - #| - __init__ - # self.pymoddir = self.PythonPath() - DFT_Params.__init__(self) - - if load_defaults: - self.params = self.default_params() - else: - self.params = {} - - self.mod_dict = self.create_mod_dict() - - # self.params = self.load_params(self.pymoddir, - # "default_espresso_params.json") - #__| - - def default_params(self): - """User-defined default DFT parameters.""" - #| - default_params - - # Do calculation - my_encut = 500 - my_enaug = 750 - my_kpts = (1, 1, 1) - my_ediff = 0.00001 - my_nsw = 200 # 0 for ASE, > 0 for VASP internal - my_prec = "Normal" # "Normal" or "Accurate" - my_istart = 0 # 0 = new job, 1: - my_npar = 4 - my_ibrion = 1 # RMM-DIIS - my_isif = 2 - my_fmax = -0.001 # ev/ang, tighter converergence - my_ispin = 2 - - params = {} - - params["ivdw"] = 0 - # params["ivdw"] = 12 - - # Dipole Correction - params["ldipol"] = False - # params["idipol"] = 4 - # params[dipol] = [0.5, 0.5, 0,5] # Center of cell - - params["kpts"] = my_kpts - params["encut"] = my_encut - params["enaug"] = my_enaug - - params["ispin"] = my_ispin - params["nsw"] = my_nsw - params["prec"] = my_prec - params["istart"] = my_istart - params["isif"] = my_isif - - # IBRION - params["ibrion"] = my_ibrion - # - - params["ismear"] = 0 - params["sigma"] = 0.05 - - params["icharg"] = 2 - params["lasph"] = True - params["voskown"] = 1 - params["algo"] = "Normal" - params["lreal"] = False - - # convergence Parameters - params["ediff"] = my_ediff - params["ediffg"] = my_fmax - - # Bader Charge Analysis - params["laechg"] = False - - # Output Options - params["nwrite"] = 1 - params["lcharg"] = True - params["lwave"] = False - - # Symmetry - params["isym"] = 0 - - # Functional Type - - # Different VASP versions use 'pbe' vs 'PBE' - if self.compute_env == "aws": - pbe_val = "pbe" - elif self.compute_env == "slac": - pbe_val = "PBE" - else: - pbe_val = "PBE" - # print(pbe_val) # TEMP_PRINT - params["xc"] = pbe_val # TEMP - params["gga"] = " PE" # sets the PBE functional - - # Compuational Parameters - params["npar"] = my_npar - params["nsim"] = 1 - params["nelmin"] = 4 - params["nelm"] = 100 - params["lplane"] = True - - # Dielectric Matrix density functional perturbation theory - params["lepsilon"] = False - - return(params) - #__| - - def create_mod_dict(self): - """ - Create modification book-keepig dictionary. - - Dictionary which keeps track of whether parameter has been updated - externally in script or if it kept at its default value. - This is useful to know for the dependent-parameters. - """ - #| - create_mod_dict - param_keys = list(self.params.keys()) - mod_dict = dict((key, False) for key in param_keys) - - return(mod_dict) - #__| - - - #__| *********************************************************************** - -class Espresso_Params(DFT_Params): - """Useful method to define quantum espresso parameters for DFT job.""" - - #| - Espresso_Params ******************************************************* - def __init__(self, load_defaults=True): - """Class encapsulating quantum espresso job parameters. - - Args: - load_defaults: - """ - #| - __init__ - DFT_Params.__init__(self) - - if load_defaults: - self.params = self.default_params() - else: - self.params = {} - - self.mod_dict = self.create_mod_dict() - #__| - - def default_params(self): # ********************************************** - """User-defined default DFT parameters.""" - #| - default_params - params = {} - - params["pw"] = 500 # plane-wave cutoff - params["dw"] = 5000 # density cutoff - params["dipole"] = {"status": True} # Turn on only for slabs not bulk - params["xc"] = "BEEF-vdW" # exchange-correlation functional - params["kpts"] = (3, 3, 1) # k-points for hexagonal symm in 2-D mater - - # TODO Scale number of bands with system size - params["nbands"] = -50 - - #| - Spin & Magnitism - # Spin-polarized calculation - params["spinpol"] = False - - # Non-collinear magnetism, magnetization in generic direction - params["noncollinear"] = False - #__| - - params["sigma"] = 0.1 # Should be low for spin calculations - - params["beefensemble"] = True - - # Parallelization <---------------------------------------------------- - params["parflags"] = None - - #| - Convergence Parameters - params["convergence"] = { - "energy": 1e-5, # convergence parameters - - # TF (Normal) or local-TF (Better for inhomogeneous systems) - "mixing_mode": "local-TF", - "mixing": 0.2, - "nmix": 20, # num of iter used in mixing scheme (Default 8) - "maxsteps": 500, - "diag": "david", - } - #__| - - #| - File Output <----------------------------------------------------- - params["output"] = { - "avoidio": True, - "removesave": True, - "removewf": True, - "wf_collect": False, - } - - params["outdir"] = "calcdir" - #__| - - return(params) - #__| - - def create_mod_dict(self): - """Create modification book-keepig dictionary. - - Dictionary which keeps track of whether parameter has been updated - externally in script or if it kept at its default value. - This is useful to know for the dependent-parameters. - """ - #| - create_mod_dict - param_keys = list(self.params.keys()) - mod_dict = dict((key, False) for key in param_keys) - - return(mod_dict) - #__| - - def test_check(self): - """Attempts to set params based on other dependent parameters. - - Ex.) If spinpol == True, then sigma should be smaller, 0.01ish - (Charlotte told me) - - Only set this dependent param if the user has not explicitly done so, - is what the condition for setting a parameter automatically is. - """ - #| - test_check - - #| - Setting dw to 10 * pw - if self.mod_dict["dw"] is False: - dw_i = 10. * self.params["pw"] - self.update_params({"dw": dw_i}, user_update=False) - #__| - - #| - Decreasing Sigma for Spin Polarization Calculations - if self.mod_dict["sigma"] is False: - if self.params["spinpol"] is True: - sigma_i = 0.02 - self.update_params({"sigma": sigma_i}, user_update=False) - #__| - - #| - BEEF Ensemble of Energies ========================================= - - #| - Removing Beef-Ensemble if XC-Functional Not BEEF - xc_list = self.params["xc"] - if "beefensemble" in self.params: - if self.params["beefensemble"] is True and "BEEF" not in xc_list: - print("Functional not compatible with BEEF-ensemble method") - self.update_params({"beefensemble": False}, user_update=False) - self.update_params({"printensemble": False}, user_update=False) - else: - pass - #__| - - #| - Turn on printensemble Parameter for BEEF Ensemble of Energies - xc_list = self.params["xc"] - if "beefensemble" in self.params: - if self.params["beefensemble"] is True and "BEEF" in xc_list: - print("Espresso_Params | " - "test_check | Turning on printensemble" - ) - self.update_params({"printensemble": True}, user_update=False) - else: - pass - - #__| - - #| - Turn off BEEF on AWS - # NOTE This is new (180412 - RF), check that it works - CC = ComputerCluster() - if CC.cluster_sys == "aws": - if "beefensemble" in self.params: - if self.params["beefensemble"] is True: - print("Espresso_Params | " - "test_check | Attempting to use BEEF ensemble on AWS, " - "which doesn't support it at this time, " - "BEEF ensemble tags will be turned off" - ) - - self.update_params({ - "beefensemble": False}, - user_update=False, - ) - - self.update_params({ - "printensemble": False}, - user_update=False, - ) - - #__| - - #__| ================================================================== - - #| - Parallelization - if self.mod_dict["parflags"] is False: - if type(self.submission_params) == dict: - if "nodes" in self.submission_params: - num_nodes = self.submission_params["nodes"] - - self.update_params( - {"parflags": "-npool " + str(int(num_nodes))}, - user_update=False, - ) - - # TEMP_PRINT - print("098sddfkfs--s-s-__-_") - print("-npool " + str(int(num_nodes))) - #__| - - #__| - - #__| ********************************************************************** - - - - - -#| - __old__ | default_params with all the commented lines -# params = {} -# -# # params["mode"] = "ase3" -# # params["opt_algorithm"] = "bfgs" -# # params["cell_dynamics"] = "bfgs" -# -# params["pw"] = 500 # plane-wave cutoff -# params["dw"] = 5000 # density cutoff -# params["dipole"] = {"status": True} # Turn on only for slabs not bulk -# params["xc"] = "BEEF-vdW" # exchange-correlation functional -# params["kpts"] = (3, 3, 1) # k-points for hexagonal symm in 2-D mater -# -# # TODO Scale number of bands with system size -# params["nbands"] = -50 -# -# #| - Spin & Magnitism -# # Spin-polarized calculation -# params["spinpol"] = False -# -# # Non-collinear magnetism, magnetization in generic direction -# params["noncollinear"] = False -# #__| -# -# params["sigma"] = 0.1 # Should be low for spin calculations -# -# # pseudopotential path -# # params["psppath"] = "/home/vossj/suncat/psp/gbrv1.5pbe/" -# -# params["beefensemble"] = True -# -# # Parallelization <---------------------------------------------------- -# # params["parflags"] = "-npool " -# params["parflags"] = None -# -# #| - Convergence Parameters -# params["convergence"] = { -# "energy": 1e-5, # convergence parameters -# -# # TF (Normal) or local-TF (Better for inhomogeneous systems) -# "mixing_mode": "local-TF", -# "mixing": 0.2, -# "nmix": 20, # num of iter used in mixing scheme (Default 8) -# "maxsteps": 500, -# "diag": "david", -# } -# #__| -# -# #| - File Output <----------------------------------------------------- -# -# # output = {'disk_io':'default', # how often espresso writes wavefunctions to disk -# # 'avoidio':False, # will overwrite disk_io parameter if True -# # 'removewf':True, -# # 'removesave':False, -# # 'wf_collect':False}, -# -# -# # params["output"] = {"removesave": True} # Aayush, saves ~nothing -# params["output"] = { -# -# # "avoidio": False, -# # "removesave": False, -# # "removewf": False, -# # "wf_collect": False, -# -# "avoidio": True, -# "removesave": True, -# "removewf": True, -# "wf_collect": False, -# } -# -# params["outdir"] = "calcdir" -# return(params) -#__| +#!/usr/bin/env python + +"""DFT calculator's default parameters. + +User Notes: + Must set COMPENV environment variable + (actually not a big deal if not using AWS cluster) + +Development Notes: + TODO Automatically scale bands with system size + TODO Call test_check in the write method or something so that I won't have + to call it manually + +""" + +#| - Import Modules +import os +import json + +# My Modules +from dft_job_automat.compute_env import ComputerCluster +#__| + +class DFT_Params: + """Base class for DFT parameters encapsulation.""" + + #| - DFT_Params ************************************************************ + + def __init__(self): + """Initialize base class.""" + #| - __init__ + self.file_name = "dft-params" + self.compute_env = os.environ.get("COMPENV") + + self.submission_params = self.load_submission_params() + #__| + + # def load_submission_params(self, filename=".submission_params.json"): + def load_submission_params(self, filename=".submission_params_2.json"): + """Attempt to load submission parameters from file. + + Args: + filename: + Name of file containing submission parameters in a json + file format. The file is created automatically from my + comp_env module when used in conjuction witht he job + submission script. + """ + #| - load_submission_params + submission_params = None + if os.path.isfile(filename): + with open(filename, "r") as fle: + submission_params = json.load(fle) + + elif os.path.isfile(".submission_params.json"): + with open(filename, "r") as fle: + submission_params = json.load(fle) + else: + print("Couldn't read submission_params file") + + return(submission_params) + #__| + + def load_params(self, dir=".", update_params=True): + """Import JSON file containing parameters in dictionary. + + Args: + dir: + update_params: + """ + #| - load_params + try: + data = open(dir + "/dft-params.json").read() + data = json.loads(data) + + if update_params is True: + self.update_params(data) + else: + self.params = data + + except: + pass + #__| + + def PythonPath(self): + """Return PYTHONPATH system variable_lst. + + Checks dir is checked for default_espresso_params file + """ + #| - PythonPath + pyth_paths = os.environ["PYTHONPATH"].split(os.pathsep) + + + pyth_path = [x for x in pyth_paths if "00_PythonModules" in x] + + #FIX | Assertion breaks whenver .bashrc is source multiple times, b.c. + # redundant paths are duplicated in the PYTHONPATH variable + + # assert len(pyth_path) == 1, "Unique PYTHONPATH dir not found" + + return pyth_path[0] + + #__| + + def update_params(self, new_params, user_update=True): + """Update parameter dict with new keys or new values for old keys. + + Args: + new_params: + user_update: + """ + #| - update_params + self.params.update(new_params) + + if user_update: + mod_d_new = {x: True for x in new_params} + self.mod_dict.update(mod_d_new) + #__| + + def write_params(self, path_i=".", overwrite=False): + """Write parameters to file in getcwd. + + TODO Do not create higher versions _1, _2, _3 if they are identical + + Args: + path: + overwrite:s + """ + #| - write_params + + def json_dump_command(params, file): + #| - json_dump_command + json.dump(params, file, indent=2, skipkeys=True) + #__| + + num_files = [fle for fle in os.listdir(path_i) if "dft-params" in fle] + num_files = len(num_files) + + if overwrite is False: + if not os.path.exists(self.file_name + ".json"): + with open(path_i + "/" + self.file_name + ".json", "w") as fle: + json_dump_command(self.params, fle) + else: + fle_name = path_i + "/" + self.file_name + "_" + \ + str(num_files) + ".json" + with open(fle_name, "w") as fle: + json_dump_command(self.params, fle) + else: + with open(path_i + "/" + self.file_name + ".json", "w+") as fle: + json_dump_command(self.params, fle) + #__| + + #__| *********************************************************************** + +class VASP_Params(DFT_Params): + """Useful method to define VASP parameters for DFT job.""" + + #| - VASP_Params *********************************************************** + def __init__(self, load_defaults=True): + """Class encapsulating VASP job parameters. + + Args: + load_defaults: + """ + #| - __init__ + # self.pymoddir = self.PythonPath() + DFT_Params.__init__(self) + + if load_defaults: + self.params = self.default_params() + else: + self.params = {} + + self.mod_dict = self.create_mod_dict() + + # self.params = self.load_params(self.pymoddir, + # "default_espresso_params.json") + #__| + + def default_params(self): + """User-defined default DFT parameters.""" + #| - default_params + + # Do calculation + my_encut = 500 + my_enaug = 750 + my_kpts = (1, 1, 1) + my_ediff = 0.00001 + my_nsw = 200 # 0 for ASE, > 0 for VASP internal + my_prec = "Normal" # "Normal" or "Accurate" + my_istart = 0 # 0 = new job, 1: + my_npar = 4 + my_ibrion = 1 # RMM-DIIS + my_isif = 2 + my_fmax = -0.001 # ev/ang, tighter converergence + my_ispin = 2 + + params = {} + + params["ivdw"] = 0 + # params["ivdw"] = 12 + + # Dipole Correction + params["ldipol"] = False + # params["idipol"] = 4 + # params[dipol] = [0.5, 0.5, 0,5] # Center of cell + + params["kpts"] = my_kpts + params["encut"] = my_encut + params["enaug"] = my_enaug + + params["ispin"] = my_ispin + params["nsw"] = my_nsw + params["prec"] = my_prec + params["istart"] = my_istart + params["isif"] = my_isif + + # IBRION + params["ibrion"] = my_ibrion + # + + params["ismear"] = 0 + params["sigma"] = 0.05 + + params["icharg"] = 2 + params["lasph"] = True + params["voskown"] = 1 + params["algo"] = "Normal" + params["lreal"] = False + + # convergence Parameters + params["ediff"] = my_ediff + params["ediffg"] = my_fmax + + # Bader Charge Analysis + params["laechg"] = False + + # Output Options + params["nwrite"] = 1 + params["lcharg"] = True + params["lwave"] = False + + # Symmetry + params["isym"] = 0 + + # Functional Type + + # Different VASP versions use 'pbe' vs 'PBE' + if self.compute_env == "aws": + pbe_val = "pbe" + elif self.compute_env == "slac": + pbe_val = "PBE" + else: + pbe_val = "PBE" + # print(pbe_val) # TEMP_PRINT + params["xc"] = pbe_val # TEMP + params["gga"] = " PE" # sets the PBE functional + + # Compuational Parameters + params["npar"] = my_npar + params["nsim"] = 1 + params["nelmin"] = 4 + params["nelm"] = 100 + params["lplane"] = True + + # Dielectric Matrix density functional perturbation theory + params["lepsilon"] = False + + return(params) + #__| + + def create_mod_dict(self): + """ + Create modification book-keepig dictionary. + + Dictionary which keeps track of whether parameter has been updated + externally in script or if it kept at its default value. + This is useful to know for the dependent-parameters. + """ + #| - create_mod_dict + param_keys = list(self.params.keys()) + mod_dict = dict((key, False) for key in param_keys) + + return(mod_dict) + #__| + + + #__| *********************************************************************** + +class Espresso_Params(DFT_Params): + """Useful method to define quantum espresso parameters for DFT job.""" + + #| - Espresso_Params ******************************************************* + def __init__(self, load_defaults=True): + """Class encapsulating quantum espresso job parameters. + + Args: + load_defaults: + """ + #| - __init__ + DFT_Params.__init__(self) + + if load_defaults: + self.params = self.default_params() + else: + self.params = {} + + self.mod_dict = self.create_mod_dict() + #__| + + def default_params(self): # ********************************************** + """User-defined default DFT parameters.""" + #| - default_params + params = {} + + params["pw"] = 500 # plane-wave cutoff + params["dw"] = 5000 # density cutoff + params["dipole"] = {"status": True} # Turn on only for slabs not bulk + params["xc"] = "BEEF-vdW" # exchange-correlation functional + params["kpts"] = (3, 3, 1) # k-points for hexagonal symm in 2-D mater + + # TODO Scale number of bands with system size + params["nbands"] = -50 + + #| - Spin & Magnitism + # Spin-polarized calculation + params["spinpol"] = False + + # Non-collinear magnetism, magnetization in generic direction + params["noncollinear"] = False + #__| + + params["sigma"] = 0.1 # Should be low for spin calculations + + params["beefensemble"] = True + + # Parallelization <---------------------------------------------------- + params["parflags"] = None + + #| - Convergence Parameters + params["convergence"] = { + "energy": 1e-5, # convergence parameters + + # TF (Normal) or local-TF (Better for inhomogeneous systems) + "mixing_mode": "local-TF", + "mixing": 0.2, + "nmix": 20, # num of iter used in mixing scheme (Default 8) + "maxsteps": 500, + "diag": "david", + } + #__| + + #| - File Output <----------------------------------------------------- + params["output"] = { + "avoidio": True, + "removesave": True, + "removewf": True, + "wf_collect": False, + } + + params["outdir"] = "calcdir" + #__| + + return(params) + #__| + + def create_mod_dict(self): + """Create modification book-keepig dictionary. + + Dictionary which keeps track of whether parameter has been updated + externally in script or if it kept at its default value. + This is useful to know for the dependent-parameters. + """ + #| - create_mod_dict + param_keys = list(self.params.keys()) + mod_dict = dict((key, False) for key in param_keys) + + return(mod_dict) + #__| + + def test_check(self): + """Attempts to set params based on other dependent parameters. + + Ex.) If spinpol == True, then sigma should be smaller, 0.01ish + (Charlotte told me) + + Only set this dependent param if the user has not explicitly done so, + is what the condition for setting a parameter automatically is. + """ + #| - test_check + + #| - Setting dw to 10 * pw + if self.mod_dict["dw"] is False: + dw_i = 10. * self.params["pw"] + self.update_params({"dw": dw_i}, user_update=False) + #__| + + #| - Decreasing Sigma for Spin Polarization Calculations + if self.mod_dict["sigma"] is False: + if self.params["spinpol"] is True: + sigma_i = 0.02 + self.update_params({"sigma": sigma_i}, user_update=False) + #__| + + #| - BEEF Ensemble of Energies ========================================= + + #| - Removing Beef-Ensemble if XC-Functional Not BEEF + xc_list = self.params["xc"] + if "beefensemble" in self.params: + if self.params["beefensemble"] is True and "BEEF" not in xc_list: + print("Functional not compatible with BEEF-ensemble method") + self.update_params({"beefensemble": False}, user_update=False) + self.update_params({"printensemble": False}, user_update=False) + else: + pass + #__| + + #| - Turn on printensemble Parameter for BEEF Ensemble of Energies + xc_list = self.params["xc"] + if "beefensemble" in self.params: + if self.params["beefensemble"] is True and "BEEF" in xc_list: + print("Espresso_Params | " + "test_check | Turning on printensemble" + ) + self.update_params({"printensemble": True}, user_update=False) + else: + pass + + #__| + + #| - Turn off BEEF on AWS + # NOTE This is new (180412 - RF), check that it works + CC = ComputerCluster() + if CC.cluster_sys == "aws": + if "beefensemble" in self.params: + if self.params["beefensemble"] is True: + print("Espresso_Params | " + "test_check | Attempting to use BEEF ensemble on AWS, " + "which doesn't support it at this time, " + "BEEF ensemble tags will be turned off" + ) + + self.update_params({ + "beefensemble": False}, + user_update=False, + ) + + self.update_params({ + "printensemble": False}, + user_update=False, + ) + + #__| + + #__| ================================================================== + + #| - Parallelization + if self.mod_dict["parflags"] is False: + if type(self.submission_params) == dict: + if "nodes" in self.submission_params: + num_nodes = self.submission_params["nodes"] + + self.update_params( + {"parflags": "-npool " + str(int(num_nodes))}, + user_update=False, + ) + + # TEMP_PRINT + print("098sddfkfs--s-s-__-_") + print("-npool " + str(int(num_nodes))) + #__| + + #__| + + #__| ********************************************************************** + + + + + +#| - __old__ | default_params with all the commented lines +# params = {} +# +# # params["mode"] = "ase3" +# # params["opt_algorithm"] = "bfgs" +# # params["cell_dynamics"] = "bfgs" +# +# params["pw"] = 500 # plane-wave cutoff +# params["dw"] = 5000 # density cutoff +# params["dipole"] = {"status": True} # Turn on only for slabs not bulk +# params["xc"] = "BEEF-vdW" # exchange-correlation functional +# params["kpts"] = (3, 3, 1) # k-points for hexagonal symm in 2-D mater +# +# # TODO Scale number of bands with system size +# params["nbands"] = -50 +# +# #| - Spin & Magnitism +# # Spin-polarized calculation +# params["spinpol"] = False +# +# # Non-collinear magnetism, magnetization in generic direction +# params["noncollinear"] = False +# #__| +# +# params["sigma"] = 0.1 # Should be low for spin calculations +# +# # pseudopotential path +# # params["psppath"] = "/home/vossj/suncat/psp/gbrv1.5pbe/" +# +# params["beefensemble"] = True +# +# # Parallelization <---------------------------------------------------- +# # params["parflags"] = "-npool " +# params["parflags"] = None +# +# #| - Convergence Parameters +# params["convergence"] = { +# "energy": 1e-5, # convergence parameters +# +# # TF (Normal) or local-TF (Better for inhomogeneous systems) +# "mixing_mode": "local-TF", +# "mixing": 0.2, +# "nmix": 20, # num of iter used in mixing scheme (Default 8) +# "maxsteps": 500, +# "diag": "david", +# } +# #__| +# +# #| - File Output <----------------------------------------------------- +# +# # output = {'disk_io':'default', # how often espresso writes wavefunctions to disk +# # 'avoidio':False, # will overwrite disk_io parameter if True +# # 'removewf':True, +# # 'removesave':False, +# # 'wf_collect':False}, +# +# +# # params["output"] = {"removesave": True} # Aayush, saves ~nothing +# params["output"] = { +# +# # "avoidio": False, +# # "removesave": False, +# # "removewf": False, +# # "wf_collect": False, +# +# "avoidio": True, +# "removesave": True, +# "removewf": True, +# "wf_collect": False, +# } +# +# params["outdir"] = "calcdir" +# return(params) +#__| diff --git a/ase_modules/get_G.py b/ase_modules/get_G.py index 9364c40..cbe903c 100644 --- a/ase_modules/get_G.py +++ b/ase_modules/get_G.py @@ -1,802 +1,802 @@ -#!/usr/bin/env python - -""" -Author(s): Colin Dickens - -TODO - continue to test - add reaction printing to __repr__ - add potential/pressure/temperature dependence to __repr__ - add optional keyword arguments to command line interface for setting potential/pressure/temperature - add Sr, Ru references -""" - -#| - Import Modules -import os - -import glob -import filecmp - -import numpy as np - -from ase.atoms import Atoms -from ase.io import read -#__| - -class Get_G: - """ - Class that automatically calculates standard change in free energy between two states by referencing any atoms - missing between them to a number of gas-phase or aqueous references - """ - - #| - Get_G - def __init__(self, - slab, - ads, - default_vib_bool=True, - get_E=False, - index=-1, - quiet=False, - ): - """ - Get_G(ads,slab) where ads/slab are either paths to traj files or paths to directory containing traj files that have energy and forces. - The directories that contain these traj files must also contain a calculation directory with pw.inp. - """ - #| - __init__ - self.default_vib_bool = default_vib_bool - self.get_E = get_E - self.quiet = quiet - - if type(slab) == str: - self.ads_atoms = self.read_atoms(ads,index=index) - self.slab_atoms = self.read_atoms(slab,index=index) - - elif isinstance(slab, Atoms): - - self.slab_atoms = slab - self.ads_atoms = ads - - - # RF | 181106 - # self.update_params(self.ads_atoms) - # self.update_params(self.slab_atoms) - # - # if self.ads_atoms.PARAMS != self.slab_atoms.PARAMS: - # - # print("%s:"%slab) - # print(self.slab_atoms.PARAMS) - # print("%s:"%ads) - # print(self.ads_atoms.PARAMS) - # - # # print "%s:"%slab - # # print self.slab_atoms.PARAMS - # # print "%s:"%ads - # # print self.ads_atoms.PARAMS - # - # for param in ('dw','pp','pw','xc'): - # if self.ads_atoms.PARAMS[param] != self.slab_atoms.PARAMS[param]: - # raise Exception("Calculations performed with different parameters") - # else: - # print("WARNING, ONE CALCULATION IS SPIN-POLARIZED") - - self.update_delta_atoms() - self.vib_correction() - self.set_refs() - - # RF | 181106 - # if self.slab_atoms.PARAMS['sp']: - # self.compare_magmoms() - - # self.calc_G() - # self.compare_wf() - #__| - - def read_atoms(self,path,**kwargs): - """ - Loads traj file. Path must be direct path to traj files or paths to directory containing them named as either qn.traj or qnXX.traj. - """ - #| - read_atoms - if path.find('traj') != -1: #Checks if directory or filename has been specified - atoms = read(path) - if '/' in path: - atoms.PATH = '/'.join(path.split('/')[:-1]) - else: - atoms.PATH = '.' - else: - files = glob.glob(path + '/qn*.traj') - qn = -1 - for file in files: - file = file.split('/')[-1] - if len(file.split(".")[0]) == 2: #qn.traj - atoms_path = path + '/qn.traj' - elif int(file.split('.')[0][2:]) > qn: #qnXX.traj - qn = int(file.split('.')[0][2:]) - atoms_path = path + '/qn%i.traj'%qn - try: - atoms = read(atoms_path, **kwargs) - atoms.PATH = path - except NameError: - raise IOError("Could not find traj file associate with " + path) - if self.fmax(atoms) > 0.05: - print("WARNING: fmax = %.2f for atoms in %s"%(self.fmax(atoms),atoms.PATH)) - return atoms - #__| - - def update_params(self,atoms): - """ - Takes atoms object containing PATH attribute and adds PARAMS dict as attribute with keys pw, dw, xc, pp. - Assumes PATH contains outdir or calcdir with pw.inp - """ - #| - update_params - if os.path.isdir(atoms.PATH + '/outdir'): - calcdir = atoms.PATH + '/outdir' - elif os.path.isdir(atoms.PATH + '/calcdir'): - calcdir = atoms.PATH + '/calcdir' - else: - raise IOError('Cannot find calculation directory (outdir or calcdir) for ' + atoms.PATH) - - file = open(calcdir + '/pw.inp') - lines = file.readlines() - file.close() - - self.params = {} - self.params['sp'] = False - - for line in lines: - if line[2:9] == 'ecutwfc': - self.params['pw'] = int(float(line.split('=')[-1][:-4])*rydberg) - if line[2:9] == 'ecutrho': - self.params['dw'] = int(float(line.split('=')[-1][:-4])*rydberg) - if line[2:11] == 'input_dft': - self.params['xc'] = line.split('=')[-1][1:-3] - if line[2:12] == 'pseudo_dir': - self.params['pp'] = line.split('=')[-1][1:-3] - if line[2:8] == 'nspin=': - self.params['sp'] = True - - - for key in synonyms: - if self.params[key] in synonyms[key]: - self.params[key] = synonyms[key][self.params[key]] - - atoms.PARAMS = self.params - #__| - - def update_delta_atoms(self): - """ - Update dictionary self.data_atoms with difference in chemical formulas between ads and slab. - Positive numbers represent species that ads has and slab doesn't. - """ - #| - update_delta_atoms - self.delta_atoms = {} - ads_syms = self.ads_atoms.get_chemical_symbols() - slab_syms = self.slab_atoms.get_chemical_symbols() - ads_dict = {} - slab_dict = {} - - for sym in ads_syms: - if sym in ads_dict: - ads_dict[sym] += 1 - else: - ads_dict[sym] = 1 - - for sym in slab_syms: - if sym in slab_dict: - slab_dict[sym] += 1 - else: - slab_dict[sym] = 1 - - for sym in ads_dict: - try: - self.delta_atoms[sym] = ads_dict[sym] - slab_dict[sym] - except KeyError: #no sym in slab_dict - self.delta_atoms[sym] = ads_dict[sym] - - for sym in slab_dict: - if sym not in self.delta_atoms: - self.delta_atoms[sym] = -slab_dict[sym] - - print(self.delta_atoms) - print("LKSDJFKLDJS_------_-_-__----") - - # for key in self.delta_atoms.keys(): - for key in list(self.delta_atoms): - if self.delta_atoms[key] == 0: - del self.delta_atoms[key] - #__| - - def vib_correction(self): - """ - Attempt to add explicitly calculated vibrational correction from vib directory within PATH of ads_atoms and slab_atoms. - Otherwise, default vibrational corrections are used by calling default_vib() - """ - #| - vib_correction - - def vib_indices(atoms): - """ - Return a dict with symbol/count key/value pairs given an atoms object with PATH attribute - """ - #| - vib_indices - dict = {} - - vib_pkls = glob.glob(atoms.PATH + '/vib/vib.*.pckl') - indices = [] - for vib_pkl in vib_pkls: - if vib_pkl != atoms.PATH + '/vib/vib.eq.pckl': - i = vib_pkl.split('/')[-1].split('.')[1][:-2] - if int(i) not in indices: - indices.append(int(i)) - - for index in indices: - sym = atoms[index].symbol - if sym in dict: - dict[sym] +=1 - else: - dict[sym] = 1 - - return dict - #__| - - def parse_corr(path): - """ - Return vibrational correction from myjob.out in path. Return -1 if myjob.out cannot be read (imag freqs?) - """ - #| - parse_corr - file = open(path) - lines = file.readlines() - file.close() - for line in lines: - if len(line.split()) > 1: - if line.split()[0] == 'G' or line.split()[0] == 'F': - corr = float(line.split()[1]) - return corr - return -1 - - """ - try: - try: - corr = float([item for item in [line for line in lines if 'G' in line][0].split(' ') if item.strip()][1]) - return corr - except: - corr = float([item for item in [line for line in lines if 'F' in line][0].split(' ') if item.strip()][1]) - return corr - except: - return -1 - """ - #__| - - if self.get_E: - self.ads_corr = 0 - self.slab_corr = 0 - return - - if self.default_vib_bool: - self.default_vib() - return - - ads_dict = vib_indices(self.ads_atoms) - slab_dict = vib_indices(self.slab_atoms) - - self.delta_vib = {} - - for sym in ads_dict: - try: - self.delta_vib[sym] = ads_dict[sym] - slab_dict[sym] - except KeyError: #no sym in slab_dict - self.delta_vib[sym] = ads_dict[sym] - - for sym in slab_dict: - if sym not in self.delta_vib: - self.delta_vib[sym] = -slab_dict[sym] - - for sym in self.delta_vib.keys(): - if self.delta_vib[sym] == 0: - del self.delta_vib[sym] - - - if self.delta_vib == self.delta_atoms: #explicit vibrational corrections appear valid - if ads_dict != {}: - self.ads_corr = parse_corr(self.ads_atoms.PATH + '/vib/myjob.out') - if self.ads_corr == -1: - print("Correct number of vibrational modes, but cannot read myjob.out (imag freqs?)") - self.default_vib() - return - else: - self.ads_corr = 0 - - if slab_dict != {}: - self.slab_corr = parse_corr(self.slab_atoms.PATH + '/vib/myjob.out') - if self.slab_corr == -1: - print("Correct number of vibrational modes, but cannot read myjob.out (imag freqs?)") - self.default_vib() - return - else: - self.slab_corr = 0 - else: - self.default_vib() - return - #__| - - def default_vib(self): - """ - Calculate vibrational corrections using estimates based on atom identity. - """ - #| - default_vib - self.default_vib_bool = True - self.ads_corr = 0 - self.slab_corr = 0 - for sym in self.delta_atoms: - if self.delta_atoms[sym] > 0: - self.ads_corr += default_vib_dict[sym]*self.delta_atoms[sym] - else: - self.slab_corr -= default_vib_dict[sym]*self.delta_atoms[sym] - #__| - - def set_refs(self): - """ - Formulate references for atoms in self.delta_atoms. Currently chooses reference indicated as default. - """ - #| - set_refs - self.references = {} - for sym in self.delta_atoms: - for atom in references: - if atom == sym: - for ref in references[atom]: - if len(references[atom][ref]) == 3: #use default reference - self.references[sym] = references[atom][ref][:2] - #__| - - def calc_G(self): - """ - Perform free energy calculation at standard conditions and record thermodynamic dependencies on pressure, tempreature, potential, etc. - """ - #| - calc_G - self.G_std = self.ads_atoms.get_potential_energy() - self.slab_atoms.get_potential_energy() - self.G_std += self.ads_corr - self.slab_corr - self.G_thermo = {} - for sym in self.delta_atoms: - for DFT_ref in self.references[sym][0]: - n = DFT_ref[1] - DFT_G = self.get_DFT_ref(DFT_ref[0]) - self.G_std -= self.delta_atoms[sym]*DFT_G*n - for thermo,n in self.references[sym][1]: - if thermo in self.G_thermo: - self.G_thermo[thermo] -= n*self.delta_atoms[sym] - else: - self.G_thermo[thermo] = -n*self.delta_atoms[sym] - #__| - - def get_DFT_ref(self,ref): - """ - Pull appropriate DFT reference energy from database according to computational parameters - """ - #| - get_DFT_ref - xc = self.params['xc'] - pwdw =(self.params['pw'],self.params['dw']) - pp = self.params['pp'] - - if self.get_E: - DFT_references = DFT_E_references - else: - DFT_references = DFT_G_references - - if xc in DFT_references[ref]: - if pwdw in DFT_references[ref][xc]: - if pp in DFT_references[ref][xc][pwdw]: - return DFT_references[ref][xc][pwdw][pp] - else: - for pp_ref in DFT_references[ref][xc][pwdw]: - if self.compare_pp(pp,pp_ref,DFT_references[ref]['syms']): - return DFT_references[ref][xc][pwdw][pp_ref] - - raise Exception("No reference found for %s with %s @ %s with %s"%(ref,xc,pwdw,pp)) - #__| - - def compare_pp(self,pp1,pp2,syms): - """ - """ - #| - compare_pp - for sym in syms: - if not filecmp.cmp("%s/%s.UPF"%(pp1,sym),"%s/%s.UPF"%(pp2,sym)): - return False - return True - #__| - - def fmax(self,atoms): - """ - """ - #| - fmax - forces = atoms.get_forces() - max = 0 - for force in forces: - tot = (force[0]**2 + force[1]**2 + force[2]**2)**0.5 - if tot > max: - max = tot - return max - #__| - - def compare_magmoms(self): - """ - """ - #| - compare_magmoms - def nearest_atom(atoms,position): - "Returns atom nearest to position" - position = np.array(position) - dist_list = [] - for atom in atoms: - dist = np.linalg.norm(position - atom.position) - dist_list.append(dist) - - return atoms[np.argmin(dist_list)] - - if len(self.ads_atoms) >= len(self.slab_atoms): - ads = self.ads_atoms - slab = self.slab_atoms - indexed_by = "slab" - not_indexed_by = "ads" - else: - slab = self.ads_atoms - ads = self.slab_atoms - indexed_by = "ads" - not_indexed_by = "slab" - - delta_magmoms = [] - ads_indices_used = [] - for atom in slab: - ads_atom = nearest_atom(ads,atom.position) - if not self.quiet: - if ads_atom.symbol != atom.symbol: print("WARNING! MAGMOM COMPARISON FAILURE") - ads_indices_used.append(ads_atom.index) - delta_magmoms.append(atom.magmom - ads_atom.magmom) - - ads_indices_not_used = [] - for i in range(len(ads)): - if i not in ads_indices_used: - ads_indices_not_used.append(i) - - # RF | 181106 - # self.delta_magmoms = zip(range(len(slab)), delta_magmoms) - self.delta_magmoms = list(zip(range(len(slab)), delta_magmoms)) - self.delta_magmoms.sort(key=lambda x: abs(x[1]),reverse=True) - - common = "" - uncommon = "" - for i in range(8): - atom = slab[self.delta_magmoms[i][0]] - common += "%s%d: %.2f\t"%(atom.symbol,atom.index,self.delta_magmoms[i][1]) - for i in ads_indices_not_used: - uncommon += "%s%d: %.2f\t"%(ads[i].symbol,ads[i].index,ads[i].magmom) - - if self.quiet: - return - else: - - print("~"*6 + "MAGNETIC MOMENT COMPARISON" + "~"*6) - print("Largest magnetic moment discrepancies (indexed by %s)"%indexed_by) - print(common) - print("Magnetic moments only present in %s"%not_indexed_by) - print(uncommon + "\n") - - # print("~"*6 + "MAGNETIC MOMENT COMPARISON" + "~"*6) - # print("Largest magnetic moment discrepancies (indexed by %s)"%indexed_by) - # print(common) - # print("Magnetic moments only present in %s"%not_indexed_by) - # print(uncommon + "\n") - #__| - - def rms_displacement(self): - """ - """ - #| - rms_displacement - displacements = np.zeros(np.min((len(self.slab_atoms),len(self.ads_atoms)))) - for i in range(len(displacements)): - displacements[i] = np.linalg.norm(self.slab_atoms[i].position-self.ads_atoms[i].position)**2 - return np.sqrt(displacements.mean()) - #__| - - def compare_wf(self): - """ - """ - #| - compare_wf - self.wf_slab = self.read_wf(self.slab_atoms.PATH) - self.wf_ads = self.read_wf(self.ads_atoms.PATH) - - if 'N/A' in [self.wf_slab,self.wf_ads]: - self.d_wf = 'N/A' - else: - self.d_wf = self.wf_ads - self.wf_slab - self.avg_wf = (self.wf_ads + self.wf_slab)/2 - self.d_mu = 0.0055 * self.d_wf * np.linalg.norm(np.cross(self.ads_atoms.cell[0],self.ads_atoms.cell[1])) - #__| - - def read_wf(self,path): - """ - """ - #| - read_wf - try: - f = open(path + '/out.WF') - except: - return 'N/A' - - line = f.readlines()[0] - return float(line.split(',')[0][1:]) - #__| - - - #| - __old__ | old __repr__ - # def __repr__(self): - # """ - # String representation of free energy calculation. Example output: - # - # Ir48O100 + H+/e- --> HIr48O100 dG = (-0.5 + eU_RHE) - # pw/dw = 600/6000 xc = RPBE pp = /home/vossj/suncat/esdld/psp - # Default vibrational corrections applied to adsorbates - # Other possible references include H2... - # """ - # #| - __repr__ - # string = "" - # if self.get_E: - # string += "dE = %.3f eV"%self.G_std - # else: - # string += "dG = %.3f eV"%self.G_std - # - # for thermo in self.G_thermo: - # if self.G_thermo[thermo] > 0: - # string += " + %d%s"%(self.G_thermo[thermo],thermo) - # elif self.G_thermo[thermo] < 0: - # string += " - %d%s"%(-self.G_thermo[thermo],thermo) - # - # string += '\n' - # string += "xc = %s\tpw/dw = %d/%d\tpp = %s"%(self.params['xc'],self.params['pw'],self.params['dw'],self.params['pp']) - # - # if not self.get_E: - # if self.default_vib_bool: - # string += "\nUsing default vibrational corrections for adsorbates" - # else: - # string += "\nUsing vibrational corrections for adsorbates found in directory" - # - # string += "\nRMS Displacement = %.3f Angstroms"%self.rms_displacement() - # if type(self.d_wf) == float: - # string += "\nIS WF = %.2f eV, FS WF = %.2f eV, Change in WF = %.2f eV, Change in Dipole = %.2f eA, Average WF = %.2f eV"\ - # %(self.wf_slab,self.wf_ads,self.d_wf,self.d_mu,self.avg_wf) - # return string - # #__| - #__| - - #__| - - - - - - - -#| - out_of_sight - -rydberg = 13.6057 #rydberg to eV conversion - -default_vib_dict = {'H':0.3, 'O':0.05, 'N': 0.05, 'Ru':0.} - -references = { - 'H':{ - 'H2':([('H2',0.5)],[('kB*T*ln(P_H2)',0.5)]), - 'H+/e-':([('H2',0.5)],[('e*U_RHE',-1)],'DEF') - }, - 'O':{ - 'O2':([('H2O(l)',1),('H2',-1),(2.46)],[('kB*(300 K)*ln(P_O2)',0.5)]), - 'H2O(l)':([('H2O(l)',1),('H2',-1)],[('e*U_RHE',2)],'DEF') - }, - 'N':{ - 'N2':([('N2',0.5)],[('kB*T*ln*(P_N2)',0.5)],'DEF') - }, - 'Ru':{ - 'RuO4':([('RuO4(l)',1),('H2O(l)',-4),('H2',4)],[('e*U_RHE',-8)],'DEF') - }, - 'Li':{ - 'Li':([('Li',1)],[('N/A',0)],'DEF') - }, - } - - -#Preliminary dictionary of DFT reference chemical potentials (assuming ideal gas or electronic energy for solids) -DFT_G_references = { - 'H2':{ - 'RPBE':{ - (600,6000):{ - '/home/vossj/suncat/esdld/psp':-32.1129703764, - '/scratch/users/colinfd/psp/gbrv':-32.0745195582 - }, - (500,5000):{ - '/home/vossj/suncat/esdld/psp':-32.097274273 - } - }, - 'PBE':{ - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-31.7495756638, - '/home/vossj/suncat/esdld/psp':-31.7878744197 - } - }, - 'BEEF':{ - (600,6000):{ - '/home/vossj/suncat/esdld/psp':-33.0011548009, - '/scratch/users/colinfd/psp/gbrv':-32.9557311734, - }, - (500,5000):{ - '/home/vossj/suncat/esdld/psp':-32.9825919425, - '/scratch/users/colinfd/psp/gbrv':-32.955410852 - }, - (550,5500):{ - '/home/vossj/suncat/esdld/psp':-32.9946770046, - } - }, - 'syms':['H'] #used for comparing pseudopotentials - }, - 'H2O(l)':{ - 'RPBE':{ - (600,6000):{ - '/home/vossj/suncat/esdld/psp':-491.396166885, - '/scratch/users/colinfd/psp/gbrv':-472.461551626 - }, - (500,5000):{ - '/home/vossj/suncat/esdld/psp':-491.260712609 - } - }, - 'PBE':{ - (600,6000):{ - '/home/vossj/suncat/esdld/psp':-490.525317314, - '/scratch/users/colinfd/psp/gbrv':-471.663372251 - } - }, - 'BEEF':{ - (600,6000):{ - '/home/vossj/suncat/esdld/psp':-496.410477954, - '/scratch/users/colinfd/psp/gbrv':-476.619940391, - }, - (500,5000):{ - '/home/vossj/suncat/esdld/psp':-496.404846831 - } - }, - 'syms':['H','O'] #used for comparing pseudopoentials - }, - 'N2':{ - 'BEEF':{ - (500,5000):{ - '/scratch/users/colinfd/psp/gbrv':-553.966954842, - '/home/vossj/suncat/esdld/psp':-555.426924645 - } - }, - 'syms':['N'] #used for comparing pseudopoentials - }, - 'RuO4(l)':{ - 'RPBE':{ - (600,6000):{ - '/home/vossj/suncat/esdld/psp':-2512.43779553, - '/scratch/users/colinfd/psp/esp_psp_w_gbrvRu':-4475.37701007 - } - }, - 'BEEF':{ - (600,6000):{ - '/scratch/users/colinfd/psp/esp_psp_w_gbrvRu':-4503.54664532 - } - }, - 'syms':['Ru','O'] - } - } - - -DFT_E_references = { - 'H2':{ - 'BEEF':{ - (500,5000):{ - '/scratch/users/colinfd/psp/gbrv':-32.9198000182, - '/home/vossj/suncat/esdld/psp':-32.9423056024, - }, - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-32.9199219252, - '/home/vossj/suncat/esdld/psp':-32.9629591797, - } - }, - 'RPBE':{ - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-32.0316308866, - '/home/vossj/suncat/esdld/psp':-32.0667357502 - }, - }, - 'PBE':{ - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-31.7044722137, - '/home/vossj/suncat/esdld/psp':-31.7393674136 - } - }, - 'syms':['H'] #used for comparing pseudopoentials - }, - 'N2':{ - 'BEEF':{ - (500,5000):{ - '/scratch/users/colinfd/psp/gbrv':-553.610425617, - '/home/vossj/suncat/esdld/psp':-555.069481444 - } - }, - 'syms':['N'] #used for comparing pseudopoentials - }, - - 'H2O(l)':{ - 'RPBE':{ - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-472.468333263, - '/home/vossj/suncat/esdld/psp':-491.389771898 - } - }, - 'PBE':{ - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-471.668649297, - '/home/vossj/suncat/esdld/psp':-490.517735036 - } - }, - 'BEEF':{ - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-476.630765091, - '/home/vossj/suncat/esdld/psp':-496.411376542 - } - }, - - 'syms':['O','H'] #used for comparing pseudopotentials - }, - - 'Li':{ - 'BEEF':{ - (500,5000):{ - '/home/vossj/suncat/esdld/psp':-204.787513924 - }, - }, - } - } - -##synonyms -synonyms = { - 'pp':{ - #2014 gbrv - '/nfs/slac/g/suncatfs/colinfd/psp/esp_psp_w_gbrvRu': - '/scratch/users/colinfd/psp/esp_psp_w_gbrvRu', - - '/nfs/slac/g/suncatfs/colinfd/psp/gbrv': - '/scratch/users/colinfd/psp/gbrv', - - '/home/vossj/suncat/psp/gbrv1.5pbe': - '/scratch/users/colinfd/psp/gbrv', - - '/global/project/projectdirs/m2997/colinfd/psp/gbrv': - '/scratch/users/colinfd/psp/gbrv', - - #v2 (default QE) - '/nfs/slac/g/suncatfs/sw/external/esp-psp/v2': - '/home/vossj/suncat/esdld/psp', - - '/nfs/slac/g/suncatfs/sw/rh6/external/../../external/esp-psp/v2': - '/home/vossj/suncat/esdld/psp', - - '/global/project/projectdirs/m2997/colinfd/psp/esp_psp/': - '/home/vossj/suncat/esdld/psp', - - '/scratch/users/colinfd/psp/esp_psp': - '/home/vossj/suncat/esdld/psp', - }, - 'xc':{ - 'BEEF-vdW':'BEEF' - } -} - -#__| - -# if __name__ == "__main__": -# import argparse -# parser = argparse.ArgumentParser() -# parser.add_argument('slab', type=str) -# parser.add_argument('ads', type=str) -# parser.add_argument('-vib', '--vibrations', action = 'store_false', help='Look for vibrational calculations in vib/') -# parser.add_argument('-E', '--elec_only', action = 'store_true', help='Calculate change in electronic energy (no TS, ZPE, etc)') -# parser.add_argument('-i', '--index', type=int, help = 'Index to use for both traj files', default = -1) -# -# args = parser.parse_args() -# G = Get_G(args.slab,args.ads,default_vib_bool = args.vibrations, get_E = args.elec_only, index=args.index) -# print G +#!/usr/bin/env python + +""" +Author(s): Colin Dickens + +TODO + continue to test + add reaction printing to __repr__ + add potential/pressure/temperature dependence to __repr__ + add optional keyword arguments to command line interface for setting potential/pressure/temperature + add Sr, Ru references +""" + +#| - Import Modules +import os + +import glob +import filecmp + +import numpy as np + +from ase.atoms import Atoms +from ase.io import read +#__| + +class Get_G: + """ + Class that automatically calculates standard change in free energy between two states by referencing any atoms + missing between them to a number of gas-phase or aqueous references + """ + + #| - Get_G + def __init__(self, + slab, + ads, + default_vib_bool=True, + get_E=False, + index=-1, + quiet=False, + ): + """ + Get_G(ads,slab) where ads/slab are either paths to traj files or paths to directory containing traj files that have energy and forces. + The directories that contain these traj files must also contain a calculation directory with pw.inp. + """ + #| - __init__ + self.default_vib_bool = default_vib_bool + self.get_E = get_E + self.quiet = quiet + + if type(slab) == str: + self.ads_atoms = self.read_atoms(ads,index=index) + self.slab_atoms = self.read_atoms(slab,index=index) + + elif isinstance(slab, Atoms): + + self.slab_atoms = slab + self.ads_atoms = ads + + + # RF | 181106 + # self.update_params(self.ads_atoms) + # self.update_params(self.slab_atoms) + # + # if self.ads_atoms.PARAMS != self.slab_atoms.PARAMS: + # + # print("%s:"%slab) + # print(self.slab_atoms.PARAMS) + # print("%s:"%ads) + # print(self.ads_atoms.PARAMS) + # + # # print "%s:"%slab + # # print self.slab_atoms.PARAMS + # # print "%s:"%ads + # # print self.ads_atoms.PARAMS + # + # for param in ('dw','pp','pw','xc'): + # if self.ads_atoms.PARAMS[param] != self.slab_atoms.PARAMS[param]: + # raise Exception("Calculations performed with different parameters") + # else: + # print("WARNING, ONE CALCULATION IS SPIN-POLARIZED") + + self.update_delta_atoms() + self.vib_correction() + self.set_refs() + + # RF | 181106 + # if self.slab_atoms.PARAMS['sp']: + # self.compare_magmoms() + + # self.calc_G() + # self.compare_wf() + #__| + + def read_atoms(self,path,**kwargs): + """ + Loads traj file. Path must be direct path to traj files or paths to directory containing them named as either qn.traj or qnXX.traj. + """ + #| - read_atoms + if path.find('traj') != -1: #Checks if directory or filename has been specified + atoms = read(path) + if '/' in path: + atoms.PATH = '/'.join(path.split('/')[:-1]) + else: + atoms.PATH = '.' + else: + files = glob.glob(path + '/qn*.traj') + qn = -1 + for file in files: + file = file.split('/')[-1] + if len(file.split(".")[0]) == 2: #qn.traj + atoms_path = path + '/qn.traj' + elif int(file.split('.')[0][2:]) > qn: #qnXX.traj + qn = int(file.split('.')[0][2:]) + atoms_path = path + '/qn%i.traj'%qn + try: + atoms = read(atoms_path, **kwargs) + atoms.PATH = path + except NameError: + raise IOError("Could not find traj file associate with " + path) + if self.fmax(atoms) > 0.05: + print("WARNING: fmax = %.2f for atoms in %s"%(self.fmax(atoms),atoms.PATH)) + return atoms + #__| + + def update_params(self,atoms): + """ + Takes atoms object containing PATH attribute and adds PARAMS dict as attribute with keys pw, dw, xc, pp. + Assumes PATH contains outdir or calcdir with pw.inp + """ + #| - update_params + if os.path.isdir(atoms.PATH + '/outdir'): + calcdir = atoms.PATH + '/outdir' + elif os.path.isdir(atoms.PATH + '/calcdir'): + calcdir = atoms.PATH + '/calcdir' + else: + raise IOError('Cannot find calculation directory (outdir or calcdir) for ' + atoms.PATH) + + file = open(calcdir + '/pw.inp') + lines = file.readlines() + file.close() + + self.params = {} + self.params['sp'] = False + + for line in lines: + if line[2:9] == 'ecutwfc': + self.params['pw'] = int(float(line.split('=')[-1][:-4])*rydberg) + if line[2:9] == 'ecutrho': + self.params['dw'] = int(float(line.split('=')[-1][:-4])*rydberg) + if line[2:11] == 'input_dft': + self.params['xc'] = line.split('=')[-1][1:-3] + if line[2:12] == 'pseudo_dir': + self.params['pp'] = line.split('=')[-1][1:-3] + if line[2:8] == 'nspin=': + self.params['sp'] = True + + + for key in synonyms: + if self.params[key] in synonyms[key]: + self.params[key] = synonyms[key][self.params[key]] + + atoms.PARAMS = self.params + #__| + + def update_delta_atoms(self): + """ + Update dictionary self.data_atoms with difference in chemical formulas between ads and slab. + Positive numbers represent species that ads has and slab doesn't. + """ + #| - update_delta_atoms + self.delta_atoms = {} + ads_syms = self.ads_atoms.get_chemical_symbols() + slab_syms = self.slab_atoms.get_chemical_symbols() + ads_dict = {} + slab_dict = {} + + for sym in ads_syms: + if sym in ads_dict: + ads_dict[sym] += 1 + else: + ads_dict[sym] = 1 + + for sym in slab_syms: + if sym in slab_dict: + slab_dict[sym] += 1 + else: + slab_dict[sym] = 1 + + for sym in ads_dict: + try: + self.delta_atoms[sym] = ads_dict[sym] - slab_dict[sym] + except KeyError: #no sym in slab_dict + self.delta_atoms[sym] = ads_dict[sym] + + for sym in slab_dict: + if sym not in self.delta_atoms: + self.delta_atoms[sym] = -slab_dict[sym] + + print(self.delta_atoms) + print("LKSDJFKLDJS_------_-_-__----") + + # for key in self.delta_atoms.keys(): + for key in list(self.delta_atoms): + if self.delta_atoms[key] == 0: + del self.delta_atoms[key] + #__| + + def vib_correction(self): + """ + Attempt to add explicitly calculated vibrational correction from vib directory within PATH of ads_atoms and slab_atoms. + Otherwise, default vibrational corrections are used by calling default_vib() + """ + #| - vib_correction + + def vib_indices(atoms): + """ + Return a dict with symbol/count key/value pairs given an atoms object with PATH attribute + """ + #| - vib_indices + dict = {} + + vib_pkls = glob.glob(atoms.PATH + '/vib/vib.*.pckl') + indices = [] + for vib_pkl in vib_pkls: + if vib_pkl != atoms.PATH + '/vib/vib.eq.pckl': + i = vib_pkl.split('/')[-1].split('.')[1][:-2] + if int(i) not in indices: + indices.append(int(i)) + + for index in indices: + sym = atoms[index].symbol + if sym in dict: + dict[sym] +=1 + else: + dict[sym] = 1 + + return dict + #__| + + def parse_corr(path): + """ + Return vibrational correction from myjob.out in path. Return -1 if myjob.out cannot be read (imag freqs?) + """ + #| - parse_corr + file = open(path) + lines = file.readlines() + file.close() + for line in lines: + if len(line.split()) > 1: + if line.split()[0] == 'G' or line.split()[0] == 'F': + corr = float(line.split()[1]) + return corr + return -1 + + """ + try: + try: + corr = float([item for item in [line for line in lines if 'G' in line][0].split(' ') if item.strip()][1]) + return corr + except: + corr = float([item for item in [line for line in lines if 'F' in line][0].split(' ') if item.strip()][1]) + return corr + except: + return -1 + """ + #__| + + if self.get_E: + self.ads_corr = 0 + self.slab_corr = 0 + return + + if self.default_vib_bool: + self.default_vib() + return + + ads_dict = vib_indices(self.ads_atoms) + slab_dict = vib_indices(self.slab_atoms) + + self.delta_vib = {} + + for sym in ads_dict: + try: + self.delta_vib[sym] = ads_dict[sym] - slab_dict[sym] + except KeyError: #no sym in slab_dict + self.delta_vib[sym] = ads_dict[sym] + + for sym in slab_dict: + if sym not in self.delta_vib: + self.delta_vib[sym] = -slab_dict[sym] + + for sym in self.delta_vib.keys(): + if self.delta_vib[sym] == 0: + del self.delta_vib[sym] + + + if self.delta_vib == self.delta_atoms: #explicit vibrational corrections appear valid + if ads_dict != {}: + self.ads_corr = parse_corr(self.ads_atoms.PATH + '/vib/myjob.out') + if self.ads_corr == -1: + print("Correct number of vibrational modes, but cannot read myjob.out (imag freqs?)") + self.default_vib() + return + else: + self.ads_corr = 0 + + if slab_dict != {}: + self.slab_corr = parse_corr(self.slab_atoms.PATH + '/vib/myjob.out') + if self.slab_corr == -1: + print("Correct number of vibrational modes, but cannot read myjob.out (imag freqs?)") + self.default_vib() + return + else: + self.slab_corr = 0 + else: + self.default_vib() + return + #__| + + def default_vib(self): + """ + Calculate vibrational corrections using estimates based on atom identity. + """ + #| - default_vib + self.default_vib_bool = True + self.ads_corr = 0 + self.slab_corr = 0 + for sym in self.delta_atoms: + if self.delta_atoms[sym] > 0: + self.ads_corr += default_vib_dict[sym]*self.delta_atoms[sym] + else: + self.slab_corr -= default_vib_dict[sym]*self.delta_atoms[sym] + #__| + + def set_refs(self): + """ + Formulate references for atoms in self.delta_atoms. Currently chooses reference indicated as default. + """ + #| - set_refs + self.references = {} + for sym in self.delta_atoms: + for atom in references: + if atom == sym: + for ref in references[atom]: + if len(references[atom][ref]) == 3: #use default reference + self.references[sym] = references[atom][ref][:2] + #__| + + def calc_G(self): + """ + Perform free energy calculation at standard conditions and record thermodynamic dependencies on pressure, tempreature, potential, etc. + """ + #| - calc_G + self.G_std = self.ads_atoms.get_potential_energy() - self.slab_atoms.get_potential_energy() + self.G_std += self.ads_corr - self.slab_corr + self.G_thermo = {} + for sym in self.delta_atoms: + for DFT_ref in self.references[sym][0]: + n = DFT_ref[1] + DFT_G = self.get_DFT_ref(DFT_ref[0]) + self.G_std -= self.delta_atoms[sym]*DFT_G*n + for thermo,n in self.references[sym][1]: + if thermo in self.G_thermo: + self.G_thermo[thermo] -= n*self.delta_atoms[sym] + else: + self.G_thermo[thermo] = -n*self.delta_atoms[sym] + #__| + + def get_DFT_ref(self,ref): + """ + Pull appropriate DFT reference energy from database according to computational parameters + """ + #| - get_DFT_ref + xc = self.params['xc'] + pwdw =(self.params['pw'],self.params['dw']) + pp = self.params['pp'] + + if self.get_E: + DFT_references = DFT_E_references + else: + DFT_references = DFT_G_references + + if xc in DFT_references[ref]: + if pwdw in DFT_references[ref][xc]: + if pp in DFT_references[ref][xc][pwdw]: + return DFT_references[ref][xc][pwdw][pp] + else: + for pp_ref in DFT_references[ref][xc][pwdw]: + if self.compare_pp(pp,pp_ref,DFT_references[ref]['syms']): + return DFT_references[ref][xc][pwdw][pp_ref] + + raise Exception("No reference found for %s with %s @ %s with %s"%(ref,xc,pwdw,pp)) + #__| + + def compare_pp(self,pp1,pp2,syms): + """ + """ + #| - compare_pp + for sym in syms: + if not filecmp.cmp("%s/%s.UPF"%(pp1,sym),"%s/%s.UPF"%(pp2,sym)): + return False + return True + #__| + + def fmax(self,atoms): + """ + """ + #| - fmax + forces = atoms.get_forces() + max = 0 + for force in forces: + tot = (force[0]**2 + force[1]**2 + force[2]**2)**0.5 + if tot > max: + max = tot + return max + #__| + + def compare_magmoms(self): + """ + """ + #| - compare_magmoms + def nearest_atom(atoms,position): + "Returns atom nearest to position" + position = np.array(position) + dist_list = [] + for atom in atoms: + dist = np.linalg.norm(position - atom.position) + dist_list.append(dist) + + return atoms[np.argmin(dist_list)] + + if len(self.ads_atoms) >= len(self.slab_atoms): + ads = self.ads_atoms + slab = self.slab_atoms + indexed_by = "slab" + not_indexed_by = "ads" + else: + slab = self.ads_atoms + ads = self.slab_atoms + indexed_by = "ads" + not_indexed_by = "slab" + + delta_magmoms = [] + ads_indices_used = [] + for atom in slab: + ads_atom = nearest_atom(ads,atom.position) + if not self.quiet: + if ads_atom.symbol != atom.symbol: print("WARNING! MAGMOM COMPARISON FAILURE") + ads_indices_used.append(ads_atom.index) + delta_magmoms.append(atom.magmom - ads_atom.magmom) + + ads_indices_not_used = [] + for i in range(len(ads)): + if i not in ads_indices_used: + ads_indices_not_used.append(i) + + # RF | 181106 + # self.delta_magmoms = zip(range(len(slab)), delta_magmoms) + self.delta_magmoms = list(zip(range(len(slab)), delta_magmoms)) + self.delta_magmoms.sort(key=lambda x: abs(x[1]),reverse=True) + + common = "" + uncommon = "" + for i in range(8): + atom = slab[self.delta_magmoms[i][0]] + common += "%s%d: %.2f\t"%(atom.symbol,atom.index,self.delta_magmoms[i][1]) + for i in ads_indices_not_used: + uncommon += "%s%d: %.2f\t"%(ads[i].symbol,ads[i].index,ads[i].magmom) + + if self.quiet: + return + else: + + print("~"*6 + "MAGNETIC MOMENT COMPARISON" + "~"*6) + print("Largest magnetic moment discrepancies (indexed by %s)"%indexed_by) + print(common) + print("Magnetic moments only present in %s"%not_indexed_by) + print(uncommon + "\n") + + # print("~"*6 + "MAGNETIC MOMENT COMPARISON" + "~"*6) + # print("Largest magnetic moment discrepancies (indexed by %s)"%indexed_by) + # print(common) + # print("Magnetic moments only present in %s"%not_indexed_by) + # print(uncommon + "\n") + #__| + + def rms_displacement(self): + """ + """ + #| - rms_displacement + displacements = np.zeros(np.min((len(self.slab_atoms),len(self.ads_atoms)))) + for i in range(len(displacements)): + displacements[i] = np.linalg.norm(self.slab_atoms[i].position-self.ads_atoms[i].position)**2 + return np.sqrt(displacements.mean()) + #__| + + def compare_wf(self): + """ + """ + #| - compare_wf + self.wf_slab = self.read_wf(self.slab_atoms.PATH) + self.wf_ads = self.read_wf(self.ads_atoms.PATH) + + if 'N/A' in [self.wf_slab,self.wf_ads]: + self.d_wf = 'N/A' + else: + self.d_wf = self.wf_ads - self.wf_slab + self.avg_wf = (self.wf_ads + self.wf_slab)/2 + self.d_mu = 0.0055 * self.d_wf * np.linalg.norm(np.cross(self.ads_atoms.cell[0],self.ads_atoms.cell[1])) + #__| + + def read_wf(self,path): + """ + """ + #| - read_wf + try: + f = open(path + '/out.WF') + except: + return 'N/A' + + line = f.readlines()[0] + return float(line.split(',')[0][1:]) + #__| + + + #| - __old__ | old __repr__ + # def __repr__(self): + # """ + # String representation of free energy calculation. Example output: + # + # Ir48O100 + H+/e- --> HIr48O100 dG = (-0.5 + eU_RHE) + # pw/dw = 600/6000 xc = RPBE pp = /home/vossj/suncat/esdld/psp + # Default vibrational corrections applied to adsorbates + # Other possible references include H2... + # """ + # #| - __repr__ + # string = "" + # if self.get_E: + # string += "dE = %.3f eV"%self.G_std + # else: + # string += "dG = %.3f eV"%self.G_std + # + # for thermo in self.G_thermo: + # if self.G_thermo[thermo] > 0: + # string += " + %d%s"%(self.G_thermo[thermo],thermo) + # elif self.G_thermo[thermo] < 0: + # string += " - %d%s"%(-self.G_thermo[thermo],thermo) + # + # string += '\n' + # string += "xc = %s\tpw/dw = %d/%d\tpp = %s"%(self.params['xc'],self.params['pw'],self.params['dw'],self.params['pp']) + # + # if not self.get_E: + # if self.default_vib_bool: + # string += "\nUsing default vibrational corrections for adsorbates" + # else: + # string += "\nUsing vibrational corrections for adsorbates found in directory" + # + # string += "\nRMS Displacement = %.3f Angstroms"%self.rms_displacement() + # if type(self.d_wf) == float: + # string += "\nIS WF = %.2f eV, FS WF = %.2f eV, Change in WF = %.2f eV, Change in Dipole = %.2f eA, Average WF = %.2f eV"\ + # %(self.wf_slab,self.wf_ads,self.d_wf,self.d_mu,self.avg_wf) + # return string + # #__| + #__| + + #__| + + + + + + + +#| - out_of_sight + +rydberg = 13.6057 #rydberg to eV conversion + +default_vib_dict = {'H':0.3, 'O':0.05, 'N': 0.05, 'Ru':0.} + +references = { + 'H':{ + 'H2':([('H2',0.5)],[('kB*T*ln(P_H2)',0.5)]), + 'H+/e-':([('H2',0.5)],[('e*U_RHE',-1)],'DEF') + }, + 'O':{ + 'O2':([('H2O(l)',1),('H2',-1),(2.46)],[('kB*(300 K)*ln(P_O2)',0.5)]), + 'H2O(l)':([('H2O(l)',1),('H2',-1)],[('e*U_RHE',2)],'DEF') + }, + 'N':{ + 'N2':([('N2',0.5)],[('kB*T*ln*(P_N2)',0.5)],'DEF') + }, + 'Ru':{ + 'RuO4':([('RuO4(l)',1),('H2O(l)',-4),('H2',4)],[('e*U_RHE',-8)],'DEF') + }, + 'Li':{ + 'Li':([('Li',1)],[('N/A',0)],'DEF') + }, + } + + +#Preliminary dictionary of DFT reference chemical potentials (assuming ideal gas or electronic energy for solids) +DFT_G_references = { + 'H2':{ + 'RPBE':{ + (600,6000):{ + '/home/vossj/suncat/esdld/psp':-32.1129703764, + '/scratch/users/colinfd/psp/gbrv':-32.0745195582 + }, + (500,5000):{ + '/home/vossj/suncat/esdld/psp':-32.097274273 + } + }, + 'PBE':{ + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-31.7495756638, + '/home/vossj/suncat/esdld/psp':-31.7878744197 + } + }, + 'BEEF':{ + (600,6000):{ + '/home/vossj/suncat/esdld/psp':-33.0011548009, + '/scratch/users/colinfd/psp/gbrv':-32.9557311734, + }, + (500,5000):{ + '/home/vossj/suncat/esdld/psp':-32.9825919425, + '/scratch/users/colinfd/psp/gbrv':-32.955410852 + }, + (550,5500):{ + '/home/vossj/suncat/esdld/psp':-32.9946770046, + } + }, + 'syms':['H'] #used for comparing pseudopotentials + }, + 'H2O(l)':{ + 'RPBE':{ + (600,6000):{ + '/home/vossj/suncat/esdld/psp':-491.396166885, + '/scratch/users/colinfd/psp/gbrv':-472.461551626 + }, + (500,5000):{ + '/home/vossj/suncat/esdld/psp':-491.260712609 + } + }, + 'PBE':{ + (600,6000):{ + '/home/vossj/suncat/esdld/psp':-490.525317314, + '/scratch/users/colinfd/psp/gbrv':-471.663372251 + } + }, + 'BEEF':{ + (600,6000):{ + '/home/vossj/suncat/esdld/psp':-496.410477954, + '/scratch/users/colinfd/psp/gbrv':-476.619940391, + }, + (500,5000):{ + '/home/vossj/suncat/esdld/psp':-496.404846831 + } + }, + 'syms':['H','O'] #used for comparing pseudopoentials + }, + 'N2':{ + 'BEEF':{ + (500,5000):{ + '/scratch/users/colinfd/psp/gbrv':-553.966954842, + '/home/vossj/suncat/esdld/psp':-555.426924645 + } + }, + 'syms':['N'] #used for comparing pseudopoentials + }, + 'RuO4(l)':{ + 'RPBE':{ + (600,6000):{ + '/home/vossj/suncat/esdld/psp':-2512.43779553, + '/scratch/users/colinfd/psp/esp_psp_w_gbrvRu':-4475.37701007 + } + }, + 'BEEF':{ + (600,6000):{ + '/scratch/users/colinfd/psp/esp_psp_w_gbrvRu':-4503.54664532 + } + }, + 'syms':['Ru','O'] + } + } + + +DFT_E_references = { + 'H2':{ + 'BEEF':{ + (500,5000):{ + '/scratch/users/colinfd/psp/gbrv':-32.9198000182, + '/home/vossj/suncat/esdld/psp':-32.9423056024, + }, + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-32.9199219252, + '/home/vossj/suncat/esdld/psp':-32.9629591797, + } + }, + 'RPBE':{ + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-32.0316308866, + '/home/vossj/suncat/esdld/psp':-32.0667357502 + }, + }, + 'PBE':{ + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-31.7044722137, + '/home/vossj/suncat/esdld/psp':-31.7393674136 + } + }, + 'syms':['H'] #used for comparing pseudopoentials + }, + 'N2':{ + 'BEEF':{ + (500,5000):{ + '/scratch/users/colinfd/psp/gbrv':-553.610425617, + '/home/vossj/suncat/esdld/psp':-555.069481444 + } + }, + 'syms':['N'] #used for comparing pseudopoentials + }, + + 'H2O(l)':{ + 'RPBE':{ + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-472.468333263, + '/home/vossj/suncat/esdld/psp':-491.389771898 + } + }, + 'PBE':{ + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-471.668649297, + '/home/vossj/suncat/esdld/psp':-490.517735036 + } + }, + 'BEEF':{ + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-476.630765091, + '/home/vossj/suncat/esdld/psp':-496.411376542 + } + }, + + 'syms':['O','H'] #used for comparing pseudopotentials + }, + + 'Li':{ + 'BEEF':{ + (500,5000):{ + '/home/vossj/suncat/esdld/psp':-204.787513924 + }, + }, + } + } + +##synonyms +synonyms = { + 'pp':{ + #2014 gbrv + '/nfs/slac/g/suncatfs/colinfd/psp/esp_psp_w_gbrvRu': + '/scratch/users/colinfd/psp/esp_psp_w_gbrvRu', + + '/nfs/slac/g/suncatfs/colinfd/psp/gbrv': + '/scratch/users/colinfd/psp/gbrv', + + '/home/vossj/suncat/psp/gbrv1.5pbe': + '/scratch/users/colinfd/psp/gbrv', + + '/global/project/projectdirs/m2997/colinfd/psp/gbrv': + '/scratch/users/colinfd/psp/gbrv', + + #v2 (default QE) + '/nfs/slac/g/suncatfs/sw/external/esp-psp/v2': + '/home/vossj/suncat/esdld/psp', + + '/nfs/slac/g/suncatfs/sw/rh6/external/../../external/esp-psp/v2': + '/home/vossj/suncat/esdld/psp', + + '/global/project/projectdirs/m2997/colinfd/psp/esp_psp/': + '/home/vossj/suncat/esdld/psp', + + '/scratch/users/colinfd/psp/esp_psp': + '/home/vossj/suncat/esdld/psp', + }, + 'xc':{ + 'BEEF-vdW':'BEEF' + } +} + +#__| + +# if __name__ == "__main__": +# import argparse +# parser = argparse.ArgumentParser() +# parser.add_argument('slab', type=str) +# parser.add_argument('ads', type=str) +# parser.add_argument('-vib', '--vibrations', action = 'store_false', help='Look for vibrational calculations in vib/') +# parser.add_argument('-E', '--elec_only', action = 'store_true', help='Calculate change in electronic energy (no TS, ZPE, etc)') +# parser.add_argument('-i', '--index', type=int, help = 'Index to use for both traj files', default = -1) +# +# args = parser.parse_args() +# G = Get_G(args.slab,args.ads,default_vib_bool = args.vibrations, get_E = args.elec_only, index=args.index) +# print G diff --git a/atoms_objects/slab_generation.py b/atoms_objects/slab_generation.py index 2a365a7..37c9538 100644 --- a/atoms_objects/slab_generation.py +++ b/atoms_objects/slab_generation.py @@ -1,131 +1,131 @@ -#!/usr/bin/env python - -"""Cut slabs from bulk structures. - -Author: Raul A. Flores -""" - -#| - Import Modules -from ase.build import surface -# from ase import io - -from catkit.gen.surface import SlabGenerator as SlabGenerator_catkit -# from ase.visualize import view - -from pymatgen.io.ase import AseAtomsAdaptor -from pymatgen.core.surface import SlabGenerator as SlabGenerator_pymatgen -#__| - -def cut_slab_ase( - bulk, - facet, - layers=6, - vacuum=8, - ): - """Cut slab from bulk using ASE. - - Args: - bulk: - facet: - """ - #| - cut_slab_ase - # facet = [1, 1, 0] - # layers = 6 - # vacuum = 8 - - out_file = "out_slab_ase.traj" - - # facet = [int(i) for i in facet] - - # atoms = io.read("qn.traj") # Bulk traj file (no vacuum) - # atoms = io.read("init.cif") # Bulk traj file (no vacuum) - - slab = surface(bulk, facet, layers, vacuum) - slab.set_pbc(True) - # slab.write(out_file) - - return(slab) - #__| - -def cut_slab_pymatgen( - bulk, - facet, - min_slab_size=18., - min_vacuum_size=10., - ): - """Cut slab from bulk using pymatgen. - - Args: - bulk: - facet: - """ - #| - cut_slab_pymatgen - # atoms = io.read("init.traj") - # atoms = io.read("init.cif") - - structure = AseAtomsAdaptor.get_structure(bulk) - - # ZnO=Structure.from_file("ZnO.cif",primitive=False) - - slab_pymatgen = SlabGenerator_pymatgen( - structure, - # [1, 1, 0], - facet, - min_slab_size, - min_vacuum_size, - lll_reduce=True, - center_slab=True, - max_normal_search=2, - ).get_slab() - - # initial_structure, miller_index, min_slab_size, - # min_vacuum_size, lll_reduce=False, center_slab=False, - # in_unit_planes=False, primitive=True, max_normal_search=None, - # reorient_lattice=True - - slab = AseAtomsAdaptor.get_atoms(slab_pymatgen) - - slab.center() - - # slab.write("out_slab_pymatgen.traj") - - # IStructure.to(Al55, "poscar", filename="POSCAR") - - return(slab) - #__| - -def cut_slab_catkit( - bulk, - facet, - slab_thickness=6, - vacuum=8., - ): - """Cut slab from bulk using CatKit. - - Args: - bulk: - facet: - """ - #| - cut_slab_catkit - gen = SlabGenerator_catkit( - bulk, - miller_index=facet, - layers=slab_thickness, - vacuum=vacuum, - fixed=2, - layer_type='ang', - # attach_graph=True, - standardize_bulk=False, - tol=1e-8 - ) - - terminations = gen.get_unique_terminations() - - images = [] - for i, t in enumerate(terminations): - images += [gen.get_slab(iterm=i, size=1)] - - # view(images) - - return(images) - #__| +#!/usr/bin/env python + +"""Cut slabs from bulk structures. + +Author: Raul A. Flores +""" + +#| - Import Modules +from ase.build import surface +# from ase import io + +from catkit.gen.surface import SlabGenerator as SlabGenerator_catkit +# from ase.visualize import view + +from pymatgen.io.ase import AseAtomsAdaptor +from pymatgen.core.surface import SlabGenerator as SlabGenerator_pymatgen +#__| + +def cut_slab_ase( + bulk, + facet, + layers=6, + vacuum=8, + ): + """Cut slab from bulk using ASE. + + Args: + bulk: + facet: + """ + #| - cut_slab_ase + # facet = [1, 1, 0] + # layers = 6 + # vacuum = 8 + + out_file = "out_slab_ase.traj" + + # facet = [int(i) for i in facet] + + # atoms = io.read("qn.traj") # Bulk traj file (no vacuum) + # atoms = io.read("init.cif") # Bulk traj file (no vacuum) + + slab = surface(bulk, facet, layers, vacuum) + slab.set_pbc(True) + # slab.write(out_file) + + return(slab) + #__| + +def cut_slab_pymatgen( + bulk, + facet, + min_slab_size=18., + min_vacuum_size=10., + ): + """Cut slab from bulk using pymatgen. + + Args: + bulk: + facet: + """ + #| - cut_slab_pymatgen + # atoms = io.read("init.traj") + # atoms = io.read("init.cif") + + structure = AseAtomsAdaptor.get_structure(bulk) + + # ZnO=Structure.from_file("ZnO.cif",primitive=False) + + slab_pymatgen = SlabGenerator_pymatgen( + structure, + # [1, 1, 0], + facet, + min_slab_size, + min_vacuum_size, + lll_reduce=True, + center_slab=True, + max_normal_search=2, + ).get_slab() + + # initial_structure, miller_index, min_slab_size, + # min_vacuum_size, lll_reduce=False, center_slab=False, + # in_unit_planes=False, primitive=True, max_normal_search=None, + # reorient_lattice=True + + slab = AseAtomsAdaptor.get_atoms(slab_pymatgen) + + slab.center() + + # slab.write("out_slab_pymatgen.traj") + + # IStructure.to(Al55, "poscar", filename="POSCAR") + + return(slab) + #__| + +def cut_slab_catkit( + bulk, + facet, + slab_thickness=6, + vacuum=8., + ): + """Cut slab from bulk using CatKit. + + Args: + bulk: + facet: + """ + #| - cut_slab_catkit + gen = SlabGenerator_catkit( + bulk, + miller_index=facet, + layers=slab_thickness, + vacuum=vacuum, + fixed=2, + layer_type='ang', + # attach_graph=True, + standardize_bulk=False, + tol=1e-8 + ) + + terminations = gen.get_unique_terminations() + + images = [] + for i, t in enumerate(terminations): + images += [gen.get_slab(iterm=i, size=1)] + + # view(images) + + return(images) + #__| diff --git a/bader_charge/bader.py b/bader_charge/bader.py index 8c532ed..676a22b 100644 --- a/bader_charge/bader.py +++ b/bader_charge/bader.py @@ -1,269 +1,347 @@ -#!/usr/bin/env python - -"""Bader charge analysis methods. - -Author(s): Colin Dickins wrote most of this; Raul A. Flores -""" - -#| - IMPORT MODULES -import sys -import os - -import pickle as pickle -import copy - -import numpy as np -# from ase.io import write -from ase import io -#__| - - -def bader(atoms, spinpol=False, outdir=None, run_exec=True): - """Perform bader charge analysis on atoms. - - Calculate charge density using atoms.calc, calculate bader charges on each - atom in atoms, and assign to atom.data["bader_charge"]. - - If spinpol: also assign atom.data["bader_magmom"]. - - Args: - atoms: ASE atoms object - spinpol: Spin polarized calculation - outdir: Output directory location - run_exec: Whether to run bader executable or just create preliminary - file (some clusters don't/can't have the bader fortran code) - """ - #| - bader - mess = "Executing Bader Analysis " - mess += "*****************************************************" - print(mess); sys.stdout.flush() - - #| - Don't Run Bader Executable on AWS - if "COMPENV" not in os.environ: - print("COMPENV env. var. doesn't exits, probably in AWS?") - print("Bader executable turned off") - - run_exec = False - else: - pass - #__| - - if not os.path.exists("dir_bader"): - os.makedirs("dir_bader") - - calc = atoms.calc - - #| - Using Spin Polarization - if spinpol: - - #| - Spin up - cd2cube(atoms, spin="up") - if run_exec: - bader_exec(atoms, spin="up") - #__| - - #| - Spin down - cd2cube(atoms, spin="down") - if run_exec: - bader_exec(atoms, spin="down") - #__| - - print("BADER MAGMOMS: " + str(atoms.get_initial_magnetic_moments())) - - #__| - - #| - Not Spin Polarized - else: - cd2cube(atoms) - - if run_exec: - bader_exec(atoms) - #__| - - print("BADER CHARGES: " + str(atoms.get_initial_charges())) - - # if run_exec: - # io.write("dir_bader/bader.traj", atoms) - - if outdir: - os.system("rm %s/charge.log" % outdir) - - #| - Writing 2 Atoms Objects with mogmoms and charges written - - if run_exec: - # Charges written to init_charges - atoms_cpy1 = copy.deepcopy(atoms) - bader_charges = atoms_cpy1.info["bader_charges"] - atoms_cpy1.set_initial_charges(bader_charges) - atoms_cpy1.write("dir_bader/bader_charges.traj") - - if spinpol: - atoms_cpy2 = copy.deepcopy(atoms) - bader_magmoms = atoms_cpy2.info["bader_magmoms"] - atoms_cpy2.set_initial_charges(bader_magmoms) - atoms_cpy2.write("dir_bader/bader_magmoms.traj") - - # atoms.set_calculator(calc=calc) - atoms.write("dir_bader/out.traj") - #__| - - #__| - - -def cd2cube(atoms, spin=""): - """Convert ASE charge density file to cube format. - - Takes charge density pickle file from ase-qe and writes a cube file ready - for bader analysis to the current directory - - Args: - atoms: - spin: - """ - #| - cd2cube - # cd2cube(atoms.calc.extract_charge_density(spin="up")[2], atoms) - - if spin == "": - cd = atoms.calc.extract_charge_density()[2] - else: - cd = atoms.calc.extract_charge_density(spin=spin)[2] - - file_name = "density" + spin + ".cube" - - nx, ny, nz = np.shape(cd) - #cut away periodic image planes to correct QE output - u = nx - 1 - v = ny - 1 - w = nz - 1 - cd2 = np.empty((u, v, w), np.float) - for i in range(u): - for j in range(v): - cd2[i][j][:] = cd[i][j][:w] - - io.write(file_name, atoms, data=cd2) - - # edit density.cube grid size if odd number of grid points to - # correct for old versions of ASE - bohr = 0.52917721092 - cell = atoms.get_cell() - da = cell[0] / (u * bohr) - db = cell[1] / (v * bohr) - dc = cell[2] / (w * bohr) - - f = open(file_name, "r") - lines = f.readlines() - f.close() - - line3 = "%5.0f %.6f %.6f %.6f\n" % (u, da[0], da[1], da[2]) - line4 = "%5.0f %.6f %.6f %.6f\n" % (v, db[0], db[1], db[2]) - line5 = "%5.0f %.6f %.6f %.6f\n" % (w, dc[0], dc[1], dc[2]) - - lines[3] = line3 - lines[4] = line4 - lines[5] = line5 - - f = open(file_name, "w") - f.writelines(lines) - f.close() - #__| - -def cleanup(suffix="", save_cube=True): - """Cleanup unnecessary and/or large file after routine completes. - - Args: - suffix: - save_cube: - """ - #| - cleanup - if not os.path.exists("dir_bader"): - os.makedirs("dir_bader") - - if not save_cube: - os.system("rm density" + suffix + ".cube") - else: - os.system("mv density" + suffix + ".cube dir_bader") - - os.system("mv ACF.dat dir_bader/ACF%s.dat" % suffix) - # os.system("rm AVF.dat") - # os.system("rm BCF.dat") - os.system("mv bader.out dir_bader/bader%s.out" % suffix) - - os.system("mv AVF.dat dir_bader/AVF.dat") - os.system("mv BCF.dat dir_bader/BCF.dat") - #__| - -def bader_exec(atoms, spin=""): - """Run bader executable on cube density file. - - Args: - spin: - """ - #| - bader_exec - bash_comm = "bader density" + spin + ".cube >> bader.out" - os.system(bash_comm) - - #| - Spin Polarlized Calculation - if spin == "up": - - f = open("ACF.dat"); lines = f.readlines(); f.close() - for i, line in enumerate(lines[2:-4]): - line = line.split() - atoms[i].magmom = float(line[4]) - atoms[i].charge = -float(line[4]) - cleanup(suffix=spin) - - elif spin == "down": - f = open("ACF.dat"); lines = f.readlines(); f.close() - - magmom_list = [] - charge_list = [] - for i, line in enumerate(lines[2:-4]): - line = line.split() - atoms[i].magmom -= float(line[4]) - val_i = atoms.calc.get_nvalence()[1][atoms[i].symbol] - atoms[i].charge -= float(line[4]) - val_i - - magmom_list.append(atoms[i].magmom) - charge_list.append(atoms[i].charge) - - atoms.info.update({"magmom_set": True}) - atoms.info.update({"bader_magmoms": magmom_list}) - atoms.info.update({"bader_charges": charge_list}) - - #| - Write data to file - with open("dir_bader/bader_charges_magmoms.pickle", "w") as fle: - pickle.dump( - {"charge_list": charge_list, "magmom_list": magmom_list}, - fle, - ) - #__| - - - cleanup(suffix=spin) - #__| - - #| - Non-Spin Polarized Calculation - elif spin == "": - charge_list = [] - f = open("ACF.dat"); lines = f.readlines(); f.close() - for i, line in enumerate(lines[2:-4]): - line = line.split() - - charge_i = atoms.calc.get_nvalence()[1][atoms[i].symbol] - atoms[i].charge = charge_i - float(line[4]) - charge_list.append(atoms[i].charge) - - atoms.info.update({"bader_charges": charge_list}) - - #| - Write data to file - with open("dir_bader/bader_charges_magmoms.pickle", "w") as fle: - pickle.dump( - {"charge_list": charge_list, "magmom_list": None}, - fle, - ) - #__| - - cleanup() - #__| - - #__| +#!/usr/bin/env python + +"""Bader charge analysis methods. + +Author(s): Colin Dickins wrote most of this; Raul A. Flores +""" + +#| - IMPORT MODULES +import sys +import os + +import pickle as pickle +import copy + +import numpy as np +# from ase.io import write +from ase import io +#__| + + +def bader( + atoms, + spinpol=False, + outdir=None, + run_exec=True, + run_exec_2=True, + convert_charge_den=True, + cleanup=True, + dft_code="QE", + ): + """Perform bader charge analysis on atoms. + + Calculate charge density using atoms.calc, calculate bader charges on each + atom in atoms, and assign to atom.data["bader_charge"]. + + If spinpol: also assign atom.data["bader_magmom"]. + + Args: + atoms: ASE atoms object + spinpol: Spin polarized calculation + outdir: Output directory location + run_exec: Whether to run bader executable or just create preliminary + file (some clusters don't/can't have the bader fortran code) + """ + #| - bader + mess = "Executing Bader Analysis " + mess += "*****************************************************" + print(mess); sys.stdout.flush() + + #| - Don't Run Bader Executable on AWS + if "COMPENV" not in os.environ: + print("COMPENV env. var. doesn't exits, probably in AWS?") + print("Bader executable turned off") + + run_exec = False + else: + pass + #__| + + if not os.path.exists("dir_bader"): + os.makedirs("dir_bader") + + calc = atoms.calc + + #| - Using Spin Polarization + if spinpol: + + #| - Spin up + if convert_charge_den: + cd2cube(atoms, spin="up") + if run_exec: + bader_exec( + atoms, + spin="up", + execute_bader=run_exec_2, + clean_up=cleanup, + dft_code=dft_code, + ) + + #__| + + #| - Spin down + if convert_charge_den: + cd2cube(atoms, spin="down") + if run_exec: + bader_exec( + atoms, + spin="down", + execute_bader=run_exec_2, + clean_up=cleanup, + dft_code=dft_code, + ) + #__| + + print("BADER MAGMOMS: " + str(atoms.get_initial_magnetic_moments())) + + #__| + + #| - Not Spin Polarized + else: + if convert_charge_den: + cd2cube(atoms) + if run_exec: + bader_exec( + atoms, + spin="", + clean_up=cleanup, + execute_bader=run_exec_2, + dft_code=dft_code, + ) + #__| + + print("BADER CHARGES: " + str(atoms.get_initial_charges())) + + # if run_exec: + # io.write("dir_bader/bader.traj", atoms) + + if outdir: + os.system("rm %s/charge.log" % outdir) + + #| - Writing 2 Atoms Objects with mogmoms and charges written + + if run_exec: + # Charges written to init_charges + atoms_cpy1 = copy.deepcopy(atoms) + bader_charges = atoms_cpy1.info["bader_charges"] + atoms_cpy1.set_initial_charges(bader_charges) + atoms_cpy1.write("dir_bader/bader_charges.traj") + + if spinpol: + atoms_cpy2 = copy.deepcopy(atoms) + bader_magmoms = atoms_cpy2.info["bader_magmoms"] + atoms_cpy2.set_initial_charges(bader_magmoms) + atoms_cpy2.write("dir_bader/bader_magmoms.traj") + + # atoms.set_calculator(calc=calc) + atoms.write("dir_bader/out.traj") + #__| + + #__| + + +def cd2cube(atoms, spin=""): + """Convert ASE charge density file to cube format. + + Takes charge density pickle file from ase-qe and writes a cube file ready + for bader analysis to the current directory + + Args: + atoms: + spin: + """ + #| - cd2cube + # cd2cube(atoms.calc.extract_charge_density(spin="up")[2], atoms) + + if spin == "": + cd = atoms.calc.extract_charge_density()[2] + else: + cd = atoms.calc.extract_charge_density(spin=spin)[2] + + file_name = "density" + spin + ".cube" + + nx, ny, nz = np.shape(cd) + #cut away periodic image planes to correct QE output + u = nx - 1 + v = ny - 1 + w = nz - 1 + cd2 = np.empty((u, v, w), np.float) + for i in range(u): + for j in range(v): + cd2[i][j][:] = cd[i][j][:w] + + io.write(file_name, atoms, data=cd2) + + # edit density.cube grid size if odd number of grid points to + # correct for old versions of ASE + bohr = 0.52917721092 + cell = atoms.get_cell() + da = cell[0] / (u * bohr) + db = cell[1] / (v * bohr) + dc = cell[2] / (w * bohr) + + f = open(file_name, "r") + lines = f.readlines() + f.close() + + line3 = "%5.0f %.6f %.6f %.6f\n" % (u, da[0], da[1], da[2]) + line4 = "%5.0f %.6f %.6f %.6f\n" % (v, db[0], db[1], db[2]) + line5 = "%5.0f %.6f %.6f %.6f\n" % (w, dc[0], dc[1], dc[2]) + + lines[3] = line3 + lines[4] = line4 + lines[5] = line5 + + f = open(file_name, "w") + f.writelines(lines) + f.close() + #__| + +def cleanup(suffix="", save_cube=True): + """Cleanup unnecessary and/or large file after routine completes. + + Args: + suffix: + save_cube: + """ + #| - cleanup + if not os.path.exists("dir_bader"): + os.makedirs("dir_bader") + + if not save_cube: + os.system("rm density" + suffix + ".cube") + else: + os.system("mv density" + suffix + ".cube dir_bader") + + os.system("mv ACF.dat dir_bader/ACF%s.dat" % suffix) + # os.system("rm AVF.dat") + # os.system("rm BCF.dat") + os.system("mv bader.out dir_bader/bader%s.out" % suffix) + + os.system("mv AVF.dat dir_bader/AVF.dat") + os.system("mv BCF.dat dir_bader/BCF.dat") + #__| + +def bader_exec( + atoms, + spin="", + execute_bader=True, + clean_up=True, + dft_code="QE", # 'VASP' or 'QE' + ): + """Run bader executable on cube density file and process data. + + Args: + atoms: + spin: + Spin component to process | "", "up", "down" + + """ + #| - bader_exec + if execute_bader: + bash_comm = "bader density" + spin + ".cube >> bader.out" + os.system(bash_comm) + + if dft_code == "VASP": + if execute_bader: + bash_comm = "chgsum.pl AECCAR0 AECCAR2" + os.system(bash_comm) + bash_comm = "bader CHGCAR -ref CHGCAR_sum" + os.system(bash_comm) + + #| - Spin Polarlized Calculation + if spin == "up": + f = open("ACF.dat"); lines = f.readlines(); f.close() + for i, line in enumerate(lines[2:-4]): + line = line.split() + atoms[i].magmom = float(line[4]) + atoms[i].charge = -float(line[4]) + if clean_up: + cleanup(suffix=spin) + + elif spin == "down": + f = open("ACF.dat"); lines = f.readlines(); f.close() + + magmom_list = [] + charge_list = [] + for i, line in enumerate(lines[2:-4]): + line = line.split() + atoms[i].magmom -= float(line[4]) + + #| - Getting number of valence electrons + calc_has_get_nvalence = getattr(atoms.calc, "get_nvalence", None) + if calc_has_get_nvalence: + val_i = atoms.calc.get_nvalence()[1][atoms[i].symbol] + else: + val_i = valence_dict.get(atoms[i].symbol, None) + + assert val_i is not None, "Can't find # of valence electrons!!" + #__| + + atoms[i].charge -= float(line[4]) - val_i + + magmom_list.append(atoms[i].magmom) + charge_list.append(atoms[i].charge) + + atoms.info.update({"magmom_set": True}) + atoms.info.update({"bader_magmoms": magmom_list}) + atoms.info.update({"bader_charges": charge_list}) + + #| - Write data to file + with open("dir_bader/bader_charges_magmoms.pickle", "w") as fle: + pickle.dump( + {"charge_list": charge_list, "magmom_list": magmom_list}, + fle, + ) + #__| + + if clean_up: + cleanup(suffix=spin) + #__| + + #| - Non-Spin Polarized Calculation + elif spin == "": + charge_list = [] + f = open("ACF.dat"); lines = f.readlines(); f.close() + for i, line in enumerate(lines[2:-4]): + line = line.split() + + #| - Getting number of valence electrons + calc_has_get_nvalence = getattr(atoms.calc, "get_nvalence", None) + if calc_has_get_nvalence: + charge_i = atoms.calc.get_nvalence()[1][atoms[i].symbol] + else: + charge_i = valence_dict.get(atoms[i].symbol, None) + + assert charge_i is not None, "Can't find # of valence electrons!!" + #__| + + # charge_i = atoms.calc.get_nvalence()[1][atoms[i].symbol] + + atoms[i].charge = charge_i - float(line[4]) + charge_list.append(atoms[i].charge) + + atoms.info.update({"bader_charges": charge_list}) + + #| - Write data to file + with open("dir_bader/bader_charges_magmoms.pickle", "w") as fle: + pickle.dump( + {"charge_list": charge_list, "magmom_list": None}, + fle, + ) + #__| + + cleanup() + #__| + + #__| + + +# From VASP PBE +valence_dict = { + "O": 6, + "Ir": 9, + "Cr": 6, + "Ti": 4, + "Ni": 10, + } diff --git a/classical_methods/lennard_jones.py b/classical_methods/lennard_jones.py index 51a9fa7..196fe71 100644 --- a/classical_methods/lennard_jones.py +++ b/classical_methods/lennard_jones.py @@ -1,174 +1,174 @@ - -#!/usr/bin/env python - -"""Wrapper code around ASAP & ASE LJ implementation. - -Author: Raul A. Flores -""" - -#| - Import Modules -import gc -import math -import numpy as np # import pandas as pd -import collections -from pymatgen.core.periodic_table import Element -from asap3 import LennardJones -#__| - -def lennard_jones_sp( - epsilon, - sigma, - atoms, - modified_lj=True, - normalize_per_atom=True, - return_quantity="energy", # 'energy', 'forces', 'both', 'energy&forces' - ): - """Calculate single-point energy and forces with Lennard Jones force field. - - Because the order of the elements must be internally consistent, the - convention will be that the element list goes from smalles to largest - atomic number. - - Args: - epsilon: - sigma: - atoms: - modified_lj: - return: - """ - #| - lennard_jones_sp - atomic_num_list = atoms.get_atomic_numbers() - atomic_num_list = list(set(atomic_num_list)) - atomic_num_list.sort() - - atomic_type_num_dict = collections.Counter(atomic_num_list) - - orig_num_of_atoms = atoms.get_number_of_atoms() - - #| - Filter Relevant LJ Parameters - row_col_to_keep = [ - Element.from_Z(atomic_num).name - for - atomic_num - in - atomic_num_list - ] - - epsilon = epsilon.loc[row_col_to_keep] - epsilon = epsilon[row_col_to_keep] - - sigma = sigma.loc[row_col_to_keep] - sigma = sigma[row_col_to_keep] - - # epsilon = epsilon.values - # sigma = sigma.values - #__| - - calc = LennardJones( - list(atomic_type_num_dict), - epsilon.values, - sigma.values, - rCut=-1, - modified=modified_lj, - ) - - #| - Repeat Unit Cell - repeat_unit_cell = repeat_unit_cell_ASAP(atoms, sigma) - - atoms = atoms.repeat(repeat_unit_cell) - #__| - - atoms.set_calculator(calc) - - #| - Energy - lj_energy = atoms.get_potential_energy() - lj_energy_per_atom = lj_energy / atoms.get_number_of_atoms() - - # This is total energy w.r.t. the original number of atoms in the - # computational cell (since the cell was repeated) - lj_total_energy = lj_energy_per_atom * orig_num_of_atoms - - if normalize_per_atom: - lj_energy = lj_energy_per_atom - - else: - lj_energy = lj_total_energy - #__| - - #| - Forces -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* - # COMBAK - # Find a way to decrease the number of atoms again - lj_forces = atoms.get_forces() - - #__| - - if return_quantity == "energy": - out = lj_energy - elif return_quantity == "forces": - out = lj_forces - elif return_quantity == "both" or return_quantity == "both": - out = (lj_energy, lj_forces) - - return(out) - #__| - -def repeat_unit_cell_ASAP(atoms, sigma): - """Return repeat array such that ASAP doesn't complain about r_cut. - - Args: - atoms - """ - #| - repeat_unit_cell_ASAP - - def calc_cell_heights(unit_cell): - """Calculate heights of cell. - - Obtained code from ASAP NormalAtoms.invert_cell - - Args: - unit_cell: - sigma: - """ - #| - calc_cell_heights - determinant = np.cross( - unit_cell[0], - unit_cell[1], - ) - determinant = abs(determinant.dot(unit_cell[2])) - - heights = [] - for i_ind, unit_vect_i in enumerate(unit_cell): - inv = np.cross( - unit_cell[(i_ind + 1) % 3], - unit_cell[(i_ind + 2) % 3], - ) - - den = math.sqrt(np.dot(inv, inv)) - height_i = determinant / den - heights.append(height_i) - - return(heights) - #__| - - heights = calc_cell_heights(atoms.cell) - - # The cut-off length is internally set by ASAP to 3 * 2 * (max_sigma_value) - - # max_sigma = sigma.flatten().max() - max_sigma = sigma.values.flatten().max() - - cut_off_length = 3 * 2 * max_sigma - - #| - Repeat Unit Cell - repeat_unit_cell = [] - for i_ind, height_i in enumerate(heights): - if height_i < cut_off_length: - cell_repeat_fact = math.ceil(cut_off_length / height_i) - cell_repeat_fact = int(cell_repeat_fact) - repeat_unit_cell.append(cell_repeat_fact) - else: - repeat_unit_cell.append(1) - #__| - - return(repeat_unit_cell) - #__| + +#!/usr/bin/env python + +"""Wrapper code around ASAP & ASE LJ implementation. + +Author: Raul A. Flores +""" + +#| - Import Modules +import gc +import math +import numpy as np # import pandas as pd +import collections +from pymatgen.core.periodic_table import Element +from asap3 import LennardJones +#__| + +def lennard_jones_sp( + epsilon, + sigma, + atoms, + modified_lj=True, + normalize_per_atom=True, + return_quantity="energy", # 'energy', 'forces', 'both', 'energy&forces' + ): + """Calculate single-point energy and forces with Lennard Jones force field. + + Because the order of the elements must be internally consistent, the + convention will be that the element list goes from smalles to largest + atomic number. + + Args: + epsilon: + sigma: + atoms: + modified_lj: + return: + """ + #| - lennard_jones_sp + atomic_num_list = atoms.get_atomic_numbers() + atomic_num_list = list(set(atomic_num_list)) + atomic_num_list.sort() + + atomic_type_num_dict = collections.Counter(atomic_num_list) + + orig_num_of_atoms = atoms.get_number_of_atoms() + + #| - Filter Relevant LJ Parameters + row_col_to_keep = [ + Element.from_Z(atomic_num).name + for + atomic_num + in + atomic_num_list + ] + + epsilon = epsilon.loc[row_col_to_keep] + epsilon = epsilon[row_col_to_keep] + + sigma = sigma.loc[row_col_to_keep] + sigma = sigma[row_col_to_keep] + + # epsilon = epsilon.values + # sigma = sigma.values + #__| + + calc = LennardJones( + list(atomic_type_num_dict), + epsilon.values, + sigma.values, + rCut=-1, + modified=modified_lj, + ) + + #| - Repeat Unit Cell + repeat_unit_cell = repeat_unit_cell_ASAP(atoms, sigma) + + atoms = atoms.repeat(repeat_unit_cell) + #__| + + atoms.set_calculator(calc) + + #| - Energy + lj_energy = atoms.get_potential_energy() + lj_energy_per_atom = lj_energy / atoms.get_number_of_atoms() + + # This is total energy w.r.t. the original number of atoms in the + # computational cell (since the cell was repeated) + lj_total_energy = lj_energy_per_atom * orig_num_of_atoms + + if normalize_per_atom: + lj_energy = lj_energy_per_atom + + else: + lj_energy = lj_total_energy + #__| + + #| - Forces -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* + # COMBAK + # Find a way to decrease the number of atoms again + lj_forces = atoms.get_forces() + + #__| + + if return_quantity == "energy": + out = lj_energy + elif return_quantity == "forces": + out = lj_forces + elif return_quantity == "both" or return_quantity == "both": + out = (lj_energy, lj_forces) + + return(out) + #__| + +def repeat_unit_cell_ASAP(atoms, sigma): + """Return repeat array such that ASAP doesn't complain about r_cut. + + Args: + atoms + """ + #| - repeat_unit_cell_ASAP + + def calc_cell_heights(unit_cell): + """Calculate heights of cell. + + Obtained code from ASAP NormalAtoms.invert_cell + + Args: + unit_cell: + sigma: + """ + #| - calc_cell_heights + determinant = np.cross( + unit_cell[0], + unit_cell[1], + ) + determinant = abs(determinant.dot(unit_cell[2])) + + heights = [] + for i_ind, unit_vect_i in enumerate(unit_cell): + inv = np.cross( + unit_cell[(i_ind + 1) % 3], + unit_cell[(i_ind + 2) % 3], + ) + + den = math.sqrt(np.dot(inv, inv)) + height_i = determinant / den + heights.append(height_i) + + return(heights) + #__| + + heights = calc_cell_heights(atoms.cell) + + # The cut-off length is internally set by ASAP to 3 * 2 * (max_sigma_value) + + # max_sigma = sigma.flatten().max() + max_sigma = sigma.values.flatten().max() + + cut_off_length = 3 * 2 * max_sigma + + #| - Repeat Unit Cell + repeat_unit_cell = [] + for i_ind, height_i in enumerate(heights): + if height_i < cut_off_length: + cell_repeat_fact = math.ceil(cut_off_length / height_i) + cell_repeat_fact = int(cell_repeat_fact) + repeat_unit_cell.append(cell_repeat_fact) + else: + repeat_unit_cell.append(1) + #__| + + return(repeat_unit_cell) + #__| diff --git a/dft_job_automat/compute_env.py b/dft_job_automat/compute_env.py index 817de0b..41212fe 100644 --- a/dft_job_automat/compute_env.py +++ b/dft_job_automat/compute_env.py @@ -93,7 +93,7 @@ def slurm_squeue_parse( #__| -################################################################################ +############################################################################### class ComputerCluster(): """Base class for interfacing with computing resources. @@ -311,7 +311,7 @@ def submit_job(self, **kwargs): #__| ********************************************************************** -################################################################################ +############################################################################### class EdisonCluster(ComputerCluster): @@ -1214,6 +1214,7 @@ def submit_job_clust(self, **kwargs): ) sub_time = datetime.datetime.now().isoformat() + # except subprocess.CalledProcessError, e: except subprocess.CalledProcessError as e: print("Ping stdout output:\n", e.output) @@ -1445,7 +1446,11 @@ def get_jobid(self, path_i="."): class AWSCluster(ComputerCluster): - """AWS EC2 computing resource.""" + """AWS EC2 computing resource. + + Must define $awsdir environment variable + ex. $awsdir=/scratch/users/flores12/AWS/matr.io + """ #| - AWSCluster *********************************************************** def __init__(self, @@ -1457,8 +1462,18 @@ def __init__(self, self.job_data_dir = "/simulation" self.root_dir = root_dir self.default_sub_params = self.default_submission_parameters() - self.aws_dir = os.environ["aws_sc"] - self.job_queue_dir = self.aws_dir + "/jobs_bin" + self.aws_dir = os.environ.get("awsdir", "") + + #| - Create job_queue_dir + self.job_queue_dir = os.path.join( + self.aws_dir, + "jobs_bin") + + directory = self.job_queue_dir + if not os.path.exists(directory): + os.makedirs(directory) + #__| + self.job_state_keys = self.job_state_dict() self.queues = self.__queue_types__() self.job_queue_state_key = "job_status" @@ -1479,7 +1494,7 @@ def default_submission_parameters(self): "job_script": "model.py", "copy_PythonModules": True, - "copy_PythonPackages": True, + "copy_PythonPackages": False, } return(def_params) @@ -1514,7 +1529,7 @@ def submit_job_clust(self, **kwargs): if os.path.isfile(".SUBMITTED"): print("Directory already submitted, will be skipped") os.chdir(root_dir) - return(None) # <-------- SKIP JOB --------------------------------- + return(None) # <-------- SKIP JOB -------------------------------- else: os.chdir(root_dir) #__| @@ -1536,25 +1551,39 @@ def submit_job_clust(self, **kwargs): return(None) else: print("submitting job") - aws_dir = os.environ["aws_sc"] + aws_dir = self.aws_dir if cpus == "default": bash_command = aws_dir + "/bin/trisub -q " + queue - # bash_command = aws_dir + "/matr.io/bin/trisub -q " + queue else: + + #| - Checking that number of cpus is within allows + if queue == "medium": + if cpus > 4: + print("Medium queue can't have more than 4 cpus") + print(" setting cpus to 4") + cpus = 4 + #__| + bash_command = aws_dir + "/bin/trisub -c " + str(cpus) + \ " -q " + queue - try: - output = subprocess.check_output(bash_command, shell=True) - sub_time = datetime.datetime.now().isoformat() - # except subprocess.CalledProcessError, e: - except subprocess.CalledProcessError as e: - print("Ping stdout output:\n", e.output) + # try: + output = subprocess.check_output( + bash_command, + shell=True, + universal_newlines=True, # CHANGED + ) - os.chdir(root_dir) - print("JOB SKIPPED: ") - return(None) + sub_time = datetime.datetime.now().isoformat() + + # # except subprocess.CalledProcessError, e: + # except subprocess.CalledProcessError as e: + # print("Ping stdout output:\n", e.output) + # + # os.chdir(root_dir) + # print("JOB SKIPPED: ") + # return(None) #__| os.system("chmod 777 " + path + "/*") @@ -1562,6 +1591,8 @@ def submit_job_clust(self, **kwargs): #| - Parsing Submission for Job ID output = output.splitlines() + print(output) # CHANGED + for line in output: if "jobId" in line: lst = line.split('"') @@ -1796,6 +1827,7 @@ def job_info_batch(self, job_id): #__| ********************************************************************** + class DummyCluster(ComputerCluster): """Placeholder class for when current cluster isn't supported.""" #| - DummyCluster @@ -1837,287 +1869,4 @@ def submit_job_clust(self, **kwargs): print("Nothing happens!!") #__| - - #| - Not Needed - - # def default_submission_parameters(self): - # """Defaul SLURM parameters for - # """ - # #| - default_submission_parameters - # def_params = { - # "queue": "owners,iric,normal", # -p flag - # "nodes": "1", # --nodes - # "cpus": "16", # --ntasks-per-node - # "memory": "4000", # --mem-per-cpu - # "wall_time": "720", # --time (720min -> 12hrs) - # "job_name": "Default", # --job-name - # "priority": "normal", # --qos - # "email": "flores12@stanford.edu", # --mail-user - # "email_mess": "FAIL", # --mail-type - # } - # - # return(def_params) - # #__| - # - # def submit_job_clust(self, **kwargs): - # """ - # Submits job to sherlck. - # """ - # #| - submit_job - # time.sleep(1.5) - # - # #| - Merging Submission Parameters - # params = merge_two_dicts(self.default_sub_params, kwargs) - # - # path = params["path_i"] - # #__| - # - # #| - Submit Job - # os.chdir(path) - # - # if params["job_name"] == "Default": - # params["job_name"] = os.getcwd() - # - # print("submitting job") - # os.system("chmod 777 *") - # # bash_command = "/u/if/flores12/bin/qv model.py" - # #__| **** TEMP - # - # #| - Bash Submisssion Command - # bash_command = "/usr/bin/sbatch " - # - # bash_command += "-p " + str(params["queue"]) + " " - # bash_command += "--nodes " + str(params["nodes"]) + " " - # bash_command += "--ntasks-per-node " + str(params["cpus"]) + " " - # bash_command += "--mem-per-cpu " + str(params["memory"]) + " " - # bash_command += "--time " + str(params["wall_time"]) + " " - # bash_command += "--job-name " + str(params["job_name"]) + " " - # bash_command += "--qos " + str(params["priority"]) + " " - # bash_command += "--mail-user " + str(params["email"]) + " " - # bash_command += "--mail-type " + str(params["email_mess"]) + " " - # bash_command += "--output " + str(params["out_file"]) + " " - # bash_command += "--error " + str(params["err_file"]) + " " - # bash_command += "-C CPU_GEN:HSW " # COMBAK Formalize this cpu architecture filter - # - # bash_command += params["job_script"] - # - # print("Bash Submission Command:") - # print(bash_command) - # #__| - # - # try: - # output = subprocess.Popen( - # bash_command, - # stdout=subprocess.PIPE, - # shell=True, - # ) - # sub_time = datetime.datetime.now().isoformat() - # # except subprocess.CalledProcessError, e: - # except subprocess.CalledProcessError as e: - # print("Ping stdout output:\n", e.output) - # - # os.chdir(self.root_dir) - # print("JOB SKIPPED: ") - # return(None) - # - # #| - Parsing Output - # out = output.communicate()[0] - # out_copy = copy.deepcopy(out) - # - # ind = out.find("job") - # out = out[ind + 3:] - # - # jobid = re.sub("[^0-9]", "", out) - # - # try: - # jobid = int(jobid) - # - # except: - # print("Couldn't parse for jobid | !@!!") - # jobid = None - # pass - # - # if type(jobid) == int: - # jobid = jobid - # else: - # jobid = None - # #__| - # - # #| - Writing Files - # with open(".SUBMITTED", "w") as fle: - # fle.write("\n") - # - # with open(".bash_comm", "w") as fle: - # fle.write(str(bash_command) + str("\n")) - # - # with open(".jobid", "w") as fle: - # fle.write(str(jobid) + str("\n")) - # - # with open(".sub_out", "w") as fle: - # fle.write(out_copy) - # #__| - # - # os.chdir(self.root_dir) - # - # return(out, jobid) - # - # #__| - # - # def job_state_dict(self): - # """ - # """ - # #| - job_state_dict - # job_state_dict = { - # "PD": "PENDING", - # "R": "RUNNING", - # "CF": "CONFIGURING", - # "SUCCEEDED": "SUCCEEDED", - # - # # "FAILED": "FAILED", - # # "STARTING": "STARTING", - # # "RUNNABLE": "PENDING", - # # "SUBMITTED": "SUBMITTED", - # } - # - # return(job_state_dict) - # #__| - # - # def __queue_types__(self): - # """Queue types for SLAC cluster - # """ - # #| - __queue_types__ - # queue_list = [ - # "owners", - # "iric", - # ] - # - # return(queue_list) - # #__| - # - # def get_jobid(self, path_i="."): - # """ - # """ - # #| - get_jobid - # # # path_i = "." - # # fileid_path = path_i + "/.jobid" - # # # print(fileid_path) - # # if os.path.isfile(fileid_path): - # # with open(path_i + "/.jobid") as fle: - # # jobid = fle.read().strip() - # # else: - # # jobid=None - # # - # # return(jobid) - # #__| - # - # def job_info_batch(self, job_id, path_i=None): - # """ - # """ - # #| - job_info_batch - # bash_comm = "squeue -j " + str(job_id) - # - # try: - # out = subprocess.check_output( - # bash_comm, - # shell=True, - # stderr=subprocess.STDOUT, - # ) - # - # # 'JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)' - # out = out.splitlines() - # out = out[1].split(" ") - # out = [i for i in out if i != ''] - # - # data_dict = { - # "PARTITION": out[1], - # "STAT": out[4], - # # "CF": - # } - # - # if path_i is not None: - # key = self.job_queue_state_key - # with open(path_i + "/.QUEUESTATE", "w") as fle: - # fle.write(self.job_state_keys[data_dict[key]]) - # fle.write("\n") - # - # except subprocess.CalledProcessError: - # data_dict = None - # pass - # - # except: - # data_dict = None - # pass - # - # - # return(data_dict) - # - # #__| - # - # def completed_file(self, path_i="."): - # """ - # Check whether ".FINISHED" file exists. - # - # Indicates that the job has gone to completion - # - # Args: - # path_i: - # """ - # #| - completed_file - # completed_fle = False - # if os.path.exists(path_i + "/.FINISHED"): - # completed_fle = True - # - # return(completed_fle) - # #__| - # - # def job_state(self, path_i="."): - # """ - # Return job state of path_i --> job_i. - # - # Args: - # path_i - # """ - # #| - job_state - # job_id = self.get_jobid(path_i=path_i) - # - # job_state_out = None - # if job_id is not None: - # job_info = self.job_info_batch(job_id, path_i=path_i) - # - # if job_info is not None: - # key = self.job_queue_state_key - # if key in job_info: - # job_state_out = job_info[key] - # job_state_out = self.job_state_keys[job_state_out] - # - # #| - Checking for "completed" file indicating success - # completed_fle = self.completed_file(path_i=path_i) - # if completed_fle: - # job_state_out = self.job_state_keys["SUCCEEDED"] - # #__| - # - # return(job_state_out) - # - # #__| - # - # def get_jobid(self, path_i="."): - # """ - # Return job ID of job_i. - # - # Args: - # path_i: - # """ - # #| - get_jobid - # fileid_path = path_i + "/.jobid" - # if os.path.isfile(fileid_path): - # with open(path_i + "/.jobid") as fle: - # jobid = fle.read().strip() - # else: - # jobid = None - # - # return(jobid) - # #__| - - #__| - #__| diff --git a/dft_job_automat/job_setup.py b/dft_job_automat/job_setup.py index 1933989..d520d2c 100644 --- a/dft_job_automat/job_setup.py +++ b/dft_job_automat/job_setup.py @@ -1,1420 +1,1420 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -"""Job automation class. - -Author: Raul A. Flores -""" - -#| - Import Modules -import os -import shutil -import copy - -import itertools -import pickle -import json - -import numpy as np -import pandas as pd - -import ast - -# My Modules -from dft_job_automat.compute_env import ComputerCluster -#__| - - -class Job: - """Encapsulates data and method related to single jobs. - - Still a work in progress - """ - - #| - Job ****************************************************************** - def __init__(self, - path_i=None, - job_params_dict=None, - max_revision=None, - - root_dir=None, - ): - """COMBAK Flesh this out later. - - Args: - path_i: - Path to job folder - job_params_dict: - Job parameter dictionary - max_revision: - Max revisions for unique job, defined by the set of job params - """ - #| - __init__ - - #| - Setting class attributes - self.full_path = path_i - self.job_params_dict = job_params_dict - self.max_revision = max_revision - self.root_dir = root_dir - #__| - - # if job_params_dict is None: - - self.job_params = self.__set_job_parameters__(job_params_dict) - - # print(self.job_params) - # print("____-d-sfs") - # print("") - - # else: - # self.__write_job_parameters__() - - self.revision_number = self.__revision_number__() - #__| - - def write_job_parameters(self): - """ - """ - #| - __write_job_parameters__ - leaf_dir = self.full_path.split("/")[-1] - - if "_" in leaf_dir: - # if leaf_dir[1:].isnumeric(): - if leaf_dir[1:].isdigit(): - leaf_dir = self.full_path.split("/")[-1] - ind_i = self.full_path.rfind(leaf_dir) - path_i = self.full_path[:ind_i - 1] - - - #| - NEW | Trying to remove keys which aren't JSON serializable - def is_jsonable(x): - """ - """ - #| - is_jsonable - try: - json.dumps(x) - return True - except: - return False - #__| - - job_params_dict_cpy = copy.deepcopy(self.job_params_dict) - - keys_to_delete = [] - for key, value in job_params_dict_cpy.items(): - if not is_jsonable(value): - keys_to_delete.append(key) - - if len(keys_to_delete) > 0: - print( - "The following job properties couldn't be JSON serialized", - ", and will be ignored" - ) - print(keys_to_delete) - - for k in keys_to_delete: - job_params_dict_cpy.pop(k, None) - - print(job_params_dict_cpy) - #__| - - - file_path_i = os.path.join(path_i, "job_params.json") - with open(file_path_i, 'w') as outfile: - json.dump( - job_params_dict_cpy, - # self.job_params_dict, - outfile, - indent=2, - ) - #__| - - def __set_job_parameters__(self, job_params_dict): - """ - - Args: - job_params_dict: - """ - #| - __set_job_parameters__ - job_params_from_file = self.__read_job_params_file__() - - if job_params_dict is not None: - # job_params_dict.update(job_params_from_file) - job_params_from_file.update(job_params_dict) - - return(job_params_from_file) - #__| - - def __read_job_params_file__(self): - """Read "job_parameters.json" file from job direcory. - - Development Notes: - Search in the job root dir (one level up from "_" dirs) - - Args: - """ - #| - __read_job_params_file__ - job_params = {} - - # file_path = self.full_path + "/" + "job_parameters.json" - - file_exists = False - - file_path = os.path.join( - self.full_path, - "job_parameters.json") - if os.path.exists(file_path): - file_exists = True - with open(file_path, "r") as fle: - job_params = json.load(fle) - - - ind_i = self.full_path.rfind(self.full_path.split("/")[-1]) - path_i_rt = self.full_path[:ind_i - 1] - - file_path = os.path.join( - # self.full_path[0:-2], - path_i_rt, - "job_parameters.json", - ) - if os.path.exists(file_path): - file_exists = True - with open(file_path, "r") as fle: - job_params = json.load(fle) - - - file_path = os.path.join( - # self.full_path[0:-2], - path_i_rt, - "job_params.json", - ) - if os.path.exists(file_path): - file_exists = True - with open(file_path, "r") as fle: - job_params = json.load(fle) - - if not file_exists: - print("No job_params file found for following job:") - print(self.full_path) - - return(job_params) - #__| - - def __revision_number__(self): - """ - """ - #| - __revision_number__ - # print(self.full_path) - revision_i = int(self.full_path.split("/")[-1].split("_")[-1]) - - return(revision_i) - #__| - - #__| ********************************************************************** - - -class DFT_Jobs_Setup: - """Useful class to set up multiple DFT job in a directory structure. - - Must be initialized with tree_level and level_entries inputs (Not really) - """ - - #| - DFT_Jobs_Setup ******************************************************* - - def __init__(self, - tree_level=None, - level_entries=None, - indiv_dir_lst=None, - indiv_job_lst=None, - indiv_job_dict_lst=None, - skip_dirs_lst=None, - root_dir=".", - working_dir=".", - folders_exist=None, - parse_all_revisions=True, - ): - """Initialize DFT_Jobs_Setup Instance. - - Args: - tree_level: - level_entries: - indiv_dir_lst: - indiv_job_lst: - List of dictionaries representing jobs - skip_dirs_lst: - working_dir: - folders_exist: - """ - #| - __init__ - - #| - Initializing Some Class Attributes - self.order_dict = None - self.job_var_lst = None - self.Job_list = [] - self.sep = "-" - self.level_entries = level_entries - self.tree_level_labels = tree_level - self.level_entries_list = level_entries - self.skip_dirs_lst = skip_dirs_lst - self.indiv_dir_lst = indiv_dir_lst - self.indiv_job_lst = indiv_job_lst - - self.indiv_job_dict_lst = indiv_job_dict_lst - self.parse_all_revisions = parse_all_revisions - #__| - - self.root_dir = self.__set_root_dir__(root_dir) - - self.working_dir = self.__set_working_dir__(working_dir) - - self.cluster = ComputerCluster() - self.jobs_att = self.__load_jobs_attributes__() - self.__create_jobs_bin__() - self.folders_exist = self.__folders_exist__(folders_exist) - - self.load_dir_struct() - self.__create_dir_structure_file__() - self.num_jobs = self.__number_of_jobs__() - self.__Job_list__() - - self.data_frame = self.__gen_datatable__() - - # if self.folders_exist: - # # self.data_frame = self.__generate_data_table__() - - self.check_inputs() - #__| - - def __job_i_param_dict_to_job_var_lst__(self, params_dict): - """Constructs a job_variable list from a dictionary of parameters. - - Args: - params_dict: - """ - #| - __job_i_param_dict_to_job_var_lst__ - assert self.tree_level_labels is not None - - job_var_lst_i = [] - for level_prop in self.tree_level_labels: - level_var_dict = {} - for key_i, value_i in params_dict.items(): - if key_i == level_prop: - level_var_dict["property"] = key_i - level_var_dict["value"] = value_i - - job_var_lst_i.append(level_var_dict) - break - - return(job_var_lst_i) - #__| - - - def write_job_params_json_file(self): - """ - """ - #| - write_job_params_json_file - for Job in self.Job_list: - Job.write_job_parameters() - - #__| - - def create_Jobs_from_dicts_and_paths(self, - jobs_list, - ): - """Populate Job_list attribute manually. - - Args: - jobs_list - List of dictionaries with 'properties' and 'path' keys - - """ - #| - create_Jobs_from_dicts_and_paths - for job_i in jobs_list: - - path_i = job_i["path"] - job_params_dict = job_i["properties"] - - rev_dirs, max_rev = self.__revision_list_and_max__( - path_i, - ) - - for rev_i in rev_dirs: - path_i = os.path.join(path_i, rev_i) - path_i = os.path.normpath(path_i) - - Job_i = Job( - path_i=path_i, - job_params_dict=job_params_dict, - max_revision=max_rev, - root_dir=None, - ) - - self.Job_list.append(Job_i) - #__| - - def __Job_list__(self): - """Create Job list from various input sources.""" - #| - __Job_list__ - - #| - Adding Jobs From Individual Directory List - if self.indiv_dir_lst is not None: - for job_i_dir in self.indiv_dir_lst: - - rev_dirs, max_rev = self.__revision_list_and_max__(job_i_dir) - - print(job_i_dir) - if rev_dirs: - if self.parse_all_revisions is False: - rev_dirs = [rev_dirs[-1]] - - for rev_i in rev_dirs: - path_i = os.path.join(job_i_dir, rev_i) - path_i = os.path.normpath(path_i) - - Job_i = Job( - path_i=path_i, - job_params_dict=None, - max_revision=max_rev, - root_dir=None, - ) - - self.Job_list.append(Job_i) - else: - print("Didn't find any job dirs here:") - print(job_i_dir) - pass - #__| - - #| - Adding Jobs From Enumerated Job Properties Tree - if self.job_var_lst is not None: - for job_i in self.job_var_lst: - job_var_dict = self.__job_i_vars_to_dict__(job_i) - - if self.folders_exist: - path_i = self.var_lst_to_path( - job_i, - job_rev="Auto", - relative_path=False, - ) - - #| - __old__ - # else: - # print("else *s8fs*sdf") - # path_i = os.path.join( - # - # self.var_lst_to_path( - # job_i, - # job_rev="Auto", - # relative_path=False, - # ), - # - # # self.var_lst_to_path( - # # job_i, - # # ), - # - # "_1", - # ) - #__| - - rev_dirs, max_rev = self.__revision_list_and_max__( - # path_i - self.var_lst_to_path( - job_i, - job_rev="None", - relative_path=False, - ) - ) - - Job_i = Job( - path_i=path_i, - job_params_dict=job_var_dict, - max_revision=max_rev, - root_dir=self.root_dir, - ) - - self.Job_list.append(Job_i) - #__| - - #| - TEMP | I don't remember why this is here - indiv_job = self.indiv_job_lst is not None - level_labels = self.tree_level_labels is not None - if indiv_job and level_labels: - print("LSKDJFKLDS_-09sdfsdfs9dfas") - for job_params_i in self.indiv_job_lst: - - job_var_lst_i = self.__job_i_param_dict_to_job_var_lst__( - job_params_i, - ) - - path_i = os.path.join( - self.new_var_lst_to_path(job_var_lst_i), - "_1", - ) - - Job_i = Job( - path_i=path_i, - job_params_dict=job_params_i, - max_revision=None, - root_dir=self.root_dir, - ) - - self.Job_list.append(Job_i) - #__| - - if self.indiv_job_dict_lst is not None: - self.create_Jobs_from_dicts_and_paths( - self.indiv_job_dict_lst, - ) - #__| - - - #| - Misc Methods - - def __job_i_vars_to_dict__(self, job_i_vars): - """ - - Args: - job_i_vars: - """ - #| - __job_i_vars_to_dict__ - job_vars_dict = {} - for prop in job_i_vars: - prop_key = prop["property"] - prop_value = prop["value"] - - job_vars_dict[prop_key] = prop_value - - return(job_vars_dict) - #__| - - def __create_jobs_bin__(self): - """Create /jobs_bin folder if it doesn't exist.""" - #| - __create_jobs_bin__ - folder_dir = os.path.join(self.root_dir, self.working_dir, "jobs_bin") - # folder_dir = self.root_dir + "/jobs_bin" - - if not os.path.exists(folder_dir): - # print("KDJFDI__") - # print(folder_dir) - os.makedirs(folder_dir) - #__| - - def __folders_exist__(self, folders_exist): - """Check whether directory structure exists. - - The alternative is to be creating an instance from a location where - the original job files don't exist but the job dataframe does - """ - #| - __folders_exist__ - # User override - if folders_exist is not None: - return(folders_exist) - - folders_exist = False - - #| - Folders Exist Criteria - crit_0 = False - if os.path.isfile(self.root_dir + "/jobs_bin/.folders_exist"): - crit_0 = True - - crit_1 = False - if os.path.isdir(self.root_dir + "/data"): - crit_1 = True - #__| - - #| - Deciding whether folders exist or not - if crit_0 is True: - pass - if crit_1 is True: - folders_exist = True - else: - folders_exist = False - else: - folders_exist = False - #__| - - return(folders_exist) - #__| - - def __set_root_dir__(self, root_dir_in): - """Returns root directory.""" - #| - __set_root_dir__ - if root_dir_in == ".": - root_dir = os.getcwd() - else: - root_dir = root_dir_in - - return(root_dir) - #__| - - def __set_working_dir__(self, working_dir_in): - """ - """ - #| - __set_working_dir__ - if working_dir_in == ".": - working_dir = "" - else: - working_dir = working_dir_in - - return(working_dir) - #__| - - - def __check_input__(self): - """Check that tree_level and level_entries are of matching length.""" - #| - __check_input__ - tmp = set(self.tree_level_labels) - input_diff = tmp.symmetric_difference(self.level_entries.keys()) - if not input_diff == set(): - undefined_labels = [] - for i in input_diff: - undefined_labels.append(i) - - print("\n") - message = "Did not fill out level entries dict properly" + "\n" - message += "The following properties need to be defined" + "\n" - message += str(undefined_labels) - raise ValueError(message) - #__| - - - def __number_of_jobs__(self): - """Count number of jobs in instance. - - # TODO Should count jobs in job_var_lst and the indiv_dir jobs - # TODO Make distinction between total jobs (including number of - revisions) and just the before revision number - - Depends on number of unique variable list and number of revisions for - each job. - """ - #| - __number_of_jobs__ - num_jobs = 0 - - # Regular jobs - if self.job_var_lst is not None: - num_jobs = len(self.job_var_lst) - - # Individual dir jobs - if self.indiv_dir_lst is not None: - num_jobs += len(self.indiv_dir_lst) - - - return(num_jobs) - #__| - - - def new_var_lst_to_path(self, - variable_lst, - job_rev="False", - relative_path=True, - ): - """ - """ - #| - new_var_lst_to_path - if isinstance(variable_lst, str): - variable_lst = ast.literal_eval(variable_lst) - else: - pass - - level_cnt = 0 - dir_name = "data/" - for level in variable_lst: - level_cnt += 1 - - if self.level_entries is not None: - tmp = self.tree_level_labels[level_cnt - 1] - index = self.level_entries[tmp].index(level["value"]) + 1 - if index < 10: - index = "0" + str(index) - else: - index = str(index) - - beggining = index + self.sep - - else: - index = "" - beggining = index - - #| - REPLACING PERIODS WITH "p" and NEGATIVE SIGNS WITH "n" - # if type(level["value"]) == type(1.23): - if isinstance(level["value"], float): - - # TODO - # NOTE - # Replace the line with the commented out line such that floats - # are rounded in their path representation - - # prop_value = str(round(level["value"], 4)).replace(".", "p") - prop_value = str(level["value"]).replace(".", "p") - - if "-" in str(level["value"]): - prop_value = prop_value.replace("-", "n") - - else: - prop_value = str(level["value"]) - #__| - - dir_name += beggining + prop_value + "/" - - if job_rev == "Auto": - - revision_dirs, highest_rev = self.__revision_list_and_max__( - self.var_lst_to_path(variable_lst), - ) - - dir_name += "_" + str(highest_rev) - - if relative_path is False: - dir_name = os.path.join( - self.root_dir, - self.working_dir, - dir_name, - ) - else: - dir_name = os.path.join( - self.working_dir, - dir_name, - ) - - return(dir_name) - #__| - - def var_lst_to_path(self, - variable_lst, - job_rev="False", - relative_path=True, - ): - """Construct path string from variable list. - - Args: - variable_lst: - Produced from DFT_Jobs_Setup.job_var_lst. - job_rev: - False: - Auto: - """ - #| - var_lst_to_path - if isinstance(variable_lst, str): - variable_lst = ast.literal_eval(variable_lst) - else: - pass - - level_cnt = 0 - dir_name = "data/" - for level in variable_lst: - level_cnt += 1 - tmp = self.tree_level_labels[level_cnt - 1] - index = self.level_entries[tmp].index(level["value"]) + 1 - if index < 10: index = "0" + str(index) - else: index = str(index) - - #| - REPLACING PERIODS WITH "p" and NEGATIVE SIGNS WITH "n" - # if type(level["value"]) == type(1.23): - if isinstance(level["value"], float): - prop_value = str(level["value"]).replace(".", "p") - - if "-" in str(level["value"]): - prop_value = prop_value.replace("-", "n") - - else: - prop_value = str(level["value"]) - #__| - - dir_name += index + self.sep + prop_value + "/" - - # Removing the trailing '/' character - dir_name = dir_name[:-1] - - if job_rev == "Auto": - - revision_dirs, highest_rev = self.__revision_list_and_max__( - self.var_lst_to_path( - variable_lst, - job_rev="False", - relative_path=False, - ), - ) - - # dir_name += "_" + str(highest_rev) - dir_name += "/_" + str(highest_rev) - - if relative_path is False: - dir_name = os.path.join( - self.root_dir, - self.working_dir, - dir_name, - ) - - return(dir_name) - #__| - - def extract_prop_from_var_lst(self, variable_lst, property): - """Extract the property from the variable list. - - Args: - variable_lst: - property: - """ - #| - extract_prop_from_var_lst - # result = {} - for i in variable_lst: - if i["property"] == property: - return i["value"] - #__| - - - #__| - - - #| - Job Variable Tree Methods - - def load_dir_struct(self): - """Attempt to load dir structure from file in root dir if none given. - - job_var_lst is constructed - level_entries_list is constructed - level_entries is constructed - order_dict is constructed - - """ - #| - load_dir_struct - if self.tree_level_labels is None and self.level_entries is None: - self.__load_dir_structure_file__() - - # self.__check_input__() # TEMP had to comment out because of switching - # to new format of input files - - #| - If tree_level_labels and level_entries couldn't be parsed - if self.tree_level_labels is None and self.level_entries is None: - return(None) - #__| - - # FIXME - # if not type(self.level_entries) == list: - # # self.level_entries_list = self.__level_entries_list__() - # level_entries_list = self.__level_entries_list__() - - if type(self.level_entries) == dict: - #| - OLD way - self.order_dict = self.__order_dict__( - self.tree_level_labels, - self.level_entries) - - self.job_var_lst = self.__job_variable_list__( - # self.level_entries_list, - level_entries_list, - self.order_dict) - #__| - - elif type(self.level_entries) == list: - #| - New Way of Inputing Structure Files - tmp = self.__create_level_entries_dict__( - self.tree_level_labels, - self.level_entries, - ) - self.level_entries = tmp - - - self.level_entries_list = self.__level_entries_list__() - - - self.order_dict = self.__order_dict__( - self.tree_level_labels, - self.level_entries) - - self.job_var_lst = self.__job_variable_list__( - # self.level_entries, - self.level_entries_list, - # level_entries_list, - self.order_dict, - ) - #__| - - #__| - - def __load_dir_structure_file__(self): - """Attempt o load dir_structure.json from file.""" - #| - __load_dir_structure_file__ - try: - try: - fle_name = self.root_dir + "/jobs_bin/dir_structure.json" - - with open(fle_name, "r") as dir_struct_f: - data = json.load(dir_struct_f) - - tree_level = data["tree_level_labels"] - level_entries = data["level_entries_dict"] - - if "skip_dirs" in data.keys(): - skip_dirs_lst = data["skip_dirs"] - self.skip_dirs_lst = skip_dirs_lst - - self.tree_level_labels = tree_level - self.level_entries = level_entries - self.level_entries_list = level_entries - - except: - print("Couldn't read /jobs_bin/dir_structure.json") - - try: - - #| - __old__ - tmp = 42 - # print("old - Reading dir_structure.json file \ - # from root_dir") - # - # fle_name = self.root_dir + "/dir_structure.json" - # with open(fle_name, "r") as dir_struct_f: - # data = json.load(dir_struct_f) - # tree_level = data["tree_level_labels"] - # level_entries = data["level_entries_dict"] - # - # if "skip_dirs" in data.keys(): - # skip_dirs_lst = data["skip_dirs"] - # self.skip_dirs_lst = skip_dirs_lst - # - # self.tree_level_labels = tree_level - # self.level_entries = level_entries - #__| - - except: - print("Couldn't read /dir_structure.json") - - pass - - except: - mess = "Error opening 'dir_structure.json' file" - raise IOError(mess) - - #__| - - def __create_level_entries_dict__(self, - tree_level_labels, - tree_level_values, - ): - """ - Create level_entries_dict from labels and values lists. - - Args: - tree_level_labels: - tree_level_values: - """ - #| - create_level_entries_dict - level_entries_dict = {} - for index, variable in enumerate(tree_level_labels): - level_entries_dict[variable] = tree_level_values[index] - - return(level_entries_dict) - #__| - - def __level_entries_list__(self): - """Construct level entries list. - - Construct level_entries_list from level_entries_dict and level_labels - """ - #| - __level_entries_list__ - level_entries_dict = self.level_entries - level_labels = self.tree_level_labels - - level_entries_list = [] - for param_i in level_labels: - # for name, params_list in level_entries_dict.iteritems(): - for name, params_list in level_entries_dict.items(): - if param_i == name: - level_entries_list.append(params_list) - - return(level_entries_list) - #__| - - def __order_dict__(self, tree_level_labels, level_entries): - """Order of properties to correspond to order of tree. - - Creates "order_dict", which contains the depth level for each - descriptor. Each job directory will have a unique descriptor list. - The "order_dict" variable is used to make sure that the ordering of the - descriptors in this list matches the "dir_tree_level" structure. - - Args: - tree_level_labels: - level_entries: - """ - #| - __order_dict__ - order_dict = {} # <-------------------------------------- - - level_cnt = 0 - for level in tree_level_labels: - level_cnt += 1 - for prop in level_entries[level]: - order_dict[prop] = level_cnt - 1 - - return order_dict - - #__| - - def __job_variable_list__(self, level_entries, order_dict): - """Return the job variable list. - - Args: - level_entries: - order_dict: - """ - #| - __job_variable_list__ - all_comb = itertools.product(*level_entries) - - job_dir_lst = [] - for job_dir in all_comb: - final_lst_2 = [] - param_names = self.tree_level_labels - - for ind, prop in enumerate(job_dir): - new_entry = {} - new_entry["property"] = param_names[ind] - new_entry["value"] = job_dir[ind] - final_lst_2.append(new_entry) - - job_dir_lst.append(final_lst_2) - - if self.skip_dirs_lst is not None: - for skip in self.skip_dirs_lst: - job_dir_lst.remove(skip) - - return(job_dir_lst) - #__| - - #__| - - - #| - Create Directory Tree - - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - # NEW - def create_dir_struct(self, create_first_rev_folder="True"): - """Create directory structure according to job variable list & dict. - - Development Notes: - This should really be looping over the jobs_list I think - - Args: - create_first_rev_folder: - """ - #| - create_dir_struct - for Job_i in self.Job_list: - - #| - FOR LOOP BODY - # if create_first_rev_folder == "True": - # path = os.path.join(Job_i.full_path, "_1") - # elif create_first_rev_folder == "False": - # path = Job_i.full_path - - path = Job_i.full_path - - if os.path.exists(path): - # mess = "Path already exists: " + str(path) - # print(mess) - pass - - elif not os.path.exists(path): - os.makedirs(path) - #__| - - #| - folders_exist attribute should be True from now on - # file_name = self.root_dir + "/jobs_bin/.folders_exist" - file_name = os.path.join( - self.root_dir, - self.working_dir, - "jobs_bin/.folders_exist" - ) - - with open(file_name, "w") as fle: - fle.write("\n") - - self.folders_exist = self.__folders_exist__(True) - #__| - - #__| - - def old_create_dir_struct(self, create_first_rev_folder="True"): - """Create directory structure according to job variable list & dict. - - Development Notes: - This should really be looping over the jobs_list I think - - Args: - create_first_rev_folder: - """ - #| - create_dir_struct - for job in self.job_var_lst: - if create_first_rev_folder == "True": - path = self.var_lst_to_path(job) + "_1" - elif create_first_rev_folder == "False": - path = self.var_lst_to_path(job) - - path = self.root_dir + "/" + path - - if os.path.exists(path): - mess = "Path already exists: " + str(path) - print(mess) - - elif not os.path.exists(path): - os.makedirs(path) - - #| - Creating Variable Text Files Through Directoy Structure - for job in self.job_var_lst: - path = self.var_lst_to_path(job) - path = self.root_dir + "/" + path - - file_name = path + "job_dir_level" - with open(file_name, "w") as fle: - fle.write("\n") - - for root, dirs, files in os.walk(self.root_dir + "/data/"): - if "job_dir_level" in files: - continue - - else: - prop_lst = [] - for folder in dirs: - tmp = self.sep.join(folder.split(self.sep)[1:]) - - prop = self.__replace_p_for_per__(tmp) - prop = self.__replace_negative_for_n__(prop) - prop_lst.append(prop) - - for key, value in self.level_entries.items(): - if set(prop_lst) == set(map(str, value)): - - file_name = root + "/properties.txt" - with open(file_name, "w") as fle: - fle.write(key + "\n") - - # f = open(root + "/properties.txt", "w") - # f.write(key + "\n") - # f.close() - #__| - - # self.__create_dir_structure_file__() - - #| - folders_exist attribute should be True from now on - file_name = self.root_dir + "/jobs_bin/.folders_exist" - with open(file_name, "w") as fle: - fle.write("\n") - - self.folders_exist = self.__folders_exist__(True) - #__| - - #__| - - - - - - - - - - - - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - - - - - - - def check_inputs(self): - """ - """ - #| - check_inputs - if self.tree_level_labels is not None: - assert isinstance(self.tree_level_labels[0], np.ndarray) is False, \ - "Please don't use numpy array types, can't be json serialized" - - if self.level_entries_list is not None: - assert isinstance(self.level_entries_list[0], np.ndarray) is False, \ - "Please don't use numpy array types, can't be json serialized" - #__| - - def __create_dir_structure_file__(self): - """ - Create directory structure file. - - Creates dir structure file from which the parameter list & dict can be - loaded from. - """ - #| - __create_dir_structure_file__ - - dir_structure_data = {} - dir_structure_data["tree_level_labels"] = self.tree_level_labels - dir_structure_data["level_entries_dict"] = self.level_entries_list - # TEMP - dir_structure_data["skip_dirs"] = self.skip_dirs_lst - - fle_name = os.path.join( - self.root_dir, - self.working_dir, - "jobs_bin/dir_structure.json", - ) - - with open(fle_name, "w") as fle: - json.dump(dir_structure_data, fle, indent=2) - #__| - - def __replace_p_for_per__(self, text): - """Replace p in variable with "." character. - - TODO Fails if last letter is a "p" - - Variables with "." character had them previously replaced with a "p" - character to avoid periods in a folder name. - """ - #| - __replace_p_for_per__ - lst = [pos for pos, char in enumerate(text) if char == "p"] - - # Replaces character at lett with a period if both the previous - # and next character are numeric - for lett in lst: - - # COMBAK - # Skip entries which have p at end of text - # Ignores possibility of variables like the following: - # 2. --> 2p (will not go back to 2.) - if lett == len(text) - 1: - continue - - cond_1 = text[lett - 1].isdigit() - cond_2 = text[lett + 1].isdigit() - if cond_1 is True and cond_2 is True: - text = text[:lett] + "." + text[lett + 1:] - - return(text) - #__| - - def __replace_negative_for_n__(self, text): - """Replace variable quantities that are negative with an "n". - - Args: - text: - """ - #| - __replace_negative_for_n__ - lst = [pos for pos, char in enumerate(text) if char == "n"] - - for lett in lst: - if text[lett + 1].isdigit() is True: - text = text[:lett] + "-" + text[lett + 1:] - - return(text) - #__| - - #__| - - - #| - Job Attributes - - def __load_jobs_attributes__(self): - """Load jobs attributes data from file.""" - #| - __load_jobs_attributes__ - job_att_file = self.root_dir + "/jobs_bin/job_attributes.csv" - - if os.path.exists(job_att_file): - with open(job_att_file, "rb") as fle: - jobs_att = pickle.load(fle) - - else: - jobs_att = {} - - return(jobs_att) - #__| - - def append_jobs_attributes(self, attribute): - """ - Append to jobs attributes file. - - Append dictionary key value pair to the jobs_attributes dict. - To be pickled and saved - """ - #| - append_jobs_attributes - att_new = attribute - - self.jobs_att.update(att_new) - - job_att_file = self.root_dir + "/jobs_bin/job_attributes.csv" - pickle.dump(self.jobs_att, open(job_att_file, "wb")) - #__| - - #__| - - def __gen_datatable__(self): - """Initialze data table from the properties of the jobs directory. - - New methods iterates through Job instances - """ - #| - __generate_data_table - rows_list = [] - for Job_i in self.Job_list: - #| - FOR LOOP BODY - entry_param_dict = {} - for prop, value in Job_i.job_params.items(): - entry_param_dict[prop] = value - - entry_param_dict["Job"] = Job_i - entry_param_dict["path"] = Job_i.full_path - entry_param_dict["max_revision"] = Job_i.max_revision - entry_param_dict["revision_number"] = Job_i.revision_number - - rows_list.append(entry_param_dict) - #__| - - data_frame = pd.DataFrame(rows_list) - - return(data_frame) - #__| - - def __revision_list_and_max__(self, path_i): - """Return list of revisions for given job path and highest revision. - - If there are no revision folders or the directory structure hasn't been - created yet the following dummy values will be returned: - ( - ["_1"], - 1, - ) - - Args: - path_i: - """ - #| - __revision_list_and_max__ - if self.folders_exist: - - # dirs = os.listdir(os.path.join(self.working_dir, path_i)) - dirs = os.listdir(path_i) - - revision_dirs = [dir for dir in dirs if dir[0] == "_" and - dir[-1].isdigit() and " " not in dir] - - # dir[1].isdigit() and " " not in dir] - - revision_dirs.sort() - - if len(revision_dirs) == 0: - highest_rev = None - else: - highest_rev = max( - [int(i.split("_")[-1]) for i in revision_dirs], - ) - - return(revision_dirs, highest_rev) - else: - dummy_return = ( - ["_1"], - 1, - ) - - return(dummy_return) - #__| - - def copy_files_jd(self, file_list, variable_lst, revision="Auto"): - """ - Copy files to job directory. - - Args: - file_list: - variable_lst: - revision: - """ - #| - copy_files_jd - path = self.var_lst_to_path(variable_lst) - path += "_" + str(self.job_revision_number(variable_lst)) - - for file in file_list: - shutil.copyfile(self.root_dir + "/" + file, path + "/" + file) - #__| - - - #__| ********************************************************************** - - - - #| - __old__ - # DEPR - def __generate_data_table__(self): - """Initialze data table from the properties of the jobs directory. - - Appends unique row for every job revision - """ - #| - __generate_data_table__ - rows_list = [] - for job in self.job_var_lst: - revisions = self.job_revision_number(job) - for revision in range(revisions + 1)[1:]: - #| - FOR LOOP BODY - entry_param_dict = {} - for prop in job: - entry_param_dict[prop["property"]] = prop["value"] - - entry_param_dict["variable_list"] = job - entry_param_dict["path"] = self.var_lst_to_path(job) - - entry_param_dict["max_revision"] = revisions - entry_param_dict["revision_number"] = revision - - rows_list.append(entry_param_dict) - #__| - - data_frame = pd.DataFrame(rows_list) - - return(data_frame) - #__| - - # DEPR - def job_revision_number_old(self, variable_lst): - """ - Return the largest revision number for the given variable_lst -> job. - - If there are no revision folders or the directory structure hasn't been - created yet 1 will be returned. - - Args: - variable_lst: - """ - #| - job_revision_number - if self.folders_exist: - path = self.var_lst_to_path(variable_lst) - orig_dir = os.getcwd() - os.chdir(self.root_dir + "/" + path) - - dirs = filter(os.path.isdir, os.listdir(os.getcwd())) - - - # COMBAK Does this line break work? - num_jobs = len([dir for dir in dirs if dir[0] == "_" and - dir[1].isdigit() and " " not in dir]) - os.chdir(orig_dir) - - return(num_jobs) - else: - return(1) - - #| - __old__ - # path = self.var_lst_to_path(variable_lst) - # - # path = "/".join(path.split("/")[0:-1]) + "/" - # # Attempting to remove duplicate job folders (usually have spaces) - # dir_list = [x for x in os.walk(path).next()[1] if " " not in x] - # - # return(len(dir_list)) - # - #__| - - #__| - - - #__| +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Job automation class. + +Author: Raul A. Flores +""" + +#| - Import Modules +import os +import shutil +import copy + +import itertools +import pickle +import json + +import numpy as np +import pandas as pd + +import ast + +# My Modules +from dft_job_automat.compute_env import ComputerCluster +#__| + + +class Job: + """Encapsulates data and method related to single jobs. + + Still a work in progress + """ + + #| - Job ****************************************************************** + def __init__(self, + path_i=None, + job_params_dict=None, + max_revision=None, + + root_dir=None, + ): + """COMBAK Flesh this out later. + + Args: + path_i: + Path to job folder + job_params_dict: + Job parameter dictionary + max_revision: + Max revisions for unique job, defined by the set of job params + """ + #| - __init__ + + #| - Setting class attributes + self.full_path = path_i + self.job_params_dict = job_params_dict + self.max_revision = max_revision + self.root_dir = root_dir + #__| + + # if job_params_dict is None: + + self.job_params = self.__set_job_parameters__(job_params_dict) + + # print(self.job_params) + # print("____-d-sfs") + # print("") + + # else: + # self.__write_job_parameters__() + + self.revision_number = self.__revision_number__() + #__| + + def write_job_parameters(self): + """ + """ + #| - __write_job_parameters__ + leaf_dir = self.full_path.split("/")[-1] + + if "_" in leaf_dir: + # if leaf_dir[1:].isnumeric(): + if leaf_dir[1:].isdigit(): + leaf_dir = self.full_path.split("/")[-1] + ind_i = self.full_path.rfind(leaf_dir) + path_i = self.full_path[:ind_i - 1] + + + #| - NEW | Trying to remove keys which aren't JSON serializable + def is_jsonable(x): + """ + """ + #| - is_jsonable + try: + json.dumps(x) + return True + except: + return False + #__| + + job_params_dict_cpy = copy.deepcopy(self.job_params_dict) + + keys_to_delete = [] + for key, value in job_params_dict_cpy.items(): + if not is_jsonable(value): + keys_to_delete.append(key) + + if len(keys_to_delete) > 0: + print( + "The following job properties couldn't be JSON serialized", + ", and will be ignored" + ) + print(keys_to_delete) + + for k in keys_to_delete: + job_params_dict_cpy.pop(k, None) + + print(job_params_dict_cpy) + #__| + + + file_path_i = os.path.join(path_i, "job_params.json") + with open(file_path_i, 'w') as outfile: + json.dump( + job_params_dict_cpy, + # self.job_params_dict, + outfile, + indent=2, + ) + #__| + + def __set_job_parameters__(self, job_params_dict): + """ + + Args: + job_params_dict: + """ + #| - __set_job_parameters__ + job_params_from_file = self.__read_job_params_file__() + + if job_params_dict is not None: + # job_params_dict.update(job_params_from_file) + job_params_from_file.update(job_params_dict) + + return(job_params_from_file) + #__| + + def __read_job_params_file__(self): + """Read "job_parameters.json" file from job direcory. + + Development Notes: + Search in the job root dir (one level up from "_" dirs) + + Args: + """ + #| - __read_job_params_file__ + job_params = {} + + # file_path = self.full_path + "/" + "job_parameters.json" + + file_exists = False + + file_path = os.path.join( + self.full_path, + "job_parameters.json") + if os.path.exists(file_path): + file_exists = True + with open(file_path, "r") as fle: + job_params = json.load(fle) + + + ind_i = self.full_path.rfind(self.full_path.split("/")[-1]) + path_i_rt = self.full_path[:ind_i - 1] + + file_path = os.path.join( + # self.full_path[0:-2], + path_i_rt, + "job_parameters.json", + ) + if os.path.exists(file_path): + file_exists = True + with open(file_path, "r") as fle: + job_params = json.load(fle) + + + file_path = os.path.join( + # self.full_path[0:-2], + path_i_rt, + "job_params.json", + ) + if os.path.exists(file_path): + file_exists = True + with open(file_path, "r") as fle: + job_params = json.load(fle) + + if not file_exists: + print("No job_params file found for following job:") + print(self.full_path) + + return(job_params) + #__| + + def __revision_number__(self): + """ + """ + #| - __revision_number__ + # print(self.full_path) + revision_i = int(self.full_path.split("/")[-1].split("_")[-1]) + + return(revision_i) + #__| + + #__| ********************************************************************** + + +class DFT_Jobs_Setup: + """Useful class to set up multiple DFT job in a directory structure. + + Must be initialized with tree_level and level_entries inputs (Not really) + """ + + #| - DFT_Jobs_Setup ******************************************************* + + def __init__(self, + tree_level=None, + level_entries=None, + indiv_dir_lst=None, + indiv_job_lst=None, + indiv_job_dict_lst=None, + skip_dirs_lst=None, + root_dir=".", + working_dir=".", + folders_exist=None, + parse_all_revisions=True, + ): + """Initialize DFT_Jobs_Setup Instance. + + Args: + tree_level: + level_entries: + indiv_dir_lst: + indiv_job_lst: + List of dictionaries representing jobs + skip_dirs_lst: + working_dir: + folders_exist: + """ + #| - __init__ + + #| - Initializing Some Class Attributes + self.order_dict = None + self.job_var_lst = None + self.Job_list = [] + self.sep = "-" + self.level_entries = level_entries + self.tree_level_labels = tree_level + self.level_entries_list = level_entries + self.skip_dirs_lst = skip_dirs_lst + self.indiv_dir_lst = indiv_dir_lst + self.indiv_job_lst = indiv_job_lst + + self.indiv_job_dict_lst = indiv_job_dict_lst + self.parse_all_revisions = parse_all_revisions + #__| + + self.root_dir = self.__set_root_dir__(root_dir) + + self.working_dir = self.__set_working_dir__(working_dir) + + self.cluster = ComputerCluster() + self.jobs_att = self.__load_jobs_attributes__() + self.__create_jobs_bin__() + self.folders_exist = self.__folders_exist__(folders_exist) + + self.load_dir_struct() + self.__create_dir_structure_file__() + self.num_jobs = self.__number_of_jobs__() + self.__Job_list__() + + self.data_frame = self.__gen_datatable__() + + # if self.folders_exist: + # # self.data_frame = self.__generate_data_table__() + + self.check_inputs() + #__| + + def __job_i_param_dict_to_job_var_lst__(self, params_dict): + """Constructs a job_variable list from a dictionary of parameters. + + Args: + params_dict: + """ + #| - __job_i_param_dict_to_job_var_lst__ + assert self.tree_level_labels is not None + + job_var_lst_i = [] + for level_prop in self.tree_level_labels: + level_var_dict = {} + for key_i, value_i in params_dict.items(): + if key_i == level_prop: + level_var_dict["property"] = key_i + level_var_dict["value"] = value_i + + job_var_lst_i.append(level_var_dict) + break + + return(job_var_lst_i) + #__| + + + def write_job_params_json_file(self): + """ + """ + #| - write_job_params_json_file + for Job in self.Job_list: + Job.write_job_parameters() + + #__| + + def create_Jobs_from_dicts_and_paths(self, + jobs_list, + ): + """Populate Job_list attribute manually. + + Args: + jobs_list + List of dictionaries with 'properties' and 'path' keys + + """ + #| - create_Jobs_from_dicts_and_paths + for job_i in jobs_list: + + path_i = job_i["path"] + job_params_dict = job_i["properties"] + + rev_dirs, max_rev = self.__revision_list_and_max__( + path_i, + ) + + for rev_i in rev_dirs: + path_i = os.path.join(path_i, rev_i) + path_i = os.path.normpath(path_i) + + Job_i = Job( + path_i=path_i, + job_params_dict=job_params_dict, + max_revision=max_rev, + root_dir=None, + ) + + self.Job_list.append(Job_i) + #__| + + def __Job_list__(self): + """Create Job list from various input sources.""" + #| - __Job_list__ + + #| - Adding Jobs From Individual Directory List + if self.indiv_dir_lst is not None: + for job_i_dir in self.indiv_dir_lst: + + rev_dirs, max_rev = self.__revision_list_and_max__(job_i_dir) + + print(job_i_dir) + if rev_dirs: + if self.parse_all_revisions is False: + rev_dirs = [rev_dirs[-1]] + + for rev_i in rev_dirs: + path_i = os.path.join(job_i_dir, rev_i) + path_i = os.path.normpath(path_i) + + Job_i = Job( + path_i=path_i, + job_params_dict=None, + max_revision=max_rev, + root_dir=None, + ) + + self.Job_list.append(Job_i) + else: + print("Didn't find any job dirs here:") + print(job_i_dir) + pass + #__| + + #| - Adding Jobs From Enumerated Job Properties Tree + if self.job_var_lst is not None: + for job_i in self.job_var_lst: + job_var_dict = self.__job_i_vars_to_dict__(job_i) + + if self.folders_exist: + path_i = self.var_lst_to_path( + job_i, + job_rev="Auto", + relative_path=False, + ) + + #| - __old__ + # else: + # print("else *s8fs*sdf") + # path_i = os.path.join( + # + # self.var_lst_to_path( + # job_i, + # job_rev="Auto", + # relative_path=False, + # ), + # + # # self.var_lst_to_path( + # # job_i, + # # ), + # + # "_1", + # ) + #__| + + rev_dirs, max_rev = self.__revision_list_and_max__( + # path_i + self.var_lst_to_path( + job_i, + job_rev="None", + relative_path=False, + ) + ) + + Job_i = Job( + path_i=path_i, + job_params_dict=job_var_dict, + max_revision=max_rev, + root_dir=self.root_dir, + ) + + self.Job_list.append(Job_i) + #__| + + #| - TEMP | I don't remember why this is here + indiv_job = self.indiv_job_lst is not None + level_labels = self.tree_level_labels is not None + if indiv_job and level_labels: + print("LSKDJFKLDS_-09sdfsdfs9dfas") + for job_params_i in self.indiv_job_lst: + + job_var_lst_i = self.__job_i_param_dict_to_job_var_lst__( + job_params_i, + ) + + path_i = os.path.join( + self.new_var_lst_to_path(job_var_lst_i), + "_1", + ) + + Job_i = Job( + path_i=path_i, + job_params_dict=job_params_i, + max_revision=None, + root_dir=self.root_dir, + ) + + self.Job_list.append(Job_i) + #__| + + if self.indiv_job_dict_lst is not None: + self.create_Jobs_from_dicts_and_paths( + self.indiv_job_dict_lst, + ) + #__| + + + #| - Misc Methods + + def __job_i_vars_to_dict__(self, job_i_vars): + """ + + Args: + job_i_vars: + """ + #| - __job_i_vars_to_dict__ + job_vars_dict = {} + for prop in job_i_vars: + prop_key = prop["property"] + prop_value = prop["value"] + + job_vars_dict[prop_key] = prop_value + + return(job_vars_dict) + #__| + + def __create_jobs_bin__(self): + """Create /jobs_bin folder if it doesn't exist.""" + #| - __create_jobs_bin__ + folder_dir = os.path.join(self.root_dir, self.working_dir, "jobs_bin") + # folder_dir = self.root_dir + "/jobs_bin" + + if not os.path.exists(folder_dir): + # print("KDJFDI__") + # print(folder_dir) + os.makedirs(folder_dir) + #__| + + def __folders_exist__(self, folders_exist): + """Check whether directory structure exists. + + The alternative is to be creating an instance from a location where + the original job files don't exist but the job dataframe does + """ + #| - __folders_exist__ + # User override + if folders_exist is not None: + return(folders_exist) + + folders_exist = False + + #| - Folders Exist Criteria + crit_0 = False + if os.path.isfile(self.root_dir + "/jobs_bin/.folders_exist"): + crit_0 = True + + crit_1 = False + if os.path.isdir(self.root_dir + "/data"): + crit_1 = True + #__| + + #| - Deciding whether folders exist or not + if crit_0 is True: + pass + if crit_1 is True: + folders_exist = True + else: + folders_exist = False + else: + folders_exist = False + #__| + + return(folders_exist) + #__| + + def __set_root_dir__(self, root_dir_in): + """Returns root directory.""" + #| - __set_root_dir__ + if root_dir_in == ".": + root_dir = os.getcwd() + else: + root_dir = root_dir_in + + return(root_dir) + #__| + + def __set_working_dir__(self, working_dir_in): + """ + """ + #| - __set_working_dir__ + if working_dir_in == ".": + working_dir = "" + else: + working_dir = working_dir_in + + return(working_dir) + #__| + + + def __check_input__(self): + """Check that tree_level and level_entries are of matching length.""" + #| - __check_input__ + tmp = set(self.tree_level_labels) + input_diff = tmp.symmetric_difference(self.level_entries.keys()) + if not input_diff == set(): + undefined_labels = [] + for i in input_diff: + undefined_labels.append(i) + + print("\n") + message = "Did not fill out level entries dict properly" + "\n" + message += "The following properties need to be defined" + "\n" + message += str(undefined_labels) + raise ValueError(message) + #__| + + + def __number_of_jobs__(self): + """Count number of jobs in instance. + + # TODO Should count jobs in job_var_lst and the indiv_dir jobs + # TODO Make distinction between total jobs (including number of + revisions) and just the before revision number + + Depends on number of unique variable list and number of revisions for + each job. + """ + #| - __number_of_jobs__ + num_jobs = 0 + + # Regular jobs + if self.job_var_lst is not None: + num_jobs = len(self.job_var_lst) + + # Individual dir jobs + if self.indiv_dir_lst is not None: + num_jobs += len(self.indiv_dir_lst) + + + return(num_jobs) + #__| + + + def new_var_lst_to_path(self, + variable_lst, + job_rev="False", + relative_path=True, + ): + """ + """ + #| - new_var_lst_to_path + if isinstance(variable_lst, str): + variable_lst = ast.literal_eval(variable_lst) + else: + pass + + level_cnt = 0 + dir_name = "data/" + for level in variable_lst: + level_cnt += 1 + + if self.level_entries is not None: + tmp = self.tree_level_labels[level_cnt - 1] + index = self.level_entries[tmp].index(level["value"]) + 1 + if index < 10: + index = "0" + str(index) + else: + index = str(index) + + beggining = index + self.sep + + else: + index = "" + beggining = index + + #| - REPLACING PERIODS WITH "p" and NEGATIVE SIGNS WITH "n" + # if type(level["value"]) == type(1.23): + if isinstance(level["value"], float): + + # TODO + # NOTE + # Replace the line with the commented out line such that floats + # are rounded in their path representation + + # prop_value = str(round(level["value"], 4)).replace(".", "p") + prop_value = str(level["value"]).replace(".", "p") + + if "-" in str(level["value"]): + prop_value = prop_value.replace("-", "n") + + else: + prop_value = str(level["value"]) + #__| + + dir_name += beggining + prop_value + "/" + + if job_rev == "Auto": + + revision_dirs, highest_rev = self.__revision_list_and_max__( + self.var_lst_to_path(variable_lst), + ) + + dir_name += "_" + str(highest_rev) + + if relative_path is False: + dir_name = os.path.join( + self.root_dir, + self.working_dir, + dir_name, + ) + else: + dir_name = os.path.join( + self.working_dir, + dir_name, + ) + + return(dir_name) + #__| + + def var_lst_to_path(self, + variable_lst, + job_rev="False", + relative_path=True, + ): + """Construct path string from variable list. + + Args: + variable_lst: + Produced from DFT_Jobs_Setup.job_var_lst. + job_rev: + False: + Auto: + """ + #| - var_lst_to_path + if isinstance(variable_lst, str): + variable_lst = ast.literal_eval(variable_lst) + else: + pass + + level_cnt = 0 + dir_name = "data/" + for level in variable_lst: + level_cnt += 1 + tmp = self.tree_level_labels[level_cnt - 1] + index = self.level_entries[tmp].index(level["value"]) + 1 + if index < 10: index = "0" + str(index) + else: index = str(index) + + #| - REPLACING PERIODS WITH "p" and NEGATIVE SIGNS WITH "n" + # if type(level["value"]) == type(1.23): + if isinstance(level["value"], float): + prop_value = str(level["value"]).replace(".", "p") + + if "-" in str(level["value"]): + prop_value = prop_value.replace("-", "n") + + else: + prop_value = str(level["value"]) + #__| + + dir_name += index + self.sep + prop_value + "/" + + # Removing the trailing '/' character + dir_name = dir_name[:-1] + + if job_rev == "Auto": + + revision_dirs, highest_rev = self.__revision_list_and_max__( + self.var_lst_to_path( + variable_lst, + job_rev="False", + relative_path=False, + ), + ) + + # dir_name += "_" + str(highest_rev) + dir_name += "/_" + str(highest_rev) + + if relative_path is False: + dir_name = os.path.join( + self.root_dir, + self.working_dir, + dir_name, + ) + + return(dir_name) + #__| + + def extract_prop_from_var_lst(self, variable_lst, property): + """Extract the property from the variable list. + + Args: + variable_lst: + property: + """ + #| - extract_prop_from_var_lst + # result = {} + for i in variable_lst: + if i["property"] == property: + return i["value"] + #__| + + + #__| + + + #| - Job Variable Tree Methods + + def load_dir_struct(self): + """Attempt to load dir structure from file in root dir if none given. + + job_var_lst is constructed + level_entries_list is constructed + level_entries is constructed + order_dict is constructed + + """ + #| - load_dir_struct + if self.tree_level_labels is None and self.level_entries is None: + self.__load_dir_structure_file__() + + # self.__check_input__() # TEMP had to comment out because of switching + # to new format of input files + + #| - If tree_level_labels and level_entries couldn't be parsed + if self.tree_level_labels is None and self.level_entries is None: + return(None) + #__| + + # FIXME + # if not type(self.level_entries) == list: + # # self.level_entries_list = self.__level_entries_list__() + # level_entries_list = self.__level_entries_list__() + + if type(self.level_entries) == dict: + #| - OLD way + self.order_dict = self.__order_dict__( + self.tree_level_labels, + self.level_entries) + + self.job_var_lst = self.__job_variable_list__( + # self.level_entries_list, + level_entries_list, + self.order_dict) + #__| + + elif type(self.level_entries) == list: + #| - New Way of Inputing Structure Files + tmp = self.__create_level_entries_dict__( + self.tree_level_labels, + self.level_entries, + ) + self.level_entries = tmp + + + self.level_entries_list = self.__level_entries_list__() + + + self.order_dict = self.__order_dict__( + self.tree_level_labels, + self.level_entries) + + self.job_var_lst = self.__job_variable_list__( + # self.level_entries, + self.level_entries_list, + # level_entries_list, + self.order_dict, + ) + #__| + + #__| + + def __load_dir_structure_file__(self): + """Attempt o load dir_structure.json from file.""" + #| - __load_dir_structure_file__ + try: + try: + fle_name = self.root_dir + "/jobs_bin/dir_structure.json" + + with open(fle_name, "r") as dir_struct_f: + data = json.load(dir_struct_f) + + tree_level = data["tree_level_labels"] + level_entries = data["level_entries_dict"] + + if "skip_dirs" in data.keys(): + skip_dirs_lst = data["skip_dirs"] + self.skip_dirs_lst = skip_dirs_lst + + self.tree_level_labels = tree_level + self.level_entries = level_entries + self.level_entries_list = level_entries + + except: + print("Couldn't read /jobs_bin/dir_structure.json") + + try: + + #| - __old__ + tmp = 42 + # print("old - Reading dir_structure.json file \ + # from root_dir") + # + # fle_name = self.root_dir + "/dir_structure.json" + # with open(fle_name, "r") as dir_struct_f: + # data = json.load(dir_struct_f) + # tree_level = data["tree_level_labels"] + # level_entries = data["level_entries_dict"] + # + # if "skip_dirs" in data.keys(): + # skip_dirs_lst = data["skip_dirs"] + # self.skip_dirs_lst = skip_dirs_lst + # + # self.tree_level_labels = tree_level + # self.level_entries = level_entries + #__| + + except: + print("Couldn't read /dir_structure.json") + + pass + + except: + mess = "Error opening 'dir_structure.json' file" + raise IOError(mess) + + #__| + + def __create_level_entries_dict__(self, + tree_level_labels, + tree_level_values, + ): + """ + Create level_entries_dict from labels and values lists. + + Args: + tree_level_labels: + tree_level_values: + """ + #| - create_level_entries_dict + level_entries_dict = {} + for index, variable in enumerate(tree_level_labels): + level_entries_dict[variable] = tree_level_values[index] + + return(level_entries_dict) + #__| + + def __level_entries_list__(self): + """Construct level entries list. + + Construct level_entries_list from level_entries_dict and level_labels + """ + #| - __level_entries_list__ + level_entries_dict = self.level_entries + level_labels = self.tree_level_labels + + level_entries_list = [] + for param_i in level_labels: + # for name, params_list in level_entries_dict.iteritems(): + for name, params_list in level_entries_dict.items(): + if param_i == name: + level_entries_list.append(params_list) + + return(level_entries_list) + #__| + + def __order_dict__(self, tree_level_labels, level_entries): + """Order of properties to correspond to order of tree. + + Creates "order_dict", which contains the depth level for each + descriptor. Each job directory will have a unique descriptor list. + The "order_dict" variable is used to make sure that the ordering of the + descriptors in this list matches the "dir_tree_level" structure. + + Args: + tree_level_labels: + level_entries: + """ + #| - __order_dict__ + order_dict = {} # <-------------------------------------- + + level_cnt = 0 + for level in tree_level_labels: + level_cnt += 1 + for prop in level_entries[level]: + order_dict[prop] = level_cnt - 1 + + return order_dict + + #__| + + def __job_variable_list__(self, level_entries, order_dict): + """Return the job variable list. + + Args: + level_entries: + order_dict: + """ + #| - __job_variable_list__ + all_comb = itertools.product(*level_entries) + + job_dir_lst = [] + for job_dir in all_comb: + final_lst_2 = [] + param_names = self.tree_level_labels + + for ind, prop in enumerate(job_dir): + new_entry = {} + new_entry["property"] = param_names[ind] + new_entry["value"] = job_dir[ind] + final_lst_2.append(new_entry) + + job_dir_lst.append(final_lst_2) + + if self.skip_dirs_lst is not None: + for skip in self.skip_dirs_lst: + job_dir_lst.remove(skip) + + return(job_dir_lst) + #__| + + #__| + + + #| - Create Directory Tree + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + # NEW + def create_dir_struct(self, create_first_rev_folder="True"): + """Create directory structure according to job variable list & dict. + + Development Notes: + This should really be looping over the jobs_list I think + + Args: + create_first_rev_folder: + """ + #| - create_dir_struct + for Job_i in self.Job_list: + + #| - FOR LOOP BODY + # if create_first_rev_folder == "True": + # path = os.path.join(Job_i.full_path, "_1") + # elif create_first_rev_folder == "False": + # path = Job_i.full_path + + path = Job_i.full_path + + if os.path.exists(path): + # mess = "Path already exists: " + str(path) + # print(mess) + pass + + elif not os.path.exists(path): + os.makedirs(path) + #__| + + #| - folders_exist attribute should be True from now on + # file_name = self.root_dir + "/jobs_bin/.folders_exist" + file_name = os.path.join( + self.root_dir, + self.working_dir, + "jobs_bin/.folders_exist" + ) + + with open(file_name, "w") as fle: + fle.write("\n") + + self.folders_exist = self.__folders_exist__(True) + #__| + + #__| + + def old_create_dir_struct(self, create_first_rev_folder="True"): + """Create directory structure according to job variable list & dict. + + Development Notes: + This should really be looping over the jobs_list I think + + Args: + create_first_rev_folder: + """ + #| - create_dir_struct + for job in self.job_var_lst: + if create_first_rev_folder == "True": + path = self.var_lst_to_path(job) + "_1" + elif create_first_rev_folder == "False": + path = self.var_lst_to_path(job) + + path = self.root_dir + "/" + path + + if os.path.exists(path): + mess = "Path already exists: " + str(path) + print(mess) + + elif not os.path.exists(path): + os.makedirs(path) + + #| - Creating Variable Text Files Through Directoy Structure + for job in self.job_var_lst: + path = self.var_lst_to_path(job) + path = self.root_dir + "/" + path + + file_name = path + "job_dir_level" + with open(file_name, "w") as fle: + fle.write("\n") + + for root, dirs, files in os.walk(self.root_dir + "/data/"): + if "job_dir_level" in files: + continue + + else: + prop_lst = [] + for folder in dirs: + tmp = self.sep.join(folder.split(self.sep)[1:]) + + prop = self.__replace_p_for_per__(tmp) + prop = self.__replace_negative_for_n__(prop) + prop_lst.append(prop) + + for key, value in self.level_entries.items(): + if set(prop_lst) == set(map(str, value)): + + file_name = root + "/properties.txt" + with open(file_name, "w") as fle: + fle.write(key + "\n") + + # f = open(root + "/properties.txt", "w") + # f.write(key + "\n") + # f.close() + #__| + + # self.__create_dir_structure_file__() + + #| - folders_exist attribute should be True from now on + file_name = self.root_dir + "/jobs_bin/.folders_exist" + with open(file_name, "w") as fle: + fle.write("\n") + + self.folders_exist = self.__folders_exist__(True) + #__| + + #__| + + + + + + + + + + + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + + + + + + + def check_inputs(self): + """ + """ + #| - check_inputs + if self.tree_level_labels is not None: + assert isinstance(self.tree_level_labels[0], np.ndarray) is False, \ + "Please don't use numpy array types, can't be json serialized" + + if self.level_entries_list is not None: + assert isinstance(self.level_entries_list[0], np.ndarray) is False, \ + "Please don't use numpy array types, can't be json serialized" + #__| + + def __create_dir_structure_file__(self): + """ + Create directory structure file. + + Creates dir structure file from which the parameter list & dict can be + loaded from. + """ + #| - __create_dir_structure_file__ + + dir_structure_data = {} + dir_structure_data["tree_level_labels"] = self.tree_level_labels + dir_structure_data["level_entries_dict"] = self.level_entries_list + # TEMP + dir_structure_data["skip_dirs"] = self.skip_dirs_lst + + fle_name = os.path.join( + self.root_dir, + self.working_dir, + "jobs_bin/dir_structure.json", + ) + + with open(fle_name, "w") as fle: + json.dump(dir_structure_data, fle, indent=2) + #__| + + def __replace_p_for_per__(self, text): + """Replace p in variable with "." character. + + TODO Fails if last letter is a "p" + + Variables with "." character had them previously replaced with a "p" + character to avoid periods in a folder name. + """ + #| - __replace_p_for_per__ + lst = [pos for pos, char in enumerate(text) if char == "p"] + + # Replaces character at lett with a period if both the previous + # and next character are numeric + for lett in lst: + + # COMBAK + # Skip entries which have p at end of text + # Ignores possibility of variables like the following: + # 2. --> 2p (will not go back to 2.) + if lett == len(text) - 1: + continue + + cond_1 = text[lett - 1].isdigit() + cond_2 = text[lett + 1].isdigit() + if cond_1 is True and cond_2 is True: + text = text[:lett] + "." + text[lett + 1:] + + return(text) + #__| + + def __replace_negative_for_n__(self, text): + """Replace variable quantities that are negative with an "n". + + Args: + text: + """ + #| - __replace_negative_for_n__ + lst = [pos for pos, char in enumerate(text) if char == "n"] + + for lett in lst: + if text[lett + 1].isdigit() is True: + text = text[:lett] + "-" + text[lett + 1:] + + return(text) + #__| + + #__| + + + #| - Job Attributes + + def __load_jobs_attributes__(self): + """Load jobs attributes data from file.""" + #| - __load_jobs_attributes__ + job_att_file = self.root_dir + "/jobs_bin/job_attributes.csv" + + if os.path.exists(job_att_file): + with open(job_att_file, "rb") as fle: + jobs_att = pickle.load(fle) + + else: + jobs_att = {} + + return(jobs_att) + #__| + + def append_jobs_attributes(self, attribute): + """ + Append to jobs attributes file. + + Append dictionary key value pair to the jobs_attributes dict. + To be pickled and saved + """ + #| - append_jobs_attributes + att_new = attribute + + self.jobs_att.update(att_new) + + job_att_file = self.root_dir + "/jobs_bin/job_attributes.csv" + pickle.dump(self.jobs_att, open(job_att_file, "wb")) + #__| + + #__| + + def __gen_datatable__(self): + """Initialze data table from the properties of the jobs directory. + + New methods iterates through Job instances + """ + #| - __generate_data_table + rows_list = [] + for Job_i in self.Job_list: + #| - FOR LOOP BODY + entry_param_dict = {} + for prop, value in Job_i.job_params.items(): + entry_param_dict[prop] = value + + entry_param_dict["Job"] = Job_i + entry_param_dict["path"] = Job_i.full_path + entry_param_dict["max_revision"] = Job_i.max_revision + entry_param_dict["revision_number"] = Job_i.revision_number + + rows_list.append(entry_param_dict) + #__| + + data_frame = pd.DataFrame(rows_list) + + return(data_frame) + #__| + + def __revision_list_and_max__(self, path_i): + """Return list of revisions for given job path and highest revision. + + If there are no revision folders or the directory structure hasn't been + created yet the following dummy values will be returned: + ( + ["_1"], + 1, + ) + + Args: + path_i: + """ + #| - __revision_list_and_max__ + if self.folders_exist: + + # dirs = os.listdir(os.path.join(self.working_dir, path_i)) + dirs = os.listdir(path_i) + + revision_dirs = [dir for dir in dirs if dir[0] == "_" and + dir[-1].isdigit() and " " not in dir] + + # dir[1].isdigit() and " " not in dir] + + revision_dirs.sort() + + if len(revision_dirs) == 0: + highest_rev = None + else: + highest_rev = max( + [int(i.split("_")[-1]) for i in revision_dirs], + ) + + return(revision_dirs, highest_rev) + else: + dummy_return = ( + ["_1"], + 1, + ) + + return(dummy_return) + #__| + + def copy_files_jd(self, file_list, variable_lst, revision="Auto"): + """ + Copy files to job directory. + + Args: + file_list: + variable_lst: + revision: + """ + #| - copy_files_jd + path = self.var_lst_to_path(variable_lst) + path += "_" + str(self.job_revision_number(variable_lst)) + + for file in file_list: + shutil.copyfile(self.root_dir + "/" + file, path + "/" + file) + #__| + + + #__| ********************************************************************** + + + + #| - __old__ + # DEPR + def __generate_data_table__(self): + """Initialze data table from the properties of the jobs directory. + + Appends unique row for every job revision + """ + #| - __generate_data_table__ + rows_list = [] + for job in self.job_var_lst: + revisions = self.job_revision_number(job) + for revision in range(revisions + 1)[1:]: + #| - FOR LOOP BODY + entry_param_dict = {} + for prop in job: + entry_param_dict[prop["property"]] = prop["value"] + + entry_param_dict["variable_list"] = job + entry_param_dict["path"] = self.var_lst_to_path(job) + + entry_param_dict["max_revision"] = revisions + entry_param_dict["revision_number"] = revision + + rows_list.append(entry_param_dict) + #__| + + data_frame = pd.DataFrame(rows_list) + + return(data_frame) + #__| + + # DEPR + def job_revision_number_old(self, variable_lst): + """ + Return the largest revision number for the given variable_lst -> job. + + If there are no revision folders or the directory structure hasn't been + created yet 1 will be returned. + + Args: + variable_lst: + """ + #| - job_revision_number + if self.folders_exist: + path = self.var_lst_to_path(variable_lst) + orig_dir = os.getcwd() + os.chdir(self.root_dir + "/" + path) + + dirs = filter(os.path.isdir, os.listdir(os.getcwd())) + + + # COMBAK Does this line break work? + num_jobs = len([dir for dir in dirs if dir[0] == "_" and + dir[1].isdigit() and " " not in dir]) + os.chdir(orig_dir) + + return(num_jobs) + else: + return(1) + + #| - __old__ + # path = self.var_lst_to_path(variable_lst) + # + # path = "/".join(path.split("/")[0:-1]) + "/" + # # Attempting to remove duplicate job folders (usually have spaces) + # dir_list = [x for x in os.walk(path).next()[1] if " " not in x] + # + # return(len(dir_list)) + # + #__| + + #__| + + + #__| diff --git a/dft_post_analysis/charge_density.py b/dft_post_analysis/charge_density.py index 30b9e7b..4f48c45 100644 --- a/dft_post_analysis/charge_density.py +++ b/dft_post_analysis/charge_density.py @@ -1,459 +1,459 @@ -#!/usr/bin/env python - -"""Charge density class. - -Author: Raul A. Flores -""" - -#| - Import Modules -# import os -# import sys -import random -import pickle - -import pandas as pd -import numpy as np -from ase.io.cube import read_cube -# , write_cube -# read_cube_data, - -# import plotly as py -import plotly.graph_objs as go -#__| - -class ChargeDensity(object): - """docstring for ChargeDensity.""" - - #| - ChargeDensity ******************************************************** - def __init__(self, - cube_filename, - master_data_filter=0.98, - lower_bound_density_filter=0.025, - - wrap_atoms=True, - working_dir=".", - ): - """Initialize ChargeDensity instance. - - Args: - cube_filename: - master_data_filter: - Fraction of data to be removed randomly - lower_bound_density_filter: - Lower bound of normalized density value to be discarded - working_dir: - """ - #| - __init__ - - #| - Define User Attributes - self.cube_filename = cube_filename - self.master_data_filter = master_data_filter - self.lower_bound_density_filter = lower_bound_density_filter - self.wrap_atoms = wrap_atoms - self.working_dir = working_dir - #__| - - ( - self.atoms, - self.cd_data, - self.origin, - ) = self.__load_cube_file__() - - - self.master_data_df = self.__process_data__() - - # self.__save_dataframe__() - - self.num_data_points = self.__number_of_data_points__() - - self.__filter_data__() - self.__norm_electron_density__() - self.__filter_low_density__() - # self.__keep_only_edges__() - #__| - - def __load_cube_file__(self): - """Load charge density cube file.""" - #| - __load_cube_file__ - filename = self.cube_filename - - with open(filename, "r") as fle: - data_master = read_cube(fle) - - atoms = data_master["atoms"] - cd_data = data_master["data"] - origin = data_master["origin"] - - if self.wrap_atoms: - atoms.wrap(pbc=True) - - return(atoms, cd_data, origin) - #__| - - def __process_data__(self): - """Create dataframe from charge density data grid.""" - #| - __process_data__ - cd_data = self.cd_data - atoms = self.atoms - - master_data_list = [] - for index, dens_i in np.ndenumerate(cd_data): - data_i = {} - data_i["x_ind"] = index[0] - data_i["y_ind"] = index[1] - data_i["z_ind"] = index[2] - data_i["density"] = dens_i - - master_data_list.append(data_i) - - df = pd.DataFrame(master_data_list) - - df["x_coord_norm"] = df["x_ind"] / df["x_ind"].max() - df["y_coord_norm"] = df["y_ind"] / df["y_ind"].max() - df["z_coord_norm"] = df["z_ind"] / df["z_ind"].max() - - df["x_coord"] = df["x_coord_norm"] * atoms.cell[:, 0].sum() - df["y_coord"] = df["y_coord_norm"] * atoms.cell[:, 1].sum() - df["z_coord"] = df["z_coord_norm"] * atoms.cell[:, 2].sum() - - def multiply_by_unit_cell(row, atoms=None): - coord = np.array([ - row["x_coord_norm"], - row["y_coord_norm"], - row["z_coord_norm"], - ]) - - scaled_cell_vectors = (atoms.cell.T * coord).T - - new_coord = np.array([ - scaled_cell_vectors[:, 0].sum(), - scaled_cell_vectors[:, 1].sum(), - scaled_cell_vectors[:, 2].sum(), - ]) - - # new_coord = atoms.cell.dot(coord) - - return(new_coord[0], new_coord[1], new_coord[2]) - - ( - df["x_coord"], - df["y_coord"], - df["z_coord"], - ) = zip(*df.apply(multiply_by_unit_cell, axis=1, atoms=atoms)) - - return(df) - #__| - - def __number_of_data_points__(self): - """Return the number of individual density data points.""" - #| - __number_of_data_points__ - master_data_df = self.master_data_df - - num_data_points = len(master_data_df) - - return(num_data_points) - #__| - - def __filter_data__(self): - """Filter data randomly to decrease the data set size.""" - #| - __filter_data__ - master_data_df = self.master_data_df - num_data_points = self.num_data_points - master_data_filter = self.master_data_filter - - bool_list = [] - for data_i in range(num_data_points): - rand_i = random.random() - if rand_i > master_data_filter: - bool_list.append(True) - else: - bool_list.append(False) - - df_filtered = master_data_df[bool_list] - - self.master_data_df = df_filtered - #__| - - def __norm_electron_density__(self): - """Normalize electron density from 0 to 1.""" - #| - __norm_electron_density__ - df = self.master_data_df - - max_density = df.density.max() - df["norm_dens"] = df["density"] / max_density - #__| - - def __filter_low_density__(self): - """Filter low density entries from the data.""" - #| - __filter_low_density__ - df = self.master_data_df - lower_bound_density_filter = self.lower_bound_density_filter - - df = df[df["norm_dens"] > lower_bound_density_filter] - - self.master_data_df = df - #__| - - def __keep_only_edges__(self): - """Only keep the outer surface points for clarity.""" - #| - __keep_only_edges__ - df = self.master_data_df - - df_a = df[df["x_ind"] == df.x_ind.max()] - df_b = df[df["y_ind"] == df.y_ind.max()] - df_c = df[df["z_ind"] == df.z_ind.max()] - - df_1 = df[df["x_ind"] == 0] - df_2 = df[df["y_ind"] == 0] - df_3 = df[df["z_ind"] == 0] - - df_surf = pd.concat( - [ - df_a, df_b, df_c, - df_1, df_2, df_3, - ] - ) - - self.master_data_df = df_surf - #__| - - def __save_dataframe__(self): - """Save dataframe to pickle file. - - COMBAK impliment this to save time - """ - #| - __save_dataframe__ - df = self.master_data_df - working_dir = self.working_dir - - with open(working_dir + "/dataframe.pickle", "w") as fle: - pickle.dump(df, fle) - #__| - - def __load_dataframe__(self): - """Load dataframe from pickle file. - - COMBAK and finish this - """ - #| - __load_dataframe__ - tmp = 42 - - #__| - - def create_charge_density_plotting_trace(self, - opacity=0.4, - size=4, - ): - """Create plotly trace from charge density distribution. - - Args: - opacity: - size: - or - Either a float to represent a constant size - or - "variable", to scale individual marker size with charge density - - """ - #| - create_charge_density_plotting_trace - df = self.master_data_df - - if size == "variable": - size = df["norm_dens"] * 13. - - trace1 = go.Scatter3d( - - x=df["x_coord"], - y=df["y_coord"], - z=df["z_coord"], - - # x=df["x_coord_norm"], - # y=df["y_coord_norm"], - # z=df["z_coord_norm"], - - # x=df["x_ind"], - # y=df["y_ind"], - # z=df["z_ind"], - - mode='markers', - text=df["norm_dens"], - opacity=opacity, - marker=dict( - size=size, - color=df["norm_dens"], - - colorscale=[ - [0., 'rgb(255, 200, 200, 0.1)'], - [1.0, 'rgb(255, 0, 0, 0.9)'], - ], - ) - ) - - return(trace1) - #__| - - def create_unit_cell_plotting_trace(self, - color="red", - width=1., - ): - """TEMP. - - Args: - color - """ - #| - create_unit_cell_plotting_trace - atoms = self.atoms - - def unit_cell_leg_trace( - point_0, - point_1, - color="red", - width=1., - ): - """Create trace for unit cell line. - - Args: - point_0: - point_1: - color: - width: - """ - #| - unit_cell_leg_trace - line_i = np.array([ - point_0, - point_1, - ]) - - trace_i = go.Scatter3d( - x=line_i[:, 0], y=line_i[:, 1], z=line_i[:, 2], - mode="lines", - line=dict( - color=color, - width=width, - ) - ) - - return(trace_i) - #__| - - line_trace_list = [ - - #| - Origin to 3 adjacent corners - unit_cell_leg_trace( - np.array([0., 0., 0.]), - atoms.cell[0], - ), - - unit_cell_leg_trace( - np.array([0., 0., 0.]), - atoms.cell[1], - ), - - unit_cell_leg_trace( - np.array([0., 0., 0.]), - atoms.cell[2], - ), - #__| - - #| - Farthest corner and 3 adjacent cornerse - unit_cell_leg_trace( - atoms.cell[0] + atoms.cell[1] + atoms.cell[2], - atoms.cell[0] + atoms.cell[2] - ), - - unit_cell_leg_trace( - atoms.cell[0] + atoms.cell[1] + atoms.cell[2], - atoms.cell[1] + atoms.cell[2] - ), - - unit_cell_leg_trace( - atoms.cell[0] + atoms.cell[1] + atoms.cell[2], - atoms.cell[0] + atoms.cell[1] - ), - #__| - - #| - TEMP - unit_cell_leg_trace( - atoms.cell[1] + atoms.cell[2], - atoms.cell[1], - color=color, - ), - - unit_cell_leg_trace( - atoms.cell[0] + atoms.cell[2], - atoms.cell[0], - color=color, - ), - #__| - - #| - TEMP - unit_cell_leg_trace( - atoms.cell[2], - atoms.cell[0] + atoms.cell[2], - color=color, - - ), - - unit_cell_leg_trace( - atoms.cell[2], - atoms.cell[1] + atoms.cell[2], - color=color, - ), - #__| - - #| - TEMP - unit_cell_leg_trace( - atoms.cell[0] + atoms.cell[1], - atoms.cell[0], - color=color, - ), - - unit_cell_leg_trace( - atoms.cell[0] + atoms.cell[1], - atoms.cell[1], - color=color, - ), - #__| - - ] - - return(line_trace_list) - #__| - - def create_atoms_plotting_trace(self, - size=12, - ): - """Create atom positions plotly trace. - - Args: - size: - """ - #| - create_atoms_plotting_trace - atoms = self.atoms - - element_color_dict = {} - element_color_dict["Fe"] = "orange" - element_color_dict["C"] = "grey" - element_color_dict["N"] = "blue" - - color_list = [] - for atom in atoms: - elem = atom.symbol - color_list.append(element_color_dict[elem]) - - trace_i = go.Scatter3d( - x=atoms.positions[:, 0], - y=atoms.positions[:, 1], - z=atoms.positions[:, 2], - mode='markers', - - marker=dict( - size=size, - color=color_list, - ) - ) - - return(trace_i) - #__| - - #__| ********************************************************************** +#!/usr/bin/env python + +"""Charge density class. + +Author: Raul A. Flores +""" + +#| - Import Modules +# import os +# import sys +import random +import pickle + +import pandas as pd +import numpy as np +from ase.io.cube import read_cube +# , write_cube +# read_cube_data, + +# import plotly as py +import plotly.graph_objs as go +#__| + +class ChargeDensity(object): + """docstring for ChargeDensity.""" + + #| - ChargeDensity ******************************************************** + def __init__(self, + cube_filename, + master_data_filter=0.98, + lower_bound_density_filter=0.025, + + wrap_atoms=True, + working_dir=".", + ): + """Initialize ChargeDensity instance. + + Args: + cube_filename: + master_data_filter: + Fraction of data to be removed randomly + lower_bound_density_filter: + Lower bound of normalized density value to be discarded + working_dir: + """ + #| - __init__ + + #| - Define User Attributes + self.cube_filename = cube_filename + self.master_data_filter = master_data_filter + self.lower_bound_density_filter = lower_bound_density_filter + self.wrap_atoms = wrap_atoms + self.working_dir = working_dir + #__| + + ( + self.atoms, + self.cd_data, + self.origin, + ) = self.__load_cube_file__() + + + self.master_data_df = self.__process_data__() + + # self.__save_dataframe__() + + self.num_data_points = self.__number_of_data_points__() + + self.__filter_data__() + self.__norm_electron_density__() + self.__filter_low_density__() + # self.__keep_only_edges__() + #__| + + def __load_cube_file__(self): + """Load charge density cube file.""" + #| - __load_cube_file__ + filename = self.cube_filename + + with open(filename, "r") as fle: + data_master = read_cube(fle) + + atoms = data_master["atoms"] + cd_data = data_master["data"] + origin = data_master["origin"] + + if self.wrap_atoms: + atoms.wrap(pbc=True) + + return(atoms, cd_data, origin) + #__| + + def __process_data__(self): + """Create dataframe from charge density data grid.""" + #| - __process_data__ + cd_data = self.cd_data + atoms = self.atoms + + master_data_list = [] + for index, dens_i in np.ndenumerate(cd_data): + data_i = {} + data_i["x_ind"] = index[0] + data_i["y_ind"] = index[1] + data_i["z_ind"] = index[2] + data_i["density"] = dens_i + + master_data_list.append(data_i) + + df = pd.DataFrame(master_data_list) + + df["x_coord_norm"] = df["x_ind"] / df["x_ind"].max() + df["y_coord_norm"] = df["y_ind"] / df["y_ind"].max() + df["z_coord_norm"] = df["z_ind"] / df["z_ind"].max() + + df["x_coord"] = df["x_coord_norm"] * atoms.cell[:, 0].sum() + df["y_coord"] = df["y_coord_norm"] * atoms.cell[:, 1].sum() + df["z_coord"] = df["z_coord_norm"] * atoms.cell[:, 2].sum() + + def multiply_by_unit_cell(row, atoms=None): + coord = np.array([ + row["x_coord_norm"], + row["y_coord_norm"], + row["z_coord_norm"], + ]) + + scaled_cell_vectors = (atoms.cell.T * coord).T + + new_coord = np.array([ + scaled_cell_vectors[:, 0].sum(), + scaled_cell_vectors[:, 1].sum(), + scaled_cell_vectors[:, 2].sum(), + ]) + + # new_coord = atoms.cell.dot(coord) + + return(new_coord[0], new_coord[1], new_coord[2]) + + ( + df["x_coord"], + df["y_coord"], + df["z_coord"], + ) = zip(*df.apply(multiply_by_unit_cell, axis=1, atoms=atoms)) + + return(df) + #__| + + def __number_of_data_points__(self): + """Return the number of individual density data points.""" + #| - __number_of_data_points__ + master_data_df = self.master_data_df + + num_data_points = len(master_data_df) + + return(num_data_points) + #__| + + def __filter_data__(self): + """Filter data randomly to decrease the data set size.""" + #| - __filter_data__ + master_data_df = self.master_data_df + num_data_points = self.num_data_points + master_data_filter = self.master_data_filter + + bool_list = [] + for data_i in range(num_data_points): + rand_i = random.random() + if rand_i > master_data_filter: + bool_list.append(True) + else: + bool_list.append(False) + + df_filtered = master_data_df[bool_list] + + self.master_data_df = df_filtered + #__| + + def __norm_electron_density__(self): + """Normalize electron density from 0 to 1.""" + #| - __norm_electron_density__ + df = self.master_data_df + + max_density = df.density.max() + df["norm_dens"] = df["density"] / max_density + #__| + + def __filter_low_density__(self): + """Filter low density entries from the data.""" + #| - __filter_low_density__ + df = self.master_data_df + lower_bound_density_filter = self.lower_bound_density_filter + + df = df[df["norm_dens"] > lower_bound_density_filter] + + self.master_data_df = df + #__| + + def __keep_only_edges__(self): + """Only keep the outer surface points for clarity.""" + #| - __keep_only_edges__ + df = self.master_data_df + + df_a = df[df["x_ind"] == df.x_ind.max()] + df_b = df[df["y_ind"] == df.y_ind.max()] + df_c = df[df["z_ind"] == df.z_ind.max()] + + df_1 = df[df["x_ind"] == 0] + df_2 = df[df["y_ind"] == 0] + df_3 = df[df["z_ind"] == 0] + + df_surf = pd.concat( + [ + df_a, df_b, df_c, + df_1, df_2, df_3, + ] + ) + + self.master_data_df = df_surf + #__| + + def __save_dataframe__(self): + """Save dataframe to pickle file. + + COMBAK impliment this to save time + """ + #| - __save_dataframe__ + df = self.master_data_df + working_dir = self.working_dir + + with open(working_dir + "/dataframe.pickle", "w") as fle: + pickle.dump(df, fle) + #__| + + def __load_dataframe__(self): + """Load dataframe from pickle file. + + COMBAK and finish this + """ + #| - __load_dataframe__ + tmp = 42 + + #__| + + def create_charge_density_plotting_trace(self, + opacity=0.4, + size=4, + ): + """Create plotly trace from charge density distribution. + + Args: + opacity: + size: + or + Either a float to represent a constant size + or + "variable", to scale individual marker size with charge density + + """ + #| - create_charge_density_plotting_trace + df = self.master_data_df + + if size == "variable": + size = df["norm_dens"] * 13. + + trace1 = go.Scatter3d( + + x=df["x_coord"], + y=df["y_coord"], + z=df["z_coord"], + + # x=df["x_coord_norm"], + # y=df["y_coord_norm"], + # z=df["z_coord_norm"], + + # x=df["x_ind"], + # y=df["y_ind"], + # z=df["z_ind"], + + mode='markers', + text=df["norm_dens"], + opacity=opacity, + marker=dict( + size=size, + color=df["norm_dens"], + + colorscale=[ + [0., 'rgb(255, 200, 200, 0.1)'], + [1.0, 'rgb(255, 0, 0, 0.9)'], + ], + ) + ) + + return(trace1) + #__| + + def create_unit_cell_plotting_trace(self, + color="red", + width=1., + ): + """TEMP. + + Args: + color + """ + #| - create_unit_cell_plotting_trace + atoms = self.atoms + + def unit_cell_leg_trace( + point_0, + point_1, + color="red", + width=1., + ): + """Create trace for unit cell line. + + Args: + point_0: + point_1: + color: + width: + """ + #| - unit_cell_leg_trace + line_i = np.array([ + point_0, + point_1, + ]) + + trace_i = go.Scatter3d( + x=line_i[:, 0], y=line_i[:, 1], z=line_i[:, 2], + mode="lines", + line=dict( + color=color, + width=width, + ) + ) + + return(trace_i) + #__| + + line_trace_list = [ + + #| - Origin to 3 adjacent corners + unit_cell_leg_trace( + np.array([0., 0., 0.]), + atoms.cell[0], + ), + + unit_cell_leg_trace( + np.array([0., 0., 0.]), + atoms.cell[1], + ), + + unit_cell_leg_trace( + np.array([0., 0., 0.]), + atoms.cell[2], + ), + #__| + + #| - Farthest corner and 3 adjacent cornerse + unit_cell_leg_trace( + atoms.cell[0] + atoms.cell[1] + atoms.cell[2], + atoms.cell[0] + atoms.cell[2] + ), + + unit_cell_leg_trace( + atoms.cell[0] + atoms.cell[1] + atoms.cell[2], + atoms.cell[1] + atoms.cell[2] + ), + + unit_cell_leg_trace( + atoms.cell[0] + atoms.cell[1] + atoms.cell[2], + atoms.cell[0] + atoms.cell[1] + ), + #__| + + #| - TEMP + unit_cell_leg_trace( + atoms.cell[1] + atoms.cell[2], + atoms.cell[1], + color=color, + ), + + unit_cell_leg_trace( + atoms.cell[0] + atoms.cell[2], + atoms.cell[0], + color=color, + ), + #__| + + #| - TEMP + unit_cell_leg_trace( + atoms.cell[2], + atoms.cell[0] + atoms.cell[2], + color=color, + + ), + + unit_cell_leg_trace( + atoms.cell[2], + atoms.cell[1] + atoms.cell[2], + color=color, + ), + #__| + + #| - TEMP + unit_cell_leg_trace( + atoms.cell[0] + atoms.cell[1], + atoms.cell[0], + color=color, + ), + + unit_cell_leg_trace( + atoms.cell[0] + atoms.cell[1], + atoms.cell[1], + color=color, + ), + #__| + + ] + + return(line_trace_list) + #__| + + def create_atoms_plotting_trace(self, + size=12, + ): + """Create atom positions plotly trace. + + Args: + size: + """ + #| - create_atoms_plotting_trace + atoms = self.atoms + + element_color_dict = {} + element_color_dict["Fe"] = "orange" + element_color_dict["C"] = "grey" + element_color_dict["N"] = "blue" + + color_list = [] + for atom in atoms: + elem = atom.symbol + color_list.append(element_color_dict[elem]) + + trace_i = go.Scatter3d( + x=atoms.positions[:, 0], + y=atoms.positions[:, 1], + z=atoms.positions[:, 2], + mode='markers', + + marker=dict( + size=size, + color=color_list, + ) + ) + + return(trace_i) + #__| + + #__| ********************************************************************** diff --git a/dft_post_analysis/wf.py b/dft_post_analysis/wf.py index d229eb4..364cc74 100644 --- a/dft_post_analysis/wf.py +++ b/dft_post_analysis/wf.py @@ -1,115 +1,115 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -"""Calculate and return work function for periodic slab. - -Author(s): I got the script from Colin but I think Karen wrote these methods -""" - -#| - Import Modules -# from ase.units import Bohr -# from ase.io import read -import numpy as np -import os -#__| - -def find_max_empty_space(atoms, edir=3): - """Return scaled midpoint coordinate of largest empty space. - - Assuming periodic boundary conditions, finds the largest - continuous segment of free, unoccupied space and returns its midpoint - in scaled coordinates (0 to 1) in the edir direction (default z). - """ - #| - find_max_empty_space - # 0-indexed direction - position_array = atoms.get_scaled_positions()[..., edir - 1] - position_array.sort() - differences = np.diff(position_array) - # through the PBC - differences = np.append( - differences, - position_array[0] + 1 - position_array[-1], - ) - max_diff_index = np.argmax(differences) - if max_diff_index == len(position_array) - 1: - out = (position_array[0] + 1 + position_array[-1]) / 2 % 1 - return(out) - else: - out = (position_array[max_diff_index] + - position_array[max_diff_index + 1]) / 2. - return(out) - #__| - -def calc_wf(atoms, outdir): - """Calculate work function of slab. - - Args: - atoms: - outdir: - """ - #| - calc_wf - hartree = 27.21138505 - rydberg = 0.5 * hartree - bohr = 0.52917721092 - - # rydberg_over_bohr = rydberg / bohr - - # Pick a good place to sample vacuum level - edir = 3 - cell_length = atoms.cell[edir - 1][edir - 1] / bohr - - vacuum_pos_raw = find_max_empty_space(atoms, edir) - - vacuum_pos = vacuum_pos_raw * cell_length - avg_out = open("%s/avg.out" % outdir, "r") - record = False - average_data = [] - lines = list(avg_out) - for line in lines: - # just start reading it in at 0 - if len(line.split()) == 3 and line.split()[0] == "0.000000000": - record = True - elif len(line.split()) == 0: - record = False - if record is True: - average_data.append([float(i) for i in line.split()]) - - #vacuum_energy = average_data[np.abs(np.array(average_data)[..., 0] - - # vacuum_pos).argmin()][2] - - # Get the latest Fermi energy - fermi_data = os.popen('grep -n "Fermi" %s/log | tail -1' % outdir, "r") - fermi_energy = float(fermi_data.readline().split()[-2]) - fermi_data.close() - eopreg = 0.025 - - # we use cell_length*eopreg*3 here since the work functions seem to - # converge at that distance rather than *1 or *2 - vac1guess = vacuum_pos - cell_length * eopreg * 2.5 - vac2guess = vacuum_pos + cell_length * eopreg * 2.5 - if vac1guess < 0: - #look for where we're closest to zero - vac_pos1 = np.abs(cell_length + vacuum_pos - cell_length * - eopreg * 2.5 - np.array(average_data)[..., 0]).argmin() - #print 'shifted vac1 for %s'%outdir - else: - vac_pos1 = np.abs(np.array(average_data)[..., 0] - - vacuum_pos + cell_length * eopreg * 2.5).argmin() - #print 'normal vac1' - if vac2guess > cell_length: - vac_pos2 = np.abs(vacuum_pos + cell_length * eopreg * 2.5 - - cell_length - np.array(average_data)[..., 0]).argmin() - #print 'shifted vac2 for %s'%outdir - else: - vac_pos2 = np.abs(np.array(average_data)[..., 0] - vacuum_pos - - cell_length * eopreg * 2.5).argmin() - #print 'normal vac2' - vacuum_energy1 = average_data[vac_pos1][1] - vacuum_energy2 = average_data[vac_pos2][1] - wf = [ - vacuum_energy1 * rydberg - fermi_energy, - vacuum_energy2 * rydberg - fermi_energy, - ] - - return(wf) - #__| +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Calculate and return work function for periodic slab. + +Author(s): I got the script from Colin but I think Karen wrote these methods +""" + +#| - Import Modules +# from ase.units import Bohr +# from ase.io import read +import numpy as np +import os +#__| + +def find_max_empty_space(atoms, edir=3): + """Return scaled midpoint coordinate of largest empty space. + + Assuming periodic boundary conditions, finds the largest + continuous segment of free, unoccupied space and returns its midpoint + in scaled coordinates (0 to 1) in the edir direction (default z). + """ + #| - find_max_empty_space + # 0-indexed direction + position_array = atoms.get_scaled_positions()[..., edir - 1] + position_array.sort() + differences = np.diff(position_array) + # through the PBC + differences = np.append( + differences, + position_array[0] + 1 - position_array[-1], + ) + max_diff_index = np.argmax(differences) + if max_diff_index == len(position_array) - 1: + out = (position_array[0] + 1 + position_array[-1]) / 2 % 1 + return(out) + else: + out = (position_array[max_diff_index] + + position_array[max_diff_index + 1]) / 2. + return(out) + #__| + +def calc_wf(atoms, outdir): + """Calculate work function of slab. + + Args: + atoms: + outdir: + """ + #| - calc_wf + hartree = 27.21138505 + rydberg = 0.5 * hartree + bohr = 0.52917721092 + + # rydberg_over_bohr = rydberg / bohr + + # Pick a good place to sample vacuum level + edir = 3 + cell_length = atoms.cell[edir - 1][edir - 1] / bohr + + vacuum_pos_raw = find_max_empty_space(atoms, edir) + + vacuum_pos = vacuum_pos_raw * cell_length + avg_out = open("%s/avg.out" % outdir, "r") + record = False + average_data = [] + lines = list(avg_out) + for line in lines: + # just start reading it in at 0 + if len(line.split()) == 3 and line.split()[0] == "0.000000000": + record = True + elif len(line.split()) == 0: + record = False + if record is True: + average_data.append([float(i) for i in line.split()]) + + #vacuum_energy = average_data[np.abs(np.array(average_data)[..., 0] - + # vacuum_pos).argmin()][2] + + # Get the latest Fermi energy + fermi_data = os.popen('grep -n "Fermi" %s/log | tail -1' % outdir, "r") + fermi_energy = float(fermi_data.readline().split()[-2]) + fermi_data.close() + eopreg = 0.025 + + # we use cell_length*eopreg*3 here since the work functions seem to + # converge at that distance rather than *1 or *2 + vac1guess = vacuum_pos - cell_length * eopreg * 2.5 + vac2guess = vacuum_pos + cell_length * eopreg * 2.5 + if vac1guess < 0: + #look for where we're closest to zero + vac_pos1 = np.abs(cell_length + vacuum_pos - cell_length * + eopreg * 2.5 - np.array(average_data)[..., 0]).argmin() + #print 'shifted vac1 for %s'%outdir + else: + vac_pos1 = np.abs(np.array(average_data)[..., 0] - + vacuum_pos + cell_length * eopreg * 2.5).argmin() + #print 'normal vac1' + if vac2guess > cell_length: + vac_pos2 = np.abs(vacuum_pos + cell_length * eopreg * 2.5 - + cell_length - np.array(average_data)[..., 0]).argmin() + #print 'shifted vac2 for %s'%outdir + else: + vac_pos2 = np.abs(np.array(average_data)[..., 0] - vacuum_pos - + cell_length * eopreg * 2.5).argmin() + #print 'normal vac2' + vacuum_energy1 = average_data[vac_pos1][1] + vacuum_energy2 = average_data[vac_pos2][1] + wf = [ + vacuum_energy1 * rydberg - fermi_energy, + vacuum_energy2 * rydberg - fermi_energy, + ] + + return(wf) + #__| diff --git a/docs/Makefile b/docs/Makefile index 0ff3643..590948a 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,20 +1,20 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SPHINXPROJ = ResearchPythonModules -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = ResearchPythonModules +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/all-about-me.rst b/docs/all-about-me.rst index bc4e63f..3d0575a 100644 --- a/docs/all-about-me.rst +++ b/docs/all-about-me.rst @@ -1,11 +1,11 @@ -############ -All about me -############ - -I'm Raul A. Flores, a graduate student that doesn't have any idea how to use Sphinx or readthedocs. \_ ;) __/ - -I've contributed to: - -* django CMS -* Arkestra -* Django +############ +All about me +############ + +I'm Raul A. Flores, a graduate student that doesn't have any idea how to use Sphinx or readthedocs. \_ ;) __/ + +I've contributed to: + +* django CMS +* Arkestra +* Django diff --git a/docs/index.rst b/docs/index.rst index faf0514..6d7744f 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,40 +1,40 @@ -.. Research Python Modules documentation master file, created by - sphinx-quickstart on Wed Apr 4 10:20:57 2018. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to Research Python Modules's documentation! -=================================================== - -.. This text will not be shown - (but, for instance, in HTML might be - rendered as an HTML comment) - - about - install - tutorials/tutorials - ase/ase - cmdline - tips - gallery/gallery - releasenotes - contact - development/development - faq - - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - ase_modules/ase_modules - all-about-me - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +.. Research Python Modules documentation master file, created by + sphinx-quickstart on Wed Apr 4 10:20:57 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Research Python Modules's documentation! +=================================================== + +.. This text will not be shown + (but, for instance, in HTML might be + rendered as an HTML comment) + + about + install + tutorials/tutorials + ase/ase + cmdline + tips + gallery/gallery + releasenotes + contact + development/development + faq + + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + ase_modules/ase_modules + all-about-me + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/energetics/formation_energy.py b/energetics/formation_energy.py index 9556aa8..c2e2cd1 100644 --- a/energetics/formation_energy.py +++ b/energetics/formation_energy.py @@ -1,108 +1,108 @@ -#!/usr/bin/env python - -"""General method to calculate formation energies. - -Author: Raul A. Flores -""" - -#| - Import Modules -import numpy as np - -from ase_modules.ase_methods import create_species_element_dict -#__| - -def calc_formation_energy( - atoms, - energy, - reference_states, - normalize_per_atom=True, - ): - """Calculate formation energy of structure on a per atom basis. - - reference states = [ - { - "energy": , - "element_dict": {"H": 1, "Ir": 2}, - }, - { - - }, - ... - ] - - Args: - atoms: - energy: - reference_dict: - normalize_per_atom: - """ - #| - calc_formation_energy - atoms.info["element_dict"] = create_species_element_dict(atoms) - - num_atoms = atoms.get_number_of_atoms() - - # ordered_elems = list(atoms.info["element_dict"]) - # ordered_elems.sort() - - - #| - Finding List of Unique Elements Defined by reference_states list - ref_state_elem_list = [] - for i in reference_states: - ref_i_elems = list(i["element_dict"]) - ref_state_elem_list.extend(ref_i_elems) - - ordered_elems = list(set(ref_state_elem_list)) - ordered_elems.sort() - #__| - - - #| - Constructing the A matrix - a_matrix = [] - for ref_state_i in reference_states: - ref_i_comp_vect = [] - for elem_i in ordered_elems: - if elem_i in list(ref_state_i["element_dict"]): - elem_i_num = ref_state_i["element_dict"][elem_i] - ref_i_comp_vect.append(elem_i_num) - else: - ref_i_comp_vect.append(0.) - - a_matrix.append(np.array(ref_i_comp_vect)) - a_matrix = np.array(a_matrix).transpose() - #__| - - #| - Constructing the b vector - # phi = 1. - b_vect = [] - for elem_i in ordered_elems: - if elem_i in list(atoms.info["element_dict"]): - elem_i_num = atoms.info["element_dict"][elem_i] - b_vect.append(elem_i_num) - else: - b_vect.append(0.) - - b_vect = np.array(b_vect) - #__| - - #| - Solve linear system of equations - x = np.linalg.solve( - a_matrix, - b_vect, - ) - #__| - - #| - Calculate Formation Energy - ref_e_sum = 0. - for coeff_i, ref_i in zip(x, reference_states): - ref_i_contribution = coeff_i * ref_i["elec_e"] - ref_e_sum += ref_i_contribution - - form_e = energy - ref_e_sum - - if normalize_per_atom: - form_e = form_e / num_atoms - #__| - - - return(form_e) - #__| +#!/usr/bin/env python + +"""General method to calculate formation energies. + +Author: Raul A. Flores +""" + +#| - Import Modules +import numpy as np + +from ase_modules.ase_methods import create_species_element_dict +#__| + +def calc_formation_energy( + atoms, + energy, + reference_states, + normalize_per_atom=True, + ): + """Calculate formation energy of structure on a per atom basis. + + reference states = [ + { + "energy": , + "element_dict": {"H": 1, "Ir": 2}, + }, + { + + }, + ... + ] + + Args: + atoms: + energy: + reference_dict: + normalize_per_atom: + """ + #| - calc_formation_energy + atoms.info["element_dict"] = create_species_element_dict(atoms) + + num_atoms = atoms.get_number_of_atoms() + + # ordered_elems = list(atoms.info["element_dict"]) + # ordered_elems.sort() + + + #| - Finding List of Unique Elements Defined by reference_states list + ref_state_elem_list = [] + for i in reference_states: + ref_i_elems = list(i["element_dict"]) + ref_state_elem_list.extend(ref_i_elems) + + ordered_elems = list(set(ref_state_elem_list)) + ordered_elems.sort() + #__| + + + #| - Constructing the A matrix + a_matrix = [] + for ref_state_i in reference_states: + ref_i_comp_vect = [] + for elem_i in ordered_elems: + if elem_i in list(ref_state_i["element_dict"]): + elem_i_num = ref_state_i["element_dict"][elem_i] + ref_i_comp_vect.append(elem_i_num) + else: + ref_i_comp_vect.append(0.) + + a_matrix.append(np.array(ref_i_comp_vect)) + a_matrix = np.array(a_matrix).transpose() + #__| + + #| - Constructing the b vector + # phi = 1. + b_vect = [] + for elem_i in ordered_elems: + if elem_i in list(atoms.info["element_dict"]): + elem_i_num = atoms.info["element_dict"][elem_i] + b_vect.append(elem_i_num) + else: + b_vect.append(0.) + + b_vect = np.array(b_vect) + #__| + + #| - Solve linear system of equations + x = np.linalg.solve( + a_matrix, + b_vect, + ) + #__| + + #| - Calculate Formation Energy + ref_e_sum = 0. + for coeff_i, ref_i in zip(x, reference_states): + ref_i_contribution = coeff_i * ref_i["elec_e"] + ref_e_sum += ref_i_contribution + + form_e = energy - ref_e_sum + + if normalize_per_atom: + form_e = form_e / num_atoms + #__| + + + return(form_e) + #__| diff --git a/oxr_reaction/adsorbate_scaling.py b/oxr_reaction/adsorbate_scaling.py index 072e1ef..29a64fe 100644 --- a/oxr_reaction/adsorbate_scaling.py +++ b/oxr_reaction/adsorbate_scaling.py @@ -1,339 +1,339 @@ -#!/usr/bin/env python - -"""ORR/OER adsorbate energy scaling class and methods. - -Author: Raul A. Flores -""" - - -#| - IMPORT MODULES -# import numpy as np -# -# import pandas as pd -# pd.options.mode.chained_assignment = None -# -# from sklearn.linear_model import LinearRegression -# -# # import plotly.plotly as py -# import plotly.graph_objs as go -# -# -# from orr_reaction.orr_series import ORR_Free_E_Series -#__| - - -class Adsorbate_Scaling: - """ORR/OER adsorbates' dG/E of adsorption scaling. - - Development Notes: - """ - - #| - Adsorbate_Scaling **************************************************** - - def __init__(self, - tmp=42 - ): - """ - """ - #| - __init__ - self.tmp = tmp - - #__| - - def tmp_meth(self, - ): - """ - """ - #| - tmp - tmp = 42 - return(tmp) - #__| - - #__| ********************************************************************** - - -def get_g_ooh(m_ooh, b_ooh, g_oh): - """ - """ - #| - get_g_ooh - g_ooh = m_ooh * g_oh + b_ooh - return(g_ooh) - #__| - -def get_g_o(m_o, b_o, g_oh): - """ - """ - #| - get_g_o - g_o = m_o * g_oh + b_o - return(g_o) - #__| - -def get_g_oh(m_oh, b_oh, g_oh): - """ - """ - #| - get_g_oh - g_oh = m_oh * g_oh + b_oh - return(g_oh) - #__| - -def lim_U_i( - g_oh=None, - g_o_minus_g_oh=None, - - mech_step=None, # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' - gas_molec_dict=None, - scaling_dict=None, - rxn_direction="forward", - ): - """ - Calculate the following mechanistic step of the OER/ORR: - O2 + (H+ + e-) --> *OOH - - Args: - g_oh: - gas_molec_dict: - scaling_dict: - rxn_direction: - """ - #| - lim_U_i - - #| - Checking Input Types - if g_oh is None and g_o_minus_g_oh is None: - raise ValueError("Need to provide either g_oh or g_o_minus_g_oh") - - if g_oh is not None and g_o_minus_g_oh is not None: - raise ValueError("Please don't provide both g_oh and g_o_minus_g_oh") - - assert gas_molec_dict is not None, "Please provide gas_molec_dict" - assert scaling_dict is not None, "Please provide the scaling_dict" - assert mech_step is not None, "Please provide the step to calculate" - #__| - - #| - linear fit and gas molecule data - m_ooh = scaling_dict["ooh"]["m"] - b_ooh = scaling_dict["ooh"]["b"] - - m_o = scaling_dict["o"]["m"] - b_o = scaling_dict["o"]["b"] - - m_oh = scaling_dict["oh"]["m"] - b_oh = scaling_dict["oh"]["b"] - - - g_o2 = gas_molec_dict["o2"] - g_h2 = gas_molec_dict["h2"] - g_h2o = gas_molec_dict["h2o"] - #__| - - if g_o_minus_g_oh is not None: - """ - (G_O-G_OH) = m_o*G_OH + b_o - (G_OH) - (G_O-G_OH) - b_o = G_OH*(m_o - 1) - G_OH = [(G_O-G_OH) - b_o] / (m_o - 1) - """ - g_oh = (g_o_minus_g_oh - b_o) / (m_o - 1) - - elif g_oh is not None: - g_oh = g_oh - - #| - Calculating Limiting Potential for all legs - if mech_step == "o2_to_ooh": - lim_U_out = get_g_ooh(m_ooh, b_ooh, g_oh) + \ - - g_o2 - - elif mech_step == "ooh_to_o": - lim_U_out = get_g_o(m_o, b_o, g_oh) + \ - g_h2o + \ - - get_g_ooh(m_ooh, b_ooh, g_oh) - - elif mech_step == "o_to_oh": - lim_U_out = get_g_oh(m_oh, b_oh, g_oh) + \ - - get_g_o(m_o, b_o, g_oh) - - elif mech_step == "oh_to_h2o": - lim_U_out = g_h2o + \ - - get_g_oh(m_oh, b_oh, g_oh) - else: - raise ValueError("Woops, error here (9sdfijsd9)") - #__| - - if rxn_direction == "forward": - lim_U_out = - lim_U_out - elif rxn_direction == "reverse": - lim_U_out = + lim_U_out - - return(lim_U_out) - #__| - - - - -#| - __old__ - -# def lim_U_o2_to_ooh(g_oh, -# gas_molec_dict, scaling_dict, rxn_direction="forward"): -# """ -# Calculate the following mechanistic step of the OER/ORR: -# O2 + (H+ + e-) --> *OOH -# -# Args: -# g_oh: -# gas_molec_dict: -# scaling_dict: -# rxn_direction: -# """ -# #| - lim_U_o2_to_ooh -# -# #| - linear fit and gas molecule data -# m_ooh = scaling_dict["ooh"]["m"] -# b_ooh = scaling_dict["ooh"]["b"] -# -# m_o = scaling_dict["o"]["m"] -# b_o = scaling_dict["o"]["b"] -# -# m_oh = scaling_dict["oh"]["m"] -# b_oh = scaling_dict["oh"]["b"] -# -# -# g_o2 = gas_molec_dict["o2"] -# g_h2 = gas_molec_dict["h2"] -# g_h2o = gas_molec_dict["h2o"] -# #__| -# -# -# if False: -# -# g_oh = (TMP - b_o) / (m_o - 1) -# -# lim_U_out = get_g_ooh(m_ooh, b_ooh, g_oh) - g_o2 -# -# if rxn_direction == "forward": -# lim_U_out = - lim_U_out -# elif rxn_direction == "reverse": -# lim_U_out = + lim_U_out -# -# return(lim_U_out) -# #__| -# -# def lim_U_ooh_to_o(g_oh, -# gas_molec_dict, scaling_dict, rxn_direction="forward"): -# """ -# Calculate the following mechanistic step of the OER/ORR: -# *OOH + (H+ + e-) --> *O + H2O -# -# Args: -# g_oh: -# gas_molec_dict: -# scaling_dict: -# rxn_direction: -# """ -# #| - lim_U_ooh_to_o -# -# #| - linear fit and gas molecule data -# m_ooh = scaling_dict["ooh"]["m"] -# b_ooh = scaling_dict["ooh"]["b"] -# -# m_o = scaling_dict["o"]["m"] -# b_o = scaling_dict["o"]["b"] -# -# m_oh = scaling_dict["oh"]["m"] -# b_oh = scaling_dict["oh"]["b"] -# -# -# g_o2 = gas_molec_dict["o2"] -# g_h2 = gas_molec_dict["h2"] -# g_h2o = gas_molec_dict["h2o"] -# #__| -# -# lim_U_out = get_g_o(m_o, -# b_o, g_oh) + g_h2o - get_g_ooh(m_ooh, b_ooh, g_oh) -# -# if rxn_direction == "forward": -# lim_U_out = - lim_U_out -# elif rxn_direction == "reverse": -# lim_U_out = + lim_U_out -# -# return(lim_U_out) -# #__| -# -# def lim_U_o_to_oh(g_oh, -# gas_molec_dict, scaling_dict, rxn_direction="forward"): -# """ -# Calculate the following mechanistic step of the OER/ORR: -# O* + (H+ + e-) --> *OH -# -# Args: -# g_oh: -# gas_molec_dict: -# scaling_dict: -# rxn_direction: -# """ -# #| - lim_U_o_to_oh -# -# #| - linear fit and gas molecule data -# m_ooh = scaling_dict["ooh"]["m"] -# b_ooh = scaling_dict["ooh"]["b"] -# -# m_o = scaling_dict["o"]["m"] -# b_o = scaling_dict["o"]["b"] -# -# m_oh = scaling_dict["oh"]["m"] -# b_oh = scaling_dict["oh"]["b"] -# -# -# g_o2 = gas_molec_dict["o2"] -# g_h2 = gas_molec_dict["h2"] -# g_h2o = gas_molec_dict["h2o"] -# #__| -# -# lim_U_out = get_g_oh(m_oh, b_oh, g_oh) - get_g_o(m_o, b_o, g_oh) -# -# if rxn_direction == "forward": -# lim_U_out = - lim_U_out -# elif rxn_direction == "reverse": -# lim_U_out = + lim_U_out -# -# return(lim_U_out) -# #__| -# -# def lim_U_oh_to_h2o(g_oh, -# gas_molec_dict, scaling_dict, rxn_direction="forward"): -# """ -# Calculate the following mechanistic step of the OER/ORR: -# *OH + (H+ + e-) --> H2O -# -# Args: -# g_oh: -# gas_molec_dict: -# scaling_dict: -# rxn_direction: -# """ -# #| - lim_U_oh_to_h2o -# -# #| - linear fit and gas molecule data -# m_ooh = scaling_dict["ooh"]["m"] -# b_ooh = scaling_dict["ooh"]["b"] -# -# m_o = scaling_dict["o"]["m"] -# b_o = scaling_dict["o"]["b"] -# -# m_oh = scaling_dict["oh"]["m"] -# b_oh = scaling_dict["oh"]["b"] -# -# -# g_o2 = gas_molec_dict["o2"] -# g_h2 = gas_molec_dict["h2"] -# g_h2o = gas_molec_dict["h2o"] -# #__| -# -# lim_U_out = g_h2o - get_g_oh(m_oh, b_oh, g_oh) -# -# if rxn_direction == "forward": -# lim_U_out = - lim_U_out -# elif rxn_direction == "reverse": -# lim_U_out = + lim_U_out -# -# return(lim_U_out) -# #__| -# -#__| +#!/usr/bin/env python + +"""ORR/OER adsorbate energy scaling class and methods. + +Author: Raul A. Flores +""" + + +#| - IMPORT MODULES +# import numpy as np +# +# import pandas as pd +# pd.options.mode.chained_assignment = None +# +# from sklearn.linear_model import LinearRegression +# +# # import plotly.plotly as py +# import plotly.graph_objs as go +# +# +# from orr_reaction.orr_series import ORR_Free_E_Series +#__| + + +class Adsorbate_Scaling: + """ORR/OER adsorbates' dG/E of adsorption scaling. + + Development Notes: + """ + + #| - Adsorbate_Scaling **************************************************** + + def __init__(self, + tmp=42 + ): + """ + """ + #| - __init__ + self.tmp = tmp + + #__| + + def tmp_meth(self, + ): + """ + """ + #| - tmp + tmp = 42 + return(tmp) + #__| + + #__| ********************************************************************** + + +def get_g_ooh(m_ooh, b_ooh, g_oh): + """ + """ + #| - get_g_ooh + g_ooh = m_ooh * g_oh + b_ooh + return(g_ooh) + #__| + +def get_g_o(m_o, b_o, g_oh): + """ + """ + #| - get_g_o + g_o = m_o * g_oh + b_o + return(g_o) + #__| + +def get_g_oh(m_oh, b_oh, g_oh): + """ + """ + #| - get_g_oh + g_oh = m_oh * g_oh + b_oh + return(g_oh) + #__| + +def lim_U_i( + g_oh=None, + g_o_minus_g_oh=None, + + mech_step=None, # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' + gas_molec_dict=None, + scaling_dict=None, + rxn_direction="forward", + ): + """ + Calculate the following mechanistic step of the OER/ORR: + O2 + (H+ + e-) --> *OOH + + Args: + g_oh: + gas_molec_dict: + scaling_dict: + rxn_direction: + """ + #| - lim_U_i + + #| - Checking Input Types + if g_oh is None and g_o_minus_g_oh is None: + raise ValueError("Need to provide either g_oh or g_o_minus_g_oh") + + if g_oh is not None and g_o_minus_g_oh is not None: + raise ValueError("Please don't provide both g_oh and g_o_minus_g_oh") + + assert gas_molec_dict is not None, "Please provide gas_molec_dict" + assert scaling_dict is not None, "Please provide the scaling_dict" + assert mech_step is not None, "Please provide the step to calculate" + #__| + + #| - linear fit and gas molecule data + m_ooh = scaling_dict["ooh"]["m"] + b_ooh = scaling_dict["ooh"]["b"] + + m_o = scaling_dict["o"]["m"] + b_o = scaling_dict["o"]["b"] + + m_oh = scaling_dict["oh"]["m"] + b_oh = scaling_dict["oh"]["b"] + + + g_o2 = gas_molec_dict["o2"] + g_h2 = gas_molec_dict["h2"] + g_h2o = gas_molec_dict["h2o"] + #__| + + if g_o_minus_g_oh is not None: + """ + (G_O-G_OH) = m_o*G_OH + b_o - (G_OH) + (G_O-G_OH) - b_o = G_OH*(m_o - 1) + G_OH = [(G_O-G_OH) - b_o] / (m_o - 1) + """ + g_oh = (g_o_minus_g_oh - b_o) / (m_o - 1) + + elif g_oh is not None: + g_oh = g_oh + + #| - Calculating Limiting Potential for all legs + if mech_step == "o2_to_ooh": + lim_U_out = get_g_ooh(m_ooh, b_ooh, g_oh) + \ + - g_o2 + + elif mech_step == "ooh_to_o": + lim_U_out = get_g_o(m_o, b_o, g_oh) + \ + g_h2o + \ + - get_g_ooh(m_ooh, b_ooh, g_oh) + + elif mech_step == "o_to_oh": + lim_U_out = get_g_oh(m_oh, b_oh, g_oh) + \ + - get_g_o(m_o, b_o, g_oh) + + elif mech_step == "oh_to_h2o": + lim_U_out = g_h2o + \ + - get_g_oh(m_oh, b_oh, g_oh) + else: + raise ValueError("Woops, error here (9sdfijsd9)") + #__| + + if rxn_direction == "forward": + lim_U_out = - lim_U_out + elif rxn_direction == "reverse": + lim_U_out = + lim_U_out + + return(lim_U_out) + #__| + + + + +#| - __old__ + +# def lim_U_o2_to_ooh(g_oh, +# gas_molec_dict, scaling_dict, rxn_direction="forward"): +# """ +# Calculate the following mechanistic step of the OER/ORR: +# O2 + (H+ + e-) --> *OOH +# +# Args: +# g_oh: +# gas_molec_dict: +# scaling_dict: +# rxn_direction: +# """ +# #| - lim_U_o2_to_ooh +# +# #| - linear fit and gas molecule data +# m_ooh = scaling_dict["ooh"]["m"] +# b_ooh = scaling_dict["ooh"]["b"] +# +# m_o = scaling_dict["o"]["m"] +# b_o = scaling_dict["o"]["b"] +# +# m_oh = scaling_dict["oh"]["m"] +# b_oh = scaling_dict["oh"]["b"] +# +# +# g_o2 = gas_molec_dict["o2"] +# g_h2 = gas_molec_dict["h2"] +# g_h2o = gas_molec_dict["h2o"] +# #__| +# +# +# if False: +# +# g_oh = (TMP - b_o) / (m_o - 1) +# +# lim_U_out = get_g_ooh(m_ooh, b_ooh, g_oh) - g_o2 +# +# if rxn_direction == "forward": +# lim_U_out = - lim_U_out +# elif rxn_direction == "reverse": +# lim_U_out = + lim_U_out +# +# return(lim_U_out) +# #__| +# +# def lim_U_ooh_to_o(g_oh, +# gas_molec_dict, scaling_dict, rxn_direction="forward"): +# """ +# Calculate the following mechanistic step of the OER/ORR: +# *OOH + (H+ + e-) --> *O + H2O +# +# Args: +# g_oh: +# gas_molec_dict: +# scaling_dict: +# rxn_direction: +# """ +# #| - lim_U_ooh_to_o +# +# #| - linear fit and gas molecule data +# m_ooh = scaling_dict["ooh"]["m"] +# b_ooh = scaling_dict["ooh"]["b"] +# +# m_o = scaling_dict["o"]["m"] +# b_o = scaling_dict["o"]["b"] +# +# m_oh = scaling_dict["oh"]["m"] +# b_oh = scaling_dict["oh"]["b"] +# +# +# g_o2 = gas_molec_dict["o2"] +# g_h2 = gas_molec_dict["h2"] +# g_h2o = gas_molec_dict["h2o"] +# #__| +# +# lim_U_out = get_g_o(m_o, +# b_o, g_oh) + g_h2o - get_g_ooh(m_ooh, b_ooh, g_oh) +# +# if rxn_direction == "forward": +# lim_U_out = - lim_U_out +# elif rxn_direction == "reverse": +# lim_U_out = + lim_U_out +# +# return(lim_U_out) +# #__| +# +# def lim_U_o_to_oh(g_oh, +# gas_molec_dict, scaling_dict, rxn_direction="forward"): +# """ +# Calculate the following mechanistic step of the OER/ORR: +# O* + (H+ + e-) --> *OH +# +# Args: +# g_oh: +# gas_molec_dict: +# scaling_dict: +# rxn_direction: +# """ +# #| - lim_U_o_to_oh +# +# #| - linear fit and gas molecule data +# m_ooh = scaling_dict["ooh"]["m"] +# b_ooh = scaling_dict["ooh"]["b"] +# +# m_o = scaling_dict["o"]["m"] +# b_o = scaling_dict["o"]["b"] +# +# m_oh = scaling_dict["oh"]["m"] +# b_oh = scaling_dict["oh"]["b"] +# +# +# g_o2 = gas_molec_dict["o2"] +# g_h2 = gas_molec_dict["h2"] +# g_h2o = gas_molec_dict["h2o"] +# #__| +# +# lim_U_out = get_g_oh(m_oh, b_oh, g_oh) - get_g_o(m_o, b_o, g_oh) +# +# if rxn_direction == "forward": +# lim_U_out = - lim_U_out +# elif rxn_direction == "reverse": +# lim_U_out = + lim_U_out +# +# return(lim_U_out) +# #__| +# +# def lim_U_oh_to_h2o(g_oh, +# gas_molec_dict, scaling_dict, rxn_direction="forward"): +# """ +# Calculate the following mechanistic step of the OER/ORR: +# *OH + (H+ + e-) --> H2O +# +# Args: +# g_oh: +# gas_molec_dict: +# scaling_dict: +# rxn_direction: +# """ +# #| - lim_U_oh_to_h2o +# +# #| - linear fit and gas molecule data +# m_ooh = scaling_dict["ooh"]["m"] +# b_ooh = scaling_dict["ooh"]["b"] +# +# m_o = scaling_dict["o"]["m"] +# b_o = scaling_dict["o"]["b"] +# +# m_oh = scaling_dict["oh"]["m"] +# b_oh = scaling_dict["oh"]["b"] +# +# +# g_o2 = gas_molec_dict["o2"] +# g_h2 = gas_molec_dict["h2"] +# g_h2o = gas_molec_dict["h2o"] +# #__| +# +# lim_U_out = g_h2o - get_g_oh(m_oh, b_oh, g_oh) +# +# if rxn_direction == "forward": +# lim_U_out = - lim_U_out +# elif rxn_direction == "reverse": +# lim_U_out = + lim_U_out +# +# return(lim_U_out) +# #__| +# +#__| diff --git a/oxr_reaction/oxr_methods.py b/oxr_reaction/oxr_methods.py index 7f56a15..31ffc62 100644 --- a/oxr_reaction/oxr_methods.py +++ b/oxr_reaction/oxr_methods.py @@ -1,550 +1,550 @@ -#!/usr/bin/env python - -"""ORR energetics classes and methods. - -Author: Raul A. Flores -""" - -#| - IMPORT MODULES -import copy -import numpy as np -import pandas as pd - -from plotly.graph_objs import Scatter - -pd.options.mode.chained_assignment = None - -from oxr_reaction.oxr_series import ORR_Free_E_Series -#__| - -#| - __old__ -def plotly_fed_layout( - plot_title="FED", - plot_title_size=18, - tick_lab_size=16, - axes_lab_size=18, - legend_size=18, - ): - """ - """ - #| - plotly_fed_layout - xax_labels = ["O2", "OOH", "O", "OH", "H2O"] - layout = { - - "title": plot_title, - - "font": { - "family": "Courier New, monospace", - "size": plot_title_size, - "color": "black", - }, - - #| - Axes -------------------------------------------------------------- - "yaxis": { - "title": "Free Energy [eV]", - "zeroline": True, - "titlefont": dict(size=axes_lab_size), - "showgrid": False, - "tickfont": dict( - size=tick_lab_size, - ), - }, - - "xaxis": { - "title": "Reaction Coordinate", - "zeroline": True, - "titlefont": dict(size=axes_lab_size), - "showgrid": False, - - # "showticklabels": False, - - "ticktext": xax_labels, - "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - - "tickfont": dict( - size=tick_lab_size, - ), - }, - #__| ------------------------------------------------------------------- - - #| - Legend ------------------------------------------------------------ - "legend": { - "traceorder": "normal", - "font": dict(size=legend_size) - }, - #__| ------------------------------------------------------------------- - - #| - Plot Size - # "width": 200 * 4., - # "height": 200 * 3., - #__| - - } - - return(layout) - - #__| - -#__| - - -def calc_ads_e( - df_row, - bare_raw_e, - correction=0., - oxy_ref_e=-443.70964, - hyd_ref_e=-16.46018, - ): - """Calculate adsorption energies from raw DFT energetics. - - Default oxygen reference energy is based on water - - Args: - df_row: Pandas dataframe row - bare_raw_e: Bare slab raw DFT energy - correction: Energy correction (ZPE, entropy, solvation, etc.) - oxy_ref_e: - hyd_ref_e: - """ - #| - calc_ads_e - row = df_row - bare_slab = bare_raw_e - oxy_ref = oxy_ref_e - hyd_ref = hyd_ref_e - - #| - Oxygen & Hydrogen Atom Count - atoms_col = "atom_type_num_dict" - if atoms_col in list(row.index): - try: - num_O = row[atoms_col][0]["O"] - except: - num_O = 0 - - try: - num_H = row[atoms_col][0]["H"] - except: - num_H = 0 - - else: - - if row["adsorbate"] == "ooh": - num_O = 2 - num_H = 1 - elif row["adsorbate"] == "o": - num_O = 1 - num_H = 0 - elif row["adsorbate"] == "oh": - num_O = 1 - num_H = 1 - elif row["adsorbate"] == "bare": - num_O = 0 - num_H = 0 - #__| - - # print("oxy_ref: ", oxy_ref) - # print("hyd_ref:", hyd_ref) - - try: - raw_e = row["elec_energy"] - ads_e_i = raw_e - (bare_slab + num_O * oxy_ref + num_H * hyd_ref) - ads_e_i += correction - - # ads_e_i = raw_e - bare_slab - num_O * oxy_ref - num_H * hyd_ref - # ads_e_i += correction - except: - ads_e_i = None - - return(ads_e_i) - #__| - -def df_calc_adsorption_e( - df, - - oxy_ref, - hyd_ref, - - bare_slab_e, - bare_slab_var=None, - - corrections_mode="df_column", # 'corr_dict', 'df_column', None - corrections_column="gibbs_correction", - - corrections_dict=None, - ): - """Calculate and add adsorption energy column to data_frame. - - Args: - df: - """ - #| - df_calc_adsorption_e - ads_e_list = [] - for index, row in df.iterrows(): - bare_e = bare_slab_e - - #| - Correction - corr = 0. - # corr = fe_corr_dict[row["adsorbate"]] - - if corrections_mode == "df_column": - corr = row[corrections_column] - - # If "df_column" method return 0. then try to use correction_dict - if corr == 0.: - if corrections_dict is not None: - corr = corrections_dict[row["adsorbate"]] - - elif corrections_mode == "corr_dict" and corrections_dict is not None: - corr = corrections_dict[row["adsorbate"]] - else: - print("No correction being applied") - corr = 0. - #__| - - if type(bare_slab_e) == dict: - bare_e = bare_slab_e[row[bare_slab_var]] - - elif type(bare_slab_e) == float: - bare_e = bare_slab_e - - ads_e_i = calc_ads_e( - row, - # bare_slab, - bare_e, - correction=corr, - oxy_ref_e=oxy_ref, - hyd_ref_e=hyd_ref, - ) - ads_e_list.append(ads_e_i) - - df["ads_e"] = np.array(ads_e_list) - #__| - -def lowest_e_path( - df, - jobs_variables, - color_list, - create_ideal_series=True, - opt_name=None, - bias=0., - manual_props="*TEMP*", - plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", - smart_format=None, - ): - """Find the lowest energy pathway FED. - - COMBAK - - From a set of FE pathways corresponding to different sites, the lowest - energy states will be selected to construct a new FED. - - Args: - df: - jobs_variables: - Result of Jobs.tree_level_labels - color_list: - bias: - - """ - #| - lowest_e_path - - #| - Grouping By Adsorbate Type - df = copy.deepcopy(df) - groupby = copy.deepcopy(jobs_variables) - - groupby.remove("site") - groupby.remove("adsorbate") - - data_master = {} - if groupby == []: - series_list = [] - for ads_i in df.groupby("adsorbate"): - - min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] - series_list.append(min_e_row) - - df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T - data_master[manual_props] = df_i - - else: - for group_i in df.groupby(groupby): - series_list = [] - for ads_i in group_i[1].groupby("adsorbate"): - - min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] - series_list.append(min_e_row) - - df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T - data_master[group_i[0]] = df_i - - #__| - - #| - Creating Data Sets - - #| - Creating FED Datasets - data_list = [] - # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): - for i_cnt, (key, fe_dict) in enumerate(data_master.items()): - - ORR = ORR_Free_E_Plot( - free_energy_df=fe_dict, - ) - - dat_lst = ORR.plot_fed_series( - bias=bias, - opt_name=opt_name, - properties=key, - color_list=color_list, - i_cnt=i_cnt, - hover_text_col="site", - smart_format=smart_format, - ) - - data_list.extend(dat_lst) - #__| - - #| - Creating Ideal FED Dataset - if create_ideal_series: - e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) - - dat_ideal = ORR.create_plotly_series( - e_list_ideal, - group="Ideal", - name="Ideal", - color=color_list[-1], - plot_mode="full_lines", - ) - - dat_lst = data_list + dat_ideal - - else: - - dat_lst = data_list - - - #__| - - # dat_lst = data_list + dat_ideal - - #__| - - #| - Plotting - - #| - Plot Settings - plot_title_size = 18 - tick_lab_size = 16 - axes_lab_size = 18 - legend_size = 18 - #__| - - #| - Plot Layout - # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] - # layout = { - # - # "title": plot_title, - # - # "font": { - # "family": "Courier New, monospace", - # "size": plot_title_size, - # "color": "black", - # }, - # - # #| - Axes -------------------------------------------------------------- - # "yaxis": { - # "title": "Free Energy [eV]", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # - # "xaxis": { - # "title": "Reaction Coordinate", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # - # # "showticklabels": False, - # - # "ticktext": xax_labels, - # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - # - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Legend ------------------------------------------------------------ - # "legend": { - # "traceorder": "normal", - # "font": dict(size=legend_size) - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Plot Size - # # "width": 200 * 4., - # # "height": 200 * 3., - # #__| - # - # } - #__| - - layout = plotly_fed_layout(plot_title=plot_title) - - #__| - - return(dat_lst, layout) - - #__| - -def plot_all_states( - df, - jobs_variables, - color_list, - bias=0., - hover_text_col="site", - create_ideal_series=True, - plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", - smart_format=None, - ): - """ - - Args: - df: - jobs_variables: - color_list: - bias: - plot_title: - """ - #| - plot_all_states - - #| - Grouping By Adsorbate Type - - groupby = copy.deepcopy(jobs_variables) - # groupby = copy.deepcopy(Jojobs_variablesbs.tree_level_labels) - groupby.remove("adsorbate") - - data_master = {} - for group_i in df.groupby(groupby): - - data_master[group_i[0]] = group_i[1] - #__| - - #| - Creating Data Sets - - #| - Creating FED Datasets - data_list = [] - # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): - for i_cnt, (key, fe_dict) in enumerate(data_master.items()): - ORR = ORR_Free_E_Plot( - free_energy_df=fe_dict, - ) - - dat_lst = ORR.plot_fed_series( - bias=bias, - properties=key, - color_list=color_list, - i_cnt=i_cnt, - # hover_text_col="site" - hover_text_col=hover_text_col, - plot_mode="states_only", - smart_format=smart_format, - ) - - data_list.extend(dat_lst) - #__| - - #| - Creating Ideal FED Dataset - if create_ideal_series: - - e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) - - dat_ideal = ORR.create_plotly_series( - e_list_ideal, - group="Ideal", - name="Ideal", - color="red", - plot_mode="full_lines", - ) - - dat_lst = data_list + dat_ideal - #__| - - else: - dat_lst = data_list - - #__| - - #| - Plotting - - #| - Plot Settings - plot_title_size = 18 - tick_lab_size = 16 - axes_lab_size = 18 - legend_size = 12 - #__| - - #| - Plot Layout - # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] - # layout = { - # - # "title": plot_title, - # - # "font": { - # "family": "Courier New, monospace", - # "size": plot_title_size, - # "color": "black", - # }, - # - # #| - Axes -------------------------------------------------------------- - # "yaxis": { - # "title": "Free Energy [eV]", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # - # "xaxis": { - # "title": "Reaction Coordinate", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # - # # "showticklabels": False, - # - # "ticktext": xax_labels, - # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - # - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Legend ------------------------------------------------------------ - # "legend": { - # "traceorder": "normal", - # "font": dict(size=legend_size) - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Plot Size - # "width": 200 * 4., - # "height": 200 * 3., - # #__| - # - # } - #__| - - layout = plotly_fed_layout(plot_title=plot_title) - - return(dat_lst, layout) - - #__| - - #__| +#!/usr/bin/env python + +"""ORR energetics classes and methods. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import copy +import numpy as np +import pandas as pd + +from plotly.graph_objs import Scatter + +pd.options.mode.chained_assignment = None + +from oxr_reaction.oxr_series import ORR_Free_E_Series +#__| + +#| - __old__ +def plotly_fed_layout( + plot_title="FED", + plot_title_size=18, + tick_lab_size=16, + axes_lab_size=18, + legend_size=18, + ): + """ + """ + #| - plotly_fed_layout + xax_labels = ["O2", "OOH", "O", "OH", "H2O"] + layout = { + + "title": plot_title, + + "font": { + "family": "Courier New, monospace", + "size": plot_title_size, + "color": "black", + }, + + #| - Axes -------------------------------------------------------------- + "yaxis": { + "title": "Free Energy [eV]", + "zeroline": True, + "titlefont": dict(size=axes_lab_size), + "showgrid": False, + "tickfont": dict( + size=tick_lab_size, + ), + }, + + "xaxis": { + "title": "Reaction Coordinate", + "zeroline": True, + "titlefont": dict(size=axes_lab_size), + "showgrid": False, + + # "showticklabels": False, + + "ticktext": xax_labels, + "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], + + "tickfont": dict( + size=tick_lab_size, + ), + }, + #__| ------------------------------------------------------------------- + + #| - Legend ------------------------------------------------------------ + "legend": { + "traceorder": "normal", + "font": dict(size=legend_size) + }, + #__| ------------------------------------------------------------------- + + #| - Plot Size + # "width": 200 * 4., + # "height": 200 * 3., + #__| + + } + + return(layout) + + #__| + +#__| + + +def calc_ads_e( + df_row, + bare_raw_e, + correction=0., + oxy_ref_e=-443.70964, + hyd_ref_e=-16.46018, + ): + """Calculate adsorption energies from raw DFT energetics. + + Default oxygen reference energy is based on water + + Args: + df_row: Pandas dataframe row + bare_raw_e: Bare slab raw DFT energy + correction: Energy correction (ZPE, entropy, solvation, etc.) + oxy_ref_e: + hyd_ref_e: + """ + #| - calc_ads_e + row = df_row + bare_slab = bare_raw_e + oxy_ref = oxy_ref_e + hyd_ref = hyd_ref_e + + #| - Oxygen & Hydrogen Atom Count + atoms_col = "atom_type_num_dict" + if atoms_col in list(row.index): + try: + num_O = row[atoms_col][0]["O"] + except: + num_O = 0 + + try: + num_H = row[atoms_col][0]["H"] + except: + num_H = 0 + + else: + + if row["adsorbate"] == "ooh": + num_O = 2 + num_H = 1 + elif row["adsorbate"] == "o": + num_O = 1 + num_H = 0 + elif row["adsorbate"] == "oh": + num_O = 1 + num_H = 1 + elif row["adsorbate"] == "bare": + num_O = 0 + num_H = 0 + #__| + + # print("oxy_ref: ", oxy_ref) + # print("hyd_ref:", hyd_ref) + + try: + raw_e = row["elec_energy"] + ads_e_i = raw_e - (bare_slab + num_O * oxy_ref + num_H * hyd_ref) + ads_e_i += correction + + # ads_e_i = raw_e - bare_slab - num_O * oxy_ref - num_H * hyd_ref + # ads_e_i += correction + except: + ads_e_i = None + + return(ads_e_i) + #__| + +def df_calc_adsorption_e( + df, + + oxy_ref, + hyd_ref, + + bare_slab_e, + bare_slab_var=None, + + corrections_mode="df_column", # 'corr_dict', 'df_column', None + corrections_column="gibbs_correction", + + corrections_dict=None, + ): + """Calculate and add adsorption energy column to data_frame. + + Args: + df: + """ + #| - df_calc_adsorption_e + ads_e_list = [] + for index, row in df.iterrows(): + bare_e = bare_slab_e + + #| - Correction + corr = 0. + # corr = fe_corr_dict[row["adsorbate"]] + + if corrections_mode == "df_column": + corr = row[corrections_column] + + # If "df_column" method return 0. then try to use correction_dict + if corr == 0.: + if corrections_dict is not None: + corr = corrections_dict[row["adsorbate"]] + + elif corrections_mode == "corr_dict" and corrections_dict is not None: + corr = corrections_dict[row["adsorbate"]] + else: + print("No correction being applied") + corr = 0. + #__| + + if type(bare_slab_e) == dict: + bare_e = bare_slab_e[row[bare_slab_var]] + + elif type(bare_slab_e) == float: + bare_e = bare_slab_e + + ads_e_i = calc_ads_e( + row, + # bare_slab, + bare_e, + correction=corr, + oxy_ref_e=oxy_ref, + hyd_ref_e=hyd_ref, + ) + ads_e_list.append(ads_e_i) + + df["ads_e"] = np.array(ads_e_list) + #__| + +def lowest_e_path( + df, + jobs_variables, + color_list, + create_ideal_series=True, + opt_name=None, + bias=0., + manual_props="*TEMP*", + plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", + smart_format=None, + ): + """Find the lowest energy pathway FED. + + COMBAK + + From a set of FE pathways corresponding to different sites, the lowest + energy states will be selected to construct a new FED. + + Args: + df: + jobs_variables: + Result of Jobs.tree_level_labels + color_list: + bias: + + """ + #| - lowest_e_path + + #| - Grouping By Adsorbate Type + df = copy.deepcopy(df) + groupby = copy.deepcopy(jobs_variables) + + groupby.remove("site") + groupby.remove("adsorbate") + + data_master = {} + if groupby == []: + series_list = [] + for ads_i in df.groupby("adsorbate"): + + min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] + series_list.append(min_e_row) + + df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T + data_master[manual_props] = df_i + + else: + for group_i in df.groupby(groupby): + series_list = [] + for ads_i in group_i[1].groupby("adsorbate"): + + min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] + series_list.append(min_e_row) + + df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T + data_master[group_i[0]] = df_i + + #__| + + #| - Creating Data Sets + + #| - Creating FED Datasets + data_list = [] + # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): + for i_cnt, (key, fe_dict) in enumerate(data_master.items()): + + ORR = ORR_Free_E_Plot( + free_energy_df=fe_dict, + ) + + dat_lst = ORR.plot_fed_series( + bias=bias, + opt_name=opt_name, + properties=key, + color_list=color_list, + i_cnt=i_cnt, + hover_text_col="site", + smart_format=smart_format, + ) + + data_list.extend(dat_lst) + #__| + + #| - Creating Ideal FED Dataset + if create_ideal_series: + e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) + + dat_ideal = ORR.create_plotly_series( + e_list_ideal, + group="Ideal", + name="Ideal", + color=color_list[-1], + plot_mode="full_lines", + ) + + dat_lst = data_list + dat_ideal + + else: + + dat_lst = data_list + + + #__| + + # dat_lst = data_list + dat_ideal + + #__| + + #| - Plotting + + #| - Plot Settings + plot_title_size = 18 + tick_lab_size = 16 + axes_lab_size = 18 + legend_size = 18 + #__| + + #| - Plot Layout + # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] + # layout = { + # + # "title": plot_title, + # + # "font": { + # "family": "Courier New, monospace", + # "size": plot_title_size, + # "color": "black", + # }, + # + # #| - Axes -------------------------------------------------------------- + # "yaxis": { + # "title": "Free Energy [eV]", + # "zeroline": True, + # "titlefont": dict(size=axes_lab_size), + # "showgrid": False, + # "tickfont": dict( + # size=tick_lab_size, + # ), + # }, + # + # "xaxis": { + # "title": "Reaction Coordinate", + # "zeroline": True, + # "titlefont": dict(size=axes_lab_size), + # "showgrid": False, + # + # # "showticklabels": False, + # + # "ticktext": xax_labels, + # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], + # + # "tickfont": dict( + # size=tick_lab_size, + # ), + # }, + # #__| ------------------------------------------------------------------- + # + # #| - Legend ------------------------------------------------------------ + # "legend": { + # "traceorder": "normal", + # "font": dict(size=legend_size) + # }, + # #__| ------------------------------------------------------------------- + # + # #| - Plot Size + # # "width": 200 * 4., + # # "height": 200 * 3., + # #__| + # + # } + #__| + + layout = plotly_fed_layout(plot_title=plot_title) + + #__| + + return(dat_lst, layout) + + #__| + +def plot_all_states( + df, + jobs_variables, + color_list, + bias=0., + hover_text_col="site", + create_ideal_series=True, + plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", + smart_format=None, + ): + """ + + Args: + df: + jobs_variables: + color_list: + bias: + plot_title: + """ + #| - plot_all_states + + #| - Grouping By Adsorbate Type + + groupby = copy.deepcopy(jobs_variables) + # groupby = copy.deepcopy(Jojobs_variablesbs.tree_level_labels) + groupby.remove("adsorbate") + + data_master = {} + for group_i in df.groupby(groupby): + + data_master[group_i[0]] = group_i[1] + #__| + + #| - Creating Data Sets + + #| - Creating FED Datasets + data_list = [] + # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): + for i_cnt, (key, fe_dict) in enumerate(data_master.items()): + ORR = ORR_Free_E_Plot( + free_energy_df=fe_dict, + ) + + dat_lst = ORR.plot_fed_series( + bias=bias, + properties=key, + color_list=color_list, + i_cnt=i_cnt, + # hover_text_col="site" + hover_text_col=hover_text_col, + plot_mode="states_only", + smart_format=smart_format, + ) + + data_list.extend(dat_lst) + #__| + + #| - Creating Ideal FED Dataset + if create_ideal_series: + + e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) + + dat_ideal = ORR.create_plotly_series( + e_list_ideal, + group="Ideal", + name="Ideal", + color="red", + plot_mode="full_lines", + ) + + dat_lst = data_list + dat_ideal + #__| + + else: + dat_lst = data_list + + #__| + + #| - Plotting + + #| - Plot Settings + plot_title_size = 18 + tick_lab_size = 16 + axes_lab_size = 18 + legend_size = 12 + #__| + + #| - Plot Layout + # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] + # layout = { + # + # "title": plot_title, + # + # "font": { + # "family": "Courier New, monospace", + # "size": plot_title_size, + # "color": "black", + # }, + # + # #| - Axes -------------------------------------------------------------- + # "yaxis": { + # "title": "Free Energy [eV]", + # "zeroline": True, + # "titlefont": dict(size=axes_lab_size), + # "showgrid": False, + # "tickfont": dict( + # size=tick_lab_size, + # ), + # }, + # + # "xaxis": { + # "title": "Reaction Coordinate", + # "zeroline": True, + # "titlefont": dict(size=axes_lab_size), + # "showgrid": False, + # + # # "showticklabels": False, + # + # "ticktext": xax_labels, + # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], + # + # "tickfont": dict( + # size=tick_lab_size, + # ), + # }, + # #__| ------------------------------------------------------------------- + # + # #| - Legend ------------------------------------------------------------ + # "legend": { + # "traceorder": "normal", + # "font": dict(size=legend_size) + # }, + # #__| ------------------------------------------------------------------- + # + # #| - Plot Size + # "width": 200 * 4., + # "height": 200 * 3., + # #__| + # + # } + #__| + + layout = plotly_fed_layout(plot_title=plot_title) + + return(dat_lst, layout) + + #__| + + #__| diff --git a/oxr_reaction/oxr_rxn.py b/oxr_reaction/oxr_rxn.py index ec8e56c..3f6a347 100644 --- a/oxr_reaction/oxr_rxn.py +++ b/oxr_reaction/oxr_rxn.py @@ -1,1522 +1,242 @@ -#!/usr/bin/env python - -"""ORR energetics classes and methods. - -Author: Raul A. Flores -""" - -#| - IMPORT MODULES -import numpy as np -import pandas as pd - -from sklearn.linear_model import LinearRegression - -import plotly.graph_objs as go - -pd.options.mode.chained_assignment = None - -from oxr_reaction.oxr_series import ORR_Free_E_Series -from oxr_reaction.adsorbate_scaling import lim_U_i -#__| - - -class ORR_Free_E_Plot: - """ORR free energy diagram class. - - ACTUALLY THIS IS GOING TO BE A GENERAL ORR/OER CLASS NOW!!!!!!!!!!!!!!!!!!! - - Development Notes: - # TODO Should we consider the case where the bulk energy is not 0, and - we have to normalize all of the species energies by it? - """ - - #| - ORR_Free_E_Plot ****************************************************** - - def __init__(self, - free_energy_df=None, - ORR_Free_E_series_list=None, - state_title="adsorbate", - free_e_title="ads_e", - num_states=5, - smart_format=None, - bias=0., - color_list=None, - hover_text_col=None, - rxn_type="ORR", # ORR and OER - - # system_properties=None, - # opt_name=None, - # properties=None, - # i_cnt=0, - # plot_mode="all", - # smart_format=None, - # Plotting ************************************************************ - # show_H_e_pairs_annotations=True, - # show_legend=True, - ): - """ - Input variables to class instance. - - Args: - free_energy_df: - Pandas dataframe containing the adsorbates as rows - Required columns, adsorbate, free energy - system_properties: - state_title: - free_e_title: - - rxn_type: - ORR or OER - """ - #| - __init__ - - #| - Setting Instance Attributes - self.fe_df = free_energy_df - # self.sys_props = system_properties - self.state_title = state_title - self.fe_title = free_e_title - self.num_states = num_states - - # self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] - # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] #COMBAK Is this being used anymore - - self.bias = bias - self.color_list = color_list - self.hover_text_col = hover_text_col - self.smart_format = smart_format - - # self.show_H_e_pairs_annotations = show_H_e_pairs_annotations - # self.show_legend = show_legend - - # *********************************** - # COMBAK, moving to FED class, remove later - self.plot_states_sep = 0.3 - self.plot_states_width = 1. - - self.rxn_type = rxn_type - #__| - - - if self.rxn_type == "ORR": - self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] - self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - - elif self.rxn_type == "OER": - self.rxn_mech_states = ["bulk", "oh", "o", "ooh", "bulk"] - self.ideal_energy = [0, 1.23, 2.46, 3.69, 4.92] - - # self.rxn_x_coord_array = self.create_rxn_coord_array( - # self.num_states, - # spacing=self.plot_states_sep, - # step_size=self.plot_states_width, - # ) - # - # self.mid_state_x_array = self.create_mid_state_x_array() - # # x_array_data = self.rxn_x_coord_array - - if ORR_Free_E_series_list is None: - self.series_list = [] - else: - self.series_list = ORR_Free_E_series_list - - #| - __old__ - # if free_energy_df is not None: - # self.add_bulk_entry() - # self.fill_missing_data() - # - # self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk - # self.energy_lst = self.rxn_energy_lst() - # self.num_of_elec = range(self.num_of_states)[::-1] - # self.overpotential = self.calc_overpotential()[0] - # self.limiting_step = self.calc_overpotential()[1] - # # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - # self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() - # self.overpotential_h2o2 = self.calc_overpotential_h2o2() - #__| - - #__| - - def __create_series_name__(self, series_i): - """ - """ - #| - __create_series_name__ - - if series_i.properties is not None: - name_i = "" - for key, value in series_i.properties.items(): - - # TODO | This is an old feature, get rid of it - if key == "coverage": - continue - - name_i += str(key) + ": " + str(value) + " | " - - else: - name_i = "" - - return(name_i) - #__| - - def __create_smart_format_dict__(self, property_dict, smart_format_dict): - """Create smart format dictionary. - - Args: - property_dict: - smart_format_dict: - """ - #| - __create_smart_format_dict__ - if property_dict is None: - return({}) - - format_dict = {} - for key_i, value_i in property_dict.items(): - for format_i in smart_format_dict: - if list(format_i[0])[0] == key_i: - if list(format_i[0].values())[0] == value_i: - format_dict.update(format_i[1]) - - return(format_dict) - #__| - - def add_series(self, - fe_df, - plot_mode="all", - name_i=None, - group=None, - opt_name=None, - smart_format=True, - format_dict=None, - overpotential_type="ORR", - system_properties=None, - property_key_list=None, - add_overpot=True, - color=None, - overpotential_given=False, - ): - """Add ORR_Free_E_Series instance to ORR_Free_E_Plot.series_list. - - Note: It would be much better to simply take all of the - ORR_Free_E_Series arguments as a **kwargs term. - - Args: - TEMP - """ - #| - add_series - if smart_format: - smart_format_i = self.smart_format - else: - smart_format_i = None - - ORR_Series = ORR_Free_E_Series( - free_energy_df=fe_df, - properties=system_properties, - property_key_list=property_key_list, - state_title=self.state_title, - free_e_title=self.fe_title, - group=group, - bias=self.bias, - # rxn_x_coord_array=self.rxn_x_coord_array, - name_i=name_i, - opt_name=opt_name, # ####### - - color_list=self.color_list, - color=color, - hover_text_col=self.hover_text_col, - plot_mode=plot_mode, # ########## - smart_format=smart_format_i, - format_dict=format_dict, - add_overpot=add_overpot, - rxn_type=self.rxn_type, - overpotential_given=overpotential_given, - - # properties=opt_name, - # overpotential_type=self.rxn_type, - # i_cnt=0, # ########## - ) - - self.series_list.append(ORR_Series) - #__| - - #__| ********************************************************************** - - - - - - -#| - __old__ - -# -# # ███████ ██████ ██████ ██ ██████ ████████ -# # ██ ██ ██ ██ ██ ██ ██ ██ ██ -# # ███████ ██████ ██████ ██ ██ ██ ██ -# # ██ ██ ██ ██ ██ ██ ██ ██ -# # ███████ ██ ██ ███████ ██ ███████ ██████ ██ -# -# class Scaling_Relations_Plot(): -# """Plot scaling relations and some simple fitting schemes. -# -# Development Notes: -# IDEA: Add vertical lines to connect *O, *OH, and *OOH data points -# """ -# -# #| - Scaling_Relations_Plot *********************************************** -# -# def __init__(self, -# ORR_Free_E_Plot, -# mode="all", -# -# plot_range={ -# "y": [1., 5.], -# "x": [-2., 4.], -# }, -# -# x_ax_species="oh", -# -# marker_color_key="color2", -# marker_border_color_key="color1", -# marker_shape_key="symbol", -# ): -# """ -# Input variables to class instance. -# -# Args: -# ORR_Free_E_Plot: -# mode: -# "all", "ooh_vs_oh", "o_vs_oh" -# """ -# #| - __init__ -# self.ORR_Free_E_Plot = ORR_Free_E_Plot -# -# assert (x_ax_species == "oh"), "Only *OH as the x-axis is allowed now" -# self.x_ax_species = x_ax_species -# self.marker_color_key = marker_color_key -# self.marker_border_color_key = marker_border_color_key -# self.marker_shape_key = marker_shape_key -# -# # ################################################################# -# -# self.data_points = { -# "ooh_vs_oh": [], -# "o_vs_oh": [], -# "oh_vs_oh": [], -# } -# self.data_lines = [] -# -# self.x_range = plot_range["x"] -# self.y_range = plot_range["y"] -# -# # self.layout = self.__create_layout__( -# # title="Scaling Relations", -# # showlegend=True, -# # ) -# -# self.scaling_dict = { -# "ooh": { -# "m": None, -# "b": None, -# }, -# -# "o": { -# "m": None, -# "b": None, -# }, -# -# "oh": { -# "m": 1., -# "b": 0., -# }, -# -# } -# -# self.annotations_list = [] -# -# #__| -# -# def create_scaling_relations_plot(self, -# smart_format_dict=None, -# ): -# """Return plotly data and layout objects for scaling relations. -# -# Args: -# y_ax_spec: -# x_ax_spec: -# """ -# #| - create_scaling_relations_plot -# -# #| - Default Smart Format Dict -# if smart_format_dict is None: -# print("No smart format given!") -# smart_format_dict = [ -# [{"bulk_system": "IrO3"}, {self.marker_color_key: "green"}], -# [{"bulk_system": "IrO2"}, {self.marker_color_key: "yellow"}], -# -# [{"coverage_type": "o_covered"}, {self.marker_shape_key: "s"}], -# [{"coverage_type": "h_covered"}, {self.marker_shape_key: "^"}], -# -# [{"facet": "110"}, {self.marker_border_color_key: "red"}], -# [{"facet": "211"}, {self.marker_border_color_key: "green"}], -# [{"facet": "100"}, {self.marker_border_color_key: "black"}], -# ] -# #__| -# -# #| - Processing Data Points -# for series_i in self.ORR_Free_E_Plot.series_list: -# -# e_oh = series_i.energy_states_dict["oh"] -# e_ooh = series_i.energy_states_dict["ooh"] -# e_o = series_i.energy_states_dict["o"] -# -# -# # Change self.__create_smart_format_dict__ to, -# # self.ORR_Free_E_Plot.__create_smart_format_dict__ -# # TODO -# -# smart_format_i = self.ORR_Free_E_Plot.__create_smart_format_dict__( -# series_i.properties, -# smart_format_dict, -# ) -# -# # This is the old way of getting the name -# # name_i = self.ORR_Free_E_Plot.__create_series_name__(series_i) -# -# name_i = series_i.series_name -# -# if series_i.color is not None: -# smart_format_i[self.marker_color_key] = series_i.color -# -# # NEW, if series has format attached just use that -# if series_i.format_dict: -# smart_format_i = series_i.format_dict -# -# -# #| - ooh_vs_oh -# trace_i = self.__create_trace_i__( -# e_oh, -# e_ooh, -# smart_format_i, -# name_i, -# legendgroup="ooh_vs_oh", -# ) -# # self.data_ooh_oh.append(trace_i) -# self.data_points["ooh_vs_oh"].append(trace_i) -# #__| -# -# #| - o_vs_oh -# trace_i = self.__create_trace_i__( -# e_oh, -# e_o, -# smart_format_i, -# name_i, -# legendgroup="o_vs_oh", -# ) -# # self.data_o_oh.append(trace_i) -# self.data_points["o_vs_oh"].append(trace_i) -# #__| -# -# #| - oh_vs_oh -# trace_i = self.__create_trace_i__( -# e_oh, -# e_oh, -# smart_format_i, -# name_i, -# legendgroup="oh_vs_oh", -# ) -# # self.data_oh_oh.append(trace_i) -# self.data_points["oh_vs_oh"].append(trace_i) -# #__| -# -# #__| -# -# #__| -# -# # Deprecated, delete this later -# def __create_smart_format_dict__(self, property_dict, smart_format_dict): -# """Create smart format dictionary. -# -# Args: -# property_dict: -# smart_format_dict: -# """ -# #| - __create_smart_format_dict__ -# format_dict = {} -# for key_i, value_i in property_dict.items(): -# for format_i in smart_format_dict: -# if list(format_i[0])[0] == key_i: -# if list(format_i[0].values())[0] == value_i: -# format_dict.update(format_i[1]) -# -# return(format_dict) -# #__| -# -# def __create_series_name__(self, series_i): -# """ -# """ -# #| - create_series_name -# name_i = "" -# for key, value in series_i.properties.items(): -# if key == "coverage": -# continue -# -# name_i += str(key) + ": " + str(value) + " | " -# -# return(name_i) -# #__| -# -# def __create_trace_i__(self, -# x_energy, -# y_energy, -# smart_format_i, -# name_i, -# legendgroup=None, -# ): -# """ -# """ -# #| - create_trace_i -# # NOTE Looks like I need to put these in a list here -# x_energy = [x_energy] -# y_energy = [y_energy] -# -# trace_i = go.Scatter( -# x=x_energy, -# y=y_energy, -# text=name_i, -# name=name_i, -# mode="markers", -# legendgroup=legendgroup, -# marker=dict( -# size=smart_format_i.get("marker_size", 9), -# symbol=smart_format_i.get( -# self.marker_shape_key, "circle"), -# color=smart_format_i.get( -# self.marker_color_key, "pink"), -# line=dict( -# # color=smart_format_i[marker_border_color_key], -# color=smart_format_i.get( -# self.marker_border_color_key, "black"), -# width=1., -# ) -# ) -# ) -# -# return(trace_i) -# #__| -# -# # NOTE | This shouldn't be an internal method -# def __create_layout__(self, -# # x_ax_spec="oh", -# title="Scaling Relations", -# showlegend=True, -# layout_dict=None, -# ): -# """Create plotly layout dict. -# -# Args: -# x_ax_spec: -# title: -# showlegend: -# """ -# #| - create_layout -# -# # if x_ax_spec == "" -# if self.x_ax_species == "oh": -# x_ax_title = "Gads,*OH (eV)" -# else: -# x_ax_title = "TEMP" -# -# y_ax_title = "Gads,*OH, " + \ -# "Gads,*O, " + \ -# "Gads,*OOH (eV)" -# -# tick_lab_size = 12 * (4. / 3.) -# axes_lab_size = 14 * (4. / 3.) -# -# # legend_size = 18 -# -# #| - Common Axis Dict -# common_axis_dict = { -# -# # "range": y_axis_range, -# "zeroline": False, -# "showline": True, -# "mirror": 'ticks', -# "linecolor": 'black', -# "showgrid": False, -# -# "titlefont": dict(size=axes_lab_size), -# "tickfont": dict( -# size=tick_lab_size, -# ), -# "ticks": 'inside', -# "tick0": 0, -# "tickcolor": 'black', -# # "dtick": 0.25, -# "ticklen": 2, -# "tickwidth": 1, -# } -# #__| -# -# #| - __old__ -# # x_range_ooh_vs_oh=[0., 3.5], -# # y_range_ooh_vs_oh=[0., 5.], -# # x_range_o_vs_oh=[0., 3.5], -# # y_range_o_vs_oh=[0., 5.], -# -# # if y_ax_spec == "ooh": -# # x_range = self.x_range_ooh_vs_oh -# # elif y_ax_spec == "o": -# # x_range = self.x_range_o_vs_oh -# # elif y_ax_spec == "oh": -# # x_range = self.x_range_oh_vs_oh -# # else: -# # print("Woops - create_layout") -# # -# # if y_ax_spec == "ooh": -# # y_range = self.y_range_ooh_vs_oh -# # elif y_ax_spec == "o": -# # y_range = self._range_o_vs_oh -# # elif y_ax_spec == "oh": -# # y_range = self.y_range_oh_vs_oh -# # else: -# # print("Woops - create_layout") -# #__| -# -# x_range = self.x_range -# y_range = self.y_range -# -# layout_i = { -# "title": title, -# "titlefont": go.layout.title.Font(size=24), -# # "titlefont": go.layout.Titlefont(size=24), -# -# "xaxis": dict( -# common_axis_dict, -# **{ -# "title": x_ax_title, -# "range": x_range, -# }, -# ), -# -# "yaxis": dict( -# common_axis_dict, -# **{ -# "title": y_ax_title, -# "range": y_range, -# }, -# ), -# -# # Margin -# "margin": go.layout.Margin( -# b=50., -# l=50., -# r=50., -# t=50., -# ), -# -# "font": dict( -# family='Arial', -# # size=18, -# color='black', -# ), -# -# "width": 1.5 * 18.7 * 37.795275591, -# "height": 18.7 * 37.795275591, -# -# "showlegend": showlegend, -# -# "legend": dict( -# font=dict( -# size=10, -# ), -# ), -# } -# -# if layout_dict is not None: -# from misc_modules.misc_methods import dict_merge -# dict_merge(layout_i, layout_dict) -# # layout_i = {**layout_i, **layout_dict} -# -# return(layout_i) -# #__| -# -# def __series_excluded__(self, -# properties_i, -# exclude_dict, -# ): -# """Whether to exclude series_i from fitting. -# -# Takes an 'exclude_dict' and the series properties_dict and compares -# them key-by-key. If there is a match, then that series is excluded -# (and the function evaluates to True) -# -# Args: -# properties_i: -# exclude_dict: -# """ -# #| - series_excluded -# exclude_dict_keys = list(exclude_dict.keys()) -# properties_i_keys = list(properties_i.keys()) -# -# shared_keys = list( -# set(exclude_dict_keys).intersection(set(properties_i_keys)), -# ) -# -# if len(shared_keys) < len(exclude_dict_keys): -# print("series_i doesn't have a specific key!") -# -# value_match_list = [] -# for key_i in shared_keys: -# value_match_i = exclude_dict[key_i] == properties_i[key_i] -# value_match_list.append(value_match_i) -# -# -# all_props_match = all(value_match_list) -# -# # if all_props_match: -# # print("Ignoring this series for fitting") -# # -# # else: -# # print("Series not excluded, will include in fitting set") -# -# -# return(all_props_match) -# -# #__| -# -# def fit_scaling_lines(self, -# dependent_species, # 'ooh', 'o', 'oh' -# exclude_dict=None, -# ): -# """Linear fit of either *O or *OOH to *OH -# -# Args: -# dependent_species: -# y-axis species 'ooh' or 'o' -# """ -# #| - fit_scaling_lines -# -# #| - LOOP -# oh_list = [] -# dependent_e_list = [] -# for series_i in self.ORR_Free_E_Plot.series_list: -# -# #| - Excluding series from fitting -# if exclude_dict is not None: -# properties_i = series_i.properties -# exclude_series = self.__series_excluded__( -# properties_i, -# exclude_dict, -# ) -# if exclude_series: -# continue -# #__| -# -# energy_i = series_i.energy_states_dict[dependent_species] -# dependent_e_list.append(energy_i) -# oh_list.append(series_i.energy_states_dict["oh"]) -# -# #__| -# -# X = np.array([[i] for i in oh_list]) -# y = np.array(dependent_e_list) -# -# reg = LinearRegression().fit(X, y) -# -# slope_i = reg.coef_[0] -# intercept_i = reg.intercept_ -# -# print("Scaling fit for ", dependent_species) -# print("intercept_i: ", str(intercept_i)) -# print("slope_i: ", str(slope_i)) -# print("") -# -# out = {"slope": slope_i, "intercept": intercept_i} -# -# self.scaling_dict[dependent_species] = { -# "m": slope_i, -# "b": intercept_i, -# } -# # print("_------__)_Z(*XF(8))") -# -# #| - Equation Annotations -# if dependent_species == "ooh": -# eqn_str_i = ("" + -# "GOOH=" + -# str(round(slope_i, 4)) + -# " GOH+" + -# str(round(intercept_i, 4)) + -# "" -# ) -# -# elif dependent_species == "o": -# eqn_str_i = ("" + -# "GO = " + -# str(round(slope_i, 4)) + -# " GOH+" + -# str(round(intercept_i, 4)) + -# "" -# ) -# -# elif dependent_species == "oh": -# eqn_str_i = ("" + -# "GOH = " + -# str(round(slope_i, 4)) + -# " GOH+" + -# str(round(intercept_i, 4)) + -# "" -# ) -# -# else: -# eqn_str_i = "TEMP TEMP TEMP TEMP | 190213 | RF" -# raise ValueError('A very specific bad thing happened.') -# -# annotation_i = dict( -# x=0., -# y=1., -# xref="paper", -# yref="paper", -# text=eqn_str_i, -# font=dict( -# color="red", -# family="Droid Sans Mono,Overpass", -# size=9. * (4. / 3.), -# ), -# showarrow=False, -# xanchor="left", -# yshift=-11. * (4. / 3.) * len(self.annotations_list), -# xshift=5., -# ) -# -# self.annotations_list.append(annotation_i) -# #__| -# -# -# return(out) -# #__| -# -# def add_ideal_lines(self): -# """Add ideal scaling liknes to plot.""" -# #| - add_ideal_lines -# self.add_line({"slope": 1, "intercept": 3.2}, -# name="*OOH vs *OH Scaling", -# color="black", -# width=1, -# dash="dash", -# ) -# -# self.add_line({"slope": 2, "intercept": 0.}, -# name="*O vs *OH Scaling", -# color="black", -# width=1, -# dash="dash", -# ) -# -# self.add_line({"slope": 1, "intercept": 0.}, -# name="*OH vs *OH Scaling", -# color="black", -# width=1, -# dash="dash", -# ) -# #__| -# -# def add_line(self, -# slope_intercept_dict, -# name="add_lines - TEMP", -# color="black", -# width=1, -# dash="dash", -# ): -# """Add line of form y=mx+b to plot. -# -# Args: -# slope_intercept_dict: -# name: -# color: -# width: -# dash: -# """ -# #| - add_line -# -# # print(slope_intercept_dict) -# -# slope = slope_intercept_dict["slope"] -# intercept = slope_intercept_dict["intercept"] -# -# def scaling_meth(E_OH): -# """ -# """ -# #| - scaling_meth -# out = slope * E_OH + intercept -# -# return(out) -# #__| -# -# LH_bound = self.x_range[0] -# RH_bound = self.x_range[1] -# -# scaling_trace = go.Scatter( -# # x=[self.x_range_ooh_vs_oh[0], self.x_range_ooh_vs_oh[1]], -# x=[LH_bound, RH_bound], -# y=[ -# scaling_meth(LH_bound), -# scaling_meth(RH_bound), -# ], -# # name='Fitted scaling', -# name=name, -# mode='lines', -# line=dict( -# dash=dash, -# color=color, -# width=width, -# ), -# ) -# # self.data_ooh_oh.append(scaling_trace) -# self.data_lines.append(scaling_trace) -# -# # -# # # Annotation -# # ooh_vs_oh_eqn = ("" + -# # "G_*OOH = " + -# # str(round(SC_PLT.scaling_dict["ooh"]["m"], 5)) + -# # " G_*OH + " + -# # str(round(SC_PLT.scaling_dict["ooh"]["b"], 5)) + -# # "" -# # ) -# # -# # o_vs_oh_eqn = ("" + -# # "G_*O = " + -# # str(round(SC_PLT.scaling_dict["o"]["m"], 5)) + -# # " G_*OH + " + -# # str(round(SC_PLT.scaling_dict["o"]["b"], 5)) + -# # "" -# # ) -# -# #__| -# -# -# -# -# -# #| - __old__ -# # def __ideal_ooh_oh_scaling__(self, E_OH): -# # """Return the *OOH adsorption energy given DG_*OH by scaling. -# # -# # Args: -# # E_OH:DG_*OH energy of adsorption -# # """ -# # #| - __ideal_ooh_oh_scaling__ -# # return(E_OH + 3.2) -# # #__| -# # -# # def __ideal_h_oh_scaling__(self, E_OH): -# # """Return the *OOH adsorption energy given DG_*OH by scaling. -# # -# # Args: -# # E_OH: DG_*OH energy of adsorption. -# # """ -# # #| - __ideal_h_oh_scaling__ -# # return(2 * E_OH) -# # #__| -# # -# # def __ideal_oh_oh_scaling__(self, E_OH): -# # """Return the *OH adsorption energy given DG_*OH by scaling. -# # -# # NOTE: TRIVIAL QUANTITY!!!!!!!!!!!!!!!!!!! -# # -# # Args: -# # E_OH: DG_*OH energy of adsorption. -# # """ -# # #| - __ideal_oh_oh_scaling__ -# # return(E_OH) -# # #__| -# # -# #__| -# -# #__| ********************************************************************** - - - - -# # ██ ██ ██████ ██ ██████ ██████ ██ ██████ ████████ -# # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -# # ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ -# # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -# # ████ ██████ ███████ ██████ ███████ ██ ███████ ██████ ██ -# -# class Volcano_Plot(): -# """Class to plot OER/ORR volcano plots. -# -# Development Notes: -# TEMP -# """ -# -# #| - Volcano_Plot ********************************************************* -# -# def __init__(self, -# ORR_Free_E_Plot, -# x_ax_species="o-oh", # 'o-oh' or 'oh' -# smart_format_dict=None, -# plot_range=None, -# marker_color_key="color2", -# marker_border_color_key="color1", -# marker_shape_key="symbol", -# ): -# """ -# Input variables to class instance. -# -# Args: -# ORR_Free_E_Plot: -# mode: -# "all", "ooh_vs_oh", "o_vs_oh" -# plot_range: -# Ex.) -# plot_range={ -# "y": [1., 5.], -# "x": [-2., 4.], -# } -# -# """ -# #| - __init__ -# self.ORR_Free_E_Plot = ORR_Free_E_Plot -# self.x_ax_species = x_ax_species -# self.plot_range = plot_range -# self.smart_format_dict = smart_format_dict -# -# self.data_points = [] -# self.data_lines = [] -# -# self.marker_color_key = marker_color_key -# self.marker_border_color_key = marker_border_color_key -# self.marker_shape_key = marker_shape_key -# -# #__| -# -# # NOTE | Rename this create_volcano_plot -# def create_volcano_relations_plot(self, -# show_data_labels=False, -# # smart_format_dict=None, -# ): -# """Create ORR/OER volcano plot. -# -# Args: -# smart_format_dict: -# Optional dictionary that will format data points -# """ -# #| - create_volcano_relations_plot -# -# #| - Default Smart Format Dict -# smart_format_dict = self.smart_format_dict -# -# if smart_format_dict is None: -# print("No smart format given!") -# smart_format_dict = [ -# [{"bulk_system": "IrO3"}, {self.marker_color_key: "green"}], -# [{"bulk_system": "IrO2"}, {self.marker_color_key: "yellow"}], -# -# [{"coverage_type": "o_covered"}, {"symbol": "s"}], -# [{"coverage_type": "h_covered"}, {"symbol": "^"}], -# -# [{"facet": "110"}, {"color1": "red"}], -# [{"facet": "211"}, {"color1": "green"}], -# [{"facet": "100"}, {"color1": "black"}], -# ] -# #__| -# -# #| - Processing Data Points -# x_data_list = [] -# y_data_list = [] -# -# for series_i in self.ORR_Free_E_Plot.series_list: -# -# #| - x-axis energy -# x_spec = self.x_ax_species -# if x_spec == "o-oh": -# e_o = series_i.energy_states_dict["o"] -# e_oh = series_i.energy_states_dict["oh"] -# x_ax_energy = e_o - e_oh -# else: -# x_ax_energy = series_i.energy_states_dict[x_spec] -# #__| -# -# #| - y-axis limiting potential -# if self.ORR_Free_E_Plot.rxn_type == "ORR": -# lim_pot_i = 1.23 - series_i.overpotential -# -# elif self.ORR_Free_E_Plot.rxn_type == "OER": -# lim_pot_i = 1.23 + series_i.overpotential_OER -# else: -# print("LSDJFlksdj") -# #__| -# -# #| - Process series_i -# x_data_list.append(x_ax_energy) -# y_data_list.append(lim_pot_i) -# -# smart_format_i = self.ORR_Free_E_Plot.__create_smart_format_dict__( -# series_i.properties, -# smart_format_dict, -# ) -# -# name_i = series_i.series_name -# -# if series_i.color is not None: -# smart_format_i[self.marker_color_key] = series_i.color -# -# -# format_i = smart_format_i -# -# if series_i.format_dict: -# format_i = series_i.format_dict -# -# trace_i = self.__create_trace_i__( -# x_ax_energy, -# lim_pot_i, -# # smart_format_i, -# format_i, -# name_i, -# group=series_i.group, -# show_data_labels=show_data_labels, -# ) -# -# self.data_points.append(trace_i) -# #__| -# -# #__| -# -# #| - Finding plot axis limits -# if self.plot_range is None: -# y_axis_range = [min(y_data_list) - 0.2, max(y_data_list) + 0.2] -# if self.ORR_Free_E_Plot.rxn_type == "OER": -# y_axis_range.reverse() -# else: -# pass -# -# plot_range = { -# "y": y_axis_range, -# "x": [min(x_data_list) - 0.2, max(x_data_list) + 0.2], -# } -# -# self.plot_range = plot_range -# #__| -# -# #__| -# -# def create_volcano_lines(self, -# gas_molec_dict=None, -# scaling_dict=None, -# plot_all_legs=True, -# plot_min_max_legs=False, -# trace_priority="top", # 'top' or 'bottom' -# legs_to_plot=[ -# "o2_to_ooh", -# "ooh_to_o", -# "o_to_oh", -# "oh_to_h2o", -# ], -# line_color="black", -# ): -# """Create volcano data traces. -# -# Args: -# gas_molec_dict: -# scaling_dict: -# plot_all_legs: -# plot_min_max_legs: -# trace_priority: -# if 'top', the volcano lines will be placed on the top of the -# plot, if 'bottom' then the data points will by on top of the -# volcano -# """ -# #| - create_volcano_lines -# out_data = [] -# x_range = self.plot_range["x"] -# -# #| - Volcano Legs -# volc_legs = [ -# 'o2_to_ooh', -# 'ooh_to_o', -# 'o_to_oh', -# 'oh_to_h2o', -# ] -# -# energy_dict = { -# 'o2_to_ooh': [], -# 'ooh_to_o': [], -# 'o_to_oh': [], -# 'oh_to_h2o': [], -# } -# -# #| - Create Volcano Legs (LOOP) -# x_axis = np.linspace(x_range[0], x_range[1], num=500) -# for leg_i in volc_legs: -# for x_energy_i in x_axis: -# -# if self.x_ax_species == "oh": -# g_oh = x_energy_i -# g_o_minus_g_oh = None -# -# elif self.x_ax_species == "o-oh": -# g_oh = None -# g_o_minus_g_oh = x_energy_i -# -# energy_dict[leg_i].append( -# lim_U_i( -# g_oh=g_oh, -# g_o_minus_g_oh=g_o_minus_g_oh, -# # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' -# mech_step=leg_i, -# gas_molec_dict=gas_molec_dict, -# scaling_dict=scaling_dict, -# rxn_direction="forward", -# ), -# ) -# #__| -# -# if plot_all_legs: -# -# #| - plot_all_legs -# # hoverinfo_type = "none" -# hoverinfo_type = "name" -# -# trace_o2_to_ooh = go.Scatter( -# x=x_axis, -# y=energy_dict["o2_to_ooh"], -# name="O2->*OOH", -# hoverinfo=hoverinfo_type, -# line=dict( -# color="#e7b8bc", -# width=2, -# dash="solid", -# ) -# ) -# -# trace_ooh_to_o = go.Scatter( -# x=x_axis, -# y=energy_dict["ooh_to_o"], -# name="*OOH->*O", -# hoverinfo=hoverinfo_type, -# line=dict( -# color="#afd7c3", -# width=2, -# dash="solid", -# ) -# ) -# -# trace_o_to_oh = go.Scatter( -# x=x_axis, -# y=energy_dict["o_to_oh"], -# name="*O->*OH", -# hoverinfo=hoverinfo_type, -# line=dict( -# color="#b5c4e2", -# width=2, -# dash="solid", -# ) -# ) -# -# trace_oh_to_h2o = go.Scatter( -# x=x_axis, -# y=energy_dict["oh_to_h2o"], -# name="*OH->H2O", -# hoverinfo=hoverinfo_type, -# line=dict( -# color="#dbcdab", -# width=2, -# dash="solid", -# ) -# ) -# -# if trace_priority == "top": -# out_data.append(trace_o2_to_ooh) -# out_data.append(trace_ooh_to_o) -# out_data.append(trace_o_to_oh) -# out_data.append(trace_oh_to_h2o) -# -# elif trace_priority == "bottom": -# out_data.insert(0, trace_o2_to_ooh) -# out_data.insert(0, trace_ooh_to_o) -# out_data.insert(0, trace_o_to_oh) -# out_data.insert(0, trace_oh_to_h2o) -# #__| -# -# #__| -# -# #| - Minimum Energy Legs -# energy_lists= [] -# for leg_i in legs_to_plot: -# energy_lists.append(energy_dict[leg_i]) -# -# min_max_e_list = [] -# for legs in zip(*energy_lists): -# if self.ORR_Free_E_Plot.rxn_type == "ORR": -# energy_i = min(*legs) -# -# elif self.ORR_Free_E_Plot.rxn_type == "OER": -# energy_i = max(*legs) -# -# min_max_e_list.append(energy_i) -# -# trace_volcano = go.Scatter( -# x=x_axis, -# y=min_max_e_list, -# name="activity volcano", -# hoverinfo="skip", -# line=dict( -# color=line_color, -# width=2, -# # dash="dash", -# dash="5px,2px,5px,2px", -# ) -# ) -# -# if plot_min_max_legs: -# if trace_priority == "top": -# out_data.append(trace_volcano) -# -# elif trace_priority == "bottom": -# out_data.insert(0, trace_volcano) -# #__| -# -# return(out_data) -# #__| -# -# def __create_trace_i__(self, -# x_energy, -# y_energy, -# smart_format_i, -# name_i, -# # legendgroup=None, -# group=None, -# show_data_labels=False, -# ): -# """ -# """ -# #| - __create_trace_i__ -# -# if show_data_labels is True: -# mode_i = "markers+text" -# elif show_data_labels is False: -# mode_i = "markers" -# else: -# print("TEMP TEMP TEMP | __create_trace_i__") -# -# # print(mode_i) -# -# trace_i = go.Scatter( -# x=[x_energy], -# y=[y_energy], -# -# mode=mode_i, -# # mode="markers+text", -# # mode="markers", -# -# name=name_i, -# text=[name_i], -# # text=["TEMP"], -# -# legendgroup=group, -# -# hoverinfo="text", -# -# # hoverinfo=None, -# # hoverinfosrc=None, -# # hoverlabel=None, -# # hoveron=None, -# # hovertext=None, -# # hovertextsrc=None, -# -# # textposition='top right', -# textposition='middle left', -# textfont={ -# # "family": "Courier New, monospace", -# # "family": font_family, -# "size": 10, -# "color": "black", -# }, -# -# marker=dict( -# size=smart_format_i.get("marker_size", 9), -# color=smart_format_i.get(self.marker_color_key, "red"), -# symbol=smart_format_i.get( -# self.marker_shape_key, "circle"), -# line=dict( -# width=smart_format_i.get("marker_border_width", 1.), -# color=smart_format_i.get( -# self.marker_border_color_key, "black"), -# ), -# ), -# ) -# -# return(trace_i) -# #__| -# -# def get_plotly_layout(self, -# showlegend=False, -# width=9. * 37.795275591, -# height=9. * 37.795275591, -# layout_dict=None, -# ): -# """ -# """ -# #| - get_plotly_layout -# -# #| - Properties -# # plot_title="FED" -# plot_title = None -# # plot_title_size = 18 -# # tick_lab_size = 9 * (4. / 3.) -# tick_lab_size = 8 * (4. / 3.) -# axes_lab_size = 9 * (4. / 3.) -# legend_size = 18 -# # font_family="Computer Modern" # "Courier New, monospace" -# font_family = "Arial" # "Courier New, monospace" -# #__| -# -# # self.x_ax_spec -# -# if self.x_ax_species == "oh": -# # xaxis_title = "dG_*OH (eV)" -# xaxis_title = "dGOH (eV)" -# elif self.x_ax_species == "o-oh": -# # xaxis_title = "dG_*OH - dG_*O (eV)" -# xaxis_title = "dGO - dGOH (eV)" -# -# # layout["margin"] = go.layout.Margin( -# # b=50., -# # l=50., -# # r=50., -# # t=50., -# # # pad=20., -# # ) -# -# layout = { -# "title": plot_title, -# -# "font": { -# "family": font_family, -# "color": "black", -# }, -# -# #| - Axes ----------------------------------------------------- -# -# #| - yaxis -# "yaxis": { -# "title": "Limiting Potential (V)", -# # "title": "$\\Delta G (ev)$", -# -# "range": self.plot_range["y"], -# "zeroline": False, -# "showline": True, -# "mirror": 'ticks', -# # "linecolor": 'red', -# "linecolor": 'black', -# "showgrid": False, -# -# "titlefont": dict(size=axes_lab_size), -# -# "tickfont": dict( -# size=tick_lab_size, -# ), -# "ticks": 'inside', -# "tick0": 0, -# "tickcolor": 'black', -# "dtick": 0.1, -# "ticklen": 2, -# "tickwidth": 1, -# }, -# #__| -# -# #| - xaxis -# "xaxis": { -# # "title": "$\\Delta G_{OH} (ev)$", -# "title": xaxis_title, -# "range": self.plot_range["x"], -# "zeroline": False, -# "showline": True, -# "mirror": True, -# # "linecolor": 'red', -# "linecolor": 'black', -# "showgrid": False, -# "titlefont": dict(size=axes_lab_size), -# "showticklabels": True, -# "ticks": 'inside', -# "tick0": 0, -# "dtick": 0.2, -# "ticklen": 2, -# "tickwidth": 1, -# "tickcolor": 'black', -# "tickfont": dict( -# size=tick_lab_size, -# ), -# }, -# #__| -# -# #__| -# -# "margin": go.layout.Margin( -# b=50., -# l=50., -# r=50., -# t=50., -# ), -# -# # "paper_bgcolor": 'rgba(0,0,0,0)', -# "plot_bgcolor": 'rgba(0,0,0,0)', -# -# #| - Legend --------------------------------------------------- -# "legend": { -# "traceorder": "normal", -# "font": dict(size=legend_size), -# "x": 0., -# "y": -0.1, -# # "xanchor": "left", -# "yanchor": "top", -# }, -# -# # "showlegend": False, -# "showlegend": showlegend, -# -# #__| -# -# } -# -# #| - Plot Size Settings -# # bottom_margin_size = 2.5 * 9. * 37.795275591 -# plot_size_settings = { -# "width": width, -# "height": height, -# -# # "width": 9. * 37.795275591, -# # "height": 9 * 37.795275591, -# -# # "margin": go.layout.Margin({ -# # "l": 50, -# # "r": 50, -# # # "b": bottom_margin_size, -# # # "b": 100, -# # "b": 1200, -# # "t": 10, -# # "pad": 4, -# # }), -# } -# -# #__| -# -# layout = {**layout, **plot_size_settings} -# -# #| - Applying Layout override dict -# if layout_dict is not None: -# from misc_modules.misc_methods import dict_merge -# dict_merge(layout, layout_dict) -# -# # layout_i = {**layout_i, **layout_dict} -# -# #__| -# -# return(layout) -# -# #__| -# -# -# #__| ********************************************************************** -#__| +#!/usr/bin/env python + +"""ORR energetics classes and methods. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import numpy as np +import pandas as pd + +from sklearn.linear_model import LinearRegression + +import plotly.graph_objs as go + +pd.options.mode.chained_assignment = None + +from oxr_reaction.oxr_series import ORR_Free_E_Series +from oxr_reaction.adsorbate_scaling import lim_U_i +# from oxr_reaction.oxr_rxn import ORR_Free_E_Plot +#__| + + +class ORR_Free_E_Plot: + """ORR free energy diagram class. + + ACTUALLY THIS IS GOING TO BE A GENERAL ORR/OER CLASS NOW!!!!!!!!!!!!!!!!!!! + + Development Notes: + TODO Rename this base class to OXR_BASE or something + TODO Should we consider the case where the bulk energy is not 0, and + we have to normalize all of the species energies by it? + """ + + #| - ORR_Free_E_Plot ****************************************************** + + def __init__(self, + free_energy_df=None, + ORR_Free_E_series_list=None, + state_title="adsorbate", + free_e_title="ads_e", + num_states=5, + smart_format=None, + bias=0., + color_list=None, + hover_text_col=None, + rxn_type="ORR", # ORR and OER + + # system_properties=None, + # opt_name=None, + # properties=None, + # i_cnt=0, + # plot_mode="all", + # smart_format=None, + # Plotting ************************************************************ + # show_H_e_pairs_annotations=True, + # show_legend=True, + ): + """ + Input variables to class instance. + + Args: + free_energy_df: + Pandas dataframe containing the adsorbates as rows + Required columns, adsorbate, free energy + system_properties: + state_title: + free_e_title: + + rxn_type: + ORR or OER + """ + #| - __init__ + + #| - Setting Instance Attributes + self.fe_df = free_energy_df + # self.sys_props = system_properties + self.state_title = state_title + self.fe_title = free_e_title + self.num_states = num_states + + # self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] + # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] #COMBAK Is this being used anymore + + self.bias = bias + self.color_list = color_list + self.hover_text_col = hover_text_col + self.smart_format = smart_format + + # self.show_H_e_pairs_annotations = show_H_e_pairs_annotations + # self.show_legend = show_legend + + # *********************************** + # COMBAK, moving to FED class, remove later + self.plot_states_sep = 0.3 + self.plot_states_width = 1. + + self.rxn_type = rxn_type + #__| + + + if self.rxn_type == "ORR": + self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] + self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] + + elif self.rxn_type == "OER": + self.rxn_mech_states = ["bulk", "oh", "o", "ooh", "bulk"] + self.ideal_energy = [0, 1.23, 2.46, 3.69, 4.92] + + # self.rxn_x_coord_array = self.create_rxn_coord_array( + # self.num_states, + # spacing=self.plot_states_sep, + # step_size=self.plot_states_width, + # ) + # + # self.mid_state_x_array = self.create_mid_state_x_array() + # # x_array_data = self.rxn_x_coord_array + + if ORR_Free_E_series_list is None: + self.series_list = [] + else: + self.series_list = ORR_Free_E_series_list + + #| - __old__ + # if free_energy_df is not None: + # self.add_bulk_entry() + # self.fill_missing_data() + # + # self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk + # self.energy_lst = self.rxn_energy_lst() + # self.num_of_elec = range(self.num_of_states)[::-1] + # self.overpotential = self.calc_overpotential()[0] + # self.limiting_step = self.calc_overpotential()[1] + # # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] + # self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() + # self.overpotential_h2o2 = self.calc_overpotential_h2o2() + #__| + + #__| + + def __create_series_name__(self, series_i): + """ + """ + #| - __create_series_name__ + + if series_i.properties is not None: + name_i = "" + for key, value in series_i.properties.items(): + + # TODO | This is an old feature, get rid of it + if key == "coverage": + continue + + name_i += str(key) + ": " + str(value) + " | " + + else: + name_i = "" + + return(name_i) + #__| + + def __create_smart_format_dict__(self, property_dict, smart_format_dict): + """Create smart format dictionary. + + Args: + property_dict: + smart_format_dict: + """ + #| - __create_smart_format_dict__ + if property_dict is None: + return({}) + + format_dict = {} + for key_i, value_i in property_dict.items(): + for format_i in smart_format_dict: + if list(format_i[0])[0] == key_i: + if list(format_i[0].values())[0] == value_i: + format_dict.update(format_i[1]) + + return(format_dict) + #__| + + def add_series(self, + fe_df, + plot_mode="all", + name_i=None, + group=None, + opt_name=None, + smart_format=True, + format_dict=None, + overpotential_type="ORR", + system_properties=None, + property_key_list=None, + add_overpot=True, + color=None, + overpotential_given=False, + ): + """Add ORR_Free_E_Series instance to ORR_Free_E_Plot.series_list. + + Note: It would be much better to simply take all of the + ORR_Free_E_Series arguments as a **kwargs term. + + Args: + TEMP + """ + #| - add_series + if smart_format: + smart_format_i = self.smart_format + else: + smart_format_i = None + + ORR_Series = ORR_Free_E_Series( + free_energy_df=fe_df, + properties=system_properties, + property_key_list=property_key_list, + state_title=self.state_title, + free_e_title=self.fe_title, + group=group, + bias=self.bias, + # rxn_x_coord_array=self.rxn_x_coord_array, + name_i=name_i, + opt_name=opt_name, # ####### + + color_list=self.color_list, + color=color, + hover_text_col=self.hover_text_col, + plot_mode=plot_mode, # ########## + smart_format=smart_format_i, + format_dict=format_dict, + add_overpot=add_overpot, + rxn_type=self.rxn_type, + overpotential_given=overpotential_given, + + # properties=opt_name, + # overpotential_type=self.rxn_type, + # i_cnt=0, # ########## + ) + + self.series_list.append(ORR_Series) + #__| + + #__| ********************************************************************** diff --git a/oxr_reaction/oxr_series.py b/oxr_reaction/oxr_series.py index 4312a1b..143faa0 100644 --- a/oxr_reaction/oxr_series.py +++ b/oxr_reaction/oxr_series.py @@ -1,631 +1,643 @@ -#!/usr/bin/env python - -"""ORR energetics classes and methods. - -Author: Raul A. Flores -""" - -#| - IMPORT MODULES -import copy - -import numpy as np -import pandas as pd - -from plotly.graph_objs import Scatter -pd.options.mode.chained_assignment = None -#__| - -class ORR_Free_E_Series(): - """ORR free energy diagram series class. - - Still a work in progress - - Take a 2nd look at how the bulk/bare state is being taken care of - - # TODO | The color_list approach is not good - """ - - #| - ORR_Free_E_Series **************************************************** - - def __init__(self, - free_energy_df=None, - state_title="adsorbate", - free_e_title="ads_e", - bias=0., - group=None, - name_i=None, - opt_name=None, - properties=None, - property_key_list=None, - color_list=None, - color=None, - hover_text_col=None, - plot_mode="all", - smart_format=None, - format_dict=None, - add_overpot=True, - rxn_type="ORR", - fill_missing_data_w_scaling=True, - overpotential_given=False, - ): - """ - Input variables to class instance. - - TODO: Make sure that format_dict is used if it's supplied by user - - Args: - free_energy_df: - Pandas dataframe containing the adsorbates as rows - Required columns, adsorbate, free energy - state_title: - free_e_title: - bias: - opt_name: - Optional name - string to append to the beginning of the plot series name - properties: - color_list: - hover_text_col: - plot_mode: - smart_format: - format_dict: - overpotential_given: - If true then the overpotential is given explicitely in the - input dataframe with name "overpotential" - """ - #| - __init__ - - #| - Setting Instance Attributes - self.fe_df = free_energy_df - # self.sys_props = system_properties - - self.group = group - self.state_title = state_title - self.fe_title = free_e_title - - self.bias = bias - - # self.rxn_x_coord_array = rxn_x_coord_array - # print(self.rxn_x_coord_array) # TEMP | PRINT - - self.name_i = name_i - self.opt_name = opt_name - - self.properties = properties - - self.color_list = color_list - self.color = color - self.hover_text_col = hover_text_col - self.plot_mode = plot_mode - self.smart_format = smart_format - self.format_dict = format_dict - - # self.overpotential_type = overpotential_type - self.rxn_type = rxn_type - - self.add_overpot = add_overpot - self.overpotential_given = overpotential_given - - # self.i_cnt = i_cnt - #__| - - if self.rxn_type == "ORR": - self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] - self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - - elif self.rxn_type == "OER": - self.rxn_mech_states = ["bulk", "oh", "o", "ooh", "bulk"] - self.ideal_energy = [0, 1.23, 2.46, 3.69, 4.92] - - self.property_key_list = property_key_list - - # Doing this with a class method instead of in the analysis script - if properties is None: - self.properties = self.__create_property_dict__() - - if free_energy_df is not None: - self.add_bulk_entry() - self.fill_missing_data() - - # TEMP | Active Development - self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk - self.num_of_states_new = self.__num_of_states__() - - self.energy_lst = self.rxn_energy_lst() - # self.energy_lst_new = self.rxn_energy_lst_new() - - self.num_of_elec = range(self.num_of_states)[::-1] - self.overpotential = self.calc_overpotential()[0] - self.limiting_step = self.calc_overpotential()[1] - # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() - self.overpotential_h2o2 = self.calc_overpotential_h2o2() - self.overpotential_OER = self.calc_overpotential_OER()[0] - - self.energy_states_dict = self.__energy_states_dict__() - - if fill_missing_data_w_scaling: - self.__fill_nan_values__() - - # TODO | Put this outside of the if-statement - self.series_name = self.__series_plot_name__( - opt_name=self.opt_name, - properties=self.properties, - overpotential_type=self.rxn_type, - add_overpot=self.add_overpot, - ) - #__| - - def __fill_nan_values__(self): - """Fill nan adsorption energy values from scaling relations.""" - #| - tmp - energy_dict = self.energy_states_dict - if True in list(np.isnan(list(energy_dict.values()))): - - print("There is a nan in the energy dict!!!") - - if np.isnan(energy_dict["ooh"]): - if not np.isnan(energy_dict["oh"]): - print("*OOH energy set by *OH and standard scaling") - ooh_new = 1 * energy_dict["oh"] + 3.2 - energy_dict["ooh"] = ooh_new - - if np.isnan(energy_dict["o"]): - if not np.isnan(energy_dict["oh"]): - print("*O energy set by *OH and standard scaling") - o_new = 2 * energy_dict["oh"] + 0. - energy_dict["o"] = o_new - - if np.isnan(energy_dict["oh"]): - if not np.isnan(energy_dict["ooh"]): - print("*OH energy set by *OOH and standard scaling") - oh_new = energy_dict["ooh"] - 3.2 - energy_dict["oh"] = oh_new - - self.energy_states_dict = energy_dict - #__| - - def __num_of_states__(self): - """Return number of unique states. - - Looks at the uniqe number of entries in the 'adsorbate' column of the - data frame. The correct number of states for the OER and/or ORR - reaction are 4, only 2 states are needed for the peroxide reaction. - """ - #| - __num_of_states - df_i = self.fe_df - - num_of_states = len(set(df_i["adsorbate"].tolist())) - - err_mess = "There are not enough unique calcs (less than 4)" - assert num_of_states >= 4, err_mess - - return(num_of_states) - #__| - - def __energy_states_dict__(self): - """ - """ - #| - __energy_states_dict__ - - energy_lst = self.energy_lst - rxn_mech_states = self.rxn_mech_states - - energy_states_dict = dict(zip(rxn_mech_states, energy_lst)) - energy_states_dict.pop("bulk", None) - - return(energy_states_dict) - # energy_states_dict - #__| - - def __create_property_dict__(self): - """ - """ - #| - __create_property_dict__ - df_i = self.fe_df - - def all_same_val(df_i, prop_i, val_1): - """ - """ - #| - all_same_val - out_list = [] - for i in df_i[prop_i].tolist(): - if i == val_1: - out_list.append(True) - else: - out_list.append(False) - - out_i = all(out_list) - return(out_i) - - # [True if i == val_1 else False for i in - # df_i[prop_i].tolist()], - #__| - - if self.property_key_list is not None: - prop_dict_i = {} - for prop_i in self.property_key_list: - val_1 = df_i[prop_i].tolist()[0] - - all_same_value = all_same_val(df_i, prop_i, val_1) - # all_same_value = all( - # [True if i == val_1 else False for i in - # df_i[prop_i].tolist()], - # ) - - if all_same_value: - prop_dict_i[prop_i] = str(val_1) - else: - prop_dict_i[prop_i] = str(None) - - return(prop_dict_i) - else: - return({}) - #__| - - def add_bulk_entry(self, - bulk_e=0.0, - ): - """ - Append a row entry to data frame corresponding to bulk state. - - Args: - bulk_e: - """ - #| - add_bulk_entry - df = self.fe_df - bulk_df = pd.DataFrame([{ - "adsorbate": "bulk", - "ads_e": bulk_e, - }]) - - # TEMP - # df = df.append(bulk_df, ignore_index=True) - df = df.append(bulk_df, ignore_index=True, sort=True) - - self.fe_df = df - #__| - - def rxn_energy_lst_h2o2(self): - """Construct energy list of h2o2 FED.""" - #| - rxn_energy_lst_h2o2 - # h2o2_e = 3.52 - - df = self.fe_df - - free_energy_list = [] - for index, row in df.iterrows(): - if row["adsorbate"] == "bulk" or row["adsorbate"] == "ooh": - free_energy_list.append(row["ads_e"]) - - # TODO | Make this parse the reaction array instead of reaction list - # Checking length of energy list - if len(free_energy_list) != 2: - # raise ValueError("Not the correct # of steps for H2O2") - print("Not the correct # of steps for H2O2") - - free_energy_list[0] += 4.92 - free_energy_list.append(3.52) - - return(free_energy_list) - #__| - - def property_list(self, column_name): - """General method to create a list from a column in the dataframe. - - The length of the list will correspond to the steps in the ORR - mechanism. - - Args: - column_name: - """ - #| - property_list - df = self.fe_df - - property_list = [] - for state in self.rxn_mech_states: - tmp = df.loc[df[self.state_title] == state] - tmp1 = tmp.iloc[0][column_name] - property_list.append(tmp1) - - # free_energy_list[0] += 4.92 - - return(property_list) - #__| - - def fill_missing_data(self): - """ - """ - #| - fill_missing_data - df = self.fe_df - df_missing_data = pd.DataFrame() - for state in self.rxn_mech_states: - df_state = df.loc[df[self.state_title] == state] - - #| - If df is missing state fill in row with NaN for energy - if df_state.empty: - df_state = pd.DataFrame([{ - self.state_title: state, - self.fe_title: np.nan, - }]) - df_missing_data = df_missing_data.append(df_state) - #__| - - self.fe_df = self.fe_df.append(df_missing_data, sort=True) - #__| - - def rxn_energy_lst(self): - """List corresponding to the steps of ORR. - - (1. O2, 2. *OOH, 3. *O, 4. *OH, 5. 2H2O) - """ - #| - rxn_energy_lst - df = self.fe_df - - free_energy_list = [] - for state in self.rxn_mech_states: - df_state = df.loc[df[self.state_title] == state] - - # print(df_state) - - #| - __old__ - # Not sure what this was trying to accomplish - # if len(df_state) == 2: - # state_energy_list = [] - # for j_cnt, row_j in df_state.iterrows(): - # energy_j = row_j[self.fe_title] - # state_energy_list.append(energy_j) - #__| - - #| - If df is missing state fill in row with NaN for energy - if df_state.empty: - df_state = pd.DataFrame([{ - self.state_title: state, - self.fe_title: np.nan, - }]) - #__| - - # This just takes the first species - # If you feed a df with more than one entry per species, then - # this will stupidly choose the first one - state_energy_1 = df_state.iloc[0][self.fe_title] - - #| - __old__ - # if type(state_energy_1) != float: - # print(type(state_energy_1)) - # print("DSKFJKLSDJFSjk_d--_d-d-_D_D_d-d-d-d-d___D_D_D_") - # print( - # "state_energy_1: ", - # str(state_energy_1), - # ) - # - # print( - # "type: ", - # str(type(state_energy_1)) - # ) - # - # print(isinstance(state_energy_1, np.float)) - # print(float(state_energy_1)) - # print(type(float(state_energy_1))) - # print(np.isnan(state_energy_1)) - # if isinstance(state_energy_1, np.float) is False: - # print("lkjfksjd") - #__| - - free_energy_list.append(state_energy_1) - - if self.rxn_type == "ORR": - free_energy_list[0] += 4.92 - elif self.rxn_type == "OER": - free_energy_list[-1] += 4.92 - else: - free_energy_list[0] += 4.92 - - return(free_energy_list) - #__| - - def rxn_energy_lst_new(self): - """ - """ - #| - rxn_energy_lst_new - df = self.fe_df - free_energy_list = [] - for state in self.rxn_mech_states: - df_state = df.loc[df[self.state_title] == state] - - #| - If df is missing state fill in row with NaN for energy - if df_state.empty: - df_state = pd.DataFrame([{ - self.state_title: state, - self.fe_title: np.nan, - }]) - #__| - - state_energy_list = [] - for j_cnt, row_j in df_state.iterrows(): - energy_j = row_j[self.fe_title] - state_energy_list.append(energy_j) - - free_energy_list.append(state_energy_list) - - # tmp1 = df_state.iloc[0][self.fe_title] - # free_energy_list.append(tmp1) - - if self.rxn_type == "ORR": - free_energy_list_0_new = [i + 4.92 for i in free_energy_list[0]] - free_energy_list[0] = free_energy_list_0_new - - # free_energy_list[0] += 4.92 - - elif self.rxn_type == "OER": - # free_energy_list[-1] += 4.92 - free_energy_list_new = [i + 4.92 for i in free_energy_list[-1]] - free_energy_list[-1] = free_energy_list_new - - else: - free_energy_list[0] += 4.92 - - return(free_energy_list) - #__| - - def apply_bias(self, bias, energy_list): - """Apply bias to free energies. - - Applies a potential to every species in the 4 and 2-electron process - and adjusts their free energies accordingly - """ - #| - apply_bias - mod_free_e_lst = [] # Free energy reaction path at applied bias - for energy, elec in zip(energy_list, range(len(energy_list))[::-1]): - mod_free_e_lst.append(energy - elec * bias) - - return(mod_free_e_lst) - #__| - - def calc_overpotential(self): - """ - Calculate overpotential for 4e- process. - - Returns the limiting overpotential for the given species and the - limiting reaction step in the form of a list, species_A -> species_B is - [species_A, species_B] - """ - #| - calc_overpotential - if self.overpotential_given: - out_list = [None, None] - if "overpotential" in list(self.fe_df): - overpot_i = self.fe_df["overpotential"].tolist()[0] - out_list[0] = overpot_i - else: - print("No 'overpotential' column in df") - - else: - rxn_spec = self.rxn_mech_states - - overpotential_lst = [] - for energy_i in enumerate(self.energy_lst[:-1]): - energy_i_plus1 = self.energy_lst[energy_i[0] + 1] - overpotential_i = 1.23 + energy_i_plus1 - energy_i[1] - overpotential_lst.append(overpotential_i) - - overpotential = max(overpotential_lst) - # overpotential = min(overpotential_lst) - - lim_step_index = overpotential_lst.index(overpotential) - - limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] - out_list = [overpotential, limiting_step] - - return(out_list) - #__| - - def calc_overpotential_OER(self): - """Calculate the OER overpotential of a ORR series.""" - #| - calc_overpotential_OER - rxn_spec = self.rxn_mech_states - - overpotential_lst = [] - for energy_i in enumerate(self.energy_lst[:-1]): - energy_i_plus1 = self.energy_lst[energy_i[0] + 1] - overpotential_i = energy_i_plus1 - energy_i[1] - 1.23 - overpotential_lst.append(overpotential_i) - - overpotential = max(overpotential_lst) - lim_step_index = overpotential_lst.index(overpotential) - - limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] - out_list = [overpotential, limiting_step] - - return(out_list) - #__| - - def calc_overpotential_h2o2(self): - """ - Calculate overpotential for 2e- process. - - The overpotential for the 2e- process depends only on the energy of the - *OOH intermediate - """ - #| - calc_overpotential_h2o2 - df = self.fe_df - ooh_row = df[df["adsorbate"] == "ooh"] - ooh_ads_e = ooh_row.iloc[0]["ads_e"] - - op_4e = ooh_ads_e - 4.22 - - return(op_4e) - #__| - - def __series_plot_name__(self, - opt_name=None, - properties=None, - overpotential_type="ORR", - add_overpot=True, - use_key_in_name=False, - ): - """Create name for series. - - Args: - bias: - opt_name: - properties: - color_list: - hover_text_col: - plot_mode: - smart_format: - overpotential_type: - """ - #| - __series_plot_name__ - - #| - Getting appropriate Overpotential - if add_overpot: - if overpotential_type == "ORR": - overpot_i = self.overpotential - elif overpotential_type == "OER": - overpot_i = self.overpotential_OER - elif overpotential_type == "H2O2": - overpot_i = self.overpotential_h2o2 - else: - overpot_i = self.overpotential - else: - overpot_i = "" - #__| - - #| - Connecting properties key: values into string - if properties is not None: - properties_string_name = "" - for key_i, value_i in properties.items(): - - if use_key_in_name is True: - properties_string_name += str(key_i) - properties_string_name += "_" - properties_string_name += str(value_i) - - properties_string_name += " | " - - # Removing the trailig ' | ' - properties_string_name = properties_string_name[0:-3] - else: - properties_string_name = "" - #__| - - #| - Data Series Name - if opt_name is not None: - name_i = opt_name + ": " + properties_string_name - - else: - name_i = properties_string_name - - if add_overpot: - name_i += " (OP: " + str(round(overpot_i, 2)) + ")" - - #__| - - # NEW | If name_i given, then just use that - if self.name_i is not None: - return(self.name_i) - - return(name_i) - #__| - - #__| +#!/usr/bin/env python + +"""ORR energetics classes and methods. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import copy + +import numpy as np +import pandas as pd + +from plotly.graph_objs import Scatter +pd.options.mode.chained_assignment = None +#__| + +class ORR_Free_E_Series(): + """ORR free energy diagram series class. + + Still a work in progress + Take a 2nd look at how the bulk/bare state is being taken care of + + # TODO Break series name with a '
' so that the legend entries have a + line break + # TODO Figure out which class attributes aren't being used anymore + # TODO Calculate *OOH from scaling, as an option (Colin does this) + + # TODO | The color_list approach is not good + """ + + #| - ORR_Free_E_Series **************************************************** + def __init__(self, + free_energy_df=None, + state_title="adsorbate", + free_e_title="ads_e", + bias=0., + group=None, + name_i=None, + opt_name=None, + properties=None, + property_key_list=None, + color_list=None, + color=None, + hover_text_col=None, + plot_mode="all", + smart_format=None, + format_dict=None, + add_overpot=True, + rxn_type="ORR", + fill_missing_data_w_scaling=True, + overpotential_given=False, + ): + """ + Input variables to class instance. + + TODO: Make sure that format_dict is used if it's supplied by user + + Args: + free_energy_df: + Pandas dataframe containing the adsorbates as rows + Required columns, adsorbate, free energy + state_title: + free_e_title: + bias: + opt_name: + Optional name + string to append to the beginning of the plot series name + properties: + color_list: + hover_text_col: + plot_mode: + smart_format: + format_dict: + overpotential_given: + If true then the overpotential is given explicitely in the + input dataframe with name "overpotential" + """ + #| - __init__ + + #| - Setting Instance Attributes + self.fe_df = free_energy_df + # self.sys_props = system_properties + + self.group = group + self.state_title = state_title + self.fe_title = free_e_title + + self.bias = bias + + # self.rxn_x_coord_array = rxn_x_coord_array + # print(self.rxn_x_coord_array) # TEMP | PRINT + + self.name_i = name_i + self.opt_name = opt_name + + self.properties = properties + + self.color_list = color_list + self.color = color + self.hover_text_col = hover_text_col + self.plot_mode = plot_mode + self.smart_format = smart_format + self.format_dict = format_dict + + # self.overpotential_type = overpotential_type + self.rxn_type = rxn_type + + self.add_overpot = add_overpot + self.overpotential_given = overpotential_given + + # self.i_cnt = i_cnt + #__| + + if self.rxn_type == "ORR": + self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] + self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] + + elif self.rxn_type == "OER": + self.rxn_mech_states = ["bulk", "oh", "o", "ooh", "bulk"] + self.ideal_energy = [0, 1.23, 2.46, 3.69, 4.92] + + self.property_key_list = property_key_list + + # Doing this with a class method instead of in the analysis script + if properties is None: + self.properties = self.__create_property_dict__() + + if free_energy_df is not None: + self.add_bulk_entry() + self.fill_missing_data() + + # TEMP | Active Development + self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk + self.num_of_states_new = self.__num_of_states__() + + self.energy_lst = self.rxn_energy_lst() + # self.energy_lst_new = self.rxn_energy_lst_new() + + self.num_of_elec = range(self.num_of_states)[::-1] + self.overpotential = self.calc_overpotential()[0] + self.limiting_step = self.calc_overpotential()[1] + # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] + self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() + self.overpotential_h2o2 = self.calc_overpotential_h2o2() + self.overpotential_OER = self.calc_overpotential_OER()[0] + + self.energy_states_dict = self.__energy_states_dict__() + + if fill_missing_data_w_scaling: + self.__fill_nan_values__() + + # TODO | Put this outside of the if-statement + self.series_name = self.__series_plot_name__( + opt_name=self.opt_name, + properties=self.properties, + overpotential_type=self.rxn_type, + add_overpot=self.add_overpot, + ) + #__| + + def __fill_nan_values__(self): + """Fill nan adsorption energy values from scaling relations.""" + #| - tmp + energy_dict = self.energy_states_dict + if True in list(np.isnan(list(energy_dict.values()))): + + print("There is a nan in the energy dict!!!") + + if np.isnan(energy_dict["ooh"]): + if not np.isnan(energy_dict["oh"]): + print("*OOH energy set by *OH and standard scaling") + ooh_new = 1 * energy_dict["oh"] + 3.2 + energy_dict["ooh"] = ooh_new + + if np.isnan(energy_dict["o"]): + if not np.isnan(energy_dict["oh"]): + print("*O energy set by *OH and standard scaling") + o_new = 2 * energy_dict["oh"] + 0. + energy_dict["o"] = o_new + + if np.isnan(energy_dict["oh"]): + if not np.isnan(energy_dict["ooh"]): + print("*OH energy set by *OOH and standard scaling") + oh_new = energy_dict["ooh"] - 3.2 + energy_dict["oh"] = oh_new + + self.energy_states_dict = energy_dict + #__| + + def __num_of_states__(self): + """Return number of unique states. + + Looks at the uniqe number of entries in the 'adsorbate' column of the + data frame. The correct number of states for the OER and/or ORR + reaction are 4, only 2 states are needed for the peroxide reaction. + """ + #| - __num_of_states + df_i = self.fe_df + + num_of_states = len(set(df_i["adsorbate"].tolist())) + + err_mess = "There are not enough unique calcs (less than 4)" + assert num_of_states >= 4, err_mess + + return(num_of_states) + #__| + + def __energy_states_dict__(self): + """ + """ + #| - __energy_states_dict__ + + energy_lst = self.energy_lst + rxn_mech_states = self.rxn_mech_states + + energy_states_dict = dict(zip(rxn_mech_states, energy_lst)) + energy_states_dict.pop("bulk", None) + + return(energy_states_dict) + # energy_states_dict + #__| + + def __create_property_dict__(self): + """ + """ + #| - __create_property_dict__ + df_i = self.fe_df + + def all_same_val(df_i, prop_i, val_1): + """ + """ + #| - all_same_val + out_list = [] + for i in df_i[prop_i].tolist(): + if i == val_1: + out_list.append(True) + else: + out_list.append(False) + + out_i = all(out_list) + return(out_i) + + # [True if i == val_1 else False for i in + # df_i[prop_i].tolist()], + #__| + + if self.property_key_list is not None: + prop_dict_i = {} + for prop_i in self.property_key_list: + val_1 = df_i[prop_i].tolist()[0] + + all_same_value = all_same_val(df_i, prop_i, val_1) + # all_same_value = all( + # [True if i == val_1 else False for i in + # df_i[prop_i].tolist()], + # ) + + if all_same_value: + prop_dict_i[prop_i] = str(val_1) + else: + prop_dict_i[prop_i] = str(None) + + return(prop_dict_i) + else: + return({}) + #__| + + def add_bulk_entry(self, + bulk_e=0.0, + ): + """ + Append a row entry to data frame corresponding to bulk state. + + Args: + bulk_e: + """ + #| - add_bulk_entry + df = self.fe_df + bulk_df = pd.DataFrame([{ + "adsorbate": "bulk", + "ads_e": bulk_e, + }]) + + # TEMP + # df = df.append(bulk_df, ignore_index=True) + df = df.append(bulk_df, ignore_index=True, sort=True) + + self.fe_df = df + #__| + + def rxn_energy_lst_h2o2(self): + """Construct energy list of h2o2 FED.""" + #| - rxn_energy_lst_h2o2 + # h2o2_e = 3.52 + + df = self.fe_df + + free_energy_list = [] + for index, row in df.iterrows(): + if row["adsorbate"] == "bulk" or row["adsorbate"] == "ooh": + free_energy_list.append(row["ads_e"]) + + # TODO | Make this parse the reaction array instead of reaction list + # Checking length of energy list + if len(free_energy_list) != 2: + # raise ValueError("Not the correct # of steps for H2O2") + print("Not the correct # of steps for H2O2") + + free_energy_list[0] += 4.92 + free_energy_list.append(3.52) + + return(free_energy_list) + #__| + + def property_list(self, column_name): + """General method to create a list from a column in the dataframe. + + The length of the list will correspond to the steps in the ORR + mechanism. + + Args: + column_name: + """ + #| - property_list + df = self.fe_df + + property_list = [] + for state in self.rxn_mech_states: + tmp = df.loc[df[self.state_title] == state] + tmp1 = tmp.iloc[0][column_name] + property_list.append(tmp1) + + # free_energy_list[0] += 4.92 + + return(property_list) + #__| + + def fill_missing_data(self): + """ + """ + #| - fill_missing_data + df = self.fe_df + df_missing_data = pd.DataFrame() + for state in self.rxn_mech_states: + df_state = df.loc[df[self.state_title] == state] + + #| - If df is missing state fill in row with NaN for energy + if df_state.empty: + df_state = pd.DataFrame([{ + self.state_title: state, + self.fe_title: np.nan, + }]) + df_missing_data = df_missing_data.append(df_state) + #__| + + self.fe_df = self.fe_df.append(df_missing_data, sort=True) + #__| + + def rxn_energy_lst(self): + """List corresponding to the steps of ORR. + + (1. O2, 2. *OOH, 3. *O, 4. *OH, 5. 2H2O) + """ + #| - rxn_energy_lst + df = self.fe_df + + free_energy_list = [] + for state in self.rxn_mech_states: + df_state = df.loc[df[self.state_title] == state] + + # print(df_state) + + #| - __old__ + # Not sure what this was trying to accomplish + # if len(df_state) == 2: + # state_energy_list = [] + # for j_cnt, row_j in df_state.iterrows(): + # energy_j = row_j[self.fe_title] + # state_energy_list.append(energy_j) + #__| + + #| - If df is missing state fill in row with NaN for energy + if df_state.empty: + df_state = pd.DataFrame([{ + self.state_title: state, + self.fe_title: np.nan, + }]) + #__| + + # This just takes the first species + # If you feed a df with more than one entry per species, then + # this will stupidly choose the first one + state_energy_1 = df_state.iloc[0][self.fe_title] + + #| - __old__ + # if type(state_energy_1) != float: + # print(type(state_energy_1)) + # print("DSKFJKLSDJFSjk_d--_d-d-_D_D_d-d-d-d-d___D_D_D_") + # print( + # "state_energy_1: ", + # str(state_energy_1), + # ) + # + # print( + # "type: ", + # str(type(state_energy_1)) + # ) + # + # print(isinstance(state_energy_1, np.float)) + # print(float(state_energy_1)) + # print(type(float(state_energy_1))) + # print(np.isnan(state_energy_1)) + # if isinstance(state_energy_1, np.float) is False: + # print("lkjfksjd") + #__| + + free_energy_list.append(state_energy_1) + + if self.rxn_type == "ORR": + free_energy_list[0] += 4.92 + elif self.rxn_type == "OER": + free_energy_list[-1] += 4.92 + else: + free_energy_list[0] += 4.92 + + return(free_energy_list) + #__| + + def rxn_energy_lst_new(self): + """ + """ + #| - rxn_energy_lst_new + df = self.fe_df + free_energy_list = [] + for state in self.rxn_mech_states: + df_state = df.loc[df[self.state_title] == state] + + #| - If df is missing state fill in row with NaN for energy + if df_state.empty: + df_state = pd.DataFrame([{ + self.state_title: state, + self.fe_title: np.nan, + }]) + #__| + + state_energy_list = [] + for j_cnt, row_j in df_state.iterrows(): + energy_j = row_j[self.fe_title] + state_energy_list.append(energy_j) + + free_energy_list.append(state_energy_list) + + # tmp1 = df_state.iloc[0][self.fe_title] + # free_energy_list.append(tmp1) + + if self.rxn_type == "ORR": + free_energy_list_0_new = [i + 4.92 for i in free_energy_list[0]] + free_energy_list[0] = free_energy_list_0_new + + # free_energy_list[0] += 4.92 + + elif self.rxn_type == "OER": + # free_energy_list[-1] += 4.92 + free_energy_list_new = [i + 4.92 for i in free_energy_list[-1]] + free_energy_list[-1] = free_energy_list_new + + else: + free_energy_list[0] += 4.92 + + return(free_energy_list) + #__| + + def apply_bias(self, bias, energy_list): + """Apply bias to free energies. + + Applies a potential to every species in the 4 and 2-electron process + and adjusts their free energies accordingly + """ + #| - apply_bias + if self.rxn_type == "ORR": + flip_energy_list = False + bool_flip = -1 + elif self.rxn_type == "OER": + flip_energy_list = True + bool_flip = +1 + + e_lst = energy_list + + mod_free_e_lst = [] # Free energy reaction path at applied bias + for en, elec in zip(e_lst, range(len(e_lst))[::bool_flip]): + mod_free_e_lst.append(en - elec * bias) + + return(mod_free_e_lst) + #__| + + def calc_overpotential(self): + """ + Calculate overpotential for 4e- process. + + Returns the limiting overpotential for the given species and the + limiting reaction step in the form of a list, species_A -> species_B is + [species_A, species_B] + """ + #| - calc_overpotential + if self.overpotential_given: + out_list = [None, None] + if "overpotential" in list(self.fe_df): + overpot_i = self.fe_df["overpotential"].tolist()[0] + out_list[0] = overpot_i + else: + print("No 'overpotential' column in df") + + else: + rxn_spec = self.rxn_mech_states + + overpotential_lst = [] + for energy_i in enumerate(self.energy_lst[:-1]): + energy_i_plus1 = self.energy_lst[energy_i[0] + 1] + overpotential_i = 1.23 + energy_i_plus1 - energy_i[1] + overpotential_lst.append(overpotential_i) + + overpotential = max(overpotential_lst) + # overpotential = min(overpotential_lst) + + lim_step_index = overpotential_lst.index(overpotential) + + limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] + out_list = [overpotential, limiting_step] + + return(out_list) + #__| + + def calc_overpotential_OER(self): + """Calculate the OER overpotential of a ORR series.""" + #| - calc_overpotential_OER + rxn_spec = self.rxn_mech_states + + overpotential_lst = [] + for energy_i in enumerate(self.energy_lst[:-1]): + energy_i_plus1 = self.energy_lst[energy_i[0] + 1] + overpotential_i = energy_i_plus1 - energy_i[1] - 1.23 + overpotential_lst.append(overpotential_i) + + overpotential = max(overpotential_lst) + lim_step_index = overpotential_lst.index(overpotential) + + limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] + out_list = [overpotential, limiting_step] + + return(out_list) + #__| + + def calc_overpotential_h2o2(self): + """ + Calculate overpotential for 2e- process. + + The overpotential for the 2e- process depends only on the energy of the + *OOH intermediate + """ + #| - calc_overpotential_h2o2 + df = self.fe_df + ooh_row = df[df["adsorbate"] == "ooh"] + ooh_ads_e = ooh_row.iloc[0]["ads_e"] + + op_4e = ooh_ads_e - 4.22 + + return(op_4e) + #__| + + def __series_plot_name__(self, + opt_name=None, + properties=None, + overpotential_type="ORR", + add_overpot=True, + use_key_in_name=False, + ): + """Create name for series. + + Args: + bias: + opt_name: + properties: + color_list: + hover_text_col: + plot_mode: + smart_format: + overpotential_type: + """ + #| - __series_plot_name__ + + #| - Getting appropriate Overpotential + if add_overpot: + if overpotential_type == "ORR": + overpot_i = self.overpotential + elif overpotential_type == "OER": + overpot_i = self.overpotential_OER + elif overpotential_type == "H2O2": + overpot_i = self.overpotential_h2o2 + else: + overpot_i = self.overpotential + else: + overpot_i = "" + #__| + + #| - Connecting properties key: values into string + if properties is not None: + properties_string_name = "" + for key_i, value_i in properties.items(): + + if use_key_in_name is True: + properties_string_name += str(key_i) + properties_string_name += "_" + properties_string_name += str(value_i) + + properties_string_name += " | " + + # Removing the trailig ' | ' + properties_string_name = properties_string_name[0:-3] + else: + properties_string_name = "" + #__| + + #| - Data Series Name + if opt_name is not None: + name_i = opt_name + ": " + properties_string_name + + else: + name_i = properties_string_name + + if add_overpot: + name_i += " (OP: " + str(round(overpot_i, 2)) + ")" + + #__| + + # NEW | If name_i given, then just use that + if self.name_i is not None: + return(self.name_i) + + return(name_i) + #__| + + #__| diff --git a/periodic_table.json b/periodic_table.json index 3fc7e63..164a615 100644 --- a/periodic_table.json +++ b/periodic_table.json @@ -1,9636 +1,9636 @@ -{ - "Ac": { - "Atomic mass": 227.0, - "Atomic no": 89, - "Atomic orbitals": { - "1s": -3443.110367, - "2p": -572.7627, - "2s": -592.622878, - "3d": -119.541743, - "3p": -137.654394, - "3s": -147.320716, - "4d": -23.57061, - "4f": -12.278225, - "4p": -31.761846, - "4s": -36.15826, - "5d": -3.222752, - "5p": -6.06511, - "5s": -7.713078, - "6d": -0.137786, - "6p": -0.744524, - "6s": -1.19698, - "7s": -0.126551 - }, - "Atomic radius": 1.95, - "Atomic radius calculated": "no data", - "Boiling point": "3573 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "10070 kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].6d1.7s2", - "Ionic radii": { - "3": 1.26 - }, - "Liquid range": "2250 K", - "Melting point": "1323 K", - "Mendeleev no": 48, - "Mineral hardness": "no data", - "Molar volume": "22.55 cm3", - "Name": "Actinium", - "Oxidation states": [ - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.26, - "ionic_radius": 1.12 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "12 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.1, - "Youngs modulus": "no data GPa" - }, - "Ag": { - "Atomic mass": 107.8682, - "Atomic no": 47, - "Atomic orbitals": { - "1s": -900.324578, - "2p": -120.913351, - "2s": -129.859807, - "3d": -13.367803, - "3p": -20.06763, - "3s": -23.678437, - "4d": -0.298706, - "4p": -2.086602, - "4s": -3.22309, - "5s": -0.157407 - }, - "Atomic radius": 1.6, - "Atomic radius calculated": 1.65, - "Boiling point": "2435 K", - "Brinell hardness": "24.5 MN m-2", - "Bulk modulus": "100 GPa", - "Coefficient of linear thermal expansion": "18.9 x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "no data K", - "Density of solid": "10490 kg m-3", - "Electrical resistivity": "1.63 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s1", - "ICSD oxidation states": [ - 1, - 2, - 3 - ], - "Ionic radii": { - "1": 1.29, - "2": 1.08, - "3": 0.89 - }, - "Liquid range": "1200.07 K", - "Melting point": "1234.93 K", - "Mendeleev no": 71, - "Mineral hardness": "2.5", - "Molar volume": "10.27 cm3", - "Name": "Silver", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "0.37", - "Reflectivity": "97 %", - "Refractive index": "no data", - "Rigidity modulus": "30 GPa", - "Shannon radii": { - "1": { - "II": { - "": { - "crystal_radius": 0.81, - "ionic_radius": 0.67 - } - }, - "IV": { - "": { - "crystal_radius": 1.14, - "ionic_radius": 1.0 - } - }, - "IVSQ": { - "": { - "crystal_radius": 1.16, - "ionic_radius": 1.02 - } - }, - "V": { - "": { - "crystal_radius": 1.23, - "ionic_radius": 1.09 - } - }, - "VI": { - "": { - "crystal_radius": 1.29, - "ionic_radius": 1.15 - } - }, - "VII": { - "": { - "crystal_radius": 1.36, - "ionic_radius": 1.22 - } - }, - "VIII": { - "": { - "crystal_radius": 1.42, - "ionic_radius": 1.28 - } - } - }, - "2": { - "IVSQ": { - "": { - "crystal_radius": 0.93, - "ionic_radius": 0.79 - } - }, - "VI": { - "": { - "crystal_radius": 1.08, - "ionic_radius": 0.94 - } - } - }, - "3": { - "IVSQ": { - "": { - "crystal_radius": 0.81, - "ionic_radius": 0.67 - } - }, - "VI": { - "": { - "crystal_radius": 0.89, - "ionic_radius": 0.75 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "430 W m-1 K-1", - "Van der waals radius": 1.72, - "Velocity of sound": "2600 m s-1", - "Vickers hardness": "251 MN m-2", - "X": 1.93, - "Youngs modulus": "83 GPa" - }, - "Al": { - "Atomic mass": 26.9815386, - "Atomic no": 13, - "Atomic orbitals": { - "1s": -55.156044, - "2p": -2.564018, - "2s": -3.934827, - "3p": -0.102545, - "3s": -0.286883 - }, - "Atomic radius": 1.25, - "Atomic radius calculated": 1.18, - "Boiling point": "2792 K", - "Brinell hardness": "245 MN m-2", - "Bulk modulus": "76 GPa", - "Coefficient of linear thermal expansion": "23.1 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "2700 kg m-3", - "Electrical resistivity": "2.7 10-8 Ω m", - "Electronic structure": "[Ne].3s2.3p1", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "3": 0.675 - }, - "Liquid range": "1858.53 K", - "Melting point": "933.47 K", - "Mendeleev no": 80, - "Mineral hardness": "2.75", - "Molar volume": "10.00 cm3", - "Name": "Aluminum", - "Oxidation states": [ - 1, - 3 - ], - "Poissons ratio": "0.35", - "Reflectivity": "71 %", - "Refractive index": "no data", - "Rigidity modulus": "26 GPa", - "Shannon radii": { - "3": { - "IV": { - "": { - "crystal_radius": 0.53, - "ionic_radius": 0.39 - } - }, - "V": { - "": { - "crystal_radius": 0.62, - "ionic_radius": 0.48 - } - }, - "VI": { - "": { - "crystal_radius": 0.675, - "ionic_radius": 0.535 - } - } - } - }, - "Superconduction temperature": "1.175 K", - "Thermal conductivity": "235 W m-1 K-1", - "Van der waals radius": 1.84, - "Velocity of sound": "5100 m s-1", - "Vickers hardness": "167 MN m-2", - "X": 1.61, - "Youngs modulus": "70 GPa", - "NMR Quadrupole Moment": { - "Al-27": 146.6 - } - }, - "Am": { - "Atomic mass": 243.0, - "Atomic no": 95, - "Atomic orbitals": "no data", - "Atomic radius": 1.75, - "Atomic radius calculated": "no data", - "Boiling point": "2880 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f7.7s2", - "Ionic radii": { - "2": 1.4, - "3": 1.115, - "4": 0.99 - }, - "Liquid range": "1431 K", - "Melting point": "1449 K", - "Mendeleev no": 42, - "Mineral hardness": "no data", - "Molar volume": "17.63 cm3", - "Name": "Americium", - "Oxidation states": [ - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "2": { - "VII": { - "": { - "crystal_radius": 1.35, - "ionic_radius": 1.21 - } - }, - "VIII": { - "": { - "crystal_radius": 1.4, - "ionic_radius": 1.26 - } - }, - "IX": { - "": { - "crystal_radius": 1.45, - "ionic_radius": 1.31 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.115, - "ionic_radius": 0.975 - } - }, - "VIII": { - "": { - "crystal_radius": 1.23, - "ionic_radius": 1.09 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.99, - "ionic_radius": 0.85 - } - }, - "VIII": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - } - } - }, - "Superconduction temperature": "0.6 K", - "Thermal conductivity": "10 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Ar": { - "Atomic mass": 39.948, - "Atomic no": 18, - "Atomic orbitals": { - "1s": -113.800134, - "2p": -8.443439, - "2s": -10.794172, - "3p": -0.38233, - "3s": -0.883384 - }, - "Atomic radius": 0.71, - "Atomic radius calculated": 0.71, - "Boiling point": "87.3 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Critical temperature": "150.8 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Ne].3s2.3p6", - "Liquid range": "3.5 K", - "Max oxidation state": 0.0, - "Melting point": "83.8 K", - "Mendeleev no": 3, - "Min oxidation state": 0.0, - "Mineral hardness": "no data", - "Molar volume": "22.56 cm3", - "Name": "Argon", - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000281", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.01772 W m-1 K-1", - "Van der waals radius": 1.88, - "Velocity of sound": "319 m s-1", - "Vickers hardness": "no data MN m-2", - "Youngs modulus": "no data GPa" - }, - "As": { - "Atomic mass": 74.9216, - "Atomic no": 33, - "Atomic orbitals": { - "1s": -423.336658, - "2p": -47.527869, - "2s": -53.093086, - "3d": -1.542767, - "3p": -4.851725, - "3s": -6.730755, - "4p": -0.197497, - "4s": -0.52367 - }, - "Atomic radius": 1.15, - "Atomic radius calculated": 1.14, - "Boiling point": "887 K", - "Brinell hardness": "1440 MN m-2", - "Bulk modulus": "22 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -3, - 3, - 5 - ], - "Critical temperature": "1700 K", - "Density of solid": "5727 kg m-3", - "Electrical resistivity": "33 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2.4p3", - "ICSD oxidation states": [ - 2, - 3, - 5, - -2, - -3, - -1 - ], - "Ionic radii": { - "3": 0.72, - "5": 0.6 - }, - "Liquid range": "203 K", - "Melting point": "1090 K", - "Mendeleev no": 89, - "Mineral hardness": "3.5", - "Molar volume": "12.95 cm3", - "Name": "Arsenic", - "Oxidation states": [ - -3, - 2, - 3, - 5 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.001552", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.475, - "ionic_radius": 0.335 - } - }, - "VI": { - "": { - "crystal_radius": 0.6, - "ionic_radius": 0.46 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "50 W m-1 K-1", - "Van der waals radius": 1.85, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.18, - "Youngs modulus": "8 GPa" - }, - "At": { - "Atomic mass": 210.0, - "Atomic no": 85, - "Atomic orbitals": { - "1s": -3127.390276, - "2p": -513.044243, - "2s": -531.81835, - "3d": -103.060375, - "3p": -119.995013, - "3s": -129.035542, - "4d": -18.295162, - "4f": -8.063483, - "4p": -25.778264, - "4s": -29.809515, - "5d": -1.643758, - "5p": -4.027061, - "5s": -5.453383, - "6p": -0.255453, - "6s": -0.560189 - }, - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -1, - 1 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2.6p5", - "Ionic radii": { - "7": 0.76 - }, - "Liquid range": "no data K", - "Melting point": "575 K", - "Mendeleev no": 96, - "Mineral hardness": "no data", - "Molar volume": "no data cm3", - "Name": "Astatine", - "Oxidation states": [ - -1, - 1, - 3, - 5 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "7": { - "VI": { - "": { - "crystal_radius": 0.76, - "ionic_radius": 0.62 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "2 (estimate)W m-1 K-1", - "Van der waals radius": 2.02, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.2, - "Youngs modulus": "no data GPa" - }, - "Au": { - "Atomic mass": 196.966569, - "Atomic no": 79, - "Atomic orbitals": { - "1s": -2683.508245, - "2p": -430.725701, - "2s": -447.888973, - "3d": -81.511751, - "3p": -96.707, - "3s": -104.824516, - "4d": -12.131815, - "4f": -3.486824, - "4p": -18.578652, - "4s": -22.078357, - "5d": -0.304738, - "5p": -2.002495, - "5s": -3.113936, - "6s": -0.162334 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.74, - "Boiling point": "3129 K", - "Brinell hardness": "2450 MN m-2", - "Bulk modulus": "220 GPa", - "Coefficient of linear thermal expansion": "14.2 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "19300 kg m-3", - "Electrical resistivity": "2.2 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s1", - "Ionic radii": { - "1": 1.51, - "3": 0.99, - "5": 0.71 - }, - "Liquid range": "1791.67 K", - "Melting point": "1337.33 K", - "Mendeleev no": 70, - "Mineral hardness": "2.5", - "Molar volume": "10.21 cm3", - "Name": "Gold", - "Oxidation states": [ - -1, - 1, - 2, - 3, - 5 - ], - "Poissons ratio": "0.44", - "Reflectivity": "95 %", - "Refractive index": "no data", - "Rigidity modulus": "27 GPa", - "Shannon radii": { - "1": { - "VI": { - "": { - "crystal_radius": 1.51, - "ionic_radius": 1.37 - } - } - }, - "3": { - "IVSQ": { - "": { - "crystal_radius": 0.82, - "ionic_radius": 0.68 - } - }, - "VI": { - "": { - "crystal_radius": 0.99, - "ionic_radius": 0.85 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "320 W m-1 K-1", - "Van der waals radius": 1.66, - "Velocity of sound": "1740 m s-1", - "Vickers hardness": "216 MN m-2", - "X": 2.54, - "Youngs modulus": "78 GPa" - }, - "B": { - "Atomic mass": 10.811, - "Atomic no": 5, - "Atomic orbitals": { - "1s": -6.564347, - "2p": -0.136603, - "2s": -0.344701 - }, - "Atomic radius": 0.85, - "Atomic radius calculated": 0.87, - "Boiling point": "4200 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "320 GPa", - "Coefficient of linear thermal expansion": "6 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "2460 kg m-3", - "Electrical resistivity": "> 101210-8 Ω m", - "Electronic structure": "[He].2s2.2p1", - "ICSD oxidation states": [ - 3, - -3 - ], - "Ionic radii": { - "3": 0.41 - }, - "Liquid range": "1851 K", - "Melting point": "2349 K", - "Mendeleev no": 86, - "Mineral hardness": "9.3", - "Molar volume": "4.39 cm3", - "Name": "Boron", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "III": { - "": { - "crystal_radius": 0.15, - "ionic_radius": 0.01 - } - }, - "IV": { - "": { - "crystal_radius": 0.25, - "ionic_radius": 0.11 - } - }, - "VI": { - "": { - "crystal_radius": 0.41, - "ionic_radius": 0.27 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "27 W m-1 K-1", - "Van der waals radius": 1.92, - "Velocity of sound": "16200 m s-1", - "Vickers hardness": "49000 MN m-2", - "X": 2.04, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "B-10": 84.59, - "B-11": 40.59 - } - }, - "Ba": { - "Atomic mass": 137.327, - "Atomic no": 56, - "Atomic orbitals": { - "1s": -1305.743258, - "2p": -189.598483, - "2s": -200.844444, - "3d": -28.528933, - "3p": -37.536931, - "3s": -42.359434, - "4d": -3.432441, - "4p": -6.497622, - "4s": -8.257061, - "5p": -0.698605, - "5s": -1.157159, - "6s": -0.118967 - }, - "Atomic radius": 2.15, - "Atomic radius calculated": 2.53, - "Boiling point": "2143 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "9.6 GPa", - "Coefficient of linear thermal expansion": "20.6 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "3510 kg m-3", - "Electrical resistivity": "34 10-8 Ω m", - "Electronic structure": "[Xe].6s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 1.49 - }, - "Liquid range": "1143 K", - "Melting point": "1000 K", - "Mendeleev no": 14, - "Mineral hardness": "1.25", - "Molar volume": "38.16 cm3", - "Name": "Barium", - "Oxidation states": [ - 2 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "4.9 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.49, - "ionic_radius": 1.35 - } - }, - "VII": { - "": { - "crystal_radius": 1.52, - "ionic_radius": 1.38 - } - }, - "VIII": { - "": { - "crystal_radius": 1.56, - "ionic_radius": 1.42 - } - }, - "IX": { - "": { - "crystal_radius": 1.61, - "ionic_radius": 1.47 - } - }, - "X": { - "": { - "crystal_radius": 1.66, - "ionic_radius": 1.52 - } - }, - "XI": { - "": { - "crystal_radius": 1.71, - "ionic_radius": 1.57 - } - }, - "XII": { - "": { - "crystal_radius": 1.75, - "ionic_radius": 1.61 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "18 W m-1 K-1", - "Van der waals radius": 2.68, - "Velocity of sound": "1620 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.89, - "Youngs modulus": "13 GPa" - }, - "Be": { - "Atomic mass": 9.012182, - "Atomic no": 4, - "Atomic orbitals": { - "1s": -3.856411, - "2s": -0.205744 - }, - "Atomic radius": 1.05, - "Atomic radius calculated": 1.12, - "Boiling point": "2742 K", - "Brinell hardness": "600 MN m-2", - "Bulk modulus": "130 GPa", - "Coefficient of linear thermal expansion": "11.3 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "1848 kg m-3", - "Electrical resistivity": "3.8 10-8 Ω m", - "Electronic structure": "[He].2s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 0.59 - }, - "Liquid range": "1182 K", - "Melting point": "1560 K", - "Mendeleev no": 77, - "Mineral hardness": "5.5", - "Molar volume": "4.85 cm3", - "Name": "Beryllium", - "Oxidation states": [ - 2 - ], - "Poissons ratio": "0.032", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "132 GPa", - "Shannon radii": { - "2": { - "III": { - "": { - "crystal_radius": 0.3, - "ionic_radius": 0.16 - } - }, - "IV": { - "": { - "crystal_radius": 0.41, - "ionic_radius": 0.27 - } - }, - "VI": { - "": { - "crystal_radius": 0.59, - "ionic_radius": 0.45 - } - } - } - }, - "Superconduction temperature": "0.026 K", - "Thermal conductivity": "190 W m-1 K-1", - "Van der waals radius": 1.53, - "Velocity of sound": "13000 m s-1", - "Vickers hardness": "1670 MN m-2", - "X": 1.57, - "Youngs modulus": "287 GPa", - "NMR Quadrupole Moment": { - "Be-9": 52.88 - } - }, - "Bi": { - "Atomic mass": 208.9804, - "Atomic no": 83, - "Atomic orbitals": { - "1s": -2975.550959, - "2p": -484.716359, - "2s": -502.950758, - "3d": -95.532476, - "3p": -111.883393, - "3s": -120.613998, - "4d": -16.084817, - "4f": -6.382744, - "4p": -23.218641, - "4s": -27.07034, - "5d": -1.139408, - "5p": -3.293637, - "5s": -4.611934, - "6p": -0.180198, - "6s": -0.426129 - }, - "Atomic radius": 1.6, - "Atomic radius calculated": 1.43, - "Boiling point": "1837 K", - "Brinell hardness": "94.2 MN m-2", - "Bulk modulus": "31 GPa", - "Coefficient of linear thermal expansion": "13.4 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "9780 kg m-3", - "Electrical resistivity": "130 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2.6p3", - "ICSD oxidation states": [ - 1, - 2, - 3, - 5 - ], - "Ionic radii": { - "3": 1.17, - "5": 0.9 - }, - "Liquid range": "1292.6 K", - "Melting point": "544.4 K", - "Mendeleev no": 87, - "Mineral hardness": "2.25", - "Molar volume": "21.31 cm3", - "Name": "Bismuth", - "Oxidation states": [ - -3, - 3, - 5 - ], - "Poissons ratio": "0.33", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "12 GPa", - "Shannon radii": { - "3": { - "V": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - }, - "VI": { - "": { - "crystal_radius": 1.17, - "ionic_radius": 1.03 - } - }, - "VIII": { - "": { - "crystal_radius": 1.31, - "ionic_radius": 1.17 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "8 W m-1 K-1", - "Van der waals radius": 2.07, - "Velocity of sound": "1790 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.02, - "Youngs modulus": "32 GPa" - }, - "Bk": { - "Atomic mass": 247.0, - "Atomic no": 97, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "14780 kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f9.7s2", - "Ionic radii": { - "3": 1.1, - "4": 0.97 - }, - "Liquid range": "no data K", - "Melting point": "1259 K", - "Mendeleev no": 40, - "Mineral hardness": "no data", - "Molar volume": "16.84 cm3", - "Name": "Berkelium", - "Oxidation states": [ - 3, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.97, - "ionic_radius": 0.83 - } - }, - "VIII": { - "": { - "crystal_radius": 1.07, - "ionic_radius": 0.93 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "10 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Br": { - "Atomic mass": 79.904, - "Atomic no": 35, - "Atomic orbitals": { - "1s": -480.182643, - "2p": -55.67796, - "2s": -61.710022, - "3d": -2.52211, - "3p": -6.298805, - "3s": -8.409057, - "4p": -0.295334, - "4s": -0.720066 - }, - "Atomic radius": 1.15, - "Atomic radius calculated": 0.94, - "Boiling point": "332 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "1.9 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -1, - 1, - 3, - 5, - 7 - ], - "Critical temperature": "586 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "> 101810-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2.4p5", - "ICSD oxidation states": [ - 5, - -1 - ], - "Ionic radii": { - "-1": 1.82, - "3": 0.73, - "5": 0.45, - "7": 0.53 - }, - "Liquid range": "66.2 K", - "Melting point": "265.8 K", - "Mendeleev no": 98, - "Mineral hardness": "no data", - "Molar volume": "19.78 cm3", - "Name": "Bromine", - "Oxidation states": [ - -1, - 1, - 3, - 4, - 5, - 7 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.001132", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-1": { - "VI": { - "": { - "crystal_radius": 1.82, - "ionic_radius": 1.96 - } - } - }, - "3": { - "IVSQ": { - "": { - "crystal_radius": 0.73, - "ionic_radius": 0.59 - } - } - }, - "5": { - "IIIPY": { - "": { - "crystal_radius": 0.45, - "ionic_radius": 0.31 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.39, - "ionic_radius": 0.25 - } - }, - "VI": { - "": { - "crystal_radius": 0.53, - "ionic_radius": 0.39 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.12 W m-1 K-1", - "Van der waals radius": 1.85, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.96, - "Youngs modulus": "no data GPa" - }, - "C": { - "Atomic mass": 12.0107, - "Atomic no": 6, - "Atomic orbitals": { - "1s": -9.947718, - "2p": -0.199186, - "2s": -0.500866 - }, - "Atomic radius": 0.7, - "Atomic radius calculated": 0.67, - "Boiling point": "4300 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "33 GPa", - "Coefficient of linear thermal expansion": "7.1 x10-6K-1", - "Common oxidation states": [ - -4, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "2267 kg m-3", - "Electrical resistivity": "about 1000 - direction dependent10-8 Ω m", - "Electronic structure": "[He].2s2.2p2", - "ICSD oxidation states": [ - 2, - 3, - 4, - -4, - -3, - -2 - ], - "Ionic radii": { - "4": 0.3 - }, - "Liquid range": "500 K", - "Melting point": "3800 K", - "Mendeleev no": 95, - "Mineral hardness": "0.5 (graphite; diamond is 10.0)(no units)", - "Molar volume": "5.29 cm3", - "Name": "Carbon", - "Oxidation states": [ - -4, - -3, - -2, - -1, - 1, - 2, - 3, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "27 %", - "Refractive index": "2.417 (diamond)(no units)", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "4": { - "III": { - "": { - "crystal_radius": 0.06, - "ionic_radius": -0.08 - } - }, - "IV": { - "": { - "crystal_radius": 0.29, - "ionic_radius": 0.15 - } - }, - "VI": { - "": { - "crystal_radius": 0.3, - "ionic_radius": 0.16 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "140 W m-1 K-1", - "Van der waals radius": 1.7, - "Velocity of sound": "18350 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.55, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "C-11": 33.27 - } - }, - "Ca": { - "Atomic mass": 40.078, - "Atomic no": 20, - "Atomic orbitals": { - "1s": -143.935181, - "2p": -12.285376, - "2s": -15.046905, - "3p": -1.030572, - "3s": -1.706331, - "4s": -0.141411 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": 1.94, - "Boiling point": "1757 K", - "Brinell hardness": "167 MN m-2", - "Bulk modulus": "17 GPa", - "Coefficient of linear thermal expansion": "22.3 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "1550 kg m-3", - "Electrical resistivity": "3.4 10-8 Ω m", - "Electronic structure": "[Ar].4s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 1.14 - }, - "Liquid range": "642 K", - "Melting point": "1115 K", - "Mendeleev no": 16, - "Mineral hardness": "1.75", - "Molar volume": "26.20 cm3", - "Name": "Calcium", - "Oxidation states": [ - 2 - ], - "Poissons ratio": "0.31", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "7.4 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.14, - "ionic_radius": 1.0 - } - }, - "VII": { - "": { - "crystal_radius": 1.2, - "ionic_radius": 1.06 - } - }, - "VIII": { - "": { - "crystal_radius": 1.26, - "ionic_radius": 1.12 - } - }, - "IX": { - "": { - "crystal_radius": 1.32, - "ionic_radius": 1.18 - } - }, - "X": { - "": { - "crystal_radius": 1.37, - "ionic_radius": 1.23 - } - }, - "XII": { - "": { - "crystal_radius": 1.48, - "ionic_radius": 1.34 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "200 W m-1 K-1", - "Van der waals radius": 2.31, - "Velocity of sound": "3810 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.0, - "Youngs modulus": "20 GPa", - "NMR Quadrupole Moment": { - "Ca-41": -66.5, - "Ca-43": -40.8 - } - }, - "Cd": { - "Atomic mass": 112.411, - "Atomic no": 48, - "Atomic orbitals": { - "1s": -941.476646, - "2p": -127.63512, - "2s": -136.83249, - "3d": -14.685252, - "3p": -21.637522, - "3s": -25.379908, - "4d": -0.47053, - "4p": -2.39526, - "4s": -3.596069, - "5s": -0.204228 - }, - "Atomic radius": 1.55, - "Atomic radius calculated": 1.61, - "Boiling point": "1040 K", - "Brinell hardness": "203 MN m-2", - "Bulk modulus": "42 GPa", - "Coefficient of linear thermal expansion": "30.8 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "8650 kg m-3", - "Electrical resistivity": "7 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 1.09 - }, - "Liquid range": "445.78 K", - "Melting point": "594.22 K", - "Mendeleev no": 75, - "Mineral hardness": "2.0", - "Molar volume": "13.00 cm3", - "Name": "Cadmium", - "Oxidation states": [ - 1, - 2 - ], - "Poissons ratio": "0.30", - "Reflectivity": "67 %", - "Refractive index": "no data", - "Rigidity modulus": "19 GPa", - "Shannon radii": { - "2": { - "IV": { - "": { - "crystal_radius": 0.92, - "ionic_radius": 0.78 - } - }, - "V": { - "": { - "crystal_radius": 1.01, - "ionic_radius": 0.87 - } - }, - "VI": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - }, - "VII": { - "": { - "crystal_radius": 1.17, - "ionic_radius": 1.03 - } - }, - "VIII": { - "": { - "crystal_radius": 1.24, - "ionic_radius": 1.1 - } - }, - "XII": { - "": { - "crystal_radius": 1.45, - "ionic_radius": 1.31 - } - } - } - }, - "Superconduction temperature": "0.517 K", - "Thermal conductivity": "97 W m-1 K-1", - "Van der waals radius": 1.58, - "Velocity of sound": "2310 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.69, - "Youngs modulus": "50 GPa" - }, - "Ce": { - "Atomic mass": 140.116, - "Atomic no": 58, - "Atomic orbitals": { - "1s": -1406.148284, - "2p": -206.925148, - "2s": -218.684842, - "3d": -32.412569, - "3p": -41.938282, - "3s": -47.035283, - "4d": -4.192548, - "4f": -0.337442, - "4p": -7.532106, - "4s": -9.432744, - "5d": -0.14055, - "5p": -0.85011, - "5s": -1.369728, - "6s": -0.133974 - }, - "Atomic radius": 1.85, - "Atomic radius calculated": "no data", - "Boiling point": "3633 K", - "Brinell hardness": "412 MN m-2", - "Bulk modulus": "22 GPa", - "Coefficient of linear thermal expansion": "6.3 x10-6K-1", - "Common oxidation states": [ - 3, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "6689 kg m-3", - "Electrical resistivity": "74 10-8 Ω m", - "Electronic structure": "[Xe].4f1.5d1.6s2", - "ICSD oxidation states": [ - 3, - 4 - ], - "Ionic radii": { - "3": 1.15, - "4": 1.01 - }, - "Liquid range": "2565 K", - "Melting point": "1068 K", - "Mendeleev no": 32, - "Mineral hardness": "2.5", - "Molar volume": "20.69 cm3", - "Name": "Cerium", - "Oxidation states": [ - 2, - 3, - 4 - ], - "Poissons ratio": "0.24", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "14 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.15, - "ionic_radius": 1.01 - } - }, - "VII": { - "": { - "crystal_radius": 1.21, - "ionic_radius": 1.07 - } - }, - "VIII": { - "": { - "crystal_radius": 1.283, - "ionic_radius": 1.143 - } - }, - "IX": { - "": { - "crystal_radius": 1.336, - "ionic_radius": 1.196 - } - }, - "X": { - "": { - "crystal_radius": 1.39, - "ionic_radius": 1.25 - } - }, - "XII": { - "": { - "crystal_radius": 1.48, - "ionic_radius": 1.34 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 1.01, - "ionic_radius": 0.87 - } - }, - "VIII": { - "": { - "crystal_radius": 1.11, - "ionic_radius": 0.97 - } - }, - "X": { - "": { - "crystal_radius": 1.21, - "ionic_radius": 1.07 - } - }, - "XII": { - "": { - "crystal_radius": 1.28, - "ionic_radius": 1.14 - } - } - } - }, - "Superconduction temperature": "0.022 (under pressure)K", - "Thermal conductivity": "11 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2100 m s-1", - "Vickers hardness": "270 MN m-2", - "X": 1.12, - "Youngs modulus": "34 GPa" - }, - "Cf": { - "Atomic mass": 251.0, - "Atomic no": 98, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "15100 kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f10.7s2", - "Ionic radii": { - "3": 1.09, - "4": 0.961 - }, - "Liquid range": "no data K", - "Melting point": "1173 K", - "Mendeleev no": 39, - "Mineral hardness": "no data", - "Molar volume": "16.50 cm3", - "Name": "Californium", - "Oxidation states": [ - 2, - 3, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.961, - "ionic_radius": 0.821 - } - }, - "VIII": { - "": { - "crystal_radius": 1.06, - "ionic_radius": 0.92 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Cl": { - "Atomic mass": 35.453, - "Atomic no": 17, - "Atomic orbitals": { - "1s": -100.369229, - "2p": -7.039982, - "2s": -9.187993, - "3p": -0.32038, - "3s": -0.754458 - }, - "Atomic radius": 1.0, - "Atomic radius calculated": 0.79, - "Boiling point": "239.11 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "1.1 (liquid)GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -1, - 1, - 3, - 5, - 7 - ], - "Critical temperature": "417 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "> 101010-8 Ω m", - "Electronic structure": "[Ne].3s2.3p5", - "ICSD oxidation states": [ - -1 - ], - "Ionic radii": { - "-1": 1.67, - "5": 0.26, - "7": 0.41 - }, - "Liquid range": "67.51 K", - "Melting point": "171.6 K", - "Mendeleev no": 99, - "Mineral hardness": "no data", - "Molar volume": "17.39 cm3", - "Name": "Chlorine", - "Oxidation states": [ - -1, - 1, - 2, - 3, - 4, - 5, - 6, - 7 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000773", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-1": { - "VI": { - "": { - "crystal_radius": 1.67, - "ionic_radius": 1.81 - } - } - }, - "5": { - "IIIPY": { - "": { - "crystal_radius": 0.26, - "ionic_radius": 0.12 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.22, - "ionic_radius": 0.08 - } - }, - "VI": { - "": { - "crystal_radius": 0.41, - "ionic_radius": 0.27 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.0089 W m-1 K-1", - "Van der waals radius": 1.75, - "Velocity of sound": "206 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 3.16, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "Cl-35": -81.65, - "Cl-37": -64.35 - } - }, - "Cm": { - "Atomic mass": 247.0, - "Atomic no": 96, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "3383 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "13510 kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f7.6d1.7s2", - "Ionic radii": { - "3": 1.11, - "4": 0.99 - }, - "Liquid range": "1770 K", - "Melting point": "1613 K", - "Mendeleev no": 41, - "Mineral hardness": "no data", - "Molar volume": "18.05 cm3", - "Name": "Curium", - "Oxidation states": [ - 3, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.11, - "ionic_radius": 0.97 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.99, - "ionic_radius": 0.85 - } - }, - "VIII": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "8.8 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Co": { - "Atomic mass": 58.933195, - "Atomic no": 27, - "Atomic orbitals": { - "1s": -275.616639, - "2p": -28.152095, - "2s": -32.379758, - "3d": -0.322368, - "3p": -2.388285, - "3s": -3.651812, - "4s": -0.204497 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.52, - "Boiling point": "3200 K", - "Brinell hardness": "700 MN m-2", - "Bulk modulus": "180 GPa", - "Coefficient of linear thermal expansion": "13.0 x10-6K-1", - "Common oxidation states": [ - 2, - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "8900 kg m-3", - "Electrical resistivity": "6 10-8 Ω m", - "Electronic structure": "[Ar].3d7.4s2", - "ICSD oxidation states": [ - 1, - 2, - 3, - 4 - ], - "Ionic radii": { - "2": 0.885, - "3": 0.75, - "4": 0.67 - }, - "Ionic radii hs": { - "2": 0.885, - "3": 0.75, - "4": 0.67 - }, - "Ionic radii ls": { - "2": 0.79, - "3": 0.685 - }, - "Liquid range": "1432 K", - "Melting point": "1768 K", - "Mendeleev no": 64, - "Mineral hardness": "5.0", - "Molar volume": "6.67 cm3", - "Name": "Cobalt", - "Oxidation states": [ - -1, - 1, - 2, - 3, - 4, - 5 - ], - "Poissons ratio": "0.31", - "Reflectivity": "67 %", - "Refractive index": "no data", - "Rigidity modulus": "75 GPa", - "Shannon radii": { - "2": { - "IV": { - "High Spin": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - }, - "V": { - "": { - "crystal_radius": 0.81, - "ionic_radius": 0.67 - } - }, - "VI": { - "Low Spin": { - "crystal_radius": 0.79, - "ionic_radius": 0.65 - }, - "High Spin": { - "crystal_radius": 0.885, - "ionic_radius": 0.745 - } - }, - "VIII": { - "": { - "crystal_radius": 1.04, - "ionic_radius": 0.9 - } - } - }, - "3": { - "VI": { - "High Spin": { - "crystal_radius": 0.75, - "ionic_radius": 0.61 - }, - "Low Spin": { - "crystal_radius": 0.685, - "ionic_radius": 0.545 - } - } - }, - "4": { - "IV": { - "": { - "crystal_radius": 0.54, - "ionic_radius": 0.4 - } - }, - "VI": { - "High Spin": { - "crystal_radius": 0.67, - "ionic_radius": 0.53 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "100 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4720 m s-1", - "Vickers hardness": "1043 MN m-2", - "X": 1.88, - "Youngs modulus": "209 GPa", - "NMR Quadrupole Moment": { - "Co-59": 420.3 - } - }, - "Cr": { - "Atomic mass": 51.9961, - "Atomic no": 24, - "Atomic orbitals": { - "1s": -213.881191, - "2p": -20.526273, - "2s": -24.113457, - "3d": -0.118123, - "3p": -1.65423, - "3s": -2.649085, - "4s": -0.150445 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.66, - "Boiling point": "2944 K", - "Brinell hardness": "1120 MN m-2", - "Bulk modulus": "160 GPa", - "Coefficient of linear thermal expansion": "4.9 x10-6K-1", - "Common oxidation states": [ - 3, - 6 - ], - "Critical temperature": "no data K", - "Density of solid": "7140 kg m-3", - "Electrical resistivity": "12.7 10-8 Ω m", - "Electronic structure": "[Ar].3d5.4s1", - "ICSD oxidation states": [ - 2, - 3, - 4, - 5, - 6 - ], - "Ionic radii": { - "2": 0.94 - }, - "Ionic radii hs": { - "2": 0.94 - }, - "Ionic radii ls": { - "2": 0.87, - "3": 0.755, - "4": 0.69, - "5": 0.63, - "6": 0.58 - }, - "Liquid range": "764 K", - "Melting point": "2180 K", - "Mendeleev no": 57, - "Mineral hardness": "8.5", - "Molar volume": "7.23 cm3", - "Name": "Chromium", - "Oxidation states": [ - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.21", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "115 GPa", - "Shannon radii": { - "2": { - "VI": { - "Low Spin": { - "crystal_radius": 0.87, - "ionic_radius": 0.73 - }, - "High Spin": { - "crystal_radius": 0.94, - "ionic_radius": 0.8 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 0.755, - "ionic_radius": 0.615 - } - } - }, - "4": { - "IV": { - "": { - "crystal_radius": 0.55, - "ionic_radius": 0.41 - } - }, - "VI": { - "": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.485, - "ionic_radius": 0.345 - } - }, - "VI": { - "": { - "crystal_radius": 0.63, - "ionic_radius": 0.49 - } - }, - "VIII": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.4, - "ionic_radius": 0.26 - } - }, - "VI": { - "": { - "crystal_radius": 0.58, - "ionic_radius": 0.44 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "94 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "5940 m s-1", - "Vickers hardness": "1060 MN m-2", - "X": 1.66, - "Youngs modulus": "279 GPa", - "NMR Quadrupole Moment": { - "Cr-53": -150.5 - } - }, - "Cs": { - "Atomic mass": 132.9054519, - "Atomic no": 55, - "Atomic orbitals": { - "1s": -1256.738791, - "2p": -180.995344, - "2s": -191.981873, - "3d": -26.418398, - "3p": -35.166423, - "3s": -39.851584, - "4d": -2.848386, - "4p": -5.769326, - "4s": -7.455966, - "5p": -0.504903, - "5s": -0.915819, - "6s": -0.078699 - }, - "Atomic radius": 2.6, - "Atomic radius calculated": 2.98, - "Boiling point": "944 K", - "Brinell hardness": "0.14 MN m-2", - "Bulk modulus": "1.6 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "1938 K", - "Density of solid": "1879 kg m-3", - "Electrical resistivity": "21 10-8 Ω m", - "Electronic structure": "[Xe].6s1", - "ICSD oxidation states": [ - 1 - ], - "Ionic radii": { - "1": 1.81 - }, - "Liquid range": "642.41 K", - "Melting point": "301.59 K", - "Mendeleev no": 8, - "Mineral hardness": "0.2", - "Molar volume": "70.94 cm3", - "Name": "Cesium", - "Oxidation states": [ - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "1": { - "VI": { - "": { - "crystal_radius": 1.81, - "ionic_radius": 1.67 - } - }, - "VIII": { - "": { - "crystal_radius": 1.88, - "ionic_radius": 1.74 - } - }, - "IX": { - "": { - "crystal_radius": 1.92, - "ionic_radius": 1.78 - } - }, - "X": { - "": { - "crystal_radius": 1.95, - "ionic_radius": 1.81 - } - }, - "XI": { - "": { - "crystal_radius": 1.99, - "ionic_radius": 1.85 - } - }, - "XII": { - "": { - "crystal_radius": 2.02, - "ionic_radius": 1.88 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "36 W m-1 K-1", - "Van der waals radius": 3.43, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.79, - "Youngs modulus": "1.7 GPa" - }, - "Cu": { - "Atomic mass": 63.546, - "Atomic no": 29, - "Atomic orbitals": { - "1s": -320.78852, - "2p": -33.481247, - "2s": -38.14131, - "3d": -0.202272, - "3p": -2.609244, - "3s": -4.057453, - "4s": -0.172056 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.45, - "Boiling point": "3200 K", - "Brinell hardness": "874 MN m-2", - "Bulk modulus": "140 GPa", - "Coefficient of linear thermal expansion": "16.5 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "8920 kg m-3", - "Electrical resistivity": "1.72 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s1", - "ICSD oxidation states": [ - 1, - 2, - 3 - ], - "Ionic radii": { - "1": 0.91, - "2": 0.87, - "3": 0.68 - }, - "Liquid range": "1842.23 K", - "Melting point": "1357.77 K", - "Mendeleev no": 72, - "Mineral hardness": "3.0", - "Molar volume": "7.11 cm3", - "Name": "Copper", - "Oxidation states": [ - 1, - 2, - 3, - 4 - ], - "Poissons ratio": "0.34", - "Reflectivity": "90 %", - "Refractive index": "no data", - "Rigidity modulus": "48 GPa", - "Shannon radii": { - "1": { - "II": { - "": { - "crystal_radius": 0.6, - "ionic_radius": 0.46 - } - }, - "IV": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - }, - "VI": { - "": { - "crystal_radius": 0.91, - "ionic_radius": 0.77 - } - } - }, - "2": { - "IV": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - }, - "IVSQ": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - }, - "V": { - "": { - "crystal_radius": 0.79, - "ionic_radius": 0.65 - } - }, - "VI": { - "": { - "crystal_radius": 0.87, - "ionic_radius": 0.73 - } - } - }, - "3": { - "VI": { - "Low Spin": { - "crystal_radius": 0.68, - "ionic_radius": 0.54 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "400 W m-1 K-1", - "Van der waals radius": 1.4, - "Velocity of sound": "3570 m s-1", - "Vickers hardness": "369 MN m-2", - "X": 1.9, - "Youngs modulus": "130 GPa", - "NMR Quadrupole Moment": { - "Cu-63": -220.15, - "Cu-65": -204.14 - } - }, - "Dy": { - "Atomic mass": 162.5, - "Atomic no": 66, - "Atomic orbitals": { - "1s": -1843.229585, - "2p": -281.558531, - "2s": -295.342856, - "3d": -47.4867, - "3p": -59.091931, - "3s": -65.299442, - "4d": -5.686352, - "4f": -0.265302, - "4p": -10.094091, - "4s": -12.551251, - "5p": -0.90349, - "5s": -1.547977, - "6s": -0.132769 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": 2.28, - "Boiling point": "2840 K", - "Brinell hardness": "500 MN m-2", - "Bulk modulus": "41 GPa", - "Coefficient of linear thermal expansion": "9.9 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "8551 kg m-3", - "Electrical resistivity": "92.6 10-8 Ω m", - "Electronic structure": "[Xe].4f10.6s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "2": 1.21, - "3": 1.052 - }, - "Liquid range": "1160 K", - "Melting point": "1680 K", - "Mendeleev no": 24, - "Mineral hardness": "no data", - "Molar volume": "19.01 cm3", - "Name": "Dysprosium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.25", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "25 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.21, - "ionic_radius": 1.07 - } - }, - "VII": { - "": { - "crystal_radius": 1.27, - "ionic_radius": 1.13 - } - }, - "VIII": { - "": { - "crystal_radius": 1.33, - "ionic_radius": 1.19 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.052, - "ionic_radius": 0.912 - } - }, - "VII": { - "": { - "crystal_radius": 1.11, - "ionic_radius": 0.97 - } - }, - "VIII": { - "": { - "crystal_radius": 1.167, - "ionic_radius": 1.027 - } - }, - "IX": { - "": { - "crystal_radius": 1.223, - "ionic_radius": 1.083 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "11 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2710 m s-1", - "Vickers hardness": "540 MN m-2", - "X": 1.22, - "Youngs modulus": "61 GPa" - }, - "Er": { - "Atomic mass": 167.259, - "Atomic no": 68, - "Atomic orbitals": { - "1s": -1961.799176, - "2p": -302.01827, - "2s": -316.310631, - "3d": -51.682149, - "3p": -63.818655, - "3s": -70.310142, - "4d": -6.127443, - "4f": -0.278577, - "4p": -10.819574, - "4s": -13.423547, - "5p": -0.935202, - "5s": -1.616073, - "6s": -0.134905 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": 2.26, - "Boiling point": "3141 K", - "Brinell hardness": "814 MN m-2", - "Bulk modulus": "44 GPa", - "Coefficient of linear thermal expansion": "12.2 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "9066 kg m-3", - "Electrical resistivity": "86.0 10-8 Ω m", - "Electronic structure": "[Xe].4f12.6s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "3": 1.03 - }, - "Liquid range": "1371 K", - "Melting point": "1802 K", - "Mendeleev no": 22, - "Mineral hardness": "no data", - "Molar volume": "18.46 cm3", - "Name": "Erbium", - "Oxidation states": [ - 3 - ], - "Poissons ratio": "0.24", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "28 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.03, - "ionic_radius": 0.89 - } - }, - "VII": { - "": { - "crystal_radius": 1.085, - "ionic_radius": 0.945 - } - }, - "VIII": { - "": { - "crystal_radius": 1.144, - "ionic_radius": 1.004 - } - }, - "IX": { - "": { - "crystal_radius": 1.202, - "ionic_radius": 1.062 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "15 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2830 m s-1", - "Vickers hardness": "589 MN m-2", - "X": 1.24, - "Youngs modulus": "70 GPa" - }, - "Es": { - "Atomic mass": 252.0, - "Atomic no": 99, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f11.7s2", - "Liquid range": "no data K", - "Melting point": "1133 K", - "Mendeleev no": 38, - "Mineral hardness": "no data", - "Molar volume": "28.52 cm3", - "Name": "Einsteinium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Eu": { - "Atomic mass": 151.964, - "Atomic no": 63, - "Atomic orbitals": { - "1s": -1672.309322, - "2p": -252.176697, - "2s": -265.199534, - "3d": -41.465518, - "3p": -52.281987, - "3s": -58.068128, - "4d": -5.03242, - "4f": -0.232773, - "4p": -9.025455, - "4s": -11.267747, - "5p": -0.853575, - "5s": -1.444087, - "6s": -0.129426 - }, - "Atomic radius": 1.85, - "Atomic radius calculated": 2.31, - "Boiling point": "1800 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "8.3 GPa", - "Coefficient of linear thermal expansion": "35 x10-6K-1", - "Common oxidation states": [ - 2, - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "5244 kg m-3", - "Electrical resistivity": "90 10-8 Ω m", - "Electronic structure": "[Xe].4f7.6s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "2": 1.31, - "3": 1.087 - }, - "Liquid range": "701 K", - "Melting point": "1099 K", - "Mendeleev no": 18, - "Mineral hardness": "no data", - "Molar volume": "28.97 cm3", - "Name": "Europium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.15", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "7.9 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.31, - "ionic_radius": 1.17 - } - }, - "VII": { - "": { - "crystal_radius": 1.34, - "ionic_radius": 1.2 - } - }, - "VIII": { - "": { - "crystal_radius": 1.39, - "ionic_radius": 1.25 - } - }, - "IX": { - "": { - "crystal_radius": 1.44, - "ionic_radius": 1.3 - } - }, - "X": { - "": { - "crystal_radius": 1.49, - "ionic_radius": 1.35 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.087, - "ionic_radius": 0.947 - } - }, - "VII": { - "": { - "crystal_radius": 1.15, - "ionic_radius": 1.01 - } - }, - "VIII": { - "": { - "crystal_radius": 1.206, - "ionic_radius": 1.066 - } - }, - "IX": { - "": { - "crystal_radius": 1.26, - "ionic_radius": 1.12 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "14 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "167 MN m-2", - "X": 1.2, - "Youngs modulus": "18 GPa" - }, - "F": { - "Atomic mass": 18.9984032, - "Atomic no": 9, - "Atomic orbitals": { - "1s": -24.189391, - "2p": -0.415606, - "2s": -1.086859 - }, - "Atomic radius": 0.5, - "Atomic radius calculated": 0.42, - "Boiling point": "85.03 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -1 - ], - "Critical temperature": "144 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[He].2s2.2p5", - "ICSD oxidation states": [ - -1 - ], - "Ionic radii": { - "-1": 1.19, - "7": 0.22 - }, - "Liquid range": "31.5 K", - "Melting point": "53.53 K", - "Mendeleev no": 102, - "Mineral hardness": "no data", - "Molar volume": "11.20 cm3", - "Name": "Fluorine", - "Oxidation states": [ - -1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000195", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-1": { - "II": { - "": { - "crystal_radius": 1.145, - "ionic_radius": 1.285 - } - }, - "III": { - "": { - "crystal_radius": 1.16, - "ionic_radius": 1.3 - } - }, - "IV": { - "": { - "crystal_radius": 1.17, - "ionic_radius": 1.31 - } - }, - "VI": { - "": { - "crystal_radius": 1.19, - "ionic_radius": 1.33 - } - } - }, - "7": { - "VI": { - "": { - "crystal_radius": 0.22, - "ionic_radius": 0.08 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.0277 W m-1 K-1", - "Van der waals radius": 1.47, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 3.98, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "F-19": -94.2 - } - }, - "Fe": { - "Atomic mass": 55.845, - "Atomic no": 26, - "Atomic orbitals": { - "1s": -254.225505, - "2p": -25.551766, - "2s": -29.56486, - "3d": -0.295049, - "3p": -2.187523, - "3s": -3.360621, - "4s": -0.197978 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.56, - "Boiling point": "3134 K", - "Brinell hardness": "490 MN m-2", - "Bulk modulus": "170 GPa", - "Coefficient of linear thermal expansion": "11.8 x10-6K-1", - "Common oxidation states": [ - 2, - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "7874 kg m-3", - "Electrical resistivity": "10 10-8 Ω m", - "Electronic structure": "[Ar].3d6.4s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "2": 0.92, - "3": 0.785 - }, - "Ionic radii hs": { - "2": 0.92, - "3": 0.785 - }, - "Ionic radii ls": { - "2": 0.75, - "3": 0.69, - "4": 0.725, - "6": 0.39 - }, - "Liquid range": "1323 K", - "Melting point": "1811 K", - "Mendeleev no": 61, - "Mineral hardness": "4.0", - "Molar volume": "7.09 cm3", - "Name": "Iron", - "Oxidation states": [ - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.29", - "Reflectivity": "65 %", - "Refractive index": "no data", - "Rigidity modulus": "82 GPa", - "Shannon radii": { - "2": { - "IV": { - "High Spin": { - "crystal_radius": 0.77, - "ionic_radius": 0.63 - } - }, - "IVSQ": { - "High Spin": { - "crystal_radius": 0.78, - "ionic_radius": 0.64 - } - }, - "VI": { - "Low Spin": { - "crystal_radius": 0.75, - "ionic_radius": 0.61 - }, - "High Spin": { - "crystal_radius": 0.92, - "ionic_radius": 0.78 - } - }, - "VIII": { - "High Spin": { - "crystal_radius": 1.06, - "ionic_radius": 0.92 - } - } - }, - "3": { - "IV": { - "High Spin": { - "crystal_radius": 0.63, - "ionic_radius": 0.49 - } - }, - "V": { - "": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - }, - "VI": { - "Low Spin": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - }, - "High Spin": { - "crystal_radius": 0.785, - "ionic_radius": 0.645 - } - }, - "VIII": { - "High Spin": { - "crystal_radius": 0.92, - "ionic_radius": 0.78 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.725, - "ionic_radius": 0.585 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.39, - "ionic_radius": 0.25 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "80 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4910 m s-1", - "Vickers hardness": "608 MN m-2", - "X": 1.83, - "Youngs modulus": "211 GPa", - "NMR Quadrupole Moment": { - "Fe-57": 160.0 - } - }, - "Fm": { - "Atomic mass": 257.0, - "Atomic no": 100, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f12.7s2", - "Liquid range": "no data K", - "Melting point": "about 1800 K", - "Mendeleev no": 37, - "Mineral hardness": "no data", - "Molar volume": "no data cm3", - "Name": "Fermium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Fr": { - "Atomic mass": 223.0, - "Atomic no": 87, - "Atomic orbitals": { - "1s": -3283.263399, - "2p": -542.41424, - "2s": -561.73045, - "3d": -111.085223, - "3p": -128.607136, - "3s": -137.959632, - "4d": -20.812462, - "4f": -10.050648, - "4p": -28.648131, - "4s": -32.861013, - "5d": -2.360991, - "5p": -4.97328, - "5s": -6.509516, - "6p": -0.466197, - "6s": -0.841848, - "7s": -0.076176 - }, - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].7s1", - "Ionic radii": { - "1": 1.94 - }, - "Liquid range": "no data K", - "Melting point": "maybe about 300 K", - "Mendeleev no": 7, - "Mineral hardness": "no data", - "Molar volume": "no data cm3", - "Name": "Francium", - "Oxidation states": [ - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "1": { - "VI": { - "": { - "crystal_radius": 1.94, - "ionic_radius": 1.8 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": 3.48, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.7, - "Youngs modulus": "no data GPa" - }, - "Ga": { - "Atomic mass": 69.723, - "Atomic no": 31, - "Atomic orbitals": { - "1s": -370.170639, - "2p": -40.093339, - "2s": -45.200869, - "3d": -0.736204, - "3p": -3.584666, - "3s": -5.241645, - "4p": -0.101634, - "4s": -0.328019 - }, - "Atomic radius": 1.3, - "Atomic radius calculated": 1.36, - "Boiling point": "2477 K", - "Brinell hardness": "60 MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "120 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "5904 kg m-3", - "Electrical resistivity": "about 14 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2.4p1", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "3": 0.76 - }, - "Liquid range": "2174.09 K", - "Melting point": "302.91 K", - "Mendeleev no": 81, - "Mineral hardness": "1.5", - "Molar volume": "11.80 cm3", - "Name": "Gallium", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "IV": { - "": { - "crystal_radius": 0.61, - "ionic_radius": 0.47 - } - }, - "V": { - "": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - } - }, - "VI": { - "": { - "crystal_radius": 0.76, - "ionic_radius": 0.62 - } - } - } - }, - "Superconduction temperature": "1.083 K", - "Thermal conductivity": "29 W m-1 K-1", - "Van der waals radius": 1.87, - "Velocity of sound": "2740 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.81, - "Youngs modulus": "no data GPa" - }, - "Gd": { - "Atomic mass": 157.25, - "Atomic no": 64, - "Atomic orbitals": { - "1s": -1728.625195, - "2p": -262.081616, - "2s": -275.36313, - "3d": -43.754556, - "3p": -54.836922, - "3s": -60.764408, - "4d": -5.531835, - "4f": -0.489012, - "4p": -9.669866, - "4s": -11.986486, - "5d": -0.12722, - "5p": -0.978749, - "5s": -1.608477, - "6s": -0.143627 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": 2.33, - "Boiling point": "3523 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "38 GPa", - "Coefficient of linear thermal expansion": "9.4 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "7901 kg m-3", - "Electrical resistivity": "131 10-8 Ω m", - "Electronic structure": "[Xe].4f7.5d1.6s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "3": 1.075 - }, - "Liquid range": "1938 K", - "Melting point": "1585 K", - "Mendeleev no": 27, - "Mineral hardness": "no data", - "Molar volume": "19.90 cm3", - "Name": "Gadolinium", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "0.26", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "22 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.078, - "ionic_radius": 0.938 - } - }, - "VII": { - "": { - "crystal_radius": 1.14, - "ionic_radius": 1.0 - } - }, - "VIII": { - "": { - "crystal_radius": 1.193, - "ionic_radius": 1.053 - } - }, - "IX": { - "": { - "crystal_radius": 1.247, - "ionic_radius": 1.107 - } - } - } - }, - "Superconduction temperature": "1.083 K", - "Thermal conductivity": "11 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2680 m s-1", - "Vickers hardness": "570 MN m-2", - "X": 1.2, - "Youngs modulus": "55 GPa" - }, - "Ge": { - "Atomic mass": 72.64, - "Atomic no": 32, - "Atomic orbitals": { - "1s": -396.292991, - "2p": -43.720129, - "2s": -49.055282, - "3d": -1.117316, - "3p": -4.194822, - "3s": -5.961472, - "4p": -0.149882, - "4s": -0.426523 - }, - "Atomic radius": 1.25, - "Atomic radius calculated": 1.25, - "Boiling point": "3093 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "6 x10-6K-1", - "Common oxidation states": [ - -4, - 2, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "5323 kg m-3", - "Electrical resistivity": "about 50000 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2.4p2", - "ICSD oxidation states": [ - 2, - 3, - 4 - ], - "Ionic radii": { - "2": 0.87, - "4": 0.67 - }, - "Liquid range": "1881.6 K", - "Melting point": "1211.4 K", - "Mendeleev no": 84, - "Mineral hardness": "6.0", - "Molar volume": "13.63 cm3", - "Name": "Germanium", - "Oxidation states": [ - -4, - 1, - 2, - 3, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 0.87, - "ionic_radius": 0.73 - } - } - }, - "4": { - "IV": { - "": { - "crystal_radius": 0.53, - "ionic_radius": 0.39 - } - }, - "VI": { - "": { - "crystal_radius": 0.67, - "ionic_radius": 0.53 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "60 W m-1 K-1", - "Van der waals radius": 2.11, - "Velocity of sound": "5400 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.01, - "Youngs modulus": "no data GPa" - }, - "H": { - "Atomic mass": 1.00794, - "Atomic no": 1, - "Atomic orbitals": { - "1s": -0.233471 - }, - "Atomic radius": 0.25, - "Atomic radius calculated": 0.53, - "Boiling point": "20.28 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -1, - 1 - ], - "Critical temperature": "33 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "1s1", - "ICSD oxidation states": [ - 1, - -1 - ], - "Liquid range": "6.27 K", - "Melting point": "14.01 K", - "Mendeleev no": 103, - "Mineral hardness": "no data", - "Molar volume": "11.42 cm3", - "Name": "Hydrogen", - "Oxidation states": [ - -1, - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000132 (gas; liquid 1.12)(no units)", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "1": { - "I": { - "": { - "crystal_radius": -0.24, - "ionic_radius": -0.38 - } - }, - "II": { - "": { - "crystal_radius": -0.04, - "ionic_radius": -0.18 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.1805 W m-1 K-1", - "Van der waals radius": 1.2, - "Velocity of sound": "1270 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.2, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "H-2": 2.86 - } - }, - "He": { - "Atomic mass": 4.002602, - "Atomic no": 2, - "Atomic orbitals": { - "1s": -0.570425 - }, - "Atomic radius": "no data", - "Atomic radius calculated": 0.31, - "Boiling point": "4.22 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Critical temperature": "5.19 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "1s2", - "Liquid range": "3.27 K", - "Max oxidation state": 0.0, - "Melting point": "0.95 K", - "Mendeleev no": 1, - "Min oxidation state": 0.0, - "Mineral hardness": "no data", - "Molar volume": "21.0 cm3", - "Name": "Helium", - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000035 (gas; liquid 1.028)(no units)", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.1513 W m-1 K-1", - "Van der waals radius": 1.4, - "Velocity of sound": "970 m s-1", - "Vickers hardness": "no data MN m-2", - "Youngs modulus": "no data GPa" - }, - "Hf": { - "Atomic mass": 178.49, - "Atomic no": 72, - "Atomic orbitals": { - "1s": -2210.65199, - "2p": -345.687023, - "2s": -361.006527, - "3d": -61.231443, - "3p": -74.452656, - "3s": -81.522812, - "4d": -7.676638, - "4f": -0.871574, - "4p": -12.971211, - "4s": -15.883625, - "5d": -0.143805, - "5p": -1.246441, - "5s": -2.049828, - "6s": -0.166465 - }, - "Atomic radius": 1.55, - "Atomic radius calculated": 2.08, - "Boiling point": "4876 K", - "Brinell hardness": "1700 MN m-2", - "Bulk modulus": "110 GPa", - "Coefficient of linear thermal expansion": "5.9 x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "13310 kg m-3", - "Electrical resistivity": "34 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d2.6s2", - "ICSD oxidation states": [ - 4 - ], - "Ionic radii": { - "4": 0.85 - }, - "Liquid range": "2370 K", - "Melting point": "2506 K", - "Mendeleev no": 50, - "Mineral hardness": "5.5", - "Molar volume": "13.44 cm3", - "Name": "Hafnium", - "Oxidation states": [ - 2, - 3, - 4 - ], - "Poissons ratio": "0.37", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "30 GPa", - "Shannon radii": { - "4": { - "IV": { - "": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - }, - "VI": { - "": { - "crystal_radius": 0.85, - "ionic_radius": 0.71 - } - }, - "VII": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - }, - "VIII": { - "": { - "crystal_radius": 0.97, - "ionic_radius": 0.83 - } - } - } - }, - "Superconduction temperature": "0.128 K", - "Thermal conductivity": "23 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "3010 m s-1", - "Vickers hardness": "1760 MN m-2", - "X": 1.3, - "Youngs modulus": "78 GPa" - }, - "Hg": { - "Atomic mass": 200.59, - "Atomic no": 80, - "Atomic orbitals": { - "1s": -2755.022637, - "2p": -443.848676, - "2s": -461.27864, - "3d": -84.845492, - "3p": -100.328031, - "3s": -108.597921, - "4d": -13.019221, - "4f": -4.110291, - "4p": -19.636187, - "4s": -23.222921, - "5d": -0.452552, - "5p": -2.261975, - "5s": -3.423486, - "6s": -0.205137 - }, - "Atomic radius": 1.5, - "Atomic radius calculated": 1.71, - "Boiling point": "629.88 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "25 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 1, - 2 - ], - "Critical temperature": "1750 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "96 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2", - "ICSD oxidation states": [ - 1, - 2 - ], - "Ionic radii": { - "1": 1.33, - "2": 1.16 - }, - "Liquid range": "395.56 K", - "Melting point": "234.32 K", - "Mendeleev no": 74, - "Mineral hardness": "1.5", - "Molar volume": "14.09 cm3", - "Name": "Mercury", - "Oxidation states": [ - 1, - 2, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "73 %", - "Refractive index": "1.000933", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "1": { - "III": { - "": { - "crystal_radius": 1.11, - "ionic_radius": 0.97 - } - }, - "VI": { - "": { - "crystal_radius": 1.33, - "ionic_radius": 1.19 - } - } - }, - "2": { - "II": { - "": { - "crystal_radius": 0.83, - "ionic_radius": 0.69 - } - }, - "IV": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - }, - "VI": { - "": { - "crystal_radius": 1.16, - "ionic_radius": 1.02 - } - }, - "VIII": { - "": { - "crystal_radius": 1.28, - "ionic_radius": 1.14 - } - } - } - }, - "Superconduction temperature": "3.95 K", - "Thermal conductivity": "8.3 W m-1 K-1", - "Van der waals radius": 1.55, - "Velocity of sound": "1407 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.0, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "Hg-201": 387.6 - } - }, - "Ho": { - "Atomic mass": 164.93032, - "Atomic no": 67, - "Atomic orbitals": { - "1s": -1902.051908, - "2p": -291.700994, - "2s": -305.739294, - "3d": -49.565996, - "3p": -61.436304, - "3s": -67.785492, - "4d": -5.906195, - "4f": -0.272677, - "4p": -10.455303, - "4s": -12.985498, - "5p": -0.919463, - "5s": -1.582088, - "6s": -0.133845 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": "no data", - "Boiling point": "2993 K", - "Brinell hardness": "746 MN m-2", - "Bulk modulus": "40 GPa", - "Coefficient of linear thermal expansion": "11.2 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "8795 kg m-3", - "Electrical resistivity": "81.4 10-8 Ω m", - "Electronic structure": "[Xe].4f11.6s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "3": 1.041 - }, - "Liquid range": "1259 K", - "Melting point": "1734 K", - "Mendeleev no": 23, - "Mineral hardness": "no data", - "Molar volume": "18.74 cm3", - "Name": "Holmium", - "Oxidation states": [ - 3 - ], - "Poissons ratio": "0.23", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "26 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.041, - "ionic_radius": 0.901 - } - }, - "VIII": { - "": { - "crystal_radius": 1.155, - "ionic_radius": 1.015 - } - }, - "IX": { - "": { - "crystal_radius": 1.212, - "ionic_radius": 1.072 - } - }, - "X": { - "": { - "crystal_radius": 1.26, - "ionic_radius": 1.12 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "16 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2760 m s-1", - "Vickers hardness": "481 MN m-2", - "X": 1.23, - "Youngs modulus": "65 GPa" - }, - "I": { - "Atomic mass": 126.90447, - "Atomic no": 53, - "Atomic orbitals": { - "1s": -1161.787047, - "2p": -164.603788, - "2s": -175.073804, - "3d": -22.600693, - "3p": -30.831092, - "3s": -35.243351, - "4d": -1.938179, - "4p": -4.572522, - "4s": -6.115811, - "5p": -0.267904, - "5s": -0.596339 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.15, - "Boiling point": "457.4 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "7.7 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -1, - 1, - 3, - 5, - 7 - ], - "Critical temperature": "819 K", - "Density of solid": "4940 kg m-3", - "Electrical resistivity": "> 101510-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2.5p5", - "ICSD oxidation states": [ - 5, - -1 - ], - "Ionic radii": { - "-1": 2.06, - "5": 1.09, - "7": 0.67 - }, - "Liquid range": "70.55 K", - "Melting point": "386.85 K", - "Mendeleev no": 97, - "Mineral hardness": "no data", - "Molar volume": "25.72 cm3", - "Name": "Iodine", - "Oxidation states": [ - -1, - 1, - 3, - 5, - 7 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-1": { - "VI": { - "": { - "crystal_radius": 2.06, - "ionic_radius": 2.2 - } - } - }, - "5": { - "IIIPY": { - "": { - "crystal_radius": 0.58, - "ionic_radius": 0.44 - } - }, - "VI": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.56, - "ionic_radius": 0.42 - } - }, - "VI": { - "": { - "crystal_radius": 0.67, - "ionic_radius": 0.53 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.449 W m-1 K-1", - "Van der waals radius": 1.98, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.66, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "I-127": -696.12, - "I-129": -604.1 - } - }, - "In": { - "Atomic mass": 114.818, - "Atomic no": 49, - "Atomic orbitals": { - "1s": -983.647445, - "2p": -134.628845, - "2s": -144.078357, - "3d": -16.139823, - "3p": -23.345778, - "3s": -27.2206, - "4d": -0.730481, - "4p": -2.795832, - "4s": -4.062639, - "5p": -0.101782, - "5s": -0.290497 - }, - "Atomic radius": 1.55, - "Atomic radius calculated": 1.56, - "Boiling point": "2345 K", - "Brinell hardness": "8.83 MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "32.1 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "7310 kg m-3", - "Electrical resistivity": "8 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2.5p1", - "ICSD oxidation states": [ - 1, - 2, - 3 - ], - "Ionic radii": { - "3": 0.94 - }, - "Liquid range": "1915.25 K", - "Melting point": "429.75 K", - "Mendeleev no": 79, - "Mineral hardness": "1.2", - "Molar volume": "15.76 cm3", - "Name": "Indium", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "IV": { - "": { - "crystal_radius": 0.76, - "ionic_radius": 0.62 - } - }, - "VI": { - "": { - "crystal_radius": 0.94, - "ionic_radius": 0.8 - } - }, - "VIII": { - "": { - "crystal_radius": 1.06, - "ionic_radius": 0.92 - } - } - } - }, - "Superconduction temperature": "3.41 K", - "Thermal conductivity": "82 W m-1 K-1", - "Van der waals radius": 1.93, - "Velocity of sound": "1215 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.78, - "Youngs modulus": "11 GPa", - "NMR Quadrupole Moment": { - "In-113": 759.8, - "In-115": 770.8 - } - }, - "Ir": { - "Atomic mass": 192.217, - "Atomic no": 77, - "Atomic orbitals": { - "1s": -2543.761342, - "2p": -405.526834, - "2s": -422.159424, - "3d": -75.485027, - "3p": -90.108427, - "3s": -97.923081, - "4d": -10.856593, - "4f": -2.738339, - "4p": -16.966578, - "4s": -20.29429, - "5d": -0.335189, - "5p": -1.883349, - "5s": -2.909174, - "6s": -0.195511 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.8, - "Boiling point": "4701 K", - "Brinell hardness": "1670 MN m-2", - "Bulk modulus": "320 GPa", - "Coefficient of linear thermal expansion": "6.4 x10-6K-1", - "Common oxidation states": [ - 3, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "22650 kg m-3", - "Electrical resistivity": "4.7 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d7.6s2", - "ICSD oxidation states": [ - 3, - 4, - 5 - ], - "Ionic radii": { - "3": 0.82, - "4": 0.765, - "5": 0.71 - }, - "Liquid range": "1962 K", - "Melting point": "2739 K", - "Mendeleev no": 66, - "Mineral hardness": "6.5", - "Molar volume": "8.52 cm3", - "Name": "Iridium", - "Oxidation states": [ - -3, - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.26", - "Reflectivity": "78 %", - "Refractive index": "no data", - "Rigidity modulus": "210 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.82, - "ionic_radius": 0.68 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.765, - "ionic_radius": 0.625 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - } - } - }, - "Superconduction temperature": "0.11 K", - "Thermal conductivity": "150 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4825 m s-1", - "Vickers hardness": "1760 MN m-2", - "X": 2.2, - "Youngs modulus": "528 GPa" - }, - "K": { - "Atomic mass": 39.0983, - "Atomic no": 19, - "Atomic orbitals": { - "1s": -128.414957, - "2p": -10.283851, - "2s": -12.839001, - "3p": -0.693776, - "3s": -1.281897, - "4s": -0.088815 - }, - "Atomic radius": 2.2, - "Atomic radius calculated": 2.43, - "Boiling point": "1032 K", - "Brinell hardness": "0.363 MN m-2", - "Bulk modulus": "3.1 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "2223 K", - "Density of solid": "856 kg m-3", - "Electrical resistivity": "7.5 10-8 Ω m", - "Electronic structure": "[Ar].4s1", - "ICSD oxidation states": [ - 1 - ], - "Ionic radii": { - "1": 1.52 - }, - "Liquid range": "695.47 K", - "Melting point": "336.53 K", - "Mendeleev no": 10, - "Mineral hardness": "0.4", - "Molar volume": "45.94 cm3", - "Name": "Potassium", - "Oxidation states": [ - -1, - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "1.3 GPa", - "Shannon radii": { - "1": { - "IV": { - "": { - "crystal_radius": 1.51, - "ionic_radius": 1.37 - } - }, - "VI": { - "": { - "crystal_radius": 1.52, - "ionic_radius": 1.38 - } - }, - "VII": { - "": { - "crystal_radius": 1.6, - "ionic_radius": 1.46 - } - }, - "VIII": { - "": { - "crystal_radius": 1.65, - "ionic_radius": 1.51 - } - }, - "IX": { - "": { - "crystal_radius": 1.69, - "ionic_radius": 1.55 - } - }, - "X": { - "": { - "crystal_radius": 1.73, - "ionic_radius": 1.59 - } - }, - "XII": { - "": { - "crystal_radius": 1.78, - "ionic_radius": 1.64 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "100 W m-1 K-1", - "Van der waals radius": 2.75, - "Velocity of sound": "2000 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.82, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "K-39": 58.5, - "K-40": -73.0, - "K-41": 71.1 - } - }, - "Kr": { - "Atomic mass": 83.798, - "Atomic no": 36, - "Atomic orbitals": { - "1s": -509.982989, - "2p": -60.017328, - "2s": -66.285953, - "3d": -3.074109, - "3p": -7.086634, - "3s": -9.315192, - "4p": -0.34634, - "4s": -0.820574 - }, - "Atomic radius": "no data", - "Atomic radius calculated": 0.88, - "Boiling point": "119.93 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Critical temperature": "209.4 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2.4p6", - "Liquid range": "4.14 K", - "Max oxidation state": 0.0, - "Melting point": "115.79 K", - "Mendeleev no": 4, - "Min oxidation state": 0.0, - "Mineral hardness": "no data", - "Molar volume": "27.99 cm3", - "Name": "Krypton", - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000427", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.00943 W m-1 K-1", - "Van der waals radius": 2.02, - "Velocity of sound": "1120 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 3.0, - "Youngs modulus": "no data GPa" - }, - "La": { - "Atomic mass": 138.90547, - "Atomic no": 57, - "Atomic orbitals": { - "1s": -1355.622446, - "2p": -198.325243, - "2s": -209.831151, - "3d": -30.626696, - "3p": -39.895838, - "3s": -44.856283, - "4d": -3.95801, - "4p": -7.167724, - "4s": -9.000543, - "5d": -0.141085, - "5p": -0.824498, - "5s": -1.324936, - "6s": -0.132233 - }, - "Atomic radius": 1.95, - "Atomic radius calculated": "no data", - "Boiling point": "3743 K", - "Brinell hardness": "363 MN m-2", - "Bulk modulus": "28 GPa", - "Coefficient of linear thermal expansion": "12.1 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "6146 kg m-3", - "Electrical resistivity": "61.5 10-8 Ω m", - "Electronic structure": "[Xe].5d1.6s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "3": 1.172 - }, - "Liquid range": "2550 K", - "Melting point": "1193 K", - "Mendeleev no": 33, - "Mineral hardness": "2.5", - "Molar volume": "22.39 cm3", - "Name": "Lanthanum", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.28", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "14 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.172, - "ionic_radius": 1.032 - } - }, - "VII": { - "": { - "crystal_radius": 1.24, - "ionic_radius": 1.1 - } - }, - "VIII": { - "": { - "crystal_radius": 1.3, - "ionic_radius": 1.16 - } - }, - "IX": { - "": { - "crystal_radius": 1.356, - "ionic_radius": 1.216 - } - }, - "X": { - "": { - "crystal_radius": 1.41, - "ionic_radius": 1.27 - } - }, - "XII": { - "": { - "crystal_radius": 1.5, - "ionic_radius": 1.36 - } - } - } - }, - "Superconduction temperature": "6.00 K", - "Thermal conductivity": "13 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2475 m s-1", - "Vickers hardness": "491 MN m-2", - "X": 1.1, - "Youngs modulus": "37 GPa", - "NMR Quadrupole Moment": { - "La-139": 200.6 - } - }, - "Li": { - "Atomic mass": 6.941, - "Atomic no": 3, - "Atomic orbitals": { - "1s": -1.878564, - "2s": -0.10554 - }, - "Atomic radius": 1.45, - "Atomic radius calculated": 1.67, - "Boiling point": "1615 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "11 GPa", - "Coefficient of linear thermal expansion": "46 x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "3223 K", - "Density of solid": "535 kg m-3", - "Electrical resistivity": "9.5 10-8 Ω m", - "Electronic structure": "[He].2s1", - "ICSD oxidation states": [ - 1 - ], - "Ionic radii": { - "1": 0.9 - }, - "Liquid range": "1161.31 K", - "Melting point": "453.69 K", - "Mendeleev no": 12, - "Mineral hardness": "0.6", - "Molar volume": "13.02 cm3", - "Name": "Lithium", - "Oxidation states": [ - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "4.2 GPa", - "Shannon radii": { - "1": { - "IV": { - "": { - "crystal_radius": 0.73, - "ionic_radius": 0.59 - } - }, - "VI": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - }, - "VIII": { - "": { - "crystal_radius": 1.06, - "ionic_radius": 0.92 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "85 W m-1 K-1", - "Van der waals radius": 1.82, - "Velocity of sound": "6000 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.98, - "Youngs modulus": "4.9 GPa", - "NMR Quadrupole Moment": { - "Li-6": -0.808, - "Li-7": -40.1 - } - }, - "Lr": { - "Atomic mass": 262.0, - "Atomic no": 103, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f14.7s2.7p1 (tentative)", - "Liquid range": "no data K", - "Melting point": "about 1900 K", - "Mendeleev no": 34, - "Mineral hardness": "no data", - "Molar volume": "no data cm3", - "Name": "Lawrencium", - "Oxidation states": [ - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Lu": { - "Atomic mass": 174.967, - "Atomic no": 71, - "Atomic orbitals": { - "1s": -2146.885351, - "2p": -334.330902, - "2s": -349.390492, - "3d": -58.592982, - "3p": -71.538779, - "3s": -78.462398, - "4d": -7.113364, - "4f": -0.568096, - "4p": -12.250904, - "4s": -15.08337, - "5d": -0.103686, - "5p": -1.111991, - "5s": -1.872086, - "6s": -0.155112 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": 2.17, - "Boiling point": "3675 K", - "Brinell hardness": "893 MN m-2", - "Bulk modulus": "48 GPa", - "Coefficient of linear thermal expansion": "9.9 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "9841 kg m-3", - "Electrical resistivity": "58 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d1.6s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "3": 1.001 - }, - "Liquid range": "1750 K", - "Melting point": "1925 K", - "Mendeleev no": 20, - "Mineral hardness": "no data", - "Molar volume": "17.78 cm3", - "Name": "Lutetium", - "Oxidation states": [ - 3 - ], - "Poissons ratio": "0.26", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "27 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.001, - "ionic_radius": 0.861 - } - }, - "VIII": { - "": { - "crystal_radius": 1.117, - "ionic_radius": 0.977 - } - }, - "IX": { - "": { - "crystal_radius": 1.172, - "ionic_radius": 1.032 - } - } - } - }, - "Superconduction temperature": "0.022 K", - "Thermal conductivity": "16 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "1160 MN m-2", - "X": 1.27, - "Youngs modulus": "69 GPa" - }, - "Md": { - "Atomic mass": 258.0, - "Atomic no": 101, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f13.7s2", - "Liquid range": "no data K", - "Melting point": "about 1100 K", - "Mendeleev no": 36, - "Mineral hardness": "no data", - "Molar volume": "no data cm3", - "Name": "Mendelevium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Mg": { - "Atomic mass": 24.305, - "Atomic no": 12, - "Atomic orbitals": { - "1s": -45.973167, - "2p": -1.71897, - "2s": -2.903746, - "3s": -0.175427 - }, - "Atomic radius": 1.5, - "Atomic radius calculated": 1.45, - "Boiling point": "1363 K", - "Brinell hardness": "260 MN m-2", - "Bulk modulus": "45 GPa", - "Coefficient of linear thermal expansion": "8.2 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "1738 kg m-3", - "Electrical resistivity": "4.4 10-8 Ω m", - "Electronic structure": "[Ne].3s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 0.86 - }, - "Liquid range": "440 K", - "Melting point": "923 K", - "Mendeleev no": 73, - "Mineral hardness": "2.5", - "Molar volume": "14.00 cm3", - "Name": "Magnesium", - "Oxidation states": [ - 1, - 2 - ], - "Poissons ratio": "0.29", - "Reflectivity": "74 %", - "Refractive index": "no data", - "Rigidity modulus": "17 GPa", - "Shannon radii": { - "2": { - "IV": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - }, - "V": { - "": { - "crystal_radius": 0.8, - "ionic_radius": 0.66 - } - }, - "VI": { - "": { - "crystal_radius": 0.86, - "ionic_radius": 0.72 - } - }, - "VIII": { - "": { - "crystal_radius": 1.03, - "ionic_radius": 0.89 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "160 W m-1 K-1", - "Van der waals radius": 1.73, - "Velocity of sound": "4602 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.31, - "Youngs modulus": "45 GPa", - "NMR Quadrupole Moment": { - "Mg-25": 199.4 - } - }, - "Mn": { - "Atomic mass": 54.938045, - "Atomic no": 25, - "Atomic orbitals": { - "1s": -233.696912, - "2p": -23.066297, - "2s": -26.866646, - "3d": -0.26654, - "3p": -1.99145, - "3s": -3.076637, - "4s": -0.191136 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.61, - "Boiling point": "2334 K", - "Brinell hardness": "196 MN m-2", - "Bulk modulus": "120 GPa", - "Coefficient of linear thermal expansion": "21.7 x10-6K-1", - "Common oxidation states": [ - 2, - 4, - 7 - ], - "Critical temperature": "no data K", - "Density of solid": "7470 kg m-3", - "Electrical resistivity": "144 10-8 Ω m", - "Electronic structure": "[Ar].3d5.4s2", - "ICSD oxidation states": [ - 2, - 3, - 4, - 7 - ], - "Ionic radii": { - "2": 0.97, - "3": 0.785, - "4": 0.67, - "5": 0.47, - "6": 0.395, - "7": 0.6 - }, - "Ionic radii hs": { - "2": 0.97, - "3": 0.785 - }, - "Ionic radii ls": { - "2": 0.81, - "3": 0.72, - "4": 0.67, - "5": 0.47, - "6": 0.395, - "7": 0.6 - }, - "Liquid range": "815 K", - "Melting point": "1519 K", - "Mendeleev no": 60, - "Mineral hardness": "6.0", - "Molar volume": "7.35 cm3", - "Name": "Manganese", - "Oxidation states": [ - -3, - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6, - 7 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "2": { - "IV": { - "High Spin": { - "crystal_radius": 0.8, - "ionic_radius": 0.66 - } - }, - "V": { - "High Spin": { - "crystal_radius": 0.89, - "ionic_radius": 0.75 - } - }, - "VI": { - "Low Spin": { - "crystal_radius": 0.81, - "ionic_radius": 0.67 - }, - "High Spin": { - "crystal_radius": 0.97, - "ionic_radius": 0.83 - } - }, - "VII": { - "High Spin": { - "crystal_radius": 1.04, - "ionic_radius": 0.9 - } - }, - "VIII": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - } - }, - "3": { - "V": { - "": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - }, - "VI": { - "Low Spin": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - }, - "High Spin": { - "crystal_radius": 0.785, - "ionic_radius": 0.645 - } - } - }, - "4": { - "IV": { - "": { - "crystal_radius": 0.53, - "ionic_radius": 0.39 - } - }, - "VI": { - "": { - "crystal_radius": 0.67, - "ionic_radius": 0.53 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.47, - "ionic_radius": 0.33 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.395, - "ionic_radius": 0.255 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.39, - "ionic_radius": 0.25 - } - }, - "VI": { - "": { - "crystal_radius": 0.6, - "ionic_radius": 0.46 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "7.8 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "5150 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.55, - "Youngs modulus": "198 GPa", - "NMR Quadrupole Moment": { - "Mn-55": 330.1 - } - }, - "Mo": { - "Atomic mass": 95.94, - "Atomic no": 42, - "Atomic orbitals": { - "1s": -709.232119, - "2p": -90.791541, - "2s": -98.503638, - "3d": -8.257721, - "3p": -13.71481, - "3s": -16.681545, - "4d": -0.153347, - "4p": -1.39005, - "4s": -2.234824, - "5s": -0.14788 - }, - "Atomic radius": 1.45, - "Atomic radius calculated": 1.9, - "Boiling point": "4912 K", - "Brinell hardness": "1500 MN m-2", - "Bulk modulus": "230 GPa", - "Coefficient of linear thermal expansion": "4.8 x10-6K-1", - "Common oxidation states": [ - 4, - 6 - ], - "Critical temperature": "no data K", - "Density of solid": "10280 kg m-3", - "Electrical resistivity": "5.5 10-8 Ω m", - "Electronic structure": "[Kr].4d5.5s1", - "ICSD oxidation states": [ - 2, - 3, - 4, - 5, - 6 - ], - "Ionic radii": { - "3": 0.83, - "4": 0.79, - "5": 0.75, - "6": 0.73 - }, - "Liquid range": "2016 K", - "Melting point": "2896 K", - "Mendeleev no": 56, - "Mineral hardness": "5.5", - "Molar volume": "9.38 cm3", - "Name": "Molybdenum", - "Oxidation states": [ - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.31", - "Reflectivity": "58 %", - "Refractive index": "no data", - "Rigidity modulus": "20 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.83, - "ionic_radius": 0.69 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.79, - "ionic_radius": 0.65 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.6, - "ionic_radius": 0.46 - } - }, - "VI": { - "": { - "crystal_radius": 0.75, - "ionic_radius": 0.61 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.55, - "ionic_radius": 0.41 - } - }, - "V": { - "": { - "crystal_radius": 0.64, - "ionic_radius": 0.5 - } - }, - "VI": { - "": { - "crystal_radius": 0.73, - "ionic_radius": 0.59 - } - }, - "VII": { - "": { - "crystal_radius": 0.87, - "ionic_radius": 0.73 - } - } - } - }, - "Superconduction temperature": "0.915 K", - "Thermal conductivity": "139 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "6190 m s-1", - "Vickers hardness": "1530 MN m-2", - "X": 2.16, - "Youngs modulus": "329 GPa" - }, - "N": { - "Atomic mass": 14.0067, - "Atomic no": 7, - "Atomic orbitals": { - "1s": -14.011501, - "2p": -0.266297, - "2s": -0.676151 - }, - "Atomic radius": 0.65, - "Atomic radius calculated": 0.56, - "Boiling point": "77.36 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -3, - 3, - 5 - ], - "Critical temperature": "126.2 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[He].2s2.2p3", - "ICSD oxidation states": [ - 1, - 3, - 5, - -1, - -3, - -2 - ], - "Ionic radii": { - "-3": 1.32, - "3": 0.3, - "5": 0.27 - }, - "Liquid range": "14.31 K", - "Melting point": "63.05 K", - "Mendeleev no": 100, - "Mineral hardness": "no data", - "Molar volume": "13.54 cm3", - "Name": "Nitrogen", - "Oxidation states": [ - -3, - -2, - -1, - 1, - 2, - 3, - 4, - 5 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000298 (gas; liquid 1.197)(no units)", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-3": { - "IV": { - "": { - "crystal_radius": 1.32, - "ionic_radius": 1.46 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 0.3, - "ionic_radius": 0.16 - } - } - }, - "5": { - "III": { - "": { - "crystal_radius": 0.044, - "ionic_radius": -0.104 - } - }, - "VI": { - "": { - "crystal_radius": 0.27, - "ionic_radius": 0.13 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.02583 W m-1 K-1", - "Van der waals radius": 1.55, - "Velocity of sound": "333.6 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 3.04, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "N-14": 20.44 - } - }, - "Na": { - "Atomic mass": 22.98976928, - "Atomic no": 11, - "Atomic orbitals": { - "1s": -37.719975, - "2p": -1.060636, - "2s": -2.063401, - "3s": -0.103415 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": 1.9, - "Boiling point": "1156 K", - "Brinell hardness": "0.69 MN m-2", - "Bulk modulus": "6.3 GPa", - "Coefficient of linear thermal expansion": "71 x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "2573 K", - "Density of solid": "968 kg m-3", - "Electrical resistivity": "4.9 10-8 Ω m", - "Electronic structure": "[Ne].3s1", - "ICSD oxidation states": [ - 1 - ], - "Ionic radii": { - "1": 1.16 - }, - "Liquid range": "785.13 K", - "Melting point": "370.87 K", - "Mendeleev no": 11, - "Mineral hardness": "0.5", - "Molar volume": "23.78 cm3", - "Name": "Sodium", - "Oxidation states": [ - -1, - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "3.3 GPa", - "Shannon radii": { - "1": { - "IV": { - "": { - "crystal_radius": 1.13, - "ionic_radius": 0.99 - } - }, - "V": { - "": { - "crystal_radius": 1.14, - "ionic_radius": 1.0 - } - }, - "VI": { - "": { - "crystal_radius": 1.16, - "ionic_radius": 1.02 - } - }, - "VII": { - "": { - "crystal_radius": 1.26, - "ionic_radius": 1.12 - } - }, - "VIII": { - "": { - "crystal_radius": 1.32, - "ionic_radius": 1.18 - } - }, - "IX": { - "": { - "crystal_radius": 1.38, - "ionic_radius": 1.24 - } - }, - "XII": { - "": { - "crystal_radius": 1.53, - "ionic_radius": 1.39 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "140 W m-1 K-1", - "Van der waals radius": 2.27, - "Velocity of sound": "3200 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.93, - "Youngs modulus": "10 GPa", - "NMR Quadrupole Moment": { - "Na-23": 104.1 - } - }, - "Nb": { - "Atomic mass": 92.90638, - "Atomic no": 41, - "Atomic orbitals": { - "1s": -673.76253, - "2p": -85.272175, - "2s": -92.74086, - "3d": -7.339839, - "3p": -12.552855, - "3s": -15.393727, - "4d": -0.125252, - "4p": -1.250049, - "4s": -2.036693, - "5s": -0.144272 - }, - "Atomic radius": 1.45, - "Atomic radius calculated": 1.98, - "Boiling point": "5017 K", - "Brinell hardness": "736 MN m-2", - "Bulk modulus": "170 GPa", - "Coefficient of linear thermal expansion": "7.3 x10-6K-1", - "Common oxidation states": [ - 5 - ], - "Critical temperature": "no data K", - "Density of solid": "8570 kg m-3", - "Electrical resistivity": "15.2 10-8 Ω m", - "Electronic structure": "[Kr].4d4.5s1", - "ICSD oxidation states": [ - 2, - 3, - 4, - 5 - ], - "Ionic radii": { - "3": 0.86, - "4": 0.82, - "5": 0.78 - }, - "Liquid range": "2267 K", - "Melting point": "2750 K", - "Mendeleev no": 53, - "Mineral hardness": "6.0", - "Molar volume": "10.83 cm3", - "Name": "Niobium", - "Oxidation states": [ - -1, - 2, - 3, - 4, - 5 - ], - "Poissons ratio": "0.40", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "38 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.86, - "ionic_radius": 0.72 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.82, - "ionic_radius": 0.68 - } - }, - "VIII": { - "": { - "crystal_radius": 0.93, - "ionic_radius": 0.79 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.62, - "ionic_radius": 0.48 - } - }, - "VI": { - "": { - "crystal_radius": 0.78, - "ionic_radius": 0.64 - } - }, - "VII": { - "": { - "crystal_radius": 0.83, - "ionic_radius": 0.69 - } - }, - "VIII": { - "": { - "crystal_radius": 0.88, - "ionic_radius": 0.74 - } - } - } - }, - "Superconduction temperature": "9.25 K", - "Thermal conductivity": "54 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "3480 m s-1", - "Vickers hardness": "1320 MN m-2", - "X": 1.6, - "Youngs modulus": "105 GPa" - }, - "Nd": { - "Atomic mass": 144.242, - "Atomic no": 60, - "Atomic orbitals": { - "1s": -1509.698955, - "2p": -224.351816, - "2s": -236.613572, - "3d": -35.754515, - "3p": -45.791219, - "3s": -51.161263, - "4d": -4.377027, - "4f": -0.179508, - "4p": -7.96782, - "4s": -10.000891, - "5p": -0.798503, - "5s": -1.334934, - "6s": -0.125796 - }, - "Atomic radius": 1.85, - "Atomic radius calculated": 2.06, - "Boiling point": "3373 K", - "Brinell hardness": "265 MN m-2", - "Bulk modulus": "32 GPa", - "Coefficient of linear thermal expansion": "9.6 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "6800 kg m-3", - "Electrical resistivity": "64.3 10-8 Ω m", - "Electronic structure": "[Xe].4f4.6s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "2": 1.43, - "3": 1.123 - }, - "Liquid range": "2076 K", - "Melting point": "1297 K", - "Mendeleev no": 30, - "Mineral hardness": "no data", - "Molar volume": "20.59 cm3", - "Name": "Neodymium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.28", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "16 GPa", - "Shannon radii": { - "2": { - "VIII": { - "": { - "crystal_radius": 1.43, - "ionic_radius": 1.29 - } - }, - "IX": { - "": { - "crystal_radius": 1.49, - "ionic_radius": 1.35 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.123, - "ionic_radius": 0.983 - } - }, - "VIII": { - "": { - "crystal_radius": 1.249, - "ionic_radius": 1.109 - } - }, - "IX": { - "": { - "crystal_radius": 1.303, - "ionic_radius": 1.163 - } - }, - "XII": { - "": { - "crystal_radius": 1.41, - "ionic_radius": 1.27 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "17 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2330 m s-1", - "Vickers hardness": "343 MN m-2", - "X": 1.14, - "Youngs modulus": "41 GPa" - }, - "Ne": { - "Atomic mass": 20.1797, - "Atomic no": 10, - "Atomic orbitals": { - "1s": -30.305855, - "2p": -0.498034, - "2s": -1.322809 - }, - "Atomic radius": "no data", - "Atomic radius calculated": 0.38, - "Boiling point": "27.07 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Critical temperature": "44.4 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[He].2s2.2p6", - "Liquid range": "2.51 K", - "Max oxidation state": 0.0, - "Melting point": "24.56 K", - "Mendeleev no": 2, - "Min oxidation state": 0.0, - "Mineral hardness": "no data", - "Molar volume": "13.23 cm3", - "Name": "Neon", - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000067", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.0491 W m-1 K-1", - "Van der waals radius": 1.54, - "Velocity of sound": "936 m s-1", - "Vickers hardness": "no data MN m-2", - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "Ne-21": 101.55 - } - }, - "Ni": { - "Atomic mass": 58.6934, - "Atomic no": 28, - "Atomic orbitals": { - "1s": -297.870824, - "2p": -30.868027, - "2s": -35.312112, - "3d": -0.348699, - "3p": -2.594158, - "3s": -3.950717, - "4s": -0.210764 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.49, - "Boiling point": "3186 K", - "Brinell hardness": "700 MN m-2", - "Bulk modulus": "180 GPa", - "Coefficient of linear thermal expansion": "13.4 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "8908 kg m-3", - "Electrical resistivity": "7.2 10-8 Ω m", - "Electronic structure": "[Ar].3d8.4s2", - "ICSD oxidation states": [ - 1, - 2, - 3, - 4 - ], - "Ionic radii": { - "3": 0.74 - }, - "Ionic radii hs": { - "3": 0.74 - }, - "Ionic radii ls": { - "2": 0.83, - "3": 0.7, - "4": 0.62 - }, - "Liquid range": "1458 K", - "Melting point": "1728 K", - "Mendeleev no": 67, - "Mineral hardness": "4.0", - "Molar volume": "6.59 cm3", - "Name": "Nickel", - "Oxidation states": [ - -1, - 1, - 2, - 3, - 4 - ], - "Poissons ratio": "0.31", - "Reflectivity": "72 %", - "Refractive index": "no data", - "Rigidity modulus": "76 GPa", - "Shannon radii": { - "2": { - "IV": { - "": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - } - }, - "IVSQ": { - "": { - "crystal_radius": 0.63, - "ionic_radius": 0.49 - } - }, - "V": { - "": { - "crystal_radius": 0.77, - "ionic_radius": 0.63 - } - }, - "VI": { - "": { - "crystal_radius": 0.83, - "ionic_radius": 0.69 - } - } - }, - "3": { - "VI": { - "Low Spin": { - "crystal_radius": 0.7, - "ionic_radius": 0.56 - }, - "High Spin": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - } - }, - "4": { - "VI": { - "Low Spin": { - "crystal_radius": 0.62, - "ionic_radius": 0.48 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "91 W m-1 K-1", - "Van der waals radius": 1.63, - "Velocity of sound": "4970 m s-1", - "Vickers hardness": "638 MN m-2", - "X": 1.91, - "Youngs modulus": "200 GPa", - "NMR Quadrupole Moment": { - "Ni-61": 162.15 - } - }, - "No": { - "Atomic mass": 259.0, - "Atomic no": 102, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f14.7s2", - "Liquid range": "no data K", - "Melting point": "about 1100 K", - "Mendeleev no": 35, - "Mineral hardness": "no data", - "Molar volume": "no data cm3", - "Name": "Nobelium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.24, - "ionic_radius": 1.1 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Np": { - "Atomic mass": 237.0, - "Atomic no": 93, - "Atomic orbitals": "no data", - "Atomic radius": 1.75, - "Atomic radius calculated": "no data", - "Boiling point": "4273 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 5 - ], - "Critical temperature": "no data K", - "Density of solid": "20450 kg m-3", - "Electrical resistivity": "120 10-8 Ω m", - "Electronic structure": "[Rn].5f4.6d1.7s2", - "Ionic radii": { - "2": 1.24, - "3": 1.15, - "4": 1.01, - "5": 0.89, - "6": 0.86, - "7": 0.85 - }, - "Liquid range": "3363 K", - "Melting point": "910 K", - "Mendeleev no": 44, - "Mineral hardness": "no data", - "Molar volume": "11.59 cm3", - "Name": "Neptunium", - "Oxidation states": [ - 3, - 4, - 5, - 6, - 7 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.24, - "ionic_radius": 1.1 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.15, - "ionic_radius": 1.01 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 1.01, - "ionic_radius": 0.87 - } - }, - "VIII": { - "": { - "crystal_radius": 1.12, - "ionic_radius": 0.98 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.89, - "ionic_radius": 0.75 - } - } - }, - "6": { - "VI": { - "": { - "crystal_radius": 0.86, - "ionic_radius": 0.72 - } - } - }, - "7": { - "VI": { - "": { - "crystal_radius": 0.85, - "ionic_radius": 0.71 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "6 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.36, - "Youngs modulus": "no data GPa" - }, - "O": { - "Atomic mass": 15.9994, - "Atomic no": 8, - "Atomic orbitals": { - "1s": -18.758245, - "2p": -0.338381, - "2s": -0.871362 - }, - "Atomic radius": 0.6, - "Atomic radius calculated": 0.48, - "Boiling point": "90.2 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -2 - ], - "Critical temperature": "154.6 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[He].2s2.2p4", - "ICSD oxidation states": [ - -2 - ], - "Ionic radii": { - "-2": 1.26 - }, - "Liquid range": "35.4 K", - "Melting point": "54.8 K", - "Mendeleev no": 101, - "Mineral hardness": "no data", - "Molar volume": "17.36 cm3", - "Name": "Oxygen", - "Oxidation states": [ - -2, - -1, - 1, - 2 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000271 (gas; liquid 1.221)(no units)", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-2": { - "II": { - "": { - "crystal_radius": 1.21, - "ionic_radius": 1.35 - } - }, - "III": { - "": { - "crystal_radius": 1.22, - "ionic_radius": 1.36 - } - }, - "IV": { - "": { - "crystal_radius": 1.24, - "ionic_radius": 1.38 - } - }, - "VI": { - "": { - "crystal_radius": 1.26, - "ionic_radius": 1.4 - } - }, - "VIII": { - "": { - "crystal_radius": 1.28, - "ionic_radius": 1.42 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.02658 W m-1 K-1", - "Van der waals radius": 1.52, - "Velocity of sound": "317.5 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 3.44, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "O-17": -25.58 - } - }, - "Os": { - "Atomic mass": 190.23, - "Atomic no": 76, - "Atomic orbitals": { - "1s": -2475.238617, - "2p": -393.15408, - "2s": -409.522396, - "3d": -72.497183, - "3p": -86.837047, - "3s": -94.501324, - "4d": -10.176082, - "4f": -2.321175, - "4p": -16.119671, - "4s": -19.362527, - "5d": -0.296791, - "5p": -1.757404, - "5s": -2.738293, - "6s": -0.191489 - }, - "Atomic radius": 1.3, - "Atomic radius calculated": 1.85, - "Boiling point": "5285 K", - "Brinell hardness": "3920 MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "5.1 x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "22610 kg m-3", - "Electrical resistivity": "8.1 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d6.6s2", - "Ionic radii": { - "4": 0.77, - "5": 0.715, - "6": 0.685, - "7": 0.665, - "8": 0.53 - }, - "Liquid range": "1979 K", - "Melting point": "3306 K", - "Mendeleev no": 63, - "Mineral hardness": "7.0", - "Molar volume": "8.42 cm3", - "Name": "Osmium", - "Oxidation states": [ - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8 - ], - "Poissons ratio": "0.25", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "222 GPa", - "Shannon radii": { - "4": { - "VI": { - "": { - "crystal_radius": 0.77, - "ionic_radius": 0.63 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.715, - "ionic_radius": 0.575 - } - } - }, - "6": { - "V": { - "": { - "crystal_radius": 0.63, - "ionic_radius": 0.49 - } - }, - "VI": { - "": { - "crystal_radius": 0.685, - "ionic_radius": 0.545 - } - } - }, - "7": { - "VI": { - "": { - "crystal_radius": 0.665, - "ionic_radius": 0.525 - } - } - }, - "8": { - "IV": { - "": { - "crystal_radius": 0.53, - "ionic_radius": 0.39 - } - } - } - }, - "Superconduction temperature": "0.66 K", - "Thermal conductivity": "88 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4940 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.2, - "Youngs modulus": "no data GPa" - }, - "P": { - "Atomic mass": 30.973762, - "Atomic no": 15, - "Atomic orbitals": { - "1s": -76.061897, - "2p": -4.576617, - "2s": -6.329346, - "3p": -0.20608, - "3s": -0.512364 - }, - "Atomic radius": 1.0, - "Atomic radius calculated": 0.98, - "Boiling point": "550 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "11 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -3, - 3, - 5 - ], - "Critical temperature": "994 K", - "Density of solid": "1823 kg m-3", - "Electrical resistivity": "about 10 10-8 Ω m", - "Electronic structure": "[Ne].3s2.3p3", - "ICSD oxidation states": [ - 3, - 4, - 5, - -2, - -3, - -1 - ], - "Ionic radii": { - "3": 0.58, - "5": 0.52 - }, - "Liquid range": "232.7 K", - "Melting point": "(white P) 317.3 K", - "Mendeleev no": 90, - "Mineral hardness": "no data", - "Molar volume": "17.02 cm3", - "Name": "Phosphorus", - "Oxidation states": [ - -3, - -2, - -1, - 1, - 2, - 3, - 4, - 5 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.001212", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.58, - "ionic_radius": 0.44 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.31, - "ionic_radius": 0.17 - } - }, - "V": { - "": { - "crystal_radius": 0.43, - "ionic_radius": 0.29 - } - }, - "VI": { - "": { - "crystal_radius": 0.52, - "ionic_radius": 0.38 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.236 W m-1 K-1", - "Van der waals radius": 1.8, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.19, - "Youngs modulus": "no data GPa" - }, - "Pa": { - "Atomic mass": 231.03588, - "Atomic no": 91, - "Atomic orbitals": { - "1s": -3606.333629, - "2p": -603.470278, - "2s": -623.870431, - "3d": -127.781168, - "3p": -146.485678, - "3s": -156.466742, - "4d": -25.933121, - "4f": -14.105747, - "4p": -34.48293, - "4s": -39.064507, - "5d": -3.659928, - "5f": -0.316813, - "5p": -6.709821, - "5s": -8.463463, - "6d": -0.142481, - "6p": -0.799756, - "6s": -1.287232, - "7s": -0.129653 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 5 - ], - "Critical temperature": "no data K", - "Density of solid": "15370 kg m-3", - "Electrical resistivity": "18 10-8 Ω m", - "Electronic structure": "[Rn].5f2.6d1.7s2", - "Ionic radii": { - "3": 1.16, - "4": 1.04, - "5": 0.92 - }, - "Liquid range": "no data K", - "Melting point": "1841 K", - "Mendeleev no": 46, - "Mineral hardness": "no data", - "Molar volume": "15.18 cm3", - "Name": "Protactinium", - "Oxidation states": [ - 3, - 4, - 5 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.18, - "ionic_radius": 1.04 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 1.04, - "ionic_radius": 0.9 - } - }, - "VIII": { - "": { - "crystal_radius": 1.15, - "ionic_radius": 1.01 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.92, - "ionic_radius": 0.78 - } - }, - "VIII": { - "": { - "crystal_radius": 1.05, - "ionic_radius": 0.91 - } - }, - "IX": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - } - } - }, - "Superconduction temperature": "1.4 K", - "Thermal conductivity": "47 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.5, - "Youngs modulus": "no data GPa" - }, - "Pb": { - "Atomic mass": 207.2, - "Atomic no": 82, - "Atomic orbitals": { - "1s": -2901.078061, - "2p": -470.877785, - "2s": -488.843335, - "3d": -91.889924, - "3p": -107.950391, - "3s": -116.526852, - "4d": -15.030026, - "4f": -5.592532, - "4p": -21.990564, - "4s": -25.75333, - "5d": -0.902393, - "5p": -2.941657, - "5s": -4.206797, - "6p": -0.141831, - "6s": -0.357187 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": 1.54, - "Boiling point": "2022 K", - "Brinell hardness": "38.3 MN m-2", - "Bulk modulus": "46 GPa", - "Coefficient of linear thermal expansion": "28.9 x10-6K-1", - "Common oxidation states": [ - 2, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "11340 kg m-3", - "Electrical resistivity": "21 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2.6p2", - "ICSD oxidation states": [ - 2, - 4 - ], - "Ionic radii": { - "2": 1.33, - "4": 0.915 - }, - "Liquid range": "1421.39 K", - "Melting point": "600.61 K", - "Mendeleev no": 82, - "Mineral hardness": "1.5", - "Molar volume": "18.26 cm3", - "Name": "Lead", - "Oxidation states": [ - -4, - 2, - 4 - ], - "Poissons ratio": "0.44", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "5.6 GPa", - "Shannon radii": { - "2": { - "IVPY": { - "": { - "crystal_radius": 1.12, - "ionic_radius": 0.98 - } - }, - "VI": { - "": { - "crystal_radius": 1.33, - "ionic_radius": 1.19 - } - }, - "VII": { - "": { - "crystal_radius": 1.37, - "ionic_radius": 1.23 - } - }, - "VIII": { - "": { - "crystal_radius": 1.43, - "ionic_radius": 1.29 - } - }, - "IX": { - "": { - "crystal_radius": 1.49, - "ionic_radius": 1.35 - } - }, - "X": { - "": { - "crystal_radius": 1.54, - "ionic_radius": 1.4 - } - }, - "XI": { - "": { - "crystal_radius": 1.59, - "ionic_radius": 1.45 - } - }, - "XII": { - "": { - "crystal_radius": 1.63, - "ionic_radius": 1.49 - } - } - }, - "4": { - "IV": { - "": { - "crystal_radius": 0.79, - "ionic_radius": 0.65 - } - }, - "V": { - "": { - "crystal_radius": 0.87, - "ionic_radius": 0.73 - } - }, - "VI": { - "": { - "crystal_radius": 0.915, - "ionic_radius": 0.775 - } - }, - "VIII": { - "": { - "crystal_radius": 1.08, - "ionic_radius": 0.94 - } - } - } - }, - "Superconduction temperature": "7.2 K", - "Thermal conductivity": "35 W m-1 K-1", - "Van der waals radius": 2.02, - "Velocity of sound": "1260 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.33, - "Youngs modulus": "16 GPa" - }, - "Pd": { - "Atomic mass": 106.42, - "Atomic no": 46, - "Atomic orbitals": { - "1s": -860.134909, - "2p": -114.408286, - "2s": -123.105078, - "3d": -12.132197, - "3p": -18.580798, - "3s": -22.060898, - "4d": -0.160771, - "4p": -1.815215, - "4s": -2.889173 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.69, - "Boiling point": "3236 K", - "Brinell hardness": "37.3 MN m-2", - "Bulk modulus": "180 GPa", - "Coefficient of linear thermal expansion": "11.8 x10-6K-1", - "Common oxidation states": [ - 2, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "12023 kg m-3", - "Electrical resistivity": "10.8 10-8 Ω m", - "Electronic structure": "[Kr].4d10", - "ICSD oxidation states": [ - 2, - 4 - ], - "Ionic radii": { - "1": 0.73, - "2": 1.0, - "3": 0.9, - "4": 0.755 - }, - "Liquid range": "1407.95 K", - "Melting point": "1828.05 K", - "Mendeleev no": 69, - "Mineral hardness": "4.75", - "Molar volume": "8.56 cm3", - "Name": "Palladium", - "Oxidation states": [ - 2, - 4 - ], - "Poissons ratio": "0.39", - "Reflectivity": "72 %", - "Refractive index": "no data", - "Rigidity modulus": "44 GPa", - "Shannon radii": { - "1": { - "II": { - "": { - "crystal_radius": 0.73, - "ionic_radius": 0.59 - } - } - }, - "2": { - "IVSQ": { - "": { - "crystal_radius": 0.78, - "ionic_radius": 0.64 - } - }, - "VI": { - "": { - "crystal_radius": 1.0, - "ionic_radius": 0.86 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.755, - "ionic_radius": 0.615 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "72 W m-1 K-1", - "Van der waals radius": 1.63, - "Velocity of sound": "3070 m s-1", - "Vickers hardness": "461 MN m-2", - "X": 2.2, - "Youngs modulus": "121 GPa" - }, - "Pm": { - "Atomic mass": 145.0, - "Atomic no": 61, - "Atomic orbitals": { - "1s": -1562.980284, - "2p": -233.455114, - "2s": -245.970548, - "3d": -37.625433, - "3p": -47.921132, - "3s": -53.429311, - "4d": -4.596822, - "4f": -0.200159, - "4p": -8.320495, - "4s": -10.422756, - "5p": -0.817702, - "5s": -1.372265, - "6s": -0.127053 - }, - "Atomic radius": 1.85, - "Atomic radius calculated": 2.05, - "Boiling point": "3273 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "33 GPa", - "Coefficient of linear thermal expansion": "11 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "7264 kg m-3", - "Electrical resistivity": "about 75 10-8 Ω m", - "Electronic structure": "[Xe].4f5.6s2", - "Ionic radii": { - "3": 1.11 - }, - "Liquid range": "1900 K", - "Melting point": "1373 K", - "Mendeleev no": 29, - "Mineral hardness": "no data", - "Molar volume": "20.23 cm3", - "Name": "Promethium", - "Oxidation states": [ - 3 - ], - "Poissons ratio": "0.28", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "18 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.11, - "ionic_radius": 0.97 - } - }, - "VIII": { - "": { - "crystal_radius": 1.233, - "ionic_radius": 1.093 - } - }, - "IX": { - "": { - "crystal_radius": 1.284, - "ionic_radius": 1.144 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "15 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.13, - "Youngs modulus": "46 GPa" - }, - "Po": { - "Atomic mass": 210.0, - "Atomic no": 84, - "Atomic orbitals": { - "1s": -3050.988417, - "2p": -498.77192, - "2s": -517.275843, - "3d": -99.256068, - "3p": -115.898384, - "3s": -124.783683, - "4d": -17.173307, - "4f": -7.206499, - "4p": -24.481337, - "4s": -28.42254, - "5d": -1.386458, - "5p": -3.655382, - "5s": -5.027447, - "6p": -0.217889, - "6s": -0.493528 - }, - "Atomic radius": 1.9, - "Atomic radius calculated": 1.35, - "Boiling point": "1235 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -2, - 2, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "9196 kg m-3", - "Electrical resistivity": "40 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2.6p4", - "Ionic radii": { - "4": 1.08, - "6": 0.81 - }, - "Liquid range": "708 K", - "Melting point": "527 K", - "Mendeleev no": 91, - "Mineral hardness": "no data", - "Molar volume": "22.97 cm3", - "Name": "Polonium", - "Oxidation states": [ - -2, - 2, - 4, - 6 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "4": { - "VI": { - "": { - "crystal_radius": 1.08, - "ionic_radius": 0.94 - } - }, - "VIII": { - "": { - "crystal_radius": 1.22, - "ionic_radius": 1.08 - } - } - }, - "6": { - "VI": { - "": { - "crystal_radius": 0.81, - "ionic_radius": 0.67 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "20 W m-1 K-1", - "Van der waals radius": 1.97, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.0, - "Youngs modulus": "no data GPa" - }, - "Pr": { - "Atomic mass": 140.90765, - "Atomic no": 59, - "Atomic orbitals": { - "1s": -1457.338067, - "2p": -215.418313, - "2s": -227.426363, - "3d": -33.913996, - "3p": -43.692548, - "3s": -48.924994, - "4d": -4.154228, - "4f": -0.155138, - "4p": -7.613108, - "4s": -9.577447, - "5p": -0.778046, - "5s": -1.296106, - "6s": -0.124465 - }, - "Atomic radius": 1.85, - "Atomic radius calculated": 2.47, - "Boiling point": "3563 K", - "Brinell hardness": "481 MN m-2", - "Bulk modulus": "29 GPa", - "Coefficient of linear thermal expansion": "6.7 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "6640 kg m-3", - "Electrical resistivity": "70 10-8 Ω m", - "Electronic structure": "[Xe].4f3.6s2", - "ICSD oxidation states": [ - 3, - 4 - ], - "Ionic radii": { - "3": 1.13, - "4": 0.99 - }, - "Liquid range": "2355 K", - "Melting point": "1208 K", - "Mendeleev no": 31, - "Mineral hardness": "no data", - "Molar volume": "20.80 cm3", - "Name": "Praseodymium", - "Oxidation states": [ - 2, - 3, - 4 - ], - "Poissons ratio": "0.28", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "15 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.13, - "ionic_radius": 0.99 - } - }, - "VIII": { - "": { - "crystal_radius": 1.266, - "ionic_radius": 1.126 - } - }, - "IX": { - "": { - "crystal_radius": 1.319, - "ionic_radius": 1.179 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.99, - "ionic_radius": 0.85 - } - }, - "VIII": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "13 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2280 m s-1", - "Vickers hardness": "400 MN m-2", - "X": 1.13, - "Youngs modulus": "37 GPa" - }, - "Pt": { - "Atomic mass": 195.084, - "Atomic no": 78, - "Atomic orbitals": { - "1s": -2613.096532, - "2p": -417.96053, - "2s": -434.858003, - "3d": -78.400271, - "3p": -93.309108, - "3s": -101.274869, - "4d": -11.419476, - "4f": -3.038049, - "4p": -17.697297, - "4s": -21.110651, - "5d": -0.273634, - "5p": -1.884256, - "5s": -2.950526, - "6s": -0.161308 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.77, - "Boiling point": "4098 K", - "Brinell hardness": "392 MN m-2", - "Bulk modulus": "230 GPa", - "Coefficient of linear thermal expansion": "8.8 x10-6K-1", - "Common oxidation states": [ - 2, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "21090 kg m-3", - "Electrical resistivity": "10.6 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d9.6s1", - "Ionic radii": { - "2": 0.94, - "4": 0.765, - "5": 0.71 - }, - "Liquid range": "2056.6 K", - "Melting point": "2041.4 K", - "Mendeleev no": 68, - "Mineral hardness": "3.5", - "Molar volume": "9.09 cm3", - "Name": "Platinum", - "Oxidation states": [ - -2, - 2, - 4, - 5, - 6 - ], - "Poissons ratio": "0.38", - "Reflectivity": "73 %", - "Refractive index": "no data", - "Rigidity modulus": "61 GPa", - "Shannon radii": { - "2": { - "IVSQ": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - }, - "VI": { - "": { - "crystal_radius": 0.94, - "ionic_radius": 0.8 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.765, - "ionic_radius": 0.625 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "72 W m-1 K-1", - "Van der waals radius": 1.75, - "Velocity of sound": "2680 m s-1", - "Vickers hardness": "549 MN m-2", - "X": 2.28, - "Youngs modulus": "168 GPa" - }, - "Pu": { - "Atomic mass": 244.0, - "Atomic no": 94, - "Atomic orbitals": "no data", - "Atomic radius": 1.75, - "Atomic radius calculated": "no data", - "Boiling point": "3503 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "19816 kg m-3", - "Electrical resistivity": "150 10-8 Ω m", - "Electronic structure": "[Rn].5f6.7s2", - "Ionic radii": { - "3": 1.14, - "4": 1.0, - "5": 0.88, - "6": 0.85 - }, - "Liquid range": "2590.5 K", - "Melting point": "912.5 K", - "Mendeleev no": 43, - "Mineral hardness": "no data", - "Molar volume": "12.29 cm3", - "Name": "Plutonium", - "Oxidation states": [ - 3, - 4, - 5, - 6, - 7 - ], - "Poissons ratio": "0.21", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "43 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.14, - "ionic_radius": 1.0 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 1.0, - "ionic_radius": 0.86 - } - }, - "VIII": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.88, - "ionic_radius": 0.74 - } - } - }, - "6": { - "VI": { - "": { - "crystal_radius": 0.85, - "ionic_radius": 0.71 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "6 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2260 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.28, - "Youngs modulus": "96 GPa" - }, - "Ra": { - "Atomic mass": 226.0, - "Atomic no": 88, - "Atomic orbitals": { - "1s": -3362.736563, - "2p": -557.513214, - "2s": -577.101208, - "3d": -115.306476, - "3p": -133.12325, - "3s": -142.632426, - "4d": -22.208125, - "4f": -11.181066, - "4p": -30.221208, - "4s": -34.525628, - "5d": -2.819853, - "5p": -5.547203, - "5s": -7.139137, - "6p": -0.634674, - "6s": -1.05135, - "7s": -0.113732 - }, - "Atomic radius": 2.15, - "Atomic radius calculated": "no data", - "Boiling point": "2010 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "5000 kg m-3", - "Electrical resistivity": "100 10-8 Ω m", - "Electronic structure": "[Rn].7s2", - "Ionic radii": { - "2": 1.62 - }, - "Liquid range": "1037 K", - "Melting point": "973 K", - "Mendeleev no": 13, - "Mineral hardness": "no data", - "Molar volume": "41.09 cm3", - "Name": "Radium", - "Oxidation states": [ - 2 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "2": { - "VIII": { - "": { - "crystal_radius": 1.62, - "ionic_radius": 1.48 - } - }, - "XII": { - "": { - "crystal_radius": 1.84, - "ionic_radius": 1.7 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "19 W m-1 K-1", - "Van der waals radius": 2.83, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.9, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "Ra-223": 1210.3 - } - }, - "Rb": { - "Atomic mass": 85.4678, - "Atomic no": 37, - "Atomic orbitals": { - "1s": -540.957115, - "2p": -64.784678, - "2s": -71.291202, - "3d": -3.915508, - "3p": -8.165416, - "3s": -10.513861, - "4p": -0.59217, - "4s": -1.135051, - "5s": -0.085375 - }, - "Atomic radius": 2.35, - "Atomic radius calculated": 2.65, - "Boiling point": "961 K", - "Brinell hardness": "0.216 MN m-2", - "Bulk modulus": "2.5 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "2093 K", - "Density of solid": "1532 kg m-3", - "Electrical resistivity": "13.3 10-8 Ω m", - "Electronic structure": "[Kr].5s1", - "ICSD oxidation states": [ - 1 - ], - "Ionic radii": { - "1": 1.66 - }, - "Liquid range": "648.54 K", - "Melting point": "312.46 K", - "Mendeleev no": 9, - "Mineral hardness": "0.3", - "Molar volume": "55.76 cm3", - "Name": "Rubidium", - "Oxidation states": [ - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "1": { - "VI": { - "": { - "crystal_radius": 1.66, - "ionic_radius": 1.52 - } - }, - "VII": { - "": { - "crystal_radius": 1.7, - "ionic_radius": 1.56 - } - }, - "VIII": { - "": { - "crystal_radius": 1.75, - "ionic_radius": 1.61 - } - }, - "IX": { - "": { - "crystal_radius": 1.77, - "ionic_radius": 1.63 - } - }, - "X": { - "": { - "crystal_radius": 1.8, - "ionic_radius": 1.66 - } - }, - "XI": { - "": { - "crystal_radius": 1.83, - "ionic_radius": 1.69 - } - }, - "XII": { - "": { - "crystal_radius": 1.86, - "ionic_radius": 1.72 - } - }, - "XIV": { - "": { - "crystal_radius": 1.97, - "ionic_radius": 1.83 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "58 W m-1 K-1", - "Van der waals radius": 3.03, - "Velocity of sound": "1300 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.82, - "Youngs modulus": "2.4 GPa" - }, - "Re": { - "Atomic mass": 186.207, - "Atomic no": 75, - "Atomic orbitals": { - "1s": -2407.665572, - "2p": -380.982869, - "2s": -397.087707, - "3d": -69.57676, - "3p": -83.634578, - "3s": -91.149193, - "4d": -9.516816, - "4f": -1.92508, - "4p": -15.295495, - "4s": -18.454325, - "5d": -0.258639, - "5p": -1.631227, - "5s": -2.567348, - "6s": -0.186859 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.88, - "Boiling point": "5869 K", - "Brinell hardness": "1320 MN m-2", - "Bulk modulus": "370 GPa", - "Coefficient of linear thermal expansion": "6.2 x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "21020 kg m-3", - "Electrical resistivity": "18 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d5.6s2", - "ICSD oxidation states": [ - 3, - 4, - 5, - 6, - 7 - ], - "Ionic radii": { - "4": 0.77, - "5": 0.72, - "6": 0.69, - "7": 0.67 - }, - "Liquid range": "2410 K", - "Melting point": "3459 K", - "Mendeleev no": 58, - "Mineral hardness": "7.0", - "Molar volume": "8.86 cm3", - "Name": "Rhenium", - "Oxidation states": [ - -3, - -1, - 1, - 2, - 3, - 4, - 5, - 6, - 7 - ], - "Poissons ratio": "0.30", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "178 GPa", - "Shannon radii": { - "4": { - "VI": { - "": { - "crystal_radius": 0.77, - "ionic_radius": 0.63 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - } - }, - "6": { - "VI": { - "": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.52, - "ionic_radius": 0.38 - } - }, - "VI": { - "": { - "crystal_radius": 0.67, - "ionic_radius": 0.53 - } - } - } - }, - "Superconduction temperature": "1.70 K", - "Thermal conductivity": "48 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4700 m s-1", - "Vickers hardness": "2450 MN m-2", - "X": 1.9, - "Youngs modulus": "463 GPa" - }, - "Rh": { - "Atomic mass": 102.9055, - "Atomic no": 45, - "Atomic orbitals": { - "1s": -821.136773, - "2p": -108.357665, - "2s": -116.80695, - "3d": -11.21725, - "3p": -17.415299, - "3s": -20.765603, - "4d": -0.239422, - "4p": -1.806456, - "4s": -2.825505, - "5s": -0.154624 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.73, - "Boiling point": "3968 K", - "Brinell hardness": "1100 MN m-2", - "Bulk modulus": "380 GPa", - "Coefficient of linear thermal expansion": "8.2 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "12450 kg m-3", - "Electrical resistivity": "4.3 10-8 Ω m", - "Electronic structure": "[Kr].4d8.5s1", - "ICSD oxidation states": [ - 3, - 4 - ], - "Ionic radii": { - "3": 0.805, - "4": 0.74, - "5": 0.69 - }, - "Liquid range": "1731 K", - "Melting point": "2237 K", - "Mendeleev no": 65, - "Mineral hardness": "6.0", - "Molar volume": "8.28 cm3", - "Name": "Rhodium", - "Oxidation states": [ - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.26", - "Reflectivity": "84 %", - "Refractive index": "no data", - "Rigidity modulus": "150 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.805, - "ionic_radius": 0.665 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "150 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4700 m s-1", - "Vickers hardness": "1246 MN m-2", - "X": 2.28, - "Youngs modulus": "275 GPa" - }, - "Rn": { - "Atomic mass": 220.0, - "Atomic no": 86, - "Atomic orbitals": { - "1s": -3204.756288, - "2p": -527.533025, - "2s": -546.57796, - "3d": -106.945006, - "3p": -124.172862, - "3s": -133.369144, - "4d": -19.449994, - "4f": -8.953318, - "4p": -27.108985, - "4s": -31.230804, - "5d": -1.911329, - "5p": -4.408702, - "5s": -5.889683, - "6p": -0.29318, - "6s": -0.62657 - }, - "Atomic radius": "no data", - "Atomic radius calculated": 1.2, - "Boiling point": "211.3 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Critical temperature": "377 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2.6p6", - "Liquid range": "9.3 K", - "Max oxidation state": 0.0, - "Melting point": "202 K", - "Mendeleev no": 6, - "Min oxidation state": 0.0, - "Mineral hardness": "no data", - "Molar volume": "50.50 cm3", - "Name": "Radon", - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.00361 W m-1 K-1", - "Van der waals radius": 2.2, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.2, - "Youngs modulus": "no data GPa" - }, - "Ru": { - "Atomic mass": 101.07, - "Atomic no": 44, - "Atomic orbitals": { - "1s": -782.918621, - "2p": -102.333649, - "2s": -110.536054, - "3d": -10.195668, - "3p": -16.145217, - "3s": -19.366692, - "4d": -0.210375, - "4p": -1.667549, - "4s": -2.628363, - "5s": -0.152834 - }, - "Atomic radius": 1.3, - "Atomic radius calculated": 1.78, - "Boiling point": "4423 K", - "Brinell hardness": "2160 MN m-2", - "Bulk modulus": "220 GPa", - "Coefficient of linear thermal expansion": "6.4 x10-6K-1", - "Common oxidation states": [ - 3, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "12370 kg m-3", - "Electrical resistivity": "7.1 10-8 Ω m", - "Electronic structure": "[Kr].4d7.5s1", - "ICSD oxidation states": [ - 2, - 3, - 4, - 5, - 6 - ], - "Ionic radii": { - "3": 0.82, - "4": 0.76, - "5": 0.705, - "7": 0.52, - "8": 0.5 - }, - "Liquid range": "1816 K", - "Melting point": "2607 K", - "Mendeleev no": 62, - "Mineral hardness": "6.5", - "Molar volume": "8.17 cm3", - "Name": "Ruthenium", - "Oxidation states": [ - -2, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8 - ], - "Poissons ratio": "0.30", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "173 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.82, - "ionic_radius": 0.68 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.76, - "ionic_radius": 0.62 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.705, - "ionic_radius": 0.565 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.52, - "ionic_radius": 0.38 - } - } - }, - "8": { - "IV": { - "": { - "crystal_radius": 0.5, - "ionic_radius": 0.36 - } - } - } - }, - "Superconduction temperature": "0.49 K", - "Thermal conductivity": "120 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "5970 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.2, - "Youngs modulus": "447 GPa" - }, - "S": { - "Atomic mass": 32.065, - "Atomic no": 16, - "Atomic orbitals": { - "1s": -87.789937, - "2p": -5.751257, - "2s": -7.69994, - "3p": -0.261676, - "3s": -0.630912 - }, - "Atomic radius": 1.0, - "Atomic radius calculated": 0.88, - "Boiling point": "717.87 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "7.7 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -2, - 2, - 4, - 6 - ], - "Critical temperature": "1314 K", - "Density of solid": "1960 kg m-3", - "Electrical resistivity": "> 102310-8 Ω m", - "Electronic structure": "[Ne].3s2.3p4", - "ICSD oxidation states": [ - -1, - 2, - 4, - -2, - 6 - ], - "Ionic radii": { - "-2": 1.7, - "4": 0.51, - "6": 0.43 - }, - "Liquid range": "329.51 K", - "Melting point": "388.36 K", - "Mendeleev no": 94, - "Mineral hardness": "2.0", - "Molar volume": "15.53 cm3", - "Name": "Sulfur", - "Oxidation states": [ - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.001111", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-2": { - "VI": { - "": { - "crystal_radius": 1.7, - "ionic_radius": 1.84 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.51, - "ionic_radius": 0.37 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.26, - "ionic_radius": 0.12 - } - }, - "VI": { - "": { - "crystal_radius": 0.43, - "ionic_radius": 0.29 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.205 W m-1 K-1", - "Van der waals radius": 1.8, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.58, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "S-33": -67.8, - "S-35": 47.1 - } - }, - "Sb": { - "Atomic mass": 121.76, - "Atomic no": 51, - "Atomic orbitals": { - "1s": -1070.823495, - "2p": -149.214271, - "2s": -159.171745, - "3d": -19.239895, - "3p": -26.956184, - "3s": -31.098242, - "4d": -1.297338, - "4p": -3.646579, - "4s": -5.04964, - "5p": -0.185623, - "5s": -0.445605 - }, - "Atomic radius": 1.45, - "Atomic radius calculated": 1.33, - "Boiling point": "1860 K", - "Brinell hardness": "294 MN m-2", - "Bulk modulus": "42 GPa", - "Coefficient of linear thermal expansion": "11 x10-6K-1", - "Common oxidation states": [ - -3, - 3, - 5 - ], - "Critical temperature": "no data K", - "Density of solid": "6697 kg m-3", - "Electrical resistivity": "40 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2.5p3", - "ICSD oxidation states": [ - -2, - 3, - 5, - -1, - -3 - ], - "Ionic radii": { - "3": 0.9, - "5": 0.76 - }, - "Liquid range": "956.22 K", - "Melting point": "903.78 K", - "Mendeleev no": 88, - "Mineral hardness": "3.0", - "Molar volume": "18.19 cm3", - "Name": "Antimony", - "Oxidation states": [ - -3, - 3, - 5 - ], - "Poissons ratio": "no data", - "Reflectivity": "55 %", - "Refractive index": "no data", - "Rigidity modulus": "20 GPa", - "Shannon radii": { - "3": { - "IVPY": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - }, - "V": { - "": { - "crystal_radius": 0.94, - "ionic_radius": 0.8 - } - }, - "VI": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "24 W m-1 K-1", - "Van der waals radius": 2.06, - "Velocity of sound": "3420 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.05, - "Youngs modulus": "55 GPa", - "NMR Quadrupole Moment": { - "Sb-121": -543.11, - "Sb-123": -692.14 - } - }, - "Sc": { - "Atomic mass": 44.955912, - "Atomic no": 21, - "Atomic orbitals": { - "1s": -160.184109, - "2p": -14.240006, - "2s": -17.206464, - "3d": -0.13108, - "3p": -1.233165, - "3s": -1.988378, - "4s": -0.156478 - }, - "Atomic radius": 1.6, - "Atomic radius calculated": 1.84, - "Boiling point": "3103 K", - "Brinell hardness": "750 MN m-2", - "Bulk modulus": "57 GPa", - "Coefficient of linear thermal expansion": "10.2 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "2985 kg m-3", - "Electrical resistivity": "about 55 10-8 Ω m", - "Electronic structure": "[Ar].3d1.4s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "3": 0.885 - }, - "Liquid range": "1289 K", - "Melting point": "1814 K", - "Mendeleev no": 19, - "Mineral hardness": "no data", - "Molar volume": "15.00 cm3", - "Name": "Scandium", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "0.28", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "29 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.885, - "ionic_radius": 0.745 - } - }, - "VIII": { - "": { - "crystal_radius": 1.01, - "ionic_radius": 0.87 - } - } - } - }, - "Superconduction temperature": "0.05 (under pressure)K", - "Thermal conductivity": "16 W m-1 K-1", - "Van der waals radius": 2.11, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.36, - "Youngs modulus": "74 GPa", - "NMR Quadrupole Moment": { - "Sc-45": -220.2 - } - }, - "Se": { - "Atomic mass": 78.96, - "Atomic no": 34, - "Atomic orbitals": { - "1s": -451.300258, - "2p": -51.514388, - "2s": -57.311948, - "3d": -2.011392, - "3p": -5.553517, - "3s": -7.547186, - "4p": -0.245806, - "4s": -0.621248 - }, - "Atomic radius": 1.15, - "Atomic radius calculated": 1.03, - "Boiling point": "958 K", - "Brinell hardness": "736 MN m-2", - "Bulk modulus": "8.3 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -2, - 2, - 4, - 6 - ], - "Critical temperature": "1766 K", - "Density of solid": "4819 kg m-3", - "Electrical resistivity": "high 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2.4p4", - "ICSD oxidation states": [ - -1, - 4, - -2, - 6 - ], - "Ionic radii": { - "-2": 1.84, - "4": 0.64, - "6": 0.56 - }, - "Liquid range": "464 K", - "Melting point": "494 K", - "Mendeleev no": 93, - "Mineral hardness": "2.0", - "Molar volume": "16.42 cm3", - "Name": "Selenium", - "Oxidation states": [ - -2, - 2, - 4, - 6 - ], - "Poissons ratio": "0.33", - "Reflectivity": "no data %", - "Refractive index": "1.000895", - "Rigidity modulus": "3.7 GPa", - "Shannon radii": { - "-2": { - "VI": { - "": { - "crystal_radius": 1.84, - "ionic_radius": 1.98 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.64, - "ionic_radius": 0.5 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.42, - "ionic_radius": 0.28 - } - }, - "VI": { - "": { - "crystal_radius": 0.56, - "ionic_radius": 0.42 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.52 W m-1 K-1", - "Van der waals radius": 1.9, - "Velocity of sound": "3350 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.55, - "Youngs modulus": "10 GPa" - }, - "Si": { - "Atomic mass": 28.0855, - "Atomic no": 14, - "Atomic orbitals": { - "1s": -65.184426, - "2p": -3.514938, - "2s": -5.075056, - "3p": -0.153293, - "3s": -0.398139 - }, - "Atomic radius": 1.1, - "Atomic radius calculated": 1.11, - "Boiling point": "3173 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "100 GPa", - "Coefficient of linear thermal expansion": "2.6 x10-6K-1", - "Common oxidation states": [ - -4, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "2330 kg m-3", - "Electrical resistivity": "about 100000 10-8 Ω m", - "Electronic structure": "[Ne].3s2.3p2", - "ICSD oxidation states": [ - -4, - 4 - ], - "Ionic radii": { - "4": 0.54 - }, - "Liquid range": "1486 K", - "Melting point": "1687 K", - "Mendeleev no": 85, - "Mineral hardness": "6.5", - "Molar volume": "12.06 cm3", - "Name": "Silicon", - "Oxidation states": [ - -4, - -3, - -2, - -1, - 1, - 2, - 3, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "28 %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "4": { - "IV": { - "": { - "crystal_radius": 0.4, - "ionic_radius": 0.26 - } - }, - "VI": { - "": { - "crystal_radius": 0.54, - "ionic_radius": 0.4 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "150 W m-1 K-1", - "Van der waals radius": 2.1, - "Velocity of sound": "2200 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.9, - "Youngs modulus": "47 GPa" - }, - "Sm": { - "Atomic mass": 150.36, - "Atomic no": 62, - "Atomic orbitals": { - "1s": -1617.183426, - "2p": -242.729726, - "2s": -255.498846, - "3d": -39.528656, - "3p": -50.08426, - "3s": -55.731133, - "4d": -4.814978, - "4f": -0.21776, - "4p": -8.672685, - "4s": -10.844667, - "5p": -0.835987, - "5s": -1.408552, - "6s": -0.128259 - }, - "Atomic radius": 1.85, - "Atomic radius calculated": 2.38, - "Boiling point": "2076 K", - "Brinell hardness": "441 MN m-2", - "Bulk modulus": "38 GPa", - "Coefficient of linear thermal expansion": "12.7 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "7353 kg m-3", - "Electrical resistivity": "94 10-8 Ω m", - "Electronic structure": "[Xe].4f6.6s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "2": 1.36, - "3": 1.0979999999999999 - }, - "Liquid range": "731 K", - "Melting point": "1345 K", - "Mendeleev no": 28, - "Mineral hardness": "no data", - "Molar volume": "19.98 cm3", - "Name": "Samarium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.27", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "20 GPa", - "Shannon radii": { - "2": { - "VII": { - "": { - "crystal_radius": 1.36, - "ionic_radius": 1.22 - } - }, - "VIII": { - "": { - "crystal_radius": 1.41, - "ionic_radius": 1.27 - } - }, - "IX": { - "": { - "crystal_radius": 1.46, - "ionic_radius": 1.32 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.098, - "ionic_radius": 0.958 - } - }, - "VII": { - "": { - "crystal_radius": 1.16, - "ionic_radius": 1.02 - } - }, - "VIII": { - "": { - "crystal_radius": 1.219, - "ionic_radius": 1.079 - } - }, - "IX": { - "": { - "crystal_radius": 1.272, - "ionic_radius": 1.132 - } - }, - "XII": { - "": { - "crystal_radius": 1.38, - "ionic_radius": 1.24 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "13 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2130 m s-1", - "Vickers hardness": "412 MN m-2", - "X": 1.17, - "Youngs modulus": "50 GPa" - }, - "Sn": { - "Atomic mass": 118.71, - "Atomic no": 50, - "Atomic orbitals": { - "1s": -1026.762169, - "2p": -141.821093, - "2s": -151.523991, - "3d": -17.657276, - "3p": -25.117913, - "3s": -29.125969, - "4d": -1.004952, - "4p": -3.211998, - "4s": -4.546335, - "5p": -0.14445, - "5s": -0.369349 - }, - "Atomic radius": 1.45, - "Atomic radius calculated": 1.45, - "Boiling point": "2875 K", - "Brinell hardness": "51 MN m-2", - "Bulk modulus": "58 GPa", - "Coefficient of linear thermal expansion": "22 x10-6K-1", - "Common oxidation states": [ - -4, - 2, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "7310 kg m-3", - "Electrical resistivity": "11.5 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2.5p2", - "ICSD oxidation states": [ - 2, - 3, - 4 - ], - "Ionic radii": { - "4": 0.83 - }, - "Liquid range": "2369.92 K", - "Melting point": "505.08 K", - "Mendeleev no": 83, - "Mineral hardness": "1.5", - "Molar volume": "16.29 cm3", - "Name": "Tin", - "Oxidation states": [ - -4, - 2, - 4 - ], - "Poissons ratio": "0.36", - "Reflectivity": "54 %", - "Refractive index": "no data", - "Rigidity modulus": "18 GPa", - "Shannon radii": { - "4": { - "IV": { - "": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - } - }, - "V": { - "": { - "crystal_radius": 0.76, - "ionic_radius": 0.62 - } - }, - "VI": { - "": { - "crystal_radius": 0.83, - "ionic_radius": 0.69 - } - }, - "VII": { - "": { - "crystal_radius": 0.89, - "ionic_radius": 0.75 - } - }, - "VIII": { - "": { - "crystal_radius": 0.95, - "ionic_radius": 0.81 - } - } - } - }, - "Superconduction temperature": "3.72 K", - "Thermal conductivity": "67 W m-1 K-1", - "Van der waals radius": 2.17, - "Velocity of sound": "2500 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.96, - "Youngs modulus": "50 GPa", - "NMR Quadrupole Moment": { - "Sn-119": -132.1 - } - }, - "Sr": { - "Atomic mass": 87.62, - "Atomic no": 38, - "Atomic orbitals": { - "1s": -572.870169, - "2p": -69.745941, - "2s": -76.491823, - "3d": -4.813498, - "3p": -9.301863, - "3s": -11.771585, - "4p": -0.844489, - "4s": -1.455317, - "5s": -0.131793 - }, - "Atomic radius": 2.0, - "Atomic radius calculated": 2.19, - "Boiling point": "1655 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "22.5 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "2630 kg m-3", - "Electrical resistivity": "13.5 10-8 Ω m", - "Electronic structure": "[Kr].5s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 1.32 - }, - "Liquid range": "605 K", - "Melting point": "1050 K", - "Mendeleev no": 15, - "Mineral hardness": "1.5", - "Molar volume": "33.94 cm3", - "Name": "Strontium", - "Oxidation states": [ - 2 - ], - "Poissons ratio": "0.28", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "6.1 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.32, - "ionic_radius": 1.18 - } - }, - "VII": { - "": { - "crystal_radius": 1.35, - "ionic_radius": 1.21 - } - }, - "VIII": { - "": { - "crystal_radius": 1.4, - "ionic_radius": 1.26 - } - }, - "IX": { - "": { - "crystal_radius": 1.45, - "ionic_radius": 1.31 - } - }, - "X": { - "": { - "crystal_radius": 1.5, - "ionic_radius": 1.36 - } - }, - "XII": { - "": { - "crystal_radius": 1.58, - "ionic_radius": 1.44 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "35 W m-1 K-1", - "Van der waals radius": 2.49, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.95, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "Sr-87": 305.2 - } - }, - "Ta": { - "Atomic mass": 180.94788, - "Atomic no": 73, - "Atomic orbitals": { - "1s": -2275.371387, - "2p": -357.248334, - "2s": -372.828724, - "3d": -63.942521, - "3p": -77.440942, - "3s": -84.658467, - "4d": -8.265848, - "4f": -1.199347, - "4p": -13.71981, - "4s": -16.713337, - "5d": -0.182464, - "5p": -1.37653, - "5s": -2.223807, - "6s": -0.174814 - }, - "Atomic radius": 1.45, - "Atomic radius calculated": 2.0, - "Boiling point": "5731 K", - "Brinell hardness": "800 MN m-2", - "Bulk modulus": "200 GPa", - "Coefficient of linear thermal expansion": "6.3 x10-6K-1", - "Common oxidation states": [ - 5 - ], - "Critical temperature": "no data K", - "Density of solid": "16650 kg m-3", - "Electrical resistivity": "13.5 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d3.6s2", - "ICSD oxidation states": [ - 3, - 4, - 5 - ], - "Ionic radii": { - "3": 0.86, - "4": 0.82, - "5": 0.78 - }, - "Liquid range": "2441 K", - "Melting point": "3290 K", - "Mendeleev no": 52, - "Mineral hardness": "6.5", - "Molar volume": "10.85 cm3", - "Name": "Tantalum", - "Oxidation states": [ - -1, - 2, - 3, - 4, - 5 - ], - "Poissons ratio": "0.34", - "Reflectivity": "78 %", - "Refractive index": "no data", - "Rigidity modulus": "69 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.86, - "ionic_radius": 0.72 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.82, - "ionic_radius": 0.68 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.78, - "ionic_radius": 0.64 - } - }, - "VII": { - "": { - "crystal_radius": 0.83, - "ionic_radius": 0.69 - } - }, - "VIII": { - "": { - "crystal_radius": 0.88, - "ionic_radius": 0.74 - } - } - } - }, - "Superconduction temperature": "4.47 K", - "Thermal conductivity": "57 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "3400 m s-1", - "Vickers hardness": "873 MN m-2", - "X": 1.5, - "Youngs modulus": "186 GPa" - }, - "Tb": { - "Atomic mass": 158.92535, - "Atomic no": 65, - "Atomic orbitals": { - "1s": -1785.331942, - "2p": -271.590585, - "2s": -285.121013, - "3d": -45.443863, - "3p": -56.785113, - "3s": -62.851563, - "4d": -5.467662, - "4f": -0.256311, - "4p": -9.735637, - "4s": -12.120486, - "5p": -0.88723, - "5s": -1.513669, - "6s": -0.131677 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": 2.25, - "Boiling point": "3503 K", - "Brinell hardness": "677 MN m-2", - "Bulk modulus": "38.7 GPa", - "Coefficient of linear thermal expansion": "10.3 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "8219 kg m-3", - "Electrical resistivity": "115 10-8 Ω m", - "Electronic structure": "[Xe].4f9.6s2", - "ICSD oxidation states": [ - 3, - 4 - ], - "Ionic radii": { - "3": 1.063, - "4": 0.9 - }, - "Liquid range": "1874 K", - "Melting point": "1629 K", - "Mendeleev no": 26, - "Mineral hardness": "no data", - "Molar volume": "19.30 cm3", - "Name": "Terbium", - "Oxidation states": [ - 1, - 3, - 4 - ], - "Poissons ratio": "0.26", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "22 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.063, - "ionic_radius": 0.923 - } - }, - "VII": { - "": { - "crystal_radius": 1.12, - "ionic_radius": 0.98 - } - }, - "VIII": { - "": { - "crystal_radius": 1.18, - "ionic_radius": 1.04 - } - }, - "IX": { - "": { - "crystal_radius": 1.235, - "ionic_radius": 1.095 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - }, - "VIII": { - "": { - "crystal_radius": 1.02, - "ionic_radius": 0.88 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "11 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2620 m s-1", - "Vickers hardness": "863 MN m-2", - "X": 1.1, - "Youngs modulus": "56 GPa" - }, - "Tc": { - "Atomic mass": 98.0, - "Atomic no": 43, - "Atomic orbitals": { - "1s": -745.742024, - "2p": -96.61021, - "2s": -104.567508, - "3d": -9.33986, - "3p": -15.041738, - "3s": -18.135303, - "4d": -0.270262, - "4p": -1.64323, - "4s": -2.550712, - "5s": -0.183636 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.83, - "Boiling point": "4538 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 4, - 7 - ], - "Critical temperature": "no data K", - "Density of solid": "11500 kg m-3", - "Electrical resistivity": "about 22 10-8 Ω m", - "Electronic structure": "[Kr].4d5.5s2", - "Ionic radii": { - "4": 0.785, - "5": 0.74, - "7": 0.7 - }, - "Liquid range": "2108 K", - "Melting point": "2430 K", - "Mendeleev no": 59, - "Mineral hardness": "no data", - "Molar volume": "8.63 cm3", - "Name": "Technetium", - "Oxidation states": [ - -3, - -1, - 1, - 2, - 3, - 4, - 5, - 6, - 7 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "4": { - "VI": { - "": { - "crystal_radius": 0.785, - "ionic_radius": 0.645 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.51, - "ionic_radius": 0.37 - } - }, - "VI": { - "": { - "crystal_radius": 0.7, - "ionic_radius": 0.56 - } - } - } - }, - "Superconduction temperature": "7.8 K", - "Thermal conductivity": "51 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.9, - "Youngs modulus": "no data GPa" - }, - "Te": { - "Atomic mass": 127.6, - "Atomic no": 52, - "Atomic orbitals": { - "1s": -1115.831819, - "2p": -156.808583, - "2s": -167.021776, - "3d": -20.887801, - "3p": -28.860685, - "3s": -33.137485, - "4d": -1.608381, - "4p": -4.100084, - "4s": -5.572846, - "5p": -0.226594, - "5s": -0.520997 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.23, - "Boiling point": "1261 K", - "Brinell hardness": "180 MN m-2", - "Bulk modulus": "65 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -2, - 2, - 4, - 6 - ], - "Critical temperature": "no data K", - "Density of solid": "6240 kg m-3", - "Electrical resistivity": "about 10000 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2.5p4", - "ICSD oxidation states": [ - -2, - 4, - -1, - 6 - ], - "Ionic radii": { - "-2": 2.07, - "4": 1.11, - "6": 0.7 - }, - "Liquid range": "538.34 K", - "Melting point": "722.66 K", - "Mendeleev no": 92, - "Mineral hardness": "2.25", - "Molar volume": "20.46 cm3", - "Name": "Tellurium", - "Oxidation states": [ - -2, - 2, - 4, - 5, - 6 - ], - "Poissons ratio": "no data", - "Reflectivity": "50 %", - "Refractive index": "1.000991", - "Rigidity modulus": "16 GPa", - "Shannon radii": { - "-2": { - "VI": { - "": { - "crystal_radius": 2.07, - "ionic_radius": 2.21 - } - } - }, - "4": { - "III": { - "": { - "crystal_radius": 0.66, - "ionic_radius": 0.52 - } - }, - "IV": { - "": { - "crystal_radius": 0.8, - "ionic_radius": 0.66 - } - }, - "VI": { - "": { - "crystal_radius": 1.11, - "ionic_radius": 0.97 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.57, - "ionic_radius": 0.43 - } - }, - "VI": { - "": { - "crystal_radius": 0.7, - "ionic_radius": 0.56 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "3 W m-1 K-1", - "Van der waals radius": 2.06, - "Velocity of sound": "2610 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.1, - "Youngs modulus": "43 GPa" - }, - "Th": { - "Atomic mass": 232.03806, - "Atomic no": 90, - "Atomic orbitals": { - "1s": -3524.439052, - "2p": -588.218112, - "2s": -608.350958, - "3d": -123.846396, - "3p": -142.25581, - "3s": -152.079741, - "4d": -24.955184, - "4f": -13.397389, - "4p": -33.325252, - "4s": -37.814094, - "5d": -3.625729, - "5p": -6.58281, - "5s": -8.287057, - "6d": -0.172896, - "6p": -0.846921, - "6s": -1.333769, - "7s": -0.135872 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": "no data", - "Boiling point": "5093 K", - "Brinell hardness": "400 MN m-2", - "Bulk modulus": "54 GPa", - "Coefficient of linear thermal expansion": "11.0 x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "11724 kg m-3", - "Electrical resistivity": "15 10-8 Ω m", - "Electronic structure": "[Rn].6d2.7s2", - "ICSD oxidation states": [ - 4 - ], - "Ionic radii": { - "4": 1.08 - }, - "Liquid range": "2978 K", - "Melting point": "2115 K", - "Mendeleev no": 47, - "Mineral hardness": "3.0", - "Molar volume": "19.80 cm3", - "Name": "Thorium", - "Oxidation states": [ - 2, - 3, - 4 - ], - "Poissons ratio": "0.27", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "31 GPa", - "Shannon radii": { - "4": { - "VI": { - "": { - "crystal_radius": 1.08, - "ionic_radius": 0.94 - } - }, - "VIII": { - "": { - "crystal_radius": 1.19, - "ionic_radius": 1.05 - } - }, - "IX": { - "": { - "crystal_radius": 1.23, - "ionic_radius": 1.09 - } - }, - "X": { - "": { - "crystal_radius": 1.27, - "ionic_radius": 1.13 - } - }, - "XI": { - "": { - "crystal_radius": 1.32, - "ionic_radius": 1.18 - } - }, - "XII": { - "": { - "crystal_radius": 1.35, - "ionic_radius": 1.21 - } - } - } - }, - "Superconduction temperature": "1.38 K", - "Thermal conductivity": "54 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2490 m s-1", - "Vickers hardness": "350 MN m-2", - "X": 1.3, - "Youngs modulus": "79 GPa" - }, - "Ti": { - "Atomic mass": 47.867, - "Atomic no": 22, - "Atomic orbitals": { - "1s": -177.276643, - "2p": -16.285339, - "2s": -19.457901, - "3d": -0.17001, - "3p": -1.422947, - "3s": -2.258007, - "4s": -0.167106 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.76, - "Boiling point": "3560 K", - "Brinell hardness": "716 MN m-2", - "Bulk modulus": "110 GPa", - "Coefficient of linear thermal expansion": "8.6 x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "4507 kg m-3", - "Electrical resistivity": "about 40 10-8 Ω m", - "Electronic structure": "[Ar].3d2.4s2", - "ICSD oxidation states": [ - 2, - 3, - 4 - ], - "Ionic radii": { - "2": 1.0, - "3": 0.81, - "4": 0.745 - }, - "Liquid range": "1619 K", - "Melting point": "1941 K", - "Mendeleev no": 51, - "Mineral hardness": "6.0", - "Molar volume": "10.64 cm3", - "Name": "Titanium", - "Oxidation states": [ - -1, - 2, - 3, - 4 - ], - "Poissons ratio": "0.32", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "44 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.0, - "ionic_radius": 0.86 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 0.81, - "ionic_radius": 0.67 - } - } - }, - "4": { - "IV": { - "": { - "crystal_radius": 0.56, - "ionic_radius": 0.42 - } - }, - "V": { - "": { - "crystal_radius": 0.65, - "ionic_radius": 0.51 - } - }, - "VI": { - "": { - "crystal_radius": 0.745, - "ionic_radius": 0.605 - } - }, - "VIII": { - "": { - "crystal_radius": 0.88, - "ionic_radius": 0.74 - } - } - } - }, - "Superconduction temperature": "0.40 K", - "Thermal conductivity": "22 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4140 m s-1", - "Vickers hardness": "970 MN m-2", - "X": 1.54, - "Youngs modulus": "116 GPa", - "NMR Quadrupole Moment": { - "Ti-47": 302.1, - "Ti-49": 247.11 - } - }, - "Tl": { - "Atomic mass": 204.3833, - "Atomic no": 81, - "Atomic orbitals": { - "1s": -2827.569408, - "2p": -457.255971, - "2s": -474.953368, - "3d": -88.328299, - "3p": -104.099296, - "3s": -112.52218, - "4d": -14.008848, - "4f": -4.835747, - "4p": -20.797078, - "4s": -24.471512, - "5d": -0.674544, - "5p": -2.59873, - "5s": -3.811512, - "6p": -0.101507, - "6s": -0.28502 - }, - "Atomic radius": 1.9, - "Atomic radius calculated": 1.56, - "Boiling point": "1746 K", - "Brinell hardness": "26.4 MN m-2", - "Bulk modulus": "43 GPa", - "Coefficient of linear thermal expansion": "29.9 x10-6K-1", - "Common oxidation states": [ - 1, - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "11850 kg m-3", - "Electrical resistivity": "15 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2.6p1", - "ICSD oxidation states": [ - 1, - 3 - ], - "Ionic radii": { - "1": 1.64, - "3": 1.025 - }, - "Liquid range": "1169 K", - "Melting point": "577 K", - "Mendeleev no": 78, - "Mineral hardness": "1.2", - "Molar volume": "17.22 cm3", - "Name": "Thallium", - "Oxidation states": [ - 1, - 3 - ], - "Poissons ratio": "0.45", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "2.8 GPa", - "Shannon radii": { - "1": { - "VI": { - "": { - "crystal_radius": 1.64, - "ionic_radius": 1.5 - } - }, - "VIII": { - "": { - "crystal_radius": 1.73, - "ionic_radius": 1.59 - } - }, - "XII": { - "": { - "crystal_radius": 1.84, - "ionic_radius": 1.7 - } - } - }, - "3": { - "IV": { - "": { - "crystal_radius": 0.89, - "ionic_radius": 0.75 - } - }, - "VI": { - "": { - "crystal_radius": 1.025, - "ionic_radius": 0.885 - } - }, - "VIII": { - "": { - "crystal_radius": 1.12, - "ionic_radius": 0.98 - } - } - } - }, - "Superconduction temperature": "2.38 K", - "Thermal conductivity": "46 W m-1 K-1", - "Van der waals radius": 1.96, - "Velocity of sound": "818 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.62, - "Youngs modulus": "8 GPa" - }, - "Tm": { - "Atomic mass": 168.93421, - "Atomic no": 69, - "Atomic orbitals": { - "1s": -2022.471608, - "2p": -312.510608, - "2s": -327.05712, - "3d": -53.835494, - "3p": -66.239338, - "3s": -72.873753, - "4d": -6.350307, - "4f": -0.28312, - "4p": -11.187151, - "4s": -13.865665, - "5p": -0.950748, - "5s": -1.64999, - "6s": -0.135953 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": 2.22, - "Boiling point": "2223 K", - "Brinell hardness": "471 MN m-2", - "Bulk modulus": "45 GPa", - "Coefficient of linear thermal expansion": "13.3 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "9321 kg m-3", - "Electrical resistivity": "67.6 10-8 Ω m", - "Electronic structure": "[Xe].4f13.6s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "2": 1.17, - "3": 1.02 - }, - "Liquid range": "405 K", - "Melting point": "1818 K", - "Mendeleev no": 21, - "Mineral hardness": "no data", - "Molar volume": "19.1 cm3", - "Name": "Thulium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.21", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "31 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.17, - "ionic_radius": 1.03 - } - }, - "VII": { - "": { - "crystal_radius": 1.23, - "ionic_radius": 1.09 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.02, - "ionic_radius": 0.88 - } - }, - "VIII": { - "": { - "crystal_radius": 1.134, - "ionic_radius": 0.994 - } - }, - "IX": { - "": { - "crystal_radius": 1.192, - "ionic_radius": 1.052 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "17 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "520 MN m-2", - "X": 1.25, - "Youngs modulus": "74 GPa" - }, - "U": { - "Atomic mass": 238.02891, - "Atomic no": 92, - "Atomic orbitals": { - "1s": -3689.355141, - "2p": -619.10855, - "2s": -639.778728, - "3d": -131.977358, - "3p": -150.97898, - "3s": -161.118073, - "4d": -27.123212, - "4f": -15.02746, - "4p": -35.853321, - "4s": -40.528084, - "5d": -3.866175, - "5f": -0.366543, - "5p": -7.018092, - "5s": -8.824089, - "6d": -0.14319, - "6p": -0.822538, - "6s": -1.325976, - "7s": -0.130948 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": "no data", - "Boiling point": "4200 K", - "Brinell hardness": "2400 MN m-2", - "Bulk modulus": "100 GPa", - "Coefficient of linear thermal expansion": "13.9 x10-6K-1", - "Common oxidation states": [ - 6 - ], - "Critical temperature": "no data K", - "Density of solid": "19050 kg m-3", - "Electrical resistivity": "28 10-8 Ω m", - "Electronic structure": "[Rn].5f3.6d1.7s2", - "ICSD oxidation states": [ - 3, - 4, - 5, - 6 - ], - "Ionic radii": { - "3": 1.165, - "4": 1.03, - "5": 0.9, - "6": 0.87 - }, - "Liquid range": "2794.7 K", - "Melting point": "1405.3 K", - "Mendeleev no": 45, - "Mineral hardness": "6.0", - "Molar volume": "12.49 cm3", - "Name": "Uranium", - "Oxidation states": [ - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.23", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "111 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.165, - "ionic_radius": 1.025 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 1.03, - "ionic_radius": 0.89 - } - }, - "VII": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - }, - "VIII": { - "": { - "crystal_radius": 1.14, - "ionic_radius": 1.0 - } - }, - "IX": { - "": { - "crystal_radius": 1.19, - "ionic_radius": 1.05 - } - }, - "XII": { - "": { - "crystal_radius": 1.31, - "ionic_radius": 1.17 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - }, - "VII": { - "": { - "crystal_radius": 0.98, - "ionic_radius": 0.84 - } - } - }, - "6": { - "II": { - "": { - "crystal_radius": 0.59, - "ionic_radius": 0.45 - } - }, - "IV": { - "": { - "crystal_radius": 0.66, - "ionic_radius": 0.52 - } - }, - "VI": { - "": { - "crystal_radius": 0.87, - "ionic_radius": 0.73 - } - }, - "VII": { - "": { - "crystal_radius": 0.95, - "ionic_radius": 0.81 - } - }, - "VIII": { - "": { - "crystal_radius": 1.0, - "ionic_radius": 0.86 - } - } - } - }, - "Superconduction temperature": "0.2 K", - "Thermal conductivity": "27 W m-1 K-1", - "Van der waals radius": 1.86, - "Velocity of sound": "3155 m s-1", - "Vickers hardness": "1960 MN m-2", - "X": 1.38, - "Youngs modulus": "208 GPa" - }, - "V": { - "Atomic mass": 50.9415, - "Atomic no": 23, - "Atomic orbitals": { - "1s": -195.224014, - "2p": -18.435189, - "2s": -21.815346, - "3d": -0.204634, - "3p": -1.610516, - "3s": -2.526904, - "4s": -0.175968 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.71, - "Boiling point": "3680 K", - "Brinell hardness": "628 MN m-2", - "Bulk modulus": "160 GPa", - "Coefficient of linear thermal expansion": "8.4 x10-6K-1", - "Common oxidation states": [ - 5 - ], - "Critical temperature": "no data K", - "Density of solid": "6110 kg m-3", - "Electrical resistivity": "20 10-8 Ω m", - "Electronic structure": "[Ar].3d3.4s2", - "ICSD oxidation states": [ - 2, - 3, - 4, - 5 - ], - "Ionic radii": { - "2": 0.93, - "3": 0.78, - "4": 0.72, - "5": 0.68 - }, - "Liquid range": "1497 K", - "Melting point": "2183 K", - "Mendeleev no": 54, - "Mineral hardness": "7.0", - "Molar volume": "8.32 cm3", - "Name": "Vanadium", - "Oxidation states": [ - -1, - 1, - 2, - 3, - 4, - 5 - ], - "Poissons ratio": "0.37", - "Reflectivity": "61 %", - "Refractive index": "no data", - "Rigidity modulus": "47 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 0.93, - "ionic_radius": 0.79 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 0.78, - "ionic_radius": 0.64 - } - } - }, - "4": { - "V": { - "": { - "crystal_radius": 0.67, - "ionic_radius": 0.53 - } - }, - "VI": { - "": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - }, - "VIII": { - "": { - "crystal_radius": 0.86, - "ionic_radius": 0.72 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.495, - "ionic_radius": 0.355 - } - }, - "V": { - "": { - "crystal_radius": 0.6, - "ionic_radius": 0.46 - } - }, - "VI": { - "": { - "crystal_radius": 0.68, - "ionic_radius": 0.54 - } - } - } - }, - "Superconduction temperature": "5.40 K", - "Thermal conductivity": "31 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4560 m s-1", - "Vickers hardness": "628 MN m-2", - "X": 1.63, - "Youngs modulus": "128 GPa", - "NMR Quadrupole Moment": { - "V-50": 210.4, - "V-51": -52.1 - } - }, - "W": { - "Atomic mass": 183.84, - "Atomic no": 74, - "Atomic orbitals": { - "1s": -2341.042887, - "2p": -369.013973, - "2s": -384.856157, - "3d": -66.724787, - "3p": -80.502102, - "3s": -87.867792, - "4d": -8.879693, - "4f": -1.550835, - "4p": -14.495102, - "4s": -17.570797, - "5d": -0.220603, - "5p": -1.504457, - "5s": -2.396018, - "6s": -0.181413 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.93, - "Boiling point": "5828 K", - "Brinell hardness": "2570 MN m-2", - "Bulk modulus": "310 GPa", - "Coefficient of linear thermal expansion": "4.5 x10-6K-1", - "Common oxidation states": [ - 4, - 6 - ], - "Critical temperature": "no data K", - "Density of solid": "19250 kg m-3", - "Electrical resistivity": "5.4 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d4.6s2", - "ICSD oxidation states": [ - 2, - 3, - 4, - 5, - 6 - ], - "Ionic radii": { - "4": 0.8, - "5": 0.76, - "6": 0.74 - }, - "Liquid range": "2133 K", - "Melting point": "3695 K", - "Mendeleev no": 55, - "Mineral hardness": "7.5", - "Molar volume": "9.47 cm3", - "Name": "Tungsten", - "Oxidation states": [ - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.28", - "Reflectivity": "62 %", - "Refractive index": "no data", - "Rigidity modulus": "161 GPa", - "Shannon radii": { - "4": { - "VI": { - "": { - "crystal_radius": 0.8, - "ionic_radius": 0.66 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.76, - "ionic_radius": 0.62 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.56, - "ionic_radius": 0.42 - } - }, - "V": { - "": { - "crystal_radius": 0.65, - "ionic_radius": 0.51 - } - }, - "VI": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - } - } - }, - "Superconduction temperature": "0.015 K", - "Thermal conductivity": "170 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "5174 m s-1", - "Vickers hardness": "3430 MN m-2", - "X": 2.36, - "Youngs modulus": "411 GPa" - }, - "Xe": { - "Atomic mass": 131.293, - "Atomic no": 54, - "Atomic orbitals": { - "1s": -1208.688993, - "2p": -172.599583, - "2s": -183.327495, - "3d": -24.37823, - "3p": -32.867042, - "3s": -37.415454, - "4d": -2.286666, - "4p": -5.063802, - "4s": -6.67834, - "5p": -0.309835, - "5s": -0.672086 - }, - "Atomic radius": "no data", - "Atomic radius calculated": 1.08, - "Boiling point": "165.1 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Critical temperature": "289.7 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2.5p6", - "Ionic radii": { - "8": 0.62 - }, - "Liquid range": "3.7 K", - "Max oxidation state": 8.0, - "Melting point": "161.4 K", - "Mendeleev no": 5, - "Min oxidation state": 2.0, - "Mineral hardness": "no data", - "Molar volume": "35.92 cm3", - "Name": "Xenon", - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000702", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "8": { - "IV": { - "": { - "crystal_radius": 0.54, - "ionic_radius": 0.4 - } - }, - "VI": { - "": { - "crystal_radius": 0.62, - "ionic_radius": 0.48 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.00565 W m-1 K-1", - "Van der waals radius": 2.16, - "Velocity of sound": "1090 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.6, - "Youngs modulus": "no data GPa" - }, - "Y": { - "Atomic mass": 88.90585, - "Atomic no": 39, - "Atomic orbitals": { - "1s": -605.631981, - "2p": -74.803201, - "2s": -81.789102, - "3d": -5.671499, - "3p": -10.399926, - "3s": -12.992217, - "4d": -0.108691, - "4p": -1.02449, - "4s": -1.697124, - "5s": -0.150727 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": 2.12, - "Boiling point": "3609 K", - "Brinell hardness": "589 MN m-2", - "Bulk modulus": "41 GPa", - "Coefficient of linear thermal expansion": "10.6 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "4472 kg m-3", - "Electrical resistivity": "about 60 10-8 Ω m", - "Electronic structure": "[Kr].4d1.5s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "3": 1.04 - }, - "Liquid range": "1810 K", - "Melting point": "1799 K", - "Mendeleev no": 25, - "Mineral hardness": "no data", - "Molar volume": "19.88 cm3", - "Name": "Yttrium", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "0.24", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "26 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.04, - "ionic_radius": 0.9 - } - }, - "VII": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - }, - "VIII": { - "": { - "crystal_radius": 1.159, - "ionic_radius": 1.019 - } - }, - "IX": { - "": { - "crystal_radius": 1.215, - "ionic_radius": 1.075 - } - } - } - }, - "Superconduction temperature": "1.3 (under pressure)K", - "Thermal conductivity": "17 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "3300 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.22, - "Youngs modulus": "64 GPa" - }, - "Yb": { - "Atomic mass": 173.04, - "Atomic no": 70, - "Atomic orbitals": { - "1s": -2084.069389, - "2p": -323.178219, - "2s": -337.978976, - "3d": -56.026315, - "3p": -68.698655, - "3s": -75.47663, - "4d": -6.574963, - "4f": -0.286408, - "4p": -11.558246, - "4s": -14.312076, - "5p": -0.966137, - "5s": -1.683886, - "6s": -0.136989 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": 2.22, - "Boiling point": "1469 K", - "Brinell hardness": "343 MN m-2", - "Bulk modulus": "31 GPa", - "Coefficient of linear thermal expansion": "26.3 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "6570 kg m-3", - "Electrical resistivity": "25.0 10-8 Ω m", - "Electronic structure": "[Xe].4f14.6s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "2": 1.16, - "3": 1.008 - }, - "Liquid range": "372 K", - "Melting point": "1097 K", - "Mendeleev no": 17, - "Mineral hardness": "no data", - "Molar volume": "24.84 cm3", - "Name": "Ytterbium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.21", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "9.9 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.16, - "ionic_radius": 1.02 - } - }, - "VII": { - "": { - "crystal_radius": 1.22, - "ionic_radius": 1.08 - } - }, - "VIII": { - "": { - "crystal_radius": 1.28, - "ionic_radius": 1.14 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.008, - "ionic_radius": 0.868 - } - }, - "VII": { - "": { - "crystal_radius": 1.065, - "ionic_radius": 0.925 - } - }, - "VIII": { - "": { - "crystal_radius": 1.125, - "ionic_radius": 0.985 - } - }, - "IX": { - "": { - "crystal_radius": 1.182, - "ionic_radius": 1.042 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "39 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "1590 m s-1", - "Vickers hardness": "206 MN m-2", - "X": 1.1, - "Youngs modulus": "24 GPa" - }, - "Zn": { - "Atomic mass": 65.409, - "Atomic no": 30, - "Atomic orbitals": { - "1s": -344.969756, - "2p": -36.648765, - "2s": -41.531323, - "3d": -0.398944, - "3p": -3.022363, - "3s": -4.573041, - "4s": -0.222725 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.42, - "Boiling point": "1180 K", - "Brinell hardness": "412 MN m-2", - "Bulk modulus": "70 GPa", - "Coefficient of linear thermal expansion": "30.2 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "7140 kg m-3", - "Electrical resistivity": "6.0 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 0.88 - }, - "Liquid range": "487.32 K", - "Melting point": "692.68 K", - "Mendeleev no": 76, - "Mineral hardness": "2.5", - "Molar volume": "9.16 cm3", - "Name": "Zinc", - "Oxidation states": [ - 1, - 2 - ], - "Poissons ratio": "0.25", - "Reflectivity": "80 %", - "Refractive index": "1.002050", - "Rigidity modulus": "43 GPa", - "Shannon radii": { - "2": { - "IV": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - }, - "V": { - "": { - "crystal_radius": 0.82, - "ionic_radius": 0.68 - } - }, - "VI": { - "": { - "crystal_radius": 0.88, - "ionic_radius": 0.74 - } - }, - "VIII": { - "": { - "crystal_radius": 1.04, - "ionic_radius": 0.9 - } - } - } - }, - "Superconduction temperature": "0.85 K", - "Thermal conductivity": "120 W m-1 K-1", - "Van der waals radius": 1.39, - "Velocity of sound": "3700 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.65, - "Youngs modulus": "108 GPa", - "NMR Quadrupole Moment": { - "Zn-67": 150.15 - } - }, - "Zr": { - "Atomic mass": 91.224, - "Atomic no": 40, - "Atomic orbitals": { - "1s": -639.292236, - "2p": -80.010043, - "2s": -87.237062, - "3d": -6.544643, - "3p": -11.514415, - "3s": -14.230432, - "4d": -0.150673, - "4p": -1.186597, - "4s": -1.918971, - "5s": -0.162391 - }, - "Atomic radius": 1.55, - "Atomic radius calculated": 2.06, - "Boiling point": "4682 K", - "Brinell hardness": "650 MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "5.7 x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "6511 kg m-3", - "Electrical resistivity": "43.3 10-8 Ω m", - "Electronic structure": "[Kr].4d2.5s2", - "ICSD oxidation states": [ - 2, - 3, - 4 - ], - "Ionic radii": { - "4": 0.86 - }, - "Liquid range": "2554 K", - "Melting point": "2128 K", - "Mendeleev no": 49, - "Mineral hardness": "5.0", - "Molar volume": "14.02 cm3", - "Name": "Zirconium", - "Oxidation states": [ - 1, - 2, - 3, - 4 - ], - "Poissons ratio": "0.34", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "33 GPa", - "Shannon radii": { - "4": { - "IV": { - "": { - "crystal_radius": 0.73, - "ionic_radius": 0.59 - } - }, - "V": { - "": { - "crystal_radius": 0.8, - "ionic_radius": 0.66 - } - }, - "VI": { - "": { - "crystal_radius": 0.86, - "ionic_radius": 0.72 - } - }, - "VII": { - "": { - "crystal_radius": 0.92, - "ionic_radius": 0.78 - } - }, - "VIII": { - "": { - "crystal_radius": 0.98, - "ionic_radius": 0.84 - } - }, - "IX": { - "": { - "crystal_radius": 1.03, - "ionic_radius": 0.89 - } - } - } - }, - "Superconduction temperature": "0.61 K", - "Thermal conductivity": "23 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "3800 m s-1", - "Vickers hardness": "903 MN m-2", - "X": 1.33, - "Youngs modulus": "68 GPa" - } +{ + "Ac": { + "Atomic mass": 227.0, + "Atomic no": 89, + "Atomic orbitals": { + "1s": -3443.110367, + "2p": -572.7627, + "2s": -592.622878, + "3d": -119.541743, + "3p": -137.654394, + "3s": -147.320716, + "4d": -23.57061, + "4f": -12.278225, + "4p": -31.761846, + "4s": -36.15826, + "5d": -3.222752, + "5p": -6.06511, + "5s": -7.713078, + "6d": -0.137786, + "6p": -0.744524, + "6s": -1.19698, + "7s": -0.126551 + }, + "Atomic radius": 1.95, + "Atomic radius calculated": "no data", + "Boiling point": "3573 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "10070 kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].6d1.7s2", + "Ionic radii": { + "3": 1.26 + }, + "Liquid range": "2250 K", + "Melting point": "1323 K", + "Mendeleev no": 48, + "Mineral hardness": "no data", + "Molar volume": "22.55 cm3", + "Name": "Actinium", + "Oxidation states": [ + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.26, + "ionic_radius": 1.12 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "12 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.1, + "Youngs modulus": "no data GPa" + }, + "Ag": { + "Atomic mass": 107.8682, + "Atomic no": 47, + "Atomic orbitals": { + "1s": -900.324578, + "2p": -120.913351, + "2s": -129.859807, + "3d": -13.367803, + "3p": -20.06763, + "3s": -23.678437, + "4d": -0.298706, + "4p": -2.086602, + "4s": -3.22309, + "5s": -0.157407 + }, + "Atomic radius": 1.6, + "Atomic radius calculated": 1.65, + "Boiling point": "2435 K", + "Brinell hardness": "24.5 MN m-2", + "Bulk modulus": "100 GPa", + "Coefficient of linear thermal expansion": "18.9 x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "no data K", + "Density of solid": "10490 kg m-3", + "Electrical resistivity": "1.63 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s1", + "ICSD oxidation states": [ + 1, + 2, + 3 + ], + "Ionic radii": { + "1": 1.29, + "2": 1.08, + "3": 0.89 + }, + "Liquid range": "1200.07 K", + "Melting point": "1234.93 K", + "Mendeleev no": 71, + "Mineral hardness": "2.5", + "Molar volume": "10.27 cm3", + "Name": "Silver", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "0.37", + "Reflectivity": "97 %", + "Refractive index": "no data", + "Rigidity modulus": "30 GPa", + "Shannon radii": { + "1": { + "II": { + "": { + "crystal_radius": 0.81, + "ionic_radius": 0.67 + } + }, + "IV": { + "": { + "crystal_radius": 1.14, + "ionic_radius": 1.0 + } + }, + "IVSQ": { + "": { + "crystal_radius": 1.16, + "ionic_radius": 1.02 + } + }, + "V": { + "": { + "crystal_radius": 1.23, + "ionic_radius": 1.09 + } + }, + "VI": { + "": { + "crystal_radius": 1.29, + "ionic_radius": 1.15 + } + }, + "VII": { + "": { + "crystal_radius": 1.36, + "ionic_radius": 1.22 + } + }, + "VIII": { + "": { + "crystal_radius": 1.42, + "ionic_radius": 1.28 + } + } + }, + "2": { + "IVSQ": { + "": { + "crystal_radius": 0.93, + "ionic_radius": 0.79 + } + }, + "VI": { + "": { + "crystal_radius": 1.08, + "ionic_radius": 0.94 + } + } + }, + "3": { + "IVSQ": { + "": { + "crystal_radius": 0.81, + "ionic_radius": 0.67 + } + }, + "VI": { + "": { + "crystal_radius": 0.89, + "ionic_radius": 0.75 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "430 W m-1 K-1", + "Van der waals radius": 1.72, + "Velocity of sound": "2600 m s-1", + "Vickers hardness": "251 MN m-2", + "X": 1.93, + "Youngs modulus": "83 GPa" + }, + "Al": { + "Atomic mass": 26.9815386, + "Atomic no": 13, + "Atomic orbitals": { + "1s": -55.156044, + "2p": -2.564018, + "2s": -3.934827, + "3p": -0.102545, + "3s": -0.286883 + }, + "Atomic radius": 1.25, + "Atomic radius calculated": 1.18, + "Boiling point": "2792 K", + "Brinell hardness": "245 MN m-2", + "Bulk modulus": "76 GPa", + "Coefficient of linear thermal expansion": "23.1 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "2700 kg m-3", + "Electrical resistivity": "2.7 10-8 Ω m", + "Electronic structure": "[Ne].3s2.3p1", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "3": 0.675 + }, + "Liquid range": "1858.53 K", + "Melting point": "933.47 K", + "Mendeleev no": 80, + "Mineral hardness": "2.75", + "Molar volume": "10.00 cm3", + "Name": "Aluminum", + "Oxidation states": [ + 1, + 3 + ], + "Poissons ratio": "0.35", + "Reflectivity": "71 %", + "Refractive index": "no data", + "Rigidity modulus": "26 GPa", + "Shannon radii": { + "3": { + "IV": { + "": { + "crystal_radius": 0.53, + "ionic_radius": 0.39 + } + }, + "V": { + "": { + "crystal_radius": 0.62, + "ionic_radius": 0.48 + } + }, + "VI": { + "": { + "crystal_radius": 0.675, + "ionic_radius": 0.535 + } + } + } + }, + "Superconduction temperature": "1.175 K", + "Thermal conductivity": "235 W m-1 K-1", + "Van der waals radius": 1.84, + "Velocity of sound": "5100 m s-1", + "Vickers hardness": "167 MN m-2", + "X": 1.61, + "Youngs modulus": "70 GPa", + "NMR Quadrupole Moment": { + "Al-27": 146.6 + } + }, + "Am": { + "Atomic mass": 243.0, + "Atomic no": 95, + "Atomic orbitals": "no data", + "Atomic radius": 1.75, + "Atomic radius calculated": "no data", + "Boiling point": "2880 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f7.7s2", + "Ionic radii": { + "2": 1.4, + "3": 1.115, + "4": 0.99 + }, + "Liquid range": "1431 K", + "Melting point": "1449 K", + "Mendeleev no": 42, + "Mineral hardness": "no data", + "Molar volume": "17.63 cm3", + "Name": "Americium", + "Oxidation states": [ + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "2": { + "VII": { + "": { + "crystal_radius": 1.35, + "ionic_radius": 1.21 + } + }, + "VIII": { + "": { + "crystal_radius": 1.4, + "ionic_radius": 1.26 + } + }, + "IX": { + "": { + "crystal_radius": 1.45, + "ionic_radius": 1.31 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.115, + "ionic_radius": 0.975 + } + }, + "VIII": { + "": { + "crystal_radius": 1.23, + "ionic_radius": 1.09 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.99, + "ionic_radius": 0.85 + } + }, + "VIII": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + } + } + }, + "Superconduction temperature": "0.6 K", + "Thermal conductivity": "10 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Ar": { + "Atomic mass": 39.948, + "Atomic no": 18, + "Atomic orbitals": { + "1s": -113.800134, + "2p": -8.443439, + "2s": -10.794172, + "3p": -0.38233, + "3s": -0.883384 + }, + "Atomic radius": 0.71, + "Atomic radius calculated": 0.71, + "Boiling point": "87.3 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Critical temperature": "150.8 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Ne].3s2.3p6", + "Liquid range": "3.5 K", + "Max oxidation state": 0.0, + "Melting point": "83.8 K", + "Mendeleev no": 3, + "Min oxidation state": 0.0, + "Mineral hardness": "no data", + "Molar volume": "22.56 cm3", + "Name": "Argon", + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000281", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.01772 W m-1 K-1", + "Van der waals radius": 1.88, + "Velocity of sound": "319 m s-1", + "Vickers hardness": "no data MN m-2", + "Youngs modulus": "no data GPa" + }, + "As": { + "Atomic mass": 74.9216, + "Atomic no": 33, + "Atomic orbitals": { + "1s": -423.336658, + "2p": -47.527869, + "2s": -53.093086, + "3d": -1.542767, + "3p": -4.851725, + "3s": -6.730755, + "4p": -0.197497, + "4s": -0.52367 + }, + "Atomic radius": 1.15, + "Atomic radius calculated": 1.14, + "Boiling point": "887 K", + "Brinell hardness": "1440 MN m-2", + "Bulk modulus": "22 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -3, + 3, + 5 + ], + "Critical temperature": "1700 K", + "Density of solid": "5727 kg m-3", + "Electrical resistivity": "33 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2.4p3", + "ICSD oxidation states": [ + 2, + 3, + 5, + -2, + -3, + -1 + ], + "Ionic radii": { + "3": 0.72, + "5": 0.6 + }, + "Liquid range": "203 K", + "Melting point": "1090 K", + "Mendeleev no": 89, + "Mineral hardness": "3.5", + "Molar volume": "12.95 cm3", + "Name": "Arsenic", + "Oxidation states": [ + -3, + 2, + 3, + 5 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.001552", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.475, + "ionic_radius": 0.335 + } + }, + "VI": { + "": { + "crystal_radius": 0.6, + "ionic_radius": 0.46 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "50 W m-1 K-1", + "Van der waals radius": 1.85, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.18, + "Youngs modulus": "8 GPa" + }, + "At": { + "Atomic mass": 210.0, + "Atomic no": 85, + "Atomic orbitals": { + "1s": -3127.390276, + "2p": -513.044243, + "2s": -531.81835, + "3d": -103.060375, + "3p": -119.995013, + "3s": -129.035542, + "4d": -18.295162, + "4f": -8.063483, + "4p": -25.778264, + "4s": -29.809515, + "5d": -1.643758, + "5p": -4.027061, + "5s": -5.453383, + "6p": -0.255453, + "6s": -0.560189 + }, + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -1, + 1 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2.6p5", + "Ionic radii": { + "7": 0.76 + }, + "Liquid range": "no data K", + "Melting point": "575 K", + "Mendeleev no": 96, + "Mineral hardness": "no data", + "Molar volume": "no data cm3", + "Name": "Astatine", + "Oxidation states": [ + -1, + 1, + 3, + 5 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "7": { + "VI": { + "": { + "crystal_radius": 0.76, + "ionic_radius": 0.62 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "2 (estimate)W m-1 K-1", + "Van der waals radius": 2.02, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.2, + "Youngs modulus": "no data GPa" + }, + "Au": { + "Atomic mass": 196.966569, + "Atomic no": 79, + "Atomic orbitals": { + "1s": -2683.508245, + "2p": -430.725701, + "2s": -447.888973, + "3d": -81.511751, + "3p": -96.707, + "3s": -104.824516, + "4d": -12.131815, + "4f": -3.486824, + "4p": -18.578652, + "4s": -22.078357, + "5d": -0.304738, + "5p": -2.002495, + "5s": -3.113936, + "6s": -0.162334 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.74, + "Boiling point": "3129 K", + "Brinell hardness": "2450 MN m-2", + "Bulk modulus": "220 GPa", + "Coefficient of linear thermal expansion": "14.2 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "19300 kg m-3", + "Electrical resistivity": "2.2 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s1", + "Ionic radii": { + "1": 1.51, + "3": 0.99, + "5": 0.71 + }, + "Liquid range": "1791.67 K", + "Melting point": "1337.33 K", + "Mendeleev no": 70, + "Mineral hardness": "2.5", + "Molar volume": "10.21 cm3", + "Name": "Gold", + "Oxidation states": [ + -1, + 1, + 2, + 3, + 5 + ], + "Poissons ratio": "0.44", + "Reflectivity": "95 %", + "Refractive index": "no data", + "Rigidity modulus": "27 GPa", + "Shannon radii": { + "1": { + "VI": { + "": { + "crystal_radius": 1.51, + "ionic_radius": 1.37 + } + } + }, + "3": { + "IVSQ": { + "": { + "crystal_radius": 0.82, + "ionic_radius": 0.68 + } + }, + "VI": { + "": { + "crystal_radius": 0.99, + "ionic_radius": 0.85 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "320 W m-1 K-1", + "Van der waals radius": 1.66, + "Velocity of sound": "1740 m s-1", + "Vickers hardness": "216 MN m-2", + "X": 2.54, + "Youngs modulus": "78 GPa" + }, + "B": { + "Atomic mass": 10.811, + "Atomic no": 5, + "Atomic orbitals": { + "1s": -6.564347, + "2p": -0.136603, + "2s": -0.344701 + }, + "Atomic radius": 0.85, + "Atomic radius calculated": 0.87, + "Boiling point": "4200 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "320 GPa", + "Coefficient of linear thermal expansion": "6 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "2460 kg m-3", + "Electrical resistivity": "> 101210-8 Ω m", + "Electronic structure": "[He].2s2.2p1", + "ICSD oxidation states": [ + 3, + -3 + ], + "Ionic radii": { + "3": 0.41 + }, + "Liquid range": "1851 K", + "Melting point": "2349 K", + "Mendeleev no": 86, + "Mineral hardness": "9.3", + "Molar volume": "4.39 cm3", + "Name": "Boron", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "III": { + "": { + "crystal_radius": 0.15, + "ionic_radius": 0.01 + } + }, + "IV": { + "": { + "crystal_radius": 0.25, + "ionic_radius": 0.11 + } + }, + "VI": { + "": { + "crystal_radius": 0.41, + "ionic_radius": 0.27 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "27 W m-1 K-1", + "Van der waals radius": 1.92, + "Velocity of sound": "16200 m s-1", + "Vickers hardness": "49000 MN m-2", + "X": 2.04, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "B-10": 84.59, + "B-11": 40.59 + } + }, + "Ba": { + "Atomic mass": 137.327, + "Atomic no": 56, + "Atomic orbitals": { + "1s": -1305.743258, + "2p": -189.598483, + "2s": -200.844444, + "3d": -28.528933, + "3p": -37.536931, + "3s": -42.359434, + "4d": -3.432441, + "4p": -6.497622, + "4s": -8.257061, + "5p": -0.698605, + "5s": -1.157159, + "6s": -0.118967 + }, + "Atomic radius": 2.15, + "Atomic radius calculated": 2.53, + "Boiling point": "2143 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "9.6 GPa", + "Coefficient of linear thermal expansion": "20.6 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "3510 kg m-3", + "Electrical resistivity": "34 10-8 Ω m", + "Electronic structure": "[Xe].6s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 1.49 + }, + "Liquid range": "1143 K", + "Melting point": "1000 K", + "Mendeleev no": 14, + "Mineral hardness": "1.25", + "Molar volume": "38.16 cm3", + "Name": "Barium", + "Oxidation states": [ + 2 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "4.9 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.49, + "ionic_radius": 1.35 + } + }, + "VII": { + "": { + "crystal_radius": 1.52, + "ionic_radius": 1.38 + } + }, + "VIII": { + "": { + "crystal_radius": 1.56, + "ionic_radius": 1.42 + } + }, + "IX": { + "": { + "crystal_radius": 1.61, + "ionic_radius": 1.47 + } + }, + "X": { + "": { + "crystal_radius": 1.66, + "ionic_radius": 1.52 + } + }, + "XI": { + "": { + "crystal_radius": 1.71, + "ionic_radius": 1.57 + } + }, + "XII": { + "": { + "crystal_radius": 1.75, + "ionic_radius": 1.61 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "18 W m-1 K-1", + "Van der waals radius": 2.68, + "Velocity of sound": "1620 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.89, + "Youngs modulus": "13 GPa" + }, + "Be": { + "Atomic mass": 9.012182, + "Atomic no": 4, + "Atomic orbitals": { + "1s": -3.856411, + "2s": -0.205744 + }, + "Atomic radius": 1.05, + "Atomic radius calculated": 1.12, + "Boiling point": "2742 K", + "Brinell hardness": "600 MN m-2", + "Bulk modulus": "130 GPa", + "Coefficient of linear thermal expansion": "11.3 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "1848 kg m-3", + "Electrical resistivity": "3.8 10-8 Ω m", + "Electronic structure": "[He].2s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 0.59 + }, + "Liquid range": "1182 K", + "Melting point": "1560 K", + "Mendeleev no": 77, + "Mineral hardness": "5.5", + "Molar volume": "4.85 cm3", + "Name": "Beryllium", + "Oxidation states": [ + 2 + ], + "Poissons ratio": "0.032", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "132 GPa", + "Shannon radii": { + "2": { + "III": { + "": { + "crystal_radius": 0.3, + "ionic_radius": 0.16 + } + }, + "IV": { + "": { + "crystal_radius": 0.41, + "ionic_radius": 0.27 + } + }, + "VI": { + "": { + "crystal_radius": 0.59, + "ionic_radius": 0.45 + } + } + } + }, + "Superconduction temperature": "0.026 K", + "Thermal conductivity": "190 W m-1 K-1", + "Van der waals radius": 1.53, + "Velocity of sound": "13000 m s-1", + "Vickers hardness": "1670 MN m-2", + "X": 1.57, + "Youngs modulus": "287 GPa", + "NMR Quadrupole Moment": { + "Be-9": 52.88 + } + }, + "Bi": { + "Atomic mass": 208.9804, + "Atomic no": 83, + "Atomic orbitals": { + "1s": -2975.550959, + "2p": -484.716359, + "2s": -502.950758, + "3d": -95.532476, + "3p": -111.883393, + "3s": -120.613998, + "4d": -16.084817, + "4f": -6.382744, + "4p": -23.218641, + "4s": -27.07034, + "5d": -1.139408, + "5p": -3.293637, + "5s": -4.611934, + "6p": -0.180198, + "6s": -0.426129 + }, + "Atomic radius": 1.6, + "Atomic radius calculated": 1.43, + "Boiling point": "1837 K", + "Brinell hardness": "94.2 MN m-2", + "Bulk modulus": "31 GPa", + "Coefficient of linear thermal expansion": "13.4 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "9780 kg m-3", + "Electrical resistivity": "130 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2.6p3", + "ICSD oxidation states": [ + 1, + 2, + 3, + 5 + ], + "Ionic radii": { + "3": 1.17, + "5": 0.9 + }, + "Liquid range": "1292.6 K", + "Melting point": "544.4 K", + "Mendeleev no": 87, + "Mineral hardness": "2.25", + "Molar volume": "21.31 cm3", + "Name": "Bismuth", + "Oxidation states": [ + -3, + 3, + 5 + ], + "Poissons ratio": "0.33", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "12 GPa", + "Shannon radii": { + "3": { + "V": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + }, + "VI": { + "": { + "crystal_radius": 1.17, + "ionic_radius": 1.03 + } + }, + "VIII": { + "": { + "crystal_radius": 1.31, + "ionic_radius": 1.17 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "8 W m-1 K-1", + "Van der waals radius": 2.07, + "Velocity of sound": "1790 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.02, + "Youngs modulus": "32 GPa" + }, + "Bk": { + "Atomic mass": 247.0, + "Atomic no": 97, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "14780 kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f9.7s2", + "Ionic radii": { + "3": 1.1, + "4": 0.97 + }, + "Liquid range": "no data K", + "Melting point": "1259 K", + "Mendeleev no": 40, + "Mineral hardness": "no data", + "Molar volume": "16.84 cm3", + "Name": "Berkelium", + "Oxidation states": [ + 3, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.97, + "ionic_radius": 0.83 + } + }, + "VIII": { + "": { + "crystal_radius": 1.07, + "ionic_radius": 0.93 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "10 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Br": { + "Atomic mass": 79.904, + "Atomic no": 35, + "Atomic orbitals": { + "1s": -480.182643, + "2p": -55.67796, + "2s": -61.710022, + "3d": -2.52211, + "3p": -6.298805, + "3s": -8.409057, + "4p": -0.295334, + "4s": -0.720066 + }, + "Atomic radius": 1.15, + "Atomic radius calculated": 0.94, + "Boiling point": "332 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "1.9 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -1, + 1, + 3, + 5, + 7 + ], + "Critical temperature": "586 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "> 101810-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2.4p5", + "ICSD oxidation states": [ + 5, + -1 + ], + "Ionic radii": { + "-1": 1.82, + "3": 0.73, + "5": 0.45, + "7": 0.53 + }, + "Liquid range": "66.2 K", + "Melting point": "265.8 K", + "Mendeleev no": 98, + "Mineral hardness": "no data", + "Molar volume": "19.78 cm3", + "Name": "Bromine", + "Oxidation states": [ + -1, + 1, + 3, + 4, + 5, + 7 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.001132", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-1": { + "VI": { + "": { + "crystal_radius": 1.82, + "ionic_radius": 1.96 + } + } + }, + "3": { + "IVSQ": { + "": { + "crystal_radius": 0.73, + "ionic_radius": 0.59 + } + } + }, + "5": { + "IIIPY": { + "": { + "crystal_radius": 0.45, + "ionic_radius": 0.31 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.39, + "ionic_radius": 0.25 + } + }, + "VI": { + "": { + "crystal_radius": 0.53, + "ionic_radius": 0.39 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.12 W m-1 K-1", + "Van der waals radius": 1.85, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.96, + "Youngs modulus": "no data GPa" + }, + "C": { + "Atomic mass": 12.0107, + "Atomic no": 6, + "Atomic orbitals": { + "1s": -9.947718, + "2p": -0.199186, + "2s": -0.500866 + }, + "Atomic radius": 0.7, + "Atomic radius calculated": 0.67, + "Boiling point": "4300 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "33 GPa", + "Coefficient of linear thermal expansion": "7.1 x10-6K-1", + "Common oxidation states": [ + -4, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "2267 kg m-3", + "Electrical resistivity": "about 1000 - direction dependent10-8 Ω m", + "Electronic structure": "[He].2s2.2p2", + "ICSD oxidation states": [ + 2, + 3, + 4, + -4, + -3, + -2 + ], + "Ionic radii": { + "4": 0.3 + }, + "Liquid range": "500 K", + "Melting point": "3800 K", + "Mendeleev no": 95, + "Mineral hardness": "0.5 (graphite; diamond is 10.0)(no units)", + "Molar volume": "5.29 cm3", + "Name": "Carbon", + "Oxidation states": [ + -4, + -3, + -2, + -1, + 1, + 2, + 3, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "27 %", + "Refractive index": "2.417 (diamond)(no units)", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "4": { + "III": { + "": { + "crystal_radius": 0.06, + "ionic_radius": -0.08 + } + }, + "IV": { + "": { + "crystal_radius": 0.29, + "ionic_radius": 0.15 + } + }, + "VI": { + "": { + "crystal_radius": 0.3, + "ionic_radius": 0.16 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "140 W m-1 K-1", + "Van der waals radius": 1.7, + "Velocity of sound": "18350 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.55, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "C-11": 33.27 + } + }, + "Ca": { + "Atomic mass": 40.078, + "Atomic no": 20, + "Atomic orbitals": { + "1s": -143.935181, + "2p": -12.285376, + "2s": -15.046905, + "3p": -1.030572, + "3s": -1.706331, + "4s": -0.141411 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": 1.94, + "Boiling point": "1757 K", + "Brinell hardness": "167 MN m-2", + "Bulk modulus": "17 GPa", + "Coefficient of linear thermal expansion": "22.3 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "1550 kg m-3", + "Electrical resistivity": "3.4 10-8 Ω m", + "Electronic structure": "[Ar].4s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 1.14 + }, + "Liquid range": "642 K", + "Melting point": "1115 K", + "Mendeleev no": 16, + "Mineral hardness": "1.75", + "Molar volume": "26.20 cm3", + "Name": "Calcium", + "Oxidation states": [ + 2 + ], + "Poissons ratio": "0.31", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "7.4 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.14, + "ionic_radius": 1.0 + } + }, + "VII": { + "": { + "crystal_radius": 1.2, + "ionic_radius": 1.06 + } + }, + "VIII": { + "": { + "crystal_radius": 1.26, + "ionic_radius": 1.12 + } + }, + "IX": { + "": { + "crystal_radius": 1.32, + "ionic_radius": 1.18 + } + }, + "X": { + "": { + "crystal_radius": 1.37, + "ionic_radius": 1.23 + } + }, + "XII": { + "": { + "crystal_radius": 1.48, + "ionic_radius": 1.34 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "200 W m-1 K-1", + "Van der waals radius": 2.31, + "Velocity of sound": "3810 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.0, + "Youngs modulus": "20 GPa", + "NMR Quadrupole Moment": { + "Ca-41": -66.5, + "Ca-43": -40.8 + } + }, + "Cd": { + "Atomic mass": 112.411, + "Atomic no": 48, + "Atomic orbitals": { + "1s": -941.476646, + "2p": -127.63512, + "2s": -136.83249, + "3d": -14.685252, + "3p": -21.637522, + "3s": -25.379908, + "4d": -0.47053, + "4p": -2.39526, + "4s": -3.596069, + "5s": -0.204228 + }, + "Atomic radius": 1.55, + "Atomic radius calculated": 1.61, + "Boiling point": "1040 K", + "Brinell hardness": "203 MN m-2", + "Bulk modulus": "42 GPa", + "Coefficient of linear thermal expansion": "30.8 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "8650 kg m-3", + "Electrical resistivity": "7 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 1.09 + }, + "Liquid range": "445.78 K", + "Melting point": "594.22 K", + "Mendeleev no": 75, + "Mineral hardness": "2.0", + "Molar volume": "13.00 cm3", + "Name": "Cadmium", + "Oxidation states": [ + 1, + 2 + ], + "Poissons ratio": "0.30", + "Reflectivity": "67 %", + "Refractive index": "no data", + "Rigidity modulus": "19 GPa", + "Shannon radii": { + "2": { + "IV": { + "": { + "crystal_radius": 0.92, + "ionic_radius": 0.78 + } + }, + "V": { + "": { + "crystal_radius": 1.01, + "ionic_radius": 0.87 + } + }, + "VI": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + }, + "VII": { + "": { + "crystal_radius": 1.17, + "ionic_radius": 1.03 + } + }, + "VIII": { + "": { + "crystal_radius": 1.24, + "ionic_radius": 1.1 + } + }, + "XII": { + "": { + "crystal_radius": 1.45, + "ionic_radius": 1.31 + } + } + } + }, + "Superconduction temperature": "0.517 K", + "Thermal conductivity": "97 W m-1 K-1", + "Van der waals radius": 1.58, + "Velocity of sound": "2310 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.69, + "Youngs modulus": "50 GPa" + }, + "Ce": { + "Atomic mass": 140.116, + "Atomic no": 58, + "Atomic orbitals": { + "1s": -1406.148284, + "2p": -206.925148, + "2s": -218.684842, + "3d": -32.412569, + "3p": -41.938282, + "3s": -47.035283, + "4d": -4.192548, + "4f": -0.337442, + "4p": -7.532106, + "4s": -9.432744, + "5d": -0.14055, + "5p": -0.85011, + "5s": -1.369728, + "6s": -0.133974 + }, + "Atomic radius": 1.85, + "Atomic radius calculated": "no data", + "Boiling point": "3633 K", + "Brinell hardness": "412 MN m-2", + "Bulk modulus": "22 GPa", + "Coefficient of linear thermal expansion": "6.3 x10-6K-1", + "Common oxidation states": [ + 3, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "6689 kg m-3", + "Electrical resistivity": "74 10-8 Ω m", + "Electronic structure": "[Xe].4f1.5d1.6s2", + "ICSD oxidation states": [ + 3, + 4 + ], + "Ionic radii": { + "3": 1.15, + "4": 1.01 + }, + "Liquid range": "2565 K", + "Melting point": "1068 K", + "Mendeleev no": 32, + "Mineral hardness": "2.5", + "Molar volume": "20.69 cm3", + "Name": "Cerium", + "Oxidation states": [ + 2, + 3, + 4 + ], + "Poissons ratio": "0.24", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "14 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.15, + "ionic_radius": 1.01 + } + }, + "VII": { + "": { + "crystal_radius": 1.21, + "ionic_radius": 1.07 + } + }, + "VIII": { + "": { + "crystal_radius": 1.283, + "ionic_radius": 1.143 + } + }, + "IX": { + "": { + "crystal_radius": 1.336, + "ionic_radius": 1.196 + } + }, + "X": { + "": { + "crystal_radius": 1.39, + "ionic_radius": 1.25 + } + }, + "XII": { + "": { + "crystal_radius": 1.48, + "ionic_radius": 1.34 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 1.01, + "ionic_radius": 0.87 + } + }, + "VIII": { + "": { + "crystal_radius": 1.11, + "ionic_radius": 0.97 + } + }, + "X": { + "": { + "crystal_radius": 1.21, + "ionic_radius": 1.07 + } + }, + "XII": { + "": { + "crystal_radius": 1.28, + "ionic_radius": 1.14 + } + } + } + }, + "Superconduction temperature": "0.022 (under pressure)K", + "Thermal conductivity": "11 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2100 m s-1", + "Vickers hardness": "270 MN m-2", + "X": 1.12, + "Youngs modulus": "34 GPa" + }, + "Cf": { + "Atomic mass": 251.0, + "Atomic no": 98, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "15100 kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f10.7s2", + "Ionic radii": { + "3": 1.09, + "4": 0.961 + }, + "Liquid range": "no data K", + "Melting point": "1173 K", + "Mendeleev no": 39, + "Mineral hardness": "no data", + "Molar volume": "16.50 cm3", + "Name": "Californium", + "Oxidation states": [ + 2, + 3, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.961, + "ionic_radius": 0.821 + } + }, + "VIII": { + "": { + "crystal_radius": 1.06, + "ionic_radius": 0.92 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Cl": { + "Atomic mass": 35.453, + "Atomic no": 17, + "Atomic orbitals": { + "1s": -100.369229, + "2p": -7.039982, + "2s": -9.187993, + "3p": -0.32038, + "3s": -0.754458 + }, + "Atomic radius": 1.0, + "Atomic radius calculated": 0.79, + "Boiling point": "239.11 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "1.1 (liquid)GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -1, + 1, + 3, + 5, + 7 + ], + "Critical temperature": "417 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "> 101010-8 Ω m", + "Electronic structure": "[Ne].3s2.3p5", + "ICSD oxidation states": [ + -1 + ], + "Ionic radii": { + "-1": 1.67, + "5": 0.26, + "7": 0.41 + }, + "Liquid range": "67.51 K", + "Melting point": "171.6 K", + "Mendeleev no": 99, + "Mineral hardness": "no data", + "Molar volume": "17.39 cm3", + "Name": "Chlorine", + "Oxidation states": [ + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000773", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-1": { + "VI": { + "": { + "crystal_radius": 1.67, + "ionic_radius": 1.81 + } + } + }, + "5": { + "IIIPY": { + "": { + "crystal_radius": 0.26, + "ionic_radius": 0.12 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.22, + "ionic_radius": 0.08 + } + }, + "VI": { + "": { + "crystal_radius": 0.41, + "ionic_radius": 0.27 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.0089 W m-1 K-1", + "Van der waals radius": 1.75, + "Velocity of sound": "206 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 3.16, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "Cl-35": -81.65, + "Cl-37": -64.35 + } + }, + "Cm": { + "Atomic mass": 247.0, + "Atomic no": 96, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "3383 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "13510 kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f7.6d1.7s2", + "Ionic radii": { + "3": 1.11, + "4": 0.99 + }, + "Liquid range": "1770 K", + "Melting point": "1613 K", + "Mendeleev no": 41, + "Mineral hardness": "no data", + "Molar volume": "18.05 cm3", + "Name": "Curium", + "Oxidation states": [ + 3, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.11, + "ionic_radius": 0.97 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.99, + "ionic_radius": 0.85 + } + }, + "VIII": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "8.8 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Co": { + "Atomic mass": 58.933195, + "Atomic no": 27, + "Atomic orbitals": { + "1s": -275.616639, + "2p": -28.152095, + "2s": -32.379758, + "3d": -0.322368, + "3p": -2.388285, + "3s": -3.651812, + "4s": -0.204497 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.52, + "Boiling point": "3200 K", + "Brinell hardness": "700 MN m-2", + "Bulk modulus": "180 GPa", + "Coefficient of linear thermal expansion": "13.0 x10-6K-1", + "Common oxidation states": [ + 2, + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "8900 kg m-3", + "Electrical resistivity": "6 10-8 Ω m", + "Electronic structure": "[Ar].3d7.4s2", + "ICSD oxidation states": [ + 1, + 2, + 3, + 4 + ], + "Ionic radii": { + "2": 0.885, + "3": 0.75, + "4": 0.67 + }, + "Ionic radii hs": { + "2": 0.885, + "3": 0.75, + "4": 0.67 + }, + "Ionic radii ls": { + "2": 0.79, + "3": 0.685 + }, + "Liquid range": "1432 K", + "Melting point": "1768 K", + "Mendeleev no": 64, + "Mineral hardness": "5.0", + "Molar volume": "6.67 cm3", + "Name": "Cobalt", + "Oxidation states": [ + -1, + 1, + 2, + 3, + 4, + 5 + ], + "Poissons ratio": "0.31", + "Reflectivity": "67 %", + "Refractive index": "no data", + "Rigidity modulus": "75 GPa", + "Shannon radii": { + "2": { + "IV": { + "High Spin": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + }, + "V": { + "": { + "crystal_radius": 0.81, + "ionic_radius": 0.67 + } + }, + "VI": { + "Low Spin": { + "crystal_radius": 0.79, + "ionic_radius": 0.65 + }, + "High Spin": { + "crystal_radius": 0.885, + "ionic_radius": 0.745 + } + }, + "VIII": { + "": { + "crystal_radius": 1.04, + "ionic_radius": 0.9 + } + } + }, + "3": { + "VI": { + "High Spin": { + "crystal_radius": 0.75, + "ionic_radius": 0.61 + }, + "Low Spin": { + "crystal_radius": 0.685, + "ionic_radius": 0.545 + } + } + }, + "4": { + "IV": { + "": { + "crystal_radius": 0.54, + "ionic_radius": 0.4 + } + }, + "VI": { + "High Spin": { + "crystal_radius": 0.67, + "ionic_radius": 0.53 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "100 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4720 m s-1", + "Vickers hardness": "1043 MN m-2", + "X": 1.88, + "Youngs modulus": "209 GPa", + "NMR Quadrupole Moment": { + "Co-59": 420.3 + } + }, + "Cr": { + "Atomic mass": 51.9961, + "Atomic no": 24, + "Atomic orbitals": { + "1s": -213.881191, + "2p": -20.526273, + "2s": -24.113457, + "3d": -0.118123, + "3p": -1.65423, + "3s": -2.649085, + "4s": -0.150445 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.66, + "Boiling point": "2944 K", + "Brinell hardness": "1120 MN m-2", + "Bulk modulus": "160 GPa", + "Coefficient of linear thermal expansion": "4.9 x10-6K-1", + "Common oxidation states": [ + 3, + 6 + ], + "Critical temperature": "no data K", + "Density of solid": "7140 kg m-3", + "Electrical resistivity": "12.7 10-8 Ω m", + "Electronic structure": "[Ar].3d5.4s1", + "ICSD oxidation states": [ + 2, + 3, + 4, + 5, + 6 + ], + "Ionic radii": { + "2": 0.94 + }, + "Ionic radii hs": { + "2": 0.94 + }, + "Ionic radii ls": { + "2": 0.87, + "3": 0.755, + "4": 0.69, + "5": 0.63, + "6": 0.58 + }, + "Liquid range": "764 K", + "Melting point": "2180 K", + "Mendeleev no": 57, + "Mineral hardness": "8.5", + "Molar volume": "7.23 cm3", + "Name": "Chromium", + "Oxidation states": [ + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.21", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "115 GPa", + "Shannon radii": { + "2": { + "VI": { + "Low Spin": { + "crystal_radius": 0.87, + "ionic_radius": 0.73 + }, + "High Spin": { + "crystal_radius": 0.94, + "ionic_radius": 0.8 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 0.755, + "ionic_radius": 0.615 + } + } + }, + "4": { + "IV": { + "": { + "crystal_radius": 0.55, + "ionic_radius": 0.41 + } + }, + "VI": { + "": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.485, + "ionic_radius": 0.345 + } + }, + "VI": { + "": { + "crystal_radius": 0.63, + "ionic_radius": 0.49 + } + }, + "VIII": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.4, + "ionic_radius": 0.26 + } + }, + "VI": { + "": { + "crystal_radius": 0.58, + "ionic_radius": 0.44 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "94 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "5940 m s-1", + "Vickers hardness": "1060 MN m-2", + "X": 1.66, + "Youngs modulus": "279 GPa", + "NMR Quadrupole Moment": { + "Cr-53": -150.5 + } + }, + "Cs": { + "Atomic mass": 132.9054519, + "Atomic no": 55, + "Atomic orbitals": { + "1s": -1256.738791, + "2p": -180.995344, + "2s": -191.981873, + "3d": -26.418398, + "3p": -35.166423, + "3s": -39.851584, + "4d": -2.848386, + "4p": -5.769326, + "4s": -7.455966, + "5p": -0.504903, + "5s": -0.915819, + "6s": -0.078699 + }, + "Atomic radius": 2.6, + "Atomic radius calculated": 2.98, + "Boiling point": "944 K", + "Brinell hardness": "0.14 MN m-2", + "Bulk modulus": "1.6 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "1938 K", + "Density of solid": "1879 kg m-3", + "Electrical resistivity": "21 10-8 Ω m", + "Electronic structure": "[Xe].6s1", + "ICSD oxidation states": [ + 1 + ], + "Ionic radii": { + "1": 1.81 + }, + "Liquid range": "642.41 K", + "Melting point": "301.59 K", + "Mendeleev no": 8, + "Mineral hardness": "0.2", + "Molar volume": "70.94 cm3", + "Name": "Cesium", + "Oxidation states": [ + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "1": { + "VI": { + "": { + "crystal_radius": 1.81, + "ionic_radius": 1.67 + } + }, + "VIII": { + "": { + "crystal_radius": 1.88, + "ionic_radius": 1.74 + } + }, + "IX": { + "": { + "crystal_radius": 1.92, + "ionic_radius": 1.78 + } + }, + "X": { + "": { + "crystal_radius": 1.95, + "ionic_radius": 1.81 + } + }, + "XI": { + "": { + "crystal_radius": 1.99, + "ionic_radius": 1.85 + } + }, + "XII": { + "": { + "crystal_radius": 2.02, + "ionic_radius": 1.88 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "36 W m-1 K-1", + "Van der waals radius": 3.43, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.79, + "Youngs modulus": "1.7 GPa" + }, + "Cu": { + "Atomic mass": 63.546, + "Atomic no": 29, + "Atomic orbitals": { + "1s": -320.78852, + "2p": -33.481247, + "2s": -38.14131, + "3d": -0.202272, + "3p": -2.609244, + "3s": -4.057453, + "4s": -0.172056 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.45, + "Boiling point": "3200 K", + "Brinell hardness": "874 MN m-2", + "Bulk modulus": "140 GPa", + "Coefficient of linear thermal expansion": "16.5 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "8920 kg m-3", + "Electrical resistivity": "1.72 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s1", + "ICSD oxidation states": [ + 1, + 2, + 3 + ], + "Ionic radii": { + "1": 0.91, + "2": 0.87, + "3": 0.68 + }, + "Liquid range": "1842.23 K", + "Melting point": "1357.77 K", + "Mendeleev no": 72, + "Mineral hardness": "3.0", + "Molar volume": "7.11 cm3", + "Name": "Copper", + "Oxidation states": [ + 1, + 2, + 3, + 4 + ], + "Poissons ratio": "0.34", + "Reflectivity": "90 %", + "Refractive index": "no data", + "Rigidity modulus": "48 GPa", + "Shannon radii": { + "1": { + "II": { + "": { + "crystal_radius": 0.6, + "ionic_radius": 0.46 + } + }, + "IV": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + }, + "VI": { + "": { + "crystal_radius": 0.91, + "ionic_radius": 0.77 + } + } + }, + "2": { + "IV": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + }, + "IVSQ": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + }, + "V": { + "": { + "crystal_radius": 0.79, + "ionic_radius": 0.65 + } + }, + "VI": { + "": { + "crystal_radius": 0.87, + "ionic_radius": 0.73 + } + } + }, + "3": { + "VI": { + "Low Spin": { + "crystal_radius": 0.68, + "ionic_radius": 0.54 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "400 W m-1 K-1", + "Van der waals radius": 1.4, + "Velocity of sound": "3570 m s-1", + "Vickers hardness": "369 MN m-2", + "X": 1.9, + "Youngs modulus": "130 GPa", + "NMR Quadrupole Moment": { + "Cu-63": -220.15, + "Cu-65": -204.14 + } + }, + "Dy": { + "Atomic mass": 162.5, + "Atomic no": 66, + "Atomic orbitals": { + "1s": -1843.229585, + "2p": -281.558531, + "2s": -295.342856, + "3d": -47.4867, + "3p": -59.091931, + "3s": -65.299442, + "4d": -5.686352, + "4f": -0.265302, + "4p": -10.094091, + "4s": -12.551251, + "5p": -0.90349, + "5s": -1.547977, + "6s": -0.132769 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": 2.28, + "Boiling point": "2840 K", + "Brinell hardness": "500 MN m-2", + "Bulk modulus": "41 GPa", + "Coefficient of linear thermal expansion": "9.9 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "8551 kg m-3", + "Electrical resistivity": "92.6 10-8 Ω m", + "Electronic structure": "[Xe].4f10.6s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "2": 1.21, + "3": 1.052 + }, + "Liquid range": "1160 K", + "Melting point": "1680 K", + "Mendeleev no": 24, + "Mineral hardness": "no data", + "Molar volume": "19.01 cm3", + "Name": "Dysprosium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.25", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "25 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.21, + "ionic_radius": 1.07 + } + }, + "VII": { + "": { + "crystal_radius": 1.27, + "ionic_radius": 1.13 + } + }, + "VIII": { + "": { + "crystal_radius": 1.33, + "ionic_radius": 1.19 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.052, + "ionic_radius": 0.912 + } + }, + "VII": { + "": { + "crystal_radius": 1.11, + "ionic_radius": 0.97 + } + }, + "VIII": { + "": { + "crystal_radius": 1.167, + "ionic_radius": 1.027 + } + }, + "IX": { + "": { + "crystal_radius": 1.223, + "ionic_radius": 1.083 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "11 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2710 m s-1", + "Vickers hardness": "540 MN m-2", + "X": 1.22, + "Youngs modulus": "61 GPa" + }, + "Er": { + "Atomic mass": 167.259, + "Atomic no": 68, + "Atomic orbitals": { + "1s": -1961.799176, + "2p": -302.01827, + "2s": -316.310631, + "3d": -51.682149, + "3p": -63.818655, + "3s": -70.310142, + "4d": -6.127443, + "4f": -0.278577, + "4p": -10.819574, + "4s": -13.423547, + "5p": -0.935202, + "5s": -1.616073, + "6s": -0.134905 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": 2.26, + "Boiling point": "3141 K", + "Brinell hardness": "814 MN m-2", + "Bulk modulus": "44 GPa", + "Coefficient of linear thermal expansion": "12.2 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "9066 kg m-3", + "Electrical resistivity": "86.0 10-8 Ω m", + "Electronic structure": "[Xe].4f12.6s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "3": 1.03 + }, + "Liquid range": "1371 K", + "Melting point": "1802 K", + "Mendeleev no": 22, + "Mineral hardness": "no data", + "Molar volume": "18.46 cm3", + "Name": "Erbium", + "Oxidation states": [ + 3 + ], + "Poissons ratio": "0.24", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "28 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.03, + "ionic_radius": 0.89 + } + }, + "VII": { + "": { + "crystal_radius": 1.085, + "ionic_radius": 0.945 + } + }, + "VIII": { + "": { + "crystal_radius": 1.144, + "ionic_radius": 1.004 + } + }, + "IX": { + "": { + "crystal_radius": 1.202, + "ionic_radius": 1.062 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "15 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2830 m s-1", + "Vickers hardness": "589 MN m-2", + "X": 1.24, + "Youngs modulus": "70 GPa" + }, + "Es": { + "Atomic mass": 252.0, + "Atomic no": 99, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f11.7s2", + "Liquid range": "no data K", + "Melting point": "1133 K", + "Mendeleev no": 38, + "Mineral hardness": "no data", + "Molar volume": "28.52 cm3", + "Name": "Einsteinium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Eu": { + "Atomic mass": 151.964, + "Atomic no": 63, + "Atomic orbitals": { + "1s": -1672.309322, + "2p": -252.176697, + "2s": -265.199534, + "3d": -41.465518, + "3p": -52.281987, + "3s": -58.068128, + "4d": -5.03242, + "4f": -0.232773, + "4p": -9.025455, + "4s": -11.267747, + "5p": -0.853575, + "5s": -1.444087, + "6s": -0.129426 + }, + "Atomic radius": 1.85, + "Atomic radius calculated": 2.31, + "Boiling point": "1800 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "8.3 GPa", + "Coefficient of linear thermal expansion": "35 x10-6K-1", + "Common oxidation states": [ + 2, + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "5244 kg m-3", + "Electrical resistivity": "90 10-8 Ω m", + "Electronic structure": "[Xe].4f7.6s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "2": 1.31, + "3": 1.087 + }, + "Liquid range": "701 K", + "Melting point": "1099 K", + "Mendeleev no": 18, + "Mineral hardness": "no data", + "Molar volume": "28.97 cm3", + "Name": "Europium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.15", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "7.9 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.31, + "ionic_radius": 1.17 + } + }, + "VII": { + "": { + "crystal_radius": 1.34, + "ionic_radius": 1.2 + } + }, + "VIII": { + "": { + "crystal_radius": 1.39, + "ionic_radius": 1.25 + } + }, + "IX": { + "": { + "crystal_radius": 1.44, + "ionic_radius": 1.3 + } + }, + "X": { + "": { + "crystal_radius": 1.49, + "ionic_radius": 1.35 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.087, + "ionic_radius": 0.947 + } + }, + "VII": { + "": { + "crystal_radius": 1.15, + "ionic_radius": 1.01 + } + }, + "VIII": { + "": { + "crystal_radius": 1.206, + "ionic_radius": 1.066 + } + }, + "IX": { + "": { + "crystal_radius": 1.26, + "ionic_radius": 1.12 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "14 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "167 MN m-2", + "X": 1.2, + "Youngs modulus": "18 GPa" + }, + "F": { + "Atomic mass": 18.9984032, + "Atomic no": 9, + "Atomic orbitals": { + "1s": -24.189391, + "2p": -0.415606, + "2s": -1.086859 + }, + "Atomic radius": 0.5, + "Atomic radius calculated": 0.42, + "Boiling point": "85.03 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -1 + ], + "Critical temperature": "144 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[He].2s2.2p5", + "ICSD oxidation states": [ + -1 + ], + "Ionic radii": { + "-1": 1.19, + "7": 0.22 + }, + "Liquid range": "31.5 K", + "Melting point": "53.53 K", + "Mendeleev no": 102, + "Mineral hardness": "no data", + "Molar volume": "11.20 cm3", + "Name": "Fluorine", + "Oxidation states": [ + -1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000195", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-1": { + "II": { + "": { + "crystal_radius": 1.145, + "ionic_radius": 1.285 + } + }, + "III": { + "": { + "crystal_radius": 1.16, + "ionic_radius": 1.3 + } + }, + "IV": { + "": { + "crystal_radius": 1.17, + "ionic_radius": 1.31 + } + }, + "VI": { + "": { + "crystal_radius": 1.19, + "ionic_radius": 1.33 + } + } + }, + "7": { + "VI": { + "": { + "crystal_radius": 0.22, + "ionic_radius": 0.08 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.0277 W m-1 K-1", + "Van der waals radius": 1.47, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 3.98, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "F-19": -94.2 + } + }, + "Fe": { + "Atomic mass": 55.845, + "Atomic no": 26, + "Atomic orbitals": { + "1s": -254.225505, + "2p": -25.551766, + "2s": -29.56486, + "3d": -0.295049, + "3p": -2.187523, + "3s": -3.360621, + "4s": -0.197978 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.56, + "Boiling point": "3134 K", + "Brinell hardness": "490 MN m-2", + "Bulk modulus": "170 GPa", + "Coefficient of linear thermal expansion": "11.8 x10-6K-1", + "Common oxidation states": [ + 2, + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "7874 kg m-3", + "Electrical resistivity": "10 10-8 Ω m", + "Electronic structure": "[Ar].3d6.4s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "2": 0.92, + "3": 0.785 + }, + "Ionic radii hs": { + "2": 0.92, + "3": 0.785 + }, + "Ionic radii ls": { + "2": 0.75, + "3": 0.69, + "4": 0.725, + "6": 0.39 + }, + "Liquid range": "1323 K", + "Melting point": "1811 K", + "Mendeleev no": 61, + "Mineral hardness": "4.0", + "Molar volume": "7.09 cm3", + "Name": "Iron", + "Oxidation states": [ + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.29", + "Reflectivity": "65 %", + "Refractive index": "no data", + "Rigidity modulus": "82 GPa", + "Shannon radii": { + "2": { + "IV": { + "High Spin": { + "crystal_radius": 0.77, + "ionic_radius": 0.63 + } + }, + "IVSQ": { + "High Spin": { + "crystal_radius": 0.78, + "ionic_radius": 0.64 + } + }, + "VI": { + "Low Spin": { + "crystal_radius": 0.75, + "ionic_radius": 0.61 + }, + "High Spin": { + "crystal_radius": 0.92, + "ionic_radius": 0.78 + } + }, + "VIII": { + "High Spin": { + "crystal_radius": 1.06, + "ionic_radius": 0.92 + } + } + }, + "3": { + "IV": { + "High Spin": { + "crystal_radius": 0.63, + "ionic_radius": 0.49 + } + }, + "V": { + "": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + }, + "VI": { + "Low Spin": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + }, + "High Spin": { + "crystal_radius": 0.785, + "ionic_radius": 0.645 + } + }, + "VIII": { + "High Spin": { + "crystal_radius": 0.92, + "ionic_radius": 0.78 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.725, + "ionic_radius": 0.585 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.39, + "ionic_radius": 0.25 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "80 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4910 m s-1", + "Vickers hardness": "608 MN m-2", + "X": 1.83, + "Youngs modulus": "211 GPa", + "NMR Quadrupole Moment": { + "Fe-57": 160.0 + } + }, + "Fm": { + "Atomic mass": 257.0, + "Atomic no": 100, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f12.7s2", + "Liquid range": "no data K", + "Melting point": "about 1800 K", + "Mendeleev no": 37, + "Mineral hardness": "no data", + "Molar volume": "no data cm3", + "Name": "Fermium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Fr": { + "Atomic mass": 223.0, + "Atomic no": 87, + "Atomic orbitals": { + "1s": -3283.263399, + "2p": -542.41424, + "2s": -561.73045, + "3d": -111.085223, + "3p": -128.607136, + "3s": -137.959632, + "4d": -20.812462, + "4f": -10.050648, + "4p": -28.648131, + "4s": -32.861013, + "5d": -2.360991, + "5p": -4.97328, + "5s": -6.509516, + "6p": -0.466197, + "6s": -0.841848, + "7s": -0.076176 + }, + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].7s1", + "Ionic radii": { + "1": 1.94 + }, + "Liquid range": "no data K", + "Melting point": "maybe about 300 K", + "Mendeleev no": 7, + "Mineral hardness": "no data", + "Molar volume": "no data cm3", + "Name": "Francium", + "Oxidation states": [ + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "1": { + "VI": { + "": { + "crystal_radius": 1.94, + "ionic_radius": 1.8 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": 3.48, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.7, + "Youngs modulus": "no data GPa" + }, + "Ga": { + "Atomic mass": 69.723, + "Atomic no": 31, + "Atomic orbitals": { + "1s": -370.170639, + "2p": -40.093339, + "2s": -45.200869, + "3d": -0.736204, + "3p": -3.584666, + "3s": -5.241645, + "4p": -0.101634, + "4s": -0.328019 + }, + "Atomic radius": 1.3, + "Atomic radius calculated": 1.36, + "Boiling point": "2477 K", + "Brinell hardness": "60 MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "120 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "5904 kg m-3", + "Electrical resistivity": "about 14 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2.4p1", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "3": 0.76 + }, + "Liquid range": "2174.09 K", + "Melting point": "302.91 K", + "Mendeleev no": 81, + "Mineral hardness": "1.5", + "Molar volume": "11.80 cm3", + "Name": "Gallium", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "IV": { + "": { + "crystal_radius": 0.61, + "ionic_radius": 0.47 + } + }, + "V": { + "": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + } + }, + "VI": { + "": { + "crystal_radius": 0.76, + "ionic_radius": 0.62 + } + } + } + }, + "Superconduction temperature": "1.083 K", + "Thermal conductivity": "29 W m-1 K-1", + "Van der waals radius": 1.87, + "Velocity of sound": "2740 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.81, + "Youngs modulus": "no data GPa" + }, + "Gd": { + "Atomic mass": 157.25, + "Atomic no": 64, + "Atomic orbitals": { + "1s": -1728.625195, + "2p": -262.081616, + "2s": -275.36313, + "3d": -43.754556, + "3p": -54.836922, + "3s": -60.764408, + "4d": -5.531835, + "4f": -0.489012, + "4p": -9.669866, + "4s": -11.986486, + "5d": -0.12722, + "5p": -0.978749, + "5s": -1.608477, + "6s": -0.143627 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": 2.33, + "Boiling point": "3523 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "38 GPa", + "Coefficient of linear thermal expansion": "9.4 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "7901 kg m-3", + "Electrical resistivity": "131 10-8 Ω m", + "Electronic structure": "[Xe].4f7.5d1.6s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "3": 1.075 + }, + "Liquid range": "1938 K", + "Melting point": "1585 K", + "Mendeleev no": 27, + "Mineral hardness": "no data", + "Molar volume": "19.90 cm3", + "Name": "Gadolinium", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "0.26", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "22 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.078, + "ionic_radius": 0.938 + } + }, + "VII": { + "": { + "crystal_radius": 1.14, + "ionic_radius": 1.0 + } + }, + "VIII": { + "": { + "crystal_radius": 1.193, + "ionic_radius": 1.053 + } + }, + "IX": { + "": { + "crystal_radius": 1.247, + "ionic_radius": 1.107 + } + } + } + }, + "Superconduction temperature": "1.083 K", + "Thermal conductivity": "11 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2680 m s-1", + "Vickers hardness": "570 MN m-2", + "X": 1.2, + "Youngs modulus": "55 GPa" + }, + "Ge": { + "Atomic mass": 72.64, + "Atomic no": 32, + "Atomic orbitals": { + "1s": -396.292991, + "2p": -43.720129, + "2s": -49.055282, + "3d": -1.117316, + "3p": -4.194822, + "3s": -5.961472, + "4p": -0.149882, + "4s": -0.426523 + }, + "Atomic radius": 1.25, + "Atomic radius calculated": 1.25, + "Boiling point": "3093 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "6 x10-6K-1", + "Common oxidation states": [ + -4, + 2, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "5323 kg m-3", + "Electrical resistivity": "about 50000 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2.4p2", + "ICSD oxidation states": [ + 2, + 3, + 4 + ], + "Ionic radii": { + "2": 0.87, + "4": 0.67 + }, + "Liquid range": "1881.6 K", + "Melting point": "1211.4 K", + "Mendeleev no": 84, + "Mineral hardness": "6.0", + "Molar volume": "13.63 cm3", + "Name": "Germanium", + "Oxidation states": [ + -4, + 1, + 2, + 3, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 0.87, + "ionic_radius": 0.73 + } + } + }, + "4": { + "IV": { + "": { + "crystal_radius": 0.53, + "ionic_radius": 0.39 + } + }, + "VI": { + "": { + "crystal_radius": 0.67, + "ionic_radius": 0.53 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "60 W m-1 K-1", + "Van der waals radius": 2.11, + "Velocity of sound": "5400 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.01, + "Youngs modulus": "no data GPa" + }, + "H": { + "Atomic mass": 1.00794, + "Atomic no": 1, + "Atomic orbitals": { + "1s": -0.233471 + }, + "Atomic radius": 0.25, + "Atomic radius calculated": 0.53, + "Boiling point": "20.28 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -1, + 1 + ], + "Critical temperature": "33 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "1s1", + "ICSD oxidation states": [ + 1, + -1 + ], + "Liquid range": "6.27 K", + "Melting point": "14.01 K", + "Mendeleev no": 103, + "Mineral hardness": "no data", + "Molar volume": "11.42 cm3", + "Name": "Hydrogen", + "Oxidation states": [ + -1, + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000132 (gas; liquid 1.12)(no units)", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "1": { + "I": { + "": { + "crystal_radius": -0.24, + "ionic_radius": -0.38 + } + }, + "II": { + "": { + "crystal_radius": -0.04, + "ionic_radius": -0.18 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.1805 W m-1 K-1", + "Van der waals radius": 1.2, + "Velocity of sound": "1270 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.2, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "H-2": 2.86 + } + }, + "He": { + "Atomic mass": 4.002602, + "Atomic no": 2, + "Atomic orbitals": { + "1s": -0.570425 + }, + "Atomic radius": "no data", + "Atomic radius calculated": 0.31, + "Boiling point": "4.22 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Critical temperature": "5.19 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "1s2", + "Liquid range": "3.27 K", + "Max oxidation state": 0.0, + "Melting point": "0.95 K", + "Mendeleev no": 1, + "Min oxidation state": 0.0, + "Mineral hardness": "no data", + "Molar volume": "21.0 cm3", + "Name": "Helium", + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000035 (gas; liquid 1.028)(no units)", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.1513 W m-1 K-1", + "Van der waals radius": 1.4, + "Velocity of sound": "970 m s-1", + "Vickers hardness": "no data MN m-2", + "Youngs modulus": "no data GPa" + }, + "Hf": { + "Atomic mass": 178.49, + "Atomic no": 72, + "Atomic orbitals": { + "1s": -2210.65199, + "2p": -345.687023, + "2s": -361.006527, + "3d": -61.231443, + "3p": -74.452656, + "3s": -81.522812, + "4d": -7.676638, + "4f": -0.871574, + "4p": -12.971211, + "4s": -15.883625, + "5d": -0.143805, + "5p": -1.246441, + "5s": -2.049828, + "6s": -0.166465 + }, + "Atomic radius": 1.55, + "Atomic radius calculated": 2.08, + "Boiling point": "4876 K", + "Brinell hardness": "1700 MN m-2", + "Bulk modulus": "110 GPa", + "Coefficient of linear thermal expansion": "5.9 x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "13310 kg m-3", + "Electrical resistivity": "34 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d2.6s2", + "ICSD oxidation states": [ + 4 + ], + "Ionic radii": { + "4": 0.85 + }, + "Liquid range": "2370 K", + "Melting point": "2506 K", + "Mendeleev no": 50, + "Mineral hardness": "5.5", + "Molar volume": "13.44 cm3", + "Name": "Hafnium", + "Oxidation states": [ + 2, + 3, + 4 + ], + "Poissons ratio": "0.37", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "30 GPa", + "Shannon radii": { + "4": { + "IV": { + "": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + }, + "VI": { + "": { + "crystal_radius": 0.85, + "ionic_radius": 0.71 + } + }, + "VII": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + }, + "VIII": { + "": { + "crystal_radius": 0.97, + "ionic_radius": 0.83 + } + } + } + }, + "Superconduction temperature": "0.128 K", + "Thermal conductivity": "23 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "3010 m s-1", + "Vickers hardness": "1760 MN m-2", + "X": 1.3, + "Youngs modulus": "78 GPa" + }, + "Hg": { + "Atomic mass": 200.59, + "Atomic no": 80, + "Atomic orbitals": { + "1s": -2755.022637, + "2p": -443.848676, + "2s": -461.27864, + "3d": -84.845492, + "3p": -100.328031, + "3s": -108.597921, + "4d": -13.019221, + "4f": -4.110291, + "4p": -19.636187, + "4s": -23.222921, + "5d": -0.452552, + "5p": -2.261975, + "5s": -3.423486, + "6s": -0.205137 + }, + "Atomic radius": 1.5, + "Atomic radius calculated": 1.71, + "Boiling point": "629.88 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "25 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 1, + 2 + ], + "Critical temperature": "1750 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "96 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2", + "ICSD oxidation states": [ + 1, + 2 + ], + "Ionic radii": { + "1": 1.33, + "2": 1.16 + }, + "Liquid range": "395.56 K", + "Melting point": "234.32 K", + "Mendeleev no": 74, + "Mineral hardness": "1.5", + "Molar volume": "14.09 cm3", + "Name": "Mercury", + "Oxidation states": [ + 1, + 2, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "73 %", + "Refractive index": "1.000933", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "1": { + "III": { + "": { + "crystal_radius": 1.11, + "ionic_radius": 0.97 + } + }, + "VI": { + "": { + "crystal_radius": 1.33, + "ionic_radius": 1.19 + } + } + }, + "2": { + "II": { + "": { + "crystal_radius": 0.83, + "ionic_radius": 0.69 + } + }, + "IV": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + }, + "VI": { + "": { + "crystal_radius": 1.16, + "ionic_radius": 1.02 + } + }, + "VIII": { + "": { + "crystal_radius": 1.28, + "ionic_radius": 1.14 + } + } + } + }, + "Superconduction temperature": "3.95 K", + "Thermal conductivity": "8.3 W m-1 K-1", + "Van der waals radius": 1.55, + "Velocity of sound": "1407 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.0, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "Hg-201": 387.6 + } + }, + "Ho": { + "Atomic mass": 164.93032, + "Atomic no": 67, + "Atomic orbitals": { + "1s": -1902.051908, + "2p": -291.700994, + "2s": -305.739294, + "3d": -49.565996, + "3p": -61.436304, + "3s": -67.785492, + "4d": -5.906195, + "4f": -0.272677, + "4p": -10.455303, + "4s": -12.985498, + "5p": -0.919463, + "5s": -1.582088, + "6s": -0.133845 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": "no data", + "Boiling point": "2993 K", + "Brinell hardness": "746 MN m-2", + "Bulk modulus": "40 GPa", + "Coefficient of linear thermal expansion": "11.2 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "8795 kg m-3", + "Electrical resistivity": "81.4 10-8 Ω m", + "Electronic structure": "[Xe].4f11.6s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "3": 1.041 + }, + "Liquid range": "1259 K", + "Melting point": "1734 K", + "Mendeleev no": 23, + "Mineral hardness": "no data", + "Molar volume": "18.74 cm3", + "Name": "Holmium", + "Oxidation states": [ + 3 + ], + "Poissons ratio": "0.23", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "26 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.041, + "ionic_radius": 0.901 + } + }, + "VIII": { + "": { + "crystal_radius": 1.155, + "ionic_radius": 1.015 + } + }, + "IX": { + "": { + "crystal_radius": 1.212, + "ionic_radius": 1.072 + } + }, + "X": { + "": { + "crystal_radius": 1.26, + "ionic_radius": 1.12 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "16 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2760 m s-1", + "Vickers hardness": "481 MN m-2", + "X": 1.23, + "Youngs modulus": "65 GPa" + }, + "I": { + "Atomic mass": 126.90447, + "Atomic no": 53, + "Atomic orbitals": { + "1s": -1161.787047, + "2p": -164.603788, + "2s": -175.073804, + "3d": -22.600693, + "3p": -30.831092, + "3s": -35.243351, + "4d": -1.938179, + "4p": -4.572522, + "4s": -6.115811, + "5p": -0.267904, + "5s": -0.596339 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.15, + "Boiling point": "457.4 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "7.7 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -1, + 1, + 3, + 5, + 7 + ], + "Critical temperature": "819 K", + "Density of solid": "4940 kg m-3", + "Electrical resistivity": "> 101510-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2.5p5", + "ICSD oxidation states": [ + 5, + -1 + ], + "Ionic radii": { + "-1": 2.06, + "5": 1.09, + "7": 0.67 + }, + "Liquid range": "70.55 K", + "Melting point": "386.85 K", + "Mendeleev no": 97, + "Mineral hardness": "no data", + "Molar volume": "25.72 cm3", + "Name": "Iodine", + "Oxidation states": [ + -1, + 1, + 3, + 5, + 7 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-1": { + "VI": { + "": { + "crystal_radius": 2.06, + "ionic_radius": 2.2 + } + } + }, + "5": { + "IIIPY": { + "": { + "crystal_radius": 0.58, + "ionic_radius": 0.44 + } + }, + "VI": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.56, + "ionic_radius": 0.42 + } + }, + "VI": { + "": { + "crystal_radius": 0.67, + "ionic_radius": 0.53 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.449 W m-1 K-1", + "Van der waals radius": 1.98, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.66, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "I-127": -696.12, + "I-129": -604.1 + } + }, + "In": { + "Atomic mass": 114.818, + "Atomic no": 49, + "Atomic orbitals": { + "1s": -983.647445, + "2p": -134.628845, + "2s": -144.078357, + "3d": -16.139823, + "3p": -23.345778, + "3s": -27.2206, + "4d": -0.730481, + "4p": -2.795832, + "4s": -4.062639, + "5p": -0.101782, + "5s": -0.290497 + }, + "Atomic radius": 1.55, + "Atomic radius calculated": 1.56, + "Boiling point": "2345 K", + "Brinell hardness": "8.83 MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "32.1 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "7310 kg m-3", + "Electrical resistivity": "8 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2.5p1", + "ICSD oxidation states": [ + 1, + 2, + 3 + ], + "Ionic radii": { + "3": 0.94 + }, + "Liquid range": "1915.25 K", + "Melting point": "429.75 K", + "Mendeleev no": 79, + "Mineral hardness": "1.2", + "Molar volume": "15.76 cm3", + "Name": "Indium", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "IV": { + "": { + "crystal_radius": 0.76, + "ionic_radius": 0.62 + } + }, + "VI": { + "": { + "crystal_radius": 0.94, + "ionic_radius": 0.8 + } + }, + "VIII": { + "": { + "crystal_radius": 1.06, + "ionic_radius": 0.92 + } + } + } + }, + "Superconduction temperature": "3.41 K", + "Thermal conductivity": "82 W m-1 K-1", + "Van der waals radius": 1.93, + "Velocity of sound": "1215 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.78, + "Youngs modulus": "11 GPa", + "NMR Quadrupole Moment": { + "In-113": 759.8, + "In-115": 770.8 + } + }, + "Ir": { + "Atomic mass": 192.217, + "Atomic no": 77, + "Atomic orbitals": { + "1s": -2543.761342, + "2p": -405.526834, + "2s": -422.159424, + "3d": -75.485027, + "3p": -90.108427, + "3s": -97.923081, + "4d": -10.856593, + "4f": -2.738339, + "4p": -16.966578, + "4s": -20.29429, + "5d": -0.335189, + "5p": -1.883349, + "5s": -2.909174, + "6s": -0.195511 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.8, + "Boiling point": "4701 K", + "Brinell hardness": "1670 MN m-2", + "Bulk modulus": "320 GPa", + "Coefficient of linear thermal expansion": "6.4 x10-6K-1", + "Common oxidation states": [ + 3, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "22650 kg m-3", + "Electrical resistivity": "4.7 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d7.6s2", + "ICSD oxidation states": [ + 3, + 4, + 5 + ], + "Ionic radii": { + "3": 0.82, + "4": 0.765, + "5": 0.71 + }, + "Liquid range": "1962 K", + "Melting point": "2739 K", + "Mendeleev no": 66, + "Mineral hardness": "6.5", + "Molar volume": "8.52 cm3", + "Name": "Iridium", + "Oxidation states": [ + -3, + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.26", + "Reflectivity": "78 %", + "Refractive index": "no data", + "Rigidity modulus": "210 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.82, + "ionic_radius": 0.68 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.765, + "ionic_radius": 0.625 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + } + } + }, + "Superconduction temperature": "0.11 K", + "Thermal conductivity": "150 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4825 m s-1", + "Vickers hardness": "1760 MN m-2", + "X": 2.2, + "Youngs modulus": "528 GPa" + }, + "K": { + "Atomic mass": 39.0983, + "Atomic no": 19, + "Atomic orbitals": { + "1s": -128.414957, + "2p": -10.283851, + "2s": -12.839001, + "3p": -0.693776, + "3s": -1.281897, + "4s": -0.088815 + }, + "Atomic radius": 2.2, + "Atomic radius calculated": 2.43, + "Boiling point": "1032 K", + "Brinell hardness": "0.363 MN m-2", + "Bulk modulus": "3.1 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "2223 K", + "Density of solid": "856 kg m-3", + "Electrical resistivity": "7.5 10-8 Ω m", + "Electronic structure": "[Ar].4s1", + "ICSD oxidation states": [ + 1 + ], + "Ionic radii": { + "1": 1.52 + }, + "Liquid range": "695.47 K", + "Melting point": "336.53 K", + "Mendeleev no": 10, + "Mineral hardness": "0.4", + "Molar volume": "45.94 cm3", + "Name": "Potassium", + "Oxidation states": [ + -1, + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "1.3 GPa", + "Shannon radii": { + "1": { + "IV": { + "": { + "crystal_radius": 1.51, + "ionic_radius": 1.37 + } + }, + "VI": { + "": { + "crystal_radius": 1.52, + "ionic_radius": 1.38 + } + }, + "VII": { + "": { + "crystal_radius": 1.6, + "ionic_radius": 1.46 + } + }, + "VIII": { + "": { + "crystal_radius": 1.65, + "ionic_radius": 1.51 + } + }, + "IX": { + "": { + "crystal_radius": 1.69, + "ionic_radius": 1.55 + } + }, + "X": { + "": { + "crystal_radius": 1.73, + "ionic_radius": 1.59 + } + }, + "XII": { + "": { + "crystal_radius": 1.78, + "ionic_radius": 1.64 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "100 W m-1 K-1", + "Van der waals radius": 2.75, + "Velocity of sound": "2000 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.82, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "K-39": 58.5, + "K-40": -73.0, + "K-41": 71.1 + } + }, + "Kr": { + "Atomic mass": 83.798, + "Atomic no": 36, + "Atomic orbitals": { + "1s": -509.982989, + "2p": -60.017328, + "2s": -66.285953, + "3d": -3.074109, + "3p": -7.086634, + "3s": -9.315192, + "4p": -0.34634, + "4s": -0.820574 + }, + "Atomic radius": "no data", + "Atomic radius calculated": 0.88, + "Boiling point": "119.93 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Critical temperature": "209.4 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2.4p6", + "Liquid range": "4.14 K", + "Max oxidation state": 0.0, + "Melting point": "115.79 K", + "Mendeleev no": 4, + "Min oxidation state": 0.0, + "Mineral hardness": "no data", + "Molar volume": "27.99 cm3", + "Name": "Krypton", + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000427", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.00943 W m-1 K-1", + "Van der waals radius": 2.02, + "Velocity of sound": "1120 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 3.0, + "Youngs modulus": "no data GPa" + }, + "La": { + "Atomic mass": 138.90547, + "Atomic no": 57, + "Atomic orbitals": { + "1s": -1355.622446, + "2p": -198.325243, + "2s": -209.831151, + "3d": -30.626696, + "3p": -39.895838, + "3s": -44.856283, + "4d": -3.95801, + "4p": -7.167724, + "4s": -9.000543, + "5d": -0.141085, + "5p": -0.824498, + "5s": -1.324936, + "6s": -0.132233 + }, + "Atomic radius": 1.95, + "Atomic radius calculated": "no data", + "Boiling point": "3743 K", + "Brinell hardness": "363 MN m-2", + "Bulk modulus": "28 GPa", + "Coefficient of linear thermal expansion": "12.1 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "6146 kg m-3", + "Electrical resistivity": "61.5 10-8 Ω m", + "Electronic structure": "[Xe].5d1.6s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "3": 1.172 + }, + "Liquid range": "2550 K", + "Melting point": "1193 K", + "Mendeleev no": 33, + "Mineral hardness": "2.5", + "Molar volume": "22.39 cm3", + "Name": "Lanthanum", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.28", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "14 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.172, + "ionic_radius": 1.032 + } + }, + "VII": { + "": { + "crystal_radius": 1.24, + "ionic_radius": 1.1 + } + }, + "VIII": { + "": { + "crystal_radius": 1.3, + "ionic_radius": 1.16 + } + }, + "IX": { + "": { + "crystal_radius": 1.356, + "ionic_radius": 1.216 + } + }, + "X": { + "": { + "crystal_radius": 1.41, + "ionic_radius": 1.27 + } + }, + "XII": { + "": { + "crystal_radius": 1.5, + "ionic_radius": 1.36 + } + } + } + }, + "Superconduction temperature": "6.00 K", + "Thermal conductivity": "13 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2475 m s-1", + "Vickers hardness": "491 MN m-2", + "X": 1.1, + "Youngs modulus": "37 GPa", + "NMR Quadrupole Moment": { + "La-139": 200.6 + } + }, + "Li": { + "Atomic mass": 6.941, + "Atomic no": 3, + "Atomic orbitals": { + "1s": -1.878564, + "2s": -0.10554 + }, + "Atomic radius": 1.45, + "Atomic radius calculated": 1.67, + "Boiling point": "1615 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "11 GPa", + "Coefficient of linear thermal expansion": "46 x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "3223 K", + "Density of solid": "535 kg m-3", + "Electrical resistivity": "9.5 10-8 Ω m", + "Electronic structure": "[He].2s1", + "ICSD oxidation states": [ + 1 + ], + "Ionic radii": { + "1": 0.9 + }, + "Liquid range": "1161.31 K", + "Melting point": "453.69 K", + "Mendeleev no": 12, + "Mineral hardness": "0.6", + "Molar volume": "13.02 cm3", + "Name": "Lithium", + "Oxidation states": [ + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "4.2 GPa", + "Shannon radii": { + "1": { + "IV": { + "": { + "crystal_radius": 0.73, + "ionic_radius": 0.59 + } + }, + "VI": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + }, + "VIII": { + "": { + "crystal_radius": 1.06, + "ionic_radius": 0.92 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "85 W m-1 K-1", + "Van der waals radius": 1.82, + "Velocity of sound": "6000 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.98, + "Youngs modulus": "4.9 GPa", + "NMR Quadrupole Moment": { + "Li-6": -0.808, + "Li-7": -40.1 + } + }, + "Lr": { + "Atomic mass": 262.0, + "Atomic no": 103, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f14.7s2.7p1 (tentative)", + "Liquid range": "no data K", + "Melting point": "about 1900 K", + "Mendeleev no": 34, + "Mineral hardness": "no data", + "Molar volume": "no data cm3", + "Name": "Lawrencium", + "Oxidation states": [ + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Lu": { + "Atomic mass": 174.967, + "Atomic no": 71, + "Atomic orbitals": { + "1s": -2146.885351, + "2p": -334.330902, + "2s": -349.390492, + "3d": -58.592982, + "3p": -71.538779, + "3s": -78.462398, + "4d": -7.113364, + "4f": -0.568096, + "4p": -12.250904, + "4s": -15.08337, + "5d": -0.103686, + "5p": -1.111991, + "5s": -1.872086, + "6s": -0.155112 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": 2.17, + "Boiling point": "3675 K", + "Brinell hardness": "893 MN m-2", + "Bulk modulus": "48 GPa", + "Coefficient of linear thermal expansion": "9.9 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "9841 kg m-3", + "Electrical resistivity": "58 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d1.6s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "3": 1.001 + }, + "Liquid range": "1750 K", + "Melting point": "1925 K", + "Mendeleev no": 20, + "Mineral hardness": "no data", + "Molar volume": "17.78 cm3", + "Name": "Lutetium", + "Oxidation states": [ + 3 + ], + "Poissons ratio": "0.26", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "27 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.001, + "ionic_radius": 0.861 + } + }, + "VIII": { + "": { + "crystal_radius": 1.117, + "ionic_radius": 0.977 + } + }, + "IX": { + "": { + "crystal_radius": 1.172, + "ionic_radius": 1.032 + } + } + } + }, + "Superconduction temperature": "0.022 K", + "Thermal conductivity": "16 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "1160 MN m-2", + "X": 1.27, + "Youngs modulus": "69 GPa" + }, + "Md": { + "Atomic mass": 258.0, + "Atomic no": 101, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f13.7s2", + "Liquid range": "no data K", + "Melting point": "about 1100 K", + "Mendeleev no": 36, + "Mineral hardness": "no data", + "Molar volume": "no data cm3", + "Name": "Mendelevium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Mg": { + "Atomic mass": 24.305, + "Atomic no": 12, + "Atomic orbitals": { + "1s": -45.973167, + "2p": -1.71897, + "2s": -2.903746, + "3s": -0.175427 + }, + "Atomic radius": 1.5, + "Atomic radius calculated": 1.45, + "Boiling point": "1363 K", + "Brinell hardness": "260 MN m-2", + "Bulk modulus": "45 GPa", + "Coefficient of linear thermal expansion": "8.2 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "1738 kg m-3", + "Electrical resistivity": "4.4 10-8 Ω m", + "Electronic structure": "[Ne].3s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 0.86 + }, + "Liquid range": "440 K", + "Melting point": "923 K", + "Mendeleev no": 73, + "Mineral hardness": "2.5", + "Molar volume": "14.00 cm3", + "Name": "Magnesium", + "Oxidation states": [ + 1, + 2 + ], + "Poissons ratio": "0.29", + "Reflectivity": "74 %", + "Refractive index": "no data", + "Rigidity modulus": "17 GPa", + "Shannon radii": { + "2": { + "IV": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + }, + "V": { + "": { + "crystal_radius": 0.8, + "ionic_radius": 0.66 + } + }, + "VI": { + "": { + "crystal_radius": 0.86, + "ionic_radius": 0.72 + } + }, + "VIII": { + "": { + "crystal_radius": 1.03, + "ionic_radius": 0.89 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "160 W m-1 K-1", + "Van der waals radius": 1.73, + "Velocity of sound": "4602 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.31, + "Youngs modulus": "45 GPa", + "NMR Quadrupole Moment": { + "Mg-25": 199.4 + } + }, + "Mn": { + "Atomic mass": 54.938045, + "Atomic no": 25, + "Atomic orbitals": { + "1s": -233.696912, + "2p": -23.066297, + "2s": -26.866646, + "3d": -0.26654, + "3p": -1.99145, + "3s": -3.076637, + "4s": -0.191136 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.61, + "Boiling point": "2334 K", + "Brinell hardness": "196 MN m-2", + "Bulk modulus": "120 GPa", + "Coefficient of linear thermal expansion": "21.7 x10-6K-1", + "Common oxidation states": [ + 2, + 4, + 7 + ], + "Critical temperature": "no data K", + "Density of solid": "7470 kg m-3", + "Electrical resistivity": "144 10-8 Ω m", + "Electronic structure": "[Ar].3d5.4s2", + "ICSD oxidation states": [ + 2, + 3, + 4, + 7 + ], + "Ionic radii": { + "2": 0.97, + "3": 0.785, + "4": 0.67, + "5": 0.47, + "6": 0.395, + "7": 0.6 + }, + "Ionic radii hs": { + "2": 0.97, + "3": 0.785 + }, + "Ionic radii ls": { + "2": 0.81, + "3": 0.72, + "4": 0.67, + "5": 0.47, + "6": 0.395, + "7": 0.6 + }, + "Liquid range": "815 K", + "Melting point": "1519 K", + "Mendeleev no": 60, + "Mineral hardness": "6.0", + "Molar volume": "7.35 cm3", + "Name": "Manganese", + "Oxidation states": [ + -3, + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "2": { + "IV": { + "High Spin": { + "crystal_radius": 0.8, + "ionic_radius": 0.66 + } + }, + "V": { + "High Spin": { + "crystal_radius": 0.89, + "ionic_radius": 0.75 + } + }, + "VI": { + "Low Spin": { + "crystal_radius": 0.81, + "ionic_radius": 0.67 + }, + "High Spin": { + "crystal_radius": 0.97, + "ionic_radius": 0.83 + } + }, + "VII": { + "High Spin": { + "crystal_radius": 1.04, + "ionic_radius": 0.9 + } + }, + "VIII": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + } + }, + "3": { + "V": { + "": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + }, + "VI": { + "Low Spin": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + }, + "High Spin": { + "crystal_radius": 0.785, + "ionic_radius": 0.645 + } + } + }, + "4": { + "IV": { + "": { + "crystal_radius": 0.53, + "ionic_radius": 0.39 + } + }, + "VI": { + "": { + "crystal_radius": 0.67, + "ionic_radius": 0.53 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.47, + "ionic_radius": 0.33 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.395, + "ionic_radius": 0.255 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.39, + "ionic_radius": 0.25 + } + }, + "VI": { + "": { + "crystal_radius": 0.6, + "ionic_radius": 0.46 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "7.8 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "5150 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.55, + "Youngs modulus": "198 GPa", + "NMR Quadrupole Moment": { + "Mn-55": 330.1 + } + }, + "Mo": { + "Atomic mass": 95.94, + "Atomic no": 42, + "Atomic orbitals": { + "1s": -709.232119, + "2p": -90.791541, + "2s": -98.503638, + "3d": -8.257721, + "3p": -13.71481, + "3s": -16.681545, + "4d": -0.153347, + "4p": -1.39005, + "4s": -2.234824, + "5s": -0.14788 + }, + "Atomic radius": 1.45, + "Atomic radius calculated": 1.9, + "Boiling point": "4912 K", + "Brinell hardness": "1500 MN m-2", + "Bulk modulus": "230 GPa", + "Coefficient of linear thermal expansion": "4.8 x10-6K-1", + "Common oxidation states": [ + 4, + 6 + ], + "Critical temperature": "no data K", + "Density of solid": "10280 kg m-3", + "Electrical resistivity": "5.5 10-8 Ω m", + "Electronic structure": "[Kr].4d5.5s1", + "ICSD oxidation states": [ + 2, + 3, + 4, + 5, + 6 + ], + "Ionic radii": { + "3": 0.83, + "4": 0.79, + "5": 0.75, + "6": 0.73 + }, + "Liquid range": "2016 K", + "Melting point": "2896 K", + "Mendeleev no": 56, + "Mineral hardness": "5.5", + "Molar volume": "9.38 cm3", + "Name": "Molybdenum", + "Oxidation states": [ + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.31", + "Reflectivity": "58 %", + "Refractive index": "no data", + "Rigidity modulus": "20 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.83, + "ionic_radius": 0.69 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.79, + "ionic_radius": 0.65 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.6, + "ionic_radius": 0.46 + } + }, + "VI": { + "": { + "crystal_radius": 0.75, + "ionic_radius": 0.61 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.55, + "ionic_radius": 0.41 + } + }, + "V": { + "": { + "crystal_radius": 0.64, + "ionic_radius": 0.5 + } + }, + "VI": { + "": { + "crystal_radius": 0.73, + "ionic_radius": 0.59 + } + }, + "VII": { + "": { + "crystal_radius": 0.87, + "ionic_radius": 0.73 + } + } + } + }, + "Superconduction temperature": "0.915 K", + "Thermal conductivity": "139 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "6190 m s-1", + "Vickers hardness": "1530 MN m-2", + "X": 2.16, + "Youngs modulus": "329 GPa" + }, + "N": { + "Atomic mass": 14.0067, + "Atomic no": 7, + "Atomic orbitals": { + "1s": -14.011501, + "2p": -0.266297, + "2s": -0.676151 + }, + "Atomic radius": 0.65, + "Atomic radius calculated": 0.56, + "Boiling point": "77.36 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -3, + 3, + 5 + ], + "Critical temperature": "126.2 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[He].2s2.2p3", + "ICSD oxidation states": [ + 1, + 3, + 5, + -1, + -3, + -2 + ], + "Ionic radii": { + "-3": 1.32, + "3": 0.3, + "5": 0.27 + }, + "Liquid range": "14.31 K", + "Melting point": "63.05 K", + "Mendeleev no": 100, + "Mineral hardness": "no data", + "Molar volume": "13.54 cm3", + "Name": "Nitrogen", + "Oxidation states": [ + -3, + -2, + -1, + 1, + 2, + 3, + 4, + 5 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000298 (gas; liquid 1.197)(no units)", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-3": { + "IV": { + "": { + "crystal_radius": 1.32, + "ionic_radius": 1.46 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 0.3, + "ionic_radius": 0.16 + } + } + }, + "5": { + "III": { + "": { + "crystal_radius": 0.044, + "ionic_radius": -0.104 + } + }, + "VI": { + "": { + "crystal_radius": 0.27, + "ionic_radius": 0.13 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.02583 W m-1 K-1", + "Van der waals radius": 1.55, + "Velocity of sound": "333.6 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 3.04, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "N-14": 20.44 + } + }, + "Na": { + "Atomic mass": 22.98976928, + "Atomic no": 11, + "Atomic orbitals": { + "1s": -37.719975, + "2p": -1.060636, + "2s": -2.063401, + "3s": -0.103415 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": 1.9, + "Boiling point": "1156 K", + "Brinell hardness": "0.69 MN m-2", + "Bulk modulus": "6.3 GPa", + "Coefficient of linear thermal expansion": "71 x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "2573 K", + "Density of solid": "968 kg m-3", + "Electrical resistivity": "4.9 10-8 Ω m", + "Electronic structure": "[Ne].3s1", + "ICSD oxidation states": [ + 1 + ], + "Ionic radii": { + "1": 1.16 + }, + "Liquid range": "785.13 K", + "Melting point": "370.87 K", + "Mendeleev no": 11, + "Mineral hardness": "0.5", + "Molar volume": "23.78 cm3", + "Name": "Sodium", + "Oxidation states": [ + -1, + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "3.3 GPa", + "Shannon radii": { + "1": { + "IV": { + "": { + "crystal_radius": 1.13, + "ionic_radius": 0.99 + } + }, + "V": { + "": { + "crystal_radius": 1.14, + "ionic_radius": 1.0 + } + }, + "VI": { + "": { + "crystal_radius": 1.16, + "ionic_radius": 1.02 + } + }, + "VII": { + "": { + "crystal_radius": 1.26, + "ionic_radius": 1.12 + } + }, + "VIII": { + "": { + "crystal_radius": 1.32, + "ionic_radius": 1.18 + } + }, + "IX": { + "": { + "crystal_radius": 1.38, + "ionic_radius": 1.24 + } + }, + "XII": { + "": { + "crystal_radius": 1.53, + "ionic_radius": 1.39 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "140 W m-1 K-1", + "Van der waals radius": 2.27, + "Velocity of sound": "3200 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.93, + "Youngs modulus": "10 GPa", + "NMR Quadrupole Moment": { + "Na-23": 104.1 + } + }, + "Nb": { + "Atomic mass": 92.90638, + "Atomic no": 41, + "Atomic orbitals": { + "1s": -673.76253, + "2p": -85.272175, + "2s": -92.74086, + "3d": -7.339839, + "3p": -12.552855, + "3s": -15.393727, + "4d": -0.125252, + "4p": -1.250049, + "4s": -2.036693, + "5s": -0.144272 + }, + "Atomic radius": 1.45, + "Atomic radius calculated": 1.98, + "Boiling point": "5017 K", + "Brinell hardness": "736 MN m-2", + "Bulk modulus": "170 GPa", + "Coefficient of linear thermal expansion": "7.3 x10-6K-1", + "Common oxidation states": [ + 5 + ], + "Critical temperature": "no data K", + "Density of solid": "8570 kg m-3", + "Electrical resistivity": "15.2 10-8 Ω m", + "Electronic structure": "[Kr].4d4.5s1", + "ICSD oxidation states": [ + 2, + 3, + 4, + 5 + ], + "Ionic radii": { + "3": 0.86, + "4": 0.82, + "5": 0.78 + }, + "Liquid range": "2267 K", + "Melting point": "2750 K", + "Mendeleev no": 53, + "Mineral hardness": "6.0", + "Molar volume": "10.83 cm3", + "Name": "Niobium", + "Oxidation states": [ + -1, + 2, + 3, + 4, + 5 + ], + "Poissons ratio": "0.40", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "38 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.86, + "ionic_radius": 0.72 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.82, + "ionic_radius": 0.68 + } + }, + "VIII": { + "": { + "crystal_radius": 0.93, + "ionic_radius": 0.79 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.62, + "ionic_radius": 0.48 + } + }, + "VI": { + "": { + "crystal_radius": 0.78, + "ionic_radius": 0.64 + } + }, + "VII": { + "": { + "crystal_radius": 0.83, + "ionic_radius": 0.69 + } + }, + "VIII": { + "": { + "crystal_radius": 0.88, + "ionic_radius": 0.74 + } + } + } + }, + "Superconduction temperature": "9.25 K", + "Thermal conductivity": "54 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "3480 m s-1", + "Vickers hardness": "1320 MN m-2", + "X": 1.6, + "Youngs modulus": "105 GPa" + }, + "Nd": { + "Atomic mass": 144.242, + "Atomic no": 60, + "Atomic orbitals": { + "1s": -1509.698955, + "2p": -224.351816, + "2s": -236.613572, + "3d": -35.754515, + "3p": -45.791219, + "3s": -51.161263, + "4d": -4.377027, + "4f": -0.179508, + "4p": -7.96782, + "4s": -10.000891, + "5p": -0.798503, + "5s": -1.334934, + "6s": -0.125796 + }, + "Atomic radius": 1.85, + "Atomic radius calculated": 2.06, + "Boiling point": "3373 K", + "Brinell hardness": "265 MN m-2", + "Bulk modulus": "32 GPa", + "Coefficient of linear thermal expansion": "9.6 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "6800 kg m-3", + "Electrical resistivity": "64.3 10-8 Ω m", + "Electronic structure": "[Xe].4f4.6s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "2": 1.43, + "3": 1.123 + }, + "Liquid range": "2076 K", + "Melting point": "1297 K", + "Mendeleev no": 30, + "Mineral hardness": "no data", + "Molar volume": "20.59 cm3", + "Name": "Neodymium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.28", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "16 GPa", + "Shannon radii": { + "2": { + "VIII": { + "": { + "crystal_radius": 1.43, + "ionic_radius": 1.29 + } + }, + "IX": { + "": { + "crystal_radius": 1.49, + "ionic_radius": 1.35 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.123, + "ionic_radius": 0.983 + } + }, + "VIII": { + "": { + "crystal_radius": 1.249, + "ionic_radius": 1.109 + } + }, + "IX": { + "": { + "crystal_radius": 1.303, + "ionic_radius": 1.163 + } + }, + "XII": { + "": { + "crystal_radius": 1.41, + "ionic_radius": 1.27 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "17 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2330 m s-1", + "Vickers hardness": "343 MN m-2", + "X": 1.14, + "Youngs modulus": "41 GPa" + }, + "Ne": { + "Atomic mass": 20.1797, + "Atomic no": 10, + "Atomic orbitals": { + "1s": -30.305855, + "2p": -0.498034, + "2s": -1.322809 + }, + "Atomic radius": "no data", + "Atomic radius calculated": 0.38, + "Boiling point": "27.07 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Critical temperature": "44.4 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[He].2s2.2p6", + "Liquid range": "2.51 K", + "Max oxidation state": 0.0, + "Melting point": "24.56 K", + "Mendeleev no": 2, + "Min oxidation state": 0.0, + "Mineral hardness": "no data", + "Molar volume": "13.23 cm3", + "Name": "Neon", + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000067", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.0491 W m-1 K-1", + "Van der waals radius": 1.54, + "Velocity of sound": "936 m s-1", + "Vickers hardness": "no data MN m-2", + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "Ne-21": 101.55 + } + }, + "Ni": { + "Atomic mass": 58.6934, + "Atomic no": 28, + "Atomic orbitals": { + "1s": -297.870824, + "2p": -30.868027, + "2s": -35.312112, + "3d": -0.348699, + "3p": -2.594158, + "3s": -3.950717, + "4s": -0.210764 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.49, + "Boiling point": "3186 K", + "Brinell hardness": "700 MN m-2", + "Bulk modulus": "180 GPa", + "Coefficient of linear thermal expansion": "13.4 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "8908 kg m-3", + "Electrical resistivity": "7.2 10-8 Ω m", + "Electronic structure": "[Ar].3d8.4s2", + "ICSD oxidation states": [ + 1, + 2, + 3, + 4 + ], + "Ionic radii": { + "3": 0.74 + }, + "Ionic radii hs": { + "3": 0.74 + }, + "Ionic radii ls": { + "2": 0.83, + "3": 0.7, + "4": 0.62 + }, + "Liquid range": "1458 K", + "Melting point": "1728 K", + "Mendeleev no": 67, + "Mineral hardness": "4.0", + "Molar volume": "6.59 cm3", + "Name": "Nickel", + "Oxidation states": [ + -1, + 1, + 2, + 3, + 4 + ], + "Poissons ratio": "0.31", + "Reflectivity": "72 %", + "Refractive index": "no data", + "Rigidity modulus": "76 GPa", + "Shannon radii": { + "2": { + "IV": { + "": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + } + }, + "IVSQ": { + "": { + "crystal_radius": 0.63, + "ionic_radius": 0.49 + } + }, + "V": { + "": { + "crystal_radius": 0.77, + "ionic_radius": 0.63 + } + }, + "VI": { + "": { + "crystal_radius": 0.83, + "ionic_radius": 0.69 + } + } + }, + "3": { + "VI": { + "Low Spin": { + "crystal_radius": 0.7, + "ionic_radius": 0.56 + }, + "High Spin": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + } + }, + "4": { + "VI": { + "Low Spin": { + "crystal_radius": 0.62, + "ionic_radius": 0.48 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "91 W m-1 K-1", + "Van der waals radius": 1.63, + "Velocity of sound": "4970 m s-1", + "Vickers hardness": "638 MN m-2", + "X": 1.91, + "Youngs modulus": "200 GPa", + "NMR Quadrupole Moment": { + "Ni-61": 162.15 + } + }, + "No": { + "Atomic mass": 259.0, + "Atomic no": 102, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f14.7s2", + "Liquid range": "no data K", + "Melting point": "about 1100 K", + "Mendeleev no": 35, + "Mineral hardness": "no data", + "Molar volume": "no data cm3", + "Name": "Nobelium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.24, + "ionic_radius": 1.1 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Np": { + "Atomic mass": 237.0, + "Atomic no": 93, + "Atomic orbitals": "no data", + "Atomic radius": 1.75, + "Atomic radius calculated": "no data", + "Boiling point": "4273 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 5 + ], + "Critical temperature": "no data K", + "Density of solid": "20450 kg m-3", + "Electrical resistivity": "120 10-8 Ω m", + "Electronic structure": "[Rn].5f4.6d1.7s2", + "Ionic radii": { + "2": 1.24, + "3": 1.15, + "4": 1.01, + "5": 0.89, + "6": 0.86, + "7": 0.85 + }, + "Liquid range": "3363 K", + "Melting point": "910 K", + "Mendeleev no": 44, + "Mineral hardness": "no data", + "Molar volume": "11.59 cm3", + "Name": "Neptunium", + "Oxidation states": [ + 3, + 4, + 5, + 6, + 7 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.24, + "ionic_radius": 1.1 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.15, + "ionic_radius": 1.01 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 1.01, + "ionic_radius": 0.87 + } + }, + "VIII": { + "": { + "crystal_radius": 1.12, + "ionic_radius": 0.98 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.89, + "ionic_radius": 0.75 + } + } + }, + "6": { + "VI": { + "": { + "crystal_radius": 0.86, + "ionic_radius": 0.72 + } + } + }, + "7": { + "VI": { + "": { + "crystal_radius": 0.85, + "ionic_radius": 0.71 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "6 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.36, + "Youngs modulus": "no data GPa" + }, + "O": { + "Atomic mass": 15.9994, + "Atomic no": 8, + "Atomic orbitals": { + "1s": -18.758245, + "2p": -0.338381, + "2s": -0.871362 + }, + "Atomic radius": 0.6, + "Atomic radius calculated": 0.48, + "Boiling point": "90.2 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -2 + ], + "Critical temperature": "154.6 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[He].2s2.2p4", + "ICSD oxidation states": [ + -2 + ], + "Ionic radii": { + "-2": 1.26 + }, + "Liquid range": "35.4 K", + "Melting point": "54.8 K", + "Mendeleev no": 101, + "Mineral hardness": "no data", + "Molar volume": "17.36 cm3", + "Name": "Oxygen", + "Oxidation states": [ + -2, + -1, + 1, + 2 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000271 (gas; liquid 1.221)(no units)", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-2": { + "II": { + "": { + "crystal_radius": 1.21, + "ionic_radius": 1.35 + } + }, + "III": { + "": { + "crystal_radius": 1.22, + "ionic_radius": 1.36 + } + }, + "IV": { + "": { + "crystal_radius": 1.24, + "ionic_radius": 1.38 + } + }, + "VI": { + "": { + "crystal_radius": 1.26, + "ionic_radius": 1.4 + } + }, + "VIII": { + "": { + "crystal_radius": 1.28, + "ionic_radius": 1.42 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.02658 W m-1 K-1", + "Van der waals radius": 1.52, + "Velocity of sound": "317.5 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 3.44, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "O-17": -25.58 + } + }, + "Os": { + "Atomic mass": 190.23, + "Atomic no": 76, + "Atomic orbitals": { + "1s": -2475.238617, + "2p": -393.15408, + "2s": -409.522396, + "3d": -72.497183, + "3p": -86.837047, + "3s": -94.501324, + "4d": -10.176082, + "4f": -2.321175, + "4p": -16.119671, + "4s": -19.362527, + "5d": -0.296791, + "5p": -1.757404, + "5s": -2.738293, + "6s": -0.191489 + }, + "Atomic radius": 1.3, + "Atomic radius calculated": 1.85, + "Boiling point": "5285 K", + "Brinell hardness": "3920 MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "5.1 x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "22610 kg m-3", + "Electrical resistivity": "8.1 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d6.6s2", + "Ionic radii": { + "4": 0.77, + "5": 0.715, + "6": 0.685, + "7": 0.665, + "8": 0.53 + }, + "Liquid range": "1979 K", + "Melting point": "3306 K", + "Mendeleev no": 63, + "Mineral hardness": "7.0", + "Molar volume": "8.42 cm3", + "Name": "Osmium", + "Oxidation states": [ + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "Poissons ratio": "0.25", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "222 GPa", + "Shannon radii": { + "4": { + "VI": { + "": { + "crystal_radius": 0.77, + "ionic_radius": 0.63 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.715, + "ionic_radius": 0.575 + } + } + }, + "6": { + "V": { + "": { + "crystal_radius": 0.63, + "ionic_radius": 0.49 + } + }, + "VI": { + "": { + "crystal_radius": 0.685, + "ionic_radius": 0.545 + } + } + }, + "7": { + "VI": { + "": { + "crystal_radius": 0.665, + "ionic_radius": 0.525 + } + } + }, + "8": { + "IV": { + "": { + "crystal_radius": 0.53, + "ionic_radius": 0.39 + } + } + } + }, + "Superconduction temperature": "0.66 K", + "Thermal conductivity": "88 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4940 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.2, + "Youngs modulus": "no data GPa" + }, + "P": { + "Atomic mass": 30.973762, + "Atomic no": 15, + "Atomic orbitals": { + "1s": -76.061897, + "2p": -4.576617, + "2s": -6.329346, + "3p": -0.20608, + "3s": -0.512364 + }, + "Atomic radius": 1.0, + "Atomic radius calculated": 0.98, + "Boiling point": "550 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "11 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -3, + 3, + 5 + ], + "Critical temperature": "994 K", + "Density of solid": "1823 kg m-3", + "Electrical resistivity": "about 10 10-8 Ω m", + "Electronic structure": "[Ne].3s2.3p3", + "ICSD oxidation states": [ + 3, + 4, + 5, + -2, + -3, + -1 + ], + "Ionic radii": { + "3": 0.58, + "5": 0.52 + }, + "Liquid range": "232.7 K", + "Melting point": "(white P) 317.3 K", + "Mendeleev no": 90, + "Mineral hardness": "no data", + "Molar volume": "17.02 cm3", + "Name": "Phosphorus", + "Oxidation states": [ + -3, + -2, + -1, + 1, + 2, + 3, + 4, + 5 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.001212", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.58, + "ionic_radius": 0.44 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.31, + "ionic_radius": 0.17 + } + }, + "V": { + "": { + "crystal_radius": 0.43, + "ionic_radius": 0.29 + } + }, + "VI": { + "": { + "crystal_radius": 0.52, + "ionic_radius": 0.38 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.236 W m-1 K-1", + "Van der waals radius": 1.8, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.19, + "Youngs modulus": "no data GPa" + }, + "Pa": { + "Atomic mass": 231.03588, + "Atomic no": 91, + "Atomic orbitals": { + "1s": -3606.333629, + "2p": -603.470278, + "2s": -623.870431, + "3d": -127.781168, + "3p": -146.485678, + "3s": -156.466742, + "4d": -25.933121, + "4f": -14.105747, + "4p": -34.48293, + "4s": -39.064507, + "5d": -3.659928, + "5f": -0.316813, + "5p": -6.709821, + "5s": -8.463463, + "6d": -0.142481, + "6p": -0.799756, + "6s": -1.287232, + "7s": -0.129653 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 5 + ], + "Critical temperature": "no data K", + "Density of solid": "15370 kg m-3", + "Electrical resistivity": "18 10-8 Ω m", + "Electronic structure": "[Rn].5f2.6d1.7s2", + "Ionic radii": { + "3": 1.16, + "4": 1.04, + "5": 0.92 + }, + "Liquid range": "no data K", + "Melting point": "1841 K", + "Mendeleev no": 46, + "Mineral hardness": "no data", + "Molar volume": "15.18 cm3", + "Name": "Protactinium", + "Oxidation states": [ + 3, + 4, + 5 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.18, + "ionic_radius": 1.04 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 1.04, + "ionic_radius": 0.9 + } + }, + "VIII": { + "": { + "crystal_radius": 1.15, + "ionic_radius": 1.01 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.92, + "ionic_radius": 0.78 + } + }, + "VIII": { + "": { + "crystal_radius": 1.05, + "ionic_radius": 0.91 + } + }, + "IX": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + } + } + }, + "Superconduction temperature": "1.4 K", + "Thermal conductivity": "47 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.5, + "Youngs modulus": "no data GPa" + }, + "Pb": { + "Atomic mass": 207.2, + "Atomic no": 82, + "Atomic orbitals": { + "1s": -2901.078061, + "2p": -470.877785, + "2s": -488.843335, + "3d": -91.889924, + "3p": -107.950391, + "3s": -116.526852, + "4d": -15.030026, + "4f": -5.592532, + "4p": -21.990564, + "4s": -25.75333, + "5d": -0.902393, + "5p": -2.941657, + "5s": -4.206797, + "6p": -0.141831, + "6s": -0.357187 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": 1.54, + "Boiling point": "2022 K", + "Brinell hardness": "38.3 MN m-2", + "Bulk modulus": "46 GPa", + "Coefficient of linear thermal expansion": "28.9 x10-6K-1", + "Common oxidation states": [ + 2, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "11340 kg m-3", + "Electrical resistivity": "21 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2.6p2", + "ICSD oxidation states": [ + 2, + 4 + ], + "Ionic radii": { + "2": 1.33, + "4": 0.915 + }, + "Liquid range": "1421.39 K", + "Melting point": "600.61 K", + "Mendeleev no": 82, + "Mineral hardness": "1.5", + "Molar volume": "18.26 cm3", + "Name": "Lead", + "Oxidation states": [ + -4, + 2, + 4 + ], + "Poissons ratio": "0.44", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "5.6 GPa", + "Shannon radii": { + "2": { + "IVPY": { + "": { + "crystal_radius": 1.12, + "ionic_radius": 0.98 + } + }, + "VI": { + "": { + "crystal_radius": 1.33, + "ionic_radius": 1.19 + } + }, + "VII": { + "": { + "crystal_radius": 1.37, + "ionic_radius": 1.23 + } + }, + "VIII": { + "": { + "crystal_radius": 1.43, + "ionic_radius": 1.29 + } + }, + "IX": { + "": { + "crystal_radius": 1.49, + "ionic_radius": 1.35 + } + }, + "X": { + "": { + "crystal_radius": 1.54, + "ionic_radius": 1.4 + } + }, + "XI": { + "": { + "crystal_radius": 1.59, + "ionic_radius": 1.45 + } + }, + "XII": { + "": { + "crystal_radius": 1.63, + "ionic_radius": 1.49 + } + } + }, + "4": { + "IV": { + "": { + "crystal_radius": 0.79, + "ionic_radius": 0.65 + } + }, + "V": { + "": { + "crystal_radius": 0.87, + "ionic_radius": 0.73 + } + }, + "VI": { + "": { + "crystal_radius": 0.915, + "ionic_radius": 0.775 + } + }, + "VIII": { + "": { + "crystal_radius": 1.08, + "ionic_radius": 0.94 + } + } + } + }, + "Superconduction temperature": "7.2 K", + "Thermal conductivity": "35 W m-1 K-1", + "Van der waals radius": 2.02, + "Velocity of sound": "1260 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.33, + "Youngs modulus": "16 GPa" + }, + "Pd": { + "Atomic mass": 106.42, + "Atomic no": 46, + "Atomic orbitals": { + "1s": -860.134909, + "2p": -114.408286, + "2s": -123.105078, + "3d": -12.132197, + "3p": -18.580798, + "3s": -22.060898, + "4d": -0.160771, + "4p": -1.815215, + "4s": -2.889173 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.69, + "Boiling point": "3236 K", + "Brinell hardness": "37.3 MN m-2", + "Bulk modulus": "180 GPa", + "Coefficient of linear thermal expansion": "11.8 x10-6K-1", + "Common oxidation states": [ + 2, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "12023 kg m-3", + "Electrical resistivity": "10.8 10-8 Ω m", + "Electronic structure": "[Kr].4d10", + "ICSD oxidation states": [ + 2, + 4 + ], + "Ionic radii": { + "1": 0.73, + "2": 1.0, + "3": 0.9, + "4": 0.755 + }, + "Liquid range": "1407.95 K", + "Melting point": "1828.05 K", + "Mendeleev no": 69, + "Mineral hardness": "4.75", + "Molar volume": "8.56 cm3", + "Name": "Palladium", + "Oxidation states": [ + 2, + 4 + ], + "Poissons ratio": "0.39", + "Reflectivity": "72 %", + "Refractive index": "no data", + "Rigidity modulus": "44 GPa", + "Shannon radii": { + "1": { + "II": { + "": { + "crystal_radius": 0.73, + "ionic_radius": 0.59 + } + } + }, + "2": { + "IVSQ": { + "": { + "crystal_radius": 0.78, + "ionic_radius": 0.64 + } + }, + "VI": { + "": { + "crystal_radius": 1.0, + "ionic_radius": 0.86 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.755, + "ionic_radius": 0.615 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "72 W m-1 K-1", + "Van der waals radius": 1.63, + "Velocity of sound": "3070 m s-1", + "Vickers hardness": "461 MN m-2", + "X": 2.2, + "Youngs modulus": "121 GPa" + }, + "Pm": { + "Atomic mass": 145.0, + "Atomic no": 61, + "Atomic orbitals": { + "1s": -1562.980284, + "2p": -233.455114, + "2s": -245.970548, + "3d": -37.625433, + "3p": -47.921132, + "3s": -53.429311, + "4d": -4.596822, + "4f": -0.200159, + "4p": -8.320495, + "4s": -10.422756, + "5p": -0.817702, + "5s": -1.372265, + "6s": -0.127053 + }, + "Atomic radius": 1.85, + "Atomic radius calculated": 2.05, + "Boiling point": "3273 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "33 GPa", + "Coefficient of linear thermal expansion": "11 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "7264 kg m-3", + "Electrical resistivity": "about 75 10-8 Ω m", + "Electronic structure": "[Xe].4f5.6s2", + "Ionic radii": { + "3": 1.11 + }, + "Liquid range": "1900 K", + "Melting point": "1373 K", + "Mendeleev no": 29, + "Mineral hardness": "no data", + "Molar volume": "20.23 cm3", + "Name": "Promethium", + "Oxidation states": [ + 3 + ], + "Poissons ratio": "0.28", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "18 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.11, + "ionic_radius": 0.97 + } + }, + "VIII": { + "": { + "crystal_radius": 1.233, + "ionic_radius": 1.093 + } + }, + "IX": { + "": { + "crystal_radius": 1.284, + "ionic_radius": 1.144 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "15 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.13, + "Youngs modulus": "46 GPa" + }, + "Po": { + "Atomic mass": 210.0, + "Atomic no": 84, + "Atomic orbitals": { + "1s": -3050.988417, + "2p": -498.77192, + "2s": -517.275843, + "3d": -99.256068, + "3p": -115.898384, + "3s": -124.783683, + "4d": -17.173307, + "4f": -7.206499, + "4p": -24.481337, + "4s": -28.42254, + "5d": -1.386458, + "5p": -3.655382, + "5s": -5.027447, + "6p": -0.217889, + "6s": -0.493528 + }, + "Atomic radius": 1.9, + "Atomic radius calculated": 1.35, + "Boiling point": "1235 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -2, + 2, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "9196 kg m-3", + "Electrical resistivity": "40 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2.6p4", + "Ionic radii": { + "4": 1.08, + "6": 0.81 + }, + "Liquid range": "708 K", + "Melting point": "527 K", + "Mendeleev no": 91, + "Mineral hardness": "no data", + "Molar volume": "22.97 cm3", + "Name": "Polonium", + "Oxidation states": [ + -2, + 2, + 4, + 6 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "4": { + "VI": { + "": { + "crystal_radius": 1.08, + "ionic_radius": 0.94 + } + }, + "VIII": { + "": { + "crystal_radius": 1.22, + "ionic_radius": 1.08 + } + } + }, + "6": { + "VI": { + "": { + "crystal_radius": 0.81, + "ionic_radius": 0.67 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "20 W m-1 K-1", + "Van der waals radius": 1.97, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.0, + "Youngs modulus": "no data GPa" + }, + "Pr": { + "Atomic mass": 140.90765, + "Atomic no": 59, + "Atomic orbitals": { + "1s": -1457.338067, + "2p": -215.418313, + "2s": -227.426363, + "3d": -33.913996, + "3p": -43.692548, + "3s": -48.924994, + "4d": -4.154228, + "4f": -0.155138, + "4p": -7.613108, + "4s": -9.577447, + "5p": -0.778046, + "5s": -1.296106, + "6s": -0.124465 + }, + "Atomic radius": 1.85, + "Atomic radius calculated": 2.47, + "Boiling point": "3563 K", + "Brinell hardness": "481 MN m-2", + "Bulk modulus": "29 GPa", + "Coefficient of linear thermal expansion": "6.7 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "6640 kg m-3", + "Electrical resistivity": "70 10-8 Ω m", + "Electronic structure": "[Xe].4f3.6s2", + "ICSD oxidation states": [ + 3, + 4 + ], + "Ionic radii": { + "3": 1.13, + "4": 0.99 + }, + "Liquid range": "2355 K", + "Melting point": "1208 K", + "Mendeleev no": 31, + "Mineral hardness": "no data", + "Molar volume": "20.80 cm3", + "Name": "Praseodymium", + "Oxidation states": [ + 2, + 3, + 4 + ], + "Poissons ratio": "0.28", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "15 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.13, + "ionic_radius": 0.99 + } + }, + "VIII": { + "": { + "crystal_radius": 1.266, + "ionic_radius": 1.126 + } + }, + "IX": { + "": { + "crystal_radius": 1.319, + "ionic_radius": 1.179 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.99, + "ionic_radius": 0.85 + } + }, + "VIII": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "13 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2280 m s-1", + "Vickers hardness": "400 MN m-2", + "X": 1.13, + "Youngs modulus": "37 GPa" + }, + "Pt": { + "Atomic mass": 195.084, + "Atomic no": 78, + "Atomic orbitals": { + "1s": -2613.096532, + "2p": -417.96053, + "2s": -434.858003, + "3d": -78.400271, + "3p": -93.309108, + "3s": -101.274869, + "4d": -11.419476, + "4f": -3.038049, + "4p": -17.697297, + "4s": -21.110651, + "5d": -0.273634, + "5p": -1.884256, + "5s": -2.950526, + "6s": -0.161308 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.77, + "Boiling point": "4098 K", + "Brinell hardness": "392 MN m-2", + "Bulk modulus": "230 GPa", + "Coefficient of linear thermal expansion": "8.8 x10-6K-1", + "Common oxidation states": [ + 2, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "21090 kg m-3", + "Electrical resistivity": "10.6 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d9.6s1", + "Ionic radii": { + "2": 0.94, + "4": 0.765, + "5": 0.71 + }, + "Liquid range": "2056.6 K", + "Melting point": "2041.4 K", + "Mendeleev no": 68, + "Mineral hardness": "3.5", + "Molar volume": "9.09 cm3", + "Name": "Platinum", + "Oxidation states": [ + -2, + 2, + 4, + 5, + 6 + ], + "Poissons ratio": "0.38", + "Reflectivity": "73 %", + "Refractive index": "no data", + "Rigidity modulus": "61 GPa", + "Shannon radii": { + "2": { + "IVSQ": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + }, + "VI": { + "": { + "crystal_radius": 0.94, + "ionic_radius": 0.8 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.765, + "ionic_radius": 0.625 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "72 W m-1 K-1", + "Van der waals radius": 1.75, + "Velocity of sound": "2680 m s-1", + "Vickers hardness": "549 MN m-2", + "X": 2.28, + "Youngs modulus": "168 GPa" + }, + "Pu": { + "Atomic mass": 244.0, + "Atomic no": 94, + "Atomic orbitals": "no data", + "Atomic radius": 1.75, + "Atomic radius calculated": "no data", + "Boiling point": "3503 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "19816 kg m-3", + "Electrical resistivity": "150 10-8 Ω m", + "Electronic structure": "[Rn].5f6.7s2", + "Ionic radii": { + "3": 1.14, + "4": 1.0, + "5": 0.88, + "6": 0.85 + }, + "Liquid range": "2590.5 K", + "Melting point": "912.5 K", + "Mendeleev no": 43, + "Mineral hardness": "no data", + "Molar volume": "12.29 cm3", + "Name": "Plutonium", + "Oxidation states": [ + 3, + 4, + 5, + 6, + 7 + ], + "Poissons ratio": "0.21", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "43 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.14, + "ionic_radius": 1.0 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 1.0, + "ionic_radius": 0.86 + } + }, + "VIII": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.88, + "ionic_radius": 0.74 + } + } + }, + "6": { + "VI": { + "": { + "crystal_radius": 0.85, + "ionic_radius": 0.71 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "6 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2260 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.28, + "Youngs modulus": "96 GPa" + }, + "Ra": { + "Atomic mass": 226.0, + "Atomic no": 88, + "Atomic orbitals": { + "1s": -3362.736563, + "2p": -557.513214, + "2s": -577.101208, + "3d": -115.306476, + "3p": -133.12325, + "3s": -142.632426, + "4d": -22.208125, + "4f": -11.181066, + "4p": -30.221208, + "4s": -34.525628, + "5d": -2.819853, + "5p": -5.547203, + "5s": -7.139137, + "6p": -0.634674, + "6s": -1.05135, + "7s": -0.113732 + }, + "Atomic radius": 2.15, + "Atomic radius calculated": "no data", + "Boiling point": "2010 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "5000 kg m-3", + "Electrical resistivity": "100 10-8 Ω m", + "Electronic structure": "[Rn].7s2", + "Ionic radii": { + "2": 1.62 + }, + "Liquid range": "1037 K", + "Melting point": "973 K", + "Mendeleev no": 13, + "Mineral hardness": "no data", + "Molar volume": "41.09 cm3", + "Name": "Radium", + "Oxidation states": [ + 2 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "2": { + "VIII": { + "": { + "crystal_radius": 1.62, + "ionic_radius": 1.48 + } + }, + "XII": { + "": { + "crystal_radius": 1.84, + "ionic_radius": 1.7 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "19 W m-1 K-1", + "Van der waals radius": 2.83, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.9, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "Ra-223": 1210.3 + } + }, + "Rb": { + "Atomic mass": 85.4678, + "Atomic no": 37, + "Atomic orbitals": { + "1s": -540.957115, + "2p": -64.784678, + "2s": -71.291202, + "3d": -3.915508, + "3p": -8.165416, + "3s": -10.513861, + "4p": -0.59217, + "4s": -1.135051, + "5s": -0.085375 + }, + "Atomic radius": 2.35, + "Atomic radius calculated": 2.65, + "Boiling point": "961 K", + "Brinell hardness": "0.216 MN m-2", + "Bulk modulus": "2.5 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "2093 K", + "Density of solid": "1532 kg m-3", + "Electrical resistivity": "13.3 10-8 Ω m", + "Electronic structure": "[Kr].5s1", + "ICSD oxidation states": [ + 1 + ], + "Ionic radii": { + "1": 1.66 + }, + "Liquid range": "648.54 K", + "Melting point": "312.46 K", + "Mendeleev no": 9, + "Mineral hardness": "0.3", + "Molar volume": "55.76 cm3", + "Name": "Rubidium", + "Oxidation states": [ + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "1": { + "VI": { + "": { + "crystal_radius": 1.66, + "ionic_radius": 1.52 + } + }, + "VII": { + "": { + "crystal_radius": 1.7, + "ionic_radius": 1.56 + } + }, + "VIII": { + "": { + "crystal_radius": 1.75, + "ionic_radius": 1.61 + } + }, + "IX": { + "": { + "crystal_radius": 1.77, + "ionic_radius": 1.63 + } + }, + "X": { + "": { + "crystal_radius": 1.8, + "ionic_radius": 1.66 + } + }, + "XI": { + "": { + "crystal_radius": 1.83, + "ionic_radius": 1.69 + } + }, + "XII": { + "": { + "crystal_radius": 1.86, + "ionic_radius": 1.72 + } + }, + "XIV": { + "": { + "crystal_radius": 1.97, + "ionic_radius": 1.83 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "58 W m-1 K-1", + "Van der waals radius": 3.03, + "Velocity of sound": "1300 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.82, + "Youngs modulus": "2.4 GPa" + }, + "Re": { + "Atomic mass": 186.207, + "Atomic no": 75, + "Atomic orbitals": { + "1s": -2407.665572, + "2p": -380.982869, + "2s": -397.087707, + "3d": -69.57676, + "3p": -83.634578, + "3s": -91.149193, + "4d": -9.516816, + "4f": -1.92508, + "4p": -15.295495, + "4s": -18.454325, + "5d": -0.258639, + "5p": -1.631227, + "5s": -2.567348, + "6s": -0.186859 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.88, + "Boiling point": "5869 K", + "Brinell hardness": "1320 MN m-2", + "Bulk modulus": "370 GPa", + "Coefficient of linear thermal expansion": "6.2 x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "21020 kg m-3", + "Electrical resistivity": "18 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d5.6s2", + "ICSD oxidation states": [ + 3, + 4, + 5, + 6, + 7 + ], + "Ionic radii": { + "4": 0.77, + "5": 0.72, + "6": 0.69, + "7": 0.67 + }, + "Liquid range": "2410 K", + "Melting point": "3459 K", + "Mendeleev no": 58, + "Mineral hardness": "7.0", + "Molar volume": "8.86 cm3", + "Name": "Rhenium", + "Oxidation states": [ + -3, + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "Poissons ratio": "0.30", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "178 GPa", + "Shannon radii": { + "4": { + "VI": { + "": { + "crystal_radius": 0.77, + "ionic_radius": 0.63 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + } + }, + "6": { + "VI": { + "": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.52, + "ionic_radius": 0.38 + } + }, + "VI": { + "": { + "crystal_radius": 0.67, + "ionic_radius": 0.53 + } + } + } + }, + "Superconduction temperature": "1.70 K", + "Thermal conductivity": "48 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4700 m s-1", + "Vickers hardness": "2450 MN m-2", + "X": 1.9, + "Youngs modulus": "463 GPa" + }, + "Rh": { + "Atomic mass": 102.9055, + "Atomic no": 45, + "Atomic orbitals": { + "1s": -821.136773, + "2p": -108.357665, + "2s": -116.80695, + "3d": -11.21725, + "3p": -17.415299, + "3s": -20.765603, + "4d": -0.239422, + "4p": -1.806456, + "4s": -2.825505, + "5s": -0.154624 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.73, + "Boiling point": "3968 K", + "Brinell hardness": "1100 MN m-2", + "Bulk modulus": "380 GPa", + "Coefficient of linear thermal expansion": "8.2 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "12450 kg m-3", + "Electrical resistivity": "4.3 10-8 Ω m", + "Electronic structure": "[Kr].4d8.5s1", + "ICSD oxidation states": [ + 3, + 4 + ], + "Ionic radii": { + "3": 0.805, + "4": 0.74, + "5": 0.69 + }, + "Liquid range": "1731 K", + "Melting point": "2237 K", + "Mendeleev no": 65, + "Mineral hardness": "6.0", + "Molar volume": "8.28 cm3", + "Name": "Rhodium", + "Oxidation states": [ + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.26", + "Reflectivity": "84 %", + "Refractive index": "no data", + "Rigidity modulus": "150 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.805, + "ionic_radius": 0.665 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "150 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4700 m s-1", + "Vickers hardness": "1246 MN m-2", + "X": 2.28, + "Youngs modulus": "275 GPa" + }, + "Rn": { + "Atomic mass": 220.0, + "Atomic no": 86, + "Atomic orbitals": { + "1s": -3204.756288, + "2p": -527.533025, + "2s": -546.57796, + "3d": -106.945006, + "3p": -124.172862, + "3s": -133.369144, + "4d": -19.449994, + "4f": -8.953318, + "4p": -27.108985, + "4s": -31.230804, + "5d": -1.911329, + "5p": -4.408702, + "5s": -5.889683, + "6p": -0.29318, + "6s": -0.62657 + }, + "Atomic radius": "no data", + "Atomic radius calculated": 1.2, + "Boiling point": "211.3 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Critical temperature": "377 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2.6p6", + "Liquid range": "9.3 K", + "Max oxidation state": 0.0, + "Melting point": "202 K", + "Mendeleev no": 6, + "Min oxidation state": 0.0, + "Mineral hardness": "no data", + "Molar volume": "50.50 cm3", + "Name": "Radon", + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.00361 W m-1 K-1", + "Van der waals radius": 2.2, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.2, + "Youngs modulus": "no data GPa" + }, + "Ru": { + "Atomic mass": 101.07, + "Atomic no": 44, + "Atomic orbitals": { + "1s": -782.918621, + "2p": -102.333649, + "2s": -110.536054, + "3d": -10.195668, + "3p": -16.145217, + "3s": -19.366692, + "4d": -0.210375, + "4p": -1.667549, + "4s": -2.628363, + "5s": -0.152834 + }, + "Atomic radius": 1.3, + "Atomic radius calculated": 1.78, + "Boiling point": "4423 K", + "Brinell hardness": "2160 MN m-2", + "Bulk modulus": "220 GPa", + "Coefficient of linear thermal expansion": "6.4 x10-6K-1", + "Common oxidation states": [ + 3, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "12370 kg m-3", + "Electrical resistivity": "7.1 10-8 Ω m", + "Electronic structure": "[Kr].4d7.5s1", + "ICSD oxidation states": [ + 2, + 3, + 4, + 5, + 6 + ], + "Ionic radii": { + "3": 0.82, + "4": 0.76, + "5": 0.705, + "7": 0.52, + "8": 0.5 + }, + "Liquid range": "1816 K", + "Melting point": "2607 K", + "Mendeleev no": 62, + "Mineral hardness": "6.5", + "Molar volume": "8.17 cm3", + "Name": "Ruthenium", + "Oxidation states": [ + -2, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "Poissons ratio": "0.30", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "173 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.82, + "ionic_radius": 0.68 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.76, + "ionic_radius": 0.62 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.705, + "ionic_radius": 0.565 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.52, + "ionic_radius": 0.38 + } + } + }, + "8": { + "IV": { + "": { + "crystal_radius": 0.5, + "ionic_radius": 0.36 + } + } + } + }, + "Superconduction temperature": "0.49 K", + "Thermal conductivity": "120 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "5970 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.2, + "Youngs modulus": "447 GPa" + }, + "S": { + "Atomic mass": 32.065, + "Atomic no": 16, + "Atomic orbitals": { + "1s": -87.789937, + "2p": -5.751257, + "2s": -7.69994, + "3p": -0.261676, + "3s": -0.630912 + }, + "Atomic radius": 1.0, + "Atomic radius calculated": 0.88, + "Boiling point": "717.87 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "7.7 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -2, + 2, + 4, + 6 + ], + "Critical temperature": "1314 K", + "Density of solid": "1960 kg m-3", + "Electrical resistivity": "> 102310-8 Ω m", + "Electronic structure": "[Ne].3s2.3p4", + "ICSD oxidation states": [ + -1, + 2, + 4, + -2, + 6 + ], + "Ionic radii": { + "-2": 1.7, + "4": 0.51, + "6": 0.43 + }, + "Liquid range": "329.51 K", + "Melting point": "388.36 K", + "Mendeleev no": 94, + "Mineral hardness": "2.0", + "Molar volume": "15.53 cm3", + "Name": "Sulfur", + "Oxidation states": [ + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.001111", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-2": { + "VI": { + "": { + "crystal_radius": 1.7, + "ionic_radius": 1.84 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.51, + "ionic_radius": 0.37 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.26, + "ionic_radius": 0.12 + } + }, + "VI": { + "": { + "crystal_radius": 0.43, + "ionic_radius": 0.29 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.205 W m-1 K-1", + "Van der waals radius": 1.8, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.58, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "S-33": -67.8, + "S-35": 47.1 + } + }, + "Sb": { + "Atomic mass": 121.76, + "Atomic no": 51, + "Atomic orbitals": { + "1s": -1070.823495, + "2p": -149.214271, + "2s": -159.171745, + "3d": -19.239895, + "3p": -26.956184, + "3s": -31.098242, + "4d": -1.297338, + "4p": -3.646579, + "4s": -5.04964, + "5p": -0.185623, + "5s": -0.445605 + }, + "Atomic radius": 1.45, + "Atomic radius calculated": 1.33, + "Boiling point": "1860 K", + "Brinell hardness": "294 MN m-2", + "Bulk modulus": "42 GPa", + "Coefficient of linear thermal expansion": "11 x10-6K-1", + "Common oxidation states": [ + -3, + 3, + 5 + ], + "Critical temperature": "no data K", + "Density of solid": "6697 kg m-3", + "Electrical resistivity": "40 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2.5p3", + "ICSD oxidation states": [ + -2, + 3, + 5, + -1, + -3 + ], + "Ionic radii": { + "3": 0.9, + "5": 0.76 + }, + "Liquid range": "956.22 K", + "Melting point": "903.78 K", + "Mendeleev no": 88, + "Mineral hardness": "3.0", + "Molar volume": "18.19 cm3", + "Name": "Antimony", + "Oxidation states": [ + -3, + 3, + 5 + ], + "Poissons ratio": "no data", + "Reflectivity": "55 %", + "Refractive index": "no data", + "Rigidity modulus": "20 GPa", + "Shannon radii": { + "3": { + "IVPY": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + }, + "V": { + "": { + "crystal_radius": 0.94, + "ionic_radius": 0.8 + } + }, + "VI": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "24 W m-1 K-1", + "Van der waals radius": 2.06, + "Velocity of sound": "3420 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.05, + "Youngs modulus": "55 GPa", + "NMR Quadrupole Moment": { + "Sb-121": -543.11, + "Sb-123": -692.14 + } + }, + "Sc": { + "Atomic mass": 44.955912, + "Atomic no": 21, + "Atomic orbitals": { + "1s": -160.184109, + "2p": -14.240006, + "2s": -17.206464, + "3d": -0.13108, + "3p": -1.233165, + "3s": -1.988378, + "4s": -0.156478 + }, + "Atomic radius": 1.6, + "Atomic radius calculated": 1.84, + "Boiling point": "3103 K", + "Brinell hardness": "750 MN m-2", + "Bulk modulus": "57 GPa", + "Coefficient of linear thermal expansion": "10.2 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "2985 kg m-3", + "Electrical resistivity": "about 55 10-8 Ω m", + "Electronic structure": "[Ar].3d1.4s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "3": 0.885 + }, + "Liquid range": "1289 K", + "Melting point": "1814 K", + "Mendeleev no": 19, + "Mineral hardness": "no data", + "Molar volume": "15.00 cm3", + "Name": "Scandium", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "0.28", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "29 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.885, + "ionic_radius": 0.745 + } + }, + "VIII": { + "": { + "crystal_radius": 1.01, + "ionic_radius": 0.87 + } + } + } + }, + "Superconduction temperature": "0.05 (under pressure)K", + "Thermal conductivity": "16 W m-1 K-1", + "Van der waals radius": 2.11, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.36, + "Youngs modulus": "74 GPa", + "NMR Quadrupole Moment": { + "Sc-45": -220.2 + } + }, + "Se": { + "Atomic mass": 78.96, + "Atomic no": 34, + "Atomic orbitals": { + "1s": -451.300258, + "2p": -51.514388, + "2s": -57.311948, + "3d": -2.011392, + "3p": -5.553517, + "3s": -7.547186, + "4p": -0.245806, + "4s": -0.621248 + }, + "Atomic radius": 1.15, + "Atomic radius calculated": 1.03, + "Boiling point": "958 K", + "Brinell hardness": "736 MN m-2", + "Bulk modulus": "8.3 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -2, + 2, + 4, + 6 + ], + "Critical temperature": "1766 K", + "Density of solid": "4819 kg m-3", + "Electrical resistivity": "high 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2.4p4", + "ICSD oxidation states": [ + -1, + 4, + -2, + 6 + ], + "Ionic radii": { + "-2": 1.84, + "4": 0.64, + "6": 0.56 + }, + "Liquid range": "464 K", + "Melting point": "494 K", + "Mendeleev no": 93, + "Mineral hardness": "2.0", + "Molar volume": "16.42 cm3", + "Name": "Selenium", + "Oxidation states": [ + -2, + 2, + 4, + 6 + ], + "Poissons ratio": "0.33", + "Reflectivity": "no data %", + "Refractive index": "1.000895", + "Rigidity modulus": "3.7 GPa", + "Shannon radii": { + "-2": { + "VI": { + "": { + "crystal_radius": 1.84, + "ionic_radius": 1.98 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.64, + "ionic_radius": 0.5 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.42, + "ionic_radius": 0.28 + } + }, + "VI": { + "": { + "crystal_radius": 0.56, + "ionic_radius": 0.42 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.52 W m-1 K-1", + "Van der waals radius": 1.9, + "Velocity of sound": "3350 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.55, + "Youngs modulus": "10 GPa" + }, + "Si": { + "Atomic mass": 28.0855, + "Atomic no": 14, + "Atomic orbitals": { + "1s": -65.184426, + "2p": -3.514938, + "2s": -5.075056, + "3p": -0.153293, + "3s": -0.398139 + }, + "Atomic radius": 1.1, + "Atomic radius calculated": 1.11, + "Boiling point": "3173 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "100 GPa", + "Coefficient of linear thermal expansion": "2.6 x10-6K-1", + "Common oxidation states": [ + -4, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "2330 kg m-3", + "Electrical resistivity": "about 100000 10-8 Ω m", + "Electronic structure": "[Ne].3s2.3p2", + "ICSD oxidation states": [ + -4, + 4 + ], + "Ionic radii": { + "4": 0.54 + }, + "Liquid range": "1486 K", + "Melting point": "1687 K", + "Mendeleev no": 85, + "Mineral hardness": "6.5", + "Molar volume": "12.06 cm3", + "Name": "Silicon", + "Oxidation states": [ + -4, + -3, + -2, + -1, + 1, + 2, + 3, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "28 %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "4": { + "IV": { + "": { + "crystal_radius": 0.4, + "ionic_radius": 0.26 + } + }, + "VI": { + "": { + "crystal_radius": 0.54, + "ionic_radius": 0.4 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "150 W m-1 K-1", + "Van der waals radius": 2.1, + "Velocity of sound": "2200 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.9, + "Youngs modulus": "47 GPa" + }, + "Sm": { + "Atomic mass": 150.36, + "Atomic no": 62, + "Atomic orbitals": { + "1s": -1617.183426, + "2p": -242.729726, + "2s": -255.498846, + "3d": -39.528656, + "3p": -50.08426, + "3s": -55.731133, + "4d": -4.814978, + "4f": -0.21776, + "4p": -8.672685, + "4s": -10.844667, + "5p": -0.835987, + "5s": -1.408552, + "6s": -0.128259 + }, + "Atomic radius": 1.85, + "Atomic radius calculated": 2.38, + "Boiling point": "2076 K", + "Brinell hardness": "441 MN m-2", + "Bulk modulus": "38 GPa", + "Coefficient of linear thermal expansion": "12.7 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "7353 kg m-3", + "Electrical resistivity": "94 10-8 Ω m", + "Electronic structure": "[Xe].4f6.6s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "2": 1.36, + "3": 1.0979999999999999 + }, + "Liquid range": "731 K", + "Melting point": "1345 K", + "Mendeleev no": 28, + "Mineral hardness": "no data", + "Molar volume": "19.98 cm3", + "Name": "Samarium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.27", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "20 GPa", + "Shannon radii": { + "2": { + "VII": { + "": { + "crystal_radius": 1.36, + "ionic_radius": 1.22 + } + }, + "VIII": { + "": { + "crystal_radius": 1.41, + "ionic_radius": 1.27 + } + }, + "IX": { + "": { + "crystal_radius": 1.46, + "ionic_radius": 1.32 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.098, + "ionic_radius": 0.958 + } + }, + "VII": { + "": { + "crystal_radius": 1.16, + "ionic_radius": 1.02 + } + }, + "VIII": { + "": { + "crystal_radius": 1.219, + "ionic_radius": 1.079 + } + }, + "IX": { + "": { + "crystal_radius": 1.272, + "ionic_radius": 1.132 + } + }, + "XII": { + "": { + "crystal_radius": 1.38, + "ionic_radius": 1.24 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "13 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2130 m s-1", + "Vickers hardness": "412 MN m-2", + "X": 1.17, + "Youngs modulus": "50 GPa" + }, + "Sn": { + "Atomic mass": 118.71, + "Atomic no": 50, + "Atomic orbitals": { + "1s": -1026.762169, + "2p": -141.821093, + "2s": -151.523991, + "3d": -17.657276, + "3p": -25.117913, + "3s": -29.125969, + "4d": -1.004952, + "4p": -3.211998, + "4s": -4.546335, + "5p": -0.14445, + "5s": -0.369349 + }, + "Atomic radius": 1.45, + "Atomic radius calculated": 1.45, + "Boiling point": "2875 K", + "Brinell hardness": "51 MN m-2", + "Bulk modulus": "58 GPa", + "Coefficient of linear thermal expansion": "22 x10-6K-1", + "Common oxidation states": [ + -4, + 2, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "7310 kg m-3", + "Electrical resistivity": "11.5 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2.5p2", + "ICSD oxidation states": [ + 2, + 3, + 4 + ], + "Ionic radii": { + "4": 0.83 + }, + "Liquid range": "2369.92 K", + "Melting point": "505.08 K", + "Mendeleev no": 83, + "Mineral hardness": "1.5", + "Molar volume": "16.29 cm3", + "Name": "Tin", + "Oxidation states": [ + -4, + 2, + 4 + ], + "Poissons ratio": "0.36", + "Reflectivity": "54 %", + "Refractive index": "no data", + "Rigidity modulus": "18 GPa", + "Shannon radii": { + "4": { + "IV": { + "": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + } + }, + "V": { + "": { + "crystal_radius": 0.76, + "ionic_radius": 0.62 + } + }, + "VI": { + "": { + "crystal_radius": 0.83, + "ionic_radius": 0.69 + } + }, + "VII": { + "": { + "crystal_radius": 0.89, + "ionic_radius": 0.75 + } + }, + "VIII": { + "": { + "crystal_radius": 0.95, + "ionic_radius": 0.81 + } + } + } + }, + "Superconduction temperature": "3.72 K", + "Thermal conductivity": "67 W m-1 K-1", + "Van der waals radius": 2.17, + "Velocity of sound": "2500 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.96, + "Youngs modulus": "50 GPa", + "NMR Quadrupole Moment": { + "Sn-119": -132.1 + } + }, + "Sr": { + "Atomic mass": 87.62, + "Atomic no": 38, + "Atomic orbitals": { + "1s": -572.870169, + "2p": -69.745941, + "2s": -76.491823, + "3d": -4.813498, + "3p": -9.301863, + "3s": -11.771585, + "4p": -0.844489, + "4s": -1.455317, + "5s": -0.131793 + }, + "Atomic radius": 2.0, + "Atomic radius calculated": 2.19, + "Boiling point": "1655 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "22.5 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "2630 kg m-3", + "Electrical resistivity": "13.5 10-8 Ω m", + "Electronic structure": "[Kr].5s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 1.32 + }, + "Liquid range": "605 K", + "Melting point": "1050 K", + "Mendeleev no": 15, + "Mineral hardness": "1.5", + "Molar volume": "33.94 cm3", + "Name": "Strontium", + "Oxidation states": [ + 2 + ], + "Poissons ratio": "0.28", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "6.1 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.32, + "ionic_radius": 1.18 + } + }, + "VII": { + "": { + "crystal_radius": 1.35, + "ionic_radius": 1.21 + } + }, + "VIII": { + "": { + "crystal_radius": 1.4, + "ionic_radius": 1.26 + } + }, + "IX": { + "": { + "crystal_radius": 1.45, + "ionic_radius": 1.31 + } + }, + "X": { + "": { + "crystal_radius": 1.5, + "ionic_radius": 1.36 + } + }, + "XII": { + "": { + "crystal_radius": 1.58, + "ionic_radius": 1.44 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "35 W m-1 K-1", + "Van der waals radius": 2.49, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.95, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "Sr-87": 305.2 + } + }, + "Ta": { + "Atomic mass": 180.94788, + "Atomic no": 73, + "Atomic orbitals": { + "1s": -2275.371387, + "2p": -357.248334, + "2s": -372.828724, + "3d": -63.942521, + "3p": -77.440942, + "3s": -84.658467, + "4d": -8.265848, + "4f": -1.199347, + "4p": -13.71981, + "4s": -16.713337, + "5d": -0.182464, + "5p": -1.37653, + "5s": -2.223807, + "6s": -0.174814 + }, + "Atomic radius": 1.45, + "Atomic radius calculated": 2.0, + "Boiling point": "5731 K", + "Brinell hardness": "800 MN m-2", + "Bulk modulus": "200 GPa", + "Coefficient of linear thermal expansion": "6.3 x10-6K-1", + "Common oxidation states": [ + 5 + ], + "Critical temperature": "no data K", + "Density of solid": "16650 kg m-3", + "Electrical resistivity": "13.5 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d3.6s2", + "ICSD oxidation states": [ + 3, + 4, + 5 + ], + "Ionic radii": { + "3": 0.86, + "4": 0.82, + "5": 0.78 + }, + "Liquid range": "2441 K", + "Melting point": "3290 K", + "Mendeleev no": 52, + "Mineral hardness": "6.5", + "Molar volume": "10.85 cm3", + "Name": "Tantalum", + "Oxidation states": [ + -1, + 2, + 3, + 4, + 5 + ], + "Poissons ratio": "0.34", + "Reflectivity": "78 %", + "Refractive index": "no data", + "Rigidity modulus": "69 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.86, + "ionic_radius": 0.72 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.82, + "ionic_radius": 0.68 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.78, + "ionic_radius": 0.64 + } + }, + "VII": { + "": { + "crystal_radius": 0.83, + "ionic_radius": 0.69 + } + }, + "VIII": { + "": { + "crystal_radius": 0.88, + "ionic_radius": 0.74 + } + } + } + }, + "Superconduction temperature": "4.47 K", + "Thermal conductivity": "57 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "3400 m s-1", + "Vickers hardness": "873 MN m-2", + "X": 1.5, + "Youngs modulus": "186 GPa" + }, + "Tb": { + "Atomic mass": 158.92535, + "Atomic no": 65, + "Atomic orbitals": { + "1s": -1785.331942, + "2p": -271.590585, + "2s": -285.121013, + "3d": -45.443863, + "3p": -56.785113, + "3s": -62.851563, + "4d": -5.467662, + "4f": -0.256311, + "4p": -9.735637, + "4s": -12.120486, + "5p": -0.88723, + "5s": -1.513669, + "6s": -0.131677 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": 2.25, + "Boiling point": "3503 K", + "Brinell hardness": "677 MN m-2", + "Bulk modulus": "38.7 GPa", + "Coefficient of linear thermal expansion": "10.3 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "8219 kg m-3", + "Electrical resistivity": "115 10-8 Ω m", + "Electronic structure": "[Xe].4f9.6s2", + "ICSD oxidation states": [ + 3, + 4 + ], + "Ionic radii": { + "3": 1.063, + "4": 0.9 + }, + "Liquid range": "1874 K", + "Melting point": "1629 K", + "Mendeleev no": 26, + "Mineral hardness": "no data", + "Molar volume": "19.30 cm3", + "Name": "Terbium", + "Oxidation states": [ + 1, + 3, + 4 + ], + "Poissons ratio": "0.26", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "22 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.063, + "ionic_radius": 0.923 + } + }, + "VII": { + "": { + "crystal_radius": 1.12, + "ionic_radius": 0.98 + } + }, + "VIII": { + "": { + "crystal_radius": 1.18, + "ionic_radius": 1.04 + } + }, + "IX": { + "": { + "crystal_radius": 1.235, + "ionic_radius": 1.095 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + }, + "VIII": { + "": { + "crystal_radius": 1.02, + "ionic_radius": 0.88 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "11 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2620 m s-1", + "Vickers hardness": "863 MN m-2", + "X": 1.1, + "Youngs modulus": "56 GPa" + }, + "Tc": { + "Atomic mass": 98.0, + "Atomic no": 43, + "Atomic orbitals": { + "1s": -745.742024, + "2p": -96.61021, + "2s": -104.567508, + "3d": -9.33986, + "3p": -15.041738, + "3s": -18.135303, + "4d": -0.270262, + "4p": -1.64323, + "4s": -2.550712, + "5s": -0.183636 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.83, + "Boiling point": "4538 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 4, + 7 + ], + "Critical temperature": "no data K", + "Density of solid": "11500 kg m-3", + "Electrical resistivity": "about 22 10-8 Ω m", + "Electronic structure": "[Kr].4d5.5s2", + "Ionic radii": { + "4": 0.785, + "5": 0.74, + "7": 0.7 + }, + "Liquid range": "2108 K", + "Melting point": "2430 K", + "Mendeleev no": 59, + "Mineral hardness": "no data", + "Molar volume": "8.63 cm3", + "Name": "Technetium", + "Oxidation states": [ + -3, + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "4": { + "VI": { + "": { + "crystal_radius": 0.785, + "ionic_radius": 0.645 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.51, + "ionic_radius": 0.37 + } + }, + "VI": { + "": { + "crystal_radius": 0.7, + "ionic_radius": 0.56 + } + } + } + }, + "Superconduction temperature": "7.8 K", + "Thermal conductivity": "51 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.9, + "Youngs modulus": "no data GPa" + }, + "Te": { + "Atomic mass": 127.6, + "Atomic no": 52, + "Atomic orbitals": { + "1s": -1115.831819, + "2p": -156.808583, + "2s": -167.021776, + "3d": -20.887801, + "3p": -28.860685, + "3s": -33.137485, + "4d": -1.608381, + "4p": -4.100084, + "4s": -5.572846, + "5p": -0.226594, + "5s": -0.520997 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.23, + "Boiling point": "1261 K", + "Brinell hardness": "180 MN m-2", + "Bulk modulus": "65 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -2, + 2, + 4, + 6 + ], + "Critical temperature": "no data K", + "Density of solid": "6240 kg m-3", + "Electrical resistivity": "about 10000 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2.5p4", + "ICSD oxidation states": [ + -2, + 4, + -1, + 6 + ], + "Ionic radii": { + "-2": 2.07, + "4": 1.11, + "6": 0.7 + }, + "Liquid range": "538.34 K", + "Melting point": "722.66 K", + "Mendeleev no": 92, + "Mineral hardness": "2.25", + "Molar volume": "20.46 cm3", + "Name": "Tellurium", + "Oxidation states": [ + -2, + 2, + 4, + 5, + 6 + ], + "Poissons ratio": "no data", + "Reflectivity": "50 %", + "Refractive index": "1.000991", + "Rigidity modulus": "16 GPa", + "Shannon radii": { + "-2": { + "VI": { + "": { + "crystal_radius": 2.07, + "ionic_radius": 2.21 + } + } + }, + "4": { + "III": { + "": { + "crystal_radius": 0.66, + "ionic_radius": 0.52 + } + }, + "IV": { + "": { + "crystal_radius": 0.8, + "ionic_radius": 0.66 + } + }, + "VI": { + "": { + "crystal_radius": 1.11, + "ionic_radius": 0.97 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.57, + "ionic_radius": 0.43 + } + }, + "VI": { + "": { + "crystal_radius": 0.7, + "ionic_radius": 0.56 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "3 W m-1 K-1", + "Van der waals radius": 2.06, + "Velocity of sound": "2610 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.1, + "Youngs modulus": "43 GPa" + }, + "Th": { + "Atomic mass": 232.03806, + "Atomic no": 90, + "Atomic orbitals": { + "1s": -3524.439052, + "2p": -588.218112, + "2s": -608.350958, + "3d": -123.846396, + "3p": -142.25581, + "3s": -152.079741, + "4d": -24.955184, + "4f": -13.397389, + "4p": -33.325252, + "4s": -37.814094, + "5d": -3.625729, + "5p": -6.58281, + "5s": -8.287057, + "6d": -0.172896, + "6p": -0.846921, + "6s": -1.333769, + "7s": -0.135872 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": "no data", + "Boiling point": "5093 K", + "Brinell hardness": "400 MN m-2", + "Bulk modulus": "54 GPa", + "Coefficient of linear thermal expansion": "11.0 x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "11724 kg m-3", + "Electrical resistivity": "15 10-8 Ω m", + "Electronic structure": "[Rn].6d2.7s2", + "ICSD oxidation states": [ + 4 + ], + "Ionic radii": { + "4": 1.08 + }, + "Liquid range": "2978 K", + "Melting point": "2115 K", + "Mendeleev no": 47, + "Mineral hardness": "3.0", + "Molar volume": "19.80 cm3", + "Name": "Thorium", + "Oxidation states": [ + 2, + 3, + 4 + ], + "Poissons ratio": "0.27", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "31 GPa", + "Shannon radii": { + "4": { + "VI": { + "": { + "crystal_radius": 1.08, + "ionic_radius": 0.94 + } + }, + "VIII": { + "": { + "crystal_radius": 1.19, + "ionic_radius": 1.05 + } + }, + "IX": { + "": { + "crystal_radius": 1.23, + "ionic_radius": 1.09 + } + }, + "X": { + "": { + "crystal_radius": 1.27, + "ionic_radius": 1.13 + } + }, + "XI": { + "": { + "crystal_radius": 1.32, + "ionic_radius": 1.18 + } + }, + "XII": { + "": { + "crystal_radius": 1.35, + "ionic_radius": 1.21 + } + } + } + }, + "Superconduction temperature": "1.38 K", + "Thermal conductivity": "54 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2490 m s-1", + "Vickers hardness": "350 MN m-2", + "X": 1.3, + "Youngs modulus": "79 GPa" + }, + "Ti": { + "Atomic mass": 47.867, + "Atomic no": 22, + "Atomic orbitals": { + "1s": -177.276643, + "2p": -16.285339, + "2s": -19.457901, + "3d": -0.17001, + "3p": -1.422947, + "3s": -2.258007, + "4s": -0.167106 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.76, + "Boiling point": "3560 K", + "Brinell hardness": "716 MN m-2", + "Bulk modulus": "110 GPa", + "Coefficient of linear thermal expansion": "8.6 x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "4507 kg m-3", + "Electrical resistivity": "about 40 10-8 Ω m", + "Electronic structure": "[Ar].3d2.4s2", + "ICSD oxidation states": [ + 2, + 3, + 4 + ], + "Ionic radii": { + "2": 1.0, + "3": 0.81, + "4": 0.745 + }, + "Liquid range": "1619 K", + "Melting point": "1941 K", + "Mendeleev no": 51, + "Mineral hardness": "6.0", + "Molar volume": "10.64 cm3", + "Name": "Titanium", + "Oxidation states": [ + -1, + 2, + 3, + 4 + ], + "Poissons ratio": "0.32", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "44 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.0, + "ionic_radius": 0.86 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 0.81, + "ionic_radius": 0.67 + } + } + }, + "4": { + "IV": { + "": { + "crystal_radius": 0.56, + "ionic_radius": 0.42 + } + }, + "V": { + "": { + "crystal_radius": 0.65, + "ionic_radius": 0.51 + } + }, + "VI": { + "": { + "crystal_radius": 0.745, + "ionic_radius": 0.605 + } + }, + "VIII": { + "": { + "crystal_radius": 0.88, + "ionic_radius": 0.74 + } + } + } + }, + "Superconduction temperature": "0.40 K", + "Thermal conductivity": "22 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4140 m s-1", + "Vickers hardness": "970 MN m-2", + "X": 1.54, + "Youngs modulus": "116 GPa", + "NMR Quadrupole Moment": { + "Ti-47": 302.1, + "Ti-49": 247.11 + } + }, + "Tl": { + "Atomic mass": 204.3833, + "Atomic no": 81, + "Atomic orbitals": { + "1s": -2827.569408, + "2p": -457.255971, + "2s": -474.953368, + "3d": -88.328299, + "3p": -104.099296, + "3s": -112.52218, + "4d": -14.008848, + "4f": -4.835747, + "4p": -20.797078, + "4s": -24.471512, + "5d": -0.674544, + "5p": -2.59873, + "5s": -3.811512, + "6p": -0.101507, + "6s": -0.28502 + }, + "Atomic radius": 1.9, + "Atomic radius calculated": 1.56, + "Boiling point": "1746 K", + "Brinell hardness": "26.4 MN m-2", + "Bulk modulus": "43 GPa", + "Coefficient of linear thermal expansion": "29.9 x10-6K-1", + "Common oxidation states": [ + 1, + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "11850 kg m-3", + "Electrical resistivity": "15 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2.6p1", + "ICSD oxidation states": [ + 1, + 3 + ], + "Ionic radii": { + "1": 1.64, + "3": 1.025 + }, + "Liquid range": "1169 K", + "Melting point": "577 K", + "Mendeleev no": 78, + "Mineral hardness": "1.2", + "Molar volume": "17.22 cm3", + "Name": "Thallium", + "Oxidation states": [ + 1, + 3 + ], + "Poissons ratio": "0.45", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "2.8 GPa", + "Shannon radii": { + "1": { + "VI": { + "": { + "crystal_radius": 1.64, + "ionic_radius": 1.5 + } + }, + "VIII": { + "": { + "crystal_radius": 1.73, + "ionic_radius": 1.59 + } + }, + "XII": { + "": { + "crystal_radius": 1.84, + "ionic_radius": 1.7 + } + } + }, + "3": { + "IV": { + "": { + "crystal_radius": 0.89, + "ionic_radius": 0.75 + } + }, + "VI": { + "": { + "crystal_radius": 1.025, + "ionic_radius": 0.885 + } + }, + "VIII": { + "": { + "crystal_radius": 1.12, + "ionic_radius": 0.98 + } + } + } + }, + "Superconduction temperature": "2.38 K", + "Thermal conductivity": "46 W m-1 K-1", + "Van der waals radius": 1.96, + "Velocity of sound": "818 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.62, + "Youngs modulus": "8 GPa" + }, + "Tm": { + "Atomic mass": 168.93421, + "Atomic no": 69, + "Atomic orbitals": { + "1s": -2022.471608, + "2p": -312.510608, + "2s": -327.05712, + "3d": -53.835494, + "3p": -66.239338, + "3s": -72.873753, + "4d": -6.350307, + "4f": -0.28312, + "4p": -11.187151, + "4s": -13.865665, + "5p": -0.950748, + "5s": -1.64999, + "6s": -0.135953 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": 2.22, + "Boiling point": "2223 K", + "Brinell hardness": "471 MN m-2", + "Bulk modulus": "45 GPa", + "Coefficient of linear thermal expansion": "13.3 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "9321 kg m-3", + "Electrical resistivity": "67.6 10-8 Ω m", + "Electronic structure": "[Xe].4f13.6s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "2": 1.17, + "3": 1.02 + }, + "Liquid range": "405 K", + "Melting point": "1818 K", + "Mendeleev no": 21, + "Mineral hardness": "no data", + "Molar volume": "19.1 cm3", + "Name": "Thulium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.21", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "31 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.17, + "ionic_radius": 1.03 + } + }, + "VII": { + "": { + "crystal_radius": 1.23, + "ionic_radius": 1.09 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.02, + "ionic_radius": 0.88 + } + }, + "VIII": { + "": { + "crystal_radius": 1.134, + "ionic_radius": 0.994 + } + }, + "IX": { + "": { + "crystal_radius": 1.192, + "ionic_radius": 1.052 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "17 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "520 MN m-2", + "X": 1.25, + "Youngs modulus": "74 GPa" + }, + "U": { + "Atomic mass": 238.02891, + "Atomic no": 92, + "Atomic orbitals": { + "1s": -3689.355141, + "2p": -619.10855, + "2s": -639.778728, + "3d": -131.977358, + "3p": -150.97898, + "3s": -161.118073, + "4d": -27.123212, + "4f": -15.02746, + "4p": -35.853321, + "4s": -40.528084, + "5d": -3.866175, + "5f": -0.366543, + "5p": -7.018092, + "5s": -8.824089, + "6d": -0.14319, + "6p": -0.822538, + "6s": -1.325976, + "7s": -0.130948 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": "no data", + "Boiling point": "4200 K", + "Brinell hardness": "2400 MN m-2", + "Bulk modulus": "100 GPa", + "Coefficient of linear thermal expansion": "13.9 x10-6K-1", + "Common oxidation states": [ + 6 + ], + "Critical temperature": "no data K", + "Density of solid": "19050 kg m-3", + "Electrical resistivity": "28 10-8 Ω m", + "Electronic structure": "[Rn].5f3.6d1.7s2", + "ICSD oxidation states": [ + 3, + 4, + 5, + 6 + ], + "Ionic radii": { + "3": 1.165, + "4": 1.03, + "5": 0.9, + "6": 0.87 + }, + "Liquid range": "2794.7 K", + "Melting point": "1405.3 K", + "Mendeleev no": 45, + "Mineral hardness": "6.0", + "Molar volume": "12.49 cm3", + "Name": "Uranium", + "Oxidation states": [ + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.23", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "111 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.165, + "ionic_radius": 1.025 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 1.03, + "ionic_radius": 0.89 + } + }, + "VII": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + }, + "VIII": { + "": { + "crystal_radius": 1.14, + "ionic_radius": 1.0 + } + }, + "IX": { + "": { + "crystal_radius": 1.19, + "ionic_radius": 1.05 + } + }, + "XII": { + "": { + "crystal_radius": 1.31, + "ionic_radius": 1.17 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + }, + "VII": { + "": { + "crystal_radius": 0.98, + "ionic_radius": 0.84 + } + } + }, + "6": { + "II": { + "": { + "crystal_radius": 0.59, + "ionic_radius": 0.45 + } + }, + "IV": { + "": { + "crystal_radius": 0.66, + "ionic_radius": 0.52 + } + }, + "VI": { + "": { + "crystal_radius": 0.87, + "ionic_radius": 0.73 + } + }, + "VII": { + "": { + "crystal_radius": 0.95, + "ionic_radius": 0.81 + } + }, + "VIII": { + "": { + "crystal_radius": 1.0, + "ionic_radius": 0.86 + } + } + } + }, + "Superconduction temperature": "0.2 K", + "Thermal conductivity": "27 W m-1 K-1", + "Van der waals radius": 1.86, + "Velocity of sound": "3155 m s-1", + "Vickers hardness": "1960 MN m-2", + "X": 1.38, + "Youngs modulus": "208 GPa" + }, + "V": { + "Atomic mass": 50.9415, + "Atomic no": 23, + "Atomic orbitals": { + "1s": -195.224014, + "2p": -18.435189, + "2s": -21.815346, + "3d": -0.204634, + "3p": -1.610516, + "3s": -2.526904, + "4s": -0.175968 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.71, + "Boiling point": "3680 K", + "Brinell hardness": "628 MN m-2", + "Bulk modulus": "160 GPa", + "Coefficient of linear thermal expansion": "8.4 x10-6K-1", + "Common oxidation states": [ + 5 + ], + "Critical temperature": "no data K", + "Density of solid": "6110 kg m-3", + "Electrical resistivity": "20 10-8 Ω m", + "Electronic structure": "[Ar].3d3.4s2", + "ICSD oxidation states": [ + 2, + 3, + 4, + 5 + ], + "Ionic radii": { + "2": 0.93, + "3": 0.78, + "4": 0.72, + "5": 0.68 + }, + "Liquid range": "1497 K", + "Melting point": "2183 K", + "Mendeleev no": 54, + "Mineral hardness": "7.0", + "Molar volume": "8.32 cm3", + "Name": "Vanadium", + "Oxidation states": [ + -1, + 1, + 2, + 3, + 4, + 5 + ], + "Poissons ratio": "0.37", + "Reflectivity": "61 %", + "Refractive index": "no data", + "Rigidity modulus": "47 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 0.93, + "ionic_radius": 0.79 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 0.78, + "ionic_radius": 0.64 + } + } + }, + "4": { + "V": { + "": { + "crystal_radius": 0.67, + "ionic_radius": 0.53 + } + }, + "VI": { + "": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + }, + "VIII": { + "": { + "crystal_radius": 0.86, + "ionic_radius": 0.72 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.495, + "ionic_radius": 0.355 + } + }, + "V": { + "": { + "crystal_radius": 0.6, + "ionic_radius": 0.46 + } + }, + "VI": { + "": { + "crystal_radius": 0.68, + "ionic_radius": 0.54 + } + } + } + }, + "Superconduction temperature": "5.40 K", + "Thermal conductivity": "31 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4560 m s-1", + "Vickers hardness": "628 MN m-2", + "X": 1.63, + "Youngs modulus": "128 GPa", + "NMR Quadrupole Moment": { + "V-50": 210.4, + "V-51": -52.1 + } + }, + "W": { + "Atomic mass": 183.84, + "Atomic no": 74, + "Atomic orbitals": { + "1s": -2341.042887, + "2p": -369.013973, + "2s": -384.856157, + "3d": -66.724787, + "3p": -80.502102, + "3s": -87.867792, + "4d": -8.879693, + "4f": -1.550835, + "4p": -14.495102, + "4s": -17.570797, + "5d": -0.220603, + "5p": -1.504457, + "5s": -2.396018, + "6s": -0.181413 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.93, + "Boiling point": "5828 K", + "Brinell hardness": "2570 MN m-2", + "Bulk modulus": "310 GPa", + "Coefficient of linear thermal expansion": "4.5 x10-6K-1", + "Common oxidation states": [ + 4, + 6 + ], + "Critical temperature": "no data K", + "Density of solid": "19250 kg m-3", + "Electrical resistivity": "5.4 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d4.6s2", + "ICSD oxidation states": [ + 2, + 3, + 4, + 5, + 6 + ], + "Ionic radii": { + "4": 0.8, + "5": 0.76, + "6": 0.74 + }, + "Liquid range": "2133 K", + "Melting point": "3695 K", + "Mendeleev no": 55, + "Mineral hardness": "7.5", + "Molar volume": "9.47 cm3", + "Name": "Tungsten", + "Oxidation states": [ + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.28", + "Reflectivity": "62 %", + "Refractive index": "no data", + "Rigidity modulus": "161 GPa", + "Shannon radii": { + "4": { + "VI": { + "": { + "crystal_radius": 0.8, + "ionic_radius": 0.66 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.76, + "ionic_radius": 0.62 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.56, + "ionic_radius": 0.42 + } + }, + "V": { + "": { + "crystal_radius": 0.65, + "ionic_radius": 0.51 + } + }, + "VI": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + } + } + }, + "Superconduction temperature": "0.015 K", + "Thermal conductivity": "170 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "5174 m s-1", + "Vickers hardness": "3430 MN m-2", + "X": 2.36, + "Youngs modulus": "411 GPa" + }, + "Xe": { + "Atomic mass": 131.293, + "Atomic no": 54, + "Atomic orbitals": { + "1s": -1208.688993, + "2p": -172.599583, + "2s": -183.327495, + "3d": -24.37823, + "3p": -32.867042, + "3s": -37.415454, + "4d": -2.286666, + "4p": -5.063802, + "4s": -6.67834, + "5p": -0.309835, + "5s": -0.672086 + }, + "Atomic radius": "no data", + "Atomic radius calculated": 1.08, + "Boiling point": "165.1 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Critical temperature": "289.7 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2.5p6", + "Ionic radii": { + "8": 0.62 + }, + "Liquid range": "3.7 K", + "Max oxidation state": 8.0, + "Melting point": "161.4 K", + "Mendeleev no": 5, + "Min oxidation state": 2.0, + "Mineral hardness": "no data", + "Molar volume": "35.92 cm3", + "Name": "Xenon", + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000702", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "8": { + "IV": { + "": { + "crystal_radius": 0.54, + "ionic_radius": 0.4 + } + }, + "VI": { + "": { + "crystal_radius": 0.62, + "ionic_radius": 0.48 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.00565 W m-1 K-1", + "Van der waals radius": 2.16, + "Velocity of sound": "1090 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.6, + "Youngs modulus": "no data GPa" + }, + "Y": { + "Atomic mass": 88.90585, + "Atomic no": 39, + "Atomic orbitals": { + "1s": -605.631981, + "2p": -74.803201, + "2s": -81.789102, + "3d": -5.671499, + "3p": -10.399926, + "3s": -12.992217, + "4d": -0.108691, + "4p": -1.02449, + "4s": -1.697124, + "5s": -0.150727 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": 2.12, + "Boiling point": "3609 K", + "Brinell hardness": "589 MN m-2", + "Bulk modulus": "41 GPa", + "Coefficient of linear thermal expansion": "10.6 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "4472 kg m-3", + "Electrical resistivity": "about 60 10-8 Ω m", + "Electronic structure": "[Kr].4d1.5s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "3": 1.04 + }, + "Liquid range": "1810 K", + "Melting point": "1799 K", + "Mendeleev no": 25, + "Mineral hardness": "no data", + "Molar volume": "19.88 cm3", + "Name": "Yttrium", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "0.24", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "26 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.04, + "ionic_radius": 0.9 + } + }, + "VII": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + }, + "VIII": { + "": { + "crystal_radius": 1.159, + "ionic_radius": 1.019 + } + }, + "IX": { + "": { + "crystal_radius": 1.215, + "ionic_radius": 1.075 + } + } + } + }, + "Superconduction temperature": "1.3 (under pressure)K", + "Thermal conductivity": "17 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "3300 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.22, + "Youngs modulus": "64 GPa" + }, + "Yb": { + "Atomic mass": 173.04, + "Atomic no": 70, + "Atomic orbitals": { + "1s": -2084.069389, + "2p": -323.178219, + "2s": -337.978976, + "3d": -56.026315, + "3p": -68.698655, + "3s": -75.47663, + "4d": -6.574963, + "4f": -0.286408, + "4p": -11.558246, + "4s": -14.312076, + "5p": -0.966137, + "5s": -1.683886, + "6s": -0.136989 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": 2.22, + "Boiling point": "1469 K", + "Brinell hardness": "343 MN m-2", + "Bulk modulus": "31 GPa", + "Coefficient of linear thermal expansion": "26.3 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "6570 kg m-3", + "Electrical resistivity": "25.0 10-8 Ω m", + "Electronic structure": "[Xe].4f14.6s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "2": 1.16, + "3": 1.008 + }, + "Liquid range": "372 K", + "Melting point": "1097 K", + "Mendeleev no": 17, + "Mineral hardness": "no data", + "Molar volume": "24.84 cm3", + "Name": "Ytterbium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.21", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "9.9 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.16, + "ionic_radius": 1.02 + } + }, + "VII": { + "": { + "crystal_radius": 1.22, + "ionic_radius": 1.08 + } + }, + "VIII": { + "": { + "crystal_radius": 1.28, + "ionic_radius": 1.14 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.008, + "ionic_radius": 0.868 + } + }, + "VII": { + "": { + "crystal_radius": 1.065, + "ionic_radius": 0.925 + } + }, + "VIII": { + "": { + "crystal_radius": 1.125, + "ionic_radius": 0.985 + } + }, + "IX": { + "": { + "crystal_radius": 1.182, + "ionic_radius": 1.042 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "39 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "1590 m s-1", + "Vickers hardness": "206 MN m-2", + "X": 1.1, + "Youngs modulus": "24 GPa" + }, + "Zn": { + "Atomic mass": 65.409, + "Atomic no": 30, + "Atomic orbitals": { + "1s": -344.969756, + "2p": -36.648765, + "2s": -41.531323, + "3d": -0.398944, + "3p": -3.022363, + "3s": -4.573041, + "4s": -0.222725 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.42, + "Boiling point": "1180 K", + "Brinell hardness": "412 MN m-2", + "Bulk modulus": "70 GPa", + "Coefficient of linear thermal expansion": "30.2 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "7140 kg m-3", + "Electrical resistivity": "6.0 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 0.88 + }, + "Liquid range": "487.32 K", + "Melting point": "692.68 K", + "Mendeleev no": 76, + "Mineral hardness": "2.5", + "Molar volume": "9.16 cm3", + "Name": "Zinc", + "Oxidation states": [ + 1, + 2 + ], + "Poissons ratio": "0.25", + "Reflectivity": "80 %", + "Refractive index": "1.002050", + "Rigidity modulus": "43 GPa", + "Shannon radii": { + "2": { + "IV": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + }, + "V": { + "": { + "crystal_radius": 0.82, + "ionic_radius": 0.68 + } + }, + "VI": { + "": { + "crystal_radius": 0.88, + "ionic_radius": 0.74 + } + }, + "VIII": { + "": { + "crystal_radius": 1.04, + "ionic_radius": 0.9 + } + } + } + }, + "Superconduction temperature": "0.85 K", + "Thermal conductivity": "120 W m-1 K-1", + "Van der waals radius": 1.39, + "Velocity of sound": "3700 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.65, + "Youngs modulus": "108 GPa", + "NMR Quadrupole Moment": { + "Zn-67": 150.15 + } + }, + "Zr": { + "Atomic mass": 91.224, + "Atomic no": 40, + "Atomic orbitals": { + "1s": -639.292236, + "2p": -80.010043, + "2s": -87.237062, + "3d": -6.544643, + "3p": -11.514415, + "3s": -14.230432, + "4d": -0.150673, + "4p": -1.186597, + "4s": -1.918971, + "5s": -0.162391 + }, + "Atomic radius": 1.55, + "Atomic radius calculated": 2.06, + "Boiling point": "4682 K", + "Brinell hardness": "650 MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "5.7 x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "6511 kg m-3", + "Electrical resistivity": "43.3 10-8 Ω m", + "Electronic structure": "[Kr].4d2.5s2", + "ICSD oxidation states": [ + 2, + 3, + 4 + ], + "Ionic radii": { + "4": 0.86 + }, + "Liquid range": "2554 K", + "Melting point": "2128 K", + "Mendeleev no": 49, + "Mineral hardness": "5.0", + "Molar volume": "14.02 cm3", + "Name": "Zirconium", + "Oxidation states": [ + 1, + 2, + 3, + 4 + ], + "Poissons ratio": "0.34", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "33 GPa", + "Shannon radii": { + "4": { + "IV": { + "": { + "crystal_radius": 0.73, + "ionic_radius": 0.59 + } + }, + "V": { + "": { + "crystal_radius": 0.8, + "ionic_radius": 0.66 + } + }, + "VI": { + "": { + "crystal_radius": 0.86, + "ionic_radius": 0.72 + } + }, + "VII": { + "": { + "crystal_radius": 0.92, + "ionic_radius": 0.78 + } + }, + "VIII": { + "": { + "crystal_radius": 0.98, + "ionic_radius": 0.84 + } + }, + "IX": { + "": { + "crystal_radius": 1.03, + "ionic_radius": 0.89 + } + } + } + }, + "Superconduction temperature": "0.61 K", + "Thermal conductivity": "23 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "3800 m s-1", + "Vickers hardness": "903 MN m-2", + "X": 1.33, + "Youngs modulus": "68 GPa" + } } \ No newline at end of file diff --git a/prototype_ML_proj/lennard_jones_regress/lj_regression.py b/prototype_ML_proj/lennard_jones_regress/lj_regression.py index 6fd82b2..e8c427d 100644 --- a/prototype_ML_proj/lennard_jones_regress/lj_regression.py +++ b/prototype_ML_proj/lennard_jones_regress/lj_regression.py @@ -1,672 +1,672 @@ -#!/usr/bin/env python - -"""Methods for the regression of Lennard Jones parameters to DFT energies. - -Author: Raul A. Flores -""" - -#| - Import Modules -import gc -import pickle - -import math - -import itertools - -import numpy as np -import pandas as pd -from scipy.optimize import minimize - -#My Modules -from energetics.formation_energy import calc_formation_energy -from classical_methods.lennard_jones import lennard_jones_sp - -from IPython.display import display, clear_output - -#| - __old__ -# import os -# import copy -# from scipy import stats -# from scipy.optimize import fmin -# import collections -# import plotly.plotly as py -# import plotly.graph_objs as go -# from ase.visualize import view -# from ase import io -# from asap3 import LennardJones -# import math -# from an_data_processing import load_df -# from ase_modules.ase_methods import create_species_element_dict -#__| - -#__| - -def calc_lennard_jones_form_e( - atoms_i=None, - - atoms_H2=None, - atoms_Ir=None, - atoms_O2=None, - - epsilon=None, - sigma=None, - - ): - """Calculate the Lennard Jones formation energy of atoms object. - - Args: - atoms_i: - atoms_H2: - atoms_Ir: - atoms_O2: - epsilon: - sigma: - """ - #| - calc_lennard_jones_form_e - E_H = lennard_jones_sp(epsilon, sigma, atoms_H2) - E_O = lennard_jones_sp(epsilon, sigma, atoms_O2) - E_Ir = lennard_jones_sp(epsilon, sigma, atoms_Ir) - - reference_states = [ - { - "elec_e": E_H, - "element_dict": {"H": 1}, - }, - - { - "elec_e": E_O, - "element_dict": {"O": 1}, - }, - - { - "elec_e": E_Ir, - "element_dict": {"Ir": 1}, - }, - - ] - - E_form_i = calc_formation_energy( - atoms_i, - - lennard_jones_sp( - epsilon, - sigma, - atoms_i, - normalize_per_atom=False, - # return_quantity=return_quantity, - ), - - reference_states, - normalize_per_atom=False, - ) - - E_form_per_atom_i = E_form_i / atoms_i.get_number_of_atoms() - - E_out = E_form_per_atom_i - - return(E_out) - #__| - -def calc_lennard_jones_all_atoms( - pars, - atoms_list, - reference_atoms, - return_quantity="energies" # 'energies' or 'forces' - ): - """Calculate the Lennard Jones formation energies of list of atoms. - - Now can also return list of force arrays for all structures. - - Args: - pars: - atoms_list: - reference_atoms: - return_quantity: - """ - #| - calc_lennard_jones_all_atoms - - epsilon = pars[0] - sigma = pars[1] - - atoms_H2 = reference_atoms[0] - atoms_O2 = reference_atoms[1] - atoms_Ir = reference_atoms[2] - - predicted_energies = [] - predicted_forces = [] - - - if return_quantity == "energies": - for atoms_i in atoms_list: - - #| - Energy - lj_energy_i = calc_lennard_jones_form_e( - atoms_i=atoms_i, - atoms_H2=atoms_H2, - atoms_Ir=atoms_Ir, - atoms_O2=atoms_O2, - epsilon=epsilon, - sigma=sigma, - ) - - predicted_energies.append(lj_energy_i) - #__| - - predicted_energies = np.array(predicted_energies) - return(predicted_energies) - - if return_quantity == "forces": - for atoms_i in atoms_list: - - #| - Forces - lj_forces_i = lennard_jones_sp( - epsilon, - sigma, - atoms_i, - modified_lj=True, - normalize_per_atom=True, - return_quantity="forces", # 'energy', 'forces', 'both', 'energy&forces' - ) - - predicted_forces.append(lj_forces_i) - #__| - - predicted_forces = np.array(predicted_forces) - - return(predicted_forces) - #__| - -def objective( - pars, - known_energies, - - known_forces, - - atoms_list, - eps_shape, - sig_shape, - elem_list, - reference_atoms, - info, - ): - """Objective function to be minimized for LJ parameter fitting. - - Args: - pars: - known_energies: - atoms_list: - eps_shape: - sig_shape: - reference_atoms: - """ - #| - objective - epsilon, sigma = unflatten_eps_sig_array( - pars, - eps_shape, - sig_shape, - elem_list, - ) - - #| - Energy Term - err = known_energies - \ - calc_lennard_jones_all_atoms( - (epsilon, sigma), - atoms_list, - reference_atoms, - ) - - denominator_i = math.sqrt(np.sum(known_energies ** 2)) - numerator_i = math.sqrt(np.sum(err ** 2)) - - energy_term = numerator_i / denominator_i - - MSE = np.mean(err ** 2) - #__| - - #| - Force Term - def calc_sum_of_normals_of_forces(forces): - """Calculate sum of normals of forces on each atom. - - Args: - forces: - List of 3 components of force for each atom - """ - #| - calc_sum_of_normals_of_forces - sum_of_normals = 0. - for atom_forces_i in forces: - sum_of_normals += np.linalg.norm(atom_forces_i) - - return(sum_of_normals) - #__| - - - sum_of_structures_forces_known = 0. - for atoms_i in known_forces: - sum_of_normals_i = calc_sum_of_normals_of_forces(atoms_i) - sum_of_structures_forces_known += sum_of_normals_i - - lj_forces = calc_lennard_jones_all_atoms( - (epsilon, sigma), - atoms_list, - reference_atoms, - return_quantity="forces", # 'energies' or 'forces' - ) - - sum_of_structures_forces = 0. - for atoms_i in lj_forces: - sum_of_normals_i = calc_sum_of_normals_of_forces(atoms_i) - sum_of_structures_forces += sum_of_normals_i - - - force_term = sum_of_structures_forces / sum_of_structures_forces_known - #__| - - #| - Score Function - w_energy = 1. - w_force = 0.0001 - - score_function = w_energy * energy_term + w_force * force_term - - print(score_function) - #__| - - #| - Display Real-time Info - clear_output(wait=True) - - display("Iter: " + str(info["Nfeval"])) - display("MSE: " + str(MSE)) - - display("Energy Term: " + str(energy_term)) - display("Force Term: " + str(force_term)) - - display("Energy Term (weighted): " + str(w_energy * energy_term)) - display("Force Term (weighted): " + str(w_force * force_term)) - - - display("Score Function: " + str(score_function)) - display("Epsilon Matrix: ") - display(epsilon) - display("Sigma Matrix: ") - display(sigma) - display("__________________________") - - display(epsilon.values) - display(sigma.values) - - info["Nfeval"] += 1 - #__| - - return(score_function) - - # return(MSE) - #__| - -def flatten_eps_sig_triangular_matrices( - epsilon, - sigma, - mode="traingular", # 'triangular' or 'diagonal' - ): - """Flatten triangular epsilon and sigma matrices into a 1D array. - - Args: - epsilon: - sigma: - """ - #| - flatten_eps_sig_triangular_matrices - epsilon = epsilon.values - sigma = sigma.values - - if mode == "triangular": - flat_eps_sig = np.hstack([ - epsilon.flatten(), - sigma.flatten(), - ]) - - # Remove 0s - flat_eps_sig_no_0s = flat_eps_sig[flat_eps_sig != 0.] - - return(flat_eps_sig_no_0s) - - elif mode == "diagonal": - flat_eps_sig_diag = np.hstack( - [ - epsilon.diagonal(), - sigma.diagonal(), - ] - ) - - return(flat_eps_sig_diag) - #__| - -def unflatten_eps_sig_array( - flat_eps_sig, - eps_shape, - sig_shape, - elem_list, - ): - """Unflatten a 1D array into 2 triangular epsilon and sigma matrices. - - Args: - flat_eps_sig: - eps_shape: - sig_shape: - """ - #| - unflatten_eps_sig_array - - #| - Array Dimension Check - assert eps_shape[0] == eps_shape[1] - assert sig_shape[0] == sig_shape[1] - - N_eps = eps_shape[0] - N_sig = sig_shape[0] - - assert N_eps == N_sig - - N = N_eps - #__| - - len_pars = len(flat_eps_sig) - half_way = int(len_pars / 2) - - epsilon_short = flat_eps_sig[:half_way] - sigma_short = flat_eps_sig[half_way:] - - if len(epsilon_short) == N and len(sigma_short) == N: - pars_mode = "diagonal" - else: - pars_mode = "triangular" - - #| - Methods - def unflatten_tri_matrix_with_defined_cross_terms( - flat_array, - N, - cross_terms_mode="geo" # "geo" or "ave" - ): - """Convert array into a diagonal matrix with defined lower cross-terms. - - The lower-half cross terms are calculated from the diagonal terms. - - Args: - flat_array: - N: - cross_terms_mode: - "geo" or "ave" - """ - #| - unflatten_tri_matrix_with_defined_cross_terms - matrix = np.diag(flat_array) - - # Return list of i, j indices corresponding to the off diagonal - # cross-terms in the lower section of a triangular matrix - all_comb_indices = list(itertools.product( - np.array(range(N)), - np.array(range(N)), - )) - - unique_ij_list = [] - for i_j_pair in all_comb_indices: - i_ind = i_j_pair[0] - j_ind = i_j_pair[1] - if i_ind == j_ind: - continue - unique_ij_list.append(set(i_j_pair)) - - unique_ij_list = list(set([frozenset(item) for item in unique_ij_list])) - unique_ij_list = [list(item) for item in unique_ij_list] - - for i in unique_ij_list: - i.sort(reverse=True) - - for ij_ind in unique_ij_list: - i_ind = ij_ind[0] - j_ind = ij_ind[1] - - i_term = matrix[i_ind][i_ind] - j_term = matrix[j_ind][j_ind] - - average_ij = (i_term + j_term) / 2. - geo_ave_ij = (i_term * j_term) ** (1. / 2.) - - if cross_terms_mode == "geo": - matrix[i_ind][j_ind] = geo_ave_ij - elif cross_terms_mode == "ave": - matrix[i_ind][j_ind] = average_ij - - return(matrix) - #__| - - def unflatten_single_triangular_matrix(flat_array, N): - """Unflatten a single triangular matrix. - - Args: - flat_array: - N: - """ - #| - unflatten_single_traingular_matrix - start_index_list = [] - stop_index_list = [] - j_cnt = 0 - for i in range(N): - start_index_list.append(j_cnt) - increment = (i + 1) - j_cnt += increment - stop_index_list.append(j_cnt) - - rebuilt_matrix = [] - for i_ind, (start_i, stop_i) in enumerate(zip( - start_index_list, - stop_index_list)): - - num_of_0_to_add = N - i_ind - 1 - - final_row = np.append( - flat_array[start_i:stop_i], - num_of_0_to_add * [0.], - ) - - rebuilt_matrix.append(final_row) - - rebuilt_matrix = np.array(rebuilt_matrix) - - return(rebuilt_matrix) - #__| - - #__| - - if pars_mode == "triangular": - epsilon = unflatten_single_triangular_matrix(epsilon_short, N) - sigma = unflatten_single_triangular_matrix(sigma_short, N) - - elif pars_mode == "diagonal": - - epsilon = unflatten_tri_matrix_with_defined_cross_terms( - epsilon_short, - N, - cross_terms_mode="geo", - ) - - sigma = unflatten_tri_matrix_with_defined_cross_terms( - sigma_short, - N, - cross_terms_mode="ave", - ) - - epsilon = pd.DataFrame( - epsilon, - index=elem_list, - columns=elem_list, - ) - - sigma = pd.DataFrame( - sigma, - index=elem_list, - columns=elem_list, - ) - - return(epsilon, sigma) - - #__| - -def fit_LJ_to_DFT( - objective=None, - known_energies=None, - known_forces=None, - atoms_list=None, - elem_list=None, - reference_atoms=None, - epsilon_0=None, - sigma_0=None, - tol=1e-4, - maxiter=50, - maxfun=20, - params_mode="triangular", # "triangular" or "diagonal" - ): - """Fit LJ parameters to DFT energies. - - Args: - objective: - known_energies: - atoms_list: - reference_atoms: - epsilon_0: - sigma_0: - tol: - maxiter: - maxfun: - """ - #| - fit_LJ_to_DFT - atoms_H2 = reference_atoms[0] - atoms_O2 = reference_atoms[1] - atoms_Ir = reference_atoms[2] - - epsilon = epsilon_0 - sigma = sigma_0 - - eps_shape = epsilon.shape - sig_shape = sigma.shape - - # if params_mode == "triangular": - pars = flatten_eps_sig_triangular_matrices( - epsilon, - sigma, - mode=params_mode, # 'triangular' or 'diagonal' - ) - - #| - Minimize Method - opt_out = minimize( - objective, - pars, - - args=( - known_energies, - known_forces, - atoms_list, - eps_shape, - sig_shape, - elem_list, - [ - atoms_H2, - atoms_O2, - atoms_Ir, - ], - - {'Nfeval': 0}, - ), - - # method=None, - method='L-BFGS-B', - - jac=None, - hess=None, - hessp=None, - - # I'm adding a bit to the lower bound to avoid 0. values - # bounds=[(0, None) for i in pars], - bounds=[(0.0001, None) for i in pars], - - constraints=(), - tol=tol, - callback=None, - options={ - "maxiter": maxiter, - "maxfun": maxfun, - - "disp": True, - }, - ) - #__| - - LJ_pars = opt_out.x - - epsilon_out, sigma_out = unflatten_eps_sig_array( - LJ_pars, - eps_shape, - sig_shape, - elem_list, - ) - - with open("opt_params.pickle", "wb") as fle: - pickle.dump((epsilon_out, sigma_out), fle) - - return(epsilon_out, sigma_out) - #__| - -def calc_MSE( - pars, - df_i, - DFT_energies_col, - ref_atoms_list, - ): - """Calculate the mean-squared-error of model on dataset. - - Args: - pars: - df_i: - DFT_energies_col: - ref_atoms_list: - """ - #| - calc_MSE - # df_i = df_orig.iloc[cv_folds_indices[0]["testing"]] - epsilon = pars[0] - sigma = pars[1] - - known_energies = np.array(df_i[DFT_energies_col].tolist()) - atoms_list = df_i["final_atoms"].tolist() - - new_energies_test = calc_lennard_jones_all_atoms( - (epsilon, sigma), - atoms_list, - ref_atoms_list, - # [atoms_H2, atoms_O2, atoms_Ir], - ) - - err = known_energies - new_energies_test - MSE = np.mean(err ** 2) - - return(MSE) - #__| - -def k_fold_cross_validation(data, k=5): - """k-fold cross-validation indices list. - - Args: - data: - k: - """ - #| - k_fold_cross_validation - folds = np.array_split(data, k) - - cv_data = [] - for i_cnt in range(k): - - training_data_i = [] - for j_cnt in np.delete(np.arange(k), i_cnt): - training_data_i = np.concatenate((training_data_i, folds[j_cnt])) - testing_data_i = folds[i_cnt] - - cv_data.append({ - "training": training_data_i, - "testing": testing_data_i, - }) - - return(cv_data) - #__| +#!/usr/bin/env python + +"""Methods for the regression of Lennard Jones parameters to DFT energies. + +Author: Raul A. Flores +""" + +#| - Import Modules +import gc +import pickle + +import math + +import itertools + +import numpy as np +import pandas as pd +from scipy.optimize import minimize + +#My Modules +from energetics.formation_energy import calc_formation_energy +from classical_methods.lennard_jones import lennard_jones_sp + +from IPython.display import display, clear_output + +#| - __old__ +# import os +# import copy +# from scipy import stats +# from scipy.optimize import fmin +# import collections +# import plotly.plotly as py +# import plotly.graph_objs as go +# from ase.visualize import view +# from ase import io +# from asap3 import LennardJones +# import math +# from an_data_processing import load_df +# from ase_modules.ase_methods import create_species_element_dict +#__| + +#__| + +def calc_lennard_jones_form_e( + atoms_i=None, + + atoms_H2=None, + atoms_Ir=None, + atoms_O2=None, + + epsilon=None, + sigma=None, + + ): + """Calculate the Lennard Jones formation energy of atoms object. + + Args: + atoms_i: + atoms_H2: + atoms_Ir: + atoms_O2: + epsilon: + sigma: + """ + #| - calc_lennard_jones_form_e + E_H = lennard_jones_sp(epsilon, sigma, atoms_H2) + E_O = lennard_jones_sp(epsilon, sigma, atoms_O2) + E_Ir = lennard_jones_sp(epsilon, sigma, atoms_Ir) + + reference_states = [ + { + "elec_e": E_H, + "element_dict": {"H": 1}, + }, + + { + "elec_e": E_O, + "element_dict": {"O": 1}, + }, + + { + "elec_e": E_Ir, + "element_dict": {"Ir": 1}, + }, + + ] + + E_form_i = calc_formation_energy( + atoms_i, + + lennard_jones_sp( + epsilon, + sigma, + atoms_i, + normalize_per_atom=False, + # return_quantity=return_quantity, + ), + + reference_states, + normalize_per_atom=False, + ) + + E_form_per_atom_i = E_form_i / atoms_i.get_number_of_atoms() + + E_out = E_form_per_atom_i + + return(E_out) + #__| + +def calc_lennard_jones_all_atoms( + pars, + atoms_list, + reference_atoms, + return_quantity="energies" # 'energies' or 'forces' + ): + """Calculate the Lennard Jones formation energies of list of atoms. + + Now can also return list of force arrays for all structures. + + Args: + pars: + atoms_list: + reference_atoms: + return_quantity: + """ + #| - calc_lennard_jones_all_atoms + + epsilon = pars[0] + sigma = pars[1] + + atoms_H2 = reference_atoms[0] + atoms_O2 = reference_atoms[1] + atoms_Ir = reference_atoms[2] + + predicted_energies = [] + predicted_forces = [] + + + if return_quantity == "energies": + for atoms_i in atoms_list: + + #| - Energy + lj_energy_i = calc_lennard_jones_form_e( + atoms_i=atoms_i, + atoms_H2=atoms_H2, + atoms_Ir=atoms_Ir, + atoms_O2=atoms_O2, + epsilon=epsilon, + sigma=sigma, + ) + + predicted_energies.append(lj_energy_i) + #__| + + predicted_energies = np.array(predicted_energies) + return(predicted_energies) + + if return_quantity == "forces": + for atoms_i in atoms_list: + + #| - Forces + lj_forces_i = lennard_jones_sp( + epsilon, + sigma, + atoms_i, + modified_lj=True, + normalize_per_atom=True, + return_quantity="forces", # 'energy', 'forces', 'both', 'energy&forces' + ) + + predicted_forces.append(lj_forces_i) + #__| + + predicted_forces = np.array(predicted_forces) + + return(predicted_forces) + #__| + +def objective( + pars, + known_energies, + + known_forces, + + atoms_list, + eps_shape, + sig_shape, + elem_list, + reference_atoms, + info, + ): + """Objective function to be minimized for LJ parameter fitting. + + Args: + pars: + known_energies: + atoms_list: + eps_shape: + sig_shape: + reference_atoms: + """ + #| - objective + epsilon, sigma = unflatten_eps_sig_array( + pars, + eps_shape, + sig_shape, + elem_list, + ) + + #| - Energy Term + err = known_energies - \ + calc_lennard_jones_all_atoms( + (epsilon, sigma), + atoms_list, + reference_atoms, + ) + + denominator_i = math.sqrt(np.sum(known_energies ** 2)) + numerator_i = math.sqrt(np.sum(err ** 2)) + + energy_term = numerator_i / denominator_i + + MSE = np.mean(err ** 2) + #__| + + #| - Force Term + def calc_sum_of_normals_of_forces(forces): + """Calculate sum of normals of forces on each atom. + + Args: + forces: + List of 3 components of force for each atom + """ + #| - calc_sum_of_normals_of_forces + sum_of_normals = 0. + for atom_forces_i in forces: + sum_of_normals += np.linalg.norm(atom_forces_i) + + return(sum_of_normals) + #__| + + + sum_of_structures_forces_known = 0. + for atoms_i in known_forces: + sum_of_normals_i = calc_sum_of_normals_of_forces(atoms_i) + sum_of_structures_forces_known += sum_of_normals_i + + lj_forces = calc_lennard_jones_all_atoms( + (epsilon, sigma), + atoms_list, + reference_atoms, + return_quantity="forces", # 'energies' or 'forces' + ) + + sum_of_structures_forces = 0. + for atoms_i in lj_forces: + sum_of_normals_i = calc_sum_of_normals_of_forces(atoms_i) + sum_of_structures_forces += sum_of_normals_i + + + force_term = sum_of_structures_forces / sum_of_structures_forces_known + #__| + + #| - Score Function + w_energy = 1. + w_force = 0.0001 + + score_function = w_energy * energy_term + w_force * force_term + + print(score_function) + #__| + + #| - Display Real-time Info + clear_output(wait=True) + + display("Iter: " + str(info["Nfeval"])) + display("MSE: " + str(MSE)) + + display("Energy Term: " + str(energy_term)) + display("Force Term: " + str(force_term)) + + display("Energy Term (weighted): " + str(w_energy * energy_term)) + display("Force Term (weighted): " + str(w_force * force_term)) + + + display("Score Function: " + str(score_function)) + display("Epsilon Matrix: ") + display(epsilon) + display("Sigma Matrix: ") + display(sigma) + display("__________________________") + + display(epsilon.values) + display(sigma.values) + + info["Nfeval"] += 1 + #__| + + return(score_function) + + # return(MSE) + #__| + +def flatten_eps_sig_triangular_matrices( + epsilon, + sigma, + mode="traingular", # 'triangular' or 'diagonal' + ): + """Flatten triangular epsilon and sigma matrices into a 1D array. + + Args: + epsilon: + sigma: + """ + #| - flatten_eps_sig_triangular_matrices + epsilon = epsilon.values + sigma = sigma.values + + if mode == "triangular": + flat_eps_sig = np.hstack([ + epsilon.flatten(), + sigma.flatten(), + ]) + + # Remove 0s + flat_eps_sig_no_0s = flat_eps_sig[flat_eps_sig != 0.] + + return(flat_eps_sig_no_0s) + + elif mode == "diagonal": + flat_eps_sig_diag = np.hstack( + [ + epsilon.diagonal(), + sigma.diagonal(), + ] + ) + + return(flat_eps_sig_diag) + #__| + +def unflatten_eps_sig_array( + flat_eps_sig, + eps_shape, + sig_shape, + elem_list, + ): + """Unflatten a 1D array into 2 triangular epsilon and sigma matrices. + + Args: + flat_eps_sig: + eps_shape: + sig_shape: + """ + #| - unflatten_eps_sig_array + + #| - Array Dimension Check + assert eps_shape[0] == eps_shape[1] + assert sig_shape[0] == sig_shape[1] + + N_eps = eps_shape[0] + N_sig = sig_shape[0] + + assert N_eps == N_sig + + N = N_eps + #__| + + len_pars = len(flat_eps_sig) + half_way = int(len_pars / 2) + + epsilon_short = flat_eps_sig[:half_way] + sigma_short = flat_eps_sig[half_way:] + + if len(epsilon_short) == N and len(sigma_short) == N: + pars_mode = "diagonal" + else: + pars_mode = "triangular" + + #| - Methods + def unflatten_tri_matrix_with_defined_cross_terms( + flat_array, + N, + cross_terms_mode="geo" # "geo" or "ave" + ): + """Convert array into a diagonal matrix with defined lower cross-terms. + + The lower-half cross terms are calculated from the diagonal terms. + + Args: + flat_array: + N: + cross_terms_mode: + "geo" or "ave" + """ + #| - unflatten_tri_matrix_with_defined_cross_terms + matrix = np.diag(flat_array) + + # Return list of i, j indices corresponding to the off diagonal + # cross-terms in the lower section of a triangular matrix + all_comb_indices = list(itertools.product( + np.array(range(N)), + np.array(range(N)), + )) + + unique_ij_list = [] + for i_j_pair in all_comb_indices: + i_ind = i_j_pair[0] + j_ind = i_j_pair[1] + if i_ind == j_ind: + continue + unique_ij_list.append(set(i_j_pair)) + + unique_ij_list = list(set([frozenset(item) for item in unique_ij_list])) + unique_ij_list = [list(item) for item in unique_ij_list] + + for i in unique_ij_list: + i.sort(reverse=True) + + for ij_ind in unique_ij_list: + i_ind = ij_ind[0] + j_ind = ij_ind[1] + + i_term = matrix[i_ind][i_ind] + j_term = matrix[j_ind][j_ind] + + average_ij = (i_term + j_term) / 2. + geo_ave_ij = (i_term * j_term) ** (1. / 2.) + + if cross_terms_mode == "geo": + matrix[i_ind][j_ind] = geo_ave_ij + elif cross_terms_mode == "ave": + matrix[i_ind][j_ind] = average_ij + + return(matrix) + #__| + + def unflatten_single_triangular_matrix(flat_array, N): + """Unflatten a single triangular matrix. + + Args: + flat_array: + N: + """ + #| - unflatten_single_traingular_matrix + start_index_list = [] + stop_index_list = [] + j_cnt = 0 + for i in range(N): + start_index_list.append(j_cnt) + increment = (i + 1) + j_cnt += increment + stop_index_list.append(j_cnt) + + rebuilt_matrix = [] + for i_ind, (start_i, stop_i) in enumerate(zip( + start_index_list, + stop_index_list)): + + num_of_0_to_add = N - i_ind - 1 + + final_row = np.append( + flat_array[start_i:stop_i], + num_of_0_to_add * [0.], + ) + + rebuilt_matrix.append(final_row) + + rebuilt_matrix = np.array(rebuilt_matrix) + + return(rebuilt_matrix) + #__| + + #__| + + if pars_mode == "triangular": + epsilon = unflatten_single_triangular_matrix(epsilon_short, N) + sigma = unflatten_single_triangular_matrix(sigma_short, N) + + elif pars_mode == "diagonal": + + epsilon = unflatten_tri_matrix_with_defined_cross_terms( + epsilon_short, + N, + cross_terms_mode="geo", + ) + + sigma = unflatten_tri_matrix_with_defined_cross_terms( + sigma_short, + N, + cross_terms_mode="ave", + ) + + epsilon = pd.DataFrame( + epsilon, + index=elem_list, + columns=elem_list, + ) + + sigma = pd.DataFrame( + sigma, + index=elem_list, + columns=elem_list, + ) + + return(epsilon, sigma) + + #__| + +def fit_LJ_to_DFT( + objective=None, + known_energies=None, + known_forces=None, + atoms_list=None, + elem_list=None, + reference_atoms=None, + epsilon_0=None, + sigma_0=None, + tol=1e-4, + maxiter=50, + maxfun=20, + params_mode="triangular", # "triangular" or "diagonal" + ): + """Fit LJ parameters to DFT energies. + + Args: + objective: + known_energies: + atoms_list: + reference_atoms: + epsilon_0: + sigma_0: + tol: + maxiter: + maxfun: + """ + #| - fit_LJ_to_DFT + atoms_H2 = reference_atoms[0] + atoms_O2 = reference_atoms[1] + atoms_Ir = reference_atoms[2] + + epsilon = epsilon_0 + sigma = sigma_0 + + eps_shape = epsilon.shape + sig_shape = sigma.shape + + # if params_mode == "triangular": + pars = flatten_eps_sig_triangular_matrices( + epsilon, + sigma, + mode=params_mode, # 'triangular' or 'diagonal' + ) + + #| - Minimize Method + opt_out = minimize( + objective, + pars, + + args=( + known_energies, + known_forces, + atoms_list, + eps_shape, + sig_shape, + elem_list, + [ + atoms_H2, + atoms_O2, + atoms_Ir, + ], + + {'Nfeval': 0}, + ), + + # method=None, + method='L-BFGS-B', + + jac=None, + hess=None, + hessp=None, + + # I'm adding a bit to the lower bound to avoid 0. values + # bounds=[(0, None) for i in pars], + bounds=[(0.0001, None) for i in pars], + + constraints=(), + tol=tol, + callback=None, + options={ + "maxiter": maxiter, + "maxfun": maxfun, + + "disp": True, + }, + ) + #__| + + LJ_pars = opt_out.x + + epsilon_out, sigma_out = unflatten_eps_sig_array( + LJ_pars, + eps_shape, + sig_shape, + elem_list, + ) + + with open("opt_params.pickle", "wb") as fle: + pickle.dump((epsilon_out, sigma_out), fle) + + return(epsilon_out, sigma_out) + #__| + +def calc_MSE( + pars, + df_i, + DFT_energies_col, + ref_atoms_list, + ): + """Calculate the mean-squared-error of model on dataset. + + Args: + pars: + df_i: + DFT_energies_col: + ref_atoms_list: + """ + #| - calc_MSE + # df_i = df_orig.iloc[cv_folds_indices[0]["testing"]] + epsilon = pars[0] + sigma = pars[1] + + known_energies = np.array(df_i[DFT_energies_col].tolist()) + atoms_list = df_i["final_atoms"].tolist() + + new_energies_test = calc_lennard_jones_all_atoms( + (epsilon, sigma), + atoms_list, + ref_atoms_list, + # [atoms_H2, atoms_O2, atoms_Ir], + ) + + err = known_energies - new_energies_test + MSE = np.mean(err ** 2) + + return(MSE) + #__| + +def k_fold_cross_validation(data, k=5): + """k-fold cross-validation indices list. + + Args: + data: + k: + """ + #| - k_fold_cross_validation + folds = np.array_split(data, k) + + cv_data = [] + for i_cnt in range(k): + + training_data_i = [] + for j_cnt in np.delete(np.arange(k), i_cnt): + training_data_i = np.concatenate((training_data_i, folds[j_cnt])) + testing_data_i = folds[i_cnt] + + cv_data.append({ + "training": training_data_i, + "testing": testing_data_i, + }) + + return(cv_data) + #__| diff --git a/prototype_ML_proj/lennard_jones_regress/old.lj_regression_180724.py b/prototype_ML_proj/lennard_jones_regress/old.lj_regression_180724.py index 34babd0..5b110ce 100644 --- a/prototype_ML_proj/lennard_jones_regress/old.lj_regression_180724.py +++ b/prototype_ML_proj/lennard_jones_regress/old.lj_regression_180724.py @@ -1,653 +1,653 @@ -#!/usr/bin/env python - -"""Methods for the regression of Lennard Jones parameters to DFT energies. - -Author: Raul A. Flores -""" - -#| - Import Modules -import gc -import pickle - -import itertools - -import numpy as np -import pandas as pd -from scipy.optimize import minimize - -#My Modules -from energetics.formation_energy import calc_formation_energy -from classical_methods.lennard_jones import lennard_jones_sp - -from IPython.display import display, clear_output - -#| - __old__ -# import os -# import copy -# from scipy import stats -# from scipy.optimize import fmin -# import collections -# import plotly.plotly as py -# import plotly.graph_objs as go -# from ase.visualize import view -# from ase import io -# from asap3 import LennardJones -# import math -# from an_data_processing import load_df -# from ase_modules.ase_methods import create_species_element_dict -#__| - -#__| - -def calc_lennard_jones_form_e( - atoms_i=None, - - atoms_H2=None, - atoms_Ir=None, - atoms_O2=None, - - epsilon=None, - sigma=None, - - ): - """Calculate the Lennard Jones formation energy of atoms object. - - Args: - atoms_i: - atoms_H2: - atoms_Ir: - atoms_O2: - epsilon: - sigma: - """ - #| - calc_lennard_jones_form_e - E_H = lennard_jones_sp(epsilon, sigma, atoms_H2) - E_O = lennard_jones_sp(epsilon, sigma, atoms_O2) - E_Ir = lennard_jones_sp(epsilon, sigma, atoms_Ir) - - reference_states = [ - { - "elec_e": E_H, - "element_dict": {"H": 1}, - }, - - { - "elec_e": E_O, - "element_dict": {"O": 1}, - }, - - { - "elec_e": E_Ir, - "element_dict": {"Ir": 1}, - }, - - ] - - E_form_i = calc_formation_energy( - atoms_i, - - lennard_jones_sp( - epsilon, - sigma, - atoms_i, - normalize_per_atom=False, - # return_quantity=return_quantity, - ), - - reference_states, - normalize_per_atom=False, - ) - - E_form_per_atom_i = E_form_i / atoms_i.get_number_of_atoms() - - E_out = E_form_per_atom_i - - return(E_out) - #__| - -def calc_lennard_jones_all_atoms( - pars, - atoms_list, - reference_atoms, - return_quantity="energies" # 'energies' or 'forces' - ): - """Calculate the Lennard Jones formation energies of list of atoms. - - Now can also return list of force arrays for all structures. - - Args: - pars: - atoms_list: - reference_atoms: - return_quantity: - """ - #| - calc_lennard_jones_all_atoms - - epsilon = pars[0] - sigma = pars[1] - - atoms_H2 = reference_atoms[0] - atoms_O2 = reference_atoms[1] - atoms_Ir = reference_atoms[2] - - predicted_energies = [] - predicted_forces = [] - - - if return_quantity == "energies": - for atoms_i in atoms_list: - - #| - Energy - lj_energy_i = calc_lennard_jones_form_e( - atoms_i=atoms_i, - atoms_H2=atoms_H2, - atoms_Ir=atoms_Ir, - atoms_O2=atoms_O2, - epsilon=epsilon, - sigma=sigma, - ) - - predicted_energies.append(lj_energy_i) - #__| - - predicted_energies = np.array(predicted_energies) - return(predicted_energies) - - if return_quantity == "forces": - for atoms_i in atoms_list: - - #| - Forces - lj_forces_i = lennard_jones_sp( - epsilon, - sigma, - atoms_i, - modified_lj=True, - normalize_per_atom=True, - return_quantity="forces", # 'energy', 'forces', 'both', 'energy&forces' - ) - - predicted_forces.append(lj_forces_i) - #__| - - predicted_forces = np.array(predicted_energies) - - return(predicted_forces) - - # predicted_energies = np.array(predicted_energies) - # return(predicted_energies) - #__| - -def objective( - pars, - known_energies, - - known_forces, - - atoms_list, - eps_shape, - sig_shape, - elem_list, - reference_atoms, - info, - ): - """Objective function to be minimized for LJ parameter fitting. - - Args: - pars: - known_energies: - atoms_list: - eps_shape: - sig_shape: - reference_atoms: - """ - #| - objective - epsilon, sigma = unflatten_eps_sig_array( - pars, - eps_shape, - sig_shape, - elem_list, - ) - - #| - Energy Term - err = known_energies - \ - calc_lennard_jones_all_atoms( - (epsilon, sigma), - atoms_list, - reference_atoms, - ) - - MSE = np.mean(err ** 2) - #__| - - #| - Force Term - def calc_sum_of_normals_of_forces(forces): - """Calculate sum of normals of forces on each atom. - - Args: - forces: - List of 3 components of force for each atom - """ - #| - calc_sum_of_normals_of_forces - sum_of_normals = 0. - for atom_forces_i in forces: - sum_of_normals += np.linalg.norm(atom_forces_i) - - return(sum_of_normals) - #__| - - known_sum_of_normals = calc_sum_of_normals_of_forces(known_forces) - - lj_forces = calc_lennard_jones_all_atoms( - (epsilon, sigma), - atoms_list, - reference_atoms, - return_quantity="forces", # 'energies' or 'forces' - ) - - sum_of_structures_forces = 0. - for atom_i in lj_forces: - sum_of_normals_i = calc_sum_of_normals_of_forces(atom_i) - sum_of_structures_forces += sum_of_normals_i - - - print(sum_of_structures_forces / known_sum_of_normals) - - # print(tmp) - - print(30 * "&") - #__| - - - # clear_output(wait=True) - # - # - # display(tmp) - # display(20 * "*") - # - # - # - # display("Iter: " + str(info["Nfeval"])) - # display("MSE: " + str(MSE)) - # display("Epsilon Matrix: ") - # display(epsilon) - # display("Sigma Matrix: ") - # display(sigma) - # display("__________________________") - # - # display(epsilon.values) - # display(sigma.values) - - info["Nfeval"] += 1 - - return(MSE) - #__| - -def flatten_eps_sig_triangular_matrices( - epsilon, - sigma, - mode="traingular", # 'triangular' or 'diagonal' - ): - """Flatten triangular epsilon and sigma matrices into a 1D array. - - Args: - epsilon: - sigma: - """ - #| - flatten_eps_sig_triangular_matrices - epsilon = epsilon.values - sigma = sigma.values - - if mode == "triangular": - flat_eps_sig = np.hstack([ - epsilon.flatten(), - sigma.flatten(), - ]) - - # Remove 0s - flat_eps_sig_no_0s = flat_eps_sig[flat_eps_sig != 0.] - - return(flat_eps_sig_no_0s) - - elif mode == "diagonal": - flat_eps_sig_diag = np.hstack( - [ - epsilon.diagonal(), - sigma.diagonal(), - ] - ) - - return(flat_eps_sig_diag) - #__| - -def unflatten_eps_sig_array( - flat_eps_sig, - eps_shape, - sig_shape, - elem_list, - ): - """Unflatten a 1D array into 2 triangular epsilon and sigma matrices. - - Args: - flat_eps_sig: - eps_shape: - sig_shape: - """ - #| - unflatten_eps_sig_array - - #| - Array Dimension Check - assert eps_shape[0] == eps_shape[1] - assert sig_shape[0] == sig_shape[1] - - N_eps = eps_shape[0] - N_sig = sig_shape[0] - - assert N_eps == N_sig - - N = N_eps - #__| - - len_pars = len(flat_eps_sig) - half_way = int(len_pars / 2) - - epsilon_short = flat_eps_sig[:half_way] - sigma_short = flat_eps_sig[half_way:] - - if len(epsilon_short) == N and len(sigma_short) == N: - pars_mode = "diagonal" - else: - pars_mode = "triangular" - - #| - Methods - def unflatten_tri_matrix_with_defined_cross_terms( - flat_array, - N, - cross_terms_mode="geo" # "geo" or "ave" - ): - """Convert array into a diagonal matrix with defined lower cross-terms. - - The lower-half cross terms are calculated from the diagonal terms. - - Args: - flat_array: - N: - cross_terms_mode: - "geo" or "ave" - """ - #| - unflatten_tri_matrix_with_defined_cross_terms - matrix = np.diag(flat_array) - - # Return list of i, j indices corresponding to the off diagonal - # cross-terms in the lower section of a triangular matrix - all_comb_indices = list(itertools.product( - np.array(range(N)), - np.array(range(N)), - )) - - unique_ij_list = [] - for i_j_pair in all_comb_indices: - i_ind = i_j_pair[0] - j_ind = i_j_pair[1] - if i_ind == j_ind: - continue - unique_ij_list.append(set(i_j_pair)) - - unique_ij_list = list(set([frozenset(item) for item in unique_ij_list])) - unique_ij_list = [list(item) for item in unique_ij_list] - - for i in unique_ij_list: - i.sort(reverse=True) - - for ij_ind in unique_ij_list: - i_ind = ij_ind[0] - j_ind = ij_ind[1] - - i_term = matrix[i_ind][i_ind] - j_term = matrix[j_ind][j_ind] - - average_ij = (i_term + j_term) / 2. - geo_ave_ij = (i_term * j_term) ** (1. / 2.) - - if cross_terms_mode == "geo": - matrix[i_ind][j_ind] = geo_ave_ij - elif cross_terms_mode == "ave": - matrix[i_ind][j_ind] = average_ij - - return(matrix) - #__| - - def unflatten_single_triangular_matrix(flat_array, N): - """Unflatten a single triangular matrix. - - Args: - flat_array: - N: - """ - #| - unflatten_single_traingular_matrix - start_index_list = [] - stop_index_list = [] - j_cnt = 0 - for i in range(N): - start_index_list.append(j_cnt) - increment = (i + 1) - j_cnt += increment - stop_index_list.append(j_cnt) - - rebuilt_matrix = [] - for i_ind, (start_i, stop_i) in enumerate(zip( - start_index_list, - stop_index_list)): - - num_of_0_to_add = N - i_ind - 1 - - final_row = np.append( - flat_array[start_i:stop_i], - num_of_0_to_add * [0.], - ) - - rebuilt_matrix.append(final_row) - - rebuilt_matrix = np.array(rebuilt_matrix) - - return(rebuilt_matrix) - #__| - - #__| - - if pars_mode == "triangular": - epsilon = unflatten_single_triangular_matrix(epsilon_short, N) - sigma = unflatten_single_triangular_matrix(sigma_short, N) - - elif pars_mode == "diagonal": - - epsilon = unflatten_tri_matrix_with_defined_cross_terms( - epsilon_short, - N, - cross_terms_mode="ave", - ) - - sigma = unflatten_tri_matrix_with_defined_cross_terms( - sigma_short, - N, - cross_terms_mode="geo", - ) - - epsilon = pd.DataFrame( - epsilon, - index=elem_list, - columns=elem_list, - ) - - sigma = pd.DataFrame( - sigma, - index=elem_list, - columns=elem_list, - ) - - return(epsilon, sigma) - - #__| - -def fit_LJ_to_DFT( - objective=None, - known_energies=None, - known_forces=None, - atoms_list=None, - elem_list=None, - reference_atoms=None, - epsilon_0=None, - sigma_0=None, - tol=1e-4, - maxiter=50, - maxfun=20, - params_mode="triangular", # "triangular" or "diagonal" - ): - """Fit LJ parameters to DFT energies. - - Args: - objective: - known_energies: - atoms_list: - reference_atoms: - epsilon_0: - sigma_0: - tol: - maxiter: - maxfun: - """ - #| - fit_LJ_to_DFT - atoms_H2 = reference_atoms[0] - atoms_O2 = reference_atoms[1] - atoms_Ir = reference_atoms[2] - - epsilon = epsilon_0 - sigma = sigma_0 - - eps_shape = epsilon.shape - sig_shape = sigma.shape - - # if params_mode == "triangular": - pars = flatten_eps_sig_triangular_matrices( - epsilon, - sigma, - mode=params_mode, # 'triangular' or 'diagonal' - ) - - #| - Minimize Method - opt_out = minimize( - objective, - pars, - - args=( - known_energies, - known_forces, - atoms_list, - eps_shape, - sig_shape, - elem_list, - [ - atoms_H2, - atoms_O2, - atoms_Ir, - ], - - {'Nfeval': 0}, - ), - - # method=None, - method='L-BFGS-B', - - jac=None, - hess=None, - hessp=None, - - # I'm adding a bit to the lower bound to avoid 0. values - # bounds=[(0, None) for i in pars], - bounds=[(0.0001, None) for i in pars], - - constraints=(), - tol=tol, - callback=None, - options={ - "maxiter": maxiter, - "maxfun": maxfun, - - "disp": True, - }, - ) - #__| - - LJ_pars = opt_out.x - - epsilon_out, sigma_out = unflatten_eps_sig_array( - LJ_pars, - eps_shape, - sig_shape, - elem_list, - ) - - with open("opt_params.pickle", "wb") as fle: - pickle.dump((epsilon_out, sigma_out), fle) - - return(epsilon_out, sigma_out) - #__| - -def calc_MSE( - pars, - df_i, - DFT_energies_col, - ref_atoms_list, - ): - """Calculate the mean-squared-error of model on dataset. - - Args: - pars: - df_i: - DFT_energies_col: - ref_atoms_list: - """ - #| - calc_MSE - # df_i = df_orig.iloc[cv_folds_indices[0]["testing"]] - epsilon = pars[0] - sigma = pars[1] - - known_energies = np.array(df_i[DFT_energies_col].tolist()) - atoms_list = df_i["final_atoms"].tolist() - - new_energies_test = calc_lennard_jones_all_atoms( - (epsilon, sigma), - atoms_list, - ref_atoms_list, - # [atoms_H2, atoms_O2, atoms_Ir], - ) - - err = known_energies - new_energies_test - MSE = np.mean(err ** 2) - - return(MSE) - #__| - -def k_fold_cross_validation(data, k=5): - """k-fold cross-validation indices list. - - Args: - data: - k: - """ - #| - k_fold_cross_validation - folds = np.array_split(data, k) - - cv_data = [] - for i_cnt in range(k): - - training_data_i = [] - for j_cnt in np.delete(np.arange(k), i_cnt): - training_data_i = np.concatenate((training_data_i, folds[j_cnt])) - testing_data_i = folds[i_cnt] - - cv_data.append({ - "training": training_data_i, - "testing": testing_data_i, - }) - - return(cv_data) - #__| +#!/usr/bin/env python + +"""Methods for the regression of Lennard Jones parameters to DFT energies. + +Author: Raul A. Flores +""" + +#| - Import Modules +import gc +import pickle + +import itertools + +import numpy as np +import pandas as pd +from scipy.optimize import minimize + +#My Modules +from energetics.formation_energy import calc_formation_energy +from classical_methods.lennard_jones import lennard_jones_sp + +from IPython.display import display, clear_output + +#| - __old__ +# import os +# import copy +# from scipy import stats +# from scipy.optimize import fmin +# import collections +# import plotly.plotly as py +# import plotly.graph_objs as go +# from ase.visualize import view +# from ase import io +# from asap3 import LennardJones +# import math +# from an_data_processing import load_df +# from ase_modules.ase_methods import create_species_element_dict +#__| + +#__| + +def calc_lennard_jones_form_e( + atoms_i=None, + + atoms_H2=None, + atoms_Ir=None, + atoms_O2=None, + + epsilon=None, + sigma=None, + + ): + """Calculate the Lennard Jones formation energy of atoms object. + + Args: + atoms_i: + atoms_H2: + atoms_Ir: + atoms_O2: + epsilon: + sigma: + """ + #| - calc_lennard_jones_form_e + E_H = lennard_jones_sp(epsilon, sigma, atoms_H2) + E_O = lennard_jones_sp(epsilon, sigma, atoms_O2) + E_Ir = lennard_jones_sp(epsilon, sigma, atoms_Ir) + + reference_states = [ + { + "elec_e": E_H, + "element_dict": {"H": 1}, + }, + + { + "elec_e": E_O, + "element_dict": {"O": 1}, + }, + + { + "elec_e": E_Ir, + "element_dict": {"Ir": 1}, + }, + + ] + + E_form_i = calc_formation_energy( + atoms_i, + + lennard_jones_sp( + epsilon, + sigma, + atoms_i, + normalize_per_atom=False, + # return_quantity=return_quantity, + ), + + reference_states, + normalize_per_atom=False, + ) + + E_form_per_atom_i = E_form_i / atoms_i.get_number_of_atoms() + + E_out = E_form_per_atom_i + + return(E_out) + #__| + +def calc_lennard_jones_all_atoms( + pars, + atoms_list, + reference_atoms, + return_quantity="energies" # 'energies' or 'forces' + ): + """Calculate the Lennard Jones formation energies of list of atoms. + + Now can also return list of force arrays for all structures. + + Args: + pars: + atoms_list: + reference_atoms: + return_quantity: + """ + #| - calc_lennard_jones_all_atoms + + epsilon = pars[0] + sigma = pars[1] + + atoms_H2 = reference_atoms[0] + atoms_O2 = reference_atoms[1] + atoms_Ir = reference_atoms[2] + + predicted_energies = [] + predicted_forces = [] + + + if return_quantity == "energies": + for atoms_i in atoms_list: + + #| - Energy + lj_energy_i = calc_lennard_jones_form_e( + atoms_i=atoms_i, + atoms_H2=atoms_H2, + atoms_Ir=atoms_Ir, + atoms_O2=atoms_O2, + epsilon=epsilon, + sigma=sigma, + ) + + predicted_energies.append(lj_energy_i) + #__| + + predicted_energies = np.array(predicted_energies) + return(predicted_energies) + + if return_quantity == "forces": + for atoms_i in atoms_list: + + #| - Forces + lj_forces_i = lennard_jones_sp( + epsilon, + sigma, + atoms_i, + modified_lj=True, + normalize_per_atom=True, + return_quantity="forces", # 'energy', 'forces', 'both', 'energy&forces' + ) + + predicted_forces.append(lj_forces_i) + #__| + + predicted_forces = np.array(predicted_energies) + + return(predicted_forces) + + # predicted_energies = np.array(predicted_energies) + # return(predicted_energies) + #__| + +def objective( + pars, + known_energies, + + known_forces, + + atoms_list, + eps_shape, + sig_shape, + elem_list, + reference_atoms, + info, + ): + """Objective function to be minimized for LJ parameter fitting. + + Args: + pars: + known_energies: + atoms_list: + eps_shape: + sig_shape: + reference_atoms: + """ + #| - objective + epsilon, sigma = unflatten_eps_sig_array( + pars, + eps_shape, + sig_shape, + elem_list, + ) + + #| - Energy Term + err = known_energies - \ + calc_lennard_jones_all_atoms( + (epsilon, sigma), + atoms_list, + reference_atoms, + ) + + MSE = np.mean(err ** 2) + #__| + + #| - Force Term + def calc_sum_of_normals_of_forces(forces): + """Calculate sum of normals of forces on each atom. + + Args: + forces: + List of 3 components of force for each atom + """ + #| - calc_sum_of_normals_of_forces + sum_of_normals = 0. + for atom_forces_i in forces: + sum_of_normals += np.linalg.norm(atom_forces_i) + + return(sum_of_normals) + #__| + + known_sum_of_normals = calc_sum_of_normals_of_forces(known_forces) + + lj_forces = calc_lennard_jones_all_atoms( + (epsilon, sigma), + atoms_list, + reference_atoms, + return_quantity="forces", # 'energies' or 'forces' + ) + + sum_of_structures_forces = 0. + for atom_i in lj_forces: + sum_of_normals_i = calc_sum_of_normals_of_forces(atom_i) + sum_of_structures_forces += sum_of_normals_i + + + print(sum_of_structures_forces / known_sum_of_normals) + + # print(tmp) + + print(30 * "&") + #__| + + + # clear_output(wait=True) + # + # + # display(tmp) + # display(20 * "*") + # + # + # + # display("Iter: " + str(info["Nfeval"])) + # display("MSE: " + str(MSE)) + # display("Epsilon Matrix: ") + # display(epsilon) + # display("Sigma Matrix: ") + # display(sigma) + # display("__________________________") + # + # display(epsilon.values) + # display(sigma.values) + + info["Nfeval"] += 1 + + return(MSE) + #__| + +def flatten_eps_sig_triangular_matrices( + epsilon, + sigma, + mode="traingular", # 'triangular' or 'diagonal' + ): + """Flatten triangular epsilon and sigma matrices into a 1D array. + + Args: + epsilon: + sigma: + """ + #| - flatten_eps_sig_triangular_matrices + epsilon = epsilon.values + sigma = sigma.values + + if mode == "triangular": + flat_eps_sig = np.hstack([ + epsilon.flatten(), + sigma.flatten(), + ]) + + # Remove 0s + flat_eps_sig_no_0s = flat_eps_sig[flat_eps_sig != 0.] + + return(flat_eps_sig_no_0s) + + elif mode == "diagonal": + flat_eps_sig_diag = np.hstack( + [ + epsilon.diagonal(), + sigma.diagonal(), + ] + ) + + return(flat_eps_sig_diag) + #__| + +def unflatten_eps_sig_array( + flat_eps_sig, + eps_shape, + sig_shape, + elem_list, + ): + """Unflatten a 1D array into 2 triangular epsilon and sigma matrices. + + Args: + flat_eps_sig: + eps_shape: + sig_shape: + """ + #| - unflatten_eps_sig_array + + #| - Array Dimension Check + assert eps_shape[0] == eps_shape[1] + assert sig_shape[0] == sig_shape[1] + + N_eps = eps_shape[0] + N_sig = sig_shape[0] + + assert N_eps == N_sig + + N = N_eps + #__| + + len_pars = len(flat_eps_sig) + half_way = int(len_pars / 2) + + epsilon_short = flat_eps_sig[:half_way] + sigma_short = flat_eps_sig[half_way:] + + if len(epsilon_short) == N and len(sigma_short) == N: + pars_mode = "diagonal" + else: + pars_mode = "triangular" + + #| - Methods + def unflatten_tri_matrix_with_defined_cross_terms( + flat_array, + N, + cross_terms_mode="geo" # "geo" or "ave" + ): + """Convert array into a diagonal matrix with defined lower cross-terms. + + The lower-half cross terms are calculated from the diagonal terms. + + Args: + flat_array: + N: + cross_terms_mode: + "geo" or "ave" + """ + #| - unflatten_tri_matrix_with_defined_cross_terms + matrix = np.diag(flat_array) + + # Return list of i, j indices corresponding to the off diagonal + # cross-terms in the lower section of a triangular matrix + all_comb_indices = list(itertools.product( + np.array(range(N)), + np.array(range(N)), + )) + + unique_ij_list = [] + for i_j_pair in all_comb_indices: + i_ind = i_j_pair[0] + j_ind = i_j_pair[1] + if i_ind == j_ind: + continue + unique_ij_list.append(set(i_j_pair)) + + unique_ij_list = list(set([frozenset(item) for item in unique_ij_list])) + unique_ij_list = [list(item) for item in unique_ij_list] + + for i in unique_ij_list: + i.sort(reverse=True) + + for ij_ind in unique_ij_list: + i_ind = ij_ind[0] + j_ind = ij_ind[1] + + i_term = matrix[i_ind][i_ind] + j_term = matrix[j_ind][j_ind] + + average_ij = (i_term + j_term) / 2. + geo_ave_ij = (i_term * j_term) ** (1. / 2.) + + if cross_terms_mode == "geo": + matrix[i_ind][j_ind] = geo_ave_ij + elif cross_terms_mode == "ave": + matrix[i_ind][j_ind] = average_ij + + return(matrix) + #__| + + def unflatten_single_triangular_matrix(flat_array, N): + """Unflatten a single triangular matrix. + + Args: + flat_array: + N: + """ + #| - unflatten_single_traingular_matrix + start_index_list = [] + stop_index_list = [] + j_cnt = 0 + for i in range(N): + start_index_list.append(j_cnt) + increment = (i + 1) + j_cnt += increment + stop_index_list.append(j_cnt) + + rebuilt_matrix = [] + for i_ind, (start_i, stop_i) in enumerate(zip( + start_index_list, + stop_index_list)): + + num_of_0_to_add = N - i_ind - 1 + + final_row = np.append( + flat_array[start_i:stop_i], + num_of_0_to_add * [0.], + ) + + rebuilt_matrix.append(final_row) + + rebuilt_matrix = np.array(rebuilt_matrix) + + return(rebuilt_matrix) + #__| + + #__| + + if pars_mode == "triangular": + epsilon = unflatten_single_triangular_matrix(epsilon_short, N) + sigma = unflatten_single_triangular_matrix(sigma_short, N) + + elif pars_mode == "diagonal": + + epsilon = unflatten_tri_matrix_with_defined_cross_terms( + epsilon_short, + N, + cross_terms_mode="ave", + ) + + sigma = unflatten_tri_matrix_with_defined_cross_terms( + sigma_short, + N, + cross_terms_mode="geo", + ) + + epsilon = pd.DataFrame( + epsilon, + index=elem_list, + columns=elem_list, + ) + + sigma = pd.DataFrame( + sigma, + index=elem_list, + columns=elem_list, + ) + + return(epsilon, sigma) + + #__| + +def fit_LJ_to_DFT( + objective=None, + known_energies=None, + known_forces=None, + atoms_list=None, + elem_list=None, + reference_atoms=None, + epsilon_0=None, + sigma_0=None, + tol=1e-4, + maxiter=50, + maxfun=20, + params_mode="triangular", # "triangular" or "diagonal" + ): + """Fit LJ parameters to DFT energies. + + Args: + objective: + known_energies: + atoms_list: + reference_atoms: + epsilon_0: + sigma_0: + tol: + maxiter: + maxfun: + """ + #| - fit_LJ_to_DFT + atoms_H2 = reference_atoms[0] + atoms_O2 = reference_atoms[1] + atoms_Ir = reference_atoms[2] + + epsilon = epsilon_0 + sigma = sigma_0 + + eps_shape = epsilon.shape + sig_shape = sigma.shape + + # if params_mode == "triangular": + pars = flatten_eps_sig_triangular_matrices( + epsilon, + sigma, + mode=params_mode, # 'triangular' or 'diagonal' + ) + + #| - Minimize Method + opt_out = minimize( + objective, + pars, + + args=( + known_energies, + known_forces, + atoms_list, + eps_shape, + sig_shape, + elem_list, + [ + atoms_H2, + atoms_O2, + atoms_Ir, + ], + + {'Nfeval': 0}, + ), + + # method=None, + method='L-BFGS-B', + + jac=None, + hess=None, + hessp=None, + + # I'm adding a bit to the lower bound to avoid 0. values + # bounds=[(0, None) for i in pars], + bounds=[(0.0001, None) for i in pars], + + constraints=(), + tol=tol, + callback=None, + options={ + "maxiter": maxiter, + "maxfun": maxfun, + + "disp": True, + }, + ) + #__| + + LJ_pars = opt_out.x + + epsilon_out, sigma_out = unflatten_eps_sig_array( + LJ_pars, + eps_shape, + sig_shape, + elem_list, + ) + + with open("opt_params.pickle", "wb") as fle: + pickle.dump((epsilon_out, sigma_out), fle) + + return(epsilon_out, sigma_out) + #__| + +def calc_MSE( + pars, + df_i, + DFT_energies_col, + ref_atoms_list, + ): + """Calculate the mean-squared-error of model on dataset. + + Args: + pars: + df_i: + DFT_energies_col: + ref_atoms_list: + """ + #| - calc_MSE + # df_i = df_orig.iloc[cv_folds_indices[0]["testing"]] + epsilon = pars[0] + sigma = pars[1] + + known_energies = np.array(df_i[DFT_energies_col].tolist()) + atoms_list = df_i["final_atoms"].tolist() + + new_energies_test = calc_lennard_jones_all_atoms( + (epsilon, sigma), + atoms_list, + ref_atoms_list, + # [atoms_H2, atoms_O2, atoms_Ir], + ) + + err = known_energies - new_energies_test + MSE = np.mean(err ** 2) + + return(MSE) + #__| + +def k_fold_cross_validation(data, k=5): + """k-fold cross-validation indices list. + + Args: + data: + k: + """ + #| - k_fold_cross_validation + folds = np.array_split(data, k) + + cv_data = [] + for i_cnt in range(k): + + training_data_i = [] + for j_cnt in np.delete(np.arange(k), i_cnt): + training_data_i = np.concatenate((training_data_i, folds[j_cnt])) + testing_data_i = folds[i_cnt] + + cv_data.append({ + "training": training_data_i, + "testing": testing_data_i, + }) + + return(cv_data) + #__| From 437fde0b722e85ebd86a9752bde6fc912ecd6cf5 Mon Sep 17 00:00:00 2001 From: Raul Flores Date: Tue, 6 Aug 2019 17:20:29 -0700 Subject: [PATCH 05/16] Unimportant changes --- ase_modules/ase_methods.py | 7 +- ase_modules/dft-params.json | 20 +- oxr_reaction/__old__/old.py | 1657 +++++++++++++++++++++++++++++++++++ 3 files changed, 1671 insertions(+), 13 deletions(-) create mode 100644 oxr_reaction/__old__/old.py diff --git a/ase_modules/ase_methods.py b/ase_modules/ase_methods.py index 43642ee..c3c7029 100644 --- a/ase_modules/ase_methods.py +++ b/ase_modules/ase_methods.py @@ -1,3 +1,4 @@ + #!/usr/bin/env python """Methods for ASE scripts, mostly DFT scripts. @@ -395,7 +396,7 @@ def ionic_opt( #__| bader(atoms, spinpol=espresso_params_opt["spinpol"], run_exec=True) - + #__| #__| ************************************************************************** @@ -2155,8 +2156,8 @@ def create_species_element_dict( True: Includes all elements in the periodic table, with 0 values for the elements not present in the atoms object - elems_to_always_include: - List: List of elements to include in the final dict, not including + elems_to_always_include: + List of elements to include in the final dict, not including the elements present in the atoms object. """ diff --git a/ase_modules/dft-params.json b/ase_modules/dft-params.json index 4e54efa..9b06df4 100644 --- a/ase_modules/dft-params.json +++ b/ase_modules/dft-params.json @@ -1,10 +1,10 @@ -{ - "dw": 8000.0, - "kpts": [ - "8", - "8", - "1" - ], - "pw": 800, - "spinpol": true -} +{ + "dw": 8000.0, + "kpts": [ + "8", + "8", + "1" + ], + "pw": 800, + "spinpol": true +} diff --git a/oxr_reaction/__old__/old.py b/oxr_reaction/__old__/old.py new file mode 100644 index 0000000..8e85c38 --- /dev/null +++ b/oxr_reaction/__old__/old.py @@ -0,0 +1,1657 @@ + +#| - __old__ + + # def __create_trace_i__(self, + # x_energy, + # y_energy, + # smart_format_i, + # name_i, + # # legendgroup=None, + # group=None, + # show_data_labels=False, + # ): + # """ + # """ + # #| - __create_trace_i__ + # + # if show_data_labels is True: + # mode_i = "markers+text" + # elif show_data_labels is False: + # mode_i = "markers" + # else: + # print("TEMP TEMP TEMP | __create_trace_i__") + # + # # print(mode_i) + # + # trace_i = go.Scatter( + # x=[x_energy], + # y=[y_energy], + # + # mode=mode_i, + # # mode="markers+text", + # # mode="markers", + # + # name=name_i, + # text=[name_i], + # # text=["TEMP"], + # + # legendgroup=group, + # + # hoverinfo="text", + # + # # hoverinfo=None, + # # hoverinfosrc=None, + # # hoverlabel=None, + # # hoveron=None, + # # hovertext=None, + # # hovertextsrc=None, + # + # # textposition='top right', + # textposition='middle left', + # textfont={ + # # "family": "Courier New, monospace", + # # "family": font_family, + # "size": 10, + # "color": "black", + # }, + # + # marker=dict( + # size=smart_format_i.get("marker_size", 9), + # color=smart_format_i.get(self.marker_color_key, "red"), + # symbol=smart_format_i.get( + # self.marker_shape_key, "circle"), + # line=dict( + # width=smart_format_i.get("marker_border_width", 1.), + # color=smart_format_i.get( + # self.marker_border_color_key, "black"), + # ), + # ), + # ) + # + # return(trace_i) + # #__| + + # + # def __create_volcano_plot__(self, + # show_data_labels=False, + # # smart_format_dict=None, + # ): + # """Create ORR/OER volcano plot. + # + # Args: + # smart_format_dict: + # Optional dictionary that will format data points + # """ + # #| - create_volcano_relations_plot + # + # + # #| - __temp__ | out of the way + # # + # # #| - Default Smart Format Dict + # # smart_format_dict = self.smart_format_dict + # # + # # if smart_format_dict is None: + # # print("No smart format given!") + # # smart_format_dict = [ + # # [{"bulk_system": "IrO3"}, {self.marker_color_key: "green"}], + # # [{"bulk_system": "IrO2"}, {self.marker_color_key: "yellow"}], + # # + # # [{"coverage_type": "o_covered"}, {"symbol": "s"}], + # # [{"coverage_type": "h_covered"}, {"symbol": "^"}], + # # + # # [{"facet": "110"}, {"color1": "red"}], + # # [{"facet": "211"}, {"color1": "green"}], + # # [{"facet": "100"}, {"color1": "black"}], + # # ] + # # #__| + # # + # # #| - Processing Data Points + # # x_data_list = [] + # # y_data_list = [] + # # + # # for series_i in self.ORR_Free_E_Plot.series_list: + # # + # # #| - x-axis energy + # # x_spec = self.x_ax_species + # # if x_spec == "o-oh": + # # e_o = series_i.energy_states_dict["o"] + # # e_oh = series_i.energy_states_dict["oh"] + # # x_ax_energy = e_o - e_oh + # # else: + # # x_ax_energy = series_i.energy_states_dict[x_spec] + # # #__| + # # + # # #| - y-axis limiting potential + # # if self.ORR_Free_E_Plot.rxn_type == "ORR": + # # lim_pot_i = 1.23 - series_i.overpotential + # # + # # elif self.ORR_Free_E_Plot.rxn_type == "OER": + # # lim_pot_i = 1.23 + series_i.overpotential_OER + # # else: + # # print("LSDJFlksdj") + # # #__| + # # + # # #| - Process series_i + # # x_data_list.append(x_ax_energy) + # # y_data_list.append(lim_pot_i) + # # + # # smart_format_i = self.ORR_Free_E_Plot.__create_smart_format_dict__( + # # series_i.properties, + # # smart_format_dict, + # # ) + # # + # # name_i = series_i.series_name + # # + # # if series_i.color is not None: + # # smart_format_i[self.marker_color_key] = series_i.color + # # + # # + # # format_i = smart_format_i + # # + # # if series_i.format_dict: + # # # print(10 * "format_dict is here | ") + # # # print(series_i.format_dict) + # # + # # format_i = series_i.format_dict + # # + # # # x_energy, + # # # y_energy, + # # # smart_format_i, + # # # name_i, + # # # # legendgroup=None, + # # # group=None, + # # + # # trace_i = self.__create_trace_i__( + # # x_ax_energy, + # # lim_pot_i, + # # # smart_format_i, + # # format_i, + # # name_i, + # # group=series_i.group, + # # show_data_labels=show_data_labels, + # # ) + # # + # # self.data_points.append(trace_i) + # # #__| + # # + # # #__| + # # + # # #| - Finding plot axis limits + # # if self.plot_range is None: + # # y_axis_range = [min(y_data_list) - 0.2, max(y_data_list) + 0.2] + # # if self.ORR_Free_E_Plot.rxn_type == "OER": + # # y_axis_range.reverse() + # # else: + # # pass + # # + # # plot_range = { + # # "y": y_axis_range, + # # "x": [min(x_data_list) - 0.2, max(x_data_list) + 0.2], + # # } + # # + # # self.plot_range = plot_range + # # #__| + # # + # #__| + # + # #__| + # + # # + # def create_volcano_lines(self, + # gas_molec_dict=None, + # scaling_dict=None, + # plot_all_legs=True, + # plot_min_max_legs=False, + # trace_priority="top", # 'top' or 'bottom' + # legs_to_plot=[ + # "o2_to_ooh", + # "ooh_to_o", + # "o_to_oh", + # "oh_to_h2o", + # ], + # line_color="black", + # ): + # """Create volcano data traces. + # + # Args: + # gas_molec_dict: + # scaling_dict: + # plot_all_legs: + # plot_min_max_legs: + # trace_priority: + # if 'top', the volcano lines will be placed on the top of the + # plot, if 'bottom' then the data points will by on top of the + # volcano + # """ + # #| - create_volcano_lines + # out_data = [] + # x_range = self.plot_range["x"] + # + # #| - Volcano Legs + # volc_legs = [ + # 'o2_to_ooh', + # 'ooh_to_o', + # 'o_to_oh', + # 'oh_to_h2o', + # ] + # + # energy_dict = { + # 'o2_to_ooh': [], + # 'ooh_to_o': [], + # 'o_to_oh': [], + # 'oh_to_h2o': [], + # } + # + # #| - Create Volcano Legs (LOOP) + # x_axis = np.linspace(x_range[0], x_range[1], num=500) + # for leg_i in volc_legs: + # for x_energy_i in x_axis: + # + # if self.x_ax_species == "oh": + # g_oh = x_energy_i + # g_o_minus_g_oh = None + # + # elif self.x_ax_species == "o-oh": + # g_oh = None + # g_o_minus_g_oh = x_energy_i + # + # energy_dict[leg_i].append( + # lim_U_i( + # g_oh=g_oh, + # g_o_minus_g_oh=g_o_minus_g_oh, + # # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' + # mech_step=leg_i, + # gas_molec_dict=gas_molec_dict, + # scaling_dict=scaling_dict, + # rxn_direction="forward", + # ), + # ) + # #__| + # + # if plot_all_legs: + # + # #| - plot_all_legs + # # hoverinfo_type = "none" + # hoverinfo_type = "name" + # + # trace_o2_to_ooh = go.Scatter( + # x=x_axis, + # y=energy_dict["o2_to_ooh"], + # name="O2->*OOH", + # hoverinfo=hoverinfo_type, + # line=dict( + # color="#e7b8bc", + # width=2, + # dash="solid", + # ) + # ) + # + # trace_ooh_to_o = go.Scatter( + # x=x_axis, + # y=energy_dict["ooh_to_o"], + # name="*OOH->*O", + # hoverinfo=hoverinfo_type, + # line=dict( + # color="#afd7c3", + # width=2, + # dash="solid", + # ) + # ) + # + # trace_o_to_oh = go.Scatter( + # x=x_axis, + # y=energy_dict["o_to_oh"], + # name="*O->*OH", + # hoverinfo=hoverinfo_type, + # line=dict( + # color="#b5c4e2", + # width=2, + # dash="solid", + # ) + # ) + # + # trace_oh_to_h2o = go.Scatter( + # x=x_axis, + # y=energy_dict["oh_to_h2o"], + # name="*OH->H2O", + # hoverinfo=hoverinfo_type, + # line=dict( + # color="#dbcdab", + # width=2, + # dash="solid", + # ) + # ) + # + # if trace_priority == "top": + # out_data.append(trace_o2_to_ooh) + # out_data.append(trace_ooh_to_o) + # out_data.append(trace_o_to_oh) + # out_data.append(trace_oh_to_h2o) + # + # elif trace_priority == "bottom": + # out_data.insert(0, trace_o2_to_ooh) + # out_data.insert(0, trace_ooh_to_o) + # out_data.insert(0, trace_o_to_oh) + # out_data.insert(0, trace_oh_to_h2o) + # #__| + # + # #__| + # + # #| - Minimum Energy Legs + # energy_lists= [] + # for leg_i in legs_to_plot: + # energy_lists.append(energy_dict[leg_i]) + # + # min_max_e_list = [] + # for legs in zip(*energy_lists): + # if self.ORR_Free_E_Plot.rxn_type == "ORR": + # energy_i = min(*legs) + # + # elif self.ORR_Free_E_Plot.rxn_type == "OER": + # energy_i = max(*legs) + # + # min_max_e_list.append(energy_i) + # + # trace_volcano = go.Scatter( + # x=x_axis, + # y=min_max_e_list, + # name="activity volcano", + # hoverinfo="skip", + # line=dict( + # color=line_color, + # width=2, + # # dash="dash", + # dash="5px,2px,5px,2px", + # ) + # ) + # + # if plot_min_max_legs: + # if trace_priority == "top": + # out_data.append(trace_volcano) + # + # elif trace_priority == "bottom": + # out_data.insert(0, trace_volcano) + # #__| + # + # return(out_data) + # #__| + +#__| + + +#| - __old__ + +# +# # ███████ ██████ ██████ ██ ██████ ████████ +# # ██ ██ ██ ██ ██ ██ ██ ██ ██ +# # ███████ ██████ ██████ ██ ██ ██ ██ +# # ██ ██ ██ ██ ██ ██ ██ ██ +# # ███████ ██ ██ ███████ ██ ███████ ██████ ██ +# +# class Scaling_Relations_Plot(): +# """Plot scaling relations and some simple fitting schemes. +# +# Development Notes: +# IDEA: Add vertical lines to connect *O, *OH, and *OOH data points +# """ +# +# #| - Scaling_Relations_Plot *********************************************** +# +# def __init__(self, +# ORR_Free_E_Plot, +# mode="all", +# +# plot_range={ +# "y": [1., 5.], +# "x": [-2., 4.], +# }, +# +# x_ax_species="oh", +# +# marker_color_key="color2", +# marker_border_color_key="color1", +# marker_shape_key="symbol", +# ): +# """ +# Input variables to class instance. +# +# Args: +# ORR_Free_E_Plot: +# mode: +# "all", "ooh_vs_oh", "o_vs_oh" +# """ +# #| - __init__ +# self.ORR_Free_E_Plot = ORR_Free_E_Plot +# +# assert (x_ax_species == "oh"), "Only *OH as the x-axis is allowed now" +# self.x_ax_species = x_ax_species +# self.marker_color_key = marker_color_key +# self.marker_border_color_key = marker_border_color_key +# self.marker_shape_key = marker_shape_key +# +# # ################################################################# +# +# self.data_points = { +# "ooh_vs_oh": [], +# "o_vs_oh": [], +# "oh_vs_oh": [], +# } +# self.data_lines = [] +# +# self.x_range = plot_range["x"] +# self.y_range = plot_range["y"] +# +# # self.layout = self.__create_layout__( +# # title="Scaling Relations", +# # showlegend=True, +# # ) +# +# self.scaling_dict = { +# "ooh": { +# "m": None, +# "b": None, +# }, +# +# "o": { +# "m": None, +# "b": None, +# }, +# +# "oh": { +# "m": 1., +# "b": 0., +# }, +# +# } +# +# self.annotations_list = [] +# +# #__| +# +# def create_scaling_relations_plot(self, +# smart_format_dict=None, +# ): +# """Return plotly data and layout objects for scaling relations. +# +# Args: +# y_ax_spec: +# x_ax_spec: +# """ +# #| - create_scaling_relations_plot +# +# #| - Default Smart Format Dict +# if smart_format_dict is None: +# print("No smart format given!") +# smart_format_dict = [ +# [{"bulk_system": "IrO3"}, {self.marker_color_key: "green"}], +# [{"bulk_system": "IrO2"}, {self.marker_color_key: "yellow"}], +# +# [{"coverage_type": "o_covered"}, {self.marker_shape_key: "s"}], +# [{"coverage_type": "h_covered"}, {self.marker_shape_key: "^"}], +# +# [{"facet": "110"}, {self.marker_border_color_key: "red"}], +# [{"facet": "211"}, {self.marker_border_color_key: "green"}], +# [{"facet": "100"}, {self.marker_border_color_key: "black"}], +# ] +# #__| +# +# #| - Processing Data Points +# for series_i in self.ORR_Free_E_Plot.series_list: +# +# e_oh = series_i.energy_states_dict["oh"] +# e_ooh = series_i.energy_states_dict["ooh"] +# e_o = series_i.energy_states_dict["o"] +# +# +# # Change self.__create_smart_format_dict__ to, +# # self.ORR_Free_E_Plot.__create_smart_format_dict__ +# # TODO +# +# smart_format_i = self.ORR_Free_E_Plot.__create_smart_format_dict__( +# series_i.properties, +# smart_format_dict, +# ) +# +# # This is the old way of getting the name +# # name_i = self.ORR_Free_E_Plot.__create_series_name__(series_i) +# +# name_i = series_i.series_name +# +# if series_i.color is not None: +# smart_format_i[self.marker_color_key] = series_i.color +# +# # NEW, if series has format attached just use that +# if series_i.format_dict: +# smart_format_i = series_i.format_dict +# +# +# #| - ooh_vs_oh +# trace_i = self.__create_trace_i__( +# e_oh, +# e_ooh, +# smart_format_i, +# name_i, +# legendgroup="ooh_vs_oh", +# ) +# # self.data_ooh_oh.append(trace_i) +# self.data_points["ooh_vs_oh"].append(trace_i) +# #__| +# +# #| - o_vs_oh +# trace_i = self.__create_trace_i__( +# e_oh, +# e_o, +# smart_format_i, +# name_i, +# legendgroup="o_vs_oh", +# ) +# # self.data_o_oh.append(trace_i) +# self.data_points["o_vs_oh"].append(trace_i) +# #__| +# +# #| - oh_vs_oh +# trace_i = self.__create_trace_i__( +# e_oh, +# e_oh, +# smart_format_i, +# name_i, +# legendgroup="oh_vs_oh", +# ) +# # self.data_oh_oh.append(trace_i) +# self.data_points["oh_vs_oh"].append(trace_i) +# #__| +# +# #__| +# +# #__| +# +# # Deprecated, delete this later +# def __create_smart_format_dict__(self, property_dict, smart_format_dict): +# """Create smart format dictionary. +# +# Args: +# property_dict: +# smart_format_dict: +# """ +# #| - __create_smart_format_dict__ +# format_dict = {} +# for key_i, value_i in property_dict.items(): +# for format_i in smart_format_dict: +# if list(format_i[0])[0] == key_i: +# if list(format_i[0].values())[0] == value_i: +# format_dict.update(format_i[1]) +# +# return(format_dict) +# #__| +# +# def __create_series_name__(self, series_i): +# """ +# """ +# #| - create_series_name +# name_i = "" +# for key, value in series_i.properties.items(): +# if key == "coverage": +# continue +# +# name_i += str(key) + ": " + str(value) + " | " +# +# return(name_i) +# #__| +# +# def __create_trace_i__(self, +# x_energy, +# y_energy, +# smart_format_i, +# name_i, +# legendgroup=None, +# ): +# """ +# """ +# #| - create_trace_i +# # NOTE Looks like I need to put these in a list here +# x_energy = [x_energy] +# y_energy = [y_energy] +# +# trace_i = go.Scatter( +# x=x_energy, +# y=y_energy, +# text=name_i, +# name=name_i, +# mode="markers", +# legendgroup=legendgroup, +# marker=dict( +# size=smart_format_i.get("marker_size", 9), +# symbol=smart_format_i.get( +# self.marker_shape_key, "circle"), +# color=smart_format_i.get( +# self.marker_color_key, "pink"), +# line=dict( +# # color=smart_format_i[marker_border_color_key], +# color=smart_format_i.get( +# self.marker_border_color_key, "black"), +# width=1., +# ) +# ) +# ) +# +# return(trace_i) +# #__| +# +# # NOTE | This shouldn't be an internal method +# def __create_layout__(self, +# # x_ax_spec="oh", +# title="Scaling Relations", +# showlegend=True, +# layout_dict=None, +# ): +# """Create plotly layout dict. +# +# Args: +# x_ax_spec: +# title: +# showlegend: +# """ +# #| - create_layout +# +# # if x_ax_spec == "" +# if self.x_ax_species == "oh": +# x_ax_title = "Gads,*OH (eV)" +# else: +# x_ax_title = "TEMP" +# +# y_ax_title = "Gads,*OH, " + \ +# "Gads,*O, " + \ +# "Gads,*OOH (eV)" +# +# tick_lab_size = 12 * (4. / 3.) +# axes_lab_size = 14 * (4. / 3.) +# +# # legend_size = 18 +# +# #| - Common Axis Dict +# common_axis_dict = { +# +# # "range": y_axis_range, +# "zeroline": False, +# "showline": True, +# "mirror": 'ticks', +# "linecolor": 'black', +# "showgrid": False, +# +# "titlefont": dict(size=axes_lab_size), +# "tickfont": dict( +# size=tick_lab_size, +# ), +# "ticks": 'inside', +# "tick0": 0, +# "tickcolor": 'black', +# # "dtick": 0.25, +# "ticklen": 2, +# "tickwidth": 1, +# } +# #__| +# +# #| - __old__ +# # x_range_ooh_vs_oh=[0., 3.5], +# # y_range_ooh_vs_oh=[0., 5.], +# # x_range_o_vs_oh=[0., 3.5], +# # y_range_o_vs_oh=[0., 5.], +# +# # if y_ax_spec == "ooh": +# # x_range = self.x_range_ooh_vs_oh +# # elif y_ax_spec == "o": +# # x_range = self.x_range_o_vs_oh +# # elif y_ax_spec == "oh": +# # x_range = self.x_range_oh_vs_oh +# # else: +# # print("Woops - create_layout") +# # +# # if y_ax_spec == "ooh": +# # y_range = self.y_range_ooh_vs_oh +# # elif y_ax_spec == "o": +# # y_range = self._range_o_vs_oh +# # elif y_ax_spec == "oh": +# # y_range = self.y_range_oh_vs_oh +# # else: +# # print("Woops - create_layout") +# #__| +# +# x_range = self.x_range +# y_range = self.y_range +# +# layout_i = { +# "title": title, +# "titlefont": go.layout.title.Font(size=24), +# # "titlefont": go.layout.Titlefont(size=24), +# +# "xaxis": dict( +# common_axis_dict, +# **{ +# "title": x_ax_title, +# "range": x_range, +# }, +# ), +# +# "yaxis": dict( +# common_axis_dict, +# **{ +# "title": y_ax_title, +# "range": y_range, +# }, +# ), +# +# # Margin +# "margin": go.layout.Margin( +# b=50., +# l=50., +# r=50., +# t=50., +# ), +# +# "font": dict( +# family='Arial', +# # size=18, +# color='black', +# ), +# +# "width": 1.5 * 18.7 * 37.795275591, +# "height": 18.7 * 37.795275591, +# +# "showlegend": showlegend, +# +# "legend": dict( +# font=dict( +# size=10, +# ), +# ), +# } +# +# if layout_dict is not None: +# from misc_modules.misc_methods import dict_merge +# dict_merge(layout_i, layout_dict) +# # layout_i = {**layout_i, **layout_dict} +# +# return(layout_i) +# #__| +# +# def __series_excluded__(self, +# properties_i, +# exclude_dict, +# ): +# """Whether to exclude series_i from fitting. +# +# Takes an 'exclude_dict' and the series properties_dict and compares +# them key-by-key. If there is a match, then that series is excluded +# (and the function evaluates to True) +# +# Args: +# properties_i: +# exclude_dict: +# """ +# #| - series_excluded +# exclude_dict_keys = list(exclude_dict.keys()) +# properties_i_keys = list(properties_i.keys()) +# +# shared_keys = list( +# set(exclude_dict_keys).intersection(set(properties_i_keys)), +# ) +# +# if len(shared_keys) < len(exclude_dict_keys): +# print("series_i doesn't have a specific key!") +# +# value_match_list = [] +# for key_i in shared_keys: +# value_match_i = exclude_dict[key_i] == properties_i[key_i] +# value_match_list.append(value_match_i) +# +# +# all_props_match = all(value_match_list) +# +# # if all_props_match: +# # print("Ignoring this series for fitting") +# # +# # else: +# # print("Series not excluded, will include in fitting set") +# +# +# return(all_props_match) +# +# #__| +# +# def fit_scaling_lines(self, +# dependent_species, # 'ooh', 'o', 'oh' +# exclude_dict=None, +# ): +# """Linear fit of either *O or *OOH to *OH +# +# Args: +# dependent_species: +# y-axis species 'ooh' or 'o' +# """ +# #| - fit_scaling_lines +# +# #| - LOOP +# oh_list = [] +# dependent_e_list = [] +# for series_i in self.ORR_Free_E_Plot.series_list: +# +# #| - Excluding series from fitting +# if exclude_dict is not None: +# properties_i = series_i.properties +# exclude_series = self.__series_excluded__( +# properties_i, +# exclude_dict, +# ) +# if exclude_series: +# continue +# #__| +# +# energy_i = series_i.energy_states_dict[dependent_species] +# dependent_e_list.append(energy_i) +# oh_list.append(series_i.energy_states_dict["oh"]) +# +# #__| +# +# X = np.array([[i] for i in oh_list]) +# y = np.array(dependent_e_list) +# +# reg = LinearRegression().fit(X, y) +# +# slope_i = reg.coef_[0] +# intercept_i = reg.intercept_ +# +# print("Scaling fit for ", dependent_species) +# print("intercept_i: ", str(intercept_i)) +# print("slope_i: ", str(slope_i)) +# print("") +# +# out = {"slope": slope_i, "intercept": intercept_i} +# +# self.scaling_dict[dependent_species] = { +# "m": slope_i, +# "b": intercept_i, +# } +# # print("_------__)_Z(*XF(8))") +# +# #| - Equation Annotations +# if dependent_species == "ooh": +# eqn_str_i = ("" + +# "GOOH=" + +# str(round(slope_i, 4)) + +# " GOH+" + +# str(round(intercept_i, 4)) + +# "" +# ) +# +# elif dependent_species == "o": +# eqn_str_i = ("" + +# "GO = " + +# str(round(slope_i, 4)) + +# " GOH+" + +# str(round(intercept_i, 4)) + +# "" +# ) +# +# elif dependent_species == "oh": +# eqn_str_i = ("" + +# "GOH = " + +# str(round(slope_i, 4)) + +# " GOH+" + +# str(round(intercept_i, 4)) + +# "" +# ) +# +# else: +# eqn_str_i = "TEMP TEMP TEMP TEMP | 190213 | RF" +# raise ValueError('A very specific bad thing happened.') +# +# annotation_i = dict( +# x=0., +# y=1., +# xref="paper", +# yref="paper", +# text=eqn_str_i, +# font=dict( +# color="red", +# family="Droid Sans Mono,Overpass", +# size=9. * (4. / 3.), +# ), +# showarrow=False, +# xanchor="left", +# yshift=-11. * (4. / 3.) * len(self.annotations_list), +# xshift=5., +# ) +# +# self.annotations_list.append(annotation_i) +# #__| +# +# +# return(out) +# #__| +# +# def add_ideal_lines(self): +# """Add ideal scaling liknes to plot.""" +# #| - add_ideal_lines +# self.add_line({"slope": 1, "intercept": 3.2}, +# name="*OOH vs *OH Scaling", +# color="black", +# width=1, +# dash="dash", +# ) +# +# self.add_line({"slope": 2, "intercept": 0.}, +# name="*O vs *OH Scaling", +# color="black", +# width=1, +# dash="dash", +# ) +# +# self.add_line({"slope": 1, "intercept": 0.}, +# name="*OH vs *OH Scaling", +# color="black", +# width=1, +# dash="dash", +# ) +# #__| +# +# def add_line(self, +# slope_intercept_dict, +# name="add_lines - TEMP", +# color="black", +# width=1, +# dash="dash", +# ): +# """Add line of form y=mx+b to plot. +# +# Args: +# slope_intercept_dict: +# name: +# color: +# width: +# dash: +# """ +# #| - add_line +# +# # print(slope_intercept_dict) +# +# slope = slope_intercept_dict["slope"] +# intercept = slope_intercept_dict["intercept"] +# +# def scaling_meth(E_OH): +# """ +# """ +# #| - scaling_meth +# out = slope * E_OH + intercept +# +# return(out) +# #__| +# +# LH_bound = self.x_range[0] +# RH_bound = self.x_range[1] +# +# scaling_trace = go.Scatter( +# # x=[self.x_range_ooh_vs_oh[0], self.x_range_ooh_vs_oh[1]], +# x=[LH_bound, RH_bound], +# y=[ +# scaling_meth(LH_bound), +# scaling_meth(RH_bound), +# ], +# # name='Fitted scaling', +# name=name, +# mode='lines', +# line=dict( +# dash=dash, +# color=color, +# width=width, +# ), +# ) +# # self.data_ooh_oh.append(scaling_trace) +# self.data_lines.append(scaling_trace) +# +# # +# # # Annotation +# # ooh_vs_oh_eqn = ("" + +# # "G_*OOH = " + +# # str(round(SC_PLT.scaling_dict["ooh"]["m"], 5)) + +# # " G_*OH + " + +# # str(round(SC_PLT.scaling_dict["ooh"]["b"], 5)) + +# # "" +# # ) +# # +# # o_vs_oh_eqn = ("" + +# # "G_*O = " + +# # str(round(SC_PLT.scaling_dict["o"]["m"], 5)) + +# # " G_*OH + " + +# # str(round(SC_PLT.scaling_dict["o"]["b"], 5)) + +# # "" +# # ) +# +# #__| +# +# +# +# +# +# #| - __old__ +# # def __ideal_ooh_oh_scaling__(self, E_OH): +# # """Return the *OOH adsorption energy given DG_*OH by scaling. +# # +# # Args: +# # E_OH:DG_*OH energy of adsorption +# # """ +# # #| - __ideal_ooh_oh_scaling__ +# # return(E_OH + 3.2) +# # #__| +# # +# # def __ideal_h_oh_scaling__(self, E_OH): +# # """Return the *OOH adsorption energy given DG_*OH by scaling. +# # +# # Args: +# # E_OH: DG_*OH energy of adsorption. +# # """ +# # #| - __ideal_h_oh_scaling__ +# # return(2 * E_OH) +# # #__| +# # +# # def __ideal_oh_oh_scaling__(self, E_OH): +# # """Return the *OH adsorption energy given DG_*OH by scaling. +# # +# # NOTE: TRIVIAL QUANTITY!!!!!!!!!!!!!!!!!!! +# # +# # Args: +# # E_OH: DG_*OH energy of adsorption. +# # """ +# # #| - __ideal_oh_oh_scaling__ +# # return(E_OH) +# # #__| +# # +# #__| +# +# #__| ********************************************************************** + + + + +# # ██ ██ ██████ ██ ██████ ██████ ██ ██████ ████████ +# # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +# # ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ +# # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +# # ████ ██████ ███████ ██████ ███████ ██ ███████ ██████ ██ +# +# class Volcano_Plot(): +# """Class to plot OER/ORR volcano plots. +# +# Development Notes: +# TEMP +# """ +# +# #| - Volcano_Plot ********************************************************* +# +# def __init__(self, +# ORR_Free_E_Plot, +# x_ax_species="o-oh", # 'o-oh' or 'oh' +# smart_format_dict=None, +# plot_range=None, +# marker_color_key="color2", +# marker_border_color_key="color1", +# marker_shape_key="symbol", +# ): +# """ +# Input variables to class instance. +# +# Args: +# ORR_Free_E_Plot: +# mode: +# "all", "ooh_vs_oh", "o_vs_oh" +# plot_range: +# Ex.) +# plot_range={ +# "y": [1., 5.], +# "x": [-2., 4.], +# } +# +# """ +# #| - __init__ +# self.ORR_Free_E_Plot = ORR_Free_E_Plot +# self.x_ax_species = x_ax_species +# self.plot_range = plot_range +# self.smart_format_dict = smart_format_dict +# +# self.data_points = [] +# self.data_lines = [] +# +# self.marker_color_key = marker_color_key +# self.marker_border_color_key = marker_border_color_key +# self.marker_shape_key = marker_shape_key +# +# #__| +# +# # NOTE | Rename this create_volcano_plot +# def create_volcano_relations_plot(self, +# show_data_labels=False, +# # smart_format_dict=None, +# ): +# """Create ORR/OER volcano plot. +# +# Args: +# smart_format_dict: +# Optional dictionary that will format data points +# """ +# #| - create_volcano_relations_plot +# +# #| - Default Smart Format Dict +# smart_format_dict = self.smart_format_dict +# +# if smart_format_dict is None: +# print("No smart format given!") +# smart_format_dict = [ +# [{"bulk_system": "IrO3"}, {self.marker_color_key: "green"}], +# [{"bulk_system": "IrO2"}, {self.marker_color_key: "yellow"}], +# +# [{"coverage_type": "o_covered"}, {"symbol": "s"}], +# [{"coverage_type": "h_covered"}, {"symbol": "^"}], +# +# [{"facet": "110"}, {"color1": "red"}], +# [{"facet": "211"}, {"color1": "green"}], +# [{"facet": "100"}, {"color1": "black"}], +# ] +# #__| +# +# #| - Processing Data Points +# x_data_list = [] +# y_data_list = [] +# +# for series_i in self.ORR_Free_E_Plot.series_list: +# +# #| - x-axis energy +# x_spec = self.x_ax_species +# if x_spec == "o-oh": +# e_o = series_i.energy_states_dict["o"] +# e_oh = series_i.energy_states_dict["oh"] +# x_ax_energy = e_o - e_oh +# else: +# x_ax_energy = series_i.energy_states_dict[x_spec] +# #__| +# +# #| - y-axis limiting potential +# if self.ORR_Free_E_Plot.rxn_type == "ORR": +# lim_pot_i = 1.23 - series_i.overpotential +# +# elif self.ORR_Free_E_Plot.rxn_type == "OER": +# lim_pot_i = 1.23 + series_i.overpotential_OER +# else: +# print("LSDJFlksdj") +# #__| +# +# #| - Process series_i +# x_data_list.append(x_ax_energy) +# y_data_list.append(lim_pot_i) +# +# smart_format_i = self.ORR_Free_E_Plot.__create_smart_format_dict__( +# series_i.properties, +# smart_format_dict, +# ) +# +# name_i = series_i.series_name +# +# if series_i.color is not None: +# smart_format_i[self.marker_color_key] = series_i.color +# +# +# format_i = smart_format_i +# +# if series_i.format_dict: +# format_i = series_i.format_dict +# +# trace_i = self.__create_trace_i__( +# x_ax_energy, +# lim_pot_i, +# # smart_format_i, +# format_i, +# name_i, +# group=series_i.group, +# show_data_labels=show_data_labels, +# ) +# +# self.data_points.append(trace_i) +# #__| +# +# #__| +# +# #| - Finding plot axis limits +# if self.plot_range is None: +# y_axis_range = [min(y_data_list) - 0.2, max(y_data_list) + 0.2] +# if self.ORR_Free_E_Plot.rxn_type == "OER": +# y_axis_range.reverse() +# else: +# pass +# +# plot_range = { +# "y": y_axis_range, +# "x": [min(x_data_list) - 0.2, max(x_data_list) + 0.2], +# } +# +# self.plot_range = plot_range +# #__| +# +# #__| +# +# def create_volcano_lines(self, +# gas_molec_dict=None, +# scaling_dict=None, +# plot_all_legs=True, +# plot_min_max_legs=False, +# trace_priority="top", # 'top' or 'bottom' +# legs_to_plot=[ +# "o2_to_ooh", +# "ooh_to_o", +# "o_to_oh", +# "oh_to_h2o", +# ], +# line_color="black", +# ): +# """Create volcano data traces. +# +# Args: +# gas_molec_dict: +# scaling_dict: +# plot_all_legs: +# plot_min_max_legs: +# trace_priority: +# if 'top', the volcano lines will be placed on the top of the +# plot, if 'bottom' then the data points will by on top of the +# volcano +# """ +# #| - create_volcano_lines +# out_data = [] +# x_range = self.plot_range["x"] +# +# #| - Volcano Legs +# volc_legs = [ +# 'o2_to_ooh', +# 'ooh_to_o', +# 'o_to_oh', +# 'oh_to_h2o', +# ] +# +# energy_dict = { +# 'o2_to_ooh': [], +# 'ooh_to_o': [], +# 'o_to_oh': [], +# 'oh_to_h2o': [], +# } +# +# #| - Create Volcano Legs (LOOP) +# x_axis = np.linspace(x_range[0], x_range[1], num=500) +# for leg_i in volc_legs: +# for x_energy_i in x_axis: +# +# if self.x_ax_species == "oh": +# g_oh = x_energy_i +# g_o_minus_g_oh = None +# +# elif self.x_ax_species == "o-oh": +# g_oh = None +# g_o_minus_g_oh = x_energy_i +# +# energy_dict[leg_i].append( +# lim_U_i( +# g_oh=g_oh, +# g_o_minus_g_oh=g_o_minus_g_oh, +# # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' +# mech_step=leg_i, +# gas_molec_dict=gas_molec_dict, +# scaling_dict=scaling_dict, +# rxn_direction="forward", +# ), +# ) +# #__| +# +# if plot_all_legs: +# +# #| - plot_all_legs +# # hoverinfo_type = "none" +# hoverinfo_type = "name" +# +# trace_o2_to_ooh = go.Scatter( +# x=x_axis, +# y=energy_dict["o2_to_ooh"], +# name="O2->*OOH", +# hoverinfo=hoverinfo_type, +# line=dict( +# color="#e7b8bc", +# width=2, +# dash="solid", +# ) +# ) +# +# trace_ooh_to_o = go.Scatter( +# x=x_axis, +# y=energy_dict["ooh_to_o"], +# name="*OOH->*O", +# hoverinfo=hoverinfo_type, +# line=dict( +# color="#afd7c3", +# width=2, +# dash="solid", +# ) +# ) +# +# trace_o_to_oh = go.Scatter( +# x=x_axis, +# y=energy_dict["o_to_oh"], +# name="*O->*OH", +# hoverinfo=hoverinfo_type, +# line=dict( +# color="#b5c4e2", +# width=2, +# dash="solid", +# ) +# ) +# +# trace_oh_to_h2o = go.Scatter( +# x=x_axis, +# y=energy_dict["oh_to_h2o"], +# name="*OH->H2O", +# hoverinfo=hoverinfo_type, +# line=dict( +# color="#dbcdab", +# width=2, +# dash="solid", +# ) +# ) +# +# if trace_priority == "top": +# out_data.append(trace_o2_to_ooh) +# out_data.append(trace_ooh_to_o) +# out_data.append(trace_o_to_oh) +# out_data.append(trace_oh_to_h2o) +# +# elif trace_priority == "bottom": +# out_data.insert(0, trace_o2_to_ooh) +# out_data.insert(0, trace_ooh_to_o) +# out_data.insert(0, trace_o_to_oh) +# out_data.insert(0, trace_oh_to_h2o) +# #__| +# +# #__| +# +# #| - Minimum Energy Legs +# energy_lists= [] +# for leg_i in legs_to_plot: +# energy_lists.append(energy_dict[leg_i]) +# +# min_max_e_list = [] +# for legs in zip(*energy_lists): +# if self.ORR_Free_E_Plot.rxn_type == "ORR": +# energy_i = min(*legs) +# +# elif self.ORR_Free_E_Plot.rxn_type == "OER": +# energy_i = max(*legs) +# +# min_max_e_list.append(energy_i) +# +# trace_volcano = go.Scatter( +# x=x_axis, +# y=min_max_e_list, +# name="activity volcano", +# hoverinfo="skip", +# line=dict( +# color=line_color, +# width=2, +# # dash="dash", +# dash="5px,2px,5px,2px", +# ) +# ) +# +# if plot_min_max_legs: +# if trace_priority == "top": +# out_data.append(trace_volcano) +# +# elif trace_priority == "bottom": +# out_data.insert(0, trace_volcano) +# #__| +# +# return(out_data) +# #__| +# +# def __create_trace_i__(self, +# x_energy, +# y_energy, +# smart_format_i, +# name_i, +# # legendgroup=None, +# group=None, +# show_data_labels=False, +# ): +# """ +# """ +# #| - __create_trace_i__ +# +# if show_data_labels is True: +# mode_i = "markers+text" +# elif show_data_labels is False: +# mode_i = "markers" +# else: +# print("TEMP TEMP TEMP | __create_trace_i__") +# +# # print(mode_i) +# +# trace_i = go.Scatter( +# x=[x_energy], +# y=[y_energy], +# +# mode=mode_i, +# # mode="markers+text", +# # mode="markers", +# +# name=name_i, +# text=[name_i], +# # text=["TEMP"], +# +# legendgroup=group, +# +# hoverinfo="text", +# +# # hoverinfo=None, +# # hoverinfosrc=None, +# # hoverlabel=None, +# # hoveron=None, +# # hovertext=None, +# # hovertextsrc=None, +# +# # textposition='top right', +# textposition='middle left', +# textfont={ +# # "family": "Courier New, monospace", +# # "family": font_family, +# "size": 10, +# "color": "black", +# }, +# +# marker=dict( +# size=smart_format_i.get("marker_size", 9), +# color=smart_format_i.get(self.marker_color_key, "red"), +# symbol=smart_format_i.get( +# self.marker_shape_key, "circle"), +# line=dict( +# width=smart_format_i.get("marker_border_width", 1.), +# color=smart_format_i.get( +# self.marker_border_color_key, "black"), +# ), +# ), +# ) +# +# return(trace_i) +# #__| +# +# def get_plotly_layout(self, +# showlegend=False, +# width=9. * 37.795275591, +# height=9. * 37.795275591, +# layout_dict=None, +# ): +# """ +# """ +# #| - get_plotly_layout +# +# #| - Properties +# # plot_title="FED" +# plot_title = None +# # plot_title_size = 18 +# # tick_lab_size = 9 * (4. / 3.) +# tick_lab_size = 8 * (4. / 3.) +# axes_lab_size = 9 * (4. / 3.) +# legend_size = 18 +# # font_family="Computer Modern" # "Courier New, monospace" +# font_family = "Arial" # "Courier New, monospace" +# #__| +# +# # self.x_ax_spec +# +# if self.x_ax_species == "oh": +# # xaxis_title = "dG_*OH (eV)" +# xaxis_title = "dGOH (eV)" +# elif self.x_ax_species == "o-oh": +# # xaxis_title = "dG_*OH - dG_*O (eV)" +# xaxis_title = "dGO - dGOH (eV)" +# +# # layout["margin"] = go.layout.Margin( +# # b=50., +# # l=50., +# # r=50., +# # t=50., +# # # pad=20., +# # ) +# +# layout = { +# "title": plot_title, +# +# "font": { +# "family": font_family, +# "color": "black", +# }, +# +# #| - Axes ----------------------------------------------------- +# +# #| - yaxis +# "yaxis": { +# "title": "Limiting Potential (V)", +# # "title": "$\\Delta G (ev)$", +# +# "range": self.plot_range["y"], +# "zeroline": False, +# "showline": True, +# "mirror": 'ticks', +# # "linecolor": 'red', +# "linecolor": 'black', +# "showgrid": False, +# +# "titlefont": dict(size=axes_lab_size), +# +# "tickfont": dict( +# size=tick_lab_size, +# ), +# "ticks": 'inside', +# "tick0": 0, +# "tickcolor": 'black', +# "dtick": 0.1, +# "ticklen": 2, +# "tickwidth": 1, +# }, +# #__| +# +# #| - xaxis +# "xaxis": { +# # "title": "$\\Delta G_{OH} (ev)$", +# "title": xaxis_title, +# "range": self.plot_range["x"], +# "zeroline": False, +# "showline": True, +# "mirror": True, +# # "linecolor": 'red', +# "linecolor": 'black', +# "showgrid": False, +# "titlefont": dict(size=axes_lab_size), +# "showticklabels": True, +# "ticks": 'inside', +# "tick0": 0, +# "dtick": 0.2, +# "ticklen": 2, +# "tickwidth": 1, +# "tickcolor": 'black', +# "tickfont": dict( +# size=tick_lab_size, +# ), +# }, +# #__| +# +# #__| +# +# "margin": go.layout.Margin( +# b=50., +# l=50., +# r=50., +# t=50., +# ), +# +# # "paper_bgcolor": 'rgba(0,0,0,0)', +# "plot_bgcolor": 'rgba(0,0,0,0)', +# +# #| - Legend --------------------------------------------------- +# "legend": { +# "traceorder": "normal", +# "font": dict(size=legend_size), +# "x": 0., +# "y": -0.1, +# # "xanchor": "left", +# "yanchor": "top", +# }, +# +# # "showlegend": False, +# "showlegend": showlegend, +# +# #__| +# +# } +# +# #| - Plot Size Settings +# # bottom_margin_size = 2.5 * 9. * 37.795275591 +# plot_size_settings = { +# "width": width, +# "height": height, +# +# # "width": 9. * 37.795275591, +# # "height": 9 * 37.795275591, +# +# # "margin": go.layout.Margin({ +# # "l": 50, +# # "r": 50, +# # # "b": bottom_margin_size, +# # # "b": 100, +# # "b": 1200, +# # "t": 10, +# # "pad": 4, +# # }), +# } +# +# #__| +# +# layout = {**layout, **plot_size_settings} +# +# #| - Applying Layout override dict +# if layout_dict is not None: +# from misc_modules.misc_methods import dict_merge +# dict_merge(layout, layout_dict) +# +# # layout_i = {**layout_i, **layout_dict} +# +# #__| +# +# return(layout) +# +# #__| +# +# +# #__| ********************************************************************** +#__| From b3f96e45c561b6e196dfc3d0dc992ea7717635eb Mon Sep 17 00:00:00 2001 From: Raul Flores Date: Tue, 6 Aug 2019 17:20:47 -0700 Subject: [PATCH 06/16] Refactoring oxr classes --- .../oxr_plot_2d_volcano.py | 635 +++++++----------- .../oxr_plotting_classes/oxr_plot_fed.py | 258 ++++--- .../oxr_plotting_classes/oxr_plot_scaling.py | 345 ++++++---- .../oxr_plotting_classes/oxr_plot_volcano.py | 71 +- 4 files changed, 639 insertions(+), 670 deletions(-) diff --git a/oxr_reaction/oxr_plotting_classes/oxr_plot_2d_volcano.py b/oxr_reaction/oxr_plotting_classes/oxr_plot_2d_volcano.py index 28fdcec..9fbcf96 100644 --- a/oxr_reaction/oxr_plotting_classes/oxr_plot_2d_volcano.py +++ b/oxr_reaction/oxr_plotting_classes/oxr_plot_2d_volcano.py @@ -1,3 +1,26 @@ +#!/usr/bin/env python + +"""ORR FED plotting class. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import numpy as np +import pandas as pd +import copy + +from sklearn.linear_model import LinearRegression + +import plotly.graph_objs as go + +pd.options.mode.chained_assignment = None + +from oxr_reaction.oxr_series import ORR_Free_E_Series +from oxr_reaction.adsorbate_scaling import lim_U_i +#__| + + # ██ ██ ██████ ██ ██████ ██████ ██ ██████ ████████ # ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ # ██ ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ @@ -15,436 +38,239 @@ class Volcano_Plot_2D(): def __init__(self, ORR_Free_E_Plot, + plot_range=None, ): """ """ #| - __init__ self.ORR_Free_E_Plot = ORR_Free_E_Plot - #__| - def create_volcano_relations_plot(self, - show_data_labels=False, - # smart_format_dict=None, - ): - """Create ORR/OER volcano plot. + if plot_range is None: + self.plot_range = { + "x": [+0.5, +2.5], + "y": [-0.5, +2.0], + } + else: + self.plot_range = plot_range - Args: - smart_format_dict: - Optional dictionary that will format data points - """ - #| - create_volcano_relations_plot + # ##################################################################### - #| - Default Smart Format Dict - smart_format_dict = self.smart_format_dict - if smart_format_dict is None: - print("No smart format given!") - smart_format_dict = [ - [{"bulk_system": "IrO3"}, {self.marker_color_key: "green"}], - [{"bulk_system": "IrO2"}, {self.marker_color_key: "yellow"}], + self.contour_trace = self.__create_contour_trace__() + self.data_point_traces = self.__create_data_point_traces__() - [{"coverage_type": "o_covered"}, {"symbol": "s"}], - [{"coverage_type": "h_covered"}, {"symbol": "^"}], - [{"facet": "110"}, {"color1": "red"}], - [{"facet": "211"}, {"color1": "green"}], - [{"facet": "100"}, {"color1": "black"}], - ] + data = [] + data += self.data_point_traces + data.insert(0, self.contour_trace) + self.traces = data #__| - #| - Processing Data Points - x_data_list = [] - y_data_list = [] - - for series_i in self.ORR_Free_E_Plot.series_list: + def __create_contour_trace__(self): + """ + """ + #| - __create_contour_trace__ + x_range_bounds = self.plot_range["x"] + y_range_bounds = self.plot_range["y"] - #| - x-axis energy - x_spec = self.x_ax_species - if x_spec == "o-oh": - e_o = series_i.energy_states_dict["o"] - e_oh = series_i.energy_states_dict["oh"] - x_ax_energy = e_o - e_oh - else: - x_ax_energy = series_i.energy_states_dict[x_spec] - #__| - #| - y-axis limiting potential - if self.ORR_Free_E_Plot.rxn_type == "ORR": - lim_pot_i = 1.23 - series_i.overpotential + x_range = np.arange( + x_range_bounds[0] - 1., + x_range_bounds[1] + 1., + 0.01) - elif self.ORR_Free_E_Plot.rxn_type == "OER": - lim_pot_i = 1.23 + series_i.overpotential_OER - else: - print("LSDJFlksdj") - #__| + y_range = np.arange( + y_range_bounds[0] - 1., + y_range_bounds[1] + 1., + 0.01) - #| - Process series_i - x_data_list.append(x_ax_energy) - y_data_list.append(lim_pot_i) + # x_range = np.arange(0.9, 2, 0.01) + # y_range = np.arange(-0.5, 2., 0.01) - smart_format_i = self.ORR_Free_E_Plot.__create_smart_format_dict__( - series_i.properties, - smart_format_dict, - ) + X, Y = np.meshgrid(x_range, y_range) - name_i = series_i.series_name + for ind_i, x_i in enumerate(x_range): + for ind_j, oh_j in enumerate(y_range): + X[ind_j][ind_i] = self.overpotential3(x_i, oh_j) - if series_i.color is not None: - smart_format_i[self.marker_color_key] = series_i.color + series_i = go.Contour( + z=X, + x=x_range, + y=y_range, + zmin=0.2, + zmax=1.2, + # zmax=1.2, - format_i = smart_format_i + # ncontours=180, + ncontours=20, - if series_i.format_dict: - # print(10 * "format_dict is here | ") - # print(series_i.format_dict) + #| - Color Scale + colorscale='Jet', + reversescale=True, + autocontour=True, - format_i = series_i.format_dict + # showscale=False, + #__| - # x_energy, - # y_energy, - # smart_format_i, - # name_i, - # # legendgroup=None, - # group=None, + #| - Colorbar + colorbar=go.contour.ColorBar( + x=None, + xanchor=None, + xpad=None, + y=None, + yanchor=None, + ), + #__| - trace_i = self.__create_trace_i__( - x_ax_energy, - lim_pot_i, - # smart_format_i, - format_i, - name_i, - group=series_i.group, - show_data_labels=show_data_labels, + #| - Line + line=go.contour.Line( + color="white", + # dash="dot", + smoothing=1., + width=0.5, ) - - self.data_points.append(trace_i) + ) #__| + return(series_i) #__| - #| - Finding plot axis limits - if self.plot_range is None: - y_axis_range = [min(y_data_list) - 0.2, max(y_data_list) + 0.2] - if self.ORR_Free_E_Plot.rxn_type == "OER": - y_axis_range.reverse() - else: - pass - - plot_range = { - "y": y_axis_range, - "x": [min(x_data_list) - 0.2, max(x_data_list) + 0.2], - } - self.plot_range = plot_range - #__| + def __create_data_point_traces__(self): + """ + """ + #| - __create_data_point_traces__ + data_list = [] + for sys_i in self.ORR_Free_E_Plot.series_list: + trace_i = self.__create_scatter_trace_i__(sys_i) + data_list.append(trace_i) + + return(data_list) #__| - def create_volcano_lines(self, - gas_molec_dict=None, - scaling_dict=None, - plot_all_legs=True, - plot_min_max_legs=False, - trace_priority="top", # 'top' or 'bottom' - legs_to_plot=[ - "o2_to_ooh", - "ooh_to_o", - "o_to_oh", - "oh_to_h2o", - ], - line_color="black", + def __create_scatter_trace_i__(self, + sys_i, + smart_format_i=None, ): - """Create volcano data traces. - - Args: - gas_molec_dict: - scaling_dict: - plot_all_legs: - plot_min_max_legs: - trace_priority: - if 'top', the volcano lines will be placed on the top of the - plot, if 'bottom' then the data points will by on top of the - volcano """ - #| - create_volcano_lines - out_data = [] - x_range = self.plot_range["x"] + """ + #| - __create_trace_i__ + trace_i = go.Scatter( + x=[sys_i.energy_states_dict["o"] - sys_i.energy_states_dict["oh"]], + y=[sys_i.energy_states_dict["oh"]], + mode='markers', - #| - Volcano Legs - volc_legs = [ - 'o2_to_ooh', - 'ooh_to_o', - 'o_to_oh', - 'oh_to_h2o', - ] - - energy_dict = { - 'o2_to_ooh': [], - 'ooh_to_o': [], - 'o_to_oh': [], - 'oh_to_h2o': [], - } + # name=sys_i.series_name, + name=sys_i.series_name, + + #
+ + marker=dict( + size=20, + symbol=sys_i.format_dict["symbol_i"], + color=sys_i.format_dict["color_2"], + line=dict( + width=2, + color=sys_i.format_dict["color_1"], + ), + ), + ) - #| - Create Volcano Legs (LOOP) - x_axis = np.linspace(x_range[0], x_range[1], num=500) - for leg_i in volc_legs: - for x_energy_i in x_axis: - - if self.x_ax_species == "oh": - g_oh = x_energy_i - g_o_minus_g_oh = None - - elif self.x_ax_species == "o-oh": - g_oh = None - g_o_minus_g_oh = x_energy_i - - energy_dict[leg_i].append( - lim_U_i( - g_oh=g_oh, - g_o_minus_g_oh=g_o_minus_g_oh, - # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' - mech_step=leg_i, - gas_molec_dict=gas_molec_dict, - scaling_dict=scaling_dict, - rxn_direction="forward", - ), - ) + return(trace_i) #__| - if plot_all_legs: - #| - plot_all_legs - # hoverinfo_type = "none" - hoverinfo_type = "name" - trace_o2_to_ooh = go.Scatter( - x=x_axis, - y=energy_dict["o2_to_ooh"], - name="O2->*OOH", - hoverinfo=hoverinfo_type, - line=dict( - color="#e7b8bc", - width=2, - dash="solid", - ) - ) - trace_ooh_to_o = go.Scatter( - x=x_axis, - y=energy_dict["ooh_to_o"], - name="*OOH->*O", - hoverinfo=hoverinfo_type, - line=dict( - color="#afd7c3", - width=2, - dash="solid", - ) - ) - trace_o_to_oh = go.Scatter( - x=x_axis, - y=energy_dict["o_to_oh"], - name="*O->*OH", - hoverinfo=hoverinfo_type, - line=dict( - color="#b5c4e2", - width=2, - dash="solid", - ) - ) - trace_oh_to_h2o = go.Scatter( - x=x_axis, - y=energy_dict["oh_to_h2o"], - name="*OH->H2O", - hoverinfo=hoverinfo_type, - line=dict( - color="#dbcdab", - width=2, - dash="solid", - ) - ) - if trace_priority == "top": - out_data.append(trace_o2_to_ooh) - out_data.append(trace_ooh_to_o) - out_data.append(trace_o_to_oh) - out_data.append(trace_oh_to_h2o) - - elif trace_priority == "bottom": - out_data.insert(0, trace_o2_to_ooh) - out_data.insert(0, trace_ooh_to_o) - out_data.insert(0, trace_o_to_oh) - out_data.insert(0, trace_oh_to_h2o) - #__| - #__| - #| - Minimum Energy Legs - energy_lists= [] - for leg_i in legs_to_plot: - energy_lists.append(energy_dict[leg_i]) - - min_max_e_list = [] - for legs in zip(*energy_lists): - if self.ORR_Free_E_Plot.rxn_type == "ORR": - energy_i = min(*legs) - - elif self.ORR_Free_E_Plot.rxn_type == "OER": - energy_i = max(*legs) - - min_max_e_list.append(energy_i) - - trace_volcano = go.Scatter( - x=x_axis, - y=min_max_e_list, - name="activity volcano", - hoverinfo="skip", - line=dict( - color=line_color, - width=2, - # dash="dash", - dash="5px,2px,5px,2px", - ) - ) - if plot_min_max_legs: - if trace_priority == "top": - out_data.append(trace_volcano) + # ######################################################################### + # ######################################################################### - elif trace_priority == "bottom": - out_data.insert(0, trace_volcano) - #__| + def ooh_oh_scaling(self, doh): + """ooh_oh_scaling equation.""" + #| - ooh_oh_scaling + #like ambars + #dooh=0.5*doh + 3.0 #O + #normal one + # dooh = doh + 3.2 - return(out_data) - #__| + # m = 0.8926 + # b = 3.174 - def __create_trace_i__(self, - x_energy, - y_energy, - smart_format_i, - name_i, - # legendgroup=None, - group=None, - show_data_labels=False, - ): - """ - """ - #| - __create_trace_i__ + m = 0.9104 + b = 3.144 - if show_data_labels is True: - mode_i = "markers+text" - elif show_data_labels is False: - mode_i = "markers" - else: - print("TEMP TEMP TEMP | __create_trace_i__") + # 0.9104 x + 3.144 + # 1.302 x + 1.338 - # print(mode_i) + dooh = m * doh + b # TEMP - trace_i = go.Scatter( - x=[x_energy], - y=[y_energy], - - mode=mode_i, - # mode="markers+text", - # mode="markers", - - name=name_i, - text=[name_i], - # text=["TEMP"], - - legendgroup=group, - - hoverinfo="text", - - # hoverinfo=None, - # hoverinfosrc=None, - # hoverlabel=None, - # hoveron=None, - # hovertext=None, - # hovertextsrc=None, - - # textposition='top right', - textposition='middle left', - textfont={ - # "family": "Courier New, monospace", - # "family": font_family, - "size": 10, - "color": "black", - }, + return(dooh) + #__| - marker=dict( - size=smart_format_i.get("marker_size", 9), - color=smart_format_i.get(self.marker_color_key, "red"), - symbol=smart_format_i.get( - self.marker_shape_key, "circle"), - line=dict( - width=smart_format_i.get("marker_border_width", 1.), - color=smart_format_i.get( - self.marker_border_color_key, "black"), - ), - ), - ) + def overpotential3(self, x, doh): + """Calculate overpotential (version 3). - return(trace_i) + Args: + x: + doh: + """ + #| - overpotential3 + dooh = self.ooh_oh_scaling(doh) + dg14 = [doh, x, dooh - (x + doh), -dooh + 4.92] + m = max(dg14) + return(m - 1.23) + + #return doh*do #__| + # ######################################################################### + # ######################################################################### + + def get_plotly_layout(self, showlegend=False, - width=9. * 37.795275591, - height=9. * 37.795275591, layout_dict=None, + + # height=9. * 37.795275591, + # width=9. * 37.795275591, ): """ """ #| - get_plotly_layout + y_range = self.plot_range["y"] + x_range = self.plot_range["x"] - #| - Properties - # plot_title="FED" - plot_title = None - # plot_title_size = 18 - # tick_lab_size = 9 * (4. / 3.) tick_lab_size = 8 * (4. / 3.) axes_lab_size = 9 * (4. / 3.) - legend_size = 18 - # font_family="Computer Modern" # "Courier New, monospace" - font_family = "Arial" # "Courier New, monospace" - #__| - - # self.x_ax_spec - - if self.x_ax_species == "oh": - # xaxis_title = "dG_*OH (eV)" - xaxis_title = "dGOH (eV)" - elif self.x_ax_species == "o-oh": - # xaxis_title = "dG_*OH - dG_*O (eV)" - xaxis_title = "dGO - dGOH (eV)" - - # layout["margin"] = go.layout.Margin( - # b=50., - # l=50., - # r=50., - # t=50., - # # pad=20., - # ) layout = { - "title": plot_title, + "title": None, + + #| - Font Settings "font": { - "family": font_family, + "family": "Arial", # "Courier New, monospace" "color": "black", }, + #__| - #| - Axes ----------------------------------------------------- + #| - Axes --------------------------------------------------------- #| - yaxis "yaxis": { - "title": "Limiting Potential (V)", + "title": "ΔGOH (eV)", + # "title": "$\\Delta G (ev)$", + "range": y_range, - "range": self.plot_range["y"], "zeroline": False, "showline": True, "mirror": 'ticks', @@ -457,10 +283,12 @@ def get_plotly_layout(self, "tickfont": dict( size=tick_lab_size, ), - "ticks": 'inside', - "tick0": 0, + "ticks": 'outside', + + # "tick0": 0, + # "dtick": 0.1, + "tickcolor": 'black', - "dtick": 0.1, "ticklen": 2, "tickwidth": 1, }, @@ -468,9 +296,9 @@ def get_plotly_layout(self, #| - xaxis "xaxis": { - # "title": "$\\Delta G_{OH} (ev)$", - "title": xaxis_title, - "range": self.plot_range["x"], + "title": "ΔGO - ΔGOH (eV)", + "range": x_range, + "zeroline": False, "showline": True, "mirror": True, @@ -479,9 +307,11 @@ def get_plotly_layout(self, "showgrid": False, "titlefont": dict(size=axes_lab_size), "showticklabels": True, - "ticks": 'inside', - "tick0": 0, - "dtick": 0.2, + "ticks": 'outside', + + # "tick0": 0, + # "dtick": 0.2, + "ticklen": 2, "tickwidth": 1, "tickcolor": 'black', @@ -493,69 +323,76 @@ def get_plotly_layout(self, #__| + #| - Margins ------------------------------------------------------ "margin": go.layout.Margin( b=50., l=50., - r=50., - t=50., + r=30., + t=30., ), - - # "paper_bgcolor": 'rgba(0,0,0,0)', - "plot_bgcolor": 'rgba(0,0,0,0)', + #__| #| - Legend --------------------------------------------------- - "legend": { - "traceorder": "normal", - "font": dict(size=legend_size), - "x": 0., - "y": -0.1, - # "xanchor": "left", - "yanchor": "top", - }, + "legend": go.layout.Legend( + x=1.2, + xanchor=None, + y=0.98, + yanchor="top", + font=dict(size=18), + bgcolor="rgba(200,255,255,0.85)", + + arg=None, + bordercolor=None, + borderwidth=None, + itemclick=None, + itemdoubleclick=None, + itemsizing=None, + orientation=None, + tracegroupgap=None, + traceorder=None, + uirevision=None, + valign=None, + ), - # "showlegend": False, - "showlegend": showlegend, + "showlegend": True, + # "showlegend": showlegend, + #__| + #| - Plot Size + "width": 37 * 37.795275591, + "height": 23 * 37.795275591, #__| - } + "paper_bgcolor": 'rgba(255,255,255,1.)', + # "plot_bgcolor": 'rgba(3,3,3,0.3)', + # "plot_bgcolor": 'rgba(0,0,0,0)', - #| - Plot Size Settings - # bottom_margin_size = 2.5 * 9. * 37.795275591 - plot_size_settings = { - "width": width, - "height": height, - - # "width": 9. * 37.795275591, - # "height": 9 * 37.795275591, - - # "margin": go.layout.Margin({ - # "l": 50, - # "r": 50, - # # "b": bottom_margin_size, - # # "b": 100, - # "b": 1200, - # "t": 10, - # "pad": 4, - # }), } + #| - Plot Size Settings + # # bottom_margin_size = 2.5 * 9. * 37.795275591 + # plot_size_settings = { + # + # # "width": 37 * 37.795275591, + # # "height": 23 * 37.795275591, + # + # # "width": 25 * 37.795275591, + # # "height": 17 * 37.795275591, + # } + # layout = {**layout, **plot_size_settings} #__| - layout = {**layout, **plot_size_settings} + layout = go.Layout(**layout) - #| - Applying Layout override dict if layout_dict is not None: - from misc_modules.misc_methods import dict_merge - dict_merge(layout, layout_dict) + layout.update(layout_dict) - # layout_i = {**layout_i, **layout_dict} + # from misc_modules.misc_methods import dict_merge + # dict_merge(layout, layout_dict) - #__| - return(layout) + return(layout) # COMBAK #__| - #__| ********************************************************************** diff --git a/oxr_reaction/oxr_plotting_classes/oxr_plot_fed.py b/oxr_reaction/oxr_plotting_classes/oxr_plot_fed.py index 49448c2..114e6b2 100644 --- a/oxr_reaction/oxr_plotting_classes/oxr_plot_fed.py +++ b/oxr_reaction/oxr_plotting_classes/oxr_plot_fed.py @@ -18,9 +18,6 @@ from oxr_reaction.oxr_series import ORR_Free_E_Series from oxr_reaction.adsorbate_scaling import lim_U_i - -# from orr_reaction.orr_series import ORR_Free_E_Series -# from orr_reaction.adsorbate_scaling import lim_U_i #__| @@ -40,8 +37,6 @@ class Free_Energy_Plot(): def __init__(self, ORR_Free_E_Plot, - - bias=0., opt_name=None, properties=None, @@ -114,7 +109,6 @@ def create_fed_plot(self, overpotential_type=self.rxn_type, ) - # plot_data.append(data_i) plot_data += data_i return(plot_data) @@ -147,9 +141,16 @@ def ideal_ORR_series(self): df_ideal = pd.DataFrame(ideal_data_list) + # system_properties={"system": sys_name_i}, + # name_i=sys_name_i, + # format_dict=format_dict_i, + # opt_name=sys_name_i.replace("_", " "), + self.ORR_Free_E_Plot.add_series( df_ideal, plot_mode="full_lines", # ########## + format_dict={"opacity": 0.}, + name_i="Ideal ORR Catalyst", opt_name="Ideal ORR Catalyst", smart_format=False, color=None, @@ -223,7 +224,6 @@ def plot_fed_series(self, e_list = series_i.energy_lst e_list = series_i.apply_bias(bias, e_list) - for n, i in enumerate(e_list): if np.isnan(i) is True: e_list[n] = None @@ -429,18 +429,17 @@ def __create_plotly_series__(self, if series_i.format_dict: format_i = series_i.format_dict - print(format_i) else: format_i = plot_parameter_dict - #| - Plotly Scatter Plot Instances + #| - Plotly Scatter Plot Instances ************************************ #| - Thick horizontal state lines data_1 = go.Scatter( x=new_x_dat, y=new_y_dat, legendgroup=group, - showlegend=True, + showlegend=False, name=name, hoverinfo="none", # TEMP - 180317 @@ -483,23 +482,24 @@ def __create_plotly_series__(self, #__| #| - Points in middle of energy states (For convienient hover) - # 'color_1': 'black', 'color_2': 'blue', 'symbol_i': 'circle', 'symbol_i__matplotlib': 'o', 'marker_size': 18 - - format_i.get("color_2", "black") data_3 = go.Scatter( x=short_x, y=short_y, legendgroup=group, name=name, - showlegend=False, + showlegend=True, hoverinfo="y+text", - text=hover_text, + # hoverinfo="y+name", + # text=hover_text, + text=name, marker=dict( - size=format_i.get("marker_size", 10), + size=format_i.get("marker_size", 0), color=format_i.get("color_2", "black"), # opacity=0., - opacity=0.8, + # opacity=0.8, + opacity=format_i.get("opacity", 0.8), + symbol=format_i.get("symbol_i", "circle"), line=dict( # color=smart_format_i[marker_border_color_key], @@ -512,15 +512,108 @@ def __create_plotly_series__(self, ) #__| + #| - Points in middle of RDS states + # HACK + if series_i.limiting_step == ["ooh", "bulk"]: + ind_i = 3 + short_x = short_x[ind_i:ind_i + 2] + short_y = short_y[ind_i:ind_i + 2] + + if series_i.limiting_step == ["bulk", "ooh"]: + ind_i = 0 + short_x = short_x[ind_i:ind_i + 2] + short_y = short_y[ind_i:ind_i + 2] + + + + if series_i.limiting_step == ["o", "ooh"]: + ind_i = 2 + short_x = short_x[ind_i:ind_i + 2] + short_y = short_y[ind_i:ind_i + 2] + + if series_i.limiting_step == ["ooh", "o"]: + ind_i = 1 + short_x = short_x[ind_i:ind_i + 2] + short_y = short_y[ind_i:ind_i + 2] + + + + if series_i.limiting_step == ["oh", "o"]: + ind_i = 1 + short_x = short_x[ind_i:ind_i + 2] + short_y = short_y[ind_i:ind_i + 2] + + if series_i.limiting_step == ["o", "oh"]: + ind_i = 2 + short_x = short_x[ind_i:ind_i + 2] + short_y = short_y[ind_i:ind_i + 2] + + + + if series_i.limiting_step == ["bulk", "oh"]: + ind_i = 0 + short_x = short_x[ind_i:ind_i + 2] + short_y = short_y[ind_i:ind_i + 2] + + if series_i.limiting_step == ["oh", "bulk"]: + ind_i = 3 + short_x = short_x[ind_i:ind_i + 2] + short_y = short_y[ind_i:ind_i + 2] + + # TEMP + # print(series_i.limiting_step) + # print(short_x) + # print(short_y) + # print("***********************************************") + + rds_data = go.Scatter( + x=short_x, + y=short_y, + legendgroup=group, + name=name, + showlegend=False, + hoverinfo="none", + # text=hover_text, + marker=dict( + size=format_i.get("marker_size", 10) + 14, + # color=format_i.get("color_2", "black"), + color="grey", + opacity=0.3, + # symbol=format_i.get("symbol_i", "circle"), + symbol="circle", + line=dict( + # color=smart_format_i[marker_border_color_key], + color=format_i.get("color_1", "black"), + width=0., + ) + + ), + mode="markers", + ) #__| + #__| ****************************************************************** + #| - Plot Mode (which data series to plot) if plot_mode == "all": - data_lst = [data_1, data_2, data_3] + data_lst = [ + rds_data, + data_1, + data_2, + data_3, + ] elif plot_mode == "states_only": - data_lst = [data_1, data_3] + data_lst = [ + rds_data, + data_1, + data_3, + ] elif plot_mode == "full_lines": - data_lst = [data_2, data_3] + data_lst = [ + rds_data, + data_2, + data_3, + ] #__| return(data_lst) @@ -563,8 +656,12 @@ def max_y_value_per_step(self): # for series_i in self.series_list: for series_i in self.ORR_Free_E_Plot.series_list: + + energy_list_i = series_i.apply_bias(self.bias, series_i.energy_lst) + fe_matrix.append( - np.array(series_i.energy_lst), + energy_list_i, + # np.array(series_i.energy_lst), ) fe_matrix = np.array(fe_matrix) @@ -585,11 +682,6 @@ def H_e_pairs_annotations(self, font_size: """ #| - H_e_pairs_annotations - # ann_font_size = 18 - # states_sep = self.plot_states_sep - # states_width = self.plot_states_width - - mid_state_x_array = self.mid_state_x_array rxn_x_array = self.rxn_x_coord_array @@ -697,30 +789,17 @@ def create_mid_state_x_array(self): #__| - def plotly_fed_layout(self, - plot_title="FED", - plot_title_size=18, - tick_lab_size=16, - axes_lab_size=18, - legend_size=18, - # font_family="Computer Modern" # "Courier New, monospace" - font_family="Arial, Courier New, monospace", - plot_width=680, - plot_height=510, - annotation_size=12, - ): + def get_plotly_layout(self, layout_dict=None): """ - - Development notes: - Move all plot parameters to this method, since the user will call - this method to obtain the layout. """ #| - plotly_fed_layout + tick_lab_size = 16 + axes_lab_size = 18 + legend_size=18 + annotation_size = 12 + #| - OER vs ORR Settings if self.rxn_type == "ORR": - # xax_labels = ["$O_{2}$", "$*OOH$", "$*O$", "$*OH$", "$H_{2}O$"] - # xax_labels = ["O2", "*OOH", "*O", "*OH", "H2O"] - xax_labels = [ "O2", "*OOH", @@ -731,38 +810,45 @@ def plotly_fed_layout(self, elif self.rxn_type == "OER": # xax_labels = ["$H_{2}O$", "$*OH$", "$*O$", "$*OOH$", "$O_{2}$"] - xax_labels = ["H2O", "*OH", "*O", "*OOH", "O2"] - - # "font":dict( - # family='Arial', - # # size=18, - # color='black', - # ), + xax_labels = [ + "H2O", + "*OH", + "*O", + "*OOH", + "O2", + ] + #__| + #| - Layout layout = { - # "title": plot_title, + "title": None, + + #| - Font Settings "font": { - # "family": "Courier New, monospace", - "family": font_family, - "size": plot_title_size, + "family": "Arial", # "Courier New, monospace" "color": "black", }, + #__| + #| - Margins ------------------------------------------------------ + "margin": go.layout.Margin( + b=50., + l=50., + r=30., + t=30., + ), + #__| #| - Axes --------------------------------------------------------- "yaxis": { "title": "Free Energy (eV)", - # "title": "$\\Delta G (ev)$", - "zeroline": False, "linecolor": 'black', "showline": True, "mirror": 'ticks', "showgrid": False, - "titlefont": dict(size=axes_lab_size), - "tickfont": dict( size=tick_lab_size, ), @@ -774,7 +860,6 @@ def plotly_fed_layout(self, "ticklen": 2, "tickwidth": 1, "tickcolor": 'black', - }, "xaxis": { @@ -806,42 +891,53 @@ def plotly_fed_layout(self, #__| -------------------------------------------------------------- #| - Legend ------------------------------------------------------- - "legend": { - "traceorder": "normal", - "font": dict(size=legend_size), - "x": -0.1, - "y": -1.2, - }, + + "legend": go.layout.Legend( + x=1.1, + xanchor=None, + y=1., + yanchor="top", + font=dict(size=legend_size), + bgcolor="rgba(0,0,0,0.01)", + + arg=None, + bordercolor=None, + borderwidth=None, + itemclick=None, + itemdoubleclick=None, + itemsizing=None, + orientation=None, + tracegroupgap=None, + traceorder=None, + uirevision=None, + valign=None, + ), "showlegend": self.show_legend, #__| -------------------------------------------------------------- - #| - Plot Size - # "width": 200 * 4., - # "height": 200 * 3., - #__| - - # "paper_bgcolor": 'rgba(0,0,0,0)', - "plot_bgcolor": 'rgba(0,0,0,0)', - - # "width": 9. * 37.795275591, - # "height": 9 * 37.795275591, + "paper_bgcolor": 'rgba(240,240,240,0.9)', - "width": plot_width, - "height": plot_height, } + #__| + + #| - H/e Count Annotations if self.show_H_e_pairs_annotations: annotations = self.H_e_pairs_annotations(font_size=annotation_size) - if "annotations" in list(layout): layout["annotations"] += annotations else: layout["annotations"] = annotations + #__| + + layout = go.Layout(**layout) + + if layout_dict is not None: + layout.update(layout_dict) return(layout) #__| - #__| ********************************************************************** diff --git a/oxr_reaction/oxr_plotting_classes/oxr_plot_scaling.py b/oxr_reaction/oxr_plotting_classes/oxr_plot_scaling.py index 50479cd..2379bc9 100644 --- a/oxr_reaction/oxr_plotting_classes/oxr_plot_scaling.py +++ b/oxr_reaction/oxr_plotting_classes/oxr_plot_scaling.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -"""ORR energetics classes and methods. +"""OXR class for plotting OXR energetics (scaling relations). Author: Raul A. Flores """ @@ -13,13 +13,10 @@ import plotly.graph_objs as go -pd.options.mode.chained_assignment = None +# pd.options.mode.chained_assignment = None from oxr_reaction.oxr_series import ORR_Free_E_Series from oxr_reaction.adsorbate_scaling import lim_U_i - -# from orr_reaction.orr_series import ORR_Free_E_Series -# from orr_reaction.adsorbate_scaling import lim_U_i #__| @@ -259,7 +256,8 @@ def __create_trace_i__(self, text=name_i, name=name_i, mode="markers", - legendgroup=legendgroup, + # legendgroup=legendgroup, + legendgroup=name_i, marker=dict( size=smart_format_i.get("marker_size", 9), symbol=smart_format_i.get( @@ -278,143 +276,6 @@ def __create_trace_i__(self, return(trace_i) #__| - # NOTE | This shouldn't be an internal method - def __create_layout__(self, - # x_ax_spec="oh", - title="Scaling Relations", - showlegend=True, - layout_dict=None, - ): - """Create plotly layout dict. - - Args: - x_ax_spec: - title: - showlegend: - """ - #| - create_layout - - # if x_ax_spec == "" - if self.x_ax_species == "oh": - x_ax_title = "Gads,*OH (eV)" - else: - x_ax_title = "TEMP" - - y_ax_title = "Gads,*OH, " + \ - "Gads,*O, " + \ - "Gads,*OOH (eV)" - - tick_lab_size = 12 * (4. / 3.) - axes_lab_size = 14 * (4. / 3.) - - # legend_size = 18 - - #| - Common Axis Dict - common_axis_dict = { - - # "range": y_axis_range, - "zeroline": False, - "showline": True, - "mirror": 'ticks', - "linecolor": 'black', - "showgrid": False, - - "titlefont": dict(size=axes_lab_size), - "tickfont": dict( - size=tick_lab_size, - ), - "ticks": 'inside', - "tick0": 0, - "tickcolor": 'black', - # "dtick": 0.25, - "ticklen": 2, - "tickwidth": 1, - } - #__| - - #| - __old__ - # x_range_ooh_vs_oh=[0., 3.5], - # y_range_ooh_vs_oh=[0., 5.], - # x_range_o_vs_oh=[0., 3.5], - # y_range_o_vs_oh=[0., 5.], - - # if y_ax_spec == "ooh": - # x_range = self.x_range_ooh_vs_oh - # elif y_ax_spec == "o": - # x_range = self.x_range_o_vs_oh - # elif y_ax_spec == "oh": - # x_range = self.x_range_oh_vs_oh - # else: - # print("Woops - create_layout") - # - # if y_ax_spec == "ooh": - # y_range = self.y_range_ooh_vs_oh - # elif y_ax_spec == "o": - # y_range = self._range_o_vs_oh - # elif y_ax_spec == "oh": - # y_range = self.y_range_oh_vs_oh - # else: - # print("Woops - create_layout") - #__| - - x_range = self.x_range - y_range = self.y_range - - layout_i = { - "title": title, - "titlefont": go.layout.title.Font(size=24), - # "titlefont": go.layout.Titlefont(size=24), - - "xaxis": dict( - common_axis_dict, - **{ - "title": x_ax_title, - "range": x_range, - }, - ), - - "yaxis": dict( - common_axis_dict, - **{ - "title": y_ax_title, - "range": y_range, - }, - ), - - # Margin - "margin": go.layout.Margin( - b=50., - l=50., - r=50., - t=50., - ), - - "font": dict( - family='Arial', - # size=18, - color='black', - ), - - "width": 1.5 * 18.7 * 37.795275591, - "height": 18.7 * 37.795275591, - - "showlegend": showlegend, - - "legend": dict( - font=dict( - size=10, - ), - ), - } - - if layout_dict is not None: - from misc_modules.misc_methods import dict_merge - dict_merge(layout_i, layout_dict) - # layout_i = {**layout_i, **layout_dict} - - return(layout_i) - #__| - def __series_excluded__(self, properties_i, exclude_dict, @@ -627,11 +488,10 @@ def scaling_meth(E_OH): return(out) #__| - LH_bound = self.x_range[0] - RH_bound = self.x_range[1] + LH_bound = self.x_range[0] - 0.2 + RH_bound = self.x_range[1] + 0.2 scaling_trace = go.Scatter( - # x=[self.x_range_ooh_vs_oh[0], self.x_range_ooh_vs_oh[1]], x=[LH_bound, RH_bound], y=[ scaling_meth(LH_bound), @@ -669,6 +529,171 @@ def scaling_meth(E_OH): #__| + # NOTE | This shouldn't be an internal method + # I don't remember why I wrote the above note + def get_plotly_layout(self, + # x_ax_spec="oh", + title="Scaling Relations", + showlegend=True, + layout_dict=None, + ): + """Create plotly layout dict. + + Args: + x_ax_spec: + title: + showlegend: + """ + #| - create_layout + # if x_ax_spec == "" + if self.x_ax_species == "oh": + x_ax_title = "Gads,*OH (eV)" + else: + x_ax_title = "TEMP" + + y_ax_title = "Gads,*OH, " + \ + "Gads,*O, " + \ + "Gads,*OOH (eV)" + + tick_lab_size = 12 * (4. / 3.) + axes_lab_size = 14 * (4. / 3.) + + # legend_size = 18 + + #| - Common Axis Dict + common_axis_dict = { + + # "range": y_axis_range, + "zeroline": False, + "showline": True, + "mirror": 'ticks', + "linecolor": 'black', + "showgrid": False, + + "titlefont": dict(size=axes_lab_size), + "tickfont": dict( + size=tick_lab_size, + ), + "ticks": 'inside', + "tick0": 0, + "tickcolor": 'black', + # "dtick": 0.25, + "ticklen": 2, + "tickwidth": 1, + } + #__| + + x_range = self.x_range + y_range = self.y_range + + layout = { + "title": None, + + # "titlefont": go.layout.title.Font(size=24), + # # "titlefont": go.layout.Titlefont(size=24), + + "font": { + "family": "Arial", # "Courier New, monospace" + "color": "black", + }, + + "xaxis": dict( + common_axis_dict, + **{ + "title": x_ax_title, + "range": x_range, + }, + ), + + "yaxis": dict( + common_axis_dict, + **{ + "title": y_ax_title, + "range": y_range, + }, + ), + + #| - Margins ------------------------------------------------------ + "margin": go.layout.Margin( + b=50., + l=50., + r=30., + t=30., + ), + #__| + + + # # Margin + # "margin": go.layout.Margin( + # b=50., + # l=50., + # r=50., + # t=50., + # ), + + "font": dict( + family='Arial', + # size=18, + color='black', + ), + + #| - Plot Size + # "width": 37 * 37.795275591, + # "height": 23 * 37.795275591, + # + # # "width": 1.5 * 18.7 * 37.795275591, + # # "height": 18.7 * 37.795275591, + # # "width": 1.5 * 18.7 * 37.795275591, + # # "height": 18.7 * 37.795275591, + #__| + + #| - Legend + "showlegend": showlegend, + + "legend": go.layout.Legend( + x=1., + xanchor=None, + y=1., + yanchor="top", + font=dict(size=10), + bgcolor="rgba(0,0,0,0.01)", + + arg=None, + bordercolor=None, + borderwidth=None, + itemclick=None, + itemdoubleclick=None, + itemsizing=None, + orientation=None, + tracegroupgap=None, + traceorder=None, + uirevision=None, + valign=None, + ), + + # "legend": dict( + # font=dict( + # size=10, + # ), + # ), + + #__| + + } + + layout = go.Layout(**layout) + + if layout_dict is not None: + layout.update(layout_dict) + + # if layout_dict is not None: + # from misc_modules.misc_methods import dict_merge + # dict_merge(layout_i, layout_dict) + # # layout_i = {**layout_i, **layout_dict} + + return(layout) + #__| + @@ -709,3 +734,31 @@ def scaling_meth(E_OH): #__| #__| ********************************************************************** + + + + +#| - __old__ +# x_range_ooh_vs_oh=[0., 3.5], +# y_range_ooh_vs_oh=[0., 5.], +# x_range_o_vs_oh=[0., 3.5], +# y_range_o_vs_oh=[0., 5.], + +# if y_ax_spec == "ooh": +# x_range = self.x_range_ooh_vs_oh +# elif y_ax_spec == "o": +# x_range = self.x_range_o_vs_oh +# elif y_ax_spec == "oh": +# x_range = self.x_range_oh_vs_oh +# else: +# print("Woops - create_layout") +# +# if y_ax_spec == "ooh": +# y_range = self.y_range_ooh_vs_oh +# elif y_ax_spec == "o": +# y_range = self._range_o_vs_oh +# elif y_ax_spec == "oh": +# y_range = self.y_range_oh_vs_oh +# else: +# print("Woops - create_layout") +#__| diff --git a/oxr_reaction/oxr_plotting_classes/oxr_plot_volcano.py b/oxr_reaction/oxr_plotting_classes/oxr_plot_volcano.py index cd4dfaf..4ce84e7 100644 --- a/oxr_reaction/oxr_plotting_classes/oxr_plot_volcano.py +++ b/oxr_reaction/oxr_plotting_classes/oxr_plot_volcano.py @@ -10,16 +10,10 @@ import pandas as pd from sklearn.linear_model import LinearRegression - import plotly.graph_objs as go -pd.options.mode.chained_assignment = None - from oxr_reaction.oxr_series import ORR_Free_E_Series -# from orr_reaction.orr_series import ORR_Free_E_Series - from oxr_reaction.adsorbate_scaling import lim_U_i -# from orr_reaction.adsorbate_scaling import lim_U_i #__| @@ -438,8 +432,8 @@ def __create_trace_i__(self, def get_plotly_layout(self, showlegend=False, - width=9. * 37.795275591, - height=9. * 37.795275591, + # width=9. * 37.795275591, + # height=9. * 37.795275591, layout_dict=None, ): """ @@ -458,23 +452,11 @@ def get_plotly_layout(self, font_family = "Arial" # "Courier New, monospace" #__| - # self.x_ax_spec - if self.x_ax_species == "oh": - # xaxis_title = "dG_*OH (eV)" xaxis_title = "dGOH (eV)" elif self.x_ax_species == "o-oh": - # xaxis_title = "dG_*OH - dG_*O (eV)" xaxis_title = "dGO - dGOH (eV)" - # layout["margin"] = go.layout.Margin( - # b=50., - # l=50., - # r=50., - # t=50., - # # pad=20., - # ) - layout = { "title": plot_title, @@ -504,9 +486,9 @@ def get_plotly_layout(self, size=tick_lab_size, ), "ticks": 'inside', - "tick0": 0, + # "tick0": 0, "tickcolor": 'black', - "dtick": 0.1, + # "dtick": 0.1, "ticklen": 2, "tickwidth": 1, }, @@ -526,8 +508,8 @@ def get_plotly_layout(self, "titlefont": dict(size=axes_lab_size), "showticklabels": True, "ticks": 'inside', - "tick0": 0, - "dtick": 0.2, + # "tick0": 0, + # "dtick": 0.2, "ticklen": 2, "tickwidth": 1, "tickcolor": 'black', @@ -564,31 +546,32 @@ def get_plotly_layout(self, #__| - } + "paper_bgcolor": 'rgba(250,250,250,0.9)', - #| - Plot Size Settings - # bottom_margin_size = 2.5 * 9. * 37.795275591 - plot_size_settings = { - "width": width, - "height": height, - - # "width": 9. * 37.795275591, - # "height": 9 * 37.795275591, - - # "margin": go.layout.Margin({ - # "l": 50, - # "r": 50, - # # "b": bottom_margin_size, - # # "b": 100, - # "b": 1200, - # "t": 10, - # "pad": 4, - # }), } + #| - Plot Size Settings + # # bottom_margin_size = 2.5 * 9. * 37.795275591 + # plot_size_settings = { + # "width": width, + # "height": height, + # + # # "width": 9. * 37.795275591, + # # "height": 9 * 37.795275591, + # + # # "margin": go.layout.Margin({ + # # "l": 50, + # # "r": 50, + # # # "b": bottom_margin_size, + # # # "b": 100, + # # "b": 1200, + # # "t": 10, + # # "pad": 4, + # # }), + # } + # layout = {**layout, **plot_size_settings} #__| - layout = {**layout, **plot_size_settings} #| - Applying Layout override dict if layout_dict is not None: From b0c83a35ba7168bcd48bc313f93eb9085bf706a4 Mon Sep 17 00:00:00 2001 From: Raul Flores Date: Tue, 6 Aug 2019 17:21:12 -0700 Subject: [PATCH 07/16] Added new plotly convienence plotting method --- plotting/my_plotly.py | 114 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 5 deletions(-) diff --git a/plotting/my_plotly.py b/plotting/my_plotly.py index 38198f6..480ff6d 100644 --- a/plotting/my_plotly.py +++ b/plotting/my_plotly.py @@ -8,13 +8,14 @@ #| - Import Modules import plotly +import os +# import plotly.plotly as py +import chart_studio.plotly as py +import plotly.graph_objs as go + +from plotly import io as pyio #__| -# "font": { -# "family": "Courier New, monospace", -# "size": plot_title_size, -# "color": "black", -# }, #| - Plotly def reapply_colors(data): @@ -145,3 +146,106 @@ def plot_layout( #__| #__| + + + +def my_plotly_plot( + layout=None, + layout_override=None, + plot_name=None, + save_dir=None, + data=None, + upload_plot=True, + ): + """ + TODO: + Remove layout override functionality, this should be done before calling + the method + + Args: + --------------------------------------------------------------------------- + layout: + plotly layout + layout_override: + Dictionary to override layout + plot_name: + Plot name (used both for plot upload and local save) + save_dir: + Plot.ly folder to save figure into (Not used for local save) + data: + plotly data object + upload_plot: + Upload plot to plotly servers + + """ + #| - plot_proto + if layout is None: + layout = go.Layout() + + layout.update(layout_override) + + fig = go.Figure(data=data, layout=layout) + + #| - Upload to plot.ly website + # ######################################################################### + if upload_plot: + plotly_filename = os.path.join( + save_dir, + # "02_oer_analysis", + # "oer_2d_volcano_plot", + plot_name) + tmp = py.iplot(fig, filename=plotly_filename) + print(plotly_filename) + #__| + + #| - Local write to HTML + # ######################################################################### + plot_dir = "out_plot" + if not os.path.exists(plot_dir): + os.makedirs(plot_dir) + + local_filename = os.path.join( + plot_dir, + plot_name + ".html" + ) + + pyio.write_html( + { + "data": data, + "layout": layout, + + }, + local_filename, + ) + #__| + + #| - Write pdf and svg (if ORCA is installed and working) + import socket + hostname = socket.gethostbyaddr(socket.gethostname())[0] + + # Requires ORCA installation + if os.environ["USER"] == "raul-ubuntu-desktop" or hostname == "raul-ubuntu-vb": + print("Writing pdf with ORCA") + + # pyio.write_json( + # { + # "data": data, + # "layout": layout, + # }, + # os.path.join(plot_dir, plot_name + ".pdf")) + + # This seems to be the preferred syntax now + fig.write_image( + os.path.join(plot_dir, plot_name + ".pdf") + # "out_plot/test_fig.pdf" + ) + + # This seems to be the preferred syntax now + fig.write_image( + os.path.join(plot_dir, plot_name + ".svg") + # "out_plot/test_fig.pdf" + ) + #__| + + return(fig) + #__| From 107599e41aa645a3be2b4d1681aaf6db1e146ba6 Mon Sep 17 00:00:00 2001 From: Raul Flores Date: Tue, 6 Aug 2019 17:21:40 -0700 Subject: [PATCH 08/16] Jupyter code --- .../jupyter_helpers/following_tail.py | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 jupyter_modules/jupyter_helpers/following_tail.py diff --git a/jupyter_modules/jupyter_helpers/following_tail.py b/jupyter_modules/jupyter_helpers/following_tail.py new file mode 100644 index 0000000..1c283c6 --- /dev/null +++ b/jupyter_modules/jupyter_helpers/following_tail.py @@ -0,0 +1,72 @@ +from abc import ABC, abstractmethod +from warnings import warn + +from IPython.core.display import clear_output, display, HTML + + +def display_one_at_a_time(text): + clear_output(wait=True) + display(text) + + +class AbstractFollowingTail(ABC): + + def __init__(self, n=5): + self.n = n + + def activate(self): + pass + + @abstractmethod + def __call__(self, *args, **kwargs): + pass + + +class SimpleFollowingTail(AbstractFollowingTail): + + def __init__(self, n=1): + if n != 1: + try: + from ipywidgets import Output + warn('To use n > 1, please use PyWidgetsInteractiveTail') + except ImportError: + warn('To enable use of n > 1, please install ipywidgets package') + warn('Using n = 1') + super().__init__(n) + + def __call__(self, text): + return display_one_at_a_time(text) + + +try: + from ipywidgets import Output + + def pack_to_div(obj): + data = obj._repr_html_() if hasattr(obj, '_repr_html_') else str(obj) + return f'
{data}
' + + class PyWidgetsFollowingTail(AbstractFollowingTail): + + def __init__(self, n=5): + super().__init__(n) + self.output = Output() + self.buffer = [] + + def activate(self): + display(self.output) + + def __call__(self, text): + if len(self.buffer) == self.n: + self.buffer = self.buffer[1:] + self.buffer.append(text) + with self.output: + display(HTML( + ''.join(map(pack_to_div, self.buffer)) + )) + clear_output(wait=True) + + FollowingTail = PyWidgetsFollowingTail + +except ImportError: + + FollowingTail = SimpleFollowingTail From 1f05dee946aa547b019dbd85e4cdc9ae5b2badb8 Mon Sep 17 00:00:00 2001 From: Raul Flores Date: Tue, 6 Aug 2019 17:21:57 -0700 Subject: [PATCH 09/16] Small update to job_analysis printingg --- dft_job_automat/job_analysis.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dft_job_automat/job_analysis.py b/dft_job_automat/job_analysis.py index d368602..bba5270 100644 --- a/dft_job_automat/job_analysis.py +++ b/dft_job_automat/job_analysis.py @@ -1349,10 +1349,12 @@ def compare_parsed_and_user_job_dirs(parsed_dirs, user_dirs): print("User inputed dir_list len: ", str(len(user_dirs))) print("Parsed dir_list len: ", str(len(parsed_dirs))) - print(20 * "_") + print(20 * "_"); print("") + print("Dirs that were parsed but are not in the user specified list") print(set(parsed_dirs).difference(set(user_dirs))) print(20 * "*") + print("Dirs that are in the user list but not in the parsed list") print(set(user_dirs).difference(set(parsed_dirs))) #__| From 4d1679594884021116be9a6e261c4814cb61de42 Mon Sep 17 00:00:00 2001 From: Raul Flores Date: Tue, 6 Aug 2019 17:22:18 -0700 Subject: [PATCH 10/16] New drop_columns method for pandas dataframes --- misc_modules/pandas_methods.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/misc_modules/pandas_methods.py b/misc_modules/pandas_methods.py index e7ad861..bc072ff 100644 --- a/misc_modules/pandas_methods.py +++ b/misc_modules/pandas_methods.py @@ -87,3 +87,30 @@ def reorder_df_columns(col_order_list, df): return(df) #__| + + + +def drop_columns(df=None, columns=None, keep_or_drop="keep"): + """ + """ + #| - drop_columns + if keep_or_drop == "keep": + cols_to_keep = columns + + columns_to_drop = [] + for col_i in df.columns: + if col_i not in cols_to_keep: + columns_to_drop.append(col_i) + + df_out = df.drop(columns=columns_to_drop) + + elif keep_or_drop == "drop": + cols_to_drop = columns + + df_out = df.drop(columns=cols_to_drop) + + else: + raise ValueError('BAD BAD BAD') + + return(df_out) + #__| From fd529821fcc47e52d63e89686431187502a9020a Mon Sep 17 00:00:00 2001 From: Raul Flores Date: Tue, 6 Aug 2019 17:22:49 -0700 Subject: [PATCH 11/16] Update method to remove files from file system --- misc_modules/misc_methods.py | 42 ++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/misc_modules/misc_methods.py b/misc_modules/misc_methods.py index e80eeb2..9b8cf64 100644 --- a/misc_modules/misc_methods.py +++ b/misc_modules/misc_methods.py @@ -1,8 +1,13 @@ -"""Miscellaneous and helpful methods for everday work.""" +"""Miscellaneous and helpful methods for everday work. + +TEMP +TEMP +""" #| - IMPORT MODULES import os -import sys + +# import sys #__| @@ -72,6 +77,7 @@ def dict_merge(dct, merge_dct): def remove_file_from_all_folders( file_name_list, remove_files=False, + show_file_size=True, root_dir=".", ): """Removes charge files (CHG and CHGCAR) from Raman DFT job folders. @@ -82,21 +88,45 @@ def remove_file_from_all_folders( root_dir: Starting directory, assumed to be current directory """ #| - remove_file_from_all_folders + total_disk_usage = 0. for dirName, subdirList, fileList in os.walk(root_dir): for file_name in file_name_list: if file_name in fileList: print(dirName) - print(subdirList) - print(fileList) - print(file_name) + # print(subdirList) + # print(fileList) + # print(file_name) + + file_path_i = os.path.join( + dirName, + file_name, + ) + + if show_file_size: + file_size_i = os.stat(file_path_i).st_size * 1E-6 + print("File size: ", str(file_size_i), " MB") + + total_disk_usage += file_size_i + print("_________") if remove_files: try: - os.remove(dirName + "/" + file_name) + os.remove(file_path_i) print("File removed!!") except: pass + + + if show_file_size: + if total_disk_usage > 1E3: + total_disk_usage_print = total_disk_usage * 1E-3 + unit = "GB" + else: + total_disk_usage_print = total_disk_usage + unit = "MB" + + print("Total Disk Usage: ", str(total_disk_usage_print), "", unit) #__| From da234cc15b6bf832faef41d0449721fe1d5852ee Mon Sep 17 00:00:00 2001 From: Raul Flores Date: Tue, 6 Aug 2019 17:23:02 -0700 Subject: [PATCH 12/16] Init commit to surface energy class that I've been working on --- surface_energy/surface_energy.py | 711 +++++++++++++++++++++++++++++++ 1 file changed, 711 insertions(+) create mode 100644 surface_energy/surface_energy.py diff --git a/surface_energy/surface_energy.py b/surface_energy/surface_energy.py new file mode 100644 index 0000000..d6b7617 --- /dev/null +++ b/surface_energy/surface_energy.py @@ -0,0 +1,711 @@ +#!/usr/bin/env python + +"""Module to calclate surface energies from symmetric slabs. +TEMP +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import numpy as np +import pandas as pd + +import plotly.graph_objs as go + +from ase_modules.ase_methods import create_species_element_dict + +from pymatgen.core.composition import Composition +from ase_modules.ase_methods import create_species_element_dict +#__| + + +class SurfaceEnergy: + """Calculates surface energy of slab relative to a given bulk structure. + + TODO: + Currently assumes that the slab is symmetric (each surface is the same), + try to add check for this + """ + + #| - SurfaceEnergy ******************************************************** + _TEMP = "TEMP" + + def __init__(self, + #| - TEMP | ARGS ------------------------------------------------------ + atoms=None, + electronic_energy=None, # Only needed if not within atoms object + + bulk_atoms=None, + bulk_electronic_energy_per_atom=None, + + H_ref_electronic_energy=None, + O_ref_electronic_energy=None, + + num_surface_atoms=None, + + bias=0., + pH=0., + + verbose=True, + #__| ------------------------------------------------------------------ + ): + """ + """ + #| - __init__ + + #| - Setting Argument Instance Attributes + self.atoms = atoms + self.electronic_energy = electronic_energy + + self.bulk_atoms = bulk_atoms + self.bulk_electronic_energy_per_atom = bulk_electronic_energy_per_atom + + self.H_ref_electronic_energy = H_ref_electronic_energy + self.O_ref_electronic_energy = O_ref_electronic_energy + + self.num_surface_atoms = num_surface_atoms + + self.bias = bias + self.pH = pH + + self.verbose = verbose + #__| + + #| - Initializing Internal Instance Attributes + self.__num_atoms_reduced_bulk__ = None + + self.non_stoich_comp = None + + # TODO implement method to calc slab thickness + self.slab_thickness = None + + self.__bulk_energy_per_atom__ = None + #__| + + + self.surface_area = self.__calc_surface_area__() + + self.electronic_energy = self.__get_electronic_energy__( + self.atoms, self.electronic_energy) + + self.bulk_electronic_energy = self.__get_electronic_energy__( + self.bulk_atoms, self.bulk_electronic_energy_per_atom, + per_atom=True) + + self.__bulk_formula_units_in_slab__ = \ + self.__calc_units_of_bulk_in_slab__() + + self.__bulk_formula_reduction__ = \ + self.__calc_units_of_reduced_bulk_in_bulk__() + + self.__bulk_energy_per_formula_unit__ = \ + self.__calc_bulk_energy_per_formula_unit__() + + self.surface_e_per_side = self.calc_std_surface_energy() + + self.surface_e_per_area = self.__calc_std_surface_energy_per_area__() + + if self.num_surface_atoms is not None: + self.surface_e_per_surface_atom = \ + self.__calc_std_surface_energy_per_surface_atom__() + + self.slab_thickness = self.__calc_slab_thickness__() + #__| + + def calc_std_surface_energy(self): + """ + """ + #| - calc_std_surface_energy + electronic_energy = self.electronic_energy + bulk_formula_units_in_slab = self.__bulk_formula_units_in_slab__ + bulk_energy_per_formula_unit = self.__bulk_energy_per_formula_unit__ + H_ref_electronic_energy = self.H_ref_electronic_energy + O_ref_electronic_energy = self.O_ref_electronic_energy + + non_stoich_comp = self.non_stoich_comp + + # TODO Make the referencing more robust, take arbitary dict of + # referencec atoms + surf_e_0 = 0. + \ + +electronic_energy + \ + -bulk_formula_units_in_slab * bulk_energy_per_formula_unit + \ + -non_stoich_comp.get("O", 0.) * (O_ref_electronic_energy) + \ + -non_stoich_comp.get("H", 0.) * (H_ref_electronic_energy) + \ + +0. + + # Divide surface energy across two sides of slab + surf_e_0 /= 2 + + return(surf_e_0) + + # if norm_mode == "area": + # surf_e_0 = surf_e_0 / (2 * row_i["slab_area"]) + # elif norm_mode == "atoms": + # if num_atoms is not None: + # surf_e_0 = surf_e_0 / (2 * num_atoms) + #__| + + def __calc_std_surface_energy_per_area__(self): + """Normalize the surface energy to surface area (A^2).""" + #| - calc_std_surface_energy_per_area + surface_area = self.surface_area + surface_e_per_side = self.surface_e_per_side + + + surface_e_per_area = surface_e_per_side / surface_area + + return(surface_e_per_area) + #__| + + + def __calc_std_surface_energy_per_surface_atom__(self): + """Normalize the surface area to a per surface atom basis.""" + #| - calc_std_surface_energy_per_area + num_surface_atoms = self.num_surface_atoms + surface_e_per_side = self.surface_e_per_side + + + surface_e_per_surface_atoms = surface_e_per_side / num_surface_atoms + + return(surface_e_per_area) + #__| + + + def __calc_surface_area__(self): + """ + """ + #| - __calc_surface_area__ + atoms = self.atoms + + cell = atoms.cell + + cross_prod_i = np.cross(cell[0], cell[1]) + area_i = np.linalg.norm(cross_prod_i) + + return(area_i) + #__| + + def __get_electronic_energy__(self, + atoms, + electronic_energy, + per_atom=False): + """ + """ + #| - __get_electronic_energy__ + energy_out = None + if electronic_energy is not None: + + if self.verbose: + print("Using energy provided instead of energy attached to atoms") + + if per_atom: + energy_out = atoms.get_number_of_atoms() * electronic_energy + else: + energy_out = electronic_energy + else: + try: + energy_out = atoms.get_potential_energy() + except RuntimeError as err: + print(err, "AHHHHHHHH!!!!") + raise ValueError('No where to get energy from!!!') + except: + print("Uncaught error type") + raise ValueError('No where to get energy from!!!') + + return(energy_out) + #__| + + def __calc_units_of_bulk_in_slab__(self): + """ + """ + #| - __calc_units_of_bulk_in_slab__ + bulk_atoms = self.bulk_atoms + atoms = self.atoms + + + comp0 = Composition(bulk_atoms.get_chemical_formula()) + + df = pd.DataFrame([ + create_species_element_dict(atoms, elems_to_always_include=["O", "H"]), + dict(comp0.to_data_dict["reduced_cell_composition"])], + index=["slab", "bulk"]) + + # Replace NaNs with 0. + df = df.replace(np.nan, 0.0, regex=True) + + # Removingg columns with 0 + df = df.loc[:, (df != 0).any(axis=0)] + + slab_comp_array = np.array(list(df.loc["slab"])) + bulk_comp_array = np.array(list(df.loc["bulk"])) + + # Number of unit of the bulk's reduced formula that fit into the slab + bulk_formula_units_in_slab = int(min(slab_comp_array / bulk_comp_array)) + bfuis = bulk_formula_units_in_slab + + # ##################################################################### + # Getting the non-stoicheometric atoms composition + df.loc["nonstoich"] = df.loc["slab"] - bfuis * df.loc["bulk"] + non_stoich_comp = df.loc["nonstoich"].to_dict() + self.non_stoich_comp = non_stoich_comp + + + + return(bulk_formula_units_in_slab) + #__| + + def __calc_units_of_reduced_bulk_in_bulk__(self): + """ + """ + #| - __calc_units_of_reduced_bulk_in_bulk__ + bulk_atoms = self.bulk_atoms + + bulk_atoms.get_chemical_formula() + + comp0 = Composition(bulk_atoms.get_chemical_formula()) + + + reduced_comp = dict(comp0.to_data_dict["reduced_cell_composition"]) + num_atoms_in_reduc_form = int(sum(list(reduced_comp.values()))) + + self.__num_atoms_reduced_bulk__ = num_atoms_in_reduc_form + + + df = pd.DataFrame([ + dict(comp0.to_data_dict["reduced_cell_composition"]), + dict(comp0.to_data_dict["unit_cell_composition"])], + index=["reduced", "original"]) + + # Replace NaNs with 0. + df = df.replace(np.nan, 0.0, regex=True) + + # Removingg columns with 0 + df = df.loc[:, (df != 0).any(axis=0)] + + reduced_comp_array = np.array(list(df.loc["reduced"])) + orig_comp_array = np.array(list(df.loc["original"])) + + # Number of unit of the bulk's reduced formula that fit into the slab + bulk_reduction_factor = int(min(orig_comp_array / reduced_comp_array)) + # print(bulk_reduction_factor) + + return(bulk_reduction_factor) + #__| + + def __calc_bulk_energy_per_formula_unit__(self): + """ + """ + #| - __calc_bulk_energy_per_formula_unit__ + bulk_electronic_energy = self.bulk_electronic_energy + bulk_formula_reduction = self.__bulk_formula_reduction__ + num_atoms_reduced_bulk = self.__num_atoms_reduced_bulk__ + bulk_atoms = self.bulk_atoms + + num_atoms_bulk = bulk_atoms.get_number_of_atoms() + + # norm_fact = (E_per_atom) * (#_atoms_in_reduced_formula) + norm_fact = (num_atoms_reduced_bulk / num_atoms_bulk) + bulk_electronic_energy_per_formula = bulk_electronic_energy * norm_fact + + self.__bulk_energy_per_atom__ = \ + bulk_electronic_energy / num_atoms_bulk + + return(bulk_electronic_energy_per_formula) + #__| + + def __calc_slab_thickness__(self): + """Calculate the thickness of the atoms slab.""" + #| - __calc_slab_thickness__ + atoms = self.atoms + + slab_thickness = max(atoms.positions[:, 2]) - min(atoms.positions[:, 2]) + + return(slab_thickness) + #__| + + + + #__| ********************************************************************** + + +class SurfaceEnergyConvergence: + """Compute properties from series of slabs of increasing thickness. + + Regress bulk energy from total E's vs N + Extracting convergent surface energies from slab calculations + https://iopscience.iop.org/article/10.1088/0953-8984/8/36/005 + """ + + #| - SurfaceEnergyConvergence ********************************************* + _TEMP = "TEMP" + + def __init__(self, + SurfaceEnergy_instances=None, + num_points_to_exclude=1, + verbose=True, + ): + """ + + Args: + SurfaceEnergy_instances: + num_points_to_exclude: int + Number of points to exclude for the bulk energy regression + Thin slabs will suffer from finite size effects, so they should + not be included in regression + """ + #| - __init__ + + #| - Setting Argument Instance Attributes + self.SurfaceEnergy_instances = SurfaceEnergy_instances + self.num_points_to_exclude = num_points_to_exclude + + self.verbose = verbose + #__| + + #| - Initializing Internal Instance Attributes + self.sufficient_data_to_fit_bulk = True + self.fitted_bulk_energy = None + self.new_SurfaceEnergy_instances = [] + self.new_ave_surface_energy_per_area = None + #__| + + self.df = self.__init_dataframe__() + + self.ave_surface_energy_per_area = \ + self.__calc_ave_surface_energy__( + self.SurfaceEnergy_instances) + + # Enough data to fit? + self.__sufficient_data_to_fit_bulk() + if self.sufficient_data_to_fit_bulk: + + self.fitted_bulk_energy = self.__calc_regressed_bulk_energy__() + + self.new_SurfaceEnergy_instances = \ + self.__recalc_SurfaceEnergy_w_new_bulk__( + self.fitted_bulk_energy) + + self.new_ave_surface_energy_per_area = \ + self.__calc_ave_surface_energy__( + self.new_SurfaceEnergy_instances) + #__| + + def inst_surf_e_with_fitted_bulk(self): + """ + """ + #| - tmp_meth + fitted_bulk_energy = self.fitted_bulk_energy + SurfaceEnergy_instances = self.SurfaceEnergy_instances + + SE_old_i = SurfaceEnergy_instances[0] + + atoms = SE_old_i.atoms + + + SurfaceEnergy( + atoms=atoms, + # electronic_energy=None, # Only needed if not within atoms object + + bulk_atoms=None, + bulk_electronic_energy=None, + + H_ref_electronic_energy=None, + O_ref_electronic_energy=None, + + # num_surface_atoms=None, + # bias=0., + # pH=0., + ) + + #__| + + def __init_dataframe__(self): + """ + """ + #| - __init_dataframe__ + SurfaceEnergy_instances = self.SurfaceEnergy_instances + + atoms_list = [i.atoms for i in SurfaceEnergy_instances] + number_of_atoms = [i.get_number_of_atoms() for i in atoms_list] + potential_energy_list = [i.get_potential_energy() for i in atoms_list] + + df = pd.DataFrame() + + df["number_of_atoms"] = number_of_atoms + df["potential_energy"] = potential_energy_list + + df = df.sort_values("number_of_atoms") + + return(df) + #__| + + def __sufficient_data_to_fit_bulk(self): + """ + """ + #| - __sufficient_data_to_fit_bulk + df = self.df + num_points_to_exclude = self.num_points_to_exclude + + # If there are too few points excluding points may not be the best + # Need at least 3 points after removing points to do fit + if len(df) - num_points_to_exclude < 3: + + #| - Less than 3 data points, don't fit + if len(df) <= 2: + self.num_points_to_exclude = 0 + self.sufficient_data_to_fit_bulk = False + + if self.verbose: + print("Only ", str(len(df)), " data points, in dataframe") + print("Will not fit bulk energy") + #__| + + #| - Modifiying num_points_to_exclude to have at least 3 points + else: + num_points_to_exclude = int(len(df) - 3) + self.num_points_to_exclude = num_points_to_exclude + + if self.verbose: + print( + "Changed num_points_to_exclude to ", + num_points_to_exclude) + # print("") + #__| + + #__| + + def __calc_regressed_bulk_energy__(self): + """ + """ + #| - __calc_regressed_bulk_energy__ + df = self.df + num_points_to_exclude = self.num_points_to_exclude + nbpe = num_points_to_exclude + + number_of_atoms = df["number_of_atoms"] + potential_energy = df["potential_energy"] + + x_i = number_of_atoms + y_i = potential_energy + + z = np.polyfit(x_i[nbpe:], y_i[nbpe:], 1) + + bulk_energy = z[0] + + return(bulk_energy) + #__| + + +def __recalc_SurfaceEnergy_w_new_bulk__(self, new_bulk_energy): + """ + """ + #| - __recalc_SurfaceEnergy_w_new_bulk__ + SurfaceEnergy_instances = self.SurfaceEnergy_instances + # new_bulk_energy = self.new_bulk_energy + verbose = self.verbose + + new_SurfaceEnergy_instances = [] + for SurfaceEnergy_instance_i in SurfaceEnergy_instances: + SE_old_i = SurfaceEnergy_instance_i + + atoms = SE_old_i.atoms + bulk_atoms = SE_old_i.bulk_atoms + H_ref_electronic_energy = SE_old_i.H_ref_electronic_energy + O_ref_electronic_energy = SE_old_i.O_ref_electronic_energy + + SE_new = SurfaceEnergy( + atoms=atoms, + bulk_atoms=bulk_atoms, + bulk_electronic_energy_per_atom=new_bulk_energy, + H_ref_electronic_energy=H_ref_electronic_energy, + O_ref_electronic_energy=O_ref_electronic_energy, + verbose=verbose, + ) + + new_SurfaceEnergy_instances.append(SE_new) + + return(new_SurfaceEnergy_instances) + #__| + + + def __calc_ave_surface_energy__(self, SurfaceEnergy_instances): + """ + """ + #| - __calc_ave_surface_energy__ + # new_SurfaceEnergy_instances = self.new_SurfaceEnergy_instances + # SurfaceEnergy_instances = self.SurfaceEnergy_instances + # if + + y_surface_e = [] + x_slab_thickness = [] + for SE_inst_i in SurfaceEnergy_instances: + y_surface_e.append(SE_inst_i.surface_e_per_area) + x_slab_thickness.append(SE_inst_i.slab_thickness) + + df = pd.DataFrame() + + df["surface_energy_per_area"] = y_surface_e + df["slab_thickness"] = x_slab_thickness + + + # Number of points in the Energy vs Slab_thickness plot to include + # in the average for the new surface energy + num_points_to_average = 3 + nptoa = num_points_to_average + + df = df.sort_values("slab_thickness") + ave_surface_e = df.iloc[-nptoa:]["surface_energy_per_area"].mean() + + return(ave_surface_e) + #__| + + def plot_E_vs_N_convergence(self): + """ + """ + #| - plot_E_vs_N_convergence + df = self.df + + number_of_atoms = df["number_of_atoms"] + potential_energy_list = df["potential_energy"] + + trace_i = go.Scatter( + x=number_of_atoms, + y=potential_energy_list, + mode='markers+lines', + # name=name_i, + + marker=dict( + symbol="square", + size=10, + # color=color, + line=dict( + width=1, + color='rgb(0, 0, 0)', + ), + ), + + ) + + return(trace_i) + #__| + + + + #__| ********************************************************************** + + + + +#| - METHODS + +def surface_energy_2( + df_i, + num_points_to_exclude=0, + trace_title="surface_energy_2", + color="blue", + ): + """ + Calculates the "average" surface energy, but with a bulk_e_per_atom that + is fitted to a range of slab thicknesses. + """ + #| - surface_energy_2 + nbpe = num_points_to_exclude + + y_i = df_i["elec_energy"].tolist() + x_i=df_i["N_atoms"].tolist() + + z = np.polyfit(x_i[nbpe:], y_i[nbpe:], 1) + bulk_e_per_atom_i = z[0] + + surf_e_2=df_i["elec_energy"] - df_i["N_atoms"] * bulk_e_per_atom_i + surf_e_2=surf_e_2 / df_i.iloc[0]["slab_area"] + + trace=go.Scatter( + x=df_i["layers"], + y=surf_e_2.tolist(), +# mode='markers', + mode='lines+markers', + name=trace_title, + marker=dict( + symbol="circle", + size=12, + color=color, + line=dict( + width=2, + color='rgb(0, 0, 0)' + ) + ), + ) + + return(trace) + #__| + + +def surf_e_4( + row_i, + G_H2=0., + G_H2O=0., + bias=0., + pH=0., + bulk_e_per_atom=None, + get_e0_from_row=False, + norm_mode="area", # 'area' or 'atoms' + num_atoms=None, + ): + """ + Calculate surface energy assuming a water reference state + and using the computational hydrogen electrode. + """ + #| - surf_e_4 + + #| - Read info from row_i + # COMBAK This shouldn't be hard coded in + metal = "Ir" + + atoms_i = row_i.get("init_atoms", default=None) + elec_energy = row_i.get("elec_energy", default=0.) + nonstoich_Os = row_i.get("nonstoich_Os", default=0) + elems_dict = row_i.get("elem_num_dict", default={}) + + if bulk_e_per_atom is None: + bulk_e_per_atom = row_i.get("bulk_e_per_atom_DFT", default=0.) + + # print("bulk_e_per_atom: ", bulk_e_per_atom) + + N_stoich_in_slab = elems_dict[metal] + elems_dict.get("O", 0) - nonstoich_Os + nonstoich_Hs = elems_dict.get("H", 0) + #__| + + #| - Calculate Standard State Surface Energy + if "surf_e_0" in row_i: + surf_e_0 = row_i.get("surf_e_0", default=0.) + else: + surf_e_0 = 0. + \ + +elec_energy + \ + -N_stoich_in_slab * bulk_e_per_atom + \ + -nonstoich_Os * (G_H2O - G_H2) + \ + -nonstoich_Hs * (G_H2 / 2) + \ + +0. + + if norm_mode == "area": + surf_e_0 = surf_e_0 / (2 * row_i["slab_area"]) + elif norm_mode == "atoms": + if num_atoms is not None: + surf_e_0 = surf_e_0 / (2 * num_atoms) + #__| + + #| - Calculate V, pH Dependant Surface Energy + slope = 2 * nonstoich_Os - nonstoich_Hs + + surf_e = 0. + \ + +surf_e_0 + \ + +(slope * 0.0591 * pH) / (2 * row_i["slab_area"]) + \ + -(slope * bias) / (2 * row_i["slab_area"]) + \ + +0. + +# surf_e = surf_e / (2 * row_i["slab_area"]) + #__| + + return(surf_e) + #__| + +#__| From b57ace1352697c48cdbf26e86df2db360abb5d76 Mon Sep 17 00:00:00 2001 From: Raul Flores Date: Tue, 6 Aug 2019 17:23:24 -0700 Subject: [PATCH 13/16] Initial commit of xrd_spectra class --- xrd_spectra/xrd.py | 625 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 625 insertions(+) create mode 100644 xrd_spectra/xrd.py diff --git a/xrd_spectra/xrd.py b/xrd_spectra/xrd.py new file mode 100644 index 0000000..bd9aa1b --- /dev/null +++ b/xrd_spectra/xrd.py @@ -0,0 +1,625 @@ +#!/usr/bin/env python + +"""Module to analyze and plot simulated XRD spectra from VESTA + +# 31.0: | (111) | Heighest peak +# 25.9: | (110) | 2nd highest peak +# 35.9: | (021) | 3rd highest peak +# 56.2 & 56.3 | (221) | 4th highest peak +# 33.75 | (002) | 5th highest peak +# 43.03 | (112) | 6th +# 54.7 & 54.8 | (202) | 7th +# 58.65 | (113) | 8th +# 41.7 & 41.8 | (200) | 9th + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import os +import math + +import pandas as pd +import numpy as np +import pickle + +from sympy import Symbol +from sympy import * + +from pathlib import Path + +from tqdm import tqdm +import time + + +import chart_studio.plotly as py +import plotly.graph_objs as go +from plotly import io as pyio + +from scipy.signal import find_peaks +#__| + + +class XRD_Spectra: + """TEMP. + """ + + #| - XRD_Spectra ****************************************************** + _SAVE_FOLDER_NAME = ".xrd_save_dir" + _SAVE_FILE_NAME = "xrd_save_state.pickle" + _SAVE_ATTRIBUTES = ["df_peaks", "temp_0"] + + + def __init__(self, + reflections_table_path=None, + theta_range=[0, 150], + theta_spacing=0.1, + load_from_saved_state=True, + peak_broadening=0.04, + ): + """ + + Args: + reflections_table_path: str + path + file_name of reflections table text file + theta_range: list, len=2 + x-axis range of 2theta (should be 2theta not theta) + theta_spacing: float + Discritized spacing of x-axis (2theta) + load_from_saved_state: Bool + Whether to attempt to load attributes from file to save time + peak_broadening: float + Dictates the broadness of peaks (smaller is thinner) + """ + #| - __init__ + self.temp_0 = "TEMP TEMP TEMP TEMP" + + #| - Setting Argument Instance Attributes + self.reflections_table_path = reflections_table_path + self.theta_range = theta_range + self.theta_spacing = theta_spacing + self.load_from_saved_state = load_from_saved_state + self.peak_broadening = peak_broadening + #__| + + #| - Initializing Internal Instance Attributes + self.df_peaks = None + #__| + + # Try to load previous saved state + self.loaded_state_data = self.__load_state__() + + self.theta_array = self.__create_theta_array__() + + self.df = self.__read_reflections_table__() + + self.__process_reflections_table__() + + self.__create_lorentz_for_all_signals__() + + self.summed_lorentz = self.__create_summed_lorentz_function__() + + self.spectrum = self.__create_total_spectrum__() + #__| + + + def __read_reflections_table__(self): + """ + """ + #| - __read_reflections_table__ + file_path_i = self.reflections_table_path + # file_path_i = "/home/raulf2012/Dropbox/01_norskov/00_projects/columbite_iro2_oer/workflow/01_latt_const_opt/an_xrd_pattern/vesta_xrd_gen/optimized_bulk.txt" + + with open(file_path_i) as f: + content = f.readlines() + content = [x.strip() for x in content] + + list_of_rows = [] + for i_cnt, line_i in enumerate(content): + if i_cnt == 0: + header_row = line_i + continue + + list_of_vals = [i for i in line_i.split(" ") if i is not ""] + row_i = { + "h": int(list_of_vals[0]), + "k": int(list_of_vals[1]), + "l": int(list_of_vals[2]), + "d": float(list_of_vals[3]), + "F_real": float(list_of_vals[4]), + "F_imag": float(list_of_vals[5]), + "F_abs": float(list_of_vals[6]), + "2theta": float(list_of_vals[7]), + "I": float(list_of_vals[8]), + "M": float(list_of_vals[9]), + "theta": float(list_of_vals[10]), + "Phase": float(list_of_vals[11])} + list_of_rows.append(row_i) + + df = pd.DataFrame(list_of_rows) + + return(df) + + # column_headers = [i for i in header_row.split(" ") if i is not ""] + # df.columns = column_headers + # df = pd.read_csv("../vesta_xrd_gen/reflections_table.csv") + # df = df.sort_values("I", ascending=False) + #__| + + + def __process_reflections_table__(self): + """ + """ + #| - __process_reflections_table__ + self.__create_simplified_facet_string__() + + #__| + + + def __create_simplified_facet_string__(self): + """ + """ + #| - __create_simplified_facet_string__ + df = self.df + + # Create string facet representation + df["facet_mine"] = abs(df["h"]).astype("str") + abs(df["k"]).astype("str") + abs(df["l"]).astype("str") + #__| + + + def __create_lorentz_for_all_signals__(self): + """Create lorentz function for all signals. + + Adds column to df + """ + #| - __create_lorentz_for_all_signals__ + df = self.df + peak_broadening = self.peak_broadening + + + # Sympy addition of all functions + x = Symbol("x") + x0 = Symbol("x0") + gamma = Symbol("gamma") + peak_height = Symbol("peak_height") + + funct_list = [] + for i_ind, row_i in df.iterrows(): + gamma_i = peak_broadening + intensity_i = row_i["I"] + x0_i = row_i["2theta"] + funct_i = Lorentz_i(x0, x, gamma, peak_height).subs({ + x0: x0_i, + gamma: gamma_i, + peak_height: intensity_i}) + funct_list.append(funct_i) + + df["function"] = funct_list + #__| + + + def __create_summed_lorentz_function__(self): + """ + """ + #| - __create_summed_lorentz_function__ + df = self.df + + sum_funct = np.sum(df["function"].tolist()) + + return(sum_funct) + #__| + + + def __create_theta_array__(self): + """ + """ + #| - __create_theta_array__ + # Compute Signal + theta_range = self.theta_range + theta_spacing = self.theta_spacing + + min_theta = theta_range[0] + max_theta = theta_range[1] + # # x_range = np.arange(1, 150, 1.) #interval of points + # min_theta = 1 + # max_theta = 80 + + x_range = np.arange(min_theta, max_theta, theta_spacing) + + return(x_range) + #__| + + + def __create_total_spectrum__(self): + """ + """ + #| - __create_total_spectrum__ + summed_lorentz = self.summed_lorentz + # theta_range = self.theta_range + theta_array = self.theta_array + x = Symbol("x") + + a = lambdify((x, ), summed_lorentz) + spectrum = a(np.array(theta_array)) + + # Normalizing signal to 100 + spectrum = 100 * (spectrum / spectrum.max()) + + return(spectrum) + #__| + + + def compute_peak_positions(self): + """ + """ + #| - compute_peak_positions + + #| - Class Attributes + spectrum = self.spectrum + df = self.df + theta_array = self.theta_array + theta_array = self.theta_array + theta_range = self.theta_range + + loaded_state_data = self.loaded_state_data + #__| + + + bool_0 = (loaded_state_data is not None) + if bool_0: + bool_1 = ("df_peaks" in list(loaded_state_data.keys())) + if bool_1: + print("Loaded 'df_peaks' from save state") + df_peaks = loaded_state_data["df_peaks"] + + else: + print("Computing 'df_peaks' from scratch") + + time.sleep(3) # TEMP + + min_theta = theta_range[0] + max_theta = theta_range[1] + + x = Symbol("x") + + #| - Computing Peak Positions + # Used for peak_finder to set width + grid_to_theta = len(theta_array) / (max_theta - min_theta) + + + peaks = find_peaks( + spectrum, + height=4, + # threshold=1, + distance=grid_to_theta * 1.) + + peaks_x = [theta_array[i] for i in peaks[0]] + #__| + + + #| - Computing the Main Facets for the Prominant Peaks + main_facets_list = [] + peaks_x_tqdm = tqdm(peaks_x) + for peak_x_i in peaks_x_tqdm: + peaks_x_tqdm.set_description("Processing %s" % peak_x_i) + + intensity_list = [] + for i_ind, row_i in df.iterrows(): + funct_i = row_i["function"] + + a = lambdify((x, ), funct_i) + signal_i = a(np.array([peak_x_i])) + + if type(signal_i) is int: + intensity_list.append(float(signal_i)) + elif type(signal_i).__module__ == np.__name__: + assert len(signal_i) == 1, "ISDFJIDSJfi" + intensity_list.append(signal_i[0]) + + df[peak_x_i] = intensity_list + + highest_contributions = df.sort_values( + peak_x_i, ascending=False)[peak_x_i].unique()[0:1] + + major_facets = df[df[peak_x_i].isin( + highest_contributions)].sort_values( + peak_x_i, ascending=False)["facet_mine"].unique() + + main_facets_i = "_".join(major_facets) + + main_facets_list.append(main_facets_i) + #__| + + df_peaks = pd.DataFrame() + df_peaks["main_facets"] = main_facets_list + df_peaks["2theta"] = peaks_x + df_peaks["intensity"] = peaks[1]["peak_heights"] + + + self.df_peaks = df_peaks + + + # df.sort_values(peak_x_i, ascending=False)[peak_x_i].unique()[0:4] + # + # # df[df[peak_x_i].isin(highest_contributions)].sort_values( + # # peak_x_i, ascending=False)["facet_mine"] + # + # df[df[peak_x_i].isin(highest_contributions)].sort_values( + # peak_x_i, ascending=False) + #__| + + + def __create_save_dir__(self): + """ + """ + #| - __create_save_dir__ + save_folder_name = self._SAVE_FOLDER_NAME + if not os.path.exists(save_folder_name): + os.makedirs(save_folder_name) + #__| + + + def __save_state__(self): + """ + """ + #| - __save_states__ + save_folder_name = self._SAVE_FOLDER_NAME + save_file_name = self._SAVE_FILE_NAME + + self.__create_save_dir__() + + save_attributes = dict() + for _SAVE_ATTRIBUTE_i in self._SAVE_ATTRIBUTES: + attr_i = getattr(self, _SAVE_ATTRIBUTE_i) + + save_attributes[_SAVE_ATTRIBUTE_i] = attr_i + + with open(os.path.join(save_folder_name, save_file_name), "wb") as fle: + pickle.dump(save_attributes, fle) + #__| + + + def __load_state__(self): + """ + """ + #| - __load_state__ + save_folder_name = self._SAVE_FOLDER_NAME + save_file_name = self._SAVE_FILE_NAME + load_from_saved_state = self.load_from_saved_state + + save_data = None + if load_from_saved_state: + path_i = os.path.join(save_folder_name, save_file_name) + file_i = Path(path_i) + if file_i.is_file(): + print("SUCCESS: Loaded save state data") + with open(path_i, "rb") as fle: + save_data = pickle.load(fle) + else: + pass + + return(save_data) + #__| + + #__| ********************************************************************** + + +class XRD_Plot(): + """TEMP. + """ + + #| - XRD_Plot ************************************************************* + def __init__(self, + XRD_Spectra, + + + ): + """ + """ + #| - __init__ + + #| - Setting Instance Attributes + self.XRD_Spectra = XRD_Spectra + #__| + + def create_figure(self): + """ + """ + #| - create_figure + data = [] + + trace_i = self.__trace_peak_labels__() + data.append(trace_i) + + trace_i = self.__trace_spectra__() + data.append(trace_i) + + return(data) + #__| + + def __trace_peak_labels__(self): + """ + """ + #| - __trace_peak_labels__ + df_peaks = self.XRD_Spectra.df_peaks + + trace_i = go.Scatter( + x=df_peaks["2theta"], + y=df_peaks["intensity"] + 5, + text=df_peaks["main_facets"], + # mode="markers+text", + mode="text", + + # text=df_peaks["main_facets"], + + hoverinfo=None, + hoverinfosrc=None, + hoverlabel=None, + hoveron=None, + hovertemplate=None, + hovertemplatesrc=None, + hovertext=df_peaks["main_facets"], + hovertextsrc=None, + ) + + return(trace_i) + + # data.append(trace_1) + #__| + + + def __trace_spectra__(self): + """ + """ + #| - __trace_spectra__ + theta_array = self.XRD_Spectra.theta_array + spectrum = self.XRD_Spectra.spectrum + + trace_i = go.Scatter( + x=theta_array, + y=spectrum, + mode="lines", + hoverinfo="skip", + ) + + return(trace_i) + #__| + + def get_layout(self): + """ + """ + #| - get_layout + layout = go.Layout() + + layout.width = 18.4 * 37.795275591 + layout.height = 10 * 37.795275591 + + # layout.width = 10 * 37.795275591 + # layout.height = 6 * 37.795275591 + + layout.margin = go.layout.Margin( + b=60, + l=80, + r=10, + t=10, + ) + + layout.paper_bgcolor='rgba(240,240,240,0.8)' + layout.plot_bgcolor='rgba(250,250,250,0.9)' + # layout.plot_bgcolor='rgba(100,100,100,0.9)' + + layout.font = dict( + family='Arial', + # size=18, + color='black', + ) + + shared_dict = dict( + title_font=dict( + size=10.5 * (4/3), + # family='Courier', + # color='crimson', + ), + tickfont=dict(size=9 * (4/3)), + ) + + layout.xaxis = go.layout.XAxis( + mirror=True, + range=[20, 70], + # tickmode=, + automargin=True, + showgrid=False, + + + ticks="outside", + title="2θ", + + showticklabels=True, + + zeroline=False, + zerolinecolor="black", + + showline=True, + linecolor="black", + + **shared_dict, + ) + + layout.yaxis = go.layout.YAxis( + automargin=True, + mirror=True, + range=[0, 115], + showgrid=False, + showline=True, + showticklabels=True, + # tickmode=, + linecolor="black", + zerolinecolor="black", + ticks="outside", + title="Intensity (Arbitrary Units)", + zeroline=False, + + **shared_dict, + ) + + return(layout) + #__| + + #__| + + + #__| ********************************************************************** + + +#| - METHODS + +def get_weighted_xrange(x_bounds, gamma, x0, min_step_size=1): + """ + """ + #| - get_weighted_xrange + x_i = x_bounds[0] + x_range= [x_i] + while x_i < x_bounds[-1]: + pi = math.pi + term_1 = (gamma ** 2) * ((x_i - x0) ** 2 + gamma ** 2) ** (-1) + step_i = (0.5) * (term_1) ** -1 + + if step_i > min_step_size: + step_i = min_step_size + x_new = x_i + step_i + + x_i = x_new + x_range.append(x_i) + + return(x_range) + #__| + +def Lorentz_i(x0, x, gamma, peak_height): + """ + """ + #| - Lorentz_i + pi = math.pi + term_0 = (1 / (pi * gamma)) + term_1 = (gamma ** 2) * ((x - x0) ** 2 + gamma ** 2) ** (-1) +# y_i = term_0 * term_1 + y_i = peak_height * term_1 + + return(y_i) + #__| + +def Lorentz_distr_i(x0, x_bounds, gamma, intensity): + """ + """ + #| - Lorentz_distr_i + x_range = get_weighted_xrange(x_bounds, gamma, x0, min_step_size=2) + + + lorentz_distr = [] + for x_i in x_range: + y_i = Lorentz_i(x0, x_i, gamma, intensity) + lorentz_distr.append(y_i) + + return(x_range, lorentz_distr) + #__| + +#__| From d6d9376a1dba8b472f4595b7e8de6a8544c70a67 Mon Sep 17 00:00:00 2001 From: Raul Flores Date: Wed, 7 Aug 2019 12:56:18 -0700 Subject: [PATCH 14/16] misc updates --- surface_energy/surface_energy.py | 311 +++++++++++++++++++++++-------- 1 file changed, 233 insertions(+), 78 deletions(-) diff --git a/surface_energy/surface_energy.py b/surface_energy/surface_energy.py index d6b7617..39c80a7 100644 --- a/surface_energy/surface_energy.py +++ b/surface_energy/surface_energy.py @@ -14,7 +14,6 @@ from ase_modules.ase_methods import create_species_element_dict from pymatgen.core.composition import Composition -from ase_modules.ase_methods import create_species_element_dict #__| @@ -75,7 +74,6 @@ def __init__(self, self.non_stoich_comp = None - # TODO implement method to calc slab thickness self.slab_thickness = None self.__bulk_energy_per_atom__ = None @@ -104,7 +102,7 @@ def __init__(self, self.surface_e_per_area = self.__calc_std_surface_energy_per_area__() - if self.num_surface_atoms is not None: + if self.num_surface_atoms is not None: self.surface_e_per_surface_atom = \ self.__calc_std_surface_energy_per_surface_atom__() @@ -160,13 +158,12 @@ def __calc_std_surface_energy_per_area__(self): def __calc_std_surface_energy_per_surface_atom__(self): """Normalize the surface area to a per surface atom basis.""" #| - calc_std_surface_energy_per_area - num_surface_atoms = self.num_surface_atoms + num_surface_atoms = self.num_surface_atoms surface_e_per_side = self.surface_e_per_side - surface_e_per_surface_atoms = surface_e_per_side / num_surface_atoms - return(surface_e_per_area) + return(surface_e_per_surface_atoms) #__| @@ -184,6 +181,7 @@ def __calc_surface_area__(self): return(area_i) #__| + def __get_electronic_energy__(self, atoms, electronic_energy, @@ -225,7 +223,8 @@ def __calc_units_of_bulk_in_slab__(self): comp0 = Composition(bulk_atoms.get_chemical_formula()) df = pd.DataFrame([ - create_species_element_dict(atoms, elems_to_always_include=["O", "H"]), + create_species_element_dict(atoms, + elems_to_always_include=["O", "H"]), dict(comp0.to_data_dict["reduced_cell_composition"])], index=["slab", "bulk"]) @@ -239,7 +238,8 @@ def __calc_units_of_bulk_in_slab__(self): bulk_comp_array = np.array(list(df.loc["bulk"])) # Number of unit of the bulk's reduced formula that fit into the slab - bulk_formula_units_in_slab = int(min(slab_comp_array / bulk_comp_array)) + bulk_formula_units_in_slab = min(slab_comp_array / bulk_comp_array) + bulk_formula_units_in_slab = int(bulk_formula_units_in_slab) bfuis = bulk_formula_units_in_slab # ##################################################################### @@ -295,8 +295,8 @@ def __calc_bulk_energy_per_formula_unit__(self): """ """ #| - __calc_bulk_energy_per_formula_unit__ + # bulk_formula_reduction = self.__bulk_formula_reduction__ bulk_electronic_energy = self.bulk_electronic_energy - bulk_formula_reduction = self.__bulk_formula_reduction__ num_atoms_reduced_bulk = self.__num_atoms_reduced_bulk__ bulk_atoms = self.bulk_atoms @@ -317,7 +317,9 @@ def __calc_slab_thickness__(self): #| - __calc_slab_thickness__ atoms = self.atoms - slab_thickness = max(atoms.positions[:, 2]) - min(atoms.positions[:, 2]) + positions = atoms.positions + + slab_thickness = max(positions[:, 2]) - min(positions[:, 2]) return(slab_thickness) #__| @@ -327,6 +329,7 @@ def __calc_slab_thickness__(self): #__| ********************************************************************** + class SurfaceEnergyConvergence: """Compute properties from series of slabs of increasing thickness. @@ -340,6 +343,7 @@ class SurfaceEnergyConvergence: def __init__(self, SurfaceEnergy_instances=None, + bulk_electronic_energy_per_atom=None, num_points_to_exclude=1, verbose=True, ): @@ -357,7 +361,7 @@ def __init__(self, #| - Setting Argument Instance Attributes self.SurfaceEnergy_instances = SurfaceEnergy_instances self.num_points_to_exclude = num_points_to_exclude - + self.bulk_electronic_energy_per_atom = bulk_electronic_energy_per_atom self.verbose = verbose #__| @@ -376,48 +380,64 @@ def __init__(self, # Enough data to fit? self.__sufficient_data_to_fit_bulk() - if self.sufficient_data_to_fit_bulk: - self.fitted_bulk_energy = self.__calc_regressed_bulk_energy__() - - self.new_SurfaceEnergy_instances = \ - self.__recalc_SurfaceEnergy_w_new_bulk__( - self.fitted_bulk_energy) - - self.new_ave_surface_energy_per_area = \ - self.__calc_ave_surface_energy__( - self.new_SurfaceEnergy_instances) #__| - def inst_surf_e_with_fitted_bulk(self): + + def calculate_surface_energies(self, bulk_energy=None): """ """ - #| - tmp_meth - fitted_bulk_energy = self.fitted_bulk_energy - SurfaceEnergy_instances = self.SurfaceEnergy_instances - - SE_old_i = SurfaceEnergy_instances[0] + #| - calculate_surface_energies + self.new_SurfaceEnergy_instances = \ + self.__recalc_SurfaceEnergy_w_new_bulk__( + bulk_energy) - atoms = SE_old_i.atoms + # self.fitted_bulk_energy) + self.new_ave_surface_energy_per_area = \ + self.__calc_ave_surface_energy__( + self.new_SurfaceEnergy_instances) + #__| - SurfaceEnergy( - atoms=atoms, - # electronic_energy=None, # Only needed if not within atoms object - - bulk_atoms=None, - bulk_electronic_energy=None, - - H_ref_electronic_energy=None, - O_ref_electronic_energy=None, + def fit_bulk_energy(self): + """ + """ + #| - fit_bulk_energy + if self.sufficient_data_to_fit_bulk: + self.fitted_bulk_energy = self.__calc_regressed_bulk_energy__() + #__| - # num_surface_atoms=None, - # bias=0., - # pH=0., - ) + def inst_surf_e_with_fitted_bulk(self): + """ + COMBAK: This isn't being used now + """ + #| - tmp_meth + # fitted_bulk_energy = self.fitted_bulk_energy + # SurfaceEnergy_instances = self.SurfaceEnergy_instances + # + # SE_old_i = SurfaceEnergy_instances[0] + # + # atoms = SE_old_i.atoms + # + # + # SurfaceEnergy( + # atoms=atoms, + # # electronic_energy=None, + # + # bulk_atoms=None, + # bulk_electronic_energy=None, + # + # H_ref_electronic_energy=None, + # O_ref_electronic_energy=None, + # + # # num_surface_atoms=None, + # # bias=0., + # # pH=0., + # ) #__| + def __init_dataframe__(self): """ """ @@ -495,36 +515,36 @@ def __calc_regressed_bulk_energy__(self): #__| -def __recalc_SurfaceEnergy_w_new_bulk__(self, new_bulk_energy): - """ - """ - #| - __recalc_SurfaceEnergy_w_new_bulk__ - SurfaceEnergy_instances = self.SurfaceEnergy_instances - # new_bulk_energy = self.new_bulk_energy - verbose = self.verbose - - new_SurfaceEnergy_instances = [] - for SurfaceEnergy_instance_i in SurfaceEnergy_instances: - SE_old_i = SurfaceEnergy_instance_i - - atoms = SE_old_i.atoms - bulk_atoms = SE_old_i.bulk_atoms - H_ref_electronic_energy = SE_old_i.H_ref_electronic_energy - O_ref_electronic_energy = SE_old_i.O_ref_electronic_energy - - SE_new = SurfaceEnergy( - atoms=atoms, - bulk_atoms=bulk_atoms, - bulk_electronic_energy_per_atom=new_bulk_energy, - H_ref_electronic_energy=H_ref_electronic_energy, - O_ref_electronic_energy=O_ref_electronic_energy, - verbose=verbose, - ) + def __recalc_SurfaceEnergy_w_new_bulk__(self, new_bulk_energy): + """ + """ + #| - __recalc_SurfaceEnergy_w_new_bulk__ + SurfaceEnergy_instances = self.SurfaceEnergy_instances + # new_bulk_energy = self.new_bulk_energy + verbose = self.verbose + + new_SurfaceEnergy_instances = [] + for SurfaceEnergy_instance_i in SurfaceEnergy_instances: + SE_old_i = SurfaceEnergy_instance_i + + atoms = SE_old_i.atoms + bulk_atoms = SE_old_i.bulk_atoms + H_ref_electronic_energy = SE_old_i.H_ref_electronic_energy + O_ref_electronic_energy = SE_old_i.O_ref_electronic_energy + + SE_new = SurfaceEnergy( + atoms=atoms, + bulk_atoms=bulk_atoms, + bulk_electronic_energy_per_atom=new_bulk_energy, + H_ref_electronic_energy=H_ref_electronic_energy, + O_ref_electronic_energy=O_ref_electronic_energy, + verbose=verbose, + ) - new_SurfaceEnergy_instances.append(SE_new) + new_SurfaceEnergy_instances.append(SE_new) - return(new_SurfaceEnergy_instances) - #__| + return(new_SurfaceEnergy_instances) + #__| def __calc_ave_surface_energy__(self, SurfaceEnergy_instances): @@ -559,7 +579,9 @@ def __calc_ave_surface_energy__(self, SurfaceEnergy_instances): #__| def plot_E_vs_N_convergence(self): - """ + """Plot raw slab energy vs number of atoms. + + The slope of this plot is the fitted bulk energy """ #| - plot_E_vs_N_convergence df = self.df @@ -589,9 +611,139 @@ def plot_E_vs_N_convergence(self): #__| + def plot_surface_energy(self, + name_i="TEMP", + color_i="pink" + ): + """ + """ + #| - plot_surface_energy + data = [] - #__| ********************************************************************** + #| - Surface Energy (DFT Bulk) ######################################## + y_surface_e = []; x_slab_thickness = [] + for SE_inst_i in self.SurfaceEnergy_instances: + y_surface_e.append(SE_inst_i.surface_e_per_area) + x_slab_thickness.append(SE_inst_i.slab_thickness) + + trace_i = go.Scatter( + x=x_slab_thickness, + y=y_surface_e, + mode='markers+lines', + name=name_i, + legendgroup=name_i, + showlegend=True, + line=dict( + width=1.5, + color=color_i, + dash='dash', + ), + marker=dict( + symbol="square", + size=8, + color=color_i, + line=dict( + width=1.0, + color="black", + ), + ), + ) + data.append(trace_i) + #__| + + #| - Surface Energy (Fitted Bulk) ##################################### + y_surface_e = []; x_slab_thickness = [] + for SE_inst_i in self.new_SurfaceEnergy_instances: + y_surface_e.append(SE_inst_i.surface_e_per_area) + x_slab_thickness.append(SE_inst_i.slab_thickness) + + trace_i = go.Scatter( + x=x_slab_thickness, + y=y_surface_e, + mode='markers+lines', + name=name_i, + # legendgroup=name_i, + showlegend=False, + line=dict( + width=1.5, + color=color_i, + dash='solid', + ), + marker=dict( + symbol="circle", + size=10, + color=color_i, + line=dict( + width=1.5, + color="black", + # dash='solid', + ), + ), + ) + data.append(trace_i) + #__| + + #| - Average Surface Energy (DFT Bulk) ################################ + ave_surface_energy = self.ave_surface_energy_per_area + trace_i = go.Scatter( + x=[0, 30], + y=[ave_surface_energy, ave_surface_energy], + name=name_i, + # legendgroup=name_i, + mode='lines', + showlegend=False, + line=dict( + width=1.5, + color=color_i, + dash='dash', + ), + marker=dict( + symbol="square", + size=10, + color=color_i, + line=dict( + width=1, + # color='rgb(0, 0, 0)', + color=color_i, + ), + ), + ) + data.append(trace_i) + #__| + + #| - Average Surface Energy (Fitted Bulk) ############################# + ave_surface_energy = self.new_ave_surface_energy_per_area + trace_i = go.Scatter( + x=[0, 30], + y=[ave_surface_energy, ave_surface_energy], + name=name_i, + # legendgroup=name_i, + mode='lines', + showlegend=False, + line=dict( + width=1.5, + color=color_i, + dash='solid', + ), + marker=dict( + symbol="square", + size=10, + color=color_i, + line=dict( + width=1, + color="black", + ), + ), + ) + data.append(trace_i) + #__| + + return(data) + #__| + + + #__| ********************************************************************** @@ -611,18 +763,18 @@ def surface_energy_2( nbpe = num_points_to_exclude y_i = df_i["elec_energy"].tolist() - x_i=df_i["N_atoms"].tolist() + x_i = df_i["N_atoms"].tolist() z = np.polyfit(x_i[nbpe:], y_i[nbpe:], 1) bulk_e_per_atom_i = z[0] - surf_e_2=df_i["elec_energy"] - df_i["N_atoms"] * bulk_e_per_atom_i - surf_e_2=surf_e_2 / df_i.iloc[0]["slab_area"] + surf_e_2 = df_i["elec_energy"] - df_i["N_atoms"] * bulk_e_per_atom_i + surf_e_2 = surf_e_2 / df_i.iloc[0]["slab_area"] - trace=go.Scatter( + trace = go.Scatter( x=df_i["layers"], y=surf_e_2.tolist(), -# mode='markers', + # mode='markers', mode='lines+markers', name=trace_title, marker=dict( @@ -661,7 +813,7 @@ def surf_e_4( # COMBAK This shouldn't be hard coded in metal = "Ir" - atoms_i = row_i.get("init_atoms", default=None) + # atoms_i = row_i.get("init_atoms", default=None) elec_energy = row_i.get("elec_energy", default=0.) nonstoich_Os = row_i.get("nonstoich_Os", default=0) elems_dict = row_i.get("elem_num_dict", default={}) @@ -671,7 +823,9 @@ def surf_e_4( # print("bulk_e_per_atom: ", bulk_e_per_atom) - N_stoich_in_slab = elems_dict[metal] + elems_dict.get("O", 0) - nonstoich_Os + N_stoich_in_slab = elems_dict[metal] + \ + elems_dict.get("O", 0) - nonstoich_Os + nonstoich_Hs = elems_dict.get("H", 0) #__| @@ -685,6 +839,7 @@ def surf_e_4( -nonstoich_Os * (G_H2O - G_H2) + \ -nonstoich_Hs * (G_H2 / 2) + \ +0. + # -nonstoich_Hs * (G_H2) + \ if norm_mode == "area": surf_e_0 = surf_e_0 / (2 * row_i["slab_area"]) From 922fef23b77cb412df04a4c93d2aecd3c2db3b59 Mon Sep 17 00:00:00 2001 From: raulf2012 Date: Thu, 8 Aug 2019 09:25:30 -0700 Subject: [PATCH 15/16] dos2unix on everything --- .gitignore | 100 +- .idea/00_PythonModules.iml | 20 +- .idea/misc.xml | 6 +- .idea/modules.xml | 14 +- .idea/vcs.xml | 10 +- .idea/workspace.xml | 276 +- README.md | 14 +- __init__.py | 2 +- __misc__/sc_temp_methods.py | 144 +- ase_modules/__init__.py | 2 +- ase_modules/add_adsorbate.py | 294 +- ase_modules/adsorbates.py | 264 +- ase_modules/ase_methods.py | 4884 ++-- ase_modules/atoms_wrap.py | 20 +- ase_modules/dft-params.json | 20 +- ase_modules/dft_params.py | 1108 +- ase_modules/get_G.py | 1604 +- atoms_objects/slab_generation.py | 262 +- aws/aws_class.py | 830 +- bader_charge/bader.py | 694 +- classical_methods/lennard_jones.py | 348 +- colors/colors.py | 294 +- dft_job_automat/__init__.py | 2 +- dft_job_automat/__old__.py | 406 +- dft_job_automat/compute_env.py | 3744 +-- dft_job_automat/job_analysis.py | 3074 +-- dft_job_automat/job_dependencies.py | 1294 +- dft_job_automat/job_manager.py | 1136 +- dft_job_automat/job_setup.py | 2840 +-- .../job_types_classes/data_frame_methods.py | 160 +- .../job_types_classes/dft_methods.py | 786 +- .../job_types_classes/raman_methods.py | 196 +- dft_post_analysis/bands.py | 554 +- dft_post_analysis/charge_density.py | 918 +- dft_post_analysis/dos.py | 796 +- dft_post_analysis/dos_bands_combined.py | 166 +- dft_post_analysis/wf.py | 230 +- docs/Makefile | 38 +- docs/all-about-me.rst | 22 +- docs/ase_modules/ase_modules.rst | 26 +- docs/ase_modules/dft_job_automat.rst | 16 +- docs/ase_modules/tmp_ase_modules0 | 170 +- docs/ase_modules/tmp_dft_job_automat0 | 18 +- docs/conf.py | 344 +- docs/index.rst | 80 +- docs/make.bat | 72 +- energetics/dft_energy.py | 836 +- energetics/formation_energy.py | 216 +- misc_modules/misc_methods.py | 266 +- misc_modules/numpy_methods.py | 110 +- misc_modules/pandas_methods.py | 232 +- misc_modules/plotly_methods.py | 120 +- oxr_reaction/adsorbate_scaling.py | 678 +- oxr_reaction/oxr_methods.py | 1100 +- oxr_reaction/oxr_rxn.py | 484 +- oxr_reaction/oxr_series.py | 1286 +- periodic_table.json | 19270 ++++++++-------- plotting/my_plotly.py | 509 +- plotting/plotly_layout_template.py | 190 + pourbaix_pymatgen/LICENSE | 42 +- pourbaix_pymatgen/README.md | 4 +- pourbaix_pymatgen/data_exp_form_e.py | 244 +- pourbaix_pymatgen/element_list.py | 250 +- pourbaix_pymatgen/energy_scheme.py | 324 +- pourbaix_pymatgen/entry_methods.py | 608 +- pourbaix_pymatgen/find_closest_point_pd.py | 260 +- pourbaix_pymatgen/heat_map.py | 942 +- pourbaix_pymatgen/pd_make.py | 626 +- pourbaix_pymatgen/pd_screen_tools.py | 424 +- pourbaix_pymatgen/pourdiag.py | 150 +- pourbaix_pymatgen/read_coord_data.py | 130 +- pourbaix_pymatgen/save_data.py | 30 +- pourbaix_pymatgen/stability_crit.py | 564 +- .../lennard_jones_regress/lj_regression.py | 1344 +- .../old.lj_regression_180724.py | 1306 +- quantum_espresso/qe_methods.py | 758 +- raman_dft/vasp_raman_job_methods.py | 802 +- readthedocs.py | 30 +- vasp/vasp_methods.py | 660 +- 79 files changed, 31645 insertions(+), 31448 deletions(-) create mode 100644 plotting/plotly_layout_template.py diff --git a/.gitignore b/.gitignore index 5a74899..373489e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,50 +1,50 @@ -# My additions # -################ -*.pyc -* conflicted copy * -*__pycache__* - - -# Compiled source # -################### -*.com -*.class -*.dll -*.exe -*.o -*.so - -# Packages # -############ -# it's better to unpack these files and commit the raw source -# git has its own built in compression methods -*.7z -*.dmg -*.gz -*.iso -*.jar -*.rar -*.tar -*.zip - -# Logs and databases # -###################### -*.log -*.sql -*.sqlite - -# OS generated files # -###################### -.DS_Store -.DS_Store? -._* -.Spotlight-V100 -.Trashes -ehthumbs.db -Thumbs.db - -# readthedocs Documentation # -############################# -_build -_static -_templates +# My additions # +################ +*.pyc +* conflicted copy * +*__pycache__* + + +# Compiled source # +################### +*.com +*.class +*.dll +*.exe +*.o +*.so + +# Packages # +############ +# it's better to unpack these files and commit the raw source +# git has its own built in compression methods +*.7z +*.dmg +*.gz +*.iso +*.jar +*.rar +*.tar +*.zip + +# Logs and databases # +###################### +*.log +*.sql +*.sqlite + +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# readthedocs Documentation # +############################# +_build +_static +_templates diff --git a/.idea/00_PythonModules.iml b/.idea/00_PythonModules.iml index 9c88284..6711606 100644 --- a/.idea/00_PythonModules.iml +++ b/.idea/00_PythonModules.iml @@ -1,11 +1,11 @@ - - - - - - - - - + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 9c1a2cb..1650565 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index b0a0b8b..9252079 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -1,8 +1,8 @@ - - - - - - - + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 9661ac7..94a25f7 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,6 +1,6 @@ - - - - - + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 701c272..48cacfb 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -1,139 +1,139 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + 1523863445926 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 13d0184..5a74575 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# Python modules used in my research - -# Author(s): -Raul Flores - -# Workflowy Development List -https://workflowy.com/#/63d9234f4c4a +# Python modules used in my research + +# Author(s): +Raul Flores + +# Workflowy Development List +https://workflowy.com/#/63d9234f4c4a diff --git a/__init__.py b/__init__.py index 8958fc2..0986fb0 100644 --- a/__init__.py +++ b/__init__.py @@ -1 +1 @@ -#TEMP TEMP 171030 +#TEMP TEMP 171030 diff --git a/__misc__/sc_temp_methods.py b/__misc__/sc_temp_methods.py index 69344dc..be06545 100644 --- a/__misc__/sc_temp_methods.py +++ b/__misc__/sc_temp_methods.py @@ -1,72 +1,72 @@ -#/usr/bin/env python - -"""Temporary storage location for methods. - -Methods here should be fleshed out and included somewhere in 00_PythonModules -""" - -def color_scale_interp( - input_num, - max_num, - min_num, - color_mesh_size=80, - hex_mode=True, - ): - """ - """ - #| - color_scale_interp -# cl.scales["8"]["seq"]["Purples"] - - black_white_cs = [ - 'rgb(0,0,0)', - 'rgb(255,255,255)', - ] - - black_red_cs = [ - 'rgb(0,0,0)', - 'rgb(255,0,0)', - ] - - color_scale_i = black_red_cs - - color_scale_i = cl.scales["8"]["seq"]["Greys"][::-1] -# color_scale_i = cl.scales["8"]["seq"]["Purples"] -# color_scale_i = cl.scales['3']['div']['RdYlBu'] - - color_scale = cl.interp( - color_scale_i, - color_mesh_size, - ) - - color_scale = cl.to_rgb(color_scale) - - # Converting RGB string representatino to tuple - color_scale = cl.to_numeric(color_scale) - - input_norm = ((input_num - min_num)/ (max_num - min_num)) - - cs_index = round(input_norm * len(color_scale)) - 1 - if cs_index == -1: - cs_index = 0 - color_out = color_scale[cs_index] - - if hex_mode: - def rgb_to_hex(rgb_tuple): - """ - """ - r = int(rgb_tuple[0]) - g = int(rgb_tuple[1]) - b = int(rgb_tuple[2]) - - def clamp(x): - return max(0, min(x, 255)) - - hex_rep = "#{0:02x}{1:02x}{2:02x}".format(clamp(r), clamp(g), clamp(b)) - return(hex_rep) - - color_out = rgb_to_hex(color_out) - - - return(color_out) - - #__| +#/usr/bin/env python + +"""Temporary storage location for methods. + +Methods here should be fleshed out and included somewhere in 00_PythonModules +""" + +def color_scale_interp( + input_num, + max_num, + min_num, + color_mesh_size=80, + hex_mode=True, + ): + """ + """ + #| - color_scale_interp +# cl.scales["8"]["seq"]["Purples"] + + black_white_cs = [ + 'rgb(0,0,0)', + 'rgb(255,255,255)', + ] + + black_red_cs = [ + 'rgb(0,0,0)', + 'rgb(255,0,0)', + ] + + color_scale_i = black_red_cs + + color_scale_i = cl.scales["8"]["seq"]["Greys"][::-1] +# color_scale_i = cl.scales["8"]["seq"]["Purples"] +# color_scale_i = cl.scales['3']['div']['RdYlBu'] + + color_scale = cl.interp( + color_scale_i, + color_mesh_size, + ) + + color_scale = cl.to_rgb(color_scale) + + # Converting RGB string representatino to tuple + color_scale = cl.to_numeric(color_scale) + + input_norm = ((input_num - min_num)/ (max_num - min_num)) + + cs_index = round(input_norm * len(color_scale)) - 1 + if cs_index == -1: + cs_index = 0 + color_out = color_scale[cs_index] + + if hex_mode: + def rgb_to_hex(rgb_tuple): + """ + """ + r = int(rgb_tuple[0]) + g = int(rgb_tuple[1]) + b = int(rgb_tuple[2]) + + def clamp(x): + return max(0, min(x, 255)) + + hex_rep = "#{0:02x}{1:02x}{2:02x}".format(clamp(r), clamp(g), clamp(b)) + return(hex_rep) + + color_out = rgb_to_hex(color_out) + + + return(color_out) + + #__| diff --git a/ase_modules/__init__.py b/ase_modules/__init__.py index da2dc82..a4385dd 100644 --- a/ase_modules/__init__.py +++ b/ase_modules/__init__.py @@ -1 +1 @@ -## 171030 +## 171030 diff --git a/ase_modules/add_adsorbate.py b/ase_modules/add_adsorbate.py index 386ea32..361544e 100644 --- a/ase_modules/add_adsorbate.py +++ b/ase_modules/add_adsorbate.py @@ -1,147 +1,147 @@ -#!/usr/bin/env python - -"""Methods to add atoms/adsorbates to surfaces.""" - -#| - Import Modules -import numpy as np -import copy -import math - -from operator import itemgetter -from ase.build import add_adsorbate -from misc_modules.numpy_methods import angle_between -#__| - -def add_adsorbate_centered(active_element, slab, adsorbate, ads_height=2.5): - """Add adsorbate to surface. - - Places an adsorbate above an active element/atom of a slab. If multiple - active elements are present within a unit cell, the adsorbate will be placed - above the atom closest to the center. - - Args: - active_element: String - slab: ASE atoms object - adsorbate: ASE atoms object - ads_height: Float - """ - #| - add_adsorbate_centered - center = (sum(slab.cell)) / 2 - act_metals = [] - for atom in slab: - if atom.symbol == active_element: - act_metals.append([ - atom.index, - np.linalg.norm(atom.position - center), - ]) - - active_metal = slab[sorted(act_metals, key=itemgetter(1))[0][0]] - ads_pos = (active_metal.position[0], active_metal.position[1]) - add_adsorbate(slab, adsorbate, ads_height, position=ads_pos) - - return slab - #__| - - -def add_graphene_layer( - slab, - graphene_units=1, - graph_surf_d=3.0, - graph_bond_d_real=1.4237, - ): - """ - Add graphene layer above surface of hexagonal unit cell slab. - - Args: - slab: - graphene_units: - graph_surf_d: - graph_bond_d_real: - """ - #| - add_graphene_layer - slab = copy.deepcopy(slab) - - # num_graph_units = graphene_units + 1 - graphene_units = int(graphene_units) - - num_graph_units = int(graphene_units) - ngu = num_graph_units - - num_graph_bond_lengths = (2. + 1.) * ngu - - v1 = slab.cell[0] - v2 = slab.cell[1] - - angle = angle_between(v1, v2) - angle = math.degrees(angle) - # print("Angle between lattice vectors: " + str(angle)) - - mag1 = np.linalg.norm(v1) - mag2 = np.linalg.norm(v2) - - assert round(mag1) == round(mag2) - - graph_bond_d = mag1 / num_graph_bond_lengths - - xy_cell = slab.cell[0:2, 0:2] # x and y components of unit cell - x_unit_v = xy_cell[0] - y_unit_v = xy_cell[1] - - x_unit_v = x_unit_v / np.linalg.norm(x_unit_v) - y_unit_v = y_unit_v / np.linalg.norm(y_unit_v) - - - #| - STRAIN - tmp = mag1 / num_graph_bond_lengths - strain = 100. * (graph_bond_d_real - tmp) / graph_bond_d_real - print("Strain: " + str(strain)) - #__| - - patt_cnt_x = 0 - patt_cnt_y = 0 - C_pos_lst = [] - for y_ind in range(graphene_units * 3): - patt_cnt_x = patt_cnt_y - for x_ind in range(graphene_units * 3): - - if patt_cnt_x == 0 or patt_cnt_x == 1: - - pos_x = x_ind * graph_bond_d * x_unit_v - pos_y = y_ind * graph_bond_d * y_unit_v - - pos_i = np.array(pos_x) + np.array(pos_y) - pos_i = np.append(pos_i, 0.) - - C_pos_lst.append(pos_i) - # atom_cent = (origin[0] + x_ind * graph_bond_d - # - graph_bond_d * y_ind * y_unit_v[0], origin[1] + y_ind - # * graph_bond_d) - - add_adsorbate( - slab, - "C", - graph_surf_d, - position=(pos_i[0], pos_i[1]), - ) - - patt_cnt_x += 1 - - elif patt_cnt_x == 2: - patt_cnt_x = 0 - - if patt_cnt_y == 0: - patt_cnt_y = 2 - continue - - if patt_cnt_y == 2: - patt_cnt_y = 1 - continue - - elif patt_cnt_y == 1: - patt_cnt_y = 0 - continue - - C_pos_lst = np.array(C_pos_lst) - - return(slab) - #__| +#!/usr/bin/env python + +"""Methods to add atoms/adsorbates to surfaces.""" + +#| - Import Modules +import numpy as np +import copy +import math + +from operator import itemgetter +from ase.build import add_adsorbate +from misc_modules.numpy_methods import angle_between +#__| + +def add_adsorbate_centered(active_element, slab, adsorbate, ads_height=2.5): + """Add adsorbate to surface. + + Places an adsorbate above an active element/atom of a slab. If multiple + active elements are present within a unit cell, the adsorbate will be placed + above the atom closest to the center. + + Args: + active_element: String + slab: ASE atoms object + adsorbate: ASE atoms object + ads_height: Float + """ + #| - add_adsorbate_centered + center = (sum(slab.cell)) / 2 + act_metals = [] + for atom in slab: + if atom.symbol == active_element: + act_metals.append([ + atom.index, + np.linalg.norm(atom.position - center), + ]) + + active_metal = slab[sorted(act_metals, key=itemgetter(1))[0][0]] + ads_pos = (active_metal.position[0], active_metal.position[1]) + add_adsorbate(slab, adsorbate, ads_height, position=ads_pos) + + return slab + #__| + + +def add_graphene_layer( + slab, + graphene_units=1, + graph_surf_d=3.0, + graph_bond_d_real=1.4237, + ): + """ + Add graphene layer above surface of hexagonal unit cell slab. + + Args: + slab: + graphene_units: + graph_surf_d: + graph_bond_d_real: + """ + #| - add_graphene_layer + slab = copy.deepcopy(slab) + + # num_graph_units = graphene_units + 1 + graphene_units = int(graphene_units) + + num_graph_units = int(graphene_units) + ngu = num_graph_units + + num_graph_bond_lengths = (2. + 1.) * ngu + + v1 = slab.cell[0] + v2 = slab.cell[1] + + angle = angle_between(v1, v2) + angle = math.degrees(angle) + # print("Angle between lattice vectors: " + str(angle)) + + mag1 = np.linalg.norm(v1) + mag2 = np.linalg.norm(v2) + + assert round(mag1) == round(mag2) + + graph_bond_d = mag1 / num_graph_bond_lengths + + xy_cell = slab.cell[0:2, 0:2] # x and y components of unit cell + x_unit_v = xy_cell[0] + y_unit_v = xy_cell[1] + + x_unit_v = x_unit_v / np.linalg.norm(x_unit_v) + y_unit_v = y_unit_v / np.linalg.norm(y_unit_v) + + + #| - STRAIN + tmp = mag1 / num_graph_bond_lengths + strain = 100. * (graph_bond_d_real - tmp) / graph_bond_d_real + print("Strain: " + str(strain)) + #__| + + patt_cnt_x = 0 + patt_cnt_y = 0 + C_pos_lst = [] + for y_ind in range(graphene_units * 3): + patt_cnt_x = patt_cnt_y + for x_ind in range(graphene_units * 3): + + if patt_cnt_x == 0 or patt_cnt_x == 1: + + pos_x = x_ind * graph_bond_d * x_unit_v + pos_y = y_ind * graph_bond_d * y_unit_v + + pos_i = np.array(pos_x) + np.array(pos_y) + pos_i = np.append(pos_i, 0.) + + C_pos_lst.append(pos_i) + # atom_cent = (origin[0] + x_ind * graph_bond_d + # - graph_bond_d * y_ind * y_unit_v[0], origin[1] + y_ind + # * graph_bond_d) + + add_adsorbate( + slab, + "C", + graph_surf_d, + position=(pos_i[0], pos_i[1]), + ) + + patt_cnt_x += 1 + + elif patt_cnt_x == 2: + patt_cnt_x = 0 + + if patt_cnt_y == 0: + patt_cnt_y = 2 + continue + + if patt_cnt_y == 2: + patt_cnt_y = 1 + continue + + elif patt_cnt_y == 1: + patt_cnt_y = 0 + continue + + C_pos_lst = np.array(C_pos_lst) + + return(slab) + #__| diff --git a/ase_modules/adsorbates.py b/ase_modules/adsorbates.py index 023ade9..29c3c6e 100644 --- a/ase_modules/adsorbates.py +++ b/ase_modules/adsorbates.py @@ -1,132 +1,132 @@ -#!/usr/bin/env python - -"""Adsorbate related methods.""" - -#| - IMPORT MODULES -from ase import Atoms -from ase.build import molecule - -import numpy as np -#__| - -class Adsorbate: - """Adsorbate atoms object class.""" - - #| - Adsorbate ************************************************************ - - def __init__(self): - """Initialize Adsorbate class instance.""" - #| - __init__ - self.tmp = 42 - #__| - - def ooh(self, - OO_bl=1.359, - OH_bl=0.993, - OO_angle=30.0, - H_up_down="down", - ): - """*OOH adsorbate. - - Angles are wrt the z-axis, so 0 is along the z-axis. - - Args: - OO_bl: - OO_bl: - OO_angle: - H_up_down: - """ - #| - ooh - O_1_x = OO_bl * np.sin(np.radians(OO_angle)) - O_1_y = OO_bl * np.cos(np.radians(OO_angle)) - - if H_up_down == "up": - H_angle = 0.0 - H_x = O_1_x + OH_bl * np.sin(np.radians(H_angle)) - H_y = O_1_y + OH_bl * np.cos(np.radians(H_angle)) - - elif H_up_down == "down": - H_angle = 115.0 - - H_x = O_1_x + OH_bl * np.sin(np.radians(H_angle)) - H_y = O_1_y + OH_bl * np.cos(np.radians(H_angle)) - - ooh_mol = Atoms(["O", "O", "H"], - positions=[ - (0.0, 0.0, 0.0), - # (0, 0, 1.359), - (O_1_x, 0.0, O_1_y), - # (0.7, 0.0, 2.5), - (H_x, 0.0, H_y), - ] - ) - - return(ooh_mol) - #__| - - def o(self): - """*O adsorbate.""" - #| - o - o_mol = Atoms(['O'], - positions=[ - (0, 0, 0), - ] - ) - - return(o_mol) - #__| - - def oh(self, - OH_bl=0.978, - ): - """*OH adsorbate. - - Args: - OH_bl: - O-H bond length - """ - #| - oh - oh_mol = Atoms(["O", "H"], - positions=[ - (0, 0, 0), - (0, 0, OH_bl), - ] - ) - return(oh_mol) - #__| - - def h2o(self, - H_up_down="up", - ): - """H2O adsorbate. - - Args: - H_up_down: - Hydrogen atom pointing up or down - """ - #| - h2o - h2o_mol = molecule("H2O") - - if H_up_down == "up": - h2o_mol.rotate(180, "x") - else: - pass - - return(h2o_mol) - #__| - - def get_adsorbate(self, adsorbate, **kwargs): - """ - Get adsorbate by name. - - Args: - adsorbate: - kwargs: - """ - #| - get_adsorbate - ads = getattr(self, adsorbate)(**kwargs) - - return(ads) - #__| - - #__| ********************************************************************** +#!/usr/bin/env python + +"""Adsorbate related methods.""" + +#| - IMPORT MODULES +from ase import Atoms +from ase.build import molecule + +import numpy as np +#__| + +class Adsorbate: + """Adsorbate atoms object class.""" + + #| - Adsorbate ************************************************************ + + def __init__(self): + """Initialize Adsorbate class instance.""" + #| - __init__ + self.tmp = 42 + #__| + + def ooh(self, + OO_bl=1.359, + OH_bl=0.993, + OO_angle=30.0, + H_up_down="down", + ): + """*OOH adsorbate. + + Angles are wrt the z-axis, so 0 is along the z-axis. + + Args: + OO_bl: + OO_bl: + OO_angle: + H_up_down: + """ + #| - ooh + O_1_x = OO_bl * np.sin(np.radians(OO_angle)) + O_1_y = OO_bl * np.cos(np.radians(OO_angle)) + + if H_up_down == "up": + H_angle = 0.0 + H_x = O_1_x + OH_bl * np.sin(np.radians(H_angle)) + H_y = O_1_y + OH_bl * np.cos(np.radians(H_angle)) + + elif H_up_down == "down": + H_angle = 115.0 + + H_x = O_1_x + OH_bl * np.sin(np.radians(H_angle)) + H_y = O_1_y + OH_bl * np.cos(np.radians(H_angle)) + + ooh_mol = Atoms(["O", "O", "H"], + positions=[ + (0.0, 0.0, 0.0), + # (0, 0, 1.359), + (O_1_x, 0.0, O_1_y), + # (0.7, 0.0, 2.5), + (H_x, 0.0, H_y), + ] + ) + + return(ooh_mol) + #__| + + def o(self): + """*O adsorbate.""" + #| - o + o_mol = Atoms(['O'], + positions=[ + (0, 0, 0), + ] + ) + + return(o_mol) + #__| + + def oh(self, + OH_bl=0.978, + ): + """*OH adsorbate. + + Args: + OH_bl: + O-H bond length + """ + #| - oh + oh_mol = Atoms(["O", "H"], + positions=[ + (0, 0, 0), + (0, 0, OH_bl), + ] + ) + return(oh_mol) + #__| + + def h2o(self, + H_up_down="up", + ): + """H2O adsorbate. + + Args: + H_up_down: + Hydrogen atom pointing up or down + """ + #| - h2o + h2o_mol = molecule("H2O") + + if H_up_down == "up": + h2o_mol.rotate(180, "x") + else: + pass + + return(h2o_mol) + #__| + + def get_adsorbate(self, adsorbate, **kwargs): + """ + Get adsorbate by name. + + Args: + adsorbate: + kwargs: + """ + #| - get_adsorbate + ads = getattr(self, adsorbate)(**kwargs) + + return(ads) + #__| + + #__| ********************************************************************** diff --git a/ase_modules/ase_methods.py b/ase_modules/ase_methods.py index c3c7029..7a9eb6c 100644 --- a/ase_modules/ase_methods.py +++ b/ase_modules/ase_methods.py @@ -1,2442 +1,2442 @@ - -#!/usr/bin/env python - -"""Methods for ASE scripts, mostly DFT scripts. - -Author: Raul A. Flores - -Development Notes: - TODO Master print statements should have "****..." to be easily readable - TODO Delete all set_mag_mom_to_0 references (Already commented them out) - TODO Add work function analysis (Ask Colin about Karen's method) -""" - -#| - IMPORT MODULES -import sys -import os -import glob -import copy -import json -import math -import pickle as pickle -import numpy as np -import shutil - -from scipy.stats import norm - -# NOTE Changed for python3.6 -# import matplotlib.pyplot as plt -import matplotlib as plt - -from ase.io import read, write, Trajectory -from ase import io -from ase.dft.kpoints import ibz_points, get_bandpath -from ase.vibrations import Vibrations -from ase.thermochemistry import HarmonicThermo - -# pymatgen -from pymatgen.core.periodic_table import _pt_data as periodic_table_dict - -# My Modules -from misc_modules.numpy_methods import angle_between -from ase_modules.dft_params import Espresso_Params - -from quantum_espresso.qe_methods import estimate_magmom - -from bader_charge.bader import bader -#__| - -#| - METHODS - -def update_FINISHED(text, filename=".FINISHED.new"): - """Update finished job/processes log file with message. - - TODO Change filename --> .FINISHED when the migration to new system is - complete - - Args: - text: - filename: - """ - #| - update_FINISHED - if os.path.exists("./" + filename): - append_write = "a" # append if already exists - else: - append_write = "w" # make a new file if not - - with open(filename, append_write) as fle: - fle.write(text) - fle.write("\n") - #__| - -#__| - -#| - Parse DFT Job Parameters ************************************************* - -def set_QE_calc_params( - atoms=None, - params={}, - load_defaults=True, - init_inst=True, - ): - """Set Quantum Espresso calculation parameters to atoms object. - - Handles reading, and setting of dft calculator parameters to atoms object. - - Args: - atoms: - params: - load_defaults: - init_inst: - Whether or not to institiate an espresso instance - """ - #| - set_QE_calc_params - from espresso import espresso - - mess = "Loading QE Parameters From File " - mess += "**********************************************" - print(mess); sys.stdout.flush() - - espresso_params_inst = Espresso_Params(load_defaults=load_defaults) - - if os.path.isfile("dft-params.json"): - params_file = json.load(open("dft-params.json")) - espresso_params_inst.update_params(params_file) - - elif os.path.isfile("dir_dft_params/dft-params.json"): - params_file = json.load(open("dir_dft_params/dft-params.json")) - espresso_params_inst.update_params(params_file) - - espresso_params_inst.update_params(params) # Create params dict if wanted - - espresso_params_inst.test_check() - espresso_params_inst.write_params() - espresso_params = espresso_params_inst.params - - calc = None - if init_inst: - calc = espresso(**espresso_params) - - # NOTE Calculator set for the 1st time here - # atoms.set_calculator(calc=calc) - - return(calc, espresso_params) - #__| - -#__| ************************************************************************** - -#| - Ionic Optimization ******************************************************* - -def ionic_opt( - atoms, - calc=None, - traj=None, - espresso_params=None, - mode="opt", - fmax=0.05, - maxsteps=100000000, - run_beef_an=True, - run_bader_an=True, - save_wf=True, - ): - """Run ionic dft relaxation on atoms object. - - Development Notes: - * What to do when the job has already been previously completed? - Should I run a single point calculation just to make sure the - calculator is fully operational/loaded? - - TODO .FINSISHED file should include information about what kind of - optimization was performed - - TODO Implemetn qn.replay_trajectory('qn.traj') functionality - - Args: - atoms: ASE atoms object - calc: Calculator object - espresso_params: Quantum Espresso job parameters dictionary - mode: - fmax: Force convergence criteria - maxsteps: Maximum number of ionic steps - run_beef_an: - Attempts to run Beef-vdW ensemble of energies - Must have ran calculation with appropriate paramters to begin with - """ - #| - ionic_opt - from espresso import espresso - from ase.optimize import QuasiNewton - - mess = "Running DFT Calculation " - mess += "******************************************************" - print(mess) - sys.stdout.flush() - - # TODO Skip calculation if previously converged - # COMBAK Uncomment this section - #| - Checking if Previous Calculation Has Been Completed - # filename = ".FINISHED.new" - # if os.path.exists("./" + filename): - # with open(filename, "r") as fle: - # lines = [line.strip() for line in fle.readlines()] - # if "ionic_opt" in lines: - # print("ionic_opt | Optimization previusly completed " - # "(Running a single-point calculation)" - # ) - # mode = "sp" - #__| - - #| - Setting Optimization Specific Espresso Parameters - # espresso_params_copy = copy.deepcopy(espresso_params) - - params_opt = { - # "output": { - # "avoidio": True, - # "removesave": True, - # "removewf": True, - # "wf_collect": False, - # }, - - "outdir": "calcdir_opt", - } - - # espresso_params_copy.update(params_opt) - # calc_opt = espresso(**espresso_params_copy) - # atoms.set_calculator(calc_opt) - - calc_opt, espresso_params_opt = set_QE_calc_params( - params=params_opt, - ) - - calc_opt = espresso(**espresso_params_opt) - atoms.set_calculator(calc_opt) - #__| - - reduce_magmoms(atoms) - - if mode == "opt": - #| - Regular Optimization - mess = "Running regular optimization " - print(mess); sys.stdout.flush() - - # TEMP - do_strain_filter = False - if do_strain_filter: - print("Performing opt with StrainFilter class") - from ase.constraints import StrainFilter - SF = StrainFilter(atoms) - # atoms.set_constraint(SF) - - qn = QuasiNewton( - SF, - # trajectory="out_opt.traj", - logfile="qn.log", - ) - - else: - qn = QuasiNewton( - atoms, - # trajectory="out_opt.traj", - logfile="qn.log", - ) - - if traj is not None: - qn.attach(traj) # COMBAK Test feature (restarting traj files) - - if os.path.exists("prev.traj"): - qn.replay_trajectory("prev.traj") - - qn.run( - fmax=fmax, - steps=maxsteps, - ) - #__| - - elif mode == "easy_opt": - #| - Easy Optimization -> Full Optimization - mess = "Running easy optimization scheme" - print(mess); sys.stdout.flush() - - #| - Easy Optimization Settings - espresso_params_copy = copy.deepcopy(espresso_params) - - easy_params = { - "pw": 400, - "dw": 4000, - "spinpol": False, - "kpts": (3, 3, 1), - - "convergence": { - "energy": 5e-5, # convergence parameters - "mixing": 0.05, - "nmix": 20, - "mix": 4, - "maxsteps": 400, - "diag": "david", - }, - "outdir": "calcdir_easy", - } - - espresso_params_copy.update(easy_params) - easy_calc = espresso(**espresso_params_copy) - #__| - - #TODO: Find a way to freeze all atoms but adsorbates - # SIMPLE RELAXATION ################# - print("ionic_opt | Running Easy Relaxation"); sys.stdout.flush() - - magmoms = atoms.get_initial_magnetic_moments() - - # set_mag_mom_to_0(atoms) - - # FIXME I should be able to just use the "set_initial_magnetic_moments" - # method here. That should automatically set to magmoms to 0 from the - # QE parameters dict - atoms.set_initial_magnetic_moments(np.zeros(len(atoms))) - - atoms.set_calculator(easy_calc) - - qn = QuasiNewton( - atoms, - trajectory="out_opt_easy.traj", - logfile="qn.log", - ) - - if os.path.exists("prev.traj"): - qn.replay_trajectory("prev.traj") - - qn.run(fmax=fmax) - - # FULL RELAXATION ################# - print("ionic_opt | Running Full Relaxation"); sys.stdout.flush() - # atoms.set_calculator(calc) - atoms.set_calculator(calc_opt) - - print(magmoms) - atoms.set_initial_magnetic_moments(magmoms) - - qn = QuasiNewton( - atoms, - trajectory="out_opt.traj", - logfile="qn.log", - ) - - if os.path.exists("prev.traj"): - qn.replay_trajectory("prev.traj") - - qn.run(fmax=fmax) - #__| - - elif mode == "sp": - #| - Single Point Calculation - mess = "Running Single-Point Calculation" - print(mess); sys.stdout.flush() - - atoms.get_potential_energy() - write("out_opt.traj", atoms) - #__| - - - #TEMP - if save_wf: - atoms.calc.save_wf() - - estimate_magmom( - path_i=".", - atoms=atoms, - log="calcdir_opt/log", - ) - - elec_e = atoms.get_potential_energy() - - outdir = "dir_opt" - if not os.path.exists(outdir): - os.makedirs(outdir) - - e_out = outdir + "/elec_e.out" - with open(e_out, "w") as fle: - fle.write(str(elec_e) + "\n") - - # if mode != "sp": - # #| - Always Run Single-Point Calculation with Full IO - # mess = "Running Post-run Single-Point Calculation" - # print(mess); sys.stdout.flush() - # atoms.get_potential_energy() - # #__| - - update_FINISHED("ionic_opt") - - if run_beef_an: - an_beef_ensemble(atoms) - - if run_bader_an: - - #| - Running initial single-point calculation - params_bader = { - "output": { - "avoidio": False, - "removesave": True, - "removewf": True, - "wf_collect": False, - }, - - "outdir": "calcdir_bader", - } - - calc_bader, espresso_params_bader = set_QE_calc_params( - params=params_bader, - ) - - calc_bader = espresso(**espresso_params_bader) - atoms.set_calculator(calc_bader) - - mess = "Running single-point calc with high io " - print(mess); sys.stdout.flush() - atoms.get_potential_energy() - print("finished single-point"); sys.stdout.flush() - #__| - - bader(atoms, spinpol=espresso_params_opt["spinpol"], run_exec=True) - #__| - -#__| ************************************************************************** - -#| - Magnetic Moments ********************************************************* - -def set_init_mag_moms( - atoms, - preference="bader", - espresso_params=None, - magmoms=None, - read_from_file=False, - inc_val_magmoms=True, - ): - """Set initial magnetic moments to atoms object using several methods. - - Set inital magnetic moments to atoms object. If the atoms object has - previously had a bader or pdos analysis performed those magnetic moments - will be available under the atoms.info dict ("pdos_magmoms" and - "bader_magmoms" dict keys). - - # TODO Implement the "average" setting for the preference variable - - Args: - atoms: - Atoms object to be used - preference: - "bader" - "pdos" - "average" - magmoms: - If specified as a list, set the atom's initial magnetic - moments to list. If a element: magmom_i dict is given the magmoms - will be initilized from this dict. - inc_val_magmoms: - Will marginally increase the magnetic moments to hopefully aid - convergence. This is best used when starting from previously - converged magmoms. - """ - #| - set_init_mag_moms - mess = "Setting Inital Magnetic Moments " - mess += "**********************************************" - print(mess); sys.stdout.flush() - - preference_map_dict = { - "bader": "bader_magmoms", - "pdos": "pdos_magmoms" - } - - magmom_keys = ["pdos_magmoms", "bader_magmoms"] - magmoms_master_dict = {} - for magmom_key in magmom_keys: - if magmom_key in atoms.info.keys(): - magmoms_master_dict[magmom_key] = atoms.info[magmom_key] - - magmom_keys = magmoms_master_dict.keys() - - preferred_an = preference_map_dict[preference] - - if magmoms is not None: - - if type(magmoms) == list: - print("set_init_mag_moms | Using given magmoms") - sys.stdout.flush() - magmoms_i = magmoms - - # TODO Implement this featrure in simple_mag_moms, providing dict will - # update the init magmom dict - elif type(magmoms) == dict: - text = ("set_init_mag_moms | " - "Using simple method for initial magnetic moments " - "with updated values for dict - NOT IMPLEMENTED - 180425" - ) - print(text); sys.stdout.flush() - magmoms_i = simple_mag_moms(atoms) - - else: - spinpol_calc = calc_spinpol(atoms) - - if espresso_params is not None: - if "spinpol" in list(espresso_params): - spinpol_calc = espresso_params["spinpol"] - - #| - Spin-polarization turned off, set magmoms to 0 - if not spinpol_calc: - print("set_init_mag_moms | Spin-polarization turned off") - sys.stdout.flush() - mag_mom_list = atoms.get_initial_magnetic_moments() - magmoms_i = np.zeros(len(mag_mom_list)) - #__| - - # COMBAK This is a poor way of enforcing the analysis method preference - # Assumes that there are only 2 analysis methods - elif preferred_an in magmoms_master_dict.keys(): - text = ("set_init_mag_moms | " - "Using preferred method for initial magnetic moments " - "(" + preferred_an + ")" - ) - print(text); sys.stdout.flush() - magmoms_i = magmoms_master_dict[preferred_an] - - elif len(magmoms_master_dict.keys()) == 1: - an_method = magmoms_master_dict.keys()[0] - text = ("set_init_mag_moms | " - "Using " + an_method + " for initial magnetic moments") - print(text); sys.stdout.flush() - - magmoms_i = magmoms_master_dict[an_method] - - #| - Use simple method - else: - text = ("set_init_mag_moms | " - "Using simple method for initial magnetic moments") - print(text); sys.stdout.flush() - magmoms_i = simple_mag_moms(atoms) - #__| - - if read_from_file: - text = ("set_init_mag_moms | " - "Using magmom_init.in file for initial magnetic moments") - print(text); sys.stdout.flush() - - magmoms_tmp = read_magmoms_from_file() - if magmoms_tmp is not None: - magmoms_i = magmoms_tmp - - - #| - Check That Length of Magmoms_list == len(atoms) - if not len(magmoms_i) == len(atoms): - text = ("Length of magmoms doesn't match the number of atoms!!!!!!!!!!!" - "\n Will use simple method to assign initial magmoms") - - print(text); sys.stdout.flush() - magmoms_i = simple_mag_moms(atoms) - #__| - - if inc_val_magmoms: - magmoms_i = increase_abs_val_magmoms(atoms, magmoms_i) - - atoms.set_initial_magnetic_moments(magmoms_i) - - #| - Printing Magnetic Moments - print("set_init_mag_moms | Initial Magnetic Moments:") - for atom in atoms: - elem = atom.symbol - magmom = atom.magmom - print(elem + ": " + str(magmom)) - - #__| - - reduce_magmoms(atoms) - #__| - -def increase_abs_val_magmoms(atoms, magmoms_list, increase_amount=0.8): - """Increase absolute value of magmoms for atoms object. - - # COMBAK Shouldn't raise initial guess for light atoms (Or don't raise as - much) - - Will not modify magmoms == 0. - - Select light atoms will have their |magmom| raised by a set small amount to - not oversaturate the atomic maignetic moment (init_magmom > # valence e) - - Args: - magmoms_list: - increase_amount: - """ - #| - increase_abs_val_magmoms - inc = increase_amount - - light_atoms_list = { - "H": 0.1, - "He": 0.3, - "Li": 0.4, - "Be": 0.5, - "B": 0.6, - "C": 0.7, - "N": 0.8, - "O": 0.9, - "F": 1.0, - } - - new_magmom_list = [] - # for magmom in magmoms_list: - for atom, magmom in zip(atoms, magmoms_list): - - elem_i = atom.symbol - - if elem_i in light_atoms_list.keys(): - inc = light_atoms_list[atom.symbol] - - if magmom < 0.: - new_magmom = abs(magmom) + inc - new_magmom = -new_magmom - - elif magmom > 0.: - new_magmom = abs(magmom) + inc - - else: - new_magmom = 0. - - # Making sure H initial magmom isn't > 1 - if elem_i == "H": - if new_magmom > 0.99: - print("Setting H magmom to 1 - RF - 180423 - TEMP") - new_magmom = 1. - - new_magmom_list.append(new_magmom) - - - return(new_magmom_list) - #__| - -def calc_spinpol(atoms): - """Return whether spin polarization should be turned on or off. - - The atoms object must have the appropriate calculator object attachedd with - the relevent parameters declared - - Args: - atoms: - """ - #| - calc_spinpol - spinpol = True - if hasattr(atoms, "calc"): - if atoms.calc is not None: - spin_key = "spinpol" - params_dict = atoms.calc.__dict__ - if spin_key in params_dict: - spin_pol = params_dict[spin_key] - if spin_pol is False: - spinpol = False - # set_mag_mom_to_0(atoms) - # return(spinpol) - - return(spinpol) - #__| - -def simple_mag_moms(atoms): - """Implement simple procedure to set initial guess for magnetic moments. - - Args: - atoms - """ - #| - simple_mag_moms - - #| - High Spin Dictionary - master_dict_high_spin = { - - "Cr": 5, "Mn": 5, - "Cu": 1, "Ag": 0, "Au": 0, # 3d10 - "Ni": 3, "Pd": 3, "Pt": 3, # 3d8, 4s1 - "Co": 4, "Rh": 4, "Ir": 4, # 3d7, 4s1 - "Fe": 5, "Ru": 5, "Os": 5, # 3d6, 4s1 - "Mo": 5, "Tc": 5, "Hf": 2, - "Ta": 3, "W": 4, "Re": 5, "Ti": 2, - } - - spin_dict = { - "O": 2.5, - "H": 0.2, - "C": 0.2, - "N": 0.2, - } - #__| - - #| - Find cations - cations = [] - for atom in atoms: - if atom.symbol in master_dict_high_spin.keys(): - # if master_dict_high_spin.has_key(atom.symbol): - cations.append(atom.symbol) - #__| - - #| - Cation Magnetic Moments Dictionary - cation_magmom_dict = {} - for cation in cations: - cation_magmom_dict[cation] = master_dict_high_spin[cation] * 1.1 + 0.3 - #__| - - #| - Setting Magnetic Moments of Atoms - magmoms = atoms.get_initial_magnetic_moments() - - for atom in atoms: - if atom.symbol in cations: - magmoms[atom.index] = cation_magmom_dict[atom.symbol] - continue - - for elem_i in spin_dict.keys(): - if atom.symbol == elem_i: - magmoms[atom.index] = spin_dict[elem_i] - break - - else: - magmoms[atom.index] = 0.0 - magmoms = np.array(magmoms) - - return(magmoms) - #__| - - #__| - -def reduce_magmoms(atoms, ntypx=10): - """Reduce number of unique magnetic moments of atoms object. - - Reduce the number of unique magnetic moments by combining those that are - most similar among atoms with the same atomic symbol. This is necessary for - atoms objects with more than 10 types of magmom/symbol pairs because QE - only accepts a maximum of 10 types of atoms. - """ - #| - reduce_magmoms - syms = set(atoms.get_chemical_symbols()) - - master_dict = {} - for sym in syms: - master_dict[sym] = {} - - for atom in atoms: - if atom.magmom in master_dict[atom.symbol]: - master_dict[atom.symbol][atom.magmom].append(atom.index) - else: - master_dict[atom.symbol][atom.magmom] = [atom.index] - - ntyp = 0 - for sym in syms: - ntyp += len(master_dict[sym].keys()) - - while ntyp > ntypx: - magmom_pairs = {} - for sym in syms: - magmoms = master_dict[sym].keys() - if not len(magmoms) > 1: continue - min_delta = 1e6 - min_pair = () - for i, magmom1 in enumerate(magmoms): - for j, magmom2 in enumerate(magmoms): - if not i < j: continue - delta = np.abs(magmom1 - magmom2) - if delta < min_delta: - min_delta = delta - min_pair = (magmom1, magmom2) - - assert min_delta != 1e6 - assert min_pair != () - magmom_pairs[sym] = min_pair - - min_delta = 1e6 - min_sym = "" - for sym in magmom_pairs: - delta = np.abs(magmom_pairs[sym][0] - magmom_pairs[sym][1]) - if delta < min_delta: - min_delta = delta - min_sym = sym - - assert min_delta != 1e6 - assert min_sym != "" - if min_delta > 0.5: - warn = "WARNING, reducing pair of magmoms whose difference is " - print(warn + "%.2f" % min_delta) - - if np.abs(magmom_pairs[min_sym][0]) > np.abs(magmom_pairs[min_sym][1]): - master_dict[min_sym][magmom_pairs[min_sym][0]].extend( - master_dict[min_sym][magmom_pairs[min_sym][1]]) - del master_dict[min_sym][magmom_pairs[min_sym][1]] - else: - master_dict[min_sym][magmom_pairs[min_sym][1]].extend( - master_dict[min_sym][magmom_pairs[min_sym][0]]) - del master_dict[min_sym][magmom_pairs[min_sym][0]] - - ntyp = 0 - for sym in syms: - ntyp += len(master_dict[sym].keys()) - - #reassign magmoms - for sym in syms: - for magmom in master_dict[sym]: - for index in master_dict[sym][magmom]: - atoms[index].magmom = magmom - #__| - - -def read_magmoms_from_file(file_name="magmom_init.in"): - """Read inital magmoms from a file. - - Args: - file_name: - """ - #| - read_magmoms_from_file - print(os.path.isfile(file_name)) - magmoms = None - if os.path.isfile(file_name): - # try: - with open(file_name, "r") as fle: - # magmoms = [float(i.strip()) for i in fle.readlines()] - - magmom_list = [] - for i_tmp in fle.readlines(): - if not i_tmp == "\n": - magmom_list.append(float(i_tmp.strip())) - magmoms = magmom_list - - if magmoms is not None: - print(magmoms) - print( - "magmoms succesfully read from file!", - " | ", - "ase_methods.read_magmoms_from_file" - ) - - # except: - # print("Couldn't read init magmom file") - - - # print("__SD-sfd-") - # print(magmoms) - # # print(len(magmoms)) - # print("__SD-sfd-") - - return(magmoms) - #__| - - -#| - __old__ -# def compare_magmoms(self): -# def compare_magmoms(): -# """Compare spin states of two atoms objects. -# -# (I think I got this from Colin on 180413) -# -# Part of bigger script -# /home/colinfd/usr/bin/get_G.py -# -# TODO Port this code to my workflow -# -# Author: Colin Dickens -# """ -# #| - compare_magmoms -# def nearest_atom(atoms, position): -# """Returns atom nearest to position.""" -# #| - nearest_atom -# position = np.array(position) -# dist_list = [] -# for atom in atoms: -# dist = np.linalg.norm(position - atom.position) -# dist_list.append(dist) -# -# return atoms[np.argmin(dist_list)] -# #__| -# -# if len(self.ads_atoms) >= len(self.slab_atoms): -# ads = self.ads_atoms -# slab = self.slab_atoms -# indexed_by = self.slab -# not_indexed_by = self.ads -# else: -# slab = self.ads_atoms -# ads = self.slab_atoms -# indexed_by = self.ads -# not_indexed_by = self.slab -# -# delta_magmoms = [] -# ads_indices_used = [] -# for atom in slab: -# ads_atom = nearest_atom(ads, atom.position) -# if not self.quiet: -# if ads_atom.symbol != atom.symbol: -# print("WARNING! MAGMOM COMPARISON FAILURE") -# ads_indices_used.append(ads_atom.index) -# delta_magmoms.append(atom.magmom - ads_atom.magmom) -# -# ads_indices_not_used = [] -# for i in range(len(ads)): -# if i not in ads_indices_used: -# ads_indices_not_used.append(i) -# -# self.delta_magmoms = zip(range(len(slab)), delta_magmoms) -# self.delta_magmoms.sort(key=lambda x: abs(x[1]), reverse=True) -# -# common = "" -# uncommon = "" -# for i in range(8): -# atom = slab[self.delta_magmoms[i][0]] -# common += "%s%d: %.2f\t" % (atom.symbol, -# atom.index, -# self.delta_magmoms[i][1], -# ) -# -# for i in ads_indices_not_used: -# uncommon += "%s%d: %.2f\t"%(ads[i].symbol,ads[i].index,ads[i].magmom) -# -# if self.quiet: -# return -# print("~" * 6 + "MAGNETIC MOMENT COMPARISON" + "~" * 6) -# print("Largest magmom discrepancies (indexed by %s)" % indexed_by) -# print(common) -# print("Magnetic moments only present in %s" % not_indexed_by) -# print(uncommon + "\n") -# #__| -#__| - - -#__| ************************************************************************** - -#| - Density of States ******************************************************** -def an_pdos( - atoms, - # calc, - dos_kpts, - espresso_params, - ): - """Perform projected density of states (PDOS) analysis. - - # TODO Clean up, makes too much data - - Args: - atoms: - dos_kpts: - espresso_params: - """ - #| - an_pdos - from espresso import espresso - - mess = "Running PDOS Analysis " - mess += "********************************************************" - print(mess); sys.stdout.flush() - - outdir = "dir_pdos" - - params_dos = { - "output": { - "avoidio": False, - "removesave": True, - "removewf": True, # Changed this 181102 - "wf_collect": True, - }, - - "outdir": "calcdir_dos", - } - - calc_opt, espresso_params_dos = set_QE_calc_params( - params=params_dos, - ) - - calc_dos = espresso(**espresso_params_dos) - atoms.set_calculator(calc_dos) - - reduce_magmoms(atoms) - - mess = "Running single-point calc with high io " - print(mess); sys.stdout.flush() - atoms.get_potential_energy() - print("finished single-point"); sys.stdout.flush() - - cwd = os.getcwd() - dos = atoms.calc.calc_pdos( - nscf=True, - kpts=dos_kpts, - Emin=-20.0, - Emax=20.0, - ngauss=0, - sigma=0.2, - DeltaE=0.01, - tetrahedra=False, - slab=True, - ) - os.chdir(cwd) - - if not os.path.exists(outdir): - os.makedirs(outdir) - - pdos_out = outdir + "/dos.pickle" - with open(pdos_out, "w") as fle: - pickle.dump(dos, fle) - - # Set Magnetic Moments To Atoms Object From PDOS Intergration - spin_pdos( - atoms, - pdos_pkl=pdos_out, - outdir=outdir, - spinpol=espresso_params["spinpol"], - ) - - atoms.write(outdir + "/out_pdos.traj") - update_FINISHED("an_pdos") - #__| - -def spin_pdos( - atoms, - pdos_pkl=None, - valence_dict=None, - nscf=False, - kpts=None, - outdir=None, - save_pkl=False, - spinpol=False, - write_charges=True, - **kwargs - ): - """Calculate spin moments on each atom from PDOS analysis. - - Calculate more accurate charges/magnetic moments from pdos and assign to - atom.charge/atom.magmom. If pdos_pkl not defined, it will be calculated - (atoms object must have a real calculator attached). If pdos_pkl is - defined, will attempt to load from pickle file, but valence_dict must be - specified! Specify calculation directory as outdir for easy cleanup. - - Args: - atoms: - pdos_pkl: - valence_dict: - nscf: - kpts: - outdir: - save_pkl: - spinpol: - write_charges: - kwargs: - """ - #| - spin_pdos - valence_dict = { - "Cu": 11, "C": 4, "O": 6, "H": 1, "Li": 1, - "Rh": 17, "Co": 9, "Pd": 10, "Pt": 10, - "Ni": 1, "Fe": 16, "N": 5, "Ru": 16, - } - - #| - Reading PDOS File, Otherwise Creates It - # FIXME I don't like that it can create PDOS file, this is handled by my - # an_pdos method. - - if pdos_pkl: - print("spin_pdos | pdos_pkl is not None") # TEMP For testing purposes - assert valence_dict is not None, "MUST SPECIFY valence_dict" - single_point_calc = True - pdos = pickle.load(open(pdos_pkl)) - nvalence_dict = valence_dict - - else: - print("spin_pdos | pdos_pkl is None") # TEMP For testing purposes - single_point_calc = False - # dict with (chemical symbol) : (num valence) - nvalence_dict = atoms.calc.get_nvalence()[1] - # double k-points for higher quality pdos --> O(single point calc) - if nscf: - print("spin_pdos | TEMP1") - pdos = atoms.calc.calc_pdos(nscf=True, kpts=kpts, **kwargs) - else: # no single point calc, should take 1 or 2 minutes - print("spin_pdos | TEMP2") - pdos = atoms.calc.calc_pdos(**kwargs) - #__| - - #| - Finding Index of Fermi Level - for i_ind, e_i in enumerate(pdos[0]): - if e_i > 0: - fi = i_ind # index of fermi level - break - #__| - - #| - Analysing PDOS For Magnetic Moments and Charge of All Atoms - if spinpol: - #| - Spin Polarlized Calculation - magmom_list = [] - charge_list = [] - for i, atom in enumerate(atoms): - - #| - Integrating Up and Down Spin PDOS - spin_up = 0; spin_down = 0 - for sym in pdos[2][i]: - spin_up += np.trapz(pdos[2][i][sym][0][:fi], x=pdos[0][:fi]) - spin_down += np.trapz(pdos[2][i][sym][1][:fi], x=pdos[0][:fi]) - - #__| - - #| - Update Atoms Magmom and Charge Properties - ##Update magmom - if np.abs(spin_up - spin_down) > 1e-4: - magmom_i = spin_up - spin_down - else: - magmom_i = 0. - - magmom_list.append(magmom_i) - atom.magmom = magmom_i - - ##Update charge - if atom.symbol not in nvalence_dict.keys(): - print("Atom ", str(atom.symbol), " not is the nvalance dict") - - - - # charge_i = nvalence_dict[atom.symbol] - (spin_up + spin_down) - charge_i = nvalence_dict.get(atom.symbol, 0.) - (spin_up + spin_down) - if write_charges: - # atom.charge = nvalence_dict[atom.symbol]-(spin_up+spin_down) - atom.charge = charge_i - - charge_list.append(charge_i) - #__| - - print("PDOS MAGMOMS: " + str(atoms.get_initial_magnetic_moments())) - reduce_magmoms(atoms) - - atoms.info.update({"magmom_set": True}) - atoms.info.update({"pdos_magmoms": magmom_list}) - atoms.info.update({"pdos_charges": charge_list}) - - pickle.dump(magmom_list, open("%s/magmom_list.pickle" % outdir, "w")) - pickle.dump(charge_list, open("%s/charge_list.pickle" % outdir, "w")) - - - #| - Writing atom objects with magmom and charges written to them - # Charges written to init_charges - atoms_cpy1 = copy.deepcopy(atoms) - atoms_cpy1.set_initial_charges(charge_list) - atoms_cpy1.write( - os.path.join( - outdir, - "pdos_charges.traj", - ), - ) - - # Magmoms written to init_charges - atoms_cpy2 = copy.deepcopy(atoms) - atoms_cpy2.set_initial_charges(magmom_list) - atoms_cpy2.write( - os.path.join( - outdir, - "pdos_magmoms.traj", - ), - ) - #__| - - #__| - - else: - #| - Non-Spin Polarized Calculation - charge_list = [] - for i, atom in enumerate(atoms): - - #| - Integrating PDOS For Charges - charge = 0 - for sym in pdos[2][i]: - charge += np.trapz(pdos[2][i][sym][0][:fi], x=pdos[0][:fi]) - #__| - - #| - Update Atoms Charges - # Update charge - charge_i = nvalence_dict.get(atom.symbol, 0.) - (charge) - if write_charges: - # atom.charge = nvalence_dict[atom.symbol] - (charge) - atom.charge = charge_i - charge_list.append(charge_i) - #__| - - atoms.info.update({"pdos_charges": charge_list}) - - pickle.dump( - charge_list, - open( - "%s/charge_list.pickle" % outdir, - "w", - ) - ) - - #| - Writing atom objects with magmom and charges written to them - # Charges written to init_charges - atoms_cpy1 = copy.deepcopy(atoms) - atoms_cpy1.set_initial_charges(charge_list) - atoms_cpy1.write( - os.path.join( - outdir, - "pdos_charges.traj", - ), - ) - #__| - - #__| - - print("PDOS CHARGES: " + str(atoms.get_initial_charges())) - #__| - - #| - Writing Output To File - if outdir and not single_point_calc: - #Save only the Lowdin charges in the pdos log file - light_lines = [] - - f = open("%s/pdos.log" % outdir) - lines = f.readlines() - f.close() - - skip = False - for line in lines: - try: - if line.split()[0] == "k": - skip = True - elif line.split()[0] == "Lowdin": - skip = False - except: continue - - if not skip: - light_lines.append(line) - - f = open("%s/pdos_Lowdin.log" % outdir, "w") - f.writelines(light_lines) - f.close() - os.system("rm %s/pdos.log" % outdir) - - if save_pkl: - pickle.dump(pdos, open("pdos.pkl", "w")) - #__| - - #__| - -#__| ************************************************************************** - -#| - Band Structure *********************************************************** - -def an_bands(atoms, bands_kpts, espresso_params): - """Perform band analysis on atoms object. - - Development Notes: - * TODO Creates too much data, clean up - * TODO Check if bands have been calculated earlier - - Args: - atoms: - bands_kpts: - espresso_params: - """ - #| - an_bands - from espresso import espresso - - mess = "Executing Band Structure Analysis " - mess += "********************************************" - print(mess); sys.stdout.flush() - - # FIXME This should be handled by envoking the - # set_initial_magnetic_moments method - spinpol_calc = calc_spinpol(atoms) - if spinpol_calc is False: - print("an_bands | Spin-polarization turned off, setting magmoms to 0") - atoms.set_initial_magnetic_moments(np.zeros(len(atoms))) - # set_mag_mom_to_0(atoms) # COMBAK Remove this if working - - #| - Running initial single-point calculation - params_bands = { - "output": { - "avoidio": False, - "removewf": True, - "removesave": True, # Changed this to true so it wouldn't make big files anymore - "wf_collect": False, - }, - - "kpts": bands_kpts, - # "outdir": "dir_bands" - - "outdir": "calcdir_bands", - } - - # "avoidio": false, - # "removesave": true, - # "removewf": true, - # "wf_collect": false, - - calc_bands, espresso_params_bands = set_QE_calc_params( - params=params_bands, - ) - - calc_bands = espresso(**espresso_params_bands) - atoms.set_calculator(calc_bands) - - mess = "Running single-point calc with high io " - print(mess); sys.stdout.flush() - atoms.get_potential_energy() - print("finished single-point"); sys.stdout.flush() - #__| - - # # calc_spinpol(atoms) # COMBAK I don't think this is doing anything - # espresso_params.update( - # { - # "kpts": bands_kpts, - # "outdir": "dir_bands" - # }, - # ) - # atoms.calc = espresso(**espresso_params) - # mess = "Running single-point calculation" - # print(mess); sys.stdout.flush() - # atoms.get_potential_energy() - - atoms.calc.save_flev_chg("charge_den.tgz") - atoms.calc.load_flev_chg("charge_den.tgz") - - # COMBAK How to handle this more generally? - ip = ibz_points["fcc"] - points = ["Gamma", "X", "W", "K", "L", "Gamma"] - bzpath = [ip[p] for p in points] - kpts, x, X = get_bandpath(bzpath, atoms.cell, npoints=300) - - mess = "Calculating band structure" - print(mess); sys.stdout.flush() - - # Note Need current dir because calc_bandstructure moves to calc_dir - cwd = os.getcwd() - energies = atoms.calc.calc_bandstructure(kpts, atomic_projections=True) - os.chdir(cwd) - - if not os.path.exists("dir_bands"): - os.makedirs("dir_bands") - - with open("dir_bands/band_disp.pickle", "w") as fle: - pickle.dump((points, kpts, x, X, energies), fle) - - # COMBAK This broke when file already existed, tried a fix - 180405 - RF - shutil.move("charge_den.tgz", "dir_bands/charge_den.tgz") - atoms.write("dir_bands/out_bands.traj") - - update_FINISHED("an_bands") - #__| - -#__| ************************************************************************** - -#| - Beef Ensemble of Energies ************************************************ -# def an_beef_ensemble(atoms, xc): # COMBAK -def an_beef_ensemble(atoms): - """Perform BEEF ensemble of enery analysis. - - Atoms must have an initialized calculator object attached. - - FIXME The xc parameter is no longer needed it can be gleamed from the - atoms' calculator object - - Args: - atoms: - xc: - """ - #| - an_beef_ensemble - mess = "Executing BEEF Ensemble Analysis " - mess += "*********************************************" - print(mess); sys.stdout.flush() - - beefensemble_on = atoms.calc.beefensemble - xc = atoms.calc.xc - - if beefensemble_on is False: - print("The ase-espresso calculator has the beefensemble" - " parameter turned off!, analysis will not run!!") - return(None) - - allowed_xc = ["BEEF", "BEEF-vdW"] - # if xc != "BEEF" or xc != "BEEF-vdW": - if xc not in allowed_xc: - print("The exchange-correlation functional has to be either " - "BEEF or BEEF-vdW to do the BEEF ensemble analysis") - return(None) - - # if xc == "BEEF" or xc == "BEEF-vdW": - - # calc = atoms.calc - from ase.dft.bee import BEEFEnsemble - - energy = atoms.get_potential_energy() - # ens = BEEFEnsemble(atoms=atoms, e=energy, xc="beefvdw") - # NOTE The BEEFEnsemble class should parse xc from atoms object - # COMBAK - ens = BEEFEnsemble(atoms=atoms, e=energy) - ens_e = ens.get_ensemble_energies() - - if not os.path.exists("dir_beef_ensemble"): - os.makedirs("dir_beef_ensemble") - - with open("dir_beef_ensemble/ensemble.pickle", "w") as fle: - pickle.dump(ens_e, fle) - - update_FINISHED("an_beef_ensemble") - #__| - -def plot_beef_ensemble( - folder_dir="dir_beef_ensemble", - file_name="ensemble.pickle", - file_out="beef_ens_hist.png", - ): - """Create plot of distribution of energies from BEEF ensemble. - - Args: - folder_dir: - file_name: - file_out: - """ - #| - plot_beef_ensemble - file_loc = folder_dir + "/" + file_name - - data = pickle.load(open(file_loc, "r")) - - mu, std = norm.fit(data) - plt.hist(data, bins=25, normed=False, alpha=0.6, color="g") - - xmin, xmax = plt.xlim() - x = np.linspace(xmin, xmax, 100) - p = norm.pdf(x, mu, std) - plt.plot(x, p, 'k', linewidth=2) - title = "Fit results: mu = %.2f, std = %.2f" % (mu, std) - plt.title(title) - - out_file = folder_dir + "/" + file_out - plt.savefig(out_file) - # plt.show() - #__| - -#__| ************************************************************************** - -#| - Vibrational Analysis ***************************************************** -def an_ads_vib( - atoms, - espresso_params=None, - ads_index_list=None, - # thermochem_corrections=True, - thermochem_corrections="harmonic", # "harmonic" or "IG" - remove_imag_modes=True, - - Temperature=300.0, - Pressure=100000.0, - symmetrynumber=2, - spin=0, - linear=True, - ): - """Adsorbate vibrational analysis. - - Returns the ASE Vibrations instance in case further analysis is needed. - - Args: - atoms: - ads_index_list: - thermochem_corrections: - remove_imag_modes: Removes imaginary modes - """ - #| - an_ads_vib - # from espresso import espresso - from espresso.vibespresso import vibespresso - - mess = "Starting vibrational analysis " - mess += "************************************************" - print(mess); sys.stdout.flush() - - #| - Setting Adsorbate Index List - if ads_index_list is not None: - pass - elif "adsorbates" in atoms.info.keys(): - print("Adsorbate info present! Good good.") - ads_index_list = atoms.info["adsorbates"] - else: - print("an_ads_vib | Adsorbate index info couldn't be parsed from atoms") - print("an_ads_vib | Will vibrate all atoms!!!!!!!! (Probably not good)") - pass - #__| - - #| - Removing Empty Pickle Files - pckl_file_list = glob.glob("dir_vib/*.pckl*") + glob.glob("*.pckl*") - for pckl_file in pckl_file_list: - if os.stat(pckl_file).st_size == 0: - os.remove(pckl_file) - print("an_ads_vib | " + pckl_file + " empty, so removed") - #__| - - #| - Copy vib.pckl files back to root dir (For restarting) - for fle in glob.glob("dir_vib/*.pckl*"): - fle_name = fle.split("/")[-1] - shutil.move(fle, fle_name) - #__| - - #| - Running initial single-point calculation - params_vib = { - "output": { - "avoidio": False, - "removesave": False, - "removewf": False, - "wf_collect": True, - }, - - # "kpts": bands_kpts, - # "outdir": "dir_bands" - - "outdir": "calcdir_vib", - } - - calc_vib, espresso_params_vib = set_QE_calc_params( - params=params_vib, - ) - - calc_vib = vibespresso( - outdirprefix="out_vib", - **espresso_params_vib) - - # atoms.set_calculator(calc) - # calc_vib = espresso(**espresso_params_vib) - - atoms.set_calculator(calc_vib) - - # mess = "Running single-point calc with high io " - # print(mess); sys.stdout.flush() - # atoms.get_potential_energy() - # print("finished single-point"); sys.stdout.flush() - #__| - - set_init_mag_moms( - atoms, - preference="bader", - espresso_params=espresso_params_vib, - ) - - # set_init_mag_moms(atoms) - - vib = Vibrations(atoms, indices=ads_index_list) - vib.run() - - # print("an_ads_vib | Getting vibrational energies") - vib_e_list = vib.get_energies() - - vib.summary(log="vib_summ.out") - - #| - Copy Files to dir_vib Folder - if not os.path.exists("dir_vib"): - os.makedirs("dir_vib") - shutil.move("vib_summ.out", "dir_vib/vib_summ.out") - - dest_dir = "dir_vib" - for fle in glob.glob(r'*.pckl*'): - shutil.move(fle, dest_dir + "/" + fle) - - - for fle in glob.glob(r'*out_vib*'): - shutil.move(fle, dest_dir + "/" + fle) - #__| - - #| - Remove Imaginary Modes - # Removes them, not just making them 0 - if remove_imag_modes: - vib_e_list = vib_e_list.real - vib_e_list = [vib_i for vib_i in vib_e_list if vib_i != 0.] - #__| - - if thermochem_corrections == "harmonic": - thermochem_harm_corr(vib_e_list) - - elif thermochem_corrections == "IG": - thermochem_IG_corr( - vib_e_list, - Temperature=Temperature, - Pressure=Pressure, - potentialenergy=0., - symmetrynumber=symmetrynumber, - spin=spin, - atoms=atoms, - linear=linear, - ) - - # Saving Vibrational Mode List - with open("dir_vib/vib_modes.pickle", "w") as fle: - pickle.dump(vib_e_list, fle) - - #| - Saving Vibrations Class Instance - file_name = "dir_vib/vib_inst.pickle" - if not os.path.exists(file_name): - pass - else: - os.remove(file_name) - - # Pickling error occured when pickling the atoms object - if "atoms" in vars(vib): del vars(vib)["atoms"] - - with open(file_name, "w") as fle: - pickle.dump(vib, fle) - #__| - - update_FINISHED("an_ads_vib") - - # return(vib_e_list) - return(vib) - #__| - -def thermochem_harm_corr( - vib_e_list, - Temperature=300.0, - ): - """Thermochemical free energy corrections from vibrational analysis. - - Args: - vib_e_list: - List of vibrational modes in eV - Temperature: - """ - #| - thermochem_harm_corr - mess = "Starting thermochemical harmonic energy contributions " - mess += "***********************" - print(mess); sys.stdout.flush() - - print("Calculating thermochemical corrections @ " + str(Temperature) + "K") - - vib_e_list = np.array(vib_e_list) - - # Remove imaginary frequencies - vib_e_list = vib_e_list.real - vib_e_list = [vib_i for vib_i in vib_e_list if vib_i != 0.] - - ht = HarmonicThermo(vib_e_list) - F_energy = ht.get_helmholtz_energy(Temperature) - - if not os.path.exists("dir_vib"): - os.makedirs("dir_vib") - - with open("dir_vib/gibbs_corr.out", "w") as fle: - fle.write(str(F_energy)) - fle.write("\n") - #__| - -def thermochem_IG_corr( - vib_energies, - Temperature=300.0, - Pressure=100000.0, - potentialenergy=0., - symmetrynumber=None, - spin=None, - atoms=None, - linear=True, - ): - """Calculate free energy to gas phase molecule from vibrational modes. - - Args: - vib_e_list: - Temperature=300.0: - Pressure=100000.0: - potentialenergy=0.: - symmetrynumber=None: - spin=None: - atoms=None: - """ - #| - thermochem_IG_corr - mess = "Starting thermochemical ideal gas energy contributions " - mess += "***********************" - print(mess); sys.stdout.flush() - - from ase.thermochemistry import IdealGasThermo - - # try: - # with open("dir_vib/vib_inst.pickle", "r") as fle: - # vib = pickle.load(fle) - # except: - # pass - # - # vib_energies = vib.get_energies() - - if atoms is not None: - potentialenergy = atoms.get_potential_energy() - - if linear is True: - lin = "linear" - else: - lin = "nonlinear" - - thermo = IdealGasThermo( - vib_energies, - lin, # linear/nonlinear - potentialenergy=potentialenergy, - atoms=atoms, - - # H2O, H2, O2: 2, - symmetrynumber=symmetrynumber, # symmetry numbers from point group - spin=spin, # 1 for O2, 0 for H2O and H2 - ) - - G = thermo.get_gibbs_energy(temperature=Temperature, pressure=Pressure) - - if not os.path.exists("dir_vib"): - os.makedirs("dir_vib") - - with open("dir_vib/g_energy.out", "w") as fle: - fle.write(str(G)) - #__| - - -#__| ************************************************************************** - -#| - Job Cleanup -def clean_up_dft(): - """Clean up files after DFT job. - - I'm using a lot of try statement because I dont want this to break anywhere - """ - #| - clean_up_dft - with open(".FINISHED", "w") as fle: - fle.write("\n") - - # def update_FINISHED(text, filename=".FINISHED.new"): - - update_FINISHED("job_completed") - - if not os.path.exists("__misc__"): - os.makedirs("__misc__") - - #| - Moving Sherlock Node Files to __misc__ folder - # Sherlock didn't like this: - # Open RTE was unable to open the hostfile: - # /scratch/users/flores12/03_graph_N_Fe/01_opt_struct/N_doped_graph_Fe/1-att/__test__/1-att/_5/uniqnodefile.21286552 - # Check to make sure the path and filename are correct. - - - # try: - # if "COMPENV" in os.environ: - # compenv = os.environ["COMPENV"] - # if compenv == "sherlock": - # os.system("mv *nodefile.* __misc__") - # os.system("mv *uniqnodefile..* __misc__") - # - # except: - # pass - #__| - - #| - Moving DFT Parameter Files to dir_dft_params - try: - if not os.path.exists("dir_dft_params"): - os.makedirs("dir_dft_params") - - # os.system("ls") - # os.system("pwd") - os.system("mv *dft-params* dir_dft_params") - - except: - pass - #__| - - #__| - -#__| - -#| - Atoms File Operations **************************************************** -def read_atoms_from_file(filename=None, try_restart=True): - """Read atoms object from file. - - Checks several file names - - TODO Options and methods to read and check output trajectory files - - Args: - filename: optional atoms file, will attempt to read first. - try_restart: Restart job by reading output atoms/trajectory object - """ - #| - read_atoms_from_file - mess = "Reading Atoms Object From File " - mess += "***********************************************" - print(mess) - - atoms = None - traj = None - - #| - Restart From Output Atoms Object - restart_file_name_list = [ - "out.traj", - "out_opt.traj", - "out_final.traj", - ] - - if try_restart: - for file_name in restart_file_name_list: - if os.path.isfile(file_name): - - try: - atoms = read(file_name) - traj = Trajectory(file_name, "a", atoms) - - mess = "read_atoms_from_file | Restarting from " - mess += file_name - print(mess); sys.stdout.flush() - - break - - except: - pass - #__| - - #| - Starting From Fresh Atoms Object - file_name_list = [ - "init.traj", - "init.POSCAR", - "manual_start.traj", - "POSCAR", - ] - - if atoms is None: - - if filename is not None: - file_name_list.insert(0, filename) - - for file_name in file_name_list: - if os.path.isfile(file_name): - atoms = read(file_name) - # COMBAK Test feature - traj = Trajectory("out_opt.traj", "w", atoms) - - mess = "read_atoms_from_file | Starting from " - mess += file_name - print(mess); sys.stdout.flush() - - break - #__| - - if atoms is None: - raise IOError("No atoms file found") - - return(atoms, traj) - #__| - -def convert_atoms_object(atoms_filename, out_file): - """Convert atoms objects to new file format. - - Args: - atoms_filename: - out_file: - """ - #| - convert_atoms_object - atoms = read(atoms_filename) - - #| - Convert to New Trajectory File Format - if out_file.split(".")[-1] == "traj": - write(out_file, atoms) - - #| - Using Trajectory Class Directly (Not Right?) - # traj = Trajectory(out_file, mode="w", atoms=atoms) - # traj.set_description({"author": "Created by Raul Flores"}) - # traj.write() - #__| - - #__| - - #__| - -#__| ************************************************************************** - -#| - Atoms Geometry Methods *************************************************** -def angle_between_lattice_vectors(atoms, vector_0=0, vector_1=1): - """Calculate angle between cell lattice vectors. - - Calculates the angle between the first 2 lattice vectors of a computational - cell in degrees. - - Args: - atoms: - vector_0: - vector_1: - """ - #| - angle_between_lattice_vectors - v1 = atoms.cell[vector_0] - v2 = atoms.cell[vector_1] - - angle = angle_between(v1, v2) - angle = math.degrees(angle) - - return(angle) - #__| - -def magnitude_of_lattice_vectors(atoms): - """Return magnitude of three lattice vectors. - - Args: - atoms: - """ - #| - magnitude_of_lattice_vectors - v1 = atoms.cell[0] - v2 = atoms.cell[1] - v3 = atoms.cell[2] - - mag1 = np.linalg.norm(v1) - mag2 = np.linalg.norm(v2) - mag3 = np.linalg.norm(v3) - - out_tup = (mag1, mag2, mag3) - - return(out_tup) - #__| - -def find_diff_between_atoms_objects(atoms_A, atoms_B): - """Find indices of atoms that are unique to atoms_A and atoms_B. - - Given two atoms objects (atoms_A and atoms_B), finds the atoms that are in - atoms_B but not in atoms_A and conversly the atoms that are in atoms_A but - not in atoms_B - - The criteria for equivalence between atoms is that their positions and - element type are the same - - This method should only be used for cases where atoms are added or removed, - if a relaxation is performed then the methods will fail to find the union - of atoms between both atoms objects since there positions will no longer be - exact - - Args: - atoms_A: - atoms_B: - """ - #| - find_diff_between_atoms_objects - - #| - __old__ - - # #| - Import Modules - # from ase import io - # #__| - # - # #| - Script Inputs - # atoms_A_filename = "A.traj" - # atoms_B_filename = "B.traj" - # #__| - # - # #| - Reading Atoms Objects - # atoms_A = io.read(atoms_A_filename) - # atoms_B = io.read(atoms_B_filename) - # #__| - - #__| - - #| - Building the Identical Atom Index List for Both Atoms Objects - atoms_A_ind_list = [] - atoms_B_ind_list = [] - for atom_A in atoms_A: - for atom_B in atoms_B: - - # Comparing Positions - pos_A = atom_A.position - pos_B = atom_B.position - pos_AB_comp = pos_A == pos_B - - # Comparing Element Type - elem_A = atom_A.symbol - elem_B = atom_B.symbol - elem_AB_comp = elem_A == elem_B - - if all(pos_AB_comp) is True and elem_AB_comp is True: - atoms_A_ind_list.append(atom_A.index) - atoms_B_ind_list.append(atom_B.index) - #__| - - atoms_A_unique_ind_list = [] - for atom_A in atoms_A: - if atom_A.index not in atoms_A_ind_list: - atoms_A_unique_ind_list.append(atom_A.index) - - atoms_B_unique_ind_list = [] - for atom_B in atoms_B: - if atom_B.index not in atoms_B_ind_list: - atoms_B_unique_ind_list.append(atom_B.index) - - return(atoms_A_unique_ind_list, atoms_B_unique_ind_list) - - #__| - -#__| ************************************************************************** - -#| - Modify Atoms Object ****************************************************** - -def move_atoms_of_element_i(atoms, element, new_position, dim="z"): - """Modify positions of all atoms of certain element. - - Args: - atoms: - element: - new_position: - dim: - """ - #| - move_atoms_of_element_i - if type(atoms) == str: - atoms = read(atoms) - else: - pass - - #| - Converting Input Dimension to Integer Index - if dim == "x": - dim = 0 - elif dim == "y": - dim = 1 - elif dim == "z": - dim = 2 - #__| - - elem_i_list = [] - for atom in atoms: - if atom.symbol == element: - - atom.position[dim] = atom.position[dim] + new_position - elem_i_list.append(atom) - - # return(atoms) - #__| - -def displace_overlayer( - atoms, - x_ind, - y_ind, - mesh_size_x, - mesh_size_y, - element="C", - save_file=False, - ): - """Displace atoms in an overlayer. - - Args: - x_ind: - y_ind: - mesh_size_x: - mesh_size_y: - element: - save_file: - """ - #| - displace_overlayer - atoms = copy.deepcopy(atoms) - - x_frac = 1. * x_ind / mesh_size_x - y_frac = 1. * y_ind / mesh_size_y - - # atoms = io.read("dir_atoms/init.traj") - # mag_lv0 = np.linalg.norm(atoms.cell[0]) - # mag_lv1 = np.linalg.norm(atoms.cell[1]) - - lv0 = atoms.cell[0] - lv1 = atoms.cell[1] - - - disp = lv0 * x_frac + lv1 * y_frac - - move_atoms_of_element_i(atoms, element, disp[0], dim="x") - move_atoms_of_element_i(atoms, element, disp[1], dim="y") - - fle_name = str(x_ind).zfill(2) + "_" + str(y_ind).zfill(2) + "_new.traj" - - if save_file: - atoms.write(fle_name) - - return(atoms) - #__| - -def change_vacuum(atoms, vacuum): - """Change the amount of vacuum in a slab. - - Assumes that the vacuum is in the z-direction orthogonal to - x and y axis - - Args: - atoms: - vacuum: - """ - #| - change_vacuum - if type(atoms) == str: - atoms = read(atoms) - else: - pass - - cell_copy = copy.deepcopy(atoms.cell) - - cell_copy[2][2] = vacuum - - atoms.set_cell(cell_copy) - atoms.center() - - return(atoms) - #__| - -#__| ************************************************************************** - -#| - Atoms Information Methods ************************************************ - - -def number_of_constrained_atoms(atoms): - """Count number of constrained atoms in atoms object. - - Args: - atoms: - """ - #| - number_of_constrained_atoms - if type(atoms) == str: - atoms = read(atoms) - else: - pass - - N_constraints = len(atoms.constraints) - - return(N_constraints) - #__| - -def highest_position_of_element(atoms, element_symbol): - """Return highest z-value for given element type. - - Args: - atoms: - element_symbol - """ - #| - highest_position_of_element - - #| - SCRIPT INPUTS - # element_symbol - element_name = element_symbol - # atoms_file_name = atoms - #__| - - if type(atoms) == str: - atoms = read(atoms) - else: - pass - - elem_atom_list = [] - for atom_i in atoms: - if atom_i.symbol == element_name: - elem_atom_list.append(atom_i.position) - - elem_atom_list = np.array(elem_atom_list) - elem_atom_list = np.sort(elem_atom_list[:, 2]) - highest_z_pos = elem_atom_list[-1] - - return(highest_z_pos) - #__| - -def number_of_atoms(atoms): - """Return atom count dictionary. - - DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED - create_species_element_dict - - Args: - atoms - """ - #| - number_of_atoms - atoms_sym_list = atoms.get_chemical_symbols() - unique_atom_symbols = list(set(atoms_sym_list)) - - atom_dict = {} - for atom_sym_i in unique_atom_symbols: - atom_i_cnt = atoms_sym_list.count(atom_sym_i) - - atom_dict[atom_sym_i] = atom_i_cnt - - print("THIS HAS BEEN DEPRECATED to create_species_element_dict") - print("THIS HAS BEEN DEPRECATED to create_species_element_dict") - print("THIS HAS BEEN DEPRECATED to create_species_element_dict") - print("THIS HAS BEEN DEPRECATED to create_species_element_dict") - - # return(atom_dict) - #__| - -def create_species_element_dict( - atoms, - include_all_elems=False, - elems_to_always_include=None, - ): - """Create dict from an atoms object with element: element number entries. - - If 'include_all_elems' is True then 'elems_to_always_include' must be None - - Args: - atoms: - include_all_elems: or - False: Does not add additional elements other than the ones - present in the atoms object - - True: Includes all elements in the periodic table, with 0 values - for the elements not present in the atoms object - - elems_to_always_include: - List of elements to include in the final dict, not including - the elements present in the atoms object. - - """ - #| - create_species_element_dict - from misc_modules.misc_methods import merge_two_dicts - - all_elements = list(periodic_table_dict) - - chem_syms = atoms.get_chemical_symbols() - chem_syms_unique = set(chem_syms) - - species_elem_dict = {} - for elem_i in chem_syms_unique: - num_elem_i = chem_syms.count(elem_i) - - species_elem_dict[elem_i] = num_elem_i - - #| - Include All Elements in the periodic table - if include_all_elems or elems_to_always_include is not None: - all_non_occuring_elements = list( - filter( - lambda x: x not in set(list(species_elem_dict)), all_elements - ) - ) -# print(all_non_occuring_elements) - -# if elems_to_always_include is not None: - if elems_to_always_include is not None and type(elems_to_always_include) == list: - non_occuring_elements = [i for i in all_non_occuring_elements if i in elems_to_always_include] - else: - non_occuring_elements = all_non_occuring_elements - - non_occuring_species_elem_dict = dict( - zip( - non_occuring_elements, - [0 for i in non_occuring_elements], - ) - ) - -# non_occuring_species_elem_dict = dict( -# zip( -# all_non_occuring_elements, -# [0 for i in all_non_occuring_elements], -# ) -# ) - - - species_elem_dict = merge_two_dicts( - non_occuring_species_elem_dict, - species_elem_dict, - ) - #__| - - return(species_elem_dict) - #__| - -#__| ************************************************************************** - -#| - Visualization ************************************************************ -def create_gif_from_traj( - traj_name="qn.traj", - path_i=".", - image_range="0:5", # "all" - delay=10, - rotation="0x, 0y, 0z", - ): - """Create gif animation from trajectory file. - - Args: - traj_name: - path_i: - image_range: - delay: - - """ - #| - create_gif_from_traj - - #| - Method Parameters - atoms_file_name = "out_movie" - fold_name = "images" - #__| - - #| - Creating png ********************************************************* - if image_range == "all": - ind_range = ":" - else: - ind_range = image_range - - atoms_traj = io.read(path_i + "/" + traj_name, index=ind_range) - - folder_i = fold_name - if not os.path.isdir(path_i + folder_i): - os.makedirs(path_i + "/" + folder_i) - - for index, atoms_i in enumerate(atoms_traj): - textures = ["simple" for i in range(len(atoms_i))] - - name = "TMP" - name_i = fold_name + "/" + str(index).zfill(3) + "_" + name + "_top" - io.write( - path_i + "/" + name_i + ".pov", - atoms_i, - rotation=rotation, - run_povray=True, - textures=textures, - canvas_height=1000, - display=False - ) - - print("Creating IMAGE: " + path_i + "/" + name_i + ".png") - - os.remove(path_i + "/" + name_i + ".pov") - os.remove(path_i + "/" + name_i + ".ini") - #__| ********************************************************************** - - #| - Converting Images to GIF ********************************************* - root_dir = os.getcwd() - os.chdir(path_i + "/" + fold_name) - - bash_command = "/usr/bin/convert " - bash_command += "-delay " + str(delay) + " " - bash_command += "-loop 0 " - # bash_command += "*png animation.gif" - bash_command += "*png " + atoms_file_name + ".gif" - - print("###### CREATING GIF ####### | " + atoms_file_name) - os.system(bash_command) - os.system("mv *.gif ..") - os.chdir(root_dir) - #__| ********************************************************************** - - #__| - -def create_gif_from_atoms_movies( - atoms_file="Default", - path_i=".", - delay=10, - ): - """Create png images from an multi-atoms atoms object. - - TODO This method is way to specific, should be chopped up - TODO Use create_gif_from_traj method - - Args: - atoms_file: - path_i: - delay: - """ - #| - create_images_from_atoms_movies - - #| - SCRIPT PARAMETERS - fold_name = "images" - #__| - - #| - Read Atoms File with *.traj File Name - - if atoms_file == "Default": - filenames = next(os.walk(path_i))[2] - - traj_files = [fle for fle in filenames if ".traj" in fle] - alist = {} - if len(traj_files) == 1: - atoms_file = traj_files[0] - - atoms_file_path = path_i + "/" + atoms_file - - # alist[atoms_file] = read(atoms_file, index=":") - - else: - pass - - atoms_file_name = copy.deepcopy(atoms_file) - atoms_file_name = atoms_file_name.split(".") - atoms_file_name.remove("traj") - atoms_file_name = ".".join(atoms_file_name) - - alist[atoms_file] = read(atoms_file_path, index=":") - #__| - - folder_i = fold_name - if not os.path.isdir(path_i + folder_i): - os.makedirs(path_i + folder_i) - - for i, file in enumerate(alist): - for index, atoms_i in enumerate(alist[file]): - textures = ["simple" for i in range(len(atoms_i))] - - if "traj" in file: - name = file[0:-5] - elif "xyz" in file: - name = file[0:-4] - elif "POSCAR" in file: - name = file[0:-7] - - name_i = fold_name + "/" + str(index).zfill(2) + "_" + name + "_top" - write( - path_i + "/" + name_i + ".pov", - atoms_i, - # alist[file], - rotation="0x, 0y, 0z", - run_povray=True, - textures=textures, - canvas_height=1000, - display=False - ) - - print("Creating IMAGE: " + path_i + name_i + ".png") - - os.remove(path_i + "/" + name_i + ".pov") - os.remove(path_i + "/" + name_i + ".ini") - - - #| - Converting Images to GIF - root_dir = os.getcwd() - - os.chdir(path_i + "/" + fold_name) - - bash_command = "/usr/bin/convert " - bash_command += "-delay " + str(delay) + " " - bash_command += "-loop 0 " - # bash_command += "*png animation.gif" - bash_command += "*png " + atoms_file_name + ".gif" - - print("###### CREATING GIF ####### | " + atoms_file_name) - os.system(bash_command) - - os.system("mv *.gif ..") - - os.chdir(root_dir) - #__| - - # TODO - Remove png files after creating gif !!!!! - #__| - -#__| ************************************************************************** - -#| - MISC - -def max_force(atoms): - """Return largest force on any atom. - - Args: - atoms: - - """ - #| - max_force - from ase import Atoms - from numpy import ndarray - - if isinstance(atoms, Atoms): - forces = atoms.get_forces() - - elif isinstance(atoms, ndarray): - forces = atoms - - elif isinstance(atoms, list): - forces = np.array(atoms) - - assert len(forces.shape) == 2, "Wrong shape" - assert forces.shape[1] == 3, "Incorrect number of compenents" - - # forces = atoms.get_forces() - - sum = 0.0 - largest = 0.0 - for a in range(len(atoms)): - force = np.sqrt( - forces[a][0] ** 2 + - forces[a][1] ** 2 + - forces[a][2] ** 2 - ) - - sum += force - if(force > largest): - largest = force - - return(largest, sum) - #__| - - - -#__| + +#!/usr/bin/env python + +"""Methods for ASE scripts, mostly DFT scripts. + +Author: Raul A. Flores + +Development Notes: + TODO Master print statements should have "****..." to be easily readable + TODO Delete all set_mag_mom_to_0 references (Already commented them out) + TODO Add work function analysis (Ask Colin about Karen's method) +""" + +#| - IMPORT MODULES +import sys +import os +import glob +import copy +import json +import math +import pickle as pickle +import numpy as np +import shutil + +from scipy.stats import norm + +# NOTE Changed for python3.6 +# import matplotlib.pyplot as plt +import matplotlib as plt + +from ase.io import read, write, Trajectory +from ase import io +from ase.dft.kpoints import ibz_points, get_bandpath +from ase.vibrations import Vibrations +from ase.thermochemistry import HarmonicThermo + +# pymatgen +from pymatgen.core.periodic_table import _pt_data as periodic_table_dict + +# My Modules +from misc_modules.numpy_methods import angle_between +from ase_modules.dft_params import Espresso_Params + +from quantum_espresso.qe_methods import estimate_magmom + +from bader_charge.bader import bader +#__| + +#| - METHODS + +def update_FINISHED(text, filename=".FINISHED.new"): + """Update finished job/processes log file with message. + + TODO Change filename --> .FINISHED when the migration to new system is + complete + + Args: + text: + filename: + """ + #| - update_FINISHED + if os.path.exists("./" + filename): + append_write = "a" # append if already exists + else: + append_write = "w" # make a new file if not + + with open(filename, append_write) as fle: + fle.write(text) + fle.write("\n") + #__| + +#__| + +#| - Parse DFT Job Parameters ************************************************* + +def set_QE_calc_params( + atoms=None, + params={}, + load_defaults=True, + init_inst=True, + ): + """Set Quantum Espresso calculation parameters to atoms object. + + Handles reading, and setting of dft calculator parameters to atoms object. + + Args: + atoms: + params: + load_defaults: + init_inst: + Whether or not to institiate an espresso instance + """ + #| - set_QE_calc_params + from espresso import espresso + + mess = "Loading QE Parameters From File " + mess += "**********************************************" + print(mess); sys.stdout.flush() + + espresso_params_inst = Espresso_Params(load_defaults=load_defaults) + + if os.path.isfile("dft-params.json"): + params_file = json.load(open("dft-params.json")) + espresso_params_inst.update_params(params_file) + + elif os.path.isfile("dir_dft_params/dft-params.json"): + params_file = json.load(open("dir_dft_params/dft-params.json")) + espresso_params_inst.update_params(params_file) + + espresso_params_inst.update_params(params) # Create params dict if wanted + + espresso_params_inst.test_check() + espresso_params_inst.write_params() + espresso_params = espresso_params_inst.params + + calc = None + if init_inst: + calc = espresso(**espresso_params) + + # NOTE Calculator set for the 1st time here + # atoms.set_calculator(calc=calc) + + return(calc, espresso_params) + #__| + +#__| ************************************************************************** + +#| - Ionic Optimization ******************************************************* + +def ionic_opt( + atoms, + calc=None, + traj=None, + espresso_params=None, + mode="opt", + fmax=0.05, + maxsteps=100000000, + run_beef_an=True, + run_bader_an=True, + save_wf=True, + ): + """Run ionic dft relaxation on atoms object. + + Development Notes: + * What to do when the job has already been previously completed? + Should I run a single point calculation just to make sure the + calculator is fully operational/loaded? + + TODO .FINSISHED file should include information about what kind of + optimization was performed + + TODO Implemetn qn.replay_trajectory('qn.traj') functionality + + Args: + atoms: ASE atoms object + calc: Calculator object + espresso_params: Quantum Espresso job parameters dictionary + mode: + fmax: Force convergence criteria + maxsteps: Maximum number of ionic steps + run_beef_an: + Attempts to run Beef-vdW ensemble of energies + Must have ran calculation with appropriate paramters to begin with + """ + #| - ionic_opt + from espresso import espresso + from ase.optimize import QuasiNewton + + mess = "Running DFT Calculation " + mess += "******************************************************" + print(mess) + sys.stdout.flush() + + # TODO Skip calculation if previously converged + # COMBAK Uncomment this section + #| - Checking if Previous Calculation Has Been Completed + # filename = ".FINISHED.new" + # if os.path.exists("./" + filename): + # with open(filename, "r") as fle: + # lines = [line.strip() for line in fle.readlines()] + # if "ionic_opt" in lines: + # print("ionic_opt | Optimization previusly completed " + # "(Running a single-point calculation)" + # ) + # mode = "sp" + #__| + + #| - Setting Optimization Specific Espresso Parameters + # espresso_params_copy = copy.deepcopy(espresso_params) + + params_opt = { + # "output": { + # "avoidio": True, + # "removesave": True, + # "removewf": True, + # "wf_collect": False, + # }, + + "outdir": "calcdir_opt", + } + + # espresso_params_copy.update(params_opt) + # calc_opt = espresso(**espresso_params_copy) + # atoms.set_calculator(calc_opt) + + calc_opt, espresso_params_opt = set_QE_calc_params( + params=params_opt, + ) + + calc_opt = espresso(**espresso_params_opt) + atoms.set_calculator(calc_opt) + #__| + + reduce_magmoms(atoms) + + if mode == "opt": + #| - Regular Optimization + mess = "Running regular optimization " + print(mess); sys.stdout.flush() + + # TEMP + do_strain_filter = False + if do_strain_filter: + print("Performing opt with StrainFilter class") + from ase.constraints import StrainFilter + SF = StrainFilter(atoms) + # atoms.set_constraint(SF) + + qn = QuasiNewton( + SF, + # trajectory="out_opt.traj", + logfile="qn.log", + ) + + else: + qn = QuasiNewton( + atoms, + # trajectory="out_opt.traj", + logfile="qn.log", + ) + + if traj is not None: + qn.attach(traj) # COMBAK Test feature (restarting traj files) + + if os.path.exists("prev.traj"): + qn.replay_trajectory("prev.traj") + + qn.run( + fmax=fmax, + steps=maxsteps, + ) + #__| + + elif mode == "easy_opt": + #| - Easy Optimization -> Full Optimization + mess = "Running easy optimization scheme" + print(mess); sys.stdout.flush() + + #| - Easy Optimization Settings + espresso_params_copy = copy.deepcopy(espresso_params) + + easy_params = { + "pw": 400, + "dw": 4000, + "spinpol": False, + "kpts": (3, 3, 1), + + "convergence": { + "energy": 5e-5, # convergence parameters + "mixing": 0.05, + "nmix": 20, + "mix": 4, + "maxsteps": 400, + "diag": "david", + }, + "outdir": "calcdir_easy", + } + + espresso_params_copy.update(easy_params) + easy_calc = espresso(**espresso_params_copy) + #__| + + #TODO: Find a way to freeze all atoms but adsorbates + # SIMPLE RELAXATION ################# + print("ionic_opt | Running Easy Relaxation"); sys.stdout.flush() + + magmoms = atoms.get_initial_magnetic_moments() + + # set_mag_mom_to_0(atoms) + + # FIXME I should be able to just use the "set_initial_magnetic_moments" + # method here. That should automatically set to magmoms to 0 from the + # QE parameters dict + atoms.set_initial_magnetic_moments(np.zeros(len(atoms))) + + atoms.set_calculator(easy_calc) + + qn = QuasiNewton( + atoms, + trajectory="out_opt_easy.traj", + logfile="qn.log", + ) + + if os.path.exists("prev.traj"): + qn.replay_trajectory("prev.traj") + + qn.run(fmax=fmax) + + # FULL RELAXATION ################# + print("ionic_opt | Running Full Relaxation"); sys.stdout.flush() + # atoms.set_calculator(calc) + atoms.set_calculator(calc_opt) + + print(magmoms) + atoms.set_initial_magnetic_moments(magmoms) + + qn = QuasiNewton( + atoms, + trajectory="out_opt.traj", + logfile="qn.log", + ) + + if os.path.exists("prev.traj"): + qn.replay_trajectory("prev.traj") + + qn.run(fmax=fmax) + #__| + + elif mode == "sp": + #| - Single Point Calculation + mess = "Running Single-Point Calculation" + print(mess); sys.stdout.flush() + + atoms.get_potential_energy() + write("out_opt.traj", atoms) + #__| + + + #TEMP + if save_wf: + atoms.calc.save_wf() + + estimate_magmom( + path_i=".", + atoms=atoms, + log="calcdir_opt/log", + ) + + elec_e = atoms.get_potential_energy() + + outdir = "dir_opt" + if not os.path.exists(outdir): + os.makedirs(outdir) + + e_out = outdir + "/elec_e.out" + with open(e_out, "w") as fle: + fle.write(str(elec_e) + "\n") + + # if mode != "sp": + # #| - Always Run Single-Point Calculation with Full IO + # mess = "Running Post-run Single-Point Calculation" + # print(mess); sys.stdout.flush() + # atoms.get_potential_energy() + # #__| + + update_FINISHED("ionic_opt") + + if run_beef_an: + an_beef_ensemble(atoms) + + if run_bader_an: + + #| - Running initial single-point calculation + params_bader = { + "output": { + "avoidio": False, + "removesave": True, + "removewf": True, + "wf_collect": False, + }, + + "outdir": "calcdir_bader", + } + + calc_bader, espresso_params_bader = set_QE_calc_params( + params=params_bader, + ) + + calc_bader = espresso(**espresso_params_bader) + atoms.set_calculator(calc_bader) + + mess = "Running single-point calc with high io " + print(mess); sys.stdout.flush() + atoms.get_potential_energy() + print("finished single-point"); sys.stdout.flush() + #__| + + bader(atoms, spinpol=espresso_params_opt["spinpol"], run_exec=True) + #__| + +#__| ************************************************************************** + +#| - Magnetic Moments ********************************************************* + +def set_init_mag_moms( + atoms, + preference="bader", + espresso_params=None, + magmoms=None, + read_from_file=False, + inc_val_magmoms=True, + ): + """Set initial magnetic moments to atoms object using several methods. + + Set inital magnetic moments to atoms object. If the atoms object has + previously had a bader or pdos analysis performed those magnetic moments + will be available under the atoms.info dict ("pdos_magmoms" and + "bader_magmoms" dict keys). + + # TODO Implement the "average" setting for the preference variable + + Args: + atoms: + Atoms object to be used + preference: + "bader" + "pdos" + "average" + magmoms: + If specified as a list, set the atom's initial magnetic + moments to list. If a element: magmom_i dict is given the magmoms + will be initilized from this dict. + inc_val_magmoms: + Will marginally increase the magnetic moments to hopefully aid + convergence. This is best used when starting from previously + converged magmoms. + """ + #| - set_init_mag_moms + mess = "Setting Inital Magnetic Moments " + mess += "**********************************************" + print(mess); sys.stdout.flush() + + preference_map_dict = { + "bader": "bader_magmoms", + "pdos": "pdos_magmoms" + } + + magmom_keys = ["pdos_magmoms", "bader_magmoms"] + magmoms_master_dict = {} + for magmom_key in magmom_keys: + if magmom_key in atoms.info.keys(): + magmoms_master_dict[magmom_key] = atoms.info[magmom_key] + + magmom_keys = magmoms_master_dict.keys() + + preferred_an = preference_map_dict[preference] + + if magmoms is not None: + + if type(magmoms) == list: + print("set_init_mag_moms | Using given magmoms") + sys.stdout.flush() + magmoms_i = magmoms + + # TODO Implement this featrure in simple_mag_moms, providing dict will + # update the init magmom dict + elif type(magmoms) == dict: + text = ("set_init_mag_moms | " + "Using simple method for initial magnetic moments " + "with updated values for dict - NOT IMPLEMENTED - 180425" + ) + print(text); sys.stdout.flush() + magmoms_i = simple_mag_moms(atoms) + + else: + spinpol_calc = calc_spinpol(atoms) + + if espresso_params is not None: + if "spinpol" in list(espresso_params): + spinpol_calc = espresso_params["spinpol"] + + #| - Spin-polarization turned off, set magmoms to 0 + if not spinpol_calc: + print("set_init_mag_moms | Spin-polarization turned off") + sys.stdout.flush() + mag_mom_list = atoms.get_initial_magnetic_moments() + magmoms_i = np.zeros(len(mag_mom_list)) + #__| + + # COMBAK This is a poor way of enforcing the analysis method preference + # Assumes that there are only 2 analysis methods + elif preferred_an in magmoms_master_dict.keys(): + text = ("set_init_mag_moms | " + "Using preferred method for initial magnetic moments " + "(" + preferred_an + ")" + ) + print(text); sys.stdout.flush() + magmoms_i = magmoms_master_dict[preferred_an] + + elif len(magmoms_master_dict.keys()) == 1: + an_method = magmoms_master_dict.keys()[0] + text = ("set_init_mag_moms | " + "Using " + an_method + " for initial magnetic moments") + print(text); sys.stdout.flush() + + magmoms_i = magmoms_master_dict[an_method] + + #| - Use simple method + else: + text = ("set_init_mag_moms | " + "Using simple method for initial magnetic moments") + print(text); sys.stdout.flush() + magmoms_i = simple_mag_moms(atoms) + #__| + + if read_from_file: + text = ("set_init_mag_moms | " + "Using magmom_init.in file for initial magnetic moments") + print(text); sys.stdout.flush() + + magmoms_tmp = read_magmoms_from_file() + if magmoms_tmp is not None: + magmoms_i = magmoms_tmp + + + #| - Check That Length of Magmoms_list == len(atoms) + if not len(magmoms_i) == len(atoms): + text = ("Length of magmoms doesn't match the number of atoms!!!!!!!!!!!" + "\n Will use simple method to assign initial magmoms") + + print(text); sys.stdout.flush() + magmoms_i = simple_mag_moms(atoms) + #__| + + if inc_val_magmoms: + magmoms_i = increase_abs_val_magmoms(atoms, magmoms_i) + + atoms.set_initial_magnetic_moments(magmoms_i) + + #| - Printing Magnetic Moments + print("set_init_mag_moms | Initial Magnetic Moments:") + for atom in atoms: + elem = atom.symbol + magmom = atom.magmom + print(elem + ": " + str(magmom)) + + #__| + + reduce_magmoms(atoms) + #__| + +def increase_abs_val_magmoms(atoms, magmoms_list, increase_amount=0.8): + """Increase absolute value of magmoms for atoms object. + + # COMBAK Shouldn't raise initial guess for light atoms (Or don't raise as + much) + + Will not modify magmoms == 0. + + Select light atoms will have their |magmom| raised by a set small amount to + not oversaturate the atomic maignetic moment (init_magmom > # valence e) + + Args: + magmoms_list: + increase_amount: + """ + #| - increase_abs_val_magmoms + inc = increase_amount + + light_atoms_list = { + "H": 0.1, + "He": 0.3, + "Li": 0.4, + "Be": 0.5, + "B": 0.6, + "C": 0.7, + "N": 0.8, + "O": 0.9, + "F": 1.0, + } + + new_magmom_list = [] + # for magmom in magmoms_list: + for atom, magmom in zip(atoms, magmoms_list): + + elem_i = atom.symbol + + if elem_i in light_atoms_list.keys(): + inc = light_atoms_list[atom.symbol] + + if magmom < 0.: + new_magmom = abs(magmom) + inc + new_magmom = -new_magmom + + elif magmom > 0.: + new_magmom = abs(magmom) + inc + + else: + new_magmom = 0. + + # Making sure H initial magmom isn't > 1 + if elem_i == "H": + if new_magmom > 0.99: + print("Setting H magmom to 1 - RF - 180423 - TEMP") + new_magmom = 1. + + new_magmom_list.append(new_magmom) + + + return(new_magmom_list) + #__| + +def calc_spinpol(atoms): + """Return whether spin polarization should be turned on or off. + + The atoms object must have the appropriate calculator object attachedd with + the relevent parameters declared + + Args: + atoms: + """ + #| - calc_spinpol + spinpol = True + if hasattr(atoms, "calc"): + if atoms.calc is not None: + spin_key = "spinpol" + params_dict = atoms.calc.__dict__ + if spin_key in params_dict: + spin_pol = params_dict[spin_key] + if spin_pol is False: + spinpol = False + # set_mag_mom_to_0(atoms) + # return(spinpol) + + return(spinpol) + #__| + +def simple_mag_moms(atoms): + """Implement simple procedure to set initial guess for magnetic moments. + + Args: + atoms + """ + #| - simple_mag_moms + + #| - High Spin Dictionary + master_dict_high_spin = { + + "Cr": 5, "Mn": 5, + "Cu": 1, "Ag": 0, "Au": 0, # 3d10 + "Ni": 3, "Pd": 3, "Pt": 3, # 3d8, 4s1 + "Co": 4, "Rh": 4, "Ir": 4, # 3d7, 4s1 + "Fe": 5, "Ru": 5, "Os": 5, # 3d6, 4s1 + "Mo": 5, "Tc": 5, "Hf": 2, + "Ta": 3, "W": 4, "Re": 5, "Ti": 2, + } + + spin_dict = { + "O": 2.5, + "H": 0.2, + "C": 0.2, + "N": 0.2, + } + #__| + + #| - Find cations + cations = [] + for atom in atoms: + if atom.symbol in master_dict_high_spin.keys(): + # if master_dict_high_spin.has_key(atom.symbol): + cations.append(atom.symbol) + #__| + + #| - Cation Magnetic Moments Dictionary + cation_magmom_dict = {} + for cation in cations: + cation_magmom_dict[cation] = master_dict_high_spin[cation] * 1.1 + 0.3 + #__| + + #| - Setting Magnetic Moments of Atoms + magmoms = atoms.get_initial_magnetic_moments() + + for atom in atoms: + if atom.symbol in cations: + magmoms[atom.index] = cation_magmom_dict[atom.symbol] + continue + + for elem_i in spin_dict.keys(): + if atom.symbol == elem_i: + magmoms[atom.index] = spin_dict[elem_i] + break + + else: + magmoms[atom.index] = 0.0 + magmoms = np.array(magmoms) + + return(magmoms) + #__| + + #__| + +def reduce_magmoms(atoms, ntypx=10): + """Reduce number of unique magnetic moments of atoms object. + + Reduce the number of unique magnetic moments by combining those that are + most similar among atoms with the same atomic symbol. This is necessary for + atoms objects with more than 10 types of magmom/symbol pairs because QE + only accepts a maximum of 10 types of atoms. + """ + #| - reduce_magmoms + syms = set(atoms.get_chemical_symbols()) + + master_dict = {} + for sym in syms: + master_dict[sym] = {} + + for atom in atoms: + if atom.magmom in master_dict[atom.symbol]: + master_dict[atom.symbol][atom.magmom].append(atom.index) + else: + master_dict[atom.symbol][atom.magmom] = [atom.index] + + ntyp = 0 + for sym in syms: + ntyp += len(master_dict[sym].keys()) + + while ntyp > ntypx: + magmom_pairs = {} + for sym in syms: + magmoms = master_dict[sym].keys() + if not len(magmoms) > 1: continue + min_delta = 1e6 + min_pair = () + for i, magmom1 in enumerate(magmoms): + for j, magmom2 in enumerate(magmoms): + if not i < j: continue + delta = np.abs(magmom1 - magmom2) + if delta < min_delta: + min_delta = delta + min_pair = (magmom1, magmom2) + + assert min_delta != 1e6 + assert min_pair != () + magmom_pairs[sym] = min_pair + + min_delta = 1e6 + min_sym = "" + for sym in magmom_pairs: + delta = np.abs(magmom_pairs[sym][0] - magmom_pairs[sym][1]) + if delta < min_delta: + min_delta = delta + min_sym = sym + + assert min_delta != 1e6 + assert min_sym != "" + if min_delta > 0.5: + warn = "WARNING, reducing pair of magmoms whose difference is " + print(warn + "%.2f" % min_delta) + + if np.abs(magmom_pairs[min_sym][0]) > np.abs(magmom_pairs[min_sym][1]): + master_dict[min_sym][magmom_pairs[min_sym][0]].extend( + master_dict[min_sym][magmom_pairs[min_sym][1]]) + del master_dict[min_sym][magmom_pairs[min_sym][1]] + else: + master_dict[min_sym][magmom_pairs[min_sym][1]].extend( + master_dict[min_sym][magmom_pairs[min_sym][0]]) + del master_dict[min_sym][magmom_pairs[min_sym][0]] + + ntyp = 0 + for sym in syms: + ntyp += len(master_dict[sym].keys()) + + #reassign magmoms + for sym in syms: + for magmom in master_dict[sym]: + for index in master_dict[sym][magmom]: + atoms[index].magmom = magmom + #__| + + +def read_magmoms_from_file(file_name="magmom_init.in"): + """Read inital magmoms from a file. + + Args: + file_name: + """ + #| - read_magmoms_from_file + print(os.path.isfile(file_name)) + magmoms = None + if os.path.isfile(file_name): + # try: + with open(file_name, "r") as fle: + # magmoms = [float(i.strip()) for i in fle.readlines()] + + magmom_list = [] + for i_tmp in fle.readlines(): + if not i_tmp == "\n": + magmom_list.append(float(i_tmp.strip())) + magmoms = magmom_list + + if magmoms is not None: + print(magmoms) + print( + "magmoms succesfully read from file!", + " | ", + "ase_methods.read_magmoms_from_file" + ) + + # except: + # print("Couldn't read init magmom file") + + + # print("__SD-sfd-") + # print(magmoms) + # # print(len(magmoms)) + # print("__SD-sfd-") + + return(magmoms) + #__| + + +#| - __old__ +# def compare_magmoms(self): +# def compare_magmoms(): +# """Compare spin states of two atoms objects. +# +# (I think I got this from Colin on 180413) +# +# Part of bigger script +# /home/colinfd/usr/bin/get_G.py +# +# TODO Port this code to my workflow +# +# Author: Colin Dickens +# """ +# #| - compare_magmoms +# def nearest_atom(atoms, position): +# """Returns atom nearest to position.""" +# #| - nearest_atom +# position = np.array(position) +# dist_list = [] +# for atom in atoms: +# dist = np.linalg.norm(position - atom.position) +# dist_list.append(dist) +# +# return atoms[np.argmin(dist_list)] +# #__| +# +# if len(self.ads_atoms) >= len(self.slab_atoms): +# ads = self.ads_atoms +# slab = self.slab_atoms +# indexed_by = self.slab +# not_indexed_by = self.ads +# else: +# slab = self.ads_atoms +# ads = self.slab_atoms +# indexed_by = self.ads +# not_indexed_by = self.slab +# +# delta_magmoms = [] +# ads_indices_used = [] +# for atom in slab: +# ads_atom = nearest_atom(ads, atom.position) +# if not self.quiet: +# if ads_atom.symbol != atom.symbol: +# print("WARNING! MAGMOM COMPARISON FAILURE") +# ads_indices_used.append(ads_atom.index) +# delta_magmoms.append(atom.magmom - ads_atom.magmom) +# +# ads_indices_not_used = [] +# for i in range(len(ads)): +# if i not in ads_indices_used: +# ads_indices_not_used.append(i) +# +# self.delta_magmoms = zip(range(len(slab)), delta_magmoms) +# self.delta_magmoms.sort(key=lambda x: abs(x[1]), reverse=True) +# +# common = "" +# uncommon = "" +# for i in range(8): +# atom = slab[self.delta_magmoms[i][0]] +# common += "%s%d: %.2f\t" % (atom.symbol, +# atom.index, +# self.delta_magmoms[i][1], +# ) +# +# for i in ads_indices_not_used: +# uncommon += "%s%d: %.2f\t"%(ads[i].symbol,ads[i].index,ads[i].magmom) +# +# if self.quiet: +# return +# print("~" * 6 + "MAGNETIC MOMENT COMPARISON" + "~" * 6) +# print("Largest magmom discrepancies (indexed by %s)" % indexed_by) +# print(common) +# print("Magnetic moments only present in %s" % not_indexed_by) +# print(uncommon + "\n") +# #__| +#__| + + +#__| ************************************************************************** + +#| - Density of States ******************************************************** +def an_pdos( + atoms, + # calc, + dos_kpts, + espresso_params, + ): + """Perform projected density of states (PDOS) analysis. + + # TODO Clean up, makes too much data + + Args: + atoms: + dos_kpts: + espresso_params: + """ + #| - an_pdos + from espresso import espresso + + mess = "Running PDOS Analysis " + mess += "********************************************************" + print(mess); sys.stdout.flush() + + outdir = "dir_pdos" + + params_dos = { + "output": { + "avoidio": False, + "removesave": True, + "removewf": True, # Changed this 181102 + "wf_collect": True, + }, + + "outdir": "calcdir_dos", + } + + calc_opt, espresso_params_dos = set_QE_calc_params( + params=params_dos, + ) + + calc_dos = espresso(**espresso_params_dos) + atoms.set_calculator(calc_dos) + + reduce_magmoms(atoms) + + mess = "Running single-point calc with high io " + print(mess); sys.stdout.flush() + atoms.get_potential_energy() + print("finished single-point"); sys.stdout.flush() + + cwd = os.getcwd() + dos = atoms.calc.calc_pdos( + nscf=True, + kpts=dos_kpts, + Emin=-20.0, + Emax=20.0, + ngauss=0, + sigma=0.2, + DeltaE=0.01, + tetrahedra=False, + slab=True, + ) + os.chdir(cwd) + + if not os.path.exists(outdir): + os.makedirs(outdir) + + pdos_out = outdir + "/dos.pickle" + with open(pdos_out, "w") as fle: + pickle.dump(dos, fle) + + # Set Magnetic Moments To Atoms Object From PDOS Intergration + spin_pdos( + atoms, + pdos_pkl=pdos_out, + outdir=outdir, + spinpol=espresso_params["spinpol"], + ) + + atoms.write(outdir + "/out_pdos.traj") + update_FINISHED("an_pdos") + #__| + +def spin_pdos( + atoms, + pdos_pkl=None, + valence_dict=None, + nscf=False, + kpts=None, + outdir=None, + save_pkl=False, + spinpol=False, + write_charges=True, + **kwargs + ): + """Calculate spin moments on each atom from PDOS analysis. + + Calculate more accurate charges/magnetic moments from pdos and assign to + atom.charge/atom.magmom. If pdos_pkl not defined, it will be calculated + (atoms object must have a real calculator attached). If pdos_pkl is + defined, will attempt to load from pickle file, but valence_dict must be + specified! Specify calculation directory as outdir for easy cleanup. + + Args: + atoms: + pdos_pkl: + valence_dict: + nscf: + kpts: + outdir: + save_pkl: + spinpol: + write_charges: + kwargs: + """ + #| - spin_pdos + valence_dict = { + "Cu": 11, "C": 4, "O": 6, "H": 1, "Li": 1, + "Rh": 17, "Co": 9, "Pd": 10, "Pt": 10, + "Ni": 1, "Fe": 16, "N": 5, "Ru": 16, + } + + #| - Reading PDOS File, Otherwise Creates It + # FIXME I don't like that it can create PDOS file, this is handled by my + # an_pdos method. + + if pdos_pkl: + print("spin_pdos | pdos_pkl is not None") # TEMP For testing purposes + assert valence_dict is not None, "MUST SPECIFY valence_dict" + single_point_calc = True + pdos = pickle.load(open(pdos_pkl)) + nvalence_dict = valence_dict + + else: + print("spin_pdos | pdos_pkl is None") # TEMP For testing purposes + single_point_calc = False + # dict with (chemical symbol) : (num valence) + nvalence_dict = atoms.calc.get_nvalence()[1] + # double k-points for higher quality pdos --> O(single point calc) + if nscf: + print("spin_pdos | TEMP1") + pdos = atoms.calc.calc_pdos(nscf=True, kpts=kpts, **kwargs) + else: # no single point calc, should take 1 or 2 minutes + print("spin_pdos | TEMP2") + pdos = atoms.calc.calc_pdos(**kwargs) + #__| + + #| - Finding Index of Fermi Level + for i_ind, e_i in enumerate(pdos[0]): + if e_i > 0: + fi = i_ind # index of fermi level + break + #__| + + #| - Analysing PDOS For Magnetic Moments and Charge of All Atoms + if spinpol: + #| - Spin Polarlized Calculation + magmom_list = [] + charge_list = [] + for i, atom in enumerate(atoms): + + #| - Integrating Up and Down Spin PDOS + spin_up = 0; spin_down = 0 + for sym in pdos[2][i]: + spin_up += np.trapz(pdos[2][i][sym][0][:fi], x=pdos[0][:fi]) + spin_down += np.trapz(pdos[2][i][sym][1][:fi], x=pdos[0][:fi]) + + #__| + + #| - Update Atoms Magmom and Charge Properties + ##Update magmom + if np.abs(spin_up - spin_down) > 1e-4: + magmom_i = spin_up - spin_down + else: + magmom_i = 0. + + magmom_list.append(magmom_i) + atom.magmom = magmom_i + + ##Update charge + if atom.symbol not in nvalence_dict.keys(): + print("Atom ", str(atom.symbol), " not is the nvalance dict") + + + + # charge_i = nvalence_dict[atom.symbol] - (spin_up + spin_down) + charge_i = nvalence_dict.get(atom.symbol, 0.) - (spin_up + spin_down) + if write_charges: + # atom.charge = nvalence_dict[atom.symbol]-(spin_up+spin_down) + atom.charge = charge_i + + charge_list.append(charge_i) + #__| + + print("PDOS MAGMOMS: " + str(atoms.get_initial_magnetic_moments())) + reduce_magmoms(atoms) + + atoms.info.update({"magmom_set": True}) + atoms.info.update({"pdos_magmoms": magmom_list}) + atoms.info.update({"pdos_charges": charge_list}) + + pickle.dump(magmom_list, open("%s/magmom_list.pickle" % outdir, "w")) + pickle.dump(charge_list, open("%s/charge_list.pickle" % outdir, "w")) + + + #| - Writing atom objects with magmom and charges written to them + # Charges written to init_charges + atoms_cpy1 = copy.deepcopy(atoms) + atoms_cpy1.set_initial_charges(charge_list) + atoms_cpy1.write( + os.path.join( + outdir, + "pdos_charges.traj", + ), + ) + + # Magmoms written to init_charges + atoms_cpy2 = copy.deepcopy(atoms) + atoms_cpy2.set_initial_charges(magmom_list) + atoms_cpy2.write( + os.path.join( + outdir, + "pdos_magmoms.traj", + ), + ) + #__| + + #__| + + else: + #| - Non-Spin Polarized Calculation + charge_list = [] + for i, atom in enumerate(atoms): + + #| - Integrating PDOS For Charges + charge = 0 + for sym in pdos[2][i]: + charge += np.trapz(pdos[2][i][sym][0][:fi], x=pdos[0][:fi]) + #__| + + #| - Update Atoms Charges + # Update charge + charge_i = nvalence_dict.get(atom.symbol, 0.) - (charge) + if write_charges: + # atom.charge = nvalence_dict[atom.symbol] - (charge) + atom.charge = charge_i + charge_list.append(charge_i) + #__| + + atoms.info.update({"pdos_charges": charge_list}) + + pickle.dump( + charge_list, + open( + "%s/charge_list.pickle" % outdir, + "w", + ) + ) + + #| - Writing atom objects with magmom and charges written to them + # Charges written to init_charges + atoms_cpy1 = copy.deepcopy(atoms) + atoms_cpy1.set_initial_charges(charge_list) + atoms_cpy1.write( + os.path.join( + outdir, + "pdos_charges.traj", + ), + ) + #__| + + #__| + + print("PDOS CHARGES: " + str(atoms.get_initial_charges())) + #__| + + #| - Writing Output To File + if outdir and not single_point_calc: + #Save only the Lowdin charges in the pdos log file + light_lines = [] + + f = open("%s/pdos.log" % outdir) + lines = f.readlines() + f.close() + + skip = False + for line in lines: + try: + if line.split()[0] == "k": + skip = True + elif line.split()[0] == "Lowdin": + skip = False + except: continue + + if not skip: + light_lines.append(line) + + f = open("%s/pdos_Lowdin.log" % outdir, "w") + f.writelines(light_lines) + f.close() + os.system("rm %s/pdos.log" % outdir) + + if save_pkl: + pickle.dump(pdos, open("pdos.pkl", "w")) + #__| + + #__| + +#__| ************************************************************************** + +#| - Band Structure *********************************************************** + +def an_bands(atoms, bands_kpts, espresso_params): + """Perform band analysis on atoms object. + + Development Notes: + * TODO Creates too much data, clean up + * TODO Check if bands have been calculated earlier + + Args: + atoms: + bands_kpts: + espresso_params: + """ + #| - an_bands + from espresso import espresso + + mess = "Executing Band Structure Analysis " + mess += "********************************************" + print(mess); sys.stdout.flush() + + # FIXME This should be handled by envoking the + # set_initial_magnetic_moments method + spinpol_calc = calc_spinpol(atoms) + if spinpol_calc is False: + print("an_bands | Spin-polarization turned off, setting magmoms to 0") + atoms.set_initial_magnetic_moments(np.zeros(len(atoms))) + # set_mag_mom_to_0(atoms) # COMBAK Remove this if working + + #| - Running initial single-point calculation + params_bands = { + "output": { + "avoidio": False, + "removewf": True, + "removesave": True, # Changed this to true so it wouldn't make big files anymore + "wf_collect": False, + }, + + "kpts": bands_kpts, + # "outdir": "dir_bands" + + "outdir": "calcdir_bands", + } + + # "avoidio": false, + # "removesave": true, + # "removewf": true, + # "wf_collect": false, + + calc_bands, espresso_params_bands = set_QE_calc_params( + params=params_bands, + ) + + calc_bands = espresso(**espresso_params_bands) + atoms.set_calculator(calc_bands) + + mess = "Running single-point calc with high io " + print(mess); sys.stdout.flush() + atoms.get_potential_energy() + print("finished single-point"); sys.stdout.flush() + #__| + + # # calc_spinpol(atoms) # COMBAK I don't think this is doing anything + # espresso_params.update( + # { + # "kpts": bands_kpts, + # "outdir": "dir_bands" + # }, + # ) + # atoms.calc = espresso(**espresso_params) + # mess = "Running single-point calculation" + # print(mess); sys.stdout.flush() + # atoms.get_potential_energy() + + atoms.calc.save_flev_chg("charge_den.tgz") + atoms.calc.load_flev_chg("charge_den.tgz") + + # COMBAK How to handle this more generally? + ip = ibz_points["fcc"] + points = ["Gamma", "X", "W", "K", "L", "Gamma"] + bzpath = [ip[p] for p in points] + kpts, x, X = get_bandpath(bzpath, atoms.cell, npoints=300) + + mess = "Calculating band structure" + print(mess); sys.stdout.flush() + + # Note Need current dir because calc_bandstructure moves to calc_dir + cwd = os.getcwd() + energies = atoms.calc.calc_bandstructure(kpts, atomic_projections=True) + os.chdir(cwd) + + if not os.path.exists("dir_bands"): + os.makedirs("dir_bands") + + with open("dir_bands/band_disp.pickle", "w") as fle: + pickle.dump((points, kpts, x, X, energies), fle) + + # COMBAK This broke when file already existed, tried a fix - 180405 - RF + shutil.move("charge_den.tgz", "dir_bands/charge_den.tgz") + atoms.write("dir_bands/out_bands.traj") + + update_FINISHED("an_bands") + #__| + +#__| ************************************************************************** + +#| - Beef Ensemble of Energies ************************************************ +# def an_beef_ensemble(atoms, xc): # COMBAK +def an_beef_ensemble(atoms): + """Perform BEEF ensemble of enery analysis. + + Atoms must have an initialized calculator object attached. + + FIXME The xc parameter is no longer needed it can be gleamed from the + atoms' calculator object + + Args: + atoms: + xc: + """ + #| - an_beef_ensemble + mess = "Executing BEEF Ensemble Analysis " + mess += "*********************************************" + print(mess); sys.stdout.flush() + + beefensemble_on = atoms.calc.beefensemble + xc = atoms.calc.xc + + if beefensemble_on is False: + print("The ase-espresso calculator has the beefensemble" + " parameter turned off!, analysis will not run!!") + return(None) + + allowed_xc = ["BEEF", "BEEF-vdW"] + # if xc != "BEEF" or xc != "BEEF-vdW": + if xc not in allowed_xc: + print("The exchange-correlation functional has to be either " + "BEEF or BEEF-vdW to do the BEEF ensemble analysis") + return(None) + + # if xc == "BEEF" or xc == "BEEF-vdW": + + # calc = atoms.calc + from ase.dft.bee import BEEFEnsemble + + energy = atoms.get_potential_energy() + # ens = BEEFEnsemble(atoms=atoms, e=energy, xc="beefvdw") + # NOTE The BEEFEnsemble class should parse xc from atoms object + # COMBAK + ens = BEEFEnsemble(atoms=atoms, e=energy) + ens_e = ens.get_ensemble_energies() + + if not os.path.exists("dir_beef_ensemble"): + os.makedirs("dir_beef_ensemble") + + with open("dir_beef_ensemble/ensemble.pickle", "w") as fle: + pickle.dump(ens_e, fle) + + update_FINISHED("an_beef_ensemble") + #__| + +def plot_beef_ensemble( + folder_dir="dir_beef_ensemble", + file_name="ensemble.pickle", + file_out="beef_ens_hist.png", + ): + """Create plot of distribution of energies from BEEF ensemble. + + Args: + folder_dir: + file_name: + file_out: + """ + #| - plot_beef_ensemble + file_loc = folder_dir + "/" + file_name + + data = pickle.load(open(file_loc, "r")) + + mu, std = norm.fit(data) + plt.hist(data, bins=25, normed=False, alpha=0.6, color="g") + + xmin, xmax = plt.xlim() + x = np.linspace(xmin, xmax, 100) + p = norm.pdf(x, mu, std) + plt.plot(x, p, 'k', linewidth=2) + title = "Fit results: mu = %.2f, std = %.2f" % (mu, std) + plt.title(title) + + out_file = folder_dir + "/" + file_out + plt.savefig(out_file) + # plt.show() + #__| + +#__| ************************************************************************** + +#| - Vibrational Analysis ***************************************************** +def an_ads_vib( + atoms, + espresso_params=None, + ads_index_list=None, + # thermochem_corrections=True, + thermochem_corrections="harmonic", # "harmonic" or "IG" + remove_imag_modes=True, + + Temperature=300.0, + Pressure=100000.0, + symmetrynumber=2, + spin=0, + linear=True, + ): + """Adsorbate vibrational analysis. + + Returns the ASE Vibrations instance in case further analysis is needed. + + Args: + atoms: + ads_index_list: + thermochem_corrections: + remove_imag_modes: Removes imaginary modes + """ + #| - an_ads_vib + # from espresso import espresso + from espresso.vibespresso import vibespresso + + mess = "Starting vibrational analysis " + mess += "************************************************" + print(mess); sys.stdout.flush() + + #| - Setting Adsorbate Index List + if ads_index_list is not None: + pass + elif "adsorbates" in atoms.info.keys(): + print("Adsorbate info present! Good good.") + ads_index_list = atoms.info["adsorbates"] + else: + print("an_ads_vib | Adsorbate index info couldn't be parsed from atoms") + print("an_ads_vib | Will vibrate all atoms!!!!!!!! (Probably not good)") + pass + #__| + + #| - Removing Empty Pickle Files + pckl_file_list = glob.glob("dir_vib/*.pckl*") + glob.glob("*.pckl*") + for pckl_file in pckl_file_list: + if os.stat(pckl_file).st_size == 0: + os.remove(pckl_file) + print("an_ads_vib | " + pckl_file + " empty, so removed") + #__| + + #| - Copy vib.pckl files back to root dir (For restarting) + for fle in glob.glob("dir_vib/*.pckl*"): + fle_name = fle.split("/")[-1] + shutil.move(fle, fle_name) + #__| + + #| - Running initial single-point calculation + params_vib = { + "output": { + "avoidio": False, + "removesave": False, + "removewf": False, + "wf_collect": True, + }, + + # "kpts": bands_kpts, + # "outdir": "dir_bands" + + "outdir": "calcdir_vib", + } + + calc_vib, espresso_params_vib = set_QE_calc_params( + params=params_vib, + ) + + calc_vib = vibespresso( + outdirprefix="out_vib", + **espresso_params_vib) + + # atoms.set_calculator(calc) + # calc_vib = espresso(**espresso_params_vib) + + atoms.set_calculator(calc_vib) + + # mess = "Running single-point calc with high io " + # print(mess); sys.stdout.flush() + # atoms.get_potential_energy() + # print("finished single-point"); sys.stdout.flush() + #__| + + set_init_mag_moms( + atoms, + preference="bader", + espresso_params=espresso_params_vib, + ) + + # set_init_mag_moms(atoms) + + vib = Vibrations(atoms, indices=ads_index_list) + vib.run() + + # print("an_ads_vib | Getting vibrational energies") + vib_e_list = vib.get_energies() + + vib.summary(log="vib_summ.out") + + #| - Copy Files to dir_vib Folder + if not os.path.exists("dir_vib"): + os.makedirs("dir_vib") + shutil.move("vib_summ.out", "dir_vib/vib_summ.out") + + dest_dir = "dir_vib" + for fle in glob.glob(r'*.pckl*'): + shutil.move(fle, dest_dir + "/" + fle) + + + for fle in glob.glob(r'*out_vib*'): + shutil.move(fle, dest_dir + "/" + fle) + #__| + + #| - Remove Imaginary Modes + # Removes them, not just making them 0 + if remove_imag_modes: + vib_e_list = vib_e_list.real + vib_e_list = [vib_i for vib_i in vib_e_list if vib_i != 0.] + #__| + + if thermochem_corrections == "harmonic": + thermochem_harm_corr(vib_e_list) + + elif thermochem_corrections == "IG": + thermochem_IG_corr( + vib_e_list, + Temperature=Temperature, + Pressure=Pressure, + potentialenergy=0., + symmetrynumber=symmetrynumber, + spin=spin, + atoms=atoms, + linear=linear, + ) + + # Saving Vibrational Mode List + with open("dir_vib/vib_modes.pickle", "w") as fle: + pickle.dump(vib_e_list, fle) + + #| - Saving Vibrations Class Instance + file_name = "dir_vib/vib_inst.pickle" + if not os.path.exists(file_name): + pass + else: + os.remove(file_name) + + # Pickling error occured when pickling the atoms object + if "atoms" in vars(vib): del vars(vib)["atoms"] + + with open(file_name, "w") as fle: + pickle.dump(vib, fle) + #__| + + update_FINISHED("an_ads_vib") + + # return(vib_e_list) + return(vib) + #__| + +def thermochem_harm_corr( + vib_e_list, + Temperature=300.0, + ): + """Thermochemical free energy corrections from vibrational analysis. + + Args: + vib_e_list: + List of vibrational modes in eV + Temperature: + """ + #| - thermochem_harm_corr + mess = "Starting thermochemical harmonic energy contributions " + mess += "***********************" + print(mess); sys.stdout.flush() + + print("Calculating thermochemical corrections @ " + str(Temperature) + "K") + + vib_e_list = np.array(vib_e_list) + + # Remove imaginary frequencies + vib_e_list = vib_e_list.real + vib_e_list = [vib_i for vib_i in vib_e_list if vib_i != 0.] + + ht = HarmonicThermo(vib_e_list) + F_energy = ht.get_helmholtz_energy(Temperature) + + if not os.path.exists("dir_vib"): + os.makedirs("dir_vib") + + with open("dir_vib/gibbs_corr.out", "w") as fle: + fle.write(str(F_energy)) + fle.write("\n") + #__| + +def thermochem_IG_corr( + vib_energies, + Temperature=300.0, + Pressure=100000.0, + potentialenergy=0., + symmetrynumber=None, + spin=None, + atoms=None, + linear=True, + ): + """Calculate free energy to gas phase molecule from vibrational modes. + + Args: + vib_e_list: + Temperature=300.0: + Pressure=100000.0: + potentialenergy=0.: + symmetrynumber=None: + spin=None: + atoms=None: + """ + #| - thermochem_IG_corr + mess = "Starting thermochemical ideal gas energy contributions " + mess += "***********************" + print(mess); sys.stdout.flush() + + from ase.thermochemistry import IdealGasThermo + + # try: + # with open("dir_vib/vib_inst.pickle", "r") as fle: + # vib = pickle.load(fle) + # except: + # pass + # + # vib_energies = vib.get_energies() + + if atoms is not None: + potentialenergy = atoms.get_potential_energy() + + if linear is True: + lin = "linear" + else: + lin = "nonlinear" + + thermo = IdealGasThermo( + vib_energies, + lin, # linear/nonlinear + potentialenergy=potentialenergy, + atoms=atoms, + + # H2O, H2, O2: 2, + symmetrynumber=symmetrynumber, # symmetry numbers from point group + spin=spin, # 1 for O2, 0 for H2O and H2 + ) + + G = thermo.get_gibbs_energy(temperature=Temperature, pressure=Pressure) + + if not os.path.exists("dir_vib"): + os.makedirs("dir_vib") + + with open("dir_vib/g_energy.out", "w") as fle: + fle.write(str(G)) + #__| + + +#__| ************************************************************************** + +#| - Job Cleanup +def clean_up_dft(): + """Clean up files after DFT job. + + I'm using a lot of try statement because I dont want this to break anywhere + """ + #| - clean_up_dft + with open(".FINISHED", "w") as fle: + fle.write("\n") + + # def update_FINISHED(text, filename=".FINISHED.new"): + + update_FINISHED("job_completed") + + if not os.path.exists("__misc__"): + os.makedirs("__misc__") + + #| - Moving Sherlock Node Files to __misc__ folder + # Sherlock didn't like this: + # Open RTE was unable to open the hostfile: + # /scratch/users/flores12/03_graph_N_Fe/01_opt_struct/N_doped_graph_Fe/1-att/__test__/1-att/_5/uniqnodefile.21286552 + # Check to make sure the path and filename are correct. + + + # try: + # if "COMPENV" in os.environ: + # compenv = os.environ["COMPENV"] + # if compenv == "sherlock": + # os.system("mv *nodefile.* __misc__") + # os.system("mv *uniqnodefile..* __misc__") + # + # except: + # pass + #__| + + #| - Moving DFT Parameter Files to dir_dft_params + try: + if not os.path.exists("dir_dft_params"): + os.makedirs("dir_dft_params") + + # os.system("ls") + # os.system("pwd") + os.system("mv *dft-params* dir_dft_params") + + except: + pass + #__| + + #__| + +#__| + +#| - Atoms File Operations **************************************************** +def read_atoms_from_file(filename=None, try_restart=True): + """Read atoms object from file. + + Checks several file names + + TODO Options and methods to read and check output trajectory files + + Args: + filename: optional atoms file, will attempt to read first. + try_restart: Restart job by reading output atoms/trajectory object + """ + #| - read_atoms_from_file + mess = "Reading Atoms Object From File " + mess += "***********************************************" + print(mess) + + atoms = None + traj = None + + #| - Restart From Output Atoms Object + restart_file_name_list = [ + "out.traj", + "out_opt.traj", + "out_final.traj", + ] + + if try_restart: + for file_name in restart_file_name_list: + if os.path.isfile(file_name): + + try: + atoms = read(file_name) + traj = Trajectory(file_name, "a", atoms) + + mess = "read_atoms_from_file | Restarting from " + mess += file_name + print(mess); sys.stdout.flush() + + break + + except: + pass + #__| + + #| - Starting From Fresh Atoms Object + file_name_list = [ + "init.traj", + "init.POSCAR", + "manual_start.traj", + "POSCAR", + ] + + if atoms is None: + + if filename is not None: + file_name_list.insert(0, filename) + + for file_name in file_name_list: + if os.path.isfile(file_name): + atoms = read(file_name) + # COMBAK Test feature + traj = Trajectory("out_opt.traj", "w", atoms) + + mess = "read_atoms_from_file | Starting from " + mess += file_name + print(mess); sys.stdout.flush() + + break + #__| + + if atoms is None: + raise IOError("No atoms file found") + + return(atoms, traj) + #__| + +def convert_atoms_object(atoms_filename, out_file): + """Convert atoms objects to new file format. + + Args: + atoms_filename: + out_file: + """ + #| - convert_atoms_object + atoms = read(atoms_filename) + + #| - Convert to New Trajectory File Format + if out_file.split(".")[-1] == "traj": + write(out_file, atoms) + + #| - Using Trajectory Class Directly (Not Right?) + # traj = Trajectory(out_file, mode="w", atoms=atoms) + # traj.set_description({"author": "Created by Raul Flores"}) + # traj.write() + #__| + + #__| + + #__| + +#__| ************************************************************************** + +#| - Atoms Geometry Methods *************************************************** +def angle_between_lattice_vectors(atoms, vector_0=0, vector_1=1): + """Calculate angle between cell lattice vectors. + + Calculates the angle between the first 2 lattice vectors of a computational + cell in degrees. + + Args: + atoms: + vector_0: + vector_1: + """ + #| - angle_between_lattice_vectors + v1 = atoms.cell[vector_0] + v2 = atoms.cell[vector_1] + + angle = angle_between(v1, v2) + angle = math.degrees(angle) + + return(angle) + #__| + +def magnitude_of_lattice_vectors(atoms): + """Return magnitude of three lattice vectors. + + Args: + atoms: + """ + #| - magnitude_of_lattice_vectors + v1 = atoms.cell[0] + v2 = atoms.cell[1] + v3 = atoms.cell[2] + + mag1 = np.linalg.norm(v1) + mag2 = np.linalg.norm(v2) + mag3 = np.linalg.norm(v3) + + out_tup = (mag1, mag2, mag3) + + return(out_tup) + #__| + +def find_diff_between_atoms_objects(atoms_A, atoms_B): + """Find indices of atoms that are unique to atoms_A and atoms_B. + + Given two atoms objects (atoms_A and atoms_B), finds the atoms that are in + atoms_B but not in atoms_A and conversly the atoms that are in atoms_A but + not in atoms_B + + The criteria for equivalence between atoms is that their positions and + element type are the same + + This method should only be used for cases where atoms are added or removed, + if a relaxation is performed then the methods will fail to find the union + of atoms between both atoms objects since there positions will no longer be + exact + + Args: + atoms_A: + atoms_B: + """ + #| - find_diff_between_atoms_objects + + #| - __old__ + + # #| - Import Modules + # from ase import io + # #__| + # + # #| - Script Inputs + # atoms_A_filename = "A.traj" + # atoms_B_filename = "B.traj" + # #__| + # + # #| - Reading Atoms Objects + # atoms_A = io.read(atoms_A_filename) + # atoms_B = io.read(atoms_B_filename) + # #__| + + #__| + + #| - Building the Identical Atom Index List for Both Atoms Objects + atoms_A_ind_list = [] + atoms_B_ind_list = [] + for atom_A in atoms_A: + for atom_B in atoms_B: + + # Comparing Positions + pos_A = atom_A.position + pos_B = atom_B.position + pos_AB_comp = pos_A == pos_B + + # Comparing Element Type + elem_A = atom_A.symbol + elem_B = atom_B.symbol + elem_AB_comp = elem_A == elem_B + + if all(pos_AB_comp) is True and elem_AB_comp is True: + atoms_A_ind_list.append(atom_A.index) + atoms_B_ind_list.append(atom_B.index) + #__| + + atoms_A_unique_ind_list = [] + for atom_A in atoms_A: + if atom_A.index not in atoms_A_ind_list: + atoms_A_unique_ind_list.append(atom_A.index) + + atoms_B_unique_ind_list = [] + for atom_B in atoms_B: + if atom_B.index not in atoms_B_ind_list: + atoms_B_unique_ind_list.append(atom_B.index) + + return(atoms_A_unique_ind_list, atoms_B_unique_ind_list) + + #__| + +#__| ************************************************************************** + +#| - Modify Atoms Object ****************************************************** + +def move_atoms_of_element_i(atoms, element, new_position, dim="z"): + """Modify positions of all atoms of certain element. + + Args: + atoms: + element: + new_position: + dim: + """ + #| - move_atoms_of_element_i + if type(atoms) == str: + atoms = read(atoms) + else: + pass + + #| - Converting Input Dimension to Integer Index + if dim == "x": + dim = 0 + elif dim == "y": + dim = 1 + elif dim == "z": + dim = 2 + #__| + + elem_i_list = [] + for atom in atoms: + if atom.symbol == element: + + atom.position[dim] = atom.position[dim] + new_position + elem_i_list.append(atom) + + # return(atoms) + #__| + +def displace_overlayer( + atoms, + x_ind, + y_ind, + mesh_size_x, + mesh_size_y, + element="C", + save_file=False, + ): + """Displace atoms in an overlayer. + + Args: + x_ind: + y_ind: + mesh_size_x: + mesh_size_y: + element: + save_file: + """ + #| - displace_overlayer + atoms = copy.deepcopy(atoms) + + x_frac = 1. * x_ind / mesh_size_x + y_frac = 1. * y_ind / mesh_size_y + + # atoms = io.read("dir_atoms/init.traj") + # mag_lv0 = np.linalg.norm(atoms.cell[0]) + # mag_lv1 = np.linalg.norm(atoms.cell[1]) + + lv0 = atoms.cell[0] + lv1 = atoms.cell[1] + + + disp = lv0 * x_frac + lv1 * y_frac + + move_atoms_of_element_i(atoms, element, disp[0], dim="x") + move_atoms_of_element_i(atoms, element, disp[1], dim="y") + + fle_name = str(x_ind).zfill(2) + "_" + str(y_ind).zfill(2) + "_new.traj" + + if save_file: + atoms.write(fle_name) + + return(atoms) + #__| + +def change_vacuum(atoms, vacuum): + """Change the amount of vacuum in a slab. + + Assumes that the vacuum is in the z-direction orthogonal to + x and y axis + + Args: + atoms: + vacuum: + """ + #| - change_vacuum + if type(atoms) == str: + atoms = read(atoms) + else: + pass + + cell_copy = copy.deepcopy(atoms.cell) + + cell_copy[2][2] = vacuum + + atoms.set_cell(cell_copy) + atoms.center() + + return(atoms) + #__| + +#__| ************************************************************************** + +#| - Atoms Information Methods ************************************************ + + +def number_of_constrained_atoms(atoms): + """Count number of constrained atoms in atoms object. + + Args: + atoms: + """ + #| - number_of_constrained_atoms + if type(atoms) == str: + atoms = read(atoms) + else: + pass + + N_constraints = len(atoms.constraints) + + return(N_constraints) + #__| + +def highest_position_of_element(atoms, element_symbol): + """Return highest z-value for given element type. + + Args: + atoms: + element_symbol + """ + #| - highest_position_of_element + + #| - SCRIPT INPUTS + # element_symbol + element_name = element_symbol + # atoms_file_name = atoms + #__| + + if type(atoms) == str: + atoms = read(atoms) + else: + pass + + elem_atom_list = [] + for atom_i in atoms: + if atom_i.symbol == element_name: + elem_atom_list.append(atom_i.position) + + elem_atom_list = np.array(elem_atom_list) + elem_atom_list = np.sort(elem_atom_list[:, 2]) + highest_z_pos = elem_atom_list[-1] + + return(highest_z_pos) + #__| + +def number_of_atoms(atoms): + """Return atom count dictionary. + + DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED + create_species_element_dict + + Args: + atoms + """ + #| - number_of_atoms + atoms_sym_list = atoms.get_chemical_symbols() + unique_atom_symbols = list(set(atoms_sym_list)) + + atom_dict = {} + for atom_sym_i in unique_atom_symbols: + atom_i_cnt = atoms_sym_list.count(atom_sym_i) + + atom_dict[atom_sym_i] = atom_i_cnt + + print("THIS HAS BEEN DEPRECATED to create_species_element_dict") + print("THIS HAS BEEN DEPRECATED to create_species_element_dict") + print("THIS HAS BEEN DEPRECATED to create_species_element_dict") + print("THIS HAS BEEN DEPRECATED to create_species_element_dict") + + # return(atom_dict) + #__| + +def create_species_element_dict( + atoms, + include_all_elems=False, + elems_to_always_include=None, + ): + """Create dict from an atoms object with element: element number entries. + + If 'include_all_elems' is True then 'elems_to_always_include' must be None + + Args: + atoms: + include_all_elems: or + False: Does not add additional elements other than the ones + present in the atoms object + + True: Includes all elements in the periodic table, with 0 values + for the elements not present in the atoms object + + elems_to_always_include: + List of elements to include in the final dict, not including + the elements present in the atoms object. + + """ + #| - create_species_element_dict + from misc_modules.misc_methods import merge_two_dicts + + all_elements = list(periodic_table_dict) + + chem_syms = atoms.get_chemical_symbols() + chem_syms_unique = set(chem_syms) + + species_elem_dict = {} + for elem_i in chem_syms_unique: + num_elem_i = chem_syms.count(elem_i) + + species_elem_dict[elem_i] = num_elem_i + + #| - Include All Elements in the periodic table + if include_all_elems or elems_to_always_include is not None: + all_non_occuring_elements = list( + filter( + lambda x: x not in set(list(species_elem_dict)), all_elements + ) + ) +# print(all_non_occuring_elements) + +# if elems_to_always_include is not None: + if elems_to_always_include is not None and type(elems_to_always_include) == list: + non_occuring_elements = [i for i in all_non_occuring_elements if i in elems_to_always_include] + else: + non_occuring_elements = all_non_occuring_elements + + non_occuring_species_elem_dict = dict( + zip( + non_occuring_elements, + [0 for i in non_occuring_elements], + ) + ) + +# non_occuring_species_elem_dict = dict( +# zip( +# all_non_occuring_elements, +# [0 for i in all_non_occuring_elements], +# ) +# ) + + + species_elem_dict = merge_two_dicts( + non_occuring_species_elem_dict, + species_elem_dict, + ) + #__| + + return(species_elem_dict) + #__| + +#__| ************************************************************************** + +#| - Visualization ************************************************************ +def create_gif_from_traj( + traj_name="qn.traj", + path_i=".", + image_range="0:5", # "all" + delay=10, + rotation="0x, 0y, 0z", + ): + """Create gif animation from trajectory file. + + Args: + traj_name: + path_i: + image_range: + delay: + + """ + #| - create_gif_from_traj + + #| - Method Parameters + atoms_file_name = "out_movie" + fold_name = "images" + #__| + + #| - Creating png ********************************************************* + if image_range == "all": + ind_range = ":" + else: + ind_range = image_range + + atoms_traj = io.read(path_i + "/" + traj_name, index=ind_range) + + folder_i = fold_name + if not os.path.isdir(path_i + folder_i): + os.makedirs(path_i + "/" + folder_i) + + for index, atoms_i in enumerate(atoms_traj): + textures = ["simple" for i in range(len(atoms_i))] + + name = "TMP" + name_i = fold_name + "/" + str(index).zfill(3) + "_" + name + "_top" + io.write( + path_i + "/" + name_i + ".pov", + atoms_i, + rotation=rotation, + run_povray=True, + textures=textures, + canvas_height=1000, + display=False + ) + + print("Creating IMAGE: " + path_i + "/" + name_i + ".png") + + os.remove(path_i + "/" + name_i + ".pov") + os.remove(path_i + "/" + name_i + ".ini") + #__| ********************************************************************** + + #| - Converting Images to GIF ********************************************* + root_dir = os.getcwd() + os.chdir(path_i + "/" + fold_name) + + bash_command = "/usr/bin/convert " + bash_command += "-delay " + str(delay) + " " + bash_command += "-loop 0 " + # bash_command += "*png animation.gif" + bash_command += "*png " + atoms_file_name + ".gif" + + print("###### CREATING GIF ####### | " + atoms_file_name) + os.system(bash_command) + os.system("mv *.gif ..") + os.chdir(root_dir) + #__| ********************************************************************** + + #__| + +def create_gif_from_atoms_movies( + atoms_file="Default", + path_i=".", + delay=10, + ): + """Create png images from an multi-atoms atoms object. + + TODO This method is way to specific, should be chopped up + TODO Use create_gif_from_traj method + + Args: + atoms_file: + path_i: + delay: + """ + #| - create_images_from_atoms_movies + + #| - SCRIPT PARAMETERS + fold_name = "images" + #__| + + #| - Read Atoms File with *.traj File Name + + if atoms_file == "Default": + filenames = next(os.walk(path_i))[2] + + traj_files = [fle for fle in filenames if ".traj" in fle] + alist = {} + if len(traj_files) == 1: + atoms_file = traj_files[0] + + atoms_file_path = path_i + "/" + atoms_file + + # alist[atoms_file] = read(atoms_file, index=":") + + else: + pass + + atoms_file_name = copy.deepcopy(atoms_file) + atoms_file_name = atoms_file_name.split(".") + atoms_file_name.remove("traj") + atoms_file_name = ".".join(atoms_file_name) + + alist[atoms_file] = read(atoms_file_path, index=":") + #__| + + folder_i = fold_name + if not os.path.isdir(path_i + folder_i): + os.makedirs(path_i + folder_i) + + for i, file in enumerate(alist): + for index, atoms_i in enumerate(alist[file]): + textures = ["simple" for i in range(len(atoms_i))] + + if "traj" in file: + name = file[0:-5] + elif "xyz" in file: + name = file[0:-4] + elif "POSCAR" in file: + name = file[0:-7] + + name_i = fold_name + "/" + str(index).zfill(2) + "_" + name + "_top" + write( + path_i + "/" + name_i + ".pov", + atoms_i, + # alist[file], + rotation="0x, 0y, 0z", + run_povray=True, + textures=textures, + canvas_height=1000, + display=False + ) + + print("Creating IMAGE: " + path_i + name_i + ".png") + + os.remove(path_i + "/" + name_i + ".pov") + os.remove(path_i + "/" + name_i + ".ini") + + + #| - Converting Images to GIF + root_dir = os.getcwd() + + os.chdir(path_i + "/" + fold_name) + + bash_command = "/usr/bin/convert " + bash_command += "-delay " + str(delay) + " " + bash_command += "-loop 0 " + # bash_command += "*png animation.gif" + bash_command += "*png " + atoms_file_name + ".gif" + + print("###### CREATING GIF ####### | " + atoms_file_name) + os.system(bash_command) + + os.system("mv *.gif ..") + + os.chdir(root_dir) + #__| + + # TODO - Remove png files after creating gif !!!!! + #__| + +#__| ************************************************************************** + +#| - MISC + +def max_force(atoms): + """Return largest force on any atom. + + Args: + atoms: + + """ + #| - max_force + from ase import Atoms + from numpy import ndarray + + if isinstance(atoms, Atoms): + forces = atoms.get_forces() + + elif isinstance(atoms, ndarray): + forces = atoms + + elif isinstance(atoms, list): + forces = np.array(atoms) + + assert len(forces.shape) == 2, "Wrong shape" + assert forces.shape[1] == 3, "Incorrect number of compenents" + + # forces = atoms.get_forces() + + sum = 0.0 + largest = 0.0 + for a in range(len(atoms)): + force = np.sqrt( + forces[a][0] ** 2 + + forces[a][1] ** 2 + + forces[a][2] ** 2 + ) + + sum += force + if(force > largest): + largest = force + + return(largest, sum) + #__| + + + +#__| diff --git a/ase_modules/atoms_wrap.py b/ase_modules/atoms_wrap.py index 55d93e5..26d5790 100644 --- a/ase_modules/atoms_wrap.py +++ b/ase_modules/atoms_wrap.py @@ -1,10 +1,10 @@ -#!/usr/bin/env python - -""" -""" - -def class Atoms_Wrapper(object): - """docstring for [object Object].""" - def __init__(self, arg): - super([object Object], self).__init__() - self.arg = arg +#!/usr/bin/env python + +""" +""" + +def class Atoms_Wrapper(object): + """docstring for [object Object].""" + def __init__(self, arg): + super([object Object], self).__init__() + self.arg = arg diff --git a/ase_modules/dft-params.json b/ase_modules/dft-params.json index 9b06df4..4e54efa 100644 --- a/ase_modules/dft-params.json +++ b/ase_modules/dft-params.json @@ -1,10 +1,10 @@ -{ - "dw": 8000.0, - "kpts": [ - "8", - "8", - "1" - ], - "pw": 800, - "spinpol": true -} +{ + "dw": 8000.0, + "kpts": [ + "8", + "8", + "1" + ], + "pw": 800, + "spinpol": true +} diff --git a/ase_modules/dft_params.py b/ase_modules/dft_params.py index 0d18c89..c0f36c3 100644 --- a/ase_modules/dft_params.py +++ b/ase_modules/dft_params.py @@ -1,554 +1,554 @@ -#!/usr/bin/env python - -"""DFT calculator's default parameters. - -User Notes: - Must set COMPENV environment variable - (actually not a big deal if not using AWS cluster) - -Development Notes: - TODO Automatically scale bands with system size - TODO Call test_check in the write method or something so that I won't have - to call it manually - -""" - -#| - Import Modules -import os -import json - -# My Modules -from dft_job_automat.compute_env import ComputerCluster -#__| - -class DFT_Params: - """Base class for DFT parameters encapsulation.""" - - #| - DFT_Params ************************************************************ - - def __init__(self): - """Initialize base class.""" - #| - __init__ - self.file_name = "dft-params" - self.compute_env = os.environ.get("COMPENV") - - self.submission_params = self.load_submission_params() - #__| - - # def load_submission_params(self, filename=".submission_params.json"): - def load_submission_params(self, filename=".submission_params_2.json"): - """Attempt to load submission parameters from file. - - Args: - filename: - Name of file containing submission parameters in a json - file format. The file is created automatically from my - comp_env module when used in conjuction witht he job - submission script. - """ - #| - load_submission_params - submission_params = None - if os.path.isfile(filename): - with open(filename, "r") as fle: - submission_params = json.load(fle) - - elif os.path.isfile(".submission_params.json"): - with open(filename, "r") as fle: - submission_params = json.load(fle) - else: - print("Couldn't read submission_params file") - - return(submission_params) - #__| - - def load_params(self, dir=".", update_params=True): - """Import JSON file containing parameters in dictionary. - - Args: - dir: - update_params: - """ - #| - load_params - try: - data = open(dir + "/dft-params.json").read() - data = json.loads(data) - - if update_params is True: - self.update_params(data) - else: - self.params = data - - except: - pass - #__| - - def PythonPath(self): - """Return PYTHONPATH system variable_lst. - - Checks dir is checked for default_espresso_params file - """ - #| - PythonPath - pyth_paths = os.environ["PYTHONPATH"].split(os.pathsep) - - - pyth_path = [x for x in pyth_paths if "00_PythonModules" in x] - - #FIX | Assertion breaks whenver .bashrc is source multiple times, b.c. - # redundant paths are duplicated in the PYTHONPATH variable - - # assert len(pyth_path) == 1, "Unique PYTHONPATH dir not found" - - return pyth_path[0] - - #__| - - def update_params(self, new_params, user_update=True): - """Update parameter dict with new keys or new values for old keys. - - Args: - new_params: - user_update: - """ - #| - update_params - self.params.update(new_params) - - if user_update: - mod_d_new = {x: True for x in new_params} - self.mod_dict.update(mod_d_new) - #__| - - def write_params(self, path_i=".", overwrite=False): - """Write parameters to file in getcwd. - - TODO Do not create higher versions _1, _2, _3 if they are identical - - Args: - path: - overwrite:s - """ - #| - write_params - - def json_dump_command(params, file): - #| - json_dump_command - json.dump(params, file, indent=2, skipkeys=True) - #__| - - num_files = [fle for fle in os.listdir(path_i) if "dft-params" in fle] - num_files = len(num_files) - - if overwrite is False: - if not os.path.exists(self.file_name + ".json"): - with open(path_i + "/" + self.file_name + ".json", "w") as fle: - json_dump_command(self.params, fle) - else: - fle_name = path_i + "/" + self.file_name + "_" + \ - str(num_files) + ".json" - with open(fle_name, "w") as fle: - json_dump_command(self.params, fle) - else: - with open(path_i + "/" + self.file_name + ".json", "w+") as fle: - json_dump_command(self.params, fle) - #__| - - #__| *********************************************************************** - -class VASP_Params(DFT_Params): - """Useful method to define VASP parameters for DFT job.""" - - #| - VASP_Params *********************************************************** - def __init__(self, load_defaults=True): - """Class encapsulating VASP job parameters. - - Args: - load_defaults: - """ - #| - __init__ - # self.pymoddir = self.PythonPath() - DFT_Params.__init__(self) - - if load_defaults: - self.params = self.default_params() - else: - self.params = {} - - self.mod_dict = self.create_mod_dict() - - # self.params = self.load_params(self.pymoddir, - # "default_espresso_params.json") - #__| - - def default_params(self): - """User-defined default DFT parameters.""" - #| - default_params - - # Do calculation - my_encut = 500 - my_enaug = 750 - my_kpts = (1, 1, 1) - my_ediff = 0.00001 - my_nsw = 200 # 0 for ASE, > 0 for VASP internal - my_prec = "Normal" # "Normal" or "Accurate" - my_istart = 0 # 0 = new job, 1: - my_npar = 4 - my_ibrion = 1 # RMM-DIIS - my_isif = 2 - my_fmax = -0.001 # ev/ang, tighter converergence - my_ispin = 2 - - params = {} - - params["ivdw"] = 0 - # params["ivdw"] = 12 - - # Dipole Correction - params["ldipol"] = False - # params["idipol"] = 4 - # params[dipol] = [0.5, 0.5, 0,5] # Center of cell - - params["kpts"] = my_kpts - params["encut"] = my_encut - params["enaug"] = my_enaug - - params["ispin"] = my_ispin - params["nsw"] = my_nsw - params["prec"] = my_prec - params["istart"] = my_istart - params["isif"] = my_isif - - # IBRION - params["ibrion"] = my_ibrion - # - - params["ismear"] = 0 - params["sigma"] = 0.05 - - params["icharg"] = 2 - params["lasph"] = True - params["voskown"] = 1 - params["algo"] = "Normal" - params["lreal"] = False - - # convergence Parameters - params["ediff"] = my_ediff - params["ediffg"] = my_fmax - - # Bader Charge Analysis - params["laechg"] = False - - # Output Options - params["nwrite"] = 1 - params["lcharg"] = True - params["lwave"] = False - - # Symmetry - params["isym"] = 0 - - # Functional Type - - # Different VASP versions use 'pbe' vs 'PBE' - if self.compute_env == "aws": - pbe_val = "pbe" - elif self.compute_env == "slac": - pbe_val = "PBE" - else: - pbe_val = "PBE" - # print(pbe_val) # TEMP_PRINT - params["xc"] = pbe_val # TEMP - params["gga"] = " PE" # sets the PBE functional - - # Compuational Parameters - params["npar"] = my_npar - params["nsim"] = 1 - params["nelmin"] = 4 - params["nelm"] = 100 - params["lplane"] = True - - # Dielectric Matrix density functional perturbation theory - params["lepsilon"] = False - - return(params) - #__| - - def create_mod_dict(self): - """ - Create modification book-keepig dictionary. - - Dictionary which keeps track of whether parameter has been updated - externally in script or if it kept at its default value. - This is useful to know for the dependent-parameters. - """ - #| - create_mod_dict - param_keys = list(self.params.keys()) - mod_dict = dict((key, False) for key in param_keys) - - return(mod_dict) - #__| - - - #__| *********************************************************************** - -class Espresso_Params(DFT_Params): - """Useful method to define quantum espresso parameters for DFT job.""" - - #| - Espresso_Params ******************************************************* - def __init__(self, load_defaults=True): - """Class encapsulating quantum espresso job parameters. - - Args: - load_defaults: - """ - #| - __init__ - DFT_Params.__init__(self) - - if load_defaults: - self.params = self.default_params() - else: - self.params = {} - - self.mod_dict = self.create_mod_dict() - #__| - - def default_params(self): # ********************************************** - """User-defined default DFT parameters.""" - #| - default_params - params = {} - - params["pw"] = 500 # plane-wave cutoff - params["dw"] = 5000 # density cutoff - params["dipole"] = {"status": True} # Turn on only for slabs not bulk - params["xc"] = "BEEF-vdW" # exchange-correlation functional - params["kpts"] = (3, 3, 1) # k-points for hexagonal symm in 2-D mater - - # TODO Scale number of bands with system size - params["nbands"] = -50 - - #| - Spin & Magnitism - # Spin-polarized calculation - params["spinpol"] = False - - # Non-collinear magnetism, magnetization in generic direction - params["noncollinear"] = False - #__| - - params["sigma"] = 0.1 # Should be low for spin calculations - - params["beefensemble"] = True - - # Parallelization <---------------------------------------------------- - params["parflags"] = None - - #| - Convergence Parameters - params["convergence"] = { - "energy": 1e-5, # convergence parameters - - # TF (Normal) or local-TF (Better for inhomogeneous systems) - "mixing_mode": "local-TF", - "mixing": 0.2, - "nmix": 20, # num of iter used in mixing scheme (Default 8) - "maxsteps": 500, - "diag": "david", - } - #__| - - #| - File Output <----------------------------------------------------- - params["output"] = { - "avoidio": True, - "removesave": True, - "removewf": True, - "wf_collect": False, - } - - params["outdir"] = "calcdir" - #__| - - return(params) - #__| - - def create_mod_dict(self): - """Create modification book-keepig dictionary. - - Dictionary which keeps track of whether parameter has been updated - externally in script or if it kept at its default value. - This is useful to know for the dependent-parameters. - """ - #| - create_mod_dict - param_keys = list(self.params.keys()) - mod_dict = dict((key, False) for key in param_keys) - - return(mod_dict) - #__| - - def test_check(self): - """Attempts to set params based on other dependent parameters. - - Ex.) If spinpol == True, then sigma should be smaller, 0.01ish - (Charlotte told me) - - Only set this dependent param if the user has not explicitly done so, - is what the condition for setting a parameter automatically is. - """ - #| - test_check - - #| - Setting dw to 10 * pw - if self.mod_dict["dw"] is False: - dw_i = 10. * self.params["pw"] - self.update_params({"dw": dw_i}, user_update=False) - #__| - - #| - Decreasing Sigma for Spin Polarization Calculations - if self.mod_dict["sigma"] is False: - if self.params["spinpol"] is True: - sigma_i = 0.02 - self.update_params({"sigma": sigma_i}, user_update=False) - #__| - - #| - BEEF Ensemble of Energies ========================================= - - #| - Removing Beef-Ensemble if XC-Functional Not BEEF - xc_list = self.params["xc"] - if "beefensemble" in self.params: - if self.params["beefensemble"] is True and "BEEF" not in xc_list: - print("Functional not compatible with BEEF-ensemble method") - self.update_params({"beefensemble": False}, user_update=False) - self.update_params({"printensemble": False}, user_update=False) - else: - pass - #__| - - #| - Turn on printensemble Parameter for BEEF Ensemble of Energies - xc_list = self.params["xc"] - if "beefensemble" in self.params: - if self.params["beefensemble"] is True and "BEEF" in xc_list: - print("Espresso_Params | " - "test_check | Turning on printensemble" - ) - self.update_params({"printensemble": True}, user_update=False) - else: - pass - - #__| - - #| - Turn off BEEF on AWS - # NOTE This is new (180412 - RF), check that it works - CC = ComputerCluster() - if CC.cluster_sys == "aws": - if "beefensemble" in self.params: - if self.params["beefensemble"] is True: - print("Espresso_Params | " - "test_check | Attempting to use BEEF ensemble on AWS, " - "which doesn't support it at this time, " - "BEEF ensemble tags will be turned off" - ) - - self.update_params({ - "beefensemble": False}, - user_update=False, - ) - - self.update_params({ - "printensemble": False}, - user_update=False, - ) - - #__| - - #__| ================================================================== - - #| - Parallelization - if self.mod_dict["parflags"] is False: - if type(self.submission_params) == dict: - if "nodes" in self.submission_params: - num_nodes = self.submission_params["nodes"] - - self.update_params( - {"parflags": "-npool " + str(int(num_nodes))}, - user_update=False, - ) - - # TEMP_PRINT - print("098sddfkfs--s-s-__-_") - print("-npool " + str(int(num_nodes))) - #__| - - #__| - - #__| ********************************************************************** - - - - - -#| - __old__ | default_params with all the commented lines -# params = {} -# -# # params["mode"] = "ase3" -# # params["opt_algorithm"] = "bfgs" -# # params["cell_dynamics"] = "bfgs" -# -# params["pw"] = 500 # plane-wave cutoff -# params["dw"] = 5000 # density cutoff -# params["dipole"] = {"status": True} # Turn on only for slabs not bulk -# params["xc"] = "BEEF-vdW" # exchange-correlation functional -# params["kpts"] = (3, 3, 1) # k-points for hexagonal symm in 2-D mater -# -# # TODO Scale number of bands with system size -# params["nbands"] = -50 -# -# #| - Spin & Magnitism -# # Spin-polarized calculation -# params["spinpol"] = False -# -# # Non-collinear magnetism, magnetization in generic direction -# params["noncollinear"] = False -# #__| -# -# params["sigma"] = 0.1 # Should be low for spin calculations -# -# # pseudopotential path -# # params["psppath"] = "/home/vossj/suncat/psp/gbrv1.5pbe/" -# -# params["beefensemble"] = True -# -# # Parallelization <---------------------------------------------------- -# # params["parflags"] = "-npool " -# params["parflags"] = None -# -# #| - Convergence Parameters -# params["convergence"] = { -# "energy": 1e-5, # convergence parameters -# -# # TF (Normal) or local-TF (Better for inhomogeneous systems) -# "mixing_mode": "local-TF", -# "mixing": 0.2, -# "nmix": 20, # num of iter used in mixing scheme (Default 8) -# "maxsteps": 500, -# "diag": "david", -# } -# #__| -# -# #| - File Output <----------------------------------------------------- -# -# # output = {'disk_io':'default', # how often espresso writes wavefunctions to disk -# # 'avoidio':False, # will overwrite disk_io parameter if True -# # 'removewf':True, -# # 'removesave':False, -# # 'wf_collect':False}, -# -# -# # params["output"] = {"removesave": True} # Aayush, saves ~nothing -# params["output"] = { -# -# # "avoidio": False, -# # "removesave": False, -# # "removewf": False, -# # "wf_collect": False, -# -# "avoidio": True, -# "removesave": True, -# "removewf": True, -# "wf_collect": False, -# } -# -# params["outdir"] = "calcdir" -# return(params) -#__| +#!/usr/bin/env python + +"""DFT calculator's default parameters. + +User Notes: + Must set COMPENV environment variable + (actually not a big deal if not using AWS cluster) + +Development Notes: + TODO Automatically scale bands with system size + TODO Call test_check in the write method or something so that I won't have + to call it manually + +""" + +#| - Import Modules +import os +import json + +# My Modules +from dft_job_automat.compute_env import ComputerCluster +#__| + +class DFT_Params: + """Base class for DFT parameters encapsulation.""" + + #| - DFT_Params ************************************************************ + + def __init__(self): + """Initialize base class.""" + #| - __init__ + self.file_name = "dft-params" + self.compute_env = os.environ.get("COMPENV") + + self.submission_params = self.load_submission_params() + #__| + + # def load_submission_params(self, filename=".submission_params.json"): + def load_submission_params(self, filename=".submission_params_2.json"): + """Attempt to load submission parameters from file. + + Args: + filename: + Name of file containing submission parameters in a json + file format. The file is created automatically from my + comp_env module when used in conjuction witht he job + submission script. + """ + #| - load_submission_params + submission_params = None + if os.path.isfile(filename): + with open(filename, "r") as fle: + submission_params = json.load(fle) + + elif os.path.isfile(".submission_params.json"): + with open(filename, "r") as fle: + submission_params = json.load(fle) + else: + print("Couldn't read submission_params file") + + return(submission_params) + #__| + + def load_params(self, dir=".", update_params=True): + """Import JSON file containing parameters in dictionary. + + Args: + dir: + update_params: + """ + #| - load_params + try: + data = open(dir + "/dft-params.json").read() + data = json.loads(data) + + if update_params is True: + self.update_params(data) + else: + self.params = data + + except: + pass + #__| + + def PythonPath(self): + """Return PYTHONPATH system variable_lst. + + Checks dir is checked for default_espresso_params file + """ + #| - PythonPath + pyth_paths = os.environ["PYTHONPATH"].split(os.pathsep) + + + pyth_path = [x for x in pyth_paths if "00_PythonModules" in x] + + #FIX | Assertion breaks whenver .bashrc is source multiple times, b.c. + # redundant paths are duplicated in the PYTHONPATH variable + + # assert len(pyth_path) == 1, "Unique PYTHONPATH dir not found" + + return pyth_path[0] + + #__| + + def update_params(self, new_params, user_update=True): + """Update parameter dict with new keys or new values for old keys. + + Args: + new_params: + user_update: + """ + #| - update_params + self.params.update(new_params) + + if user_update: + mod_d_new = {x: True for x in new_params} + self.mod_dict.update(mod_d_new) + #__| + + def write_params(self, path_i=".", overwrite=False): + """Write parameters to file in getcwd. + + TODO Do not create higher versions _1, _2, _3 if they are identical + + Args: + path: + overwrite:s + """ + #| - write_params + + def json_dump_command(params, file): + #| - json_dump_command + json.dump(params, file, indent=2, skipkeys=True) + #__| + + num_files = [fle for fle in os.listdir(path_i) if "dft-params" in fle] + num_files = len(num_files) + + if overwrite is False: + if not os.path.exists(self.file_name + ".json"): + with open(path_i + "/" + self.file_name + ".json", "w") as fle: + json_dump_command(self.params, fle) + else: + fle_name = path_i + "/" + self.file_name + "_" + \ + str(num_files) + ".json" + with open(fle_name, "w") as fle: + json_dump_command(self.params, fle) + else: + with open(path_i + "/" + self.file_name + ".json", "w+") as fle: + json_dump_command(self.params, fle) + #__| + + #__| *********************************************************************** + +class VASP_Params(DFT_Params): + """Useful method to define VASP parameters for DFT job.""" + + #| - VASP_Params *********************************************************** + def __init__(self, load_defaults=True): + """Class encapsulating VASP job parameters. + + Args: + load_defaults: + """ + #| - __init__ + # self.pymoddir = self.PythonPath() + DFT_Params.__init__(self) + + if load_defaults: + self.params = self.default_params() + else: + self.params = {} + + self.mod_dict = self.create_mod_dict() + + # self.params = self.load_params(self.pymoddir, + # "default_espresso_params.json") + #__| + + def default_params(self): + """User-defined default DFT parameters.""" + #| - default_params + + # Do calculation + my_encut = 500 + my_enaug = 750 + my_kpts = (1, 1, 1) + my_ediff = 0.00001 + my_nsw = 200 # 0 for ASE, > 0 for VASP internal + my_prec = "Normal" # "Normal" or "Accurate" + my_istart = 0 # 0 = new job, 1: + my_npar = 4 + my_ibrion = 1 # RMM-DIIS + my_isif = 2 + my_fmax = -0.001 # ev/ang, tighter converergence + my_ispin = 2 + + params = {} + + params["ivdw"] = 0 + # params["ivdw"] = 12 + + # Dipole Correction + params["ldipol"] = False + # params["idipol"] = 4 + # params[dipol] = [0.5, 0.5, 0,5] # Center of cell + + params["kpts"] = my_kpts + params["encut"] = my_encut + params["enaug"] = my_enaug + + params["ispin"] = my_ispin + params["nsw"] = my_nsw + params["prec"] = my_prec + params["istart"] = my_istart + params["isif"] = my_isif + + # IBRION + params["ibrion"] = my_ibrion + # + + params["ismear"] = 0 + params["sigma"] = 0.05 + + params["icharg"] = 2 + params["lasph"] = True + params["voskown"] = 1 + params["algo"] = "Normal" + params["lreal"] = False + + # convergence Parameters + params["ediff"] = my_ediff + params["ediffg"] = my_fmax + + # Bader Charge Analysis + params["laechg"] = False + + # Output Options + params["nwrite"] = 1 + params["lcharg"] = True + params["lwave"] = False + + # Symmetry + params["isym"] = 0 + + # Functional Type + + # Different VASP versions use 'pbe' vs 'PBE' + if self.compute_env == "aws": + pbe_val = "pbe" + elif self.compute_env == "slac": + pbe_val = "PBE" + else: + pbe_val = "PBE" + # print(pbe_val) # TEMP_PRINT + params["xc"] = pbe_val # TEMP + params["gga"] = " PE" # sets the PBE functional + + # Compuational Parameters + params["npar"] = my_npar + params["nsim"] = 1 + params["nelmin"] = 4 + params["nelm"] = 100 + params["lplane"] = True + + # Dielectric Matrix density functional perturbation theory + params["lepsilon"] = False + + return(params) + #__| + + def create_mod_dict(self): + """ + Create modification book-keepig dictionary. + + Dictionary which keeps track of whether parameter has been updated + externally in script or if it kept at its default value. + This is useful to know for the dependent-parameters. + """ + #| - create_mod_dict + param_keys = list(self.params.keys()) + mod_dict = dict((key, False) for key in param_keys) + + return(mod_dict) + #__| + + + #__| *********************************************************************** + +class Espresso_Params(DFT_Params): + """Useful method to define quantum espresso parameters for DFT job.""" + + #| - Espresso_Params ******************************************************* + def __init__(self, load_defaults=True): + """Class encapsulating quantum espresso job parameters. + + Args: + load_defaults: + """ + #| - __init__ + DFT_Params.__init__(self) + + if load_defaults: + self.params = self.default_params() + else: + self.params = {} + + self.mod_dict = self.create_mod_dict() + #__| + + def default_params(self): # ********************************************** + """User-defined default DFT parameters.""" + #| - default_params + params = {} + + params["pw"] = 500 # plane-wave cutoff + params["dw"] = 5000 # density cutoff + params["dipole"] = {"status": True} # Turn on only for slabs not bulk + params["xc"] = "BEEF-vdW" # exchange-correlation functional + params["kpts"] = (3, 3, 1) # k-points for hexagonal symm in 2-D mater + + # TODO Scale number of bands with system size + params["nbands"] = -50 + + #| - Spin & Magnitism + # Spin-polarized calculation + params["spinpol"] = False + + # Non-collinear magnetism, magnetization in generic direction + params["noncollinear"] = False + #__| + + params["sigma"] = 0.1 # Should be low for spin calculations + + params["beefensemble"] = True + + # Parallelization <---------------------------------------------------- + params["parflags"] = None + + #| - Convergence Parameters + params["convergence"] = { + "energy": 1e-5, # convergence parameters + + # TF (Normal) or local-TF (Better for inhomogeneous systems) + "mixing_mode": "local-TF", + "mixing": 0.2, + "nmix": 20, # num of iter used in mixing scheme (Default 8) + "maxsteps": 500, + "diag": "david", + } + #__| + + #| - File Output <----------------------------------------------------- + params["output"] = { + "avoidio": True, + "removesave": True, + "removewf": True, + "wf_collect": False, + } + + params["outdir"] = "calcdir" + #__| + + return(params) + #__| + + def create_mod_dict(self): + """Create modification book-keepig dictionary. + + Dictionary which keeps track of whether parameter has been updated + externally in script or if it kept at its default value. + This is useful to know for the dependent-parameters. + """ + #| - create_mod_dict + param_keys = list(self.params.keys()) + mod_dict = dict((key, False) for key in param_keys) + + return(mod_dict) + #__| + + def test_check(self): + """Attempts to set params based on other dependent parameters. + + Ex.) If spinpol == True, then sigma should be smaller, 0.01ish + (Charlotte told me) + + Only set this dependent param if the user has not explicitly done so, + is what the condition for setting a parameter automatically is. + """ + #| - test_check + + #| - Setting dw to 10 * pw + if self.mod_dict["dw"] is False: + dw_i = 10. * self.params["pw"] + self.update_params({"dw": dw_i}, user_update=False) + #__| + + #| - Decreasing Sigma for Spin Polarization Calculations + if self.mod_dict["sigma"] is False: + if self.params["spinpol"] is True: + sigma_i = 0.02 + self.update_params({"sigma": sigma_i}, user_update=False) + #__| + + #| - BEEF Ensemble of Energies ========================================= + + #| - Removing Beef-Ensemble if XC-Functional Not BEEF + xc_list = self.params["xc"] + if "beefensemble" in self.params: + if self.params["beefensemble"] is True and "BEEF" not in xc_list: + print("Functional not compatible with BEEF-ensemble method") + self.update_params({"beefensemble": False}, user_update=False) + self.update_params({"printensemble": False}, user_update=False) + else: + pass + #__| + + #| - Turn on printensemble Parameter for BEEF Ensemble of Energies + xc_list = self.params["xc"] + if "beefensemble" in self.params: + if self.params["beefensemble"] is True and "BEEF" in xc_list: + print("Espresso_Params | " + "test_check | Turning on printensemble" + ) + self.update_params({"printensemble": True}, user_update=False) + else: + pass + + #__| + + #| - Turn off BEEF on AWS + # NOTE This is new (180412 - RF), check that it works + CC = ComputerCluster() + if CC.cluster_sys == "aws": + if "beefensemble" in self.params: + if self.params["beefensemble"] is True: + print("Espresso_Params | " + "test_check | Attempting to use BEEF ensemble on AWS, " + "which doesn't support it at this time, " + "BEEF ensemble tags will be turned off" + ) + + self.update_params({ + "beefensemble": False}, + user_update=False, + ) + + self.update_params({ + "printensemble": False}, + user_update=False, + ) + + #__| + + #__| ================================================================== + + #| - Parallelization + if self.mod_dict["parflags"] is False: + if type(self.submission_params) == dict: + if "nodes" in self.submission_params: + num_nodes = self.submission_params["nodes"] + + self.update_params( + {"parflags": "-npool " + str(int(num_nodes))}, + user_update=False, + ) + + # TEMP_PRINT + print("098sddfkfs--s-s-__-_") + print("-npool " + str(int(num_nodes))) + #__| + + #__| + + #__| ********************************************************************** + + + + + +#| - __old__ | default_params with all the commented lines +# params = {} +# +# # params["mode"] = "ase3" +# # params["opt_algorithm"] = "bfgs" +# # params["cell_dynamics"] = "bfgs" +# +# params["pw"] = 500 # plane-wave cutoff +# params["dw"] = 5000 # density cutoff +# params["dipole"] = {"status": True} # Turn on only for slabs not bulk +# params["xc"] = "BEEF-vdW" # exchange-correlation functional +# params["kpts"] = (3, 3, 1) # k-points for hexagonal symm in 2-D mater +# +# # TODO Scale number of bands with system size +# params["nbands"] = -50 +# +# #| - Spin & Magnitism +# # Spin-polarized calculation +# params["spinpol"] = False +# +# # Non-collinear magnetism, magnetization in generic direction +# params["noncollinear"] = False +# #__| +# +# params["sigma"] = 0.1 # Should be low for spin calculations +# +# # pseudopotential path +# # params["psppath"] = "/home/vossj/suncat/psp/gbrv1.5pbe/" +# +# params["beefensemble"] = True +# +# # Parallelization <---------------------------------------------------- +# # params["parflags"] = "-npool " +# params["parflags"] = None +# +# #| - Convergence Parameters +# params["convergence"] = { +# "energy": 1e-5, # convergence parameters +# +# # TF (Normal) or local-TF (Better for inhomogeneous systems) +# "mixing_mode": "local-TF", +# "mixing": 0.2, +# "nmix": 20, # num of iter used in mixing scheme (Default 8) +# "maxsteps": 500, +# "diag": "david", +# } +# #__| +# +# #| - File Output <----------------------------------------------------- +# +# # output = {'disk_io':'default', # how often espresso writes wavefunctions to disk +# # 'avoidio':False, # will overwrite disk_io parameter if True +# # 'removewf':True, +# # 'removesave':False, +# # 'wf_collect':False}, +# +# +# # params["output"] = {"removesave": True} # Aayush, saves ~nothing +# params["output"] = { +# +# # "avoidio": False, +# # "removesave": False, +# # "removewf": False, +# # "wf_collect": False, +# +# "avoidio": True, +# "removesave": True, +# "removewf": True, +# "wf_collect": False, +# } +# +# params["outdir"] = "calcdir" +# return(params) +#__| diff --git a/ase_modules/get_G.py b/ase_modules/get_G.py index cbe903c..9364c40 100644 --- a/ase_modules/get_G.py +++ b/ase_modules/get_G.py @@ -1,802 +1,802 @@ -#!/usr/bin/env python - -""" -Author(s): Colin Dickens - -TODO - continue to test - add reaction printing to __repr__ - add potential/pressure/temperature dependence to __repr__ - add optional keyword arguments to command line interface for setting potential/pressure/temperature - add Sr, Ru references -""" - -#| - Import Modules -import os - -import glob -import filecmp - -import numpy as np - -from ase.atoms import Atoms -from ase.io import read -#__| - -class Get_G: - """ - Class that automatically calculates standard change in free energy between two states by referencing any atoms - missing between them to a number of gas-phase or aqueous references - """ - - #| - Get_G - def __init__(self, - slab, - ads, - default_vib_bool=True, - get_E=False, - index=-1, - quiet=False, - ): - """ - Get_G(ads,slab) where ads/slab are either paths to traj files or paths to directory containing traj files that have energy and forces. - The directories that contain these traj files must also contain a calculation directory with pw.inp. - """ - #| - __init__ - self.default_vib_bool = default_vib_bool - self.get_E = get_E - self.quiet = quiet - - if type(slab) == str: - self.ads_atoms = self.read_atoms(ads,index=index) - self.slab_atoms = self.read_atoms(slab,index=index) - - elif isinstance(slab, Atoms): - - self.slab_atoms = slab - self.ads_atoms = ads - - - # RF | 181106 - # self.update_params(self.ads_atoms) - # self.update_params(self.slab_atoms) - # - # if self.ads_atoms.PARAMS != self.slab_atoms.PARAMS: - # - # print("%s:"%slab) - # print(self.slab_atoms.PARAMS) - # print("%s:"%ads) - # print(self.ads_atoms.PARAMS) - # - # # print "%s:"%slab - # # print self.slab_atoms.PARAMS - # # print "%s:"%ads - # # print self.ads_atoms.PARAMS - # - # for param in ('dw','pp','pw','xc'): - # if self.ads_atoms.PARAMS[param] != self.slab_atoms.PARAMS[param]: - # raise Exception("Calculations performed with different parameters") - # else: - # print("WARNING, ONE CALCULATION IS SPIN-POLARIZED") - - self.update_delta_atoms() - self.vib_correction() - self.set_refs() - - # RF | 181106 - # if self.slab_atoms.PARAMS['sp']: - # self.compare_magmoms() - - # self.calc_G() - # self.compare_wf() - #__| - - def read_atoms(self,path,**kwargs): - """ - Loads traj file. Path must be direct path to traj files or paths to directory containing them named as either qn.traj or qnXX.traj. - """ - #| - read_atoms - if path.find('traj') != -1: #Checks if directory or filename has been specified - atoms = read(path) - if '/' in path: - atoms.PATH = '/'.join(path.split('/')[:-1]) - else: - atoms.PATH = '.' - else: - files = glob.glob(path + '/qn*.traj') - qn = -1 - for file in files: - file = file.split('/')[-1] - if len(file.split(".")[0]) == 2: #qn.traj - atoms_path = path + '/qn.traj' - elif int(file.split('.')[0][2:]) > qn: #qnXX.traj - qn = int(file.split('.')[0][2:]) - atoms_path = path + '/qn%i.traj'%qn - try: - atoms = read(atoms_path, **kwargs) - atoms.PATH = path - except NameError: - raise IOError("Could not find traj file associate with " + path) - if self.fmax(atoms) > 0.05: - print("WARNING: fmax = %.2f for atoms in %s"%(self.fmax(atoms),atoms.PATH)) - return atoms - #__| - - def update_params(self,atoms): - """ - Takes atoms object containing PATH attribute and adds PARAMS dict as attribute with keys pw, dw, xc, pp. - Assumes PATH contains outdir or calcdir with pw.inp - """ - #| - update_params - if os.path.isdir(atoms.PATH + '/outdir'): - calcdir = atoms.PATH + '/outdir' - elif os.path.isdir(atoms.PATH + '/calcdir'): - calcdir = atoms.PATH + '/calcdir' - else: - raise IOError('Cannot find calculation directory (outdir or calcdir) for ' + atoms.PATH) - - file = open(calcdir + '/pw.inp') - lines = file.readlines() - file.close() - - self.params = {} - self.params['sp'] = False - - for line in lines: - if line[2:9] == 'ecutwfc': - self.params['pw'] = int(float(line.split('=')[-1][:-4])*rydberg) - if line[2:9] == 'ecutrho': - self.params['dw'] = int(float(line.split('=')[-1][:-4])*rydberg) - if line[2:11] == 'input_dft': - self.params['xc'] = line.split('=')[-1][1:-3] - if line[2:12] == 'pseudo_dir': - self.params['pp'] = line.split('=')[-1][1:-3] - if line[2:8] == 'nspin=': - self.params['sp'] = True - - - for key in synonyms: - if self.params[key] in synonyms[key]: - self.params[key] = synonyms[key][self.params[key]] - - atoms.PARAMS = self.params - #__| - - def update_delta_atoms(self): - """ - Update dictionary self.data_atoms with difference in chemical formulas between ads and slab. - Positive numbers represent species that ads has and slab doesn't. - """ - #| - update_delta_atoms - self.delta_atoms = {} - ads_syms = self.ads_atoms.get_chemical_symbols() - slab_syms = self.slab_atoms.get_chemical_symbols() - ads_dict = {} - slab_dict = {} - - for sym in ads_syms: - if sym in ads_dict: - ads_dict[sym] += 1 - else: - ads_dict[sym] = 1 - - for sym in slab_syms: - if sym in slab_dict: - slab_dict[sym] += 1 - else: - slab_dict[sym] = 1 - - for sym in ads_dict: - try: - self.delta_atoms[sym] = ads_dict[sym] - slab_dict[sym] - except KeyError: #no sym in slab_dict - self.delta_atoms[sym] = ads_dict[sym] - - for sym in slab_dict: - if sym not in self.delta_atoms: - self.delta_atoms[sym] = -slab_dict[sym] - - print(self.delta_atoms) - print("LKSDJFKLDJS_------_-_-__----") - - # for key in self.delta_atoms.keys(): - for key in list(self.delta_atoms): - if self.delta_atoms[key] == 0: - del self.delta_atoms[key] - #__| - - def vib_correction(self): - """ - Attempt to add explicitly calculated vibrational correction from vib directory within PATH of ads_atoms and slab_atoms. - Otherwise, default vibrational corrections are used by calling default_vib() - """ - #| - vib_correction - - def vib_indices(atoms): - """ - Return a dict with symbol/count key/value pairs given an atoms object with PATH attribute - """ - #| - vib_indices - dict = {} - - vib_pkls = glob.glob(atoms.PATH + '/vib/vib.*.pckl') - indices = [] - for vib_pkl in vib_pkls: - if vib_pkl != atoms.PATH + '/vib/vib.eq.pckl': - i = vib_pkl.split('/')[-1].split('.')[1][:-2] - if int(i) not in indices: - indices.append(int(i)) - - for index in indices: - sym = atoms[index].symbol - if sym in dict: - dict[sym] +=1 - else: - dict[sym] = 1 - - return dict - #__| - - def parse_corr(path): - """ - Return vibrational correction from myjob.out in path. Return -1 if myjob.out cannot be read (imag freqs?) - """ - #| - parse_corr - file = open(path) - lines = file.readlines() - file.close() - for line in lines: - if len(line.split()) > 1: - if line.split()[0] == 'G' or line.split()[0] == 'F': - corr = float(line.split()[1]) - return corr - return -1 - - """ - try: - try: - corr = float([item for item in [line for line in lines if 'G' in line][0].split(' ') if item.strip()][1]) - return corr - except: - corr = float([item for item in [line for line in lines if 'F' in line][0].split(' ') if item.strip()][1]) - return corr - except: - return -1 - """ - #__| - - if self.get_E: - self.ads_corr = 0 - self.slab_corr = 0 - return - - if self.default_vib_bool: - self.default_vib() - return - - ads_dict = vib_indices(self.ads_atoms) - slab_dict = vib_indices(self.slab_atoms) - - self.delta_vib = {} - - for sym in ads_dict: - try: - self.delta_vib[sym] = ads_dict[sym] - slab_dict[sym] - except KeyError: #no sym in slab_dict - self.delta_vib[sym] = ads_dict[sym] - - for sym in slab_dict: - if sym not in self.delta_vib: - self.delta_vib[sym] = -slab_dict[sym] - - for sym in self.delta_vib.keys(): - if self.delta_vib[sym] == 0: - del self.delta_vib[sym] - - - if self.delta_vib == self.delta_atoms: #explicit vibrational corrections appear valid - if ads_dict != {}: - self.ads_corr = parse_corr(self.ads_atoms.PATH + '/vib/myjob.out') - if self.ads_corr == -1: - print("Correct number of vibrational modes, but cannot read myjob.out (imag freqs?)") - self.default_vib() - return - else: - self.ads_corr = 0 - - if slab_dict != {}: - self.slab_corr = parse_corr(self.slab_atoms.PATH + '/vib/myjob.out') - if self.slab_corr == -1: - print("Correct number of vibrational modes, but cannot read myjob.out (imag freqs?)") - self.default_vib() - return - else: - self.slab_corr = 0 - else: - self.default_vib() - return - #__| - - def default_vib(self): - """ - Calculate vibrational corrections using estimates based on atom identity. - """ - #| - default_vib - self.default_vib_bool = True - self.ads_corr = 0 - self.slab_corr = 0 - for sym in self.delta_atoms: - if self.delta_atoms[sym] > 0: - self.ads_corr += default_vib_dict[sym]*self.delta_atoms[sym] - else: - self.slab_corr -= default_vib_dict[sym]*self.delta_atoms[sym] - #__| - - def set_refs(self): - """ - Formulate references for atoms in self.delta_atoms. Currently chooses reference indicated as default. - """ - #| - set_refs - self.references = {} - for sym in self.delta_atoms: - for atom in references: - if atom == sym: - for ref in references[atom]: - if len(references[atom][ref]) == 3: #use default reference - self.references[sym] = references[atom][ref][:2] - #__| - - def calc_G(self): - """ - Perform free energy calculation at standard conditions and record thermodynamic dependencies on pressure, tempreature, potential, etc. - """ - #| - calc_G - self.G_std = self.ads_atoms.get_potential_energy() - self.slab_atoms.get_potential_energy() - self.G_std += self.ads_corr - self.slab_corr - self.G_thermo = {} - for sym in self.delta_atoms: - for DFT_ref in self.references[sym][0]: - n = DFT_ref[1] - DFT_G = self.get_DFT_ref(DFT_ref[0]) - self.G_std -= self.delta_atoms[sym]*DFT_G*n - for thermo,n in self.references[sym][1]: - if thermo in self.G_thermo: - self.G_thermo[thermo] -= n*self.delta_atoms[sym] - else: - self.G_thermo[thermo] = -n*self.delta_atoms[sym] - #__| - - def get_DFT_ref(self,ref): - """ - Pull appropriate DFT reference energy from database according to computational parameters - """ - #| - get_DFT_ref - xc = self.params['xc'] - pwdw =(self.params['pw'],self.params['dw']) - pp = self.params['pp'] - - if self.get_E: - DFT_references = DFT_E_references - else: - DFT_references = DFT_G_references - - if xc in DFT_references[ref]: - if pwdw in DFT_references[ref][xc]: - if pp in DFT_references[ref][xc][pwdw]: - return DFT_references[ref][xc][pwdw][pp] - else: - for pp_ref in DFT_references[ref][xc][pwdw]: - if self.compare_pp(pp,pp_ref,DFT_references[ref]['syms']): - return DFT_references[ref][xc][pwdw][pp_ref] - - raise Exception("No reference found for %s with %s @ %s with %s"%(ref,xc,pwdw,pp)) - #__| - - def compare_pp(self,pp1,pp2,syms): - """ - """ - #| - compare_pp - for sym in syms: - if not filecmp.cmp("%s/%s.UPF"%(pp1,sym),"%s/%s.UPF"%(pp2,sym)): - return False - return True - #__| - - def fmax(self,atoms): - """ - """ - #| - fmax - forces = atoms.get_forces() - max = 0 - for force in forces: - tot = (force[0]**2 + force[1]**2 + force[2]**2)**0.5 - if tot > max: - max = tot - return max - #__| - - def compare_magmoms(self): - """ - """ - #| - compare_magmoms - def nearest_atom(atoms,position): - "Returns atom nearest to position" - position = np.array(position) - dist_list = [] - for atom in atoms: - dist = np.linalg.norm(position - atom.position) - dist_list.append(dist) - - return atoms[np.argmin(dist_list)] - - if len(self.ads_atoms) >= len(self.slab_atoms): - ads = self.ads_atoms - slab = self.slab_atoms - indexed_by = "slab" - not_indexed_by = "ads" - else: - slab = self.ads_atoms - ads = self.slab_atoms - indexed_by = "ads" - not_indexed_by = "slab" - - delta_magmoms = [] - ads_indices_used = [] - for atom in slab: - ads_atom = nearest_atom(ads,atom.position) - if not self.quiet: - if ads_atom.symbol != atom.symbol: print("WARNING! MAGMOM COMPARISON FAILURE") - ads_indices_used.append(ads_atom.index) - delta_magmoms.append(atom.magmom - ads_atom.magmom) - - ads_indices_not_used = [] - for i in range(len(ads)): - if i not in ads_indices_used: - ads_indices_not_used.append(i) - - # RF | 181106 - # self.delta_magmoms = zip(range(len(slab)), delta_magmoms) - self.delta_magmoms = list(zip(range(len(slab)), delta_magmoms)) - self.delta_magmoms.sort(key=lambda x: abs(x[1]),reverse=True) - - common = "" - uncommon = "" - for i in range(8): - atom = slab[self.delta_magmoms[i][0]] - common += "%s%d: %.2f\t"%(atom.symbol,atom.index,self.delta_magmoms[i][1]) - for i in ads_indices_not_used: - uncommon += "%s%d: %.2f\t"%(ads[i].symbol,ads[i].index,ads[i].magmom) - - if self.quiet: - return - else: - - print("~"*6 + "MAGNETIC MOMENT COMPARISON" + "~"*6) - print("Largest magnetic moment discrepancies (indexed by %s)"%indexed_by) - print(common) - print("Magnetic moments only present in %s"%not_indexed_by) - print(uncommon + "\n") - - # print("~"*6 + "MAGNETIC MOMENT COMPARISON" + "~"*6) - # print("Largest magnetic moment discrepancies (indexed by %s)"%indexed_by) - # print(common) - # print("Magnetic moments only present in %s"%not_indexed_by) - # print(uncommon + "\n") - #__| - - def rms_displacement(self): - """ - """ - #| - rms_displacement - displacements = np.zeros(np.min((len(self.slab_atoms),len(self.ads_atoms)))) - for i in range(len(displacements)): - displacements[i] = np.linalg.norm(self.slab_atoms[i].position-self.ads_atoms[i].position)**2 - return np.sqrt(displacements.mean()) - #__| - - def compare_wf(self): - """ - """ - #| - compare_wf - self.wf_slab = self.read_wf(self.slab_atoms.PATH) - self.wf_ads = self.read_wf(self.ads_atoms.PATH) - - if 'N/A' in [self.wf_slab,self.wf_ads]: - self.d_wf = 'N/A' - else: - self.d_wf = self.wf_ads - self.wf_slab - self.avg_wf = (self.wf_ads + self.wf_slab)/2 - self.d_mu = 0.0055 * self.d_wf * np.linalg.norm(np.cross(self.ads_atoms.cell[0],self.ads_atoms.cell[1])) - #__| - - def read_wf(self,path): - """ - """ - #| - read_wf - try: - f = open(path + '/out.WF') - except: - return 'N/A' - - line = f.readlines()[0] - return float(line.split(',')[0][1:]) - #__| - - - #| - __old__ | old __repr__ - # def __repr__(self): - # """ - # String representation of free energy calculation. Example output: - # - # Ir48O100 + H+/e- --> HIr48O100 dG = (-0.5 + eU_RHE) - # pw/dw = 600/6000 xc = RPBE pp = /home/vossj/suncat/esdld/psp - # Default vibrational corrections applied to adsorbates - # Other possible references include H2... - # """ - # #| - __repr__ - # string = "" - # if self.get_E: - # string += "dE = %.3f eV"%self.G_std - # else: - # string += "dG = %.3f eV"%self.G_std - # - # for thermo in self.G_thermo: - # if self.G_thermo[thermo] > 0: - # string += " + %d%s"%(self.G_thermo[thermo],thermo) - # elif self.G_thermo[thermo] < 0: - # string += " - %d%s"%(-self.G_thermo[thermo],thermo) - # - # string += '\n' - # string += "xc = %s\tpw/dw = %d/%d\tpp = %s"%(self.params['xc'],self.params['pw'],self.params['dw'],self.params['pp']) - # - # if not self.get_E: - # if self.default_vib_bool: - # string += "\nUsing default vibrational corrections for adsorbates" - # else: - # string += "\nUsing vibrational corrections for adsorbates found in directory" - # - # string += "\nRMS Displacement = %.3f Angstroms"%self.rms_displacement() - # if type(self.d_wf) == float: - # string += "\nIS WF = %.2f eV, FS WF = %.2f eV, Change in WF = %.2f eV, Change in Dipole = %.2f eA, Average WF = %.2f eV"\ - # %(self.wf_slab,self.wf_ads,self.d_wf,self.d_mu,self.avg_wf) - # return string - # #__| - #__| - - #__| - - - - - - - -#| - out_of_sight - -rydberg = 13.6057 #rydberg to eV conversion - -default_vib_dict = {'H':0.3, 'O':0.05, 'N': 0.05, 'Ru':0.} - -references = { - 'H':{ - 'H2':([('H2',0.5)],[('kB*T*ln(P_H2)',0.5)]), - 'H+/e-':([('H2',0.5)],[('e*U_RHE',-1)],'DEF') - }, - 'O':{ - 'O2':([('H2O(l)',1),('H2',-1),(2.46)],[('kB*(300 K)*ln(P_O2)',0.5)]), - 'H2O(l)':([('H2O(l)',1),('H2',-1)],[('e*U_RHE',2)],'DEF') - }, - 'N':{ - 'N2':([('N2',0.5)],[('kB*T*ln*(P_N2)',0.5)],'DEF') - }, - 'Ru':{ - 'RuO4':([('RuO4(l)',1),('H2O(l)',-4),('H2',4)],[('e*U_RHE',-8)],'DEF') - }, - 'Li':{ - 'Li':([('Li',1)],[('N/A',0)],'DEF') - }, - } - - -#Preliminary dictionary of DFT reference chemical potentials (assuming ideal gas or electronic energy for solids) -DFT_G_references = { - 'H2':{ - 'RPBE':{ - (600,6000):{ - '/home/vossj/suncat/esdld/psp':-32.1129703764, - '/scratch/users/colinfd/psp/gbrv':-32.0745195582 - }, - (500,5000):{ - '/home/vossj/suncat/esdld/psp':-32.097274273 - } - }, - 'PBE':{ - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-31.7495756638, - '/home/vossj/suncat/esdld/psp':-31.7878744197 - } - }, - 'BEEF':{ - (600,6000):{ - '/home/vossj/suncat/esdld/psp':-33.0011548009, - '/scratch/users/colinfd/psp/gbrv':-32.9557311734, - }, - (500,5000):{ - '/home/vossj/suncat/esdld/psp':-32.9825919425, - '/scratch/users/colinfd/psp/gbrv':-32.955410852 - }, - (550,5500):{ - '/home/vossj/suncat/esdld/psp':-32.9946770046, - } - }, - 'syms':['H'] #used for comparing pseudopotentials - }, - 'H2O(l)':{ - 'RPBE':{ - (600,6000):{ - '/home/vossj/suncat/esdld/psp':-491.396166885, - '/scratch/users/colinfd/psp/gbrv':-472.461551626 - }, - (500,5000):{ - '/home/vossj/suncat/esdld/psp':-491.260712609 - } - }, - 'PBE':{ - (600,6000):{ - '/home/vossj/suncat/esdld/psp':-490.525317314, - '/scratch/users/colinfd/psp/gbrv':-471.663372251 - } - }, - 'BEEF':{ - (600,6000):{ - '/home/vossj/suncat/esdld/psp':-496.410477954, - '/scratch/users/colinfd/psp/gbrv':-476.619940391, - }, - (500,5000):{ - '/home/vossj/suncat/esdld/psp':-496.404846831 - } - }, - 'syms':['H','O'] #used for comparing pseudopoentials - }, - 'N2':{ - 'BEEF':{ - (500,5000):{ - '/scratch/users/colinfd/psp/gbrv':-553.966954842, - '/home/vossj/suncat/esdld/psp':-555.426924645 - } - }, - 'syms':['N'] #used for comparing pseudopoentials - }, - 'RuO4(l)':{ - 'RPBE':{ - (600,6000):{ - '/home/vossj/suncat/esdld/psp':-2512.43779553, - '/scratch/users/colinfd/psp/esp_psp_w_gbrvRu':-4475.37701007 - } - }, - 'BEEF':{ - (600,6000):{ - '/scratch/users/colinfd/psp/esp_psp_w_gbrvRu':-4503.54664532 - } - }, - 'syms':['Ru','O'] - } - } - - -DFT_E_references = { - 'H2':{ - 'BEEF':{ - (500,5000):{ - '/scratch/users/colinfd/psp/gbrv':-32.9198000182, - '/home/vossj/suncat/esdld/psp':-32.9423056024, - }, - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-32.9199219252, - '/home/vossj/suncat/esdld/psp':-32.9629591797, - } - }, - 'RPBE':{ - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-32.0316308866, - '/home/vossj/suncat/esdld/psp':-32.0667357502 - }, - }, - 'PBE':{ - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-31.7044722137, - '/home/vossj/suncat/esdld/psp':-31.7393674136 - } - }, - 'syms':['H'] #used for comparing pseudopoentials - }, - 'N2':{ - 'BEEF':{ - (500,5000):{ - '/scratch/users/colinfd/psp/gbrv':-553.610425617, - '/home/vossj/suncat/esdld/psp':-555.069481444 - } - }, - 'syms':['N'] #used for comparing pseudopoentials - }, - - 'H2O(l)':{ - 'RPBE':{ - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-472.468333263, - '/home/vossj/suncat/esdld/psp':-491.389771898 - } - }, - 'PBE':{ - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-471.668649297, - '/home/vossj/suncat/esdld/psp':-490.517735036 - } - }, - 'BEEF':{ - (600,6000):{ - '/scratch/users/colinfd/psp/gbrv':-476.630765091, - '/home/vossj/suncat/esdld/psp':-496.411376542 - } - }, - - 'syms':['O','H'] #used for comparing pseudopotentials - }, - - 'Li':{ - 'BEEF':{ - (500,5000):{ - '/home/vossj/suncat/esdld/psp':-204.787513924 - }, - }, - } - } - -##synonyms -synonyms = { - 'pp':{ - #2014 gbrv - '/nfs/slac/g/suncatfs/colinfd/psp/esp_psp_w_gbrvRu': - '/scratch/users/colinfd/psp/esp_psp_w_gbrvRu', - - '/nfs/slac/g/suncatfs/colinfd/psp/gbrv': - '/scratch/users/colinfd/psp/gbrv', - - '/home/vossj/suncat/psp/gbrv1.5pbe': - '/scratch/users/colinfd/psp/gbrv', - - '/global/project/projectdirs/m2997/colinfd/psp/gbrv': - '/scratch/users/colinfd/psp/gbrv', - - #v2 (default QE) - '/nfs/slac/g/suncatfs/sw/external/esp-psp/v2': - '/home/vossj/suncat/esdld/psp', - - '/nfs/slac/g/suncatfs/sw/rh6/external/../../external/esp-psp/v2': - '/home/vossj/suncat/esdld/psp', - - '/global/project/projectdirs/m2997/colinfd/psp/esp_psp/': - '/home/vossj/suncat/esdld/psp', - - '/scratch/users/colinfd/psp/esp_psp': - '/home/vossj/suncat/esdld/psp', - }, - 'xc':{ - 'BEEF-vdW':'BEEF' - } -} - -#__| - -# if __name__ == "__main__": -# import argparse -# parser = argparse.ArgumentParser() -# parser.add_argument('slab', type=str) -# parser.add_argument('ads', type=str) -# parser.add_argument('-vib', '--vibrations', action = 'store_false', help='Look for vibrational calculations in vib/') -# parser.add_argument('-E', '--elec_only', action = 'store_true', help='Calculate change in electronic energy (no TS, ZPE, etc)') -# parser.add_argument('-i', '--index', type=int, help = 'Index to use for both traj files', default = -1) -# -# args = parser.parse_args() -# G = Get_G(args.slab,args.ads,default_vib_bool = args.vibrations, get_E = args.elec_only, index=args.index) -# print G +#!/usr/bin/env python + +""" +Author(s): Colin Dickens + +TODO + continue to test + add reaction printing to __repr__ + add potential/pressure/temperature dependence to __repr__ + add optional keyword arguments to command line interface for setting potential/pressure/temperature + add Sr, Ru references +""" + +#| - Import Modules +import os + +import glob +import filecmp + +import numpy as np + +from ase.atoms import Atoms +from ase.io import read +#__| + +class Get_G: + """ + Class that automatically calculates standard change in free energy between two states by referencing any atoms + missing between them to a number of gas-phase or aqueous references + """ + + #| - Get_G + def __init__(self, + slab, + ads, + default_vib_bool=True, + get_E=False, + index=-1, + quiet=False, + ): + """ + Get_G(ads,slab) where ads/slab are either paths to traj files or paths to directory containing traj files that have energy and forces. + The directories that contain these traj files must also contain a calculation directory with pw.inp. + """ + #| - __init__ + self.default_vib_bool = default_vib_bool + self.get_E = get_E + self.quiet = quiet + + if type(slab) == str: + self.ads_atoms = self.read_atoms(ads,index=index) + self.slab_atoms = self.read_atoms(slab,index=index) + + elif isinstance(slab, Atoms): + + self.slab_atoms = slab + self.ads_atoms = ads + + + # RF | 181106 + # self.update_params(self.ads_atoms) + # self.update_params(self.slab_atoms) + # + # if self.ads_atoms.PARAMS != self.slab_atoms.PARAMS: + # + # print("%s:"%slab) + # print(self.slab_atoms.PARAMS) + # print("%s:"%ads) + # print(self.ads_atoms.PARAMS) + # + # # print "%s:"%slab + # # print self.slab_atoms.PARAMS + # # print "%s:"%ads + # # print self.ads_atoms.PARAMS + # + # for param in ('dw','pp','pw','xc'): + # if self.ads_atoms.PARAMS[param] != self.slab_atoms.PARAMS[param]: + # raise Exception("Calculations performed with different parameters") + # else: + # print("WARNING, ONE CALCULATION IS SPIN-POLARIZED") + + self.update_delta_atoms() + self.vib_correction() + self.set_refs() + + # RF | 181106 + # if self.slab_atoms.PARAMS['sp']: + # self.compare_magmoms() + + # self.calc_G() + # self.compare_wf() + #__| + + def read_atoms(self,path,**kwargs): + """ + Loads traj file. Path must be direct path to traj files or paths to directory containing them named as either qn.traj or qnXX.traj. + """ + #| - read_atoms + if path.find('traj') != -1: #Checks if directory or filename has been specified + atoms = read(path) + if '/' in path: + atoms.PATH = '/'.join(path.split('/')[:-1]) + else: + atoms.PATH = '.' + else: + files = glob.glob(path + '/qn*.traj') + qn = -1 + for file in files: + file = file.split('/')[-1] + if len(file.split(".")[0]) == 2: #qn.traj + atoms_path = path + '/qn.traj' + elif int(file.split('.')[0][2:]) > qn: #qnXX.traj + qn = int(file.split('.')[0][2:]) + atoms_path = path + '/qn%i.traj'%qn + try: + atoms = read(atoms_path, **kwargs) + atoms.PATH = path + except NameError: + raise IOError("Could not find traj file associate with " + path) + if self.fmax(atoms) > 0.05: + print("WARNING: fmax = %.2f for atoms in %s"%(self.fmax(atoms),atoms.PATH)) + return atoms + #__| + + def update_params(self,atoms): + """ + Takes atoms object containing PATH attribute and adds PARAMS dict as attribute with keys pw, dw, xc, pp. + Assumes PATH contains outdir or calcdir with pw.inp + """ + #| - update_params + if os.path.isdir(atoms.PATH + '/outdir'): + calcdir = atoms.PATH + '/outdir' + elif os.path.isdir(atoms.PATH + '/calcdir'): + calcdir = atoms.PATH + '/calcdir' + else: + raise IOError('Cannot find calculation directory (outdir or calcdir) for ' + atoms.PATH) + + file = open(calcdir + '/pw.inp') + lines = file.readlines() + file.close() + + self.params = {} + self.params['sp'] = False + + for line in lines: + if line[2:9] == 'ecutwfc': + self.params['pw'] = int(float(line.split('=')[-1][:-4])*rydberg) + if line[2:9] == 'ecutrho': + self.params['dw'] = int(float(line.split('=')[-1][:-4])*rydberg) + if line[2:11] == 'input_dft': + self.params['xc'] = line.split('=')[-1][1:-3] + if line[2:12] == 'pseudo_dir': + self.params['pp'] = line.split('=')[-1][1:-3] + if line[2:8] == 'nspin=': + self.params['sp'] = True + + + for key in synonyms: + if self.params[key] in synonyms[key]: + self.params[key] = synonyms[key][self.params[key]] + + atoms.PARAMS = self.params + #__| + + def update_delta_atoms(self): + """ + Update dictionary self.data_atoms with difference in chemical formulas between ads and slab. + Positive numbers represent species that ads has and slab doesn't. + """ + #| - update_delta_atoms + self.delta_atoms = {} + ads_syms = self.ads_atoms.get_chemical_symbols() + slab_syms = self.slab_atoms.get_chemical_symbols() + ads_dict = {} + slab_dict = {} + + for sym in ads_syms: + if sym in ads_dict: + ads_dict[sym] += 1 + else: + ads_dict[sym] = 1 + + for sym in slab_syms: + if sym in slab_dict: + slab_dict[sym] += 1 + else: + slab_dict[sym] = 1 + + for sym in ads_dict: + try: + self.delta_atoms[sym] = ads_dict[sym] - slab_dict[sym] + except KeyError: #no sym in slab_dict + self.delta_atoms[sym] = ads_dict[sym] + + for sym in slab_dict: + if sym not in self.delta_atoms: + self.delta_atoms[sym] = -slab_dict[sym] + + print(self.delta_atoms) + print("LKSDJFKLDJS_------_-_-__----") + + # for key in self.delta_atoms.keys(): + for key in list(self.delta_atoms): + if self.delta_atoms[key] == 0: + del self.delta_atoms[key] + #__| + + def vib_correction(self): + """ + Attempt to add explicitly calculated vibrational correction from vib directory within PATH of ads_atoms and slab_atoms. + Otherwise, default vibrational corrections are used by calling default_vib() + """ + #| - vib_correction + + def vib_indices(atoms): + """ + Return a dict with symbol/count key/value pairs given an atoms object with PATH attribute + """ + #| - vib_indices + dict = {} + + vib_pkls = glob.glob(atoms.PATH + '/vib/vib.*.pckl') + indices = [] + for vib_pkl in vib_pkls: + if vib_pkl != atoms.PATH + '/vib/vib.eq.pckl': + i = vib_pkl.split('/')[-1].split('.')[1][:-2] + if int(i) not in indices: + indices.append(int(i)) + + for index in indices: + sym = atoms[index].symbol + if sym in dict: + dict[sym] +=1 + else: + dict[sym] = 1 + + return dict + #__| + + def parse_corr(path): + """ + Return vibrational correction from myjob.out in path. Return -1 if myjob.out cannot be read (imag freqs?) + """ + #| - parse_corr + file = open(path) + lines = file.readlines() + file.close() + for line in lines: + if len(line.split()) > 1: + if line.split()[0] == 'G' or line.split()[0] == 'F': + corr = float(line.split()[1]) + return corr + return -1 + + """ + try: + try: + corr = float([item for item in [line for line in lines if 'G' in line][0].split(' ') if item.strip()][1]) + return corr + except: + corr = float([item for item in [line for line in lines if 'F' in line][0].split(' ') if item.strip()][1]) + return corr + except: + return -1 + """ + #__| + + if self.get_E: + self.ads_corr = 0 + self.slab_corr = 0 + return + + if self.default_vib_bool: + self.default_vib() + return + + ads_dict = vib_indices(self.ads_atoms) + slab_dict = vib_indices(self.slab_atoms) + + self.delta_vib = {} + + for sym in ads_dict: + try: + self.delta_vib[sym] = ads_dict[sym] - slab_dict[sym] + except KeyError: #no sym in slab_dict + self.delta_vib[sym] = ads_dict[sym] + + for sym in slab_dict: + if sym not in self.delta_vib: + self.delta_vib[sym] = -slab_dict[sym] + + for sym in self.delta_vib.keys(): + if self.delta_vib[sym] == 0: + del self.delta_vib[sym] + + + if self.delta_vib == self.delta_atoms: #explicit vibrational corrections appear valid + if ads_dict != {}: + self.ads_corr = parse_corr(self.ads_atoms.PATH + '/vib/myjob.out') + if self.ads_corr == -1: + print("Correct number of vibrational modes, but cannot read myjob.out (imag freqs?)") + self.default_vib() + return + else: + self.ads_corr = 0 + + if slab_dict != {}: + self.slab_corr = parse_corr(self.slab_atoms.PATH + '/vib/myjob.out') + if self.slab_corr == -1: + print("Correct number of vibrational modes, but cannot read myjob.out (imag freqs?)") + self.default_vib() + return + else: + self.slab_corr = 0 + else: + self.default_vib() + return + #__| + + def default_vib(self): + """ + Calculate vibrational corrections using estimates based on atom identity. + """ + #| - default_vib + self.default_vib_bool = True + self.ads_corr = 0 + self.slab_corr = 0 + for sym in self.delta_atoms: + if self.delta_atoms[sym] > 0: + self.ads_corr += default_vib_dict[sym]*self.delta_atoms[sym] + else: + self.slab_corr -= default_vib_dict[sym]*self.delta_atoms[sym] + #__| + + def set_refs(self): + """ + Formulate references for atoms in self.delta_atoms. Currently chooses reference indicated as default. + """ + #| - set_refs + self.references = {} + for sym in self.delta_atoms: + for atom in references: + if atom == sym: + for ref in references[atom]: + if len(references[atom][ref]) == 3: #use default reference + self.references[sym] = references[atom][ref][:2] + #__| + + def calc_G(self): + """ + Perform free energy calculation at standard conditions and record thermodynamic dependencies on pressure, tempreature, potential, etc. + """ + #| - calc_G + self.G_std = self.ads_atoms.get_potential_energy() - self.slab_atoms.get_potential_energy() + self.G_std += self.ads_corr - self.slab_corr + self.G_thermo = {} + for sym in self.delta_atoms: + for DFT_ref in self.references[sym][0]: + n = DFT_ref[1] + DFT_G = self.get_DFT_ref(DFT_ref[0]) + self.G_std -= self.delta_atoms[sym]*DFT_G*n + for thermo,n in self.references[sym][1]: + if thermo in self.G_thermo: + self.G_thermo[thermo] -= n*self.delta_atoms[sym] + else: + self.G_thermo[thermo] = -n*self.delta_atoms[sym] + #__| + + def get_DFT_ref(self,ref): + """ + Pull appropriate DFT reference energy from database according to computational parameters + """ + #| - get_DFT_ref + xc = self.params['xc'] + pwdw =(self.params['pw'],self.params['dw']) + pp = self.params['pp'] + + if self.get_E: + DFT_references = DFT_E_references + else: + DFT_references = DFT_G_references + + if xc in DFT_references[ref]: + if pwdw in DFT_references[ref][xc]: + if pp in DFT_references[ref][xc][pwdw]: + return DFT_references[ref][xc][pwdw][pp] + else: + for pp_ref in DFT_references[ref][xc][pwdw]: + if self.compare_pp(pp,pp_ref,DFT_references[ref]['syms']): + return DFT_references[ref][xc][pwdw][pp_ref] + + raise Exception("No reference found for %s with %s @ %s with %s"%(ref,xc,pwdw,pp)) + #__| + + def compare_pp(self,pp1,pp2,syms): + """ + """ + #| - compare_pp + for sym in syms: + if not filecmp.cmp("%s/%s.UPF"%(pp1,sym),"%s/%s.UPF"%(pp2,sym)): + return False + return True + #__| + + def fmax(self,atoms): + """ + """ + #| - fmax + forces = atoms.get_forces() + max = 0 + for force in forces: + tot = (force[0]**2 + force[1]**2 + force[2]**2)**0.5 + if tot > max: + max = tot + return max + #__| + + def compare_magmoms(self): + """ + """ + #| - compare_magmoms + def nearest_atom(atoms,position): + "Returns atom nearest to position" + position = np.array(position) + dist_list = [] + for atom in atoms: + dist = np.linalg.norm(position - atom.position) + dist_list.append(dist) + + return atoms[np.argmin(dist_list)] + + if len(self.ads_atoms) >= len(self.slab_atoms): + ads = self.ads_atoms + slab = self.slab_atoms + indexed_by = "slab" + not_indexed_by = "ads" + else: + slab = self.ads_atoms + ads = self.slab_atoms + indexed_by = "ads" + not_indexed_by = "slab" + + delta_magmoms = [] + ads_indices_used = [] + for atom in slab: + ads_atom = nearest_atom(ads,atom.position) + if not self.quiet: + if ads_atom.symbol != atom.symbol: print("WARNING! MAGMOM COMPARISON FAILURE") + ads_indices_used.append(ads_atom.index) + delta_magmoms.append(atom.magmom - ads_atom.magmom) + + ads_indices_not_used = [] + for i in range(len(ads)): + if i not in ads_indices_used: + ads_indices_not_used.append(i) + + # RF | 181106 + # self.delta_magmoms = zip(range(len(slab)), delta_magmoms) + self.delta_magmoms = list(zip(range(len(slab)), delta_magmoms)) + self.delta_magmoms.sort(key=lambda x: abs(x[1]),reverse=True) + + common = "" + uncommon = "" + for i in range(8): + atom = slab[self.delta_magmoms[i][0]] + common += "%s%d: %.2f\t"%(atom.symbol,atom.index,self.delta_magmoms[i][1]) + for i in ads_indices_not_used: + uncommon += "%s%d: %.2f\t"%(ads[i].symbol,ads[i].index,ads[i].magmom) + + if self.quiet: + return + else: + + print("~"*6 + "MAGNETIC MOMENT COMPARISON" + "~"*6) + print("Largest magnetic moment discrepancies (indexed by %s)"%indexed_by) + print(common) + print("Magnetic moments only present in %s"%not_indexed_by) + print(uncommon + "\n") + + # print("~"*6 + "MAGNETIC MOMENT COMPARISON" + "~"*6) + # print("Largest magnetic moment discrepancies (indexed by %s)"%indexed_by) + # print(common) + # print("Magnetic moments only present in %s"%not_indexed_by) + # print(uncommon + "\n") + #__| + + def rms_displacement(self): + """ + """ + #| - rms_displacement + displacements = np.zeros(np.min((len(self.slab_atoms),len(self.ads_atoms)))) + for i in range(len(displacements)): + displacements[i] = np.linalg.norm(self.slab_atoms[i].position-self.ads_atoms[i].position)**2 + return np.sqrt(displacements.mean()) + #__| + + def compare_wf(self): + """ + """ + #| - compare_wf + self.wf_slab = self.read_wf(self.slab_atoms.PATH) + self.wf_ads = self.read_wf(self.ads_atoms.PATH) + + if 'N/A' in [self.wf_slab,self.wf_ads]: + self.d_wf = 'N/A' + else: + self.d_wf = self.wf_ads - self.wf_slab + self.avg_wf = (self.wf_ads + self.wf_slab)/2 + self.d_mu = 0.0055 * self.d_wf * np.linalg.norm(np.cross(self.ads_atoms.cell[0],self.ads_atoms.cell[1])) + #__| + + def read_wf(self,path): + """ + """ + #| - read_wf + try: + f = open(path + '/out.WF') + except: + return 'N/A' + + line = f.readlines()[0] + return float(line.split(',')[0][1:]) + #__| + + + #| - __old__ | old __repr__ + # def __repr__(self): + # """ + # String representation of free energy calculation. Example output: + # + # Ir48O100 + H+/e- --> HIr48O100 dG = (-0.5 + eU_RHE) + # pw/dw = 600/6000 xc = RPBE pp = /home/vossj/suncat/esdld/psp + # Default vibrational corrections applied to adsorbates + # Other possible references include H2... + # """ + # #| - __repr__ + # string = "" + # if self.get_E: + # string += "dE = %.3f eV"%self.G_std + # else: + # string += "dG = %.3f eV"%self.G_std + # + # for thermo in self.G_thermo: + # if self.G_thermo[thermo] > 0: + # string += " + %d%s"%(self.G_thermo[thermo],thermo) + # elif self.G_thermo[thermo] < 0: + # string += " - %d%s"%(-self.G_thermo[thermo],thermo) + # + # string += '\n' + # string += "xc = %s\tpw/dw = %d/%d\tpp = %s"%(self.params['xc'],self.params['pw'],self.params['dw'],self.params['pp']) + # + # if not self.get_E: + # if self.default_vib_bool: + # string += "\nUsing default vibrational corrections for adsorbates" + # else: + # string += "\nUsing vibrational corrections for adsorbates found in directory" + # + # string += "\nRMS Displacement = %.3f Angstroms"%self.rms_displacement() + # if type(self.d_wf) == float: + # string += "\nIS WF = %.2f eV, FS WF = %.2f eV, Change in WF = %.2f eV, Change in Dipole = %.2f eA, Average WF = %.2f eV"\ + # %(self.wf_slab,self.wf_ads,self.d_wf,self.d_mu,self.avg_wf) + # return string + # #__| + #__| + + #__| + + + + + + + +#| - out_of_sight + +rydberg = 13.6057 #rydberg to eV conversion + +default_vib_dict = {'H':0.3, 'O':0.05, 'N': 0.05, 'Ru':0.} + +references = { + 'H':{ + 'H2':([('H2',0.5)],[('kB*T*ln(P_H2)',0.5)]), + 'H+/e-':([('H2',0.5)],[('e*U_RHE',-1)],'DEF') + }, + 'O':{ + 'O2':([('H2O(l)',1),('H2',-1),(2.46)],[('kB*(300 K)*ln(P_O2)',0.5)]), + 'H2O(l)':([('H2O(l)',1),('H2',-1)],[('e*U_RHE',2)],'DEF') + }, + 'N':{ + 'N2':([('N2',0.5)],[('kB*T*ln*(P_N2)',0.5)],'DEF') + }, + 'Ru':{ + 'RuO4':([('RuO4(l)',1),('H2O(l)',-4),('H2',4)],[('e*U_RHE',-8)],'DEF') + }, + 'Li':{ + 'Li':([('Li',1)],[('N/A',0)],'DEF') + }, + } + + +#Preliminary dictionary of DFT reference chemical potentials (assuming ideal gas or electronic energy for solids) +DFT_G_references = { + 'H2':{ + 'RPBE':{ + (600,6000):{ + '/home/vossj/suncat/esdld/psp':-32.1129703764, + '/scratch/users/colinfd/psp/gbrv':-32.0745195582 + }, + (500,5000):{ + '/home/vossj/suncat/esdld/psp':-32.097274273 + } + }, + 'PBE':{ + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-31.7495756638, + '/home/vossj/suncat/esdld/psp':-31.7878744197 + } + }, + 'BEEF':{ + (600,6000):{ + '/home/vossj/suncat/esdld/psp':-33.0011548009, + '/scratch/users/colinfd/psp/gbrv':-32.9557311734, + }, + (500,5000):{ + '/home/vossj/suncat/esdld/psp':-32.9825919425, + '/scratch/users/colinfd/psp/gbrv':-32.955410852 + }, + (550,5500):{ + '/home/vossj/suncat/esdld/psp':-32.9946770046, + } + }, + 'syms':['H'] #used for comparing pseudopotentials + }, + 'H2O(l)':{ + 'RPBE':{ + (600,6000):{ + '/home/vossj/suncat/esdld/psp':-491.396166885, + '/scratch/users/colinfd/psp/gbrv':-472.461551626 + }, + (500,5000):{ + '/home/vossj/suncat/esdld/psp':-491.260712609 + } + }, + 'PBE':{ + (600,6000):{ + '/home/vossj/suncat/esdld/psp':-490.525317314, + '/scratch/users/colinfd/psp/gbrv':-471.663372251 + } + }, + 'BEEF':{ + (600,6000):{ + '/home/vossj/suncat/esdld/psp':-496.410477954, + '/scratch/users/colinfd/psp/gbrv':-476.619940391, + }, + (500,5000):{ + '/home/vossj/suncat/esdld/psp':-496.404846831 + } + }, + 'syms':['H','O'] #used for comparing pseudopoentials + }, + 'N2':{ + 'BEEF':{ + (500,5000):{ + '/scratch/users/colinfd/psp/gbrv':-553.966954842, + '/home/vossj/suncat/esdld/psp':-555.426924645 + } + }, + 'syms':['N'] #used for comparing pseudopoentials + }, + 'RuO4(l)':{ + 'RPBE':{ + (600,6000):{ + '/home/vossj/suncat/esdld/psp':-2512.43779553, + '/scratch/users/colinfd/psp/esp_psp_w_gbrvRu':-4475.37701007 + } + }, + 'BEEF':{ + (600,6000):{ + '/scratch/users/colinfd/psp/esp_psp_w_gbrvRu':-4503.54664532 + } + }, + 'syms':['Ru','O'] + } + } + + +DFT_E_references = { + 'H2':{ + 'BEEF':{ + (500,5000):{ + '/scratch/users/colinfd/psp/gbrv':-32.9198000182, + '/home/vossj/suncat/esdld/psp':-32.9423056024, + }, + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-32.9199219252, + '/home/vossj/suncat/esdld/psp':-32.9629591797, + } + }, + 'RPBE':{ + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-32.0316308866, + '/home/vossj/suncat/esdld/psp':-32.0667357502 + }, + }, + 'PBE':{ + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-31.7044722137, + '/home/vossj/suncat/esdld/psp':-31.7393674136 + } + }, + 'syms':['H'] #used for comparing pseudopoentials + }, + 'N2':{ + 'BEEF':{ + (500,5000):{ + '/scratch/users/colinfd/psp/gbrv':-553.610425617, + '/home/vossj/suncat/esdld/psp':-555.069481444 + } + }, + 'syms':['N'] #used for comparing pseudopoentials + }, + + 'H2O(l)':{ + 'RPBE':{ + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-472.468333263, + '/home/vossj/suncat/esdld/psp':-491.389771898 + } + }, + 'PBE':{ + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-471.668649297, + '/home/vossj/suncat/esdld/psp':-490.517735036 + } + }, + 'BEEF':{ + (600,6000):{ + '/scratch/users/colinfd/psp/gbrv':-476.630765091, + '/home/vossj/suncat/esdld/psp':-496.411376542 + } + }, + + 'syms':['O','H'] #used for comparing pseudopotentials + }, + + 'Li':{ + 'BEEF':{ + (500,5000):{ + '/home/vossj/suncat/esdld/psp':-204.787513924 + }, + }, + } + } + +##synonyms +synonyms = { + 'pp':{ + #2014 gbrv + '/nfs/slac/g/suncatfs/colinfd/psp/esp_psp_w_gbrvRu': + '/scratch/users/colinfd/psp/esp_psp_w_gbrvRu', + + '/nfs/slac/g/suncatfs/colinfd/psp/gbrv': + '/scratch/users/colinfd/psp/gbrv', + + '/home/vossj/suncat/psp/gbrv1.5pbe': + '/scratch/users/colinfd/psp/gbrv', + + '/global/project/projectdirs/m2997/colinfd/psp/gbrv': + '/scratch/users/colinfd/psp/gbrv', + + #v2 (default QE) + '/nfs/slac/g/suncatfs/sw/external/esp-psp/v2': + '/home/vossj/suncat/esdld/psp', + + '/nfs/slac/g/suncatfs/sw/rh6/external/../../external/esp-psp/v2': + '/home/vossj/suncat/esdld/psp', + + '/global/project/projectdirs/m2997/colinfd/psp/esp_psp/': + '/home/vossj/suncat/esdld/psp', + + '/scratch/users/colinfd/psp/esp_psp': + '/home/vossj/suncat/esdld/psp', + }, + 'xc':{ + 'BEEF-vdW':'BEEF' + } +} + +#__| + +# if __name__ == "__main__": +# import argparse +# parser = argparse.ArgumentParser() +# parser.add_argument('slab', type=str) +# parser.add_argument('ads', type=str) +# parser.add_argument('-vib', '--vibrations', action = 'store_false', help='Look for vibrational calculations in vib/') +# parser.add_argument('-E', '--elec_only', action = 'store_true', help='Calculate change in electronic energy (no TS, ZPE, etc)') +# parser.add_argument('-i', '--index', type=int, help = 'Index to use for both traj files', default = -1) +# +# args = parser.parse_args() +# G = Get_G(args.slab,args.ads,default_vib_bool = args.vibrations, get_E = args.elec_only, index=args.index) +# print G diff --git a/atoms_objects/slab_generation.py b/atoms_objects/slab_generation.py index 37c9538..2a365a7 100644 --- a/atoms_objects/slab_generation.py +++ b/atoms_objects/slab_generation.py @@ -1,131 +1,131 @@ -#!/usr/bin/env python - -"""Cut slabs from bulk structures. - -Author: Raul A. Flores -""" - -#| - Import Modules -from ase.build import surface -# from ase import io - -from catkit.gen.surface import SlabGenerator as SlabGenerator_catkit -# from ase.visualize import view - -from pymatgen.io.ase import AseAtomsAdaptor -from pymatgen.core.surface import SlabGenerator as SlabGenerator_pymatgen -#__| - -def cut_slab_ase( - bulk, - facet, - layers=6, - vacuum=8, - ): - """Cut slab from bulk using ASE. - - Args: - bulk: - facet: - """ - #| - cut_slab_ase - # facet = [1, 1, 0] - # layers = 6 - # vacuum = 8 - - out_file = "out_slab_ase.traj" - - # facet = [int(i) for i in facet] - - # atoms = io.read("qn.traj") # Bulk traj file (no vacuum) - # atoms = io.read("init.cif") # Bulk traj file (no vacuum) - - slab = surface(bulk, facet, layers, vacuum) - slab.set_pbc(True) - # slab.write(out_file) - - return(slab) - #__| - -def cut_slab_pymatgen( - bulk, - facet, - min_slab_size=18., - min_vacuum_size=10., - ): - """Cut slab from bulk using pymatgen. - - Args: - bulk: - facet: - """ - #| - cut_slab_pymatgen - # atoms = io.read("init.traj") - # atoms = io.read("init.cif") - - structure = AseAtomsAdaptor.get_structure(bulk) - - # ZnO=Structure.from_file("ZnO.cif",primitive=False) - - slab_pymatgen = SlabGenerator_pymatgen( - structure, - # [1, 1, 0], - facet, - min_slab_size, - min_vacuum_size, - lll_reduce=True, - center_slab=True, - max_normal_search=2, - ).get_slab() - - # initial_structure, miller_index, min_slab_size, - # min_vacuum_size, lll_reduce=False, center_slab=False, - # in_unit_planes=False, primitive=True, max_normal_search=None, - # reorient_lattice=True - - slab = AseAtomsAdaptor.get_atoms(slab_pymatgen) - - slab.center() - - # slab.write("out_slab_pymatgen.traj") - - # IStructure.to(Al55, "poscar", filename="POSCAR") - - return(slab) - #__| - -def cut_slab_catkit( - bulk, - facet, - slab_thickness=6, - vacuum=8., - ): - """Cut slab from bulk using CatKit. - - Args: - bulk: - facet: - """ - #| - cut_slab_catkit - gen = SlabGenerator_catkit( - bulk, - miller_index=facet, - layers=slab_thickness, - vacuum=vacuum, - fixed=2, - layer_type='ang', - # attach_graph=True, - standardize_bulk=False, - tol=1e-8 - ) - - terminations = gen.get_unique_terminations() - - images = [] - for i, t in enumerate(terminations): - images += [gen.get_slab(iterm=i, size=1)] - - # view(images) - - return(images) - #__| +#!/usr/bin/env python + +"""Cut slabs from bulk structures. + +Author: Raul A. Flores +""" + +#| - Import Modules +from ase.build import surface +# from ase import io + +from catkit.gen.surface import SlabGenerator as SlabGenerator_catkit +# from ase.visualize import view + +from pymatgen.io.ase import AseAtomsAdaptor +from pymatgen.core.surface import SlabGenerator as SlabGenerator_pymatgen +#__| + +def cut_slab_ase( + bulk, + facet, + layers=6, + vacuum=8, + ): + """Cut slab from bulk using ASE. + + Args: + bulk: + facet: + """ + #| - cut_slab_ase + # facet = [1, 1, 0] + # layers = 6 + # vacuum = 8 + + out_file = "out_slab_ase.traj" + + # facet = [int(i) for i in facet] + + # atoms = io.read("qn.traj") # Bulk traj file (no vacuum) + # atoms = io.read("init.cif") # Bulk traj file (no vacuum) + + slab = surface(bulk, facet, layers, vacuum) + slab.set_pbc(True) + # slab.write(out_file) + + return(slab) + #__| + +def cut_slab_pymatgen( + bulk, + facet, + min_slab_size=18., + min_vacuum_size=10., + ): + """Cut slab from bulk using pymatgen. + + Args: + bulk: + facet: + """ + #| - cut_slab_pymatgen + # atoms = io.read("init.traj") + # atoms = io.read("init.cif") + + structure = AseAtomsAdaptor.get_structure(bulk) + + # ZnO=Structure.from_file("ZnO.cif",primitive=False) + + slab_pymatgen = SlabGenerator_pymatgen( + structure, + # [1, 1, 0], + facet, + min_slab_size, + min_vacuum_size, + lll_reduce=True, + center_slab=True, + max_normal_search=2, + ).get_slab() + + # initial_structure, miller_index, min_slab_size, + # min_vacuum_size, lll_reduce=False, center_slab=False, + # in_unit_planes=False, primitive=True, max_normal_search=None, + # reorient_lattice=True + + slab = AseAtomsAdaptor.get_atoms(slab_pymatgen) + + slab.center() + + # slab.write("out_slab_pymatgen.traj") + + # IStructure.to(Al55, "poscar", filename="POSCAR") + + return(slab) + #__| + +def cut_slab_catkit( + bulk, + facet, + slab_thickness=6, + vacuum=8., + ): + """Cut slab from bulk using CatKit. + + Args: + bulk: + facet: + """ + #| - cut_slab_catkit + gen = SlabGenerator_catkit( + bulk, + miller_index=facet, + layers=slab_thickness, + vacuum=vacuum, + fixed=2, + layer_type='ang', + # attach_graph=True, + standardize_bulk=False, + tol=1e-8 + ) + + terminations = gen.get_unique_terminations() + + images = [] + for i, t in enumerate(terminations): + images += [gen.get_slab(iterm=i, size=1)] + + # view(images) + + return(images) + #__| diff --git a/aws/aws_class.py b/aws/aws_class.py index e790604..c46ddb9 100644 --- a/aws/aws_class.py +++ b/aws/aws_class.py @@ -1,415 +1,415 @@ -#!/usr/bin/env python - -"""Class for performing AWS operations. - -Author: Raul A. Flores -""" - -#| - Import Modules -from dft_job_automat.job_setup import DFT_Jobs_Setup -import os -import errno -import subprocess -from copy import deepcopy -import json -import datetime -import shutil -import pandas as pd - -import boto3 -#__| - - -def force_symlink(file1, file2): - #| - force_symlink - try: - os.symlink(file1, file2) - except OSError, e: - if e.errno == errno.EEXIST: - os.unlink(file2) - os.symlink(file1, file2) - #__| - - -class AWS_Queues(): - """ - """ - #| - AWS_Class ***************************************************************** - def __init__(self): - """ - """ - #| - __init__ - try: - self.aws_dir = os.environ["TRI_PATH"] - self.job_queue_dir = self.aws_dir + "/bin/job_queues" - except: - pass - - #__| - - - def job_info_batch(self, job_id): - """ - """ - #| - job_info_batch - batch = boto3.client("batch") - job_descriptions = batch.describe_jobs(jobs=[job_id]) - - #| - Checking if Job is in AWS Batch - if len(job_descriptions["jobs"]) == 0: - return("job not in batch system") - else: - job_info = job_descriptions["jobs"][0] - #__| - - job_status = job_info["status"] - job_path = job_info["parameters"]["model"] - job_ram = job_info["parameters"]["ram"] - job_cpus = job_info["parameters"]["cpus"] - job_name = job_info["jobName"] - - job_queue_str = job_info["jobQueue"] - if "small" in job_queue_str: - job_queue = "small" - elif "medium" in job_queue_str: - job_queue = "medium" - elif "large" in job_queue_str: - job_queue = "large" - elif "test" in job_queue_str: - job_queue = "test" - - job_queue_dict = {"job_status": job_status, "job_path": job_path, - "job_id": job_id, "job_ram": job_ram, - "job_queue": job_queue, "job_cpus": job_cpus, - "job_name": job_name} - - return(job_queue_dict) - #__| - - def cancel_job(self, job_id, reason="N/A"): - """ - """ - #| - cancel_job - bash_command = "aws batch cancel-job --job-id " - bash_command += job_id + " --reason " + reason - - print("Cancelling job | " + job_id) - run_bash = subprocess.check_output(bash_command, shell=True) - - #__| - - def cancel_jobs(self, job_id_list): - """Cancels all jobs in a given job id list - """ - #| - cancel_jobs - for job in job_id_list: - self.cancel_job(job) - #__| - - def list_jobs(self, queue="small"): - """ - Returns all jobs for a particular queue. - Included jobs in SUBMITTED, PENDING, RUNNABLE, STARTING, RUNNING, and - FAILED states. - """ - #| - list_jobs - batch = boto3.client("batch") - job_status_opt = ["SUBMITTED", "PENDING", "RUNNABLE", - "STARTING", "RUNNING", "SUCCEEDED", "FAILED"] - - job_id_list = [] - for status in job_status_opt: - all_jobs = batch.list_jobs(jobQueue=queue, jobStatus=status) # TEMP - job_ids = [i["jobId"] for i in all_jobs["jobSummaryList"]] - - #| - Checking that queue is being used - print(str(len(job_ids)) + " jobs in the " + status + " queue") - # - # if len(job_ids) < 1: - # print("No jobs in the " + status + " queue") - #__| - - - #| - Retreiving Job ID's From AWS - job_ids_split = [job_ids[x:x+100] for x in xrange(0, len(job_ids), 100)] - for j in range(len(job_ids_split)): - job_descriptions = batch.describe_jobs(jobs=job_ids_split[j]) - for i in job_descriptions["jobs"]: - job_id_list.append({ - "job_id": i["jobId"], - "job_name": i["jobName"], - "model": i["parameters"]["model"], - "job_state": status, - }) - #__| - - return(job_id_list) - - #__| - - def submit_job(self, path=None, queue="test", cpus="default", copy_PythonModules=True): - """ - Submits job to aws cluster. Copies PythonModules folder into - job directory - """ - #| - submit_job - root_dir = os.getcwd() - if path == None: - path = root_dir - - #| - Checking if job has already been submitted - os.chdir(path) - if os.path.isfile(".SUBMITTED"): - print("Directory already submitted, will be skipped") - os.chdir(root_dir) - return(None) # <-------- SKIP JOB --------------------------------- - else: - os.chdir(root_dir) - #__| - - - #| - Copy PYTHONMODULES to Job Directory - if os.path.isdir(path + "/PythonModules") == True: - print("PythonModules already exists, erasing and recopying") - shutil.rmtree(path + "/PythonModules") - py_mod = os.environ["python_modules"] - shutil.copytree(py_mod, path + "/PythonModules") - else: - py_mod = os.environ["python_modules"] - shutil.copytree(py_mod, path + "/PythonModules") - #__| - - - #| - Submit Job - os.chdir(path) - - if os.path.isfile(".sSUBMITTED"): - print("Directory already submitted, will be skipped") - os.chdir(root_dir) - return(None) - else: - print("submitting job") - aws_dir = os.environ["aws_dir"] - - - if cpus == "default": - bash_command = aws_dir + "/matr.io/bin/trisub -q " + queue - else: - bash_command = aws_dir + "/matr.io/bin/trisub -c " + str(cpus) + " -q " + queue - - - # bash_command = aws_dir + "/matr.io/bin/trisub " + "-c" + + "-q " + queue - - - try: - output = subprocess.check_output(bash_command, shell=True) - sub_time = datetime.datetime.now().isoformat() - except subprocess.CalledProcessError, e: - print "Ping stdout output:\n", e.output - - os.chdir(root_dir) - print("JOB SKIPPED: ") - return(None) - - #__| - - - #| - Parsing Submission for Job ID - output = output.splitlines() - for line in output: - if "jobId" in line: - lst = line.split('"') - job_id_ind = (lst.index("jobId") + 2) - jobId = lst[job_id_ind] - #__| - - file = open(".submitted", "w") - file.close() - - file = open("job_id", "w") - file.write(jobId + "\n") - - os.chdir(root_dir) - - #| - Querying AWS For Job Info - job_queue_dict = self.job_info_batch(jobId) - job_queue_dict["submit_time"] = sub_time - - jobs_file_path = self.job_queue_dir + "/jobs.csv" - - df_new = pd.DataFrame([job_queue_dict]) - if os.path.isfile(jobs_file_path): - df = pd.read_csv(jobs_file_path) - df = df.append(df_new) - else: - df = df_new - - df.to_csv(jobs_file_path, index=False) - #__| - - return job_queue_dict - #__| - - #__| *************************************************************************** - - -class AWS_Class_tmp(): - """Summary line. - - TEMP - """ - #| - AWS_Class_tmp ************************************************************* - def __init__(self): - """TMP_docstring. - - TEMP TEMP - """ - #| - __init__ - self.tmp = "TMP AWS Class Atribute!!!!!" - - try: - self.TRI_PATH = os.environ["TRI_PATH"] - except: - pass - #__| - - - def create_symlinks(self): - """ - Attempts to create symlinks in all subfolders whose names starts with _ - """ - #| - create_symlinks - # root_dir = '.' - root_dir = os.getcwd() - for dir_name, subdirList, fileList in os.walk(root_dir): - dir_name_i = dir_name.split("/")[-1] - - if dir_name_i[0] == "_" and dir_name_i[1].isdigit() == True: - # print(dir_name) - dest = dir_name + "/simulation" - - source = deepcopy(dir_name) - source = source.replace("/model/", "/simulation/", 1) - - print(source) - print(dest) - print("____") - force_symlink(source, dest) - - # print("Found directory: %s" % dirName) - # for fname in fileList: - # print('\t%s' % fname) - #__| - - - def create_symlink(self, path=None): - """ - """ - #| - create_symlink - - # def force_symlink(file1, file2): - # #| - force_symlink - # try: - # os.symlink(file1, file2) - # except OSError, e: - # if e.errno == errno.EEXIST: - # os.unlink(file2) - # os.symlink(file1, file2) - # #__| - - if path == None: - path = os.getcwd() - else: - pass - - dest = path + "/simulation" - print(dest) - - source = deepcopy(path) - source = source.replace("/model/", "/simulation/", 1) - force_symlink(source, dest) - - #__| - - #__| *************************************************************************** - -# NOT USEFUL FOR THIS TO BE CHILD CLASS -- FIX!!!!!!!!!!!! -class AWS_Class(DFT_Jobs_Setup): - """Summary line. - - TEMP - """ - #| - AWS_Class ***************************************************************** - def __init__(self, system="sherlock"): - """TMP_docstring. - - TEMP TEMP - """ - #| - __init__ - DFT_Jobs_Setup.__init__(self, system=system) - self.tmp = "TMP AWS Class Atribute!!!!!" - - try: - self.TRI_PATH = os.environ["TRI_PATH"] - except: - pass - #__| - - - def create_symlinks(self): - """Creates symlinks for every job revision in job directory. - - TEMP TEMP - """ - #| - create_symlinks - - def force_symlink(file1, file2): - #| - force_symlink - try: - os.symlink(file1, file2) - except OSError, e: - if e.errno == errno.EEXIST: - os.unlink(file2) - os.symlink(file1, file2) - #__| - - for job in self.job_var_lst: - path = self.var_lst_to_path(job) - path = self.root_dir + "/" + path - - for folder in os.walk(path).next()[1]: - path_i = path + folder - dest = path_i + "/simulation" - - source = deepcopy(path_i) - source = source.replace("/model/", "/simulation/", 1) - - force_symlink(source, dest) - #__| - - #__| *************************************************************************** - - - - - -#| - DEPRECATED METHODS - -# def list_jobs(self, status="RUNNING", queue="small"): -# """ -# """ -# #| - list_jobs -# bash_command = "aws batch list-jobs --job-status {} --job-queue {} > aws_list_jobs.json".format(status, queue) -# run_bash = subprocess.check_output(bash_command, shell=True) #TEMP -# data = json.load(open("aws_list_jobs.json")) -# -# job_id_list = [] -# for job in data["jobSummaryList"]: -# job_id_list.append(job["jobId"]) -# -# return(job_id_list) -# -# #__| - - -#__| +#!/usr/bin/env python + +"""Class for performing AWS operations. + +Author: Raul A. Flores +""" + +#| - Import Modules +from dft_job_automat.job_setup import DFT_Jobs_Setup +import os +import errno +import subprocess +from copy import deepcopy +import json +import datetime +import shutil +import pandas as pd + +import boto3 +#__| + + +def force_symlink(file1, file2): + #| - force_symlink + try: + os.symlink(file1, file2) + except OSError, e: + if e.errno == errno.EEXIST: + os.unlink(file2) + os.symlink(file1, file2) + #__| + + +class AWS_Queues(): + """ + """ + #| - AWS_Class ***************************************************************** + def __init__(self): + """ + """ + #| - __init__ + try: + self.aws_dir = os.environ["TRI_PATH"] + self.job_queue_dir = self.aws_dir + "/bin/job_queues" + except: + pass + + #__| + + + def job_info_batch(self, job_id): + """ + """ + #| - job_info_batch + batch = boto3.client("batch") + job_descriptions = batch.describe_jobs(jobs=[job_id]) + + #| - Checking if Job is in AWS Batch + if len(job_descriptions["jobs"]) == 0: + return("job not in batch system") + else: + job_info = job_descriptions["jobs"][0] + #__| + + job_status = job_info["status"] + job_path = job_info["parameters"]["model"] + job_ram = job_info["parameters"]["ram"] + job_cpus = job_info["parameters"]["cpus"] + job_name = job_info["jobName"] + + job_queue_str = job_info["jobQueue"] + if "small" in job_queue_str: + job_queue = "small" + elif "medium" in job_queue_str: + job_queue = "medium" + elif "large" in job_queue_str: + job_queue = "large" + elif "test" in job_queue_str: + job_queue = "test" + + job_queue_dict = {"job_status": job_status, "job_path": job_path, + "job_id": job_id, "job_ram": job_ram, + "job_queue": job_queue, "job_cpus": job_cpus, + "job_name": job_name} + + return(job_queue_dict) + #__| + + def cancel_job(self, job_id, reason="N/A"): + """ + """ + #| - cancel_job + bash_command = "aws batch cancel-job --job-id " + bash_command += job_id + " --reason " + reason + + print("Cancelling job | " + job_id) + run_bash = subprocess.check_output(bash_command, shell=True) + + #__| + + def cancel_jobs(self, job_id_list): + """Cancels all jobs in a given job id list + """ + #| - cancel_jobs + for job in job_id_list: + self.cancel_job(job) + #__| + + def list_jobs(self, queue="small"): + """ + Returns all jobs for a particular queue. + Included jobs in SUBMITTED, PENDING, RUNNABLE, STARTING, RUNNING, and + FAILED states. + """ + #| - list_jobs + batch = boto3.client("batch") + job_status_opt = ["SUBMITTED", "PENDING", "RUNNABLE", + "STARTING", "RUNNING", "SUCCEEDED", "FAILED"] + + job_id_list = [] + for status in job_status_opt: + all_jobs = batch.list_jobs(jobQueue=queue, jobStatus=status) # TEMP + job_ids = [i["jobId"] for i in all_jobs["jobSummaryList"]] + + #| - Checking that queue is being used + print(str(len(job_ids)) + " jobs in the " + status + " queue") + # + # if len(job_ids) < 1: + # print("No jobs in the " + status + " queue") + #__| + + + #| - Retreiving Job ID's From AWS + job_ids_split = [job_ids[x:x+100] for x in xrange(0, len(job_ids), 100)] + for j in range(len(job_ids_split)): + job_descriptions = batch.describe_jobs(jobs=job_ids_split[j]) + for i in job_descriptions["jobs"]: + job_id_list.append({ + "job_id": i["jobId"], + "job_name": i["jobName"], + "model": i["parameters"]["model"], + "job_state": status, + }) + #__| + + return(job_id_list) + + #__| + + def submit_job(self, path=None, queue="test", cpus="default", copy_PythonModules=True): + """ + Submits job to aws cluster. Copies PythonModules folder into + job directory + """ + #| - submit_job + root_dir = os.getcwd() + if path == None: + path = root_dir + + #| - Checking if job has already been submitted + os.chdir(path) + if os.path.isfile(".SUBMITTED"): + print("Directory already submitted, will be skipped") + os.chdir(root_dir) + return(None) # <-------- SKIP JOB --------------------------------- + else: + os.chdir(root_dir) + #__| + + + #| - Copy PYTHONMODULES to Job Directory + if os.path.isdir(path + "/PythonModules") == True: + print("PythonModules already exists, erasing and recopying") + shutil.rmtree(path + "/PythonModules") + py_mod = os.environ["python_modules"] + shutil.copytree(py_mod, path + "/PythonModules") + else: + py_mod = os.environ["python_modules"] + shutil.copytree(py_mod, path + "/PythonModules") + #__| + + + #| - Submit Job + os.chdir(path) + + if os.path.isfile(".sSUBMITTED"): + print("Directory already submitted, will be skipped") + os.chdir(root_dir) + return(None) + else: + print("submitting job") + aws_dir = os.environ["aws_dir"] + + + if cpus == "default": + bash_command = aws_dir + "/matr.io/bin/trisub -q " + queue + else: + bash_command = aws_dir + "/matr.io/bin/trisub -c " + str(cpus) + " -q " + queue + + + # bash_command = aws_dir + "/matr.io/bin/trisub " + "-c" + + "-q " + queue + + + try: + output = subprocess.check_output(bash_command, shell=True) + sub_time = datetime.datetime.now().isoformat() + except subprocess.CalledProcessError, e: + print "Ping stdout output:\n", e.output + + os.chdir(root_dir) + print("JOB SKIPPED: ") + return(None) + + #__| + + + #| - Parsing Submission for Job ID + output = output.splitlines() + for line in output: + if "jobId" in line: + lst = line.split('"') + job_id_ind = (lst.index("jobId") + 2) + jobId = lst[job_id_ind] + #__| + + file = open(".submitted", "w") + file.close() + + file = open("job_id", "w") + file.write(jobId + "\n") + + os.chdir(root_dir) + + #| - Querying AWS For Job Info + job_queue_dict = self.job_info_batch(jobId) + job_queue_dict["submit_time"] = sub_time + + jobs_file_path = self.job_queue_dir + "/jobs.csv" + + df_new = pd.DataFrame([job_queue_dict]) + if os.path.isfile(jobs_file_path): + df = pd.read_csv(jobs_file_path) + df = df.append(df_new) + else: + df = df_new + + df.to_csv(jobs_file_path, index=False) + #__| + + return job_queue_dict + #__| + + #__| *************************************************************************** + + +class AWS_Class_tmp(): + """Summary line. + + TEMP + """ + #| - AWS_Class_tmp ************************************************************* + def __init__(self): + """TMP_docstring. + + TEMP TEMP + """ + #| - __init__ + self.tmp = "TMP AWS Class Atribute!!!!!" + + try: + self.TRI_PATH = os.environ["TRI_PATH"] + except: + pass + #__| + + + def create_symlinks(self): + """ + Attempts to create symlinks in all subfolders whose names starts with _ + """ + #| - create_symlinks + # root_dir = '.' + root_dir = os.getcwd() + for dir_name, subdirList, fileList in os.walk(root_dir): + dir_name_i = dir_name.split("/")[-1] + + if dir_name_i[0] == "_" and dir_name_i[1].isdigit() == True: + # print(dir_name) + dest = dir_name + "/simulation" + + source = deepcopy(dir_name) + source = source.replace("/model/", "/simulation/", 1) + + print(source) + print(dest) + print("____") + force_symlink(source, dest) + + # print("Found directory: %s" % dirName) + # for fname in fileList: + # print('\t%s' % fname) + #__| + + + def create_symlink(self, path=None): + """ + """ + #| - create_symlink + + # def force_symlink(file1, file2): + # #| - force_symlink + # try: + # os.symlink(file1, file2) + # except OSError, e: + # if e.errno == errno.EEXIST: + # os.unlink(file2) + # os.symlink(file1, file2) + # #__| + + if path == None: + path = os.getcwd() + else: + pass + + dest = path + "/simulation" + print(dest) + + source = deepcopy(path) + source = source.replace("/model/", "/simulation/", 1) + force_symlink(source, dest) + + #__| + + #__| *************************************************************************** + +# NOT USEFUL FOR THIS TO BE CHILD CLASS -- FIX!!!!!!!!!!!! +class AWS_Class(DFT_Jobs_Setup): + """Summary line. + + TEMP + """ + #| - AWS_Class ***************************************************************** + def __init__(self, system="sherlock"): + """TMP_docstring. + + TEMP TEMP + """ + #| - __init__ + DFT_Jobs_Setup.__init__(self, system=system) + self.tmp = "TMP AWS Class Atribute!!!!!" + + try: + self.TRI_PATH = os.environ["TRI_PATH"] + except: + pass + #__| + + + def create_symlinks(self): + """Creates symlinks for every job revision in job directory. + + TEMP TEMP + """ + #| - create_symlinks + + def force_symlink(file1, file2): + #| - force_symlink + try: + os.symlink(file1, file2) + except OSError, e: + if e.errno == errno.EEXIST: + os.unlink(file2) + os.symlink(file1, file2) + #__| + + for job in self.job_var_lst: + path = self.var_lst_to_path(job) + path = self.root_dir + "/" + path + + for folder in os.walk(path).next()[1]: + path_i = path + folder + dest = path_i + "/simulation" + + source = deepcopy(path_i) + source = source.replace("/model/", "/simulation/", 1) + + force_symlink(source, dest) + #__| + + #__| *************************************************************************** + + + + + +#| - DEPRECATED METHODS + +# def list_jobs(self, status="RUNNING", queue="small"): +# """ +# """ +# #| - list_jobs +# bash_command = "aws batch list-jobs --job-status {} --job-queue {} > aws_list_jobs.json".format(status, queue) +# run_bash = subprocess.check_output(bash_command, shell=True) #TEMP +# data = json.load(open("aws_list_jobs.json")) +# +# job_id_list = [] +# for job in data["jobSummaryList"]: +# job_id_list.append(job["jobId"]) +# +# return(job_id_list) +# +# #__| + + +#__| diff --git a/bader_charge/bader.py b/bader_charge/bader.py index 676a22b..e24addb 100644 --- a/bader_charge/bader.py +++ b/bader_charge/bader.py @@ -1,347 +1,347 @@ -#!/usr/bin/env python - -"""Bader charge analysis methods. - -Author(s): Colin Dickins wrote most of this; Raul A. Flores -""" - -#| - IMPORT MODULES -import sys -import os - -import pickle as pickle -import copy - -import numpy as np -# from ase.io import write -from ase import io -#__| - - -def bader( - atoms, - spinpol=False, - outdir=None, - run_exec=True, - run_exec_2=True, - convert_charge_den=True, - cleanup=True, - dft_code="QE", - ): - """Perform bader charge analysis on atoms. - - Calculate charge density using atoms.calc, calculate bader charges on each - atom in atoms, and assign to atom.data["bader_charge"]. - - If spinpol: also assign atom.data["bader_magmom"]. - - Args: - atoms: ASE atoms object - spinpol: Spin polarized calculation - outdir: Output directory location - run_exec: Whether to run bader executable or just create preliminary - file (some clusters don't/can't have the bader fortran code) - """ - #| - bader - mess = "Executing Bader Analysis " - mess += "*****************************************************" - print(mess); sys.stdout.flush() - - #| - Don't Run Bader Executable on AWS - if "COMPENV" not in os.environ: - print("COMPENV env. var. doesn't exits, probably in AWS?") - print("Bader executable turned off") - - run_exec = False - else: - pass - #__| - - if not os.path.exists("dir_bader"): - os.makedirs("dir_bader") - - calc = atoms.calc - - #| - Using Spin Polarization - if spinpol: - - #| - Spin up - if convert_charge_den: - cd2cube(atoms, spin="up") - if run_exec: - bader_exec( - atoms, - spin="up", - execute_bader=run_exec_2, - clean_up=cleanup, - dft_code=dft_code, - ) - - #__| - - #| - Spin down - if convert_charge_den: - cd2cube(atoms, spin="down") - if run_exec: - bader_exec( - atoms, - spin="down", - execute_bader=run_exec_2, - clean_up=cleanup, - dft_code=dft_code, - ) - #__| - - print("BADER MAGMOMS: " + str(atoms.get_initial_magnetic_moments())) - - #__| - - #| - Not Spin Polarized - else: - if convert_charge_den: - cd2cube(atoms) - if run_exec: - bader_exec( - atoms, - spin="", - clean_up=cleanup, - execute_bader=run_exec_2, - dft_code=dft_code, - ) - #__| - - print("BADER CHARGES: " + str(atoms.get_initial_charges())) - - # if run_exec: - # io.write("dir_bader/bader.traj", atoms) - - if outdir: - os.system("rm %s/charge.log" % outdir) - - #| - Writing 2 Atoms Objects with mogmoms and charges written - - if run_exec: - # Charges written to init_charges - atoms_cpy1 = copy.deepcopy(atoms) - bader_charges = atoms_cpy1.info["bader_charges"] - atoms_cpy1.set_initial_charges(bader_charges) - atoms_cpy1.write("dir_bader/bader_charges.traj") - - if spinpol: - atoms_cpy2 = copy.deepcopy(atoms) - bader_magmoms = atoms_cpy2.info["bader_magmoms"] - atoms_cpy2.set_initial_charges(bader_magmoms) - atoms_cpy2.write("dir_bader/bader_magmoms.traj") - - # atoms.set_calculator(calc=calc) - atoms.write("dir_bader/out.traj") - #__| - - #__| - - -def cd2cube(atoms, spin=""): - """Convert ASE charge density file to cube format. - - Takes charge density pickle file from ase-qe and writes a cube file ready - for bader analysis to the current directory - - Args: - atoms: - spin: - """ - #| - cd2cube - # cd2cube(atoms.calc.extract_charge_density(spin="up")[2], atoms) - - if spin == "": - cd = atoms.calc.extract_charge_density()[2] - else: - cd = atoms.calc.extract_charge_density(spin=spin)[2] - - file_name = "density" + spin + ".cube" - - nx, ny, nz = np.shape(cd) - #cut away periodic image planes to correct QE output - u = nx - 1 - v = ny - 1 - w = nz - 1 - cd2 = np.empty((u, v, w), np.float) - for i in range(u): - for j in range(v): - cd2[i][j][:] = cd[i][j][:w] - - io.write(file_name, atoms, data=cd2) - - # edit density.cube grid size if odd number of grid points to - # correct for old versions of ASE - bohr = 0.52917721092 - cell = atoms.get_cell() - da = cell[0] / (u * bohr) - db = cell[1] / (v * bohr) - dc = cell[2] / (w * bohr) - - f = open(file_name, "r") - lines = f.readlines() - f.close() - - line3 = "%5.0f %.6f %.6f %.6f\n" % (u, da[0], da[1], da[2]) - line4 = "%5.0f %.6f %.6f %.6f\n" % (v, db[0], db[1], db[2]) - line5 = "%5.0f %.6f %.6f %.6f\n" % (w, dc[0], dc[1], dc[2]) - - lines[3] = line3 - lines[4] = line4 - lines[5] = line5 - - f = open(file_name, "w") - f.writelines(lines) - f.close() - #__| - -def cleanup(suffix="", save_cube=True): - """Cleanup unnecessary and/or large file after routine completes. - - Args: - suffix: - save_cube: - """ - #| - cleanup - if not os.path.exists("dir_bader"): - os.makedirs("dir_bader") - - if not save_cube: - os.system("rm density" + suffix + ".cube") - else: - os.system("mv density" + suffix + ".cube dir_bader") - - os.system("mv ACF.dat dir_bader/ACF%s.dat" % suffix) - # os.system("rm AVF.dat") - # os.system("rm BCF.dat") - os.system("mv bader.out dir_bader/bader%s.out" % suffix) - - os.system("mv AVF.dat dir_bader/AVF.dat") - os.system("mv BCF.dat dir_bader/BCF.dat") - #__| - -def bader_exec( - atoms, - spin="", - execute_bader=True, - clean_up=True, - dft_code="QE", # 'VASP' or 'QE' - ): - """Run bader executable on cube density file and process data. - - Args: - atoms: - spin: - Spin component to process | "", "up", "down" - - """ - #| - bader_exec - if execute_bader: - bash_comm = "bader density" + spin + ".cube >> bader.out" - os.system(bash_comm) - - if dft_code == "VASP": - if execute_bader: - bash_comm = "chgsum.pl AECCAR0 AECCAR2" - os.system(bash_comm) - bash_comm = "bader CHGCAR -ref CHGCAR_sum" - os.system(bash_comm) - - #| - Spin Polarlized Calculation - if spin == "up": - f = open("ACF.dat"); lines = f.readlines(); f.close() - for i, line in enumerate(lines[2:-4]): - line = line.split() - atoms[i].magmom = float(line[4]) - atoms[i].charge = -float(line[4]) - if clean_up: - cleanup(suffix=spin) - - elif spin == "down": - f = open("ACF.dat"); lines = f.readlines(); f.close() - - magmom_list = [] - charge_list = [] - for i, line in enumerate(lines[2:-4]): - line = line.split() - atoms[i].magmom -= float(line[4]) - - #| - Getting number of valence electrons - calc_has_get_nvalence = getattr(atoms.calc, "get_nvalence", None) - if calc_has_get_nvalence: - val_i = atoms.calc.get_nvalence()[1][atoms[i].symbol] - else: - val_i = valence_dict.get(atoms[i].symbol, None) - - assert val_i is not None, "Can't find # of valence electrons!!" - #__| - - atoms[i].charge -= float(line[4]) - val_i - - magmom_list.append(atoms[i].magmom) - charge_list.append(atoms[i].charge) - - atoms.info.update({"magmom_set": True}) - atoms.info.update({"bader_magmoms": magmom_list}) - atoms.info.update({"bader_charges": charge_list}) - - #| - Write data to file - with open("dir_bader/bader_charges_magmoms.pickle", "w") as fle: - pickle.dump( - {"charge_list": charge_list, "magmom_list": magmom_list}, - fle, - ) - #__| - - if clean_up: - cleanup(suffix=spin) - #__| - - #| - Non-Spin Polarized Calculation - elif spin == "": - charge_list = [] - f = open("ACF.dat"); lines = f.readlines(); f.close() - for i, line in enumerate(lines[2:-4]): - line = line.split() - - #| - Getting number of valence electrons - calc_has_get_nvalence = getattr(atoms.calc, "get_nvalence", None) - if calc_has_get_nvalence: - charge_i = atoms.calc.get_nvalence()[1][atoms[i].symbol] - else: - charge_i = valence_dict.get(atoms[i].symbol, None) - - assert charge_i is not None, "Can't find # of valence electrons!!" - #__| - - # charge_i = atoms.calc.get_nvalence()[1][atoms[i].symbol] - - atoms[i].charge = charge_i - float(line[4]) - charge_list.append(atoms[i].charge) - - atoms.info.update({"bader_charges": charge_list}) - - #| - Write data to file - with open("dir_bader/bader_charges_magmoms.pickle", "w") as fle: - pickle.dump( - {"charge_list": charge_list, "magmom_list": None}, - fle, - ) - #__| - - cleanup() - #__| - - #__| - - -# From VASP PBE -valence_dict = { - "O": 6, - "Ir": 9, - "Cr": 6, - "Ti": 4, - "Ni": 10, - } +#!/usr/bin/env python + +"""Bader charge analysis methods. + +Author(s): Colin Dickins wrote most of this; Raul A. Flores +""" + +#| - IMPORT MODULES +import sys +import os + +import pickle as pickle +import copy + +import numpy as np +# from ase.io import write +from ase import io +#__| + + +def bader( + atoms, + spinpol=False, + outdir=None, + run_exec=True, + run_exec_2=True, + convert_charge_den=True, + cleanup=True, + dft_code="QE", + ): + """Perform bader charge analysis on atoms. + + Calculate charge density using atoms.calc, calculate bader charges on each + atom in atoms, and assign to atom.data["bader_charge"]. + + If spinpol: also assign atom.data["bader_magmom"]. + + Args: + atoms: ASE atoms object + spinpol: Spin polarized calculation + outdir: Output directory location + run_exec: Whether to run bader executable or just create preliminary + file (some clusters don't/can't have the bader fortran code) + """ + #| - bader + mess = "Executing Bader Analysis " + mess += "*****************************************************" + print(mess); sys.stdout.flush() + + #| - Don't Run Bader Executable on AWS + if "COMPENV" not in os.environ: + print("COMPENV env. var. doesn't exits, probably in AWS?") + print("Bader executable turned off") + + run_exec = False + else: + pass + #__| + + if not os.path.exists("dir_bader"): + os.makedirs("dir_bader") + + calc = atoms.calc + + #| - Using Spin Polarization + if spinpol: + + #| - Spin up + if convert_charge_den: + cd2cube(atoms, spin="up") + if run_exec: + bader_exec( + atoms, + spin="up", + execute_bader=run_exec_2, + clean_up=cleanup, + dft_code=dft_code, + ) + + #__| + + #| - Spin down + if convert_charge_den: + cd2cube(atoms, spin="down") + if run_exec: + bader_exec( + atoms, + spin="down", + execute_bader=run_exec_2, + clean_up=cleanup, + dft_code=dft_code, + ) + #__| + + print("BADER MAGMOMS: " + str(atoms.get_initial_magnetic_moments())) + + #__| + + #| - Not Spin Polarized + else: + if convert_charge_den: + cd2cube(atoms) + if run_exec: + bader_exec( + atoms, + spin="", + clean_up=cleanup, + execute_bader=run_exec_2, + dft_code=dft_code, + ) + #__| + + print("BADER CHARGES: " + str(atoms.get_initial_charges())) + + # if run_exec: + # io.write("dir_bader/bader.traj", atoms) + + if outdir: + os.system("rm %s/charge.log" % outdir) + + #| - Writing 2 Atoms Objects with mogmoms and charges written + + if run_exec: + # Charges written to init_charges + atoms_cpy1 = copy.deepcopy(atoms) + bader_charges = atoms_cpy1.info["bader_charges"] + atoms_cpy1.set_initial_charges(bader_charges) + atoms_cpy1.write("dir_bader/bader_charges.traj") + + if spinpol: + atoms_cpy2 = copy.deepcopy(atoms) + bader_magmoms = atoms_cpy2.info["bader_magmoms"] + atoms_cpy2.set_initial_charges(bader_magmoms) + atoms_cpy2.write("dir_bader/bader_magmoms.traj") + + # atoms.set_calculator(calc=calc) + atoms.write("dir_bader/out.traj") + #__| + + #__| + + +def cd2cube(atoms, spin=""): + """Convert ASE charge density file to cube format. + + Takes charge density pickle file from ase-qe and writes a cube file ready + for bader analysis to the current directory + + Args: + atoms: + spin: + """ + #| - cd2cube + # cd2cube(atoms.calc.extract_charge_density(spin="up")[2], atoms) + + if spin == "": + cd = atoms.calc.extract_charge_density()[2] + else: + cd = atoms.calc.extract_charge_density(spin=spin)[2] + + file_name = "density" + spin + ".cube" + + nx, ny, nz = np.shape(cd) + #cut away periodic image planes to correct QE output + u = nx - 1 + v = ny - 1 + w = nz - 1 + cd2 = np.empty((u, v, w), np.float) + for i in range(u): + for j in range(v): + cd2[i][j][:] = cd[i][j][:w] + + io.write(file_name, atoms, data=cd2) + + # edit density.cube grid size if odd number of grid points to + # correct for old versions of ASE + bohr = 0.52917721092 + cell = atoms.get_cell() + da = cell[0] / (u * bohr) + db = cell[1] / (v * bohr) + dc = cell[2] / (w * bohr) + + f = open(file_name, "r") + lines = f.readlines() + f.close() + + line3 = "%5.0f %.6f %.6f %.6f\n" % (u, da[0], da[1], da[2]) + line4 = "%5.0f %.6f %.6f %.6f\n" % (v, db[0], db[1], db[2]) + line5 = "%5.0f %.6f %.6f %.6f\n" % (w, dc[0], dc[1], dc[2]) + + lines[3] = line3 + lines[4] = line4 + lines[5] = line5 + + f = open(file_name, "w") + f.writelines(lines) + f.close() + #__| + +def cleanup(suffix="", save_cube=True): + """Cleanup unnecessary and/or large file after routine completes. + + Args: + suffix: + save_cube: + """ + #| - cleanup + if not os.path.exists("dir_bader"): + os.makedirs("dir_bader") + + if not save_cube: + os.system("rm density" + suffix + ".cube") + else: + os.system("mv density" + suffix + ".cube dir_bader") + + os.system("mv ACF.dat dir_bader/ACF%s.dat" % suffix) + # os.system("rm AVF.dat") + # os.system("rm BCF.dat") + os.system("mv bader.out dir_bader/bader%s.out" % suffix) + + os.system("mv AVF.dat dir_bader/AVF.dat") + os.system("mv BCF.dat dir_bader/BCF.dat") + #__| + +def bader_exec( + atoms, + spin="", + execute_bader=True, + clean_up=True, + dft_code="QE", # 'VASP' or 'QE' + ): + """Run bader executable on cube density file and process data. + + Args: + atoms: + spin: + Spin component to process | "", "up", "down" + + """ + #| - bader_exec + if execute_bader: + bash_comm = "bader density" + spin + ".cube >> bader.out" + os.system(bash_comm) + + if dft_code == "VASP": + if execute_bader: + bash_comm = "chgsum.pl AECCAR0 AECCAR2" + os.system(bash_comm) + bash_comm = "bader CHGCAR -ref CHGCAR_sum" + os.system(bash_comm) + + #| - Spin Polarlized Calculation + if spin == "up": + f = open("ACF.dat"); lines = f.readlines(); f.close() + for i, line in enumerate(lines[2:-4]): + line = line.split() + atoms[i].magmom = float(line[4]) + atoms[i].charge = -float(line[4]) + if clean_up: + cleanup(suffix=spin) + + elif spin == "down": + f = open("ACF.dat"); lines = f.readlines(); f.close() + + magmom_list = [] + charge_list = [] + for i, line in enumerate(lines[2:-4]): + line = line.split() + atoms[i].magmom -= float(line[4]) + + #| - Getting number of valence electrons + calc_has_get_nvalence = getattr(atoms.calc, "get_nvalence", None) + if calc_has_get_nvalence: + val_i = atoms.calc.get_nvalence()[1][atoms[i].symbol] + else: + val_i = valence_dict.get(atoms[i].symbol, None) + + assert val_i is not None, "Can't find # of valence electrons!!" + #__| + + atoms[i].charge -= float(line[4]) - val_i + + magmom_list.append(atoms[i].magmom) + charge_list.append(atoms[i].charge) + + atoms.info.update({"magmom_set": True}) + atoms.info.update({"bader_magmoms": magmom_list}) + atoms.info.update({"bader_charges": charge_list}) + + #| - Write data to file + with open("dir_bader/bader_charges_magmoms.pickle", "w") as fle: + pickle.dump( + {"charge_list": charge_list, "magmom_list": magmom_list}, + fle, + ) + #__| + + if clean_up: + cleanup(suffix=spin) + #__| + + #| - Non-Spin Polarized Calculation + elif spin == "": + charge_list = [] + f = open("ACF.dat"); lines = f.readlines(); f.close() + for i, line in enumerate(lines[2:-4]): + line = line.split() + + #| - Getting number of valence electrons + calc_has_get_nvalence = getattr(atoms.calc, "get_nvalence", None) + if calc_has_get_nvalence: + charge_i = atoms.calc.get_nvalence()[1][atoms[i].symbol] + else: + charge_i = valence_dict.get(atoms[i].symbol, None) + + assert charge_i is not None, "Can't find # of valence electrons!!" + #__| + + # charge_i = atoms.calc.get_nvalence()[1][atoms[i].symbol] + + atoms[i].charge = charge_i - float(line[4]) + charge_list.append(atoms[i].charge) + + atoms.info.update({"bader_charges": charge_list}) + + #| - Write data to file + with open("dir_bader/bader_charges_magmoms.pickle", "w") as fle: + pickle.dump( + {"charge_list": charge_list, "magmom_list": None}, + fle, + ) + #__| + + cleanup() + #__| + + #__| + + +# From VASP PBE +valence_dict = { + "O": 6, + "Ir": 9, + "Cr": 6, + "Ti": 4, + "Ni": 10, + } diff --git a/classical_methods/lennard_jones.py b/classical_methods/lennard_jones.py index 196fe71..51a9fa7 100644 --- a/classical_methods/lennard_jones.py +++ b/classical_methods/lennard_jones.py @@ -1,174 +1,174 @@ - -#!/usr/bin/env python - -"""Wrapper code around ASAP & ASE LJ implementation. - -Author: Raul A. Flores -""" - -#| - Import Modules -import gc -import math -import numpy as np # import pandas as pd -import collections -from pymatgen.core.periodic_table import Element -from asap3 import LennardJones -#__| - -def lennard_jones_sp( - epsilon, - sigma, - atoms, - modified_lj=True, - normalize_per_atom=True, - return_quantity="energy", # 'energy', 'forces', 'both', 'energy&forces' - ): - """Calculate single-point energy and forces with Lennard Jones force field. - - Because the order of the elements must be internally consistent, the - convention will be that the element list goes from smalles to largest - atomic number. - - Args: - epsilon: - sigma: - atoms: - modified_lj: - return: - """ - #| - lennard_jones_sp - atomic_num_list = atoms.get_atomic_numbers() - atomic_num_list = list(set(atomic_num_list)) - atomic_num_list.sort() - - atomic_type_num_dict = collections.Counter(atomic_num_list) - - orig_num_of_atoms = atoms.get_number_of_atoms() - - #| - Filter Relevant LJ Parameters - row_col_to_keep = [ - Element.from_Z(atomic_num).name - for - atomic_num - in - atomic_num_list - ] - - epsilon = epsilon.loc[row_col_to_keep] - epsilon = epsilon[row_col_to_keep] - - sigma = sigma.loc[row_col_to_keep] - sigma = sigma[row_col_to_keep] - - # epsilon = epsilon.values - # sigma = sigma.values - #__| - - calc = LennardJones( - list(atomic_type_num_dict), - epsilon.values, - sigma.values, - rCut=-1, - modified=modified_lj, - ) - - #| - Repeat Unit Cell - repeat_unit_cell = repeat_unit_cell_ASAP(atoms, sigma) - - atoms = atoms.repeat(repeat_unit_cell) - #__| - - atoms.set_calculator(calc) - - #| - Energy - lj_energy = atoms.get_potential_energy() - lj_energy_per_atom = lj_energy / atoms.get_number_of_atoms() - - # This is total energy w.r.t. the original number of atoms in the - # computational cell (since the cell was repeated) - lj_total_energy = lj_energy_per_atom * orig_num_of_atoms - - if normalize_per_atom: - lj_energy = lj_energy_per_atom - - else: - lj_energy = lj_total_energy - #__| - - #| - Forces -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* - # COMBAK - # Find a way to decrease the number of atoms again - lj_forces = atoms.get_forces() - - #__| - - if return_quantity == "energy": - out = lj_energy - elif return_quantity == "forces": - out = lj_forces - elif return_quantity == "both" or return_quantity == "both": - out = (lj_energy, lj_forces) - - return(out) - #__| - -def repeat_unit_cell_ASAP(atoms, sigma): - """Return repeat array such that ASAP doesn't complain about r_cut. - - Args: - atoms - """ - #| - repeat_unit_cell_ASAP - - def calc_cell_heights(unit_cell): - """Calculate heights of cell. - - Obtained code from ASAP NormalAtoms.invert_cell - - Args: - unit_cell: - sigma: - """ - #| - calc_cell_heights - determinant = np.cross( - unit_cell[0], - unit_cell[1], - ) - determinant = abs(determinant.dot(unit_cell[2])) - - heights = [] - for i_ind, unit_vect_i in enumerate(unit_cell): - inv = np.cross( - unit_cell[(i_ind + 1) % 3], - unit_cell[(i_ind + 2) % 3], - ) - - den = math.sqrt(np.dot(inv, inv)) - height_i = determinant / den - heights.append(height_i) - - return(heights) - #__| - - heights = calc_cell_heights(atoms.cell) - - # The cut-off length is internally set by ASAP to 3 * 2 * (max_sigma_value) - - # max_sigma = sigma.flatten().max() - max_sigma = sigma.values.flatten().max() - - cut_off_length = 3 * 2 * max_sigma - - #| - Repeat Unit Cell - repeat_unit_cell = [] - for i_ind, height_i in enumerate(heights): - if height_i < cut_off_length: - cell_repeat_fact = math.ceil(cut_off_length / height_i) - cell_repeat_fact = int(cell_repeat_fact) - repeat_unit_cell.append(cell_repeat_fact) - else: - repeat_unit_cell.append(1) - #__| - - return(repeat_unit_cell) - #__| + +#!/usr/bin/env python + +"""Wrapper code around ASAP & ASE LJ implementation. + +Author: Raul A. Flores +""" + +#| - Import Modules +import gc +import math +import numpy as np # import pandas as pd +import collections +from pymatgen.core.periodic_table import Element +from asap3 import LennardJones +#__| + +def lennard_jones_sp( + epsilon, + sigma, + atoms, + modified_lj=True, + normalize_per_atom=True, + return_quantity="energy", # 'energy', 'forces', 'both', 'energy&forces' + ): + """Calculate single-point energy and forces with Lennard Jones force field. + + Because the order of the elements must be internally consistent, the + convention will be that the element list goes from smalles to largest + atomic number. + + Args: + epsilon: + sigma: + atoms: + modified_lj: + return: + """ + #| - lennard_jones_sp + atomic_num_list = atoms.get_atomic_numbers() + atomic_num_list = list(set(atomic_num_list)) + atomic_num_list.sort() + + atomic_type_num_dict = collections.Counter(atomic_num_list) + + orig_num_of_atoms = atoms.get_number_of_atoms() + + #| - Filter Relevant LJ Parameters + row_col_to_keep = [ + Element.from_Z(atomic_num).name + for + atomic_num + in + atomic_num_list + ] + + epsilon = epsilon.loc[row_col_to_keep] + epsilon = epsilon[row_col_to_keep] + + sigma = sigma.loc[row_col_to_keep] + sigma = sigma[row_col_to_keep] + + # epsilon = epsilon.values + # sigma = sigma.values + #__| + + calc = LennardJones( + list(atomic_type_num_dict), + epsilon.values, + sigma.values, + rCut=-1, + modified=modified_lj, + ) + + #| - Repeat Unit Cell + repeat_unit_cell = repeat_unit_cell_ASAP(atoms, sigma) + + atoms = atoms.repeat(repeat_unit_cell) + #__| + + atoms.set_calculator(calc) + + #| - Energy + lj_energy = atoms.get_potential_energy() + lj_energy_per_atom = lj_energy / atoms.get_number_of_atoms() + + # This is total energy w.r.t. the original number of atoms in the + # computational cell (since the cell was repeated) + lj_total_energy = lj_energy_per_atom * orig_num_of_atoms + + if normalize_per_atom: + lj_energy = lj_energy_per_atom + + else: + lj_energy = lj_total_energy + #__| + + #| - Forces -*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-* + # COMBAK + # Find a way to decrease the number of atoms again + lj_forces = atoms.get_forces() + + #__| + + if return_quantity == "energy": + out = lj_energy + elif return_quantity == "forces": + out = lj_forces + elif return_quantity == "both" or return_quantity == "both": + out = (lj_energy, lj_forces) + + return(out) + #__| + +def repeat_unit_cell_ASAP(atoms, sigma): + """Return repeat array such that ASAP doesn't complain about r_cut. + + Args: + atoms + """ + #| - repeat_unit_cell_ASAP + + def calc_cell_heights(unit_cell): + """Calculate heights of cell. + + Obtained code from ASAP NormalAtoms.invert_cell + + Args: + unit_cell: + sigma: + """ + #| - calc_cell_heights + determinant = np.cross( + unit_cell[0], + unit_cell[1], + ) + determinant = abs(determinant.dot(unit_cell[2])) + + heights = [] + for i_ind, unit_vect_i in enumerate(unit_cell): + inv = np.cross( + unit_cell[(i_ind + 1) % 3], + unit_cell[(i_ind + 2) % 3], + ) + + den = math.sqrt(np.dot(inv, inv)) + height_i = determinant / den + heights.append(height_i) + + return(heights) + #__| + + heights = calc_cell_heights(atoms.cell) + + # The cut-off length is internally set by ASAP to 3 * 2 * (max_sigma_value) + + # max_sigma = sigma.flatten().max() + max_sigma = sigma.values.flatten().max() + + cut_off_length = 3 * 2 * max_sigma + + #| - Repeat Unit Cell + repeat_unit_cell = [] + for i_ind, height_i in enumerate(heights): + if height_i < cut_off_length: + cell_repeat_fact = math.ceil(cut_off_length / height_i) + cell_repeat_fact = int(cell_repeat_fact) + repeat_unit_cell.append(cell_repeat_fact) + else: + repeat_unit_cell.append(1) + #__| + + return(repeat_unit_cell) + #__| diff --git a/colors/colors.py b/colors/colors.py index d44bc65..f6c5996 100644 --- a/colors/colors.py +++ b/colors/colors.py @@ -1,147 +1,147 @@ -#!/usr/bin/env python - -"""Classes and methods to encapulate colors for plotting. - -Author: Raul A. Flores -""" - -#| - Import Modules -import seaborn as sns - -import colorlover as cl -#__| - -color_list = [ - "rgb(113,166,190)", - "rgb(145,209,79)", - "rgb(124,78,196)", - "rgb(203,169,87)", - "rgb(200,72,150)", - "rgb(130,204,159)", - "rgb(190,82,63)", - "rgb(80,51,82)", - "rgb(81,92,54)", - "rgb(192,151,188)", - ] - - -#| - My Sets of Contrasting Color Schemes -color_palette_1 = [ - "rgb(198,158,61)", - "rgb(238,88,121)", - "rgb(236,186,51)", - "rgb(237,101,67)", - "rgb(222,134,54)", - ] - -color_palette_2 = [ - "rgb(181,149,213)", - "rgb(103,76,204)", - "rgb(97,166,201)", - "rgb(185,76,198)", - "rgb(93,80,139)", - ] - -#__| - -# palette = sns.color_palette(None, 3) -# palette -# -# current_palette = sns.color_palette() -# sns.palplot(current_palette) - -def generate_color_palette( - palette_name="husl", - bins=10, - ): - """ - - https://seaborn.pydata.org/tutorial/color_palettes.html - - Args: - palette_name: - bins: - Number of colors to produce - """ - #| - generate_color_palette - # tmp = sns.palplot(sns.color_palette(palette_name, bins)) - colors = sns.color_palette(palette_name, bins) - - return(colors) - #__| - - - - -def rgb_to_hex(rgb_tuple): - """ - """ - #| - rgb_to_hex - r = int(rgb_tuple[0]) - g = int(rgb_tuple[1]) - b = int(rgb_tuple[2]) - - def clamp(x): - return(max(0, min(x, 255))) - - hex_rep = "#{0:02x}{1:02x}{2:02x}".format( - clamp(r), - clamp(g), - clamp(b), - ) - - return(hex_rep) - #__| - -def color_scale_interp( - input_num, - max_num, - min_num, - color_mesh_size=80, - hex_mode=True, - ): - """ - """ - #| - color_scale_interp -# cl.scales["8"]["seq"]["Purples"] - - black_white_cs = [ - 'rgb(0,0,0)', - 'rgb(255,255,255)', - ] - - black_red_cs = [ - 'rgb(0,0,0)', - 'rgb(255,0,0)', - ] - - color_scale_i = black_red_cs - - color_scale_i = cl.scales["8"]["seq"]["Greys"][::-1] -# color_scale_i = cl.scales["8"]["seq"]["Purples"] -# color_scale_i = cl.scales['3']['div']['RdYlBu'] - - color_scale = cl.interp( - color_scale_i, - color_mesh_size, - ) - - color_scale = cl.to_rgb(color_scale) - - # Converting RGB string representatino to tuple - color_scale = cl.to_numeric(color_scale) - - input_norm = ((input_num - min_num) / (max_num - min_num)) - - cs_index = round(input_norm * len(color_scale)) - 1 - if cs_index == -1: - cs_index = 0 - - color_out = color_scale[cs_index] - - if hex_mode: - color_out = rgb_to_hex(color_out) - - - return(color_out) - #__| +#!/usr/bin/env python + +"""Classes and methods to encapulate colors for plotting. + +Author: Raul A. Flores +""" + +#| - Import Modules +import seaborn as sns + +import colorlover as cl +#__| + +color_list = [ + "rgb(113,166,190)", + "rgb(145,209,79)", + "rgb(124,78,196)", + "rgb(203,169,87)", + "rgb(200,72,150)", + "rgb(130,204,159)", + "rgb(190,82,63)", + "rgb(80,51,82)", + "rgb(81,92,54)", + "rgb(192,151,188)", + ] + + +#| - My Sets of Contrasting Color Schemes +color_palette_1 = [ + "rgb(198,158,61)", + "rgb(238,88,121)", + "rgb(236,186,51)", + "rgb(237,101,67)", + "rgb(222,134,54)", + ] + +color_palette_2 = [ + "rgb(181,149,213)", + "rgb(103,76,204)", + "rgb(97,166,201)", + "rgb(185,76,198)", + "rgb(93,80,139)", + ] + +#__| + +# palette = sns.color_palette(None, 3) +# palette +# +# current_palette = sns.color_palette() +# sns.palplot(current_palette) + +def generate_color_palette( + palette_name="husl", + bins=10, + ): + """ + + https://seaborn.pydata.org/tutorial/color_palettes.html + + Args: + palette_name: + bins: + Number of colors to produce + """ + #| - generate_color_palette + # tmp = sns.palplot(sns.color_palette(palette_name, bins)) + colors = sns.color_palette(palette_name, bins) + + return(colors) + #__| + + + + +def rgb_to_hex(rgb_tuple): + """ + """ + #| - rgb_to_hex + r = int(rgb_tuple[0]) + g = int(rgb_tuple[1]) + b = int(rgb_tuple[2]) + + def clamp(x): + return(max(0, min(x, 255))) + + hex_rep = "#{0:02x}{1:02x}{2:02x}".format( + clamp(r), + clamp(g), + clamp(b), + ) + + return(hex_rep) + #__| + +def color_scale_interp( + input_num, + max_num, + min_num, + color_mesh_size=80, + hex_mode=True, + ): + """ + """ + #| - color_scale_interp +# cl.scales["8"]["seq"]["Purples"] + + black_white_cs = [ + 'rgb(0,0,0)', + 'rgb(255,255,255)', + ] + + black_red_cs = [ + 'rgb(0,0,0)', + 'rgb(255,0,0)', + ] + + color_scale_i = black_red_cs + + color_scale_i = cl.scales["8"]["seq"]["Greys"][::-1] +# color_scale_i = cl.scales["8"]["seq"]["Purples"] +# color_scale_i = cl.scales['3']['div']['RdYlBu'] + + color_scale = cl.interp( + color_scale_i, + color_mesh_size, + ) + + color_scale = cl.to_rgb(color_scale) + + # Converting RGB string representatino to tuple + color_scale = cl.to_numeric(color_scale) + + input_norm = ((input_num - min_num) / (max_num - min_num)) + + cs_index = round(input_norm * len(color_scale)) - 1 + if cs_index == -1: + cs_index = 0 + + color_out = color_scale[cs_index] + + if hex_mode: + color_out = rgb_to_hex(color_out) + + + return(color_out) + #__| diff --git a/dft_job_automat/__init__.py b/dft_job_automat/__init__.py index 8958fc2..0986fb0 100644 --- a/dft_job_automat/__init__.py +++ b/dft_job_automat/__init__.py @@ -1 +1 @@ -#TEMP TEMP 171030 +#TEMP TEMP 171030 diff --git a/dft_job_automat/__old__.py b/dft_job_automat/__old__.py index dc3b3ba..ffe6ee7 100644 --- a/dft_job_automat/__old__.py +++ b/dft_job_automat/__old__.py @@ -1,203 +1,203 @@ -#| - job_analysis - -#| - DEPRECATED METHODS -# def max_force(self, path): -# """ -# """ -# #| - max_force -# with open(path + "/simulation/qn.log", "r") as file: -# max_f = file.readlines()[-1].split(" ")[-1] -# return(float(max_f)) -# #__| - -# def job_id_names(self): -# """ -# """ -# #| - job_id_names -# try: -# f = open("job_id_names", "r") -# job_id_data = pickle.load(f) -# f.close() -# -# id_list = job_id_data[0] -# name_list = job_id_data[1] -# -# self.data_frame["job_id"] = id_list -# self.data_frame["job_name"] = name_list -# except: -# print("Couldn't parse job_id_names file") -# -# #__| -#__| - -#__| - -#| - job_setup - -#| - __old__ - -#| - TEMP -# def __parse_cluster_type__(self): -# """ -# """ -# #| - __parse_cluster_type__ -# clusters_dict = { -# "aws": "AWSCluster", -# "slac": "SLACCluster", -# "sherlock": "SherlockCluster", -# } -# -# cluster_sys = os.environ.get("COMPENV") -# -# if cluster_sys in clusters_dict: -# package = "dft_job_automat.compute_env" -# name = clusters_dict[cluster_sys] -# cluster = getattr(__import__(package, fromlist=[name]), name) -# -# self.cluster_sys = cluster_sys -# self.cluster = cluster -# # from dft_job_automat.compute_env import clusters_dict[cluster_sys] -# return(cluster_sys) -#__| - - -#__| - -#__| - -#| - job_manager - -#| - TEMP - Old Restart Job Method -# def restart_job(self, prev_rev_file_list=[], root_dir_file_list=[], -# revision="Auto"): -# """Restart job from previous run -# -# -# variable_lst: -# Produced from DFT_Jobs_Setup.job_var_lst. -# -# Args: -# model_file: -# "Auto" | -# atoms_file: -# Name of atoms object file from previous run -# revision: -# Job revision number from which the job will be restarted from. -# "Auto" | Restarts the job from the most recent job revision. -# """ -# #| - restart_job -# for job in self.job_var_lst: -# path = self.var_lst_to_path(job) -# -# rev_n = self.job_revision_number(job) -# -# if revision == "Auto": -# prev_path = path + "_" + str(rev_n) -# else: -# prev_path = path + "_" + str(revision) -# -# new_path = path + "_" + str(rev_n + 1) -# -# self.create_job_dir(job, revision="Auto") -# -# for file in prev_rev_file_list: -# # print(file) -# if "out.traj" in file: -# dest_path = new_path + "/init.traj" -# else: -# dest_path = new_path + "/" -# -# shutil.copy(prev_path + "/" + file, dest_path) -# -# -# for file in root_dir_file_list: -# file_path = self.root_dir + "/" + file -# shutil.copy(file_path, new_path + "/") -# -# os.system("chmod 777 " + new_path + "/*") -# -# #__| -#__| - -#| - __old__ - -# def job_revision_number(self, variable_lst): - """Returns the largest revision number for the job with the given - variable list - - Args: - variable_lst: - """ - #| - job_revision_number - # # path = "data/" + self.var_lst_to_path(variable_lst) - # path = self.var_lst_to_path(variable_lst) - # bash_comm = "" - # os.chdir(path) - # - # dirs = filter(os.path.isdir, os.listdir(os.getcwd())) - # - # if self.system == "sherlock": - # num_jobs = len([dir for dir in dirs if "_jd" in dir]) - # elif self.system == "aws": - # num_jobs = len([dir for dir in dirs if dir[0] == "_" and - # dir[1].isdigit()]) - # - # # print(job_dirs) - # # os.system(bash_comm) - # os.chdir(self.root_dir) - # - # return(num_jobs) - #__| - -#__| - -#__| - -#| - compute_env - -#| - __old__ - - # def get_jobid(self, path_i="."): - # """ - # """ - # #| - get_jobid - # # path_i = "." - # fileid_path = path_i + "/.jobid" - # # print(fileid_path) - # if os.path.isfile(fileid_path): - # with open(path_i + "/.jobid") as fle: - # jobid = fle.read().strip() - # else: - # jobid=None - # - # return(jobid) - # #__| - - #| - OLD - # def job_info_batch(self, path_i="."): - # #| - job_info_batch - # data_dict = self.cluster.job_info_batch(path_i = path_i) - # - # return(data_dict) - # - # #__| - - - - # def write_job_queue_state_file(self, path="."): - # """ - # """ - # #| - write_job_queue_state_file - # print(self) - # data_dict = self.cluster.job_info_batch(path_i=path) - # key = self.cluster.job_state_key - # with open(path_i + "/.QUEUESTATE", "w") as fle: - # fle.write(data_dict[key]) - #__| - - - -#__| - - -#__| +#| - job_analysis + +#| - DEPRECATED METHODS +# def max_force(self, path): +# """ +# """ +# #| - max_force +# with open(path + "/simulation/qn.log", "r") as file: +# max_f = file.readlines()[-1].split(" ")[-1] +# return(float(max_f)) +# #__| + +# def job_id_names(self): +# """ +# """ +# #| - job_id_names +# try: +# f = open("job_id_names", "r") +# job_id_data = pickle.load(f) +# f.close() +# +# id_list = job_id_data[0] +# name_list = job_id_data[1] +# +# self.data_frame["job_id"] = id_list +# self.data_frame["job_name"] = name_list +# except: +# print("Couldn't parse job_id_names file") +# +# #__| +#__| + +#__| + +#| - job_setup + +#| - __old__ + +#| - TEMP +# def __parse_cluster_type__(self): +# """ +# """ +# #| - __parse_cluster_type__ +# clusters_dict = { +# "aws": "AWSCluster", +# "slac": "SLACCluster", +# "sherlock": "SherlockCluster", +# } +# +# cluster_sys = os.environ.get("COMPENV") +# +# if cluster_sys in clusters_dict: +# package = "dft_job_automat.compute_env" +# name = clusters_dict[cluster_sys] +# cluster = getattr(__import__(package, fromlist=[name]), name) +# +# self.cluster_sys = cluster_sys +# self.cluster = cluster +# # from dft_job_automat.compute_env import clusters_dict[cluster_sys] +# return(cluster_sys) +#__| + + +#__| + +#__| + +#| - job_manager + +#| - TEMP - Old Restart Job Method +# def restart_job(self, prev_rev_file_list=[], root_dir_file_list=[], +# revision="Auto"): +# """Restart job from previous run +# +# +# variable_lst: +# Produced from DFT_Jobs_Setup.job_var_lst. +# +# Args: +# model_file: +# "Auto" | +# atoms_file: +# Name of atoms object file from previous run +# revision: +# Job revision number from which the job will be restarted from. +# "Auto" | Restarts the job from the most recent job revision. +# """ +# #| - restart_job +# for job in self.job_var_lst: +# path = self.var_lst_to_path(job) +# +# rev_n = self.job_revision_number(job) +# +# if revision == "Auto": +# prev_path = path + "_" + str(rev_n) +# else: +# prev_path = path + "_" + str(revision) +# +# new_path = path + "_" + str(rev_n + 1) +# +# self.create_job_dir(job, revision="Auto") +# +# for file in prev_rev_file_list: +# # print(file) +# if "out.traj" in file: +# dest_path = new_path + "/init.traj" +# else: +# dest_path = new_path + "/" +# +# shutil.copy(prev_path + "/" + file, dest_path) +# +# +# for file in root_dir_file_list: +# file_path = self.root_dir + "/" + file +# shutil.copy(file_path, new_path + "/") +# +# os.system("chmod 777 " + new_path + "/*") +# +# #__| +#__| + +#| - __old__ + +# def job_revision_number(self, variable_lst): + """Returns the largest revision number for the job with the given + variable list + + Args: + variable_lst: + """ + #| - job_revision_number + # # path = "data/" + self.var_lst_to_path(variable_lst) + # path = self.var_lst_to_path(variable_lst) + # bash_comm = "" + # os.chdir(path) + # + # dirs = filter(os.path.isdir, os.listdir(os.getcwd())) + # + # if self.system == "sherlock": + # num_jobs = len([dir for dir in dirs if "_jd" in dir]) + # elif self.system == "aws": + # num_jobs = len([dir for dir in dirs if dir[0] == "_" and + # dir[1].isdigit()]) + # + # # print(job_dirs) + # # os.system(bash_comm) + # os.chdir(self.root_dir) + # + # return(num_jobs) + #__| + +#__| + +#__| + +#| - compute_env + +#| - __old__ + + # def get_jobid(self, path_i="."): + # """ + # """ + # #| - get_jobid + # # path_i = "." + # fileid_path = path_i + "/.jobid" + # # print(fileid_path) + # if os.path.isfile(fileid_path): + # with open(path_i + "/.jobid") as fle: + # jobid = fle.read().strip() + # else: + # jobid=None + # + # return(jobid) + # #__| + + #| - OLD + # def job_info_batch(self, path_i="."): + # #| - job_info_batch + # data_dict = self.cluster.job_info_batch(path_i = path_i) + # + # return(data_dict) + # + # #__| + + + + # def write_job_queue_state_file(self, path="."): + # """ + # """ + # #| - write_job_queue_state_file + # print(self) + # data_dict = self.cluster.job_info_batch(path_i=path) + # key = self.cluster.job_state_key + # with open(path_i + "/.QUEUESTATE", "w") as fle: + # fle.write(data_dict[key]) + #__| + + + +#__| + + +#__| diff --git a/dft_job_automat/compute_env.py b/dft_job_automat/compute_env.py index 41212fe..e428630 100644 --- a/dft_job_automat/compute_env.py +++ b/dft_job_automat/compute_env.py @@ -1,1872 +1,1872 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -"""Class for computer cluster operations, mainly batch. - -Development Notes: - TODO Modify .FINISHED implementation - - TODO Move the location of following command to base ComputerCluster class - with open(".SUBMITTED", "w") as fle: - fle.write("") - - TODO I don't think the child class attributes for error and out file are - being respected by ComputerCluster - -""" - -#| - Import Modules -import os -import sys -import subprocess -import datetime -import re -import shutil -import copy -import time - -import pandas as pd - -import json - -# My Modules -from misc_modules.misc_methods import merge_two_dicts -#__| - -#| - Methods - -def slurm_squeue_parse( - job_id, - path_i=None, - queue_state_key="STAT", - job_state_dict={ - "PD": "PENDING", - "R": "RUNNING", - "CF": "CONFIGURING", - "SUCCEEDED": "SUCCEEDED", - } - - ): - """Parse slurm squeue command for job state. - - Args: - job_id: - path_i: - queue_state_key: - """ - #| - slurm_squeue_parse - bash_comm = "squeue -j " + str(job_id) - - try: - out = subprocess.check_output( - bash_comm, - shell=True, - stderr=subprocess.STDOUT, - ) - - # 'JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)' - out = out.splitlines() - out = out[1].split(" ") - out = [i for i in out if i != ''] - - data_dict = { - "PARTITION": out[1], - "STAT": out[4], - # "CF": - } - - if path_i is not None: - with open(path_i + "/.QUEUESTATE", "w") as fle: - fle.write(job_state_dict[data_dict[queue_state_key]]) - fle.write("\n") - - except subprocess.CalledProcessError: - data_dict = None - pass - - except: - data_dict = None - pass - - return(data_dict) - #__| - -#__| - -############################################################################### -class ComputerCluster(): - """Base class for interfacing with computing resources. - - Development Notes: - TODO Create dummy cluster for WSL system - """ - - #| - ComputerCluster ****************************************************** - - def __init__(self, - ): - """Initialize the base ComputerCluster class.""" - #| - __init__ - self.root_dir = os.getcwd() - self.default_sub_params = self.default_submission_parameters() - - # self.username = self.__parse_username__() - - self.__parse_cluster_type__() - #__| - - #| - __old__ - # def __parse_username__(self): - # """ - # """ - # #| - __parse_username__ - # username = os.environ.get("USER") - # - # cond_1 = False - # if type(username) == str: - # cond_1 = True - # - # cond_2 = False - # if username is not None: - # cond_2 = True - # - # print(cond_1) - # print(cond_2) - # - # print(username) - # print("*******") - # return(username) - # #__| - #__| - - def __parse_cluster_type__(self): - """Parse for the current cluster system.""" - #| - __parse_cluster_type__ - clusters_dict = { - "aws": "AWSCluster", - "slac": "SLACCluster", - "sherlock": "SherlockCluster", - "nersc": "EdisonCluster", - } - - cluster_sys = os.environ.get("COMPENV") - - if cluster_sys in clusters_dict: - package = "dft_job_automat.compute_env" - name = clusters_dict[cluster_sys] - cluster = getattr(__import__(package, fromlist=[name]), name) - - self.cluster_sys = cluster_sys - - self.cluster = cluster( - root_dir=self.root_dir, - ) - else: - pass - self.cluster_sys = "dummy" - # TODO Create instance to dummy cluster class - - self.cluster = DummyCluster( - root_dir=self.root_dir, - ) - - home = os.environ.get("HOME") - try: - with open(home + "/.sys_files_rf/jobs_list_dir", "r") as fle: - jobs_dir = fle.read().rstrip() - except: - jobs_dir = None - - self.jobs_list_dir = jobs_dir - #__| - - def default_submission_parameters(self): - """Global submission parameters for cluster jobs.""" - #| - default_submission_parameters - def_params = { - "path_i": ".", - "job_name": "Default", - "job_script": "model.py", - "out_file": "job.out", - "err_file": "job.err", - } - - return(def_params) - #__| - - def is_job_submitted(self, path_i="."): - """Check if job has been submitted. - - Return TRUE if the job at 'path' has been submtted - A job is considered submitted if there exists a '.submitted' file - - Args: - path - """ - #| - add_jobs_queue_data - root_dir = os.getcwd() - os.chdir(path_i) - if os.path.isfile(".SUBMITTED"): - print("Directory already submitted, will be skipped") - os.chdir(root_dir) - submitted = True - else: - os.chdir(root_dir) - submitted = False - - return(submitted) - #__| - - def job_state(self, path_i="."): - """ - - Args: - path_i: - """ - #| - job_state - job_state = self.cluster.job_state(path_i=path_i) - - if job_state is None: - try: - with open(path_i + "/.QUEUESTATE", "r") as fle: - job_state = fle.read().rsplit() - - len_js = len(job_state) - assert type(job_state) == list and len_js == 1, "error" - # if type(job_state) == list and len(job_state) == 1: - job_state = job_state[0] - - except: - job_state = None - pass - - return(job_state) - #__| - - def job_info_batch(self, path_i="."): - """ - - Args: - path_i: - """ - #| - job_info_batch - - data_dict = self.cluster.job_info_batch(path_i=path_i) - - # jobs_file_path = self.jobs_list_dir - - - # jobs_file_path = self.jobs_list_dir + "/jobs.csv" - # df_new = pd.DataFrame([data_dict]) - # if os.path.isfile(jobs_file_path): - # df = pd.read_csv(jobs_file_path) - # df = df.append(df_new) - # else: - # df = df_new - # df.to_csv(jobs_file_path, index=False) - - - return(data_dict) - #__| - - def submit_job(self, **kwargs): - """Call cluster specific job submission method. - - Notes: - make sure to add 'path_i' key - - Args: - **kwargs: - """ - #| - submit_job - kwargs = merge_two_dicts(self.default_sub_params, kwargs) - - #| - Checking if job has already been submitted - if "path_i" in kwargs: - path_i = kwargs["path_i"] - else: - path_i = "." - - if self.is_job_submitted(path_i=path_i): - return(None) - #__| - - #| - Writing Job Submission Parameters - with open(".submission_params.json", "w") as fle: - json.dump(kwargs, fle, indent=2, skipkeys=True) - #__| - - self.cluster.submit_job_clust(**kwargs) - - #| - Writing Cluster System Info to File - if "path_i" in kwargs: - path_i = kwargs["path_i"] - - with open(".cluster_sys", "w") as fle: - # fle.write(self.cluster_sys) - fle.write(self.cluster_sys + "\n") - #__| - - #__| - - #__| ********************************************************************** - -############################################################################### - - -class EdisonCluster(ComputerCluster): - """NERSC Edison computing cluster. - - - I'll try to get this to work with Cori as well - """ - - #| - EdisonCluster ******************************************************** - def __init__(self, root_dir="."): - """Initialize Sherlock cluster instance. - - Args: - root_dir: - """ - #| - __init__ - # 24 cores (edison) 32 cpus (cori) - - nersc_host = os.environ["NERSC_HOST"] - if nersc_host == "cori": - self.cores_per_node = 32 # <-- Cori Haswell - # self.cores_per_node = 58 # <-- Cori KNL #TODO Switch to these - - elif nersc_host == "edison": - self.cores_per_node = 24 - - - # self.job_queue_dir = "/u/if/flores12/usr/bin" - - self.job_data_dir = "" - self.root_dir = root_dir - - self.default_sub_params = self.default_submission_parameters() - - self.queues = self.__queue_types__() - - # self.job_queue_dir = "/u/if/flores12/usr/bin" - - self.job_state_keys = self.job_state_dict() - self.job_queue_state_key = "STAT" # COMBAK - - self.error_file = "job.err" - self.out_file = "job.out" - - # self.aws_dir = os.environ["aws_sc"] - # self.job_queue_dir = self.aws_dir + "/jobs_bin" - # self.job_queue_state_key = "job_status" - #__| - - def default_submission_parameters(self): - """Defaul SLURM parameters for Sherlock cluster.""" - #| - default_submission_parameters - - def_params = { - "queue": "regular", # -p flag | regular, debug - ##SBATCH -p regular - #SBATCH -p debug - "nodes": "10", - #SBATCH -N 10 # 24 cpus per node on edison, 32 per node on cori haswell, 50? on knl - - "account": "m2997", # -A flag - #SBATCH -A m2997 - - "wall_time": "180", - #SBATCH -t 00:30:00 - - "priority": "scavenger", # --qos -q flag - - ##SBATCH --qos=scavenger - ##SBATCH --qos=premium - ##SBATCH --qos=debug - ##SBATCH --qos=regular - - "constraints": "haswell", - ##SBATCH -C haswell #this is for cori haswell (old) - ##SBATCH -C knl #new cori - - #SBATCH -e job.err#SBATCH -o job.out - } - - return(def_params) - #__| - - def submit_job_clust(self, **kwargs): - """Submit job to sherlck. - - Args: - **kwargs: - """ - #| - submit_job - time.sleep(1.5) - - #| - Merging Submission Parameters - params = merge_two_dicts(self.default_sub_params, kwargs) - - path = params["path_i"] - - - # Fixing debug flag specification - if params["priority"] == "debug": - params["queue"] = "debug" - - if params["queue"] == "debug": - params["priority"] = "debug" - #__| - - #| - Submit Job - os.chdir(path) - - if params["job_name"] == "Default": - params["job_name"] = os.getcwd() - - print("submitting job") - os.system("chmod 777 *") - # bash_command = "/u/if/flores12/bin/qv model.py" - #__| **** TEMP - - #| - Create vasp_run script - os.system("cd $SLURM_SUBMIT_DIR") - os.system("export TMPDIR=$SLURM_SUBMIT_DIR") - os.system("export VASP_SCRIPT=./run_vasp.py") - os.system("echo import os > run_vasp.py") - - exitcode_line = "exitcode = os.system('srun -n " + \ - str(int(self.cores_per_node * int(params["nodes"]))) + \ - " /project/projectdirs/m2997/special_edison')" - - line_2 = 'echo ' + '"' + exitcode_line + '" >> run_vasp.py' - os.system(line_2) # on edison - #__| - - #| - Bash Submisssion Command - bash_command = "/usr/bin/sbatch " - - - # The -q flag is being used in place of the -p flag - # Only the -q needs to be defined - bash_command += "-q " + str(params["queue"]) + " " - # bash_command += "-p " + str(params["queue"]) + " " - - bash_command += "--nodes " + str(params["nodes"]) + " " - bash_command += "--time " + str(params["wall_time"]) + " " - - # bash_command += "--qos " + str(params["priority"]) + " " # Didn't work - - bash_command += "--output " + str(params["out_file"]) + " " - bash_command += "--error " + str(params["err_file"]) + " " - bash_command += "-C haswell " - - bash_command += params["job_script"] - - print("Bash Submission Command:") - print(bash_command) - #__| - - try: - output = subprocess.Popen( - bash_command, - stdout=subprocess.PIPE, - shell=True, - ) - sub_time = datetime.datetime.now().isoformat() - # except subprocess.CalledProcessError, e: - except subprocess.CalledProcessError as e: - print("Ping stdout output:\n", e.output) - - os.chdir(self.root_dir) - print("JOB SKIPPED: ") - return(None) - - #| - Parsing Output - # out, err = pickle.load(open("job_sub_output.pickle", "r")) - - try: - # job_id = int(out_list[-1]) - out, err = output.communicate() - out_copy = copy.deepcopy(out) - out = out.strip() - out_list = out.split(" ") - job_id = int(out_list[-1]) - - except: - print("Couldn't parse for jobid") - job_id = None - - # out = output.communicate()[0] - # out_copy = copy.deepcopy(out) - # - # ind = out.find("job") - # out = out[ind + 3:] - # - # jobid = re.sub("[^0-9]", "", out) - # - # try: - # jobid = int(jobid) - # - # except: - # print("Couldn't parse for jobid | !@!!") - # jobid = None - # pass - # - # if type(jobid) == int: - # jobid = jobid - # else: - # jobid = None - #__| - - #| - Writing Files - with open(".SUBMITTED", "w") as fle: - fle.write("\n") - - with open(".bash_comm", "w") as fle: - fle.write(str(bash_command) + str("\n")) - - with open(".jobid", "w") as fle: - fle.write(str(job_id) + str("\n")) - - if sys.version_info >= (3, 0): - with open(".sub_out", "wb") as fle: - fle.write(out_copy) - - else: - with open(".sub_out", "w") as fle: - fle.write(out_copy) - #__| - - os.chdir(self.root_dir) - - #| - Save subprocess output for analysis - # import pickle - # - # pickle.dump( - # output.communicate(), - # open("job_sub_output.pickle", "wb"), - # ) - # return(output) - #__| - - # return(out, jobid) - #__| - - def job_state_dict(self): - """ - """ - #| - job_state_dict - job_state_dict = { - "PD": "PENDING", - "R": "RUNNING", - "CF": "CONFIGURING", - "SUCCEEDED": "SUCCEEDED", - - # "FAILED": "FAILED", - # "STARTING": "STARTING", - # "RUNNABLE": "PENDING", - # "SUBMITTED": "SUBMITTED", - } - - return(job_state_dict) - #__| - - def __queue_types__(self): - """Queue types for Edison cluster - """ - #| - __queue_types__ - queue_list = [ - "regular", - "debug", - "premium", - ] - - return(queue_list) - #__| - - def job_info_batch(self, job_id, path_i=None): - """ - """ - #| - job_info_batch - data_dict = slurm_squeue_parse( - job_id, - path_i=path_i, - queue_state_key=self.job_queue_state_key, - job_state_dict=self.job_state_keys, - ) - - return(data_dict) - - #| - __old__ - # bash_comm = "squeue -j " + str(job_id) - # - # try: - # out = subprocess.check_output( - # bash_comm, - # shell=True, - # stderr=subprocess.STDOUT, - # ) - # - # # 'JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)' - # out = out.splitlines() - # out = out[1].split(" ") - # out = [i for i in out if i != ''] - # - # data_dict = { - # "PARTITION": out[1], - # "STAT": out[4], - # # "CF": - # } - # - # if path_i is not None: - # key = self.job_queue_state_key - # with open(path_i + "/.QUEUESTATE", "w") as fle: - # fle.write(self.job_state_keys[data_dict[key]]) - # fle.write("\n") - # - # except subprocess.CalledProcessError: - # data_dict = None - # pass - # - # except: - # data_dict = None - # pass - # - # - # return(data_dict) - # - # bash_comm = "squeue -j " + str(job_id) - # - # try: - # out = subprocess.check_output( - # bash_comm, - # shell=True, - # stderr=subprocess.STDOUT, - # ) - # - # # 'JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)' - # out = out.splitlines() - # out = out[1].split(" ") - # out = [i for i in out if i != ''] - # - # data_dict = { - # "PARTITION": out[1], - # "STAT": out[4], - # # "CF": - # } - # - # if path_i is not None: - # key = self.job_queue_state_key - # with open(path_i + "/.QUEUESTATE", "w") as fle: - # fle.write(self.job_state_keys[data_dict[key]]) - # fle.write("\n") - # - # except subprocess.CalledProcessError: - # data_dict = None - # pass - # - # except: - # print("tmp except final") - # data_dict = None - # pass - # - # # TEMP_PRINT - # print(data_dict) - # - # return(data_dict) - #__| - - #__| - - def completed_file(self, path_i="."): - """Check whether ".FINISHED" file exists. - - Indicates that the job has gone to completion - - Args: - path_i: - """ - #| - completed_file - completed_fle = False - if os.path.exists(path_i + "/.FINISHED"): - completed_fle = True - - return(completed_fle) - #__| - - def job_state(self, path_i="."): - """Return job state of path_i --> job_i. - - Args: - path_i - """ - #| - job_state - job_id = self.get_jobid(path_i=path_i) - - # print("compute_env job_state job_id:") - # print(job_id) - - - job_state_out = None - if job_id is not None: - job_info = self.job_info_batch(job_id, path_i=path_i) - - # print("job_info **(***(*))") - # print(job_info) - - if job_info is not None: - key = self.job_queue_state_key - if key in job_info: - job_state_out = job_info[key] - job_state_out = self.job_state_keys[job_state_out] - - #| - Checking for "completed" file indicating success - completed_fle = self.completed_file(path_i=path_i) - if completed_fle: - job_state_out = self.job_state_keys["SUCCEEDED"] - #__| - - return(job_state_out) - #__| - - def get_jobid(self, path_i="."): - """Return job ID of job_i. - - Args: - path_i: - """ - #| - get_jobid - fileid_path = path_i + "/.jobid" - if os.path.isfile(fileid_path): - with open(path_i + "/.jobid") as fle: - jobid = fle.read().strip() - else: - jobid = None - - return(jobid) - #__| - - #__| ********************************************************************** - - -class SLACCluster(ComputerCluster): - """SLAC computing cluster.""" - - #| - SLACCluster ********************************************************** - def __init__(self, - root_dir=".", - ): - """ - """ - #| - __init__ - self.root_dir = root_dir - self.default_sub_params = self.default_submission_parameters() - self.job_data_dir = "" - - self.job_queue_dir = "/u/if/flores12/usr/bin" - self.queues = self.__queue_types__() - - self.job_state_keys = self.job_state_dict() - self.job_queue_state_key = "STAT" - #__| - - def job_state_dict(self): - """ - """ - #| - job_state_dict - job_state_dict = { - # "PENDING": "PEND", - # "FINISHED": "DONE", - # "RUNNING": "RUN", - # "FAILED": "EXIT", - "PEND": "PENDING", - "DONE": "SUCCEEDED", - "RUN": "RUNNING", - "EXIT": "FAILED", - "UNKWN": "UNKNOWN", - } - - return(job_state_dict) - #__| - - def __queue_types__(self): - """Queue types for SLAC cluster - """ - #| - __queue_types__ - queue_list = [ - "suncat-test", - "suncat", - "suncat2", - "suncat2-xlong", - "suncat3", - "suncat3-xlong", - "suncat-xlong", - ] - - return(queue_list) - #__| - - def default_submission_parameters(self): - """ - """ - #| - default_submission_parameters - def_params = { - "queue": "suncat", - "cpus": "8", - "wall_time": "3000", - # "memory": "6000", - # "job_name": "Default", - "job_script": "model.py" - } - - return(def_params) - #__| - - def submit_job_clust(self, **kwargs): - """FIX This should update data table - - ABSOLUTELY NEED TO DEFINE 'path_i' FOR THIS TO WORK!!!!!!!!!!!!!!!!!! - - Submits job to aws cluster. Copies PythonModules folder into - job directory - """ - #| - submit_job - - #| - Merging Submission Parameters - params = merge_two_dicts(self.default_sub_params, kwargs) - - path = params["path_i"] - #__| - - #| - Checking if job has already been submitted - # if self.is_job_submitted(): - # return(None) - #__| - - #| - Submit Job ******************************************************* - - os.chdir(path) - - if params["job_name"] == "Default": - params["job_name"] = os.getcwd() - - print("submitting job") - - os.system("chmod 777 *") - - # bash_command = "/u/if/flores12/bin/qv model.py" - - bash_command = "/afs/slac/g/suncat/bin/dobsub " - bash_command += "-q " + str(params["queue"]) + " " - bash_command += "-n " + str(params["cpus"]) + " " - bash_command += "-W " + str(params["wall_time"]) + " " - bash_command += "-o " + str(params["out_file"]) + " " - bash_command += "-e " + str(params["err_file"]) + " " - - # bash_command += "-o job.out " - # bash_command += "-e job.err " - - # bash_command += "-M " + params["memory"] + " " - bash_command += "-J " + params["job_name"] + " " - bash_command += params["job_script"] - - #| - FIXME Python 2 --> 3 - print("Python version info") - print(sys.version_info) - if (sys.version_info > (3, 0)): - try: - output = subprocess.Popen( - bash_command, - stdout=subprocess.PIPE, - shell=True, - ) - sub_time = datetime.datetime.now().isoformat() - - - except subprocess.CalledProcessError as e: - print("Ping stdout output:\n", e.output) - os.chdir(self.root_dir) - print("JOB SKIPPED: ") - return(None) - - else: - try: - output = subprocess.Popen( - bash_command, - stdout=subprocess.PIPE, - shell=True, - ) - sub_time = datetime.datetime.now().isoformat() - - # except subprocess.CalledProcessError, e: - except subprocess.CalledProcessError as e: - print("Ping stdout output:\n", e.output) - # print "Ping stdout output:\n", e.output - os.chdir(self.root_dir) - print("JOB SKIPPED: ") - return(None) - - #| - __old - # try: - # output = subprocess.Popen( - # bash_command, - # stdout=subprocess.PIPE, - # shell=True, - # ) - # sub_time = datetime.datetime.now().isoformat() - # - # # except subprocess.CalledProcessError, e: - # except subprocess.CalledProcessError as e: - # - # print "Ping stdout output:\n", e.output - # - # os.chdir(self.root_dir) - # print("JOB SKIPPED: ") - # return(None) - - #__| - - #__| - - #__| - - #| - Parsing Output - out = output.communicate()[0] - ind = out.find("Job <") - - out1 = out[ind:] - ind1 = out1.find("<") - ind2 = out1.find(">") - - jobid = out1[ind1 + 1:ind2] - - if jobid.isdigit(): - jobid = int(jobid) - else: - jobid = None - #__| - - #| - Writing Files - with open(".SUBMITTED", "w") as fle: - fle.write("\n") - - with open(".bash_comm", "w") as fle: - fle.write(str(bash_command) + str("\n")) - - with open(".jobid", "w") as fle: - fle.write(str(jobid) + str("\n")) - - with open(".sub_out", "w") as fle: - fle.write(out) - #__| - - os.chdir(self.root_dir) - - return(out, jobid) - #__| - - def get_jobid(self, path_i="."): - """ - """ - #| - get_jobid - # path_i = "." - - if os.path.isfile(path_i + "/.jobid"): - with open(path_i + "/.jobid") as fle: - jobid = fle.read().strip() - else: - jobid = None - - return(jobid) - #__| - - def job_info_batch(self, path_i="."): - """ - """ - #| - job_info_batch - job_id = self.get_jobid(path_i) - - #| - If No Job ID File Return None - if job_id is None: - return(None) - #__| - - bash_comm = "/usr/local/bin/bjobs -w" + " " + job_id - out = subprocess.check_output( - bash_comm, - shell=True, - stderr=subprocess.STDOUT, - ) - - #| - Checking if Job Id Still in Batch System - if "is not found" in out: - print("Job ID no longer in batch system, or ID is wrong") - return(None) - #__| - - #| - Parsing bsub Output into Dict - out = out.split() - headers = out[0:8] - data = out[8:] - data_1 = data[0:7] - - data_dict = { - "JOBID": data_1[0], - "USER": data_1[1], - "STAT": data_1[2], - "QUEUE": data_1[3], - "FROM_HOST": data_1[4], - "EXEC_HOST": data_1[5], - "JOB_NAME": data_1[6], - } - - time = data[7:] - time = "_".join(time) - data_dict["SUBMIT_TIME"] = time - #__| - - #| - bjob Command to Get Job Path From Job ID - bash_comm_2 = "/usr/local/bin/bjobs -o" + " 'exec_cwd' " + job_id - out2 = subprocess.check_output(bash_comm_2, shell=True) - out2 = out2.split() - data_dict["EXEC_CWD"] = out2[1] - #__| - - # self.write_job_queue_state_file(path=path_i) - - #| - write_job_queue_state_file - key = self.job_queue_state_key - with open(path_i + "/.QUEUESTATE", "w") as fle: - fle.write(self.job_state_keys[data_dict[key]]) - fle.write("\n") - #__| - - return(data_dict) - #__| - - def job_state(self, path_i="."): - """Query job state. - - # FIXME This should update jobs table - - Args: - path_i - """ - #| - job_state - job_info = self.job_info_batch(path_i=path_i) - - if job_info is not None: - key = self.job_queue_state_key - if key in job_info: - job_state_out = job_info[key] - job_state_out = self.job_state_keys[job_state_out] - else: - job_state_out = None - - return(job_state_out) - #__| - - #__| ********************************************************************** - - -class SherlockCluster(ComputerCluster): - """Sherlock computing cluster.""" - - #| - SherlockCluster ****************************************************** - def __init__(self, root_dir="."): - """Initialize Sherlock cluster instance. - - Args: - root_dir: - """ - #| - __init__ - # self.job_queue_dir = "/u/if/flores12/usr/bin" - - self.job_data_dir = "" - self.root_dir = root_dir - - self.username = self.__parse_username__() - self.default_sub_params = self.default_submission_parameters() - - self.queues = self.__queue_types__() - - # self.job_queue_dir = "/u/if/flores12/usr/bin" - - self.job_state_keys = self.job_state_dict() - self.job_queue_state_key = "STAT" - - - self.error_file = "job.err" - self.out_file = "job.out" - - # self.aws_dir = os.environ["aws_sc"] - # self.job_queue_dir = self.aws_dir + "/jobs_bin" - - # self.job_queue_state_key = "job_status" - #__| - - - def __parse_username__(self): - """ - """ - #| - __parse_username__ - username = os.environ.get("USER") - - cond_1 = False - if type(username) == str: - cond_1 = True - - cond_2 = False - if username is not None: - cond_2 = True - - return(username) - #__| - - - def default_submission_parameters(self): - """Defaul SLURM parameters for Sherlock cluster.""" - #| - default_submission_parameters - - def_params = { - "queue": "owners,iric,normal", # -p flag - "nodes": "1", # --nodes - "cpus": "16", # --ntasks-per-node - "memory": "4000", # --mem-per-cpu - "wall_time": "720", # --time (720min -> 12hrs) - "job_name": "Default", # --job-name - "priority": "normal", # --qos - # "email": "flores12@stanford.edu", # --mail-user - "email": self.username + "@stanford.edu", # --mail-user - "email_mess": "FAIL", # --mail-type - } - - return(def_params) - #__| - - def submit_job_clust(self, **kwargs): - """Submits job to sherlck. - - Args: - **kwargs: - """ - #| - submit_job - time.sleep(1.5) - - #| - Merging Submission Parameters - params = merge_two_dicts(self.default_sub_params, kwargs) - - path = params["path_i"] - #__| - - #| - Submit Job - os.chdir(path) - - if params["job_name"] == "Default": - params["job_name"] = os.getcwd() - - print("submitting job") - os.system("chmod 777 *") - # bash_command = "/u/if/flores12/bin/qv model.py" - #__| **** TEMP - - #| - Bash Submisssion Command - bash_command = "/usr/bin/sbatch " - - bash_command += "-p " + str(params["queue"]) + " " - bash_command += "--nodes " + str(params["nodes"]) + " " - bash_command += "--ntasks-per-node " + str(params["cpus"]) + " " - bash_command += "--mem-per-cpu " + str(params["memory"]) + " " - bash_command += "--time " + str(params["wall_time"]) + " " - bash_command += "--job-name " + str(params["job_name"]) + " " - bash_command += "--qos " + str(params["priority"]) + " " - bash_command += "--mail-user " + str(params["email"]) + " " - bash_command += "--mail-type " + str(params["email_mess"]) + " " - bash_command += "--output " + str(params["out_file"]) + " " - bash_command += "--error " + str(params["err_file"]) + " " - bash_command += "-C CPU_GEN:HSW " # COMBAK Formalize this cpu architecture filter - - bash_command += params["job_script"] - - print("Bash Submission Command:") - print(bash_command) - #__| - - try: - - if sys.version_info[0] < 3: - # raise Exception("Must be using Python 3") - output = subprocess.Popen( - bash_command, - stdout=subprocess.PIPE, - shell=True, - # encoding="utf8", - ) - - else: - output = subprocess.Popen( - bash_command, - stdout=subprocess.PIPE, - shell=True, - encoding="utf8", - ) - - sub_time = datetime.datetime.now().isoformat() - - # except subprocess.CalledProcessError, e: - except subprocess.CalledProcessError as e: - print("Ping stdout output:\n", e.output) - - os.chdir(self.root_dir) - print("JOB SKIPPED: ") - return(None) - - #| - Parsing Output - out = output.communicate()[0] - out_copy = copy.deepcopy(out) - - ind = out.find("job") - - out = out[ind + 3:] - - jobid = re.sub("[^0-9]", "", out) - - try: - jobid = int(jobid) - - except: - print("Couldn't parse for jobid | !@!!") - jobid = None - pass - - if type(jobid) == int: - jobid = jobid - else: - jobid = None - #__| - - #| - Writing Files - with open(".SUBMITTED", "w") as fle: - fle.write("\n") - - with open(".bash_comm", "w") as fle: - fle.write(str(bash_command) + str("\n")) - - with open(".jobid", "w") as fle: - fle.write(str(jobid) + str("\n")) - - with open(".sub_out", "w") as fle: - fle.write(out_copy) - - #| - Writing Job Submission Parameters - with open(".submission_params_2.json", "w") as fle: - json.dump(params, fle, indent=2, skipkeys=True) - #__| - - #__| - - os.chdir(self.root_dir) - - return(out, jobid) - - #__| - - def job_state_dict(self): - """ - """ - #| - job_state_dict - job_state_dict = { - "PD": "PENDING", - "R": "RUNNING", - "CF": "CONFIGURING", - "SUCCEEDED": "SUCCEEDED", - - # "FAILED": "FAILED", - # "STARTING": "STARTING", - # "RUNNABLE": "PENDING", - # "SUBMITTED": "SUBMITTED", - } - - return(job_state_dict) - #__| - - def __queue_types__(self): - """Queue types for SLAC cluster - """ - #| - __queue_types__ - queue_list = [ - "owners", - "iric", - ] - - return(queue_list) - #__| - - def get_jobid(self, path_i="."): - """Return the job id. - - Args: - path_i: - """ - #| - get_jobid - # # path_i = "." - # fileid_path = path_i + "/.jobid" - # # print(fileid_path) - # if os.path.isfile(fileid_path): - # with open(path_i + "/.jobid") as fle: - # jobid = fle.read().strip() - # else: - # jobid=None - # - # return(jobid) - #__| - - def job_info_batch(self, job_id, path_i=None): - """ - """ - #| - job_info_batch - data_dict = slurm_squeue_parse( - job_id, - path_i=path_i, - queue_state_key=self.job_queue_state_key, - job_state_dict=self.job_state_keys, - ) - - return(data_dict) - - #| - __old__ - # bash_comm = "squeue -j " + str(job_id) - # - # try: - # out = subprocess.check_output( - # bash_comm, - # shell=True, - # stderr=subprocess.STDOUT, - # ) - # - # # 'JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)' - # out = out.splitlines() - # out = out[1].split(" ") - # out = [i for i in out if i != ''] - # - # data_dict = { - # "PARTITION": out[1], - # "STAT": out[4], - # # "CF": - # } - # - # if path_i is not None: - # key = self.job_queue_state_key - # with open(path_i + "/.QUEUESTATE", "w") as fle: - # fle.write(self.job_state_keys[data_dict[key]]) - # fle.write("\n") - # - # except subprocess.CalledProcessError: - # data_dict = None - # pass - # - # except: - # data_dict = None - # pass - # - # - # return(data_dict) - #__| - - #__| - - def completed_file(self, path_i="."): - """ - Check whether ".FINISHED" file exists. - - Indicates that the job has gone to completion - - Args: - path_i: - """ - #| - completed_file - completed_fle = False - if os.path.exists(path_i + "/.FINISHED"): - completed_fle = True - - return(completed_fle) - #__| - - def job_state(self, path_i="."): - """ - Return job state of path_i --> job_i. - - Args: - path_i - """ - #| - job_state - job_id = self.get_jobid(path_i=path_i) - - job_state_out = None - if job_id is not None: - job_info = self.job_info_batch(job_id, path_i=path_i) - - if job_info is not None: - key = self.job_queue_state_key - if key in job_info: - job_state_out = job_info[key] - job_state_out = self.job_state_keys[job_state_out] - - #| - Checking for "completed" file indicating success - completed_fle = self.completed_file(path_i=path_i) - if completed_fle: - job_state_out = self.job_state_keys["SUCCEEDED"] - #__| - - return(job_state_out) - - #__| - - def get_jobid(self, path_i="."): - """ - Return job ID of job_i. - - Args: - path_i: - """ - #| - get_jobid - fileid_path = path_i + "/.jobid" - if os.path.isfile(fileid_path): - with open(path_i + "/.jobid") as fle: - jobid = fle.read().strip() - else: - jobid = None - - return(jobid) - #__| - - #__| ********************************************************************** - - -class AWSCluster(ComputerCluster): - """AWS EC2 computing resource. - - Must define $awsdir environment variable - ex. $awsdir=/scratch/users/flores12/AWS/matr.io - """ - - #| - AWSCluster *********************************************************** - def __init__(self, - root_dir=".", - ): - """ - """ - #| - __init__ - self.job_data_dir = "/simulation" - self.root_dir = root_dir - self.default_sub_params = self.default_submission_parameters() - self.aws_dir = os.environ.get("awsdir", "") - - #| - Create job_queue_dir - self.job_queue_dir = os.path.join( - self.aws_dir, - "jobs_bin") - - directory = self.job_queue_dir - if not os.path.exists(directory): - os.makedirs(directory) - #__| - - self.job_state_keys = self.job_state_dict() - self.queues = self.__queue_types__() - self.job_queue_state_key = "job_status" - self.error_file = "err" - self.out_file = "out" - #__| - - def default_submission_parameters(self): - """ - """ - #| - default_submission_parameters - def_params = { - "queue": "medium", - "cpus": "default", - # "wall_time": "2000", - # "memory": "6000", - # "job_name": "Default", - "job_script": "model.py", - - "copy_PythonModules": True, - "copy_PythonPackages": False, - } - - return(def_params) - #__| - - def submit_job_clust(self, **kwargs): - """Submit job to AWS cluster. - - Copies PythonModules and PythonPackages folder into job directory - - Args: - kwargs - """ - #| - submit_job_clust - - #| - Job Parameters - params = merge_two_dicts(self.default_sub_params, kwargs) - - path = params["path_i"] - copy_PythonModules = params["copy_PythonModules"] - copy_PythonPackages = params["copy_PythonPackages"] - cpus = params["cpus"] - queue = params["queue"] - #__| - - root_dir = os.getcwd() - if path is None: - path = root_dir - - #| - Checking if job has already been submitted - os.chdir(path) - if os.path.isfile(".SUBMITTED"): - print("Directory already submitted, will be skipped") - os.chdir(root_dir) - return(None) # <-------- SKIP JOB -------------------------------- - else: - os.chdir(root_dir) - #__| - - self.__copy_pyth_mods_packs_to_job_dir__( - path, - copy_mods=copy_PythonModules, - copy_packs=copy_PythonPackages, - ) - - #| - Submit Job - # Args: path, root_dir, queue, cpus - - os.chdir(path) - - if os.path.isfile(".SUBMITTED"): - print("Directory already submitted, will be skipped") - os.chdir(root_dir) - return(None) - else: - print("submitting job") - aws_dir = self.aws_dir - - if cpus == "default": - bash_command = aws_dir + "/bin/trisub -q " + queue - else: - - #| - Checking that number of cpus is within allows - if queue == "medium": - if cpus > 4: - print("Medium queue can't have more than 4 cpus") - print(" setting cpus to 4") - cpus = 4 - #__| - - bash_command = aws_dir + "/bin/trisub -c " + str(cpus) + \ - " -q " + queue - - # try: - output = subprocess.check_output( - bash_command, - shell=True, - universal_newlines=True, # CHANGED - ) - - sub_time = datetime.datetime.now().isoformat() - - # # except subprocess.CalledProcessError, e: - # except subprocess.CalledProcessError as e: - # print("Ping stdout output:\n", e.output) - # - # os.chdir(root_dir) - # print("JOB SKIPPED: ") - # return(None) - #__| - - os.system("chmod 777 " + path + "/*") - os.system("chmod 777 " + path) - - #| - Parsing Submission for Job ID - output = output.splitlines() - print(output) # CHANGED - - for line in output: - if "jobId" in line: - lst = line.split('"') - job_id_ind = (lst.index("jobId") + 2) - jobId = lst[job_id_ind] - - file = open(".jobid", "w") - file.write(jobId + "\n") - #__| - - file = open(".SUBMITTED", "w") - file.close() - - os.chdir(root_dir) - - #| - Querying AWS For Job Info - job_queue_dict = self.job_info_batch(jobId) - job_queue_dict["submit_time"] = sub_time - - jobs_file_path = self.job_queue_dir + "/jobs.csv" - - df_new = pd.DataFrame([job_queue_dict]) - if os.path.isfile(jobs_file_path): - df = pd.read_csv(jobs_file_path) - df = df.append(df_new) - else: - df = df_new - - df.to_csv(jobs_file_path, index=False) - #__| - - return job_queue_dict - #__| - - def job_state_dict(self): - """ - """ - #| - job_state_dict - job_state_dict = { - "PENDING": "PENDING", - "SUCCEEDED": "SUCCEEDED", - "FAILED": "FAILED", - "RUNNING": "RUNNING", - "STARTING": "STARTING", - - # RUNNABLE in AWS really means pending - # "RUNNABLE": "RUNNABLE", - - "RUNNABLE": "PENDING", - "SUBMITTED": "SUBMITTED", - } - - return(job_state_dict) - #__| - - def __queue_types__(self): - """Queue types for AWS cluster - """ - #| - __queue_types__ - queue_list = [ - "test", - "small", - "medium", - "large", - ] - - return(queue_list) - #__| - - def __copy_pyth_mods_packs_to_job_dir__( - self, - path_i, - copy_mods=True, - copy_packs=True, - ): - """ - """ - #| - __copy_pyth_mods_packs_to_job_dir__ - copy_PythonModules = copy_mods - copy_PythonPackages = copy_packs - - #| - Copy PYTHONMODULES to Job Directory - if copy_PythonModules: - if os.path.isdir(path_i + "/PythonModules") is True: - print("PythonModules already exists, erasing and recopying") - shutil.rmtree(path_i + "/PythonModules") - # py_mod = os.environ["python_modules"] # Old pyth mods dir - py_mod = os.environ["PYTHONMODULES"] - shutil.copytree(py_mod, path_i + "/PythonModules") - else: - # py_mod = os.environ["python_modules"] - py_mod = os.environ["PYTHONMODULES"] - shutil.copytree(py_mod, path_i + "/PythonModules") - #__| - - #| - Copy Python Packages to Job Directory - if copy_PythonPackages: - if os.path.isdir(path_i + "/PythonPackages") is True: - print("PythonPackages already exists, erasing and recopying") - shutil.rmtree(path_i + "/PythonPackages") - py_pack = os.environ["PYTHONPACKAGES"] - shutil.copytree(py_pack, path_i + "/PythonPackages") - else: - py_pack = os.environ["PYTHONPACKAGES"] - shutil.copytree(py_pack, path_i + "/PythonPackages") - #__| - - #__| - - def get_jobid(self, path_i="."): - """ - """ - #| - get_jobid - # path_i = "." - fileid_path = path_i + "/.jobid" - if os.path.isfile(fileid_path): - with open(path_i + "/.jobid") as fle: - jobid = fle.read().strip() - else: - jobid = None - - return(jobid) - #__| - - def job_state(self, path_i="."): - """ - """ - #| - job_state - job_id = self.get_jobid(path_i=path_i) - job_state_out = None - if job_id is not None: - job_info = self.job_info_batch(job_id) - - if job_info is not None: - key = self.job_queue_state_key - if key in job_info: - job_state_out = job_info[key] - job_state_out = self.job_state_keys[job_state_out] - - #| - Checking for Spot Termination - spot_term = self.spot_terminated(path_i=path_i) - if spot_term: - job_state_out = self.job_state_keys["FAILED"] - #__| - - #| - Checking for "completed" file indicating success - completed_fle = self.completed_file(path_i=path_i) - if completed_fle: - job_state_out = self.job_state_keys["SUCCEEDED"] - #__| - - if os.path.isfile(path_i + "/.QUEUESTATE"): - bash_comm = "chmod 777 " + path_i + "/.QUEUESTATE" - os.system(bash_comm) - - with open(path_i + "/.QUEUESTATE", "w") as fle: - fle.write(str(job_state_out)) - fle.write("\n") - - return(job_state_out) - #__| - - def spot_terminated(self, path_i="."): - """ - """ - #| - spot_terminated - symlink_dir = path_i + "/simulation" - - spot_terminated = False - if os.path.isdir(symlink_dir): - - if os.path.exists(symlink_dir + "/spotTerminated"): - spot_terminated = True - print("Spot Termination") - - return(spot_terminated) - #__| - - def completed_file(self, path_i="."): - """ - """ - #| - completed_file - symlink_dir = path_i + "/simulation" - - completed_fle = False - if os.path.isdir(symlink_dir): - if os.path.exists(symlink_dir + "/completed"): - completed_fle = True - - return(completed_fle) - #__| - - def job_info_batch(self, job_id): - """ - """ - #| - job_info_batch - import boto3 - batch = boto3.client("batch") - job_descriptions = batch.describe_jobs(jobs=[job_id]) - - #| - Checking if Job is in AWS Batch - if len(job_descriptions["jobs"]) == 0: - return("job not in batch system") - else: - job_info = job_descriptions["jobs"][0] - #__| - - job_status = job_info["status"] - job_path = job_info["parameters"]["model"] - job_ram = job_info["parameters"]["ram"] - job_cpus = job_info["parameters"]["cpus"] - job_name = job_info["jobName"] - - job_queue_str = job_info["jobQueue"] - if "small" in job_queue_str: - job_queue = "small" - elif "medium" in job_queue_str: - job_queue = "medium" - elif "large" in job_queue_str: - job_queue = "large" - elif "test" in job_queue_str: - job_queue = "test" - - job_queue_dict = {"job_status": job_status, "job_path": job_path, - "job_id": job_id, "job_ram": job_ram, - "job_queue": job_queue, "job_cpus": job_cpus, - "job_name": job_name} - - return(job_queue_dict) - #__| - - #__| ********************************************************************** - - - -class DummyCluster(ComputerCluster): - """Placeholder class for when current cluster isn't supported.""" - #| - DummyCluster - def __init__(self, root_dir="."): - """ - """ - #| - __init__ - # self.job_queue_dir = "/u/if/flores12/usr/bin" - - self.job_data_dir = "" - self.root_dir = root_dir - - # self.default_sub_params = self.default_submission_parameters() - # self.queues = self.__queue_types__() - - - # self.job_queue_dir = "/u/if/flores12/usr/bin" - # self.job_state_keys = self.job_state_dict() - # self.job_queue_state_key = "STAT" - - self.error_file = "job.err" - self.out_file = "job.out" - - # self.aws_dir = os.environ["aws_sc"] - # self.job_queue_dir = self.aws_dir + "/jobs_bin" - - # self.job_queue_state_key = "job_status" - #__| - - - def submit_job_clust(self, **kwargs): - """just a placeholder function. - - Args: - **kwargs: - """ - #| - submit_job - print("submit_job_clust | DummyCluster") - print("Nothing happens!!") - #__| - - #__| +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Class for computer cluster operations, mainly batch. + +Development Notes: + TODO Modify .FINISHED implementation + + TODO Move the location of following command to base ComputerCluster class + with open(".SUBMITTED", "w") as fle: + fle.write("") + + TODO I don't think the child class attributes for error and out file are + being respected by ComputerCluster + +""" + +#| - Import Modules +import os +import sys +import subprocess +import datetime +import re +import shutil +import copy +import time + +import pandas as pd + +import json + +# My Modules +from misc_modules.misc_methods import merge_two_dicts +#__| + +#| - Methods + +def slurm_squeue_parse( + job_id, + path_i=None, + queue_state_key="STAT", + job_state_dict={ + "PD": "PENDING", + "R": "RUNNING", + "CF": "CONFIGURING", + "SUCCEEDED": "SUCCEEDED", + } + + ): + """Parse slurm squeue command for job state. + + Args: + job_id: + path_i: + queue_state_key: + """ + #| - slurm_squeue_parse + bash_comm = "squeue -j " + str(job_id) + + try: + out = subprocess.check_output( + bash_comm, + shell=True, + stderr=subprocess.STDOUT, + ) + + # 'JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)' + out = out.splitlines() + out = out[1].split(" ") + out = [i for i in out if i != ''] + + data_dict = { + "PARTITION": out[1], + "STAT": out[4], + # "CF": + } + + if path_i is not None: + with open(path_i + "/.QUEUESTATE", "w") as fle: + fle.write(job_state_dict[data_dict[queue_state_key]]) + fle.write("\n") + + except subprocess.CalledProcessError: + data_dict = None + pass + + except: + data_dict = None + pass + + return(data_dict) + #__| + +#__| + +############################################################################### +class ComputerCluster(): + """Base class for interfacing with computing resources. + + Development Notes: + TODO Create dummy cluster for WSL system + """ + + #| - ComputerCluster ****************************************************** + + def __init__(self, + ): + """Initialize the base ComputerCluster class.""" + #| - __init__ + self.root_dir = os.getcwd() + self.default_sub_params = self.default_submission_parameters() + + # self.username = self.__parse_username__() + + self.__parse_cluster_type__() + #__| + + #| - __old__ + # def __parse_username__(self): + # """ + # """ + # #| - __parse_username__ + # username = os.environ.get("USER") + # + # cond_1 = False + # if type(username) == str: + # cond_1 = True + # + # cond_2 = False + # if username is not None: + # cond_2 = True + # + # print(cond_1) + # print(cond_2) + # + # print(username) + # print("*******") + # return(username) + # #__| + #__| + + def __parse_cluster_type__(self): + """Parse for the current cluster system.""" + #| - __parse_cluster_type__ + clusters_dict = { + "aws": "AWSCluster", + "slac": "SLACCluster", + "sherlock": "SherlockCluster", + "nersc": "EdisonCluster", + } + + cluster_sys = os.environ.get("COMPENV") + + if cluster_sys in clusters_dict: + package = "dft_job_automat.compute_env" + name = clusters_dict[cluster_sys] + cluster = getattr(__import__(package, fromlist=[name]), name) + + self.cluster_sys = cluster_sys + + self.cluster = cluster( + root_dir=self.root_dir, + ) + else: + pass + self.cluster_sys = "dummy" + # TODO Create instance to dummy cluster class + + self.cluster = DummyCluster( + root_dir=self.root_dir, + ) + + home = os.environ.get("HOME") + try: + with open(home + "/.sys_files_rf/jobs_list_dir", "r") as fle: + jobs_dir = fle.read().rstrip() + except: + jobs_dir = None + + self.jobs_list_dir = jobs_dir + #__| + + def default_submission_parameters(self): + """Global submission parameters for cluster jobs.""" + #| - default_submission_parameters + def_params = { + "path_i": ".", + "job_name": "Default", + "job_script": "model.py", + "out_file": "job.out", + "err_file": "job.err", + } + + return(def_params) + #__| + + def is_job_submitted(self, path_i="."): + """Check if job has been submitted. + + Return TRUE if the job at 'path' has been submtted + A job is considered submitted if there exists a '.submitted' file + + Args: + path + """ + #| - add_jobs_queue_data + root_dir = os.getcwd() + os.chdir(path_i) + if os.path.isfile(".SUBMITTED"): + print("Directory already submitted, will be skipped") + os.chdir(root_dir) + submitted = True + else: + os.chdir(root_dir) + submitted = False + + return(submitted) + #__| + + def job_state(self, path_i="."): + """ + + Args: + path_i: + """ + #| - job_state + job_state = self.cluster.job_state(path_i=path_i) + + if job_state is None: + try: + with open(path_i + "/.QUEUESTATE", "r") as fle: + job_state = fle.read().rsplit() + + len_js = len(job_state) + assert type(job_state) == list and len_js == 1, "error" + # if type(job_state) == list and len(job_state) == 1: + job_state = job_state[0] + + except: + job_state = None + pass + + return(job_state) + #__| + + def job_info_batch(self, path_i="."): + """ + + Args: + path_i: + """ + #| - job_info_batch + + data_dict = self.cluster.job_info_batch(path_i=path_i) + + # jobs_file_path = self.jobs_list_dir + + + # jobs_file_path = self.jobs_list_dir + "/jobs.csv" + # df_new = pd.DataFrame([data_dict]) + # if os.path.isfile(jobs_file_path): + # df = pd.read_csv(jobs_file_path) + # df = df.append(df_new) + # else: + # df = df_new + # df.to_csv(jobs_file_path, index=False) + + + return(data_dict) + #__| + + def submit_job(self, **kwargs): + """Call cluster specific job submission method. + + Notes: + make sure to add 'path_i' key + + Args: + **kwargs: + """ + #| - submit_job + kwargs = merge_two_dicts(self.default_sub_params, kwargs) + + #| - Checking if job has already been submitted + if "path_i" in kwargs: + path_i = kwargs["path_i"] + else: + path_i = "." + + if self.is_job_submitted(path_i=path_i): + return(None) + #__| + + #| - Writing Job Submission Parameters + with open(".submission_params.json", "w") as fle: + json.dump(kwargs, fle, indent=2, skipkeys=True) + #__| + + self.cluster.submit_job_clust(**kwargs) + + #| - Writing Cluster System Info to File + if "path_i" in kwargs: + path_i = kwargs["path_i"] + + with open(".cluster_sys", "w") as fle: + # fle.write(self.cluster_sys) + fle.write(self.cluster_sys + "\n") + #__| + + #__| + + #__| ********************************************************************** + +############################################################################### + + +class EdisonCluster(ComputerCluster): + """NERSC Edison computing cluster. + + + I'll try to get this to work with Cori as well + """ + + #| - EdisonCluster ******************************************************** + def __init__(self, root_dir="."): + """Initialize Sherlock cluster instance. + + Args: + root_dir: + """ + #| - __init__ + # 24 cores (edison) 32 cpus (cori) + + nersc_host = os.environ["NERSC_HOST"] + if nersc_host == "cori": + self.cores_per_node = 32 # <-- Cori Haswell + # self.cores_per_node = 58 # <-- Cori KNL #TODO Switch to these + + elif nersc_host == "edison": + self.cores_per_node = 24 + + + # self.job_queue_dir = "/u/if/flores12/usr/bin" + + self.job_data_dir = "" + self.root_dir = root_dir + + self.default_sub_params = self.default_submission_parameters() + + self.queues = self.__queue_types__() + + # self.job_queue_dir = "/u/if/flores12/usr/bin" + + self.job_state_keys = self.job_state_dict() + self.job_queue_state_key = "STAT" # COMBAK + + self.error_file = "job.err" + self.out_file = "job.out" + + # self.aws_dir = os.environ["aws_sc"] + # self.job_queue_dir = self.aws_dir + "/jobs_bin" + # self.job_queue_state_key = "job_status" + #__| + + def default_submission_parameters(self): + """Defaul SLURM parameters for Sherlock cluster.""" + #| - default_submission_parameters + + def_params = { + "queue": "regular", # -p flag | regular, debug + ##SBATCH -p regular + #SBATCH -p debug + "nodes": "10", + #SBATCH -N 10 # 24 cpus per node on edison, 32 per node on cori haswell, 50? on knl + + "account": "m2997", # -A flag + #SBATCH -A m2997 + + "wall_time": "180", + #SBATCH -t 00:30:00 + + "priority": "scavenger", # --qos -q flag + + ##SBATCH --qos=scavenger + ##SBATCH --qos=premium + ##SBATCH --qos=debug + ##SBATCH --qos=regular + + "constraints": "haswell", + ##SBATCH -C haswell #this is for cori haswell (old) + ##SBATCH -C knl #new cori + + #SBATCH -e job.err#SBATCH -o job.out + } + + return(def_params) + #__| + + def submit_job_clust(self, **kwargs): + """Submit job to sherlck. + + Args: + **kwargs: + """ + #| - submit_job + time.sleep(1.5) + + #| - Merging Submission Parameters + params = merge_two_dicts(self.default_sub_params, kwargs) + + path = params["path_i"] + + + # Fixing debug flag specification + if params["priority"] == "debug": + params["queue"] = "debug" + + if params["queue"] == "debug": + params["priority"] = "debug" + #__| + + #| - Submit Job + os.chdir(path) + + if params["job_name"] == "Default": + params["job_name"] = os.getcwd() + + print("submitting job") + os.system("chmod 777 *") + # bash_command = "/u/if/flores12/bin/qv model.py" + #__| **** TEMP + + #| - Create vasp_run script + os.system("cd $SLURM_SUBMIT_DIR") + os.system("export TMPDIR=$SLURM_SUBMIT_DIR") + os.system("export VASP_SCRIPT=./run_vasp.py") + os.system("echo import os > run_vasp.py") + + exitcode_line = "exitcode = os.system('srun -n " + \ + str(int(self.cores_per_node * int(params["nodes"]))) + \ + " /project/projectdirs/m2997/special_edison')" + + line_2 = 'echo ' + '"' + exitcode_line + '" >> run_vasp.py' + os.system(line_2) # on edison + #__| + + #| - Bash Submisssion Command + bash_command = "/usr/bin/sbatch " + + + # The -q flag is being used in place of the -p flag + # Only the -q needs to be defined + bash_command += "-q " + str(params["queue"]) + " " + # bash_command += "-p " + str(params["queue"]) + " " + + bash_command += "--nodes " + str(params["nodes"]) + " " + bash_command += "--time " + str(params["wall_time"]) + " " + + # bash_command += "--qos " + str(params["priority"]) + " " # Didn't work + + bash_command += "--output " + str(params["out_file"]) + " " + bash_command += "--error " + str(params["err_file"]) + " " + bash_command += "-C haswell " + + bash_command += params["job_script"] + + print("Bash Submission Command:") + print(bash_command) + #__| + + try: + output = subprocess.Popen( + bash_command, + stdout=subprocess.PIPE, + shell=True, + ) + sub_time = datetime.datetime.now().isoformat() + # except subprocess.CalledProcessError, e: + except subprocess.CalledProcessError as e: + print("Ping stdout output:\n", e.output) + + os.chdir(self.root_dir) + print("JOB SKIPPED: ") + return(None) + + #| - Parsing Output + # out, err = pickle.load(open("job_sub_output.pickle", "r")) + + try: + # job_id = int(out_list[-1]) + out, err = output.communicate() + out_copy = copy.deepcopy(out) + out = out.strip() + out_list = out.split(" ") + job_id = int(out_list[-1]) + + except: + print("Couldn't parse for jobid") + job_id = None + + # out = output.communicate()[0] + # out_copy = copy.deepcopy(out) + # + # ind = out.find("job") + # out = out[ind + 3:] + # + # jobid = re.sub("[^0-9]", "", out) + # + # try: + # jobid = int(jobid) + # + # except: + # print("Couldn't parse for jobid | !@!!") + # jobid = None + # pass + # + # if type(jobid) == int: + # jobid = jobid + # else: + # jobid = None + #__| + + #| - Writing Files + with open(".SUBMITTED", "w") as fle: + fle.write("\n") + + with open(".bash_comm", "w") as fle: + fle.write(str(bash_command) + str("\n")) + + with open(".jobid", "w") as fle: + fle.write(str(job_id) + str("\n")) + + if sys.version_info >= (3, 0): + with open(".sub_out", "wb") as fle: + fle.write(out_copy) + + else: + with open(".sub_out", "w") as fle: + fle.write(out_copy) + #__| + + os.chdir(self.root_dir) + + #| - Save subprocess output for analysis + # import pickle + # + # pickle.dump( + # output.communicate(), + # open("job_sub_output.pickle", "wb"), + # ) + # return(output) + #__| + + # return(out, jobid) + #__| + + def job_state_dict(self): + """ + """ + #| - job_state_dict + job_state_dict = { + "PD": "PENDING", + "R": "RUNNING", + "CF": "CONFIGURING", + "SUCCEEDED": "SUCCEEDED", + + # "FAILED": "FAILED", + # "STARTING": "STARTING", + # "RUNNABLE": "PENDING", + # "SUBMITTED": "SUBMITTED", + } + + return(job_state_dict) + #__| + + def __queue_types__(self): + """Queue types for Edison cluster + """ + #| - __queue_types__ + queue_list = [ + "regular", + "debug", + "premium", + ] + + return(queue_list) + #__| + + def job_info_batch(self, job_id, path_i=None): + """ + """ + #| - job_info_batch + data_dict = slurm_squeue_parse( + job_id, + path_i=path_i, + queue_state_key=self.job_queue_state_key, + job_state_dict=self.job_state_keys, + ) + + return(data_dict) + + #| - __old__ + # bash_comm = "squeue -j " + str(job_id) + # + # try: + # out = subprocess.check_output( + # bash_comm, + # shell=True, + # stderr=subprocess.STDOUT, + # ) + # + # # 'JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)' + # out = out.splitlines() + # out = out[1].split(" ") + # out = [i for i in out if i != ''] + # + # data_dict = { + # "PARTITION": out[1], + # "STAT": out[4], + # # "CF": + # } + # + # if path_i is not None: + # key = self.job_queue_state_key + # with open(path_i + "/.QUEUESTATE", "w") as fle: + # fle.write(self.job_state_keys[data_dict[key]]) + # fle.write("\n") + # + # except subprocess.CalledProcessError: + # data_dict = None + # pass + # + # except: + # data_dict = None + # pass + # + # + # return(data_dict) + # + # bash_comm = "squeue -j " + str(job_id) + # + # try: + # out = subprocess.check_output( + # bash_comm, + # shell=True, + # stderr=subprocess.STDOUT, + # ) + # + # # 'JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)' + # out = out.splitlines() + # out = out[1].split(" ") + # out = [i for i in out if i != ''] + # + # data_dict = { + # "PARTITION": out[1], + # "STAT": out[4], + # # "CF": + # } + # + # if path_i is not None: + # key = self.job_queue_state_key + # with open(path_i + "/.QUEUESTATE", "w") as fle: + # fle.write(self.job_state_keys[data_dict[key]]) + # fle.write("\n") + # + # except subprocess.CalledProcessError: + # data_dict = None + # pass + # + # except: + # print("tmp except final") + # data_dict = None + # pass + # + # # TEMP_PRINT + # print(data_dict) + # + # return(data_dict) + #__| + + #__| + + def completed_file(self, path_i="."): + """Check whether ".FINISHED" file exists. + + Indicates that the job has gone to completion + + Args: + path_i: + """ + #| - completed_file + completed_fle = False + if os.path.exists(path_i + "/.FINISHED"): + completed_fle = True + + return(completed_fle) + #__| + + def job_state(self, path_i="."): + """Return job state of path_i --> job_i. + + Args: + path_i + """ + #| - job_state + job_id = self.get_jobid(path_i=path_i) + + # print("compute_env job_state job_id:") + # print(job_id) + + + job_state_out = None + if job_id is not None: + job_info = self.job_info_batch(job_id, path_i=path_i) + + # print("job_info **(***(*))") + # print(job_info) + + if job_info is not None: + key = self.job_queue_state_key + if key in job_info: + job_state_out = job_info[key] + job_state_out = self.job_state_keys[job_state_out] + + #| - Checking for "completed" file indicating success + completed_fle = self.completed_file(path_i=path_i) + if completed_fle: + job_state_out = self.job_state_keys["SUCCEEDED"] + #__| + + return(job_state_out) + #__| + + def get_jobid(self, path_i="."): + """Return job ID of job_i. + + Args: + path_i: + """ + #| - get_jobid + fileid_path = path_i + "/.jobid" + if os.path.isfile(fileid_path): + with open(path_i + "/.jobid") as fle: + jobid = fle.read().strip() + else: + jobid = None + + return(jobid) + #__| + + #__| ********************************************************************** + + +class SLACCluster(ComputerCluster): + """SLAC computing cluster.""" + + #| - SLACCluster ********************************************************** + def __init__(self, + root_dir=".", + ): + """ + """ + #| - __init__ + self.root_dir = root_dir + self.default_sub_params = self.default_submission_parameters() + self.job_data_dir = "" + + self.job_queue_dir = "/u/if/flores12/usr/bin" + self.queues = self.__queue_types__() + + self.job_state_keys = self.job_state_dict() + self.job_queue_state_key = "STAT" + #__| + + def job_state_dict(self): + """ + """ + #| - job_state_dict + job_state_dict = { + # "PENDING": "PEND", + # "FINISHED": "DONE", + # "RUNNING": "RUN", + # "FAILED": "EXIT", + "PEND": "PENDING", + "DONE": "SUCCEEDED", + "RUN": "RUNNING", + "EXIT": "FAILED", + "UNKWN": "UNKNOWN", + } + + return(job_state_dict) + #__| + + def __queue_types__(self): + """Queue types for SLAC cluster + """ + #| - __queue_types__ + queue_list = [ + "suncat-test", + "suncat", + "suncat2", + "suncat2-xlong", + "suncat3", + "suncat3-xlong", + "suncat-xlong", + ] + + return(queue_list) + #__| + + def default_submission_parameters(self): + """ + """ + #| - default_submission_parameters + def_params = { + "queue": "suncat", + "cpus": "8", + "wall_time": "3000", + # "memory": "6000", + # "job_name": "Default", + "job_script": "model.py" + } + + return(def_params) + #__| + + def submit_job_clust(self, **kwargs): + """FIX This should update data table + + ABSOLUTELY NEED TO DEFINE 'path_i' FOR THIS TO WORK!!!!!!!!!!!!!!!!!! + + Submits job to aws cluster. Copies PythonModules folder into + job directory + """ + #| - submit_job + + #| - Merging Submission Parameters + params = merge_two_dicts(self.default_sub_params, kwargs) + + path = params["path_i"] + #__| + + #| - Checking if job has already been submitted + # if self.is_job_submitted(): + # return(None) + #__| + + #| - Submit Job ******************************************************* + + os.chdir(path) + + if params["job_name"] == "Default": + params["job_name"] = os.getcwd() + + print("submitting job") + + os.system("chmod 777 *") + + # bash_command = "/u/if/flores12/bin/qv model.py" + + bash_command = "/afs/slac/g/suncat/bin/dobsub " + bash_command += "-q " + str(params["queue"]) + " " + bash_command += "-n " + str(params["cpus"]) + " " + bash_command += "-W " + str(params["wall_time"]) + " " + bash_command += "-o " + str(params["out_file"]) + " " + bash_command += "-e " + str(params["err_file"]) + " " + + # bash_command += "-o job.out " + # bash_command += "-e job.err " + + # bash_command += "-M " + params["memory"] + " " + bash_command += "-J " + params["job_name"] + " " + bash_command += params["job_script"] + + #| - FIXME Python 2 --> 3 + print("Python version info") + print(sys.version_info) + if (sys.version_info > (3, 0)): + try: + output = subprocess.Popen( + bash_command, + stdout=subprocess.PIPE, + shell=True, + ) + sub_time = datetime.datetime.now().isoformat() + + + except subprocess.CalledProcessError as e: + print("Ping stdout output:\n", e.output) + os.chdir(self.root_dir) + print("JOB SKIPPED: ") + return(None) + + else: + try: + output = subprocess.Popen( + bash_command, + stdout=subprocess.PIPE, + shell=True, + ) + sub_time = datetime.datetime.now().isoformat() + + # except subprocess.CalledProcessError, e: + except subprocess.CalledProcessError as e: + print("Ping stdout output:\n", e.output) + # print "Ping stdout output:\n", e.output + os.chdir(self.root_dir) + print("JOB SKIPPED: ") + return(None) + + #| - __old + # try: + # output = subprocess.Popen( + # bash_command, + # stdout=subprocess.PIPE, + # shell=True, + # ) + # sub_time = datetime.datetime.now().isoformat() + # + # # except subprocess.CalledProcessError, e: + # except subprocess.CalledProcessError as e: + # + # print "Ping stdout output:\n", e.output + # + # os.chdir(self.root_dir) + # print("JOB SKIPPED: ") + # return(None) + + #__| + + #__| + + #__| + + #| - Parsing Output + out = output.communicate()[0] + ind = out.find("Job <") + + out1 = out[ind:] + ind1 = out1.find("<") + ind2 = out1.find(">") + + jobid = out1[ind1 + 1:ind2] + + if jobid.isdigit(): + jobid = int(jobid) + else: + jobid = None + #__| + + #| - Writing Files + with open(".SUBMITTED", "w") as fle: + fle.write("\n") + + with open(".bash_comm", "w") as fle: + fle.write(str(bash_command) + str("\n")) + + with open(".jobid", "w") as fle: + fle.write(str(jobid) + str("\n")) + + with open(".sub_out", "w") as fle: + fle.write(out) + #__| + + os.chdir(self.root_dir) + + return(out, jobid) + #__| + + def get_jobid(self, path_i="."): + """ + """ + #| - get_jobid + # path_i = "." + + if os.path.isfile(path_i + "/.jobid"): + with open(path_i + "/.jobid") as fle: + jobid = fle.read().strip() + else: + jobid = None + + return(jobid) + #__| + + def job_info_batch(self, path_i="."): + """ + """ + #| - job_info_batch + job_id = self.get_jobid(path_i) + + #| - If No Job ID File Return None + if job_id is None: + return(None) + #__| + + bash_comm = "/usr/local/bin/bjobs -w" + " " + job_id + out = subprocess.check_output( + bash_comm, + shell=True, + stderr=subprocess.STDOUT, + ) + + #| - Checking if Job Id Still in Batch System + if "is not found" in out: + print("Job ID no longer in batch system, or ID is wrong") + return(None) + #__| + + #| - Parsing bsub Output into Dict + out = out.split() + headers = out[0:8] + data = out[8:] + data_1 = data[0:7] + + data_dict = { + "JOBID": data_1[0], + "USER": data_1[1], + "STAT": data_1[2], + "QUEUE": data_1[3], + "FROM_HOST": data_1[4], + "EXEC_HOST": data_1[5], + "JOB_NAME": data_1[6], + } + + time = data[7:] + time = "_".join(time) + data_dict["SUBMIT_TIME"] = time + #__| + + #| - bjob Command to Get Job Path From Job ID + bash_comm_2 = "/usr/local/bin/bjobs -o" + " 'exec_cwd' " + job_id + out2 = subprocess.check_output(bash_comm_2, shell=True) + out2 = out2.split() + data_dict["EXEC_CWD"] = out2[1] + #__| + + # self.write_job_queue_state_file(path=path_i) + + #| - write_job_queue_state_file + key = self.job_queue_state_key + with open(path_i + "/.QUEUESTATE", "w") as fle: + fle.write(self.job_state_keys[data_dict[key]]) + fle.write("\n") + #__| + + return(data_dict) + #__| + + def job_state(self, path_i="."): + """Query job state. + + # FIXME This should update jobs table + + Args: + path_i + """ + #| - job_state + job_info = self.job_info_batch(path_i=path_i) + + if job_info is not None: + key = self.job_queue_state_key + if key in job_info: + job_state_out = job_info[key] + job_state_out = self.job_state_keys[job_state_out] + else: + job_state_out = None + + return(job_state_out) + #__| + + #__| ********************************************************************** + + +class SherlockCluster(ComputerCluster): + """Sherlock computing cluster.""" + + #| - SherlockCluster ****************************************************** + def __init__(self, root_dir="."): + """Initialize Sherlock cluster instance. + + Args: + root_dir: + """ + #| - __init__ + # self.job_queue_dir = "/u/if/flores12/usr/bin" + + self.job_data_dir = "" + self.root_dir = root_dir + + self.username = self.__parse_username__() + self.default_sub_params = self.default_submission_parameters() + + self.queues = self.__queue_types__() + + # self.job_queue_dir = "/u/if/flores12/usr/bin" + + self.job_state_keys = self.job_state_dict() + self.job_queue_state_key = "STAT" + + + self.error_file = "job.err" + self.out_file = "job.out" + + # self.aws_dir = os.environ["aws_sc"] + # self.job_queue_dir = self.aws_dir + "/jobs_bin" + + # self.job_queue_state_key = "job_status" + #__| + + + def __parse_username__(self): + """ + """ + #| - __parse_username__ + username = os.environ.get("USER") + + cond_1 = False + if type(username) == str: + cond_1 = True + + cond_2 = False + if username is not None: + cond_2 = True + + return(username) + #__| + + + def default_submission_parameters(self): + """Defaul SLURM parameters for Sherlock cluster.""" + #| - default_submission_parameters + + def_params = { + "queue": "owners,iric,normal", # -p flag + "nodes": "1", # --nodes + "cpus": "16", # --ntasks-per-node + "memory": "4000", # --mem-per-cpu + "wall_time": "720", # --time (720min -> 12hrs) + "job_name": "Default", # --job-name + "priority": "normal", # --qos + # "email": "flores12@stanford.edu", # --mail-user + "email": self.username + "@stanford.edu", # --mail-user + "email_mess": "FAIL", # --mail-type + } + + return(def_params) + #__| + + def submit_job_clust(self, **kwargs): + """Submits job to sherlck. + + Args: + **kwargs: + """ + #| - submit_job + time.sleep(1.5) + + #| - Merging Submission Parameters + params = merge_two_dicts(self.default_sub_params, kwargs) + + path = params["path_i"] + #__| + + #| - Submit Job + os.chdir(path) + + if params["job_name"] == "Default": + params["job_name"] = os.getcwd() + + print("submitting job") + os.system("chmod 777 *") + # bash_command = "/u/if/flores12/bin/qv model.py" + #__| **** TEMP + + #| - Bash Submisssion Command + bash_command = "/usr/bin/sbatch " + + bash_command += "-p " + str(params["queue"]) + " " + bash_command += "--nodes " + str(params["nodes"]) + " " + bash_command += "--ntasks-per-node " + str(params["cpus"]) + " " + bash_command += "--mem-per-cpu " + str(params["memory"]) + " " + bash_command += "--time " + str(params["wall_time"]) + " " + bash_command += "--job-name " + str(params["job_name"]) + " " + bash_command += "--qos " + str(params["priority"]) + " " + bash_command += "--mail-user " + str(params["email"]) + " " + bash_command += "--mail-type " + str(params["email_mess"]) + " " + bash_command += "--output " + str(params["out_file"]) + " " + bash_command += "--error " + str(params["err_file"]) + " " + bash_command += "-C CPU_GEN:HSW " # COMBAK Formalize this cpu architecture filter + + bash_command += params["job_script"] + + print("Bash Submission Command:") + print(bash_command) + #__| + + try: + + if sys.version_info[0] < 3: + # raise Exception("Must be using Python 3") + output = subprocess.Popen( + bash_command, + stdout=subprocess.PIPE, + shell=True, + # encoding="utf8", + ) + + else: + output = subprocess.Popen( + bash_command, + stdout=subprocess.PIPE, + shell=True, + encoding="utf8", + ) + + sub_time = datetime.datetime.now().isoformat() + + # except subprocess.CalledProcessError, e: + except subprocess.CalledProcessError as e: + print("Ping stdout output:\n", e.output) + + os.chdir(self.root_dir) + print("JOB SKIPPED: ") + return(None) + + #| - Parsing Output + out = output.communicate()[0] + out_copy = copy.deepcopy(out) + + ind = out.find("job") + + out = out[ind + 3:] + + jobid = re.sub("[^0-9]", "", out) + + try: + jobid = int(jobid) + + except: + print("Couldn't parse for jobid | !@!!") + jobid = None + pass + + if type(jobid) == int: + jobid = jobid + else: + jobid = None + #__| + + #| - Writing Files + with open(".SUBMITTED", "w") as fle: + fle.write("\n") + + with open(".bash_comm", "w") as fle: + fle.write(str(bash_command) + str("\n")) + + with open(".jobid", "w") as fle: + fle.write(str(jobid) + str("\n")) + + with open(".sub_out", "w") as fle: + fle.write(out_copy) + + #| - Writing Job Submission Parameters + with open(".submission_params_2.json", "w") as fle: + json.dump(params, fle, indent=2, skipkeys=True) + #__| + + #__| + + os.chdir(self.root_dir) + + return(out, jobid) + + #__| + + def job_state_dict(self): + """ + """ + #| - job_state_dict + job_state_dict = { + "PD": "PENDING", + "R": "RUNNING", + "CF": "CONFIGURING", + "SUCCEEDED": "SUCCEEDED", + + # "FAILED": "FAILED", + # "STARTING": "STARTING", + # "RUNNABLE": "PENDING", + # "SUBMITTED": "SUBMITTED", + } + + return(job_state_dict) + #__| + + def __queue_types__(self): + """Queue types for SLAC cluster + """ + #| - __queue_types__ + queue_list = [ + "owners", + "iric", + ] + + return(queue_list) + #__| + + def get_jobid(self, path_i="."): + """Return the job id. + + Args: + path_i: + """ + #| - get_jobid + # # path_i = "." + # fileid_path = path_i + "/.jobid" + # # print(fileid_path) + # if os.path.isfile(fileid_path): + # with open(path_i + "/.jobid") as fle: + # jobid = fle.read().strip() + # else: + # jobid=None + # + # return(jobid) + #__| + + def job_info_batch(self, job_id, path_i=None): + """ + """ + #| - job_info_batch + data_dict = slurm_squeue_parse( + job_id, + path_i=path_i, + queue_state_key=self.job_queue_state_key, + job_state_dict=self.job_state_keys, + ) + + return(data_dict) + + #| - __old__ + # bash_comm = "squeue -j " + str(job_id) + # + # try: + # out = subprocess.check_output( + # bash_comm, + # shell=True, + # stderr=subprocess.STDOUT, + # ) + # + # # 'JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)' + # out = out.splitlines() + # out = out[1].split(" ") + # out = [i for i in out if i != ''] + # + # data_dict = { + # "PARTITION": out[1], + # "STAT": out[4], + # # "CF": + # } + # + # if path_i is not None: + # key = self.job_queue_state_key + # with open(path_i + "/.QUEUESTATE", "w") as fle: + # fle.write(self.job_state_keys[data_dict[key]]) + # fle.write("\n") + # + # except subprocess.CalledProcessError: + # data_dict = None + # pass + # + # except: + # data_dict = None + # pass + # + # + # return(data_dict) + #__| + + #__| + + def completed_file(self, path_i="."): + """ + Check whether ".FINISHED" file exists. + + Indicates that the job has gone to completion + + Args: + path_i: + """ + #| - completed_file + completed_fle = False + if os.path.exists(path_i + "/.FINISHED"): + completed_fle = True + + return(completed_fle) + #__| + + def job_state(self, path_i="."): + """ + Return job state of path_i --> job_i. + + Args: + path_i + """ + #| - job_state + job_id = self.get_jobid(path_i=path_i) + + job_state_out = None + if job_id is not None: + job_info = self.job_info_batch(job_id, path_i=path_i) + + if job_info is not None: + key = self.job_queue_state_key + if key in job_info: + job_state_out = job_info[key] + job_state_out = self.job_state_keys[job_state_out] + + #| - Checking for "completed" file indicating success + completed_fle = self.completed_file(path_i=path_i) + if completed_fle: + job_state_out = self.job_state_keys["SUCCEEDED"] + #__| + + return(job_state_out) + + #__| + + def get_jobid(self, path_i="."): + """ + Return job ID of job_i. + + Args: + path_i: + """ + #| - get_jobid + fileid_path = path_i + "/.jobid" + if os.path.isfile(fileid_path): + with open(path_i + "/.jobid") as fle: + jobid = fle.read().strip() + else: + jobid = None + + return(jobid) + #__| + + #__| ********************************************************************** + + +class AWSCluster(ComputerCluster): + """AWS EC2 computing resource. + + Must define $awsdir environment variable + ex. $awsdir=/scratch/users/flores12/AWS/matr.io + """ + + #| - AWSCluster *********************************************************** + def __init__(self, + root_dir=".", + ): + """ + """ + #| - __init__ + self.job_data_dir = "/simulation" + self.root_dir = root_dir + self.default_sub_params = self.default_submission_parameters() + self.aws_dir = os.environ.get("awsdir", "") + + #| - Create job_queue_dir + self.job_queue_dir = os.path.join( + self.aws_dir, + "jobs_bin") + + directory = self.job_queue_dir + if not os.path.exists(directory): + os.makedirs(directory) + #__| + + self.job_state_keys = self.job_state_dict() + self.queues = self.__queue_types__() + self.job_queue_state_key = "job_status" + self.error_file = "err" + self.out_file = "out" + #__| + + def default_submission_parameters(self): + """ + """ + #| - default_submission_parameters + def_params = { + "queue": "medium", + "cpus": "default", + # "wall_time": "2000", + # "memory": "6000", + # "job_name": "Default", + "job_script": "model.py", + + "copy_PythonModules": True, + "copy_PythonPackages": False, + } + + return(def_params) + #__| + + def submit_job_clust(self, **kwargs): + """Submit job to AWS cluster. + + Copies PythonModules and PythonPackages folder into job directory + + Args: + kwargs + """ + #| - submit_job_clust + + #| - Job Parameters + params = merge_two_dicts(self.default_sub_params, kwargs) + + path = params["path_i"] + copy_PythonModules = params["copy_PythonModules"] + copy_PythonPackages = params["copy_PythonPackages"] + cpus = params["cpus"] + queue = params["queue"] + #__| + + root_dir = os.getcwd() + if path is None: + path = root_dir + + #| - Checking if job has already been submitted + os.chdir(path) + if os.path.isfile(".SUBMITTED"): + print("Directory already submitted, will be skipped") + os.chdir(root_dir) + return(None) # <-------- SKIP JOB -------------------------------- + else: + os.chdir(root_dir) + #__| + + self.__copy_pyth_mods_packs_to_job_dir__( + path, + copy_mods=copy_PythonModules, + copy_packs=copy_PythonPackages, + ) + + #| - Submit Job + # Args: path, root_dir, queue, cpus + + os.chdir(path) + + if os.path.isfile(".SUBMITTED"): + print("Directory already submitted, will be skipped") + os.chdir(root_dir) + return(None) + else: + print("submitting job") + aws_dir = self.aws_dir + + if cpus == "default": + bash_command = aws_dir + "/bin/trisub -q " + queue + else: + + #| - Checking that number of cpus is within allows + if queue == "medium": + if cpus > 4: + print("Medium queue can't have more than 4 cpus") + print(" setting cpus to 4") + cpus = 4 + #__| + + bash_command = aws_dir + "/bin/trisub -c " + str(cpus) + \ + " -q " + queue + + # try: + output = subprocess.check_output( + bash_command, + shell=True, + universal_newlines=True, # CHANGED + ) + + sub_time = datetime.datetime.now().isoformat() + + # # except subprocess.CalledProcessError, e: + # except subprocess.CalledProcessError as e: + # print("Ping stdout output:\n", e.output) + # + # os.chdir(root_dir) + # print("JOB SKIPPED: ") + # return(None) + #__| + + os.system("chmod 777 " + path + "/*") + os.system("chmod 777 " + path) + + #| - Parsing Submission for Job ID + output = output.splitlines() + print(output) # CHANGED + + for line in output: + if "jobId" in line: + lst = line.split('"') + job_id_ind = (lst.index("jobId") + 2) + jobId = lst[job_id_ind] + + file = open(".jobid", "w") + file.write(jobId + "\n") + #__| + + file = open(".SUBMITTED", "w") + file.close() + + os.chdir(root_dir) + + #| - Querying AWS For Job Info + job_queue_dict = self.job_info_batch(jobId) + job_queue_dict["submit_time"] = sub_time + + jobs_file_path = self.job_queue_dir + "/jobs.csv" + + df_new = pd.DataFrame([job_queue_dict]) + if os.path.isfile(jobs_file_path): + df = pd.read_csv(jobs_file_path) + df = df.append(df_new) + else: + df = df_new + + df.to_csv(jobs_file_path, index=False) + #__| + + return job_queue_dict + #__| + + def job_state_dict(self): + """ + """ + #| - job_state_dict + job_state_dict = { + "PENDING": "PENDING", + "SUCCEEDED": "SUCCEEDED", + "FAILED": "FAILED", + "RUNNING": "RUNNING", + "STARTING": "STARTING", + + # RUNNABLE in AWS really means pending + # "RUNNABLE": "RUNNABLE", + + "RUNNABLE": "PENDING", + "SUBMITTED": "SUBMITTED", + } + + return(job_state_dict) + #__| + + def __queue_types__(self): + """Queue types for AWS cluster + """ + #| - __queue_types__ + queue_list = [ + "test", + "small", + "medium", + "large", + ] + + return(queue_list) + #__| + + def __copy_pyth_mods_packs_to_job_dir__( + self, + path_i, + copy_mods=True, + copy_packs=True, + ): + """ + """ + #| - __copy_pyth_mods_packs_to_job_dir__ + copy_PythonModules = copy_mods + copy_PythonPackages = copy_packs + + #| - Copy PYTHONMODULES to Job Directory + if copy_PythonModules: + if os.path.isdir(path_i + "/PythonModules") is True: + print("PythonModules already exists, erasing and recopying") + shutil.rmtree(path_i + "/PythonModules") + # py_mod = os.environ["python_modules"] # Old pyth mods dir + py_mod = os.environ["PYTHONMODULES"] + shutil.copytree(py_mod, path_i + "/PythonModules") + else: + # py_mod = os.environ["python_modules"] + py_mod = os.environ["PYTHONMODULES"] + shutil.copytree(py_mod, path_i + "/PythonModules") + #__| + + #| - Copy Python Packages to Job Directory + if copy_PythonPackages: + if os.path.isdir(path_i + "/PythonPackages") is True: + print("PythonPackages already exists, erasing and recopying") + shutil.rmtree(path_i + "/PythonPackages") + py_pack = os.environ["PYTHONPACKAGES"] + shutil.copytree(py_pack, path_i + "/PythonPackages") + else: + py_pack = os.environ["PYTHONPACKAGES"] + shutil.copytree(py_pack, path_i + "/PythonPackages") + #__| + + #__| + + def get_jobid(self, path_i="."): + """ + """ + #| - get_jobid + # path_i = "." + fileid_path = path_i + "/.jobid" + if os.path.isfile(fileid_path): + with open(path_i + "/.jobid") as fle: + jobid = fle.read().strip() + else: + jobid = None + + return(jobid) + #__| + + def job_state(self, path_i="."): + """ + """ + #| - job_state + job_id = self.get_jobid(path_i=path_i) + job_state_out = None + if job_id is not None: + job_info = self.job_info_batch(job_id) + + if job_info is not None: + key = self.job_queue_state_key + if key in job_info: + job_state_out = job_info[key] + job_state_out = self.job_state_keys[job_state_out] + + #| - Checking for Spot Termination + spot_term = self.spot_terminated(path_i=path_i) + if spot_term: + job_state_out = self.job_state_keys["FAILED"] + #__| + + #| - Checking for "completed" file indicating success + completed_fle = self.completed_file(path_i=path_i) + if completed_fle: + job_state_out = self.job_state_keys["SUCCEEDED"] + #__| + + if os.path.isfile(path_i + "/.QUEUESTATE"): + bash_comm = "chmod 777 " + path_i + "/.QUEUESTATE" + os.system(bash_comm) + + with open(path_i + "/.QUEUESTATE", "w") as fle: + fle.write(str(job_state_out)) + fle.write("\n") + + return(job_state_out) + #__| + + def spot_terminated(self, path_i="."): + """ + """ + #| - spot_terminated + symlink_dir = path_i + "/simulation" + + spot_terminated = False + if os.path.isdir(symlink_dir): + + if os.path.exists(symlink_dir + "/spotTerminated"): + spot_terminated = True + print("Spot Termination") + + return(spot_terminated) + #__| + + def completed_file(self, path_i="."): + """ + """ + #| - completed_file + symlink_dir = path_i + "/simulation" + + completed_fle = False + if os.path.isdir(symlink_dir): + if os.path.exists(symlink_dir + "/completed"): + completed_fle = True + + return(completed_fle) + #__| + + def job_info_batch(self, job_id): + """ + """ + #| - job_info_batch + import boto3 + batch = boto3.client("batch") + job_descriptions = batch.describe_jobs(jobs=[job_id]) + + #| - Checking if Job is in AWS Batch + if len(job_descriptions["jobs"]) == 0: + return("job not in batch system") + else: + job_info = job_descriptions["jobs"][0] + #__| + + job_status = job_info["status"] + job_path = job_info["parameters"]["model"] + job_ram = job_info["parameters"]["ram"] + job_cpus = job_info["parameters"]["cpus"] + job_name = job_info["jobName"] + + job_queue_str = job_info["jobQueue"] + if "small" in job_queue_str: + job_queue = "small" + elif "medium" in job_queue_str: + job_queue = "medium" + elif "large" in job_queue_str: + job_queue = "large" + elif "test" in job_queue_str: + job_queue = "test" + + job_queue_dict = {"job_status": job_status, "job_path": job_path, + "job_id": job_id, "job_ram": job_ram, + "job_queue": job_queue, "job_cpus": job_cpus, + "job_name": job_name} + + return(job_queue_dict) + #__| + + #__| ********************************************************************** + + + +class DummyCluster(ComputerCluster): + """Placeholder class for when current cluster isn't supported.""" + #| - DummyCluster + def __init__(self, root_dir="."): + """ + """ + #| - __init__ + # self.job_queue_dir = "/u/if/flores12/usr/bin" + + self.job_data_dir = "" + self.root_dir = root_dir + + # self.default_sub_params = self.default_submission_parameters() + # self.queues = self.__queue_types__() + + + # self.job_queue_dir = "/u/if/flores12/usr/bin" + # self.job_state_keys = self.job_state_dict() + # self.job_queue_state_key = "STAT" + + self.error_file = "job.err" + self.out_file = "job.out" + + # self.aws_dir = os.environ["aws_sc"] + # self.job_queue_dir = self.aws_dir + "/jobs_bin" + + # self.job_queue_state_key = "job_status" + #__| + + + def submit_job_clust(self, **kwargs): + """just a placeholder function. + + Args: + **kwargs: + """ + #| - submit_job + print("submit_job_clust | DummyCluster") + print("Nothing happens!!") + #__| + + #__| diff --git a/dft_job_automat/job_analysis.py b/dft_job_automat/job_analysis.py index bba5270..0d1e211 100644 --- a/dft_job_automat/job_analysis.py +++ b/dft_job_automat/job_analysis.py @@ -1,1537 +1,1537 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -"""Class to analyse data using the DFT_Jobs_Setup class. - - -Development Notes: - TODO Automaticall read README files contained within job folders - TODO Delete the duplicate methods for job_status -""" - -#| - Import Modules -import os -import sys - -import pickle -import copy -import glob - -from datetime import datetime - - - -import pandas as pd -import numpy as np - -from ase.visualize import view - -# My Modules -from dft_job_automat.job_setup import DFT_Jobs_Setup -#__| - -class DFT_Jobs_Analysis(DFT_Jobs_Setup): - """Analysis methods for jobs in tree structure. - - # TODO path --> path_i - # TODO Modify .FINISHED implementation - - Parent class to DFT_Jobs_Setup - """ - - #| - DFT_Jobs_Analysis **************************************************** - - #| - Class Variables - finished_fle = ".FINISHED.new" - #__| - - def __init__(self, - tree_level=None, - level_entries=None, - skip_dirs_lst=None, - indiv_dir_lst=None, # <----------------------------------------------- - indiv_job_lst=None, - indiv_job_dict_lst=None, - root_dir=".", - working_dir=".", - update_job_state=False, - load_dataframe=True, - dataframe_dir=None, - job_type_class=None, - methods_to_run=None, - folders_exist=None, - parse_all_revisions=True, - parallel_exec=False, - ): - """Initialize DFT_Jobs_Analysis Instance. - - Args: - system: - tree_level: - level_entries: - skip_dirs_lst: - working_dir: - update_job_state: - Updates job status for all jobs in ensemble. - load_dataframe: - dataframe_dir: - Specify location of dataframe if not in working_dir. - job_type_class: - Job type specific class instance which constains methods - specific to the jobs being run that parse job folders. - methods_to_run : - Additional methods to run on each job dir and return value to - populate data column with. - """ - #| - __init__ - - #| - Instantiate DFT_Jobs_Setup - DFT_Jobs_Setup.__init__(self, - tree_level=tree_level, - level_entries=level_entries, - indiv_dir_lst=indiv_dir_lst, - indiv_job_lst=indiv_job_lst, - indiv_job_dict_lst=indiv_job_dict_lst, - - skip_dirs_lst=skip_dirs_lst, - root_dir=root_dir, - working_dir=working_dir, - folders_exist=folders_exist, - parse_all_revisions=parse_all_revisions, - ) - - #__| - - #| - Class Attributes - self.dataframe_dir = dataframe_dir - self.parallel_exec = parallel_exec - #__| - - #| - General Methods - if update_job_state is True: - print("update_job_state == True") - self.add_data_column( - self.job_state, - column_name="job_state", - parallel_exec=self.parallel_exec, - ) - self.add_data_column( - self.job_state_3, - column_name="N/A", - parallel_exec=self.parallel_exec, - ) - #__| - - #| - Job Type Specific Methods - # method = DFT_Methods().atom_type_num_dict - # self.add_data_column(method, column_name="TEMP", allow_failure=False) - - # TODO | Why is this only write the data frame if the there are job - # methods to run - write_data_frame = False - if load_dataframe is True: - self.__load_dataframe__() - - else: - - #| - job_type_class instance attached methods - if job_type_class is not None: - job_type_inst = job_type_class - - for method in job_type_inst.methods_to_run: - method_ref = getattr(job_type_inst, method) - - self.method = method_ref # COMBAK Is this necessary?? - - self.add_data_column( - method_ref, - column_name=method, - allow_failure=True, - # allow_failure=False, - parallel_exec=self.parallel_exec, - ) - - write_data_frame = True - #__| - - #| - methods_to_run - if methods_to_run is not None: - for method in methods_to_run: - - self.add_data_column( - method, - - # Not sure where this func_name attr. came from - # column_name=method.func_name, - column_name=method.__name__, - - allow_failure=True, - # allow_failure=False, - parallel_exec=self.parallel_exec, - ) - - write_data_frame = True - #__| - - if write_data_frame: - self.__write_dataframe__() - - self.add_all_columns_from_file() - #__| - - #__| - - #| - Job Log ************************************************************** - - def add_jobs_queue_data(self): - """Add jobs queue data to jobs.csv file.""" - #| - add_jobs_queue_data - # COMBAK Not finished - #__| - - def job_queue_info(self, path_i): - """ - Return row corresponding to job in path_i from the job queue dir. - - # FIXME Set up the jobs.csv system to work - - Args: - path_i: - """ - #| - job_queue_info - jobs_file_path = self.job_queue_dir + "/jobs.csv" - df = pd.read_csv(jobs_file_path) - - path_i = path_i[len(self.root_dir):] - full_path = self.root_dir_short + path_i - - # Looking for job path in jobs.csv file - index = df[df["job_path"] == full_path].index.tolist()[0] - - job_info = df.iloc[index].to_dict() - - return(job_info) - #__| - - #__| ********************************************************************** - - def __load_dataframe__(self): - """Attempt to load dataframe.""" - #| - __load_dataframe__ - if self.dataframe_dir is not None: - fle_name = self.dataframe_dir + "/job_dataframe.pickle" - else: - fle_name = self.root_dir + "/jobs_bin/job_dataframe.pickle" - - with open(fle_name, "rb") as fle: - if sys.version_info.major > 2: - df = pickle.load(fle, encoding="latin1") - # NOTE Added encoding="latin1" for p36 support (180415 - RF) - else: - df = pickle.load(fle) - - self.data_frame = df - #__| - - def __write_dataframe__(self): - """ - Write dataframe to file in root_dir/jobs_bin folder. - - Writes dataframe in csv and pickle format. CSV is easily human readable - """ - #| - __write_dataframe__ - df = self.data_frame - - # df.to_csv(self.root_dir + "/jobs_bin/job_dataframe.csv", index=False) - - df_pickle_fle = os.path.join( - self.root_dir, - self.working_dir, - "jobs_bin/job_dataframe.pickle", - ) - # df_pickle_fle = self.root_dir + "/jobs_bin/job_dataframe.pickle" - - with open(df_pickle_fle, "wb") as fle: - pickle.dump(df, fle) - #__| - - def add_all_columns_from_file(self): - """ - Add column to dataframe from files in data_columns folder. - - Files in data_columns folder must have the following format: - 3 columns, value | revision # | path - Columns are separated by the "|" character - File name must end with ".col" extension. - """ - #| - add_all_columns_from_file - # print("lksajkfls0sd7fsdfsd98") - # print(self.root_dir + "/jobs_bin/data_columns") - # print(self.working_dir) - - col_dir = os.path.join( - self.working_dir, - "jobs_bin/data_columns", - ) + "/*.col*" - # print(col_dir) - - dir_list = glob.glob(col_dir) - - col_data_file_list = [dir.split("/")[-1] for dir in dir_list] - - for col_file in col_data_file_list: - self.__add_data_column_from_file__(col_file) - #__| - - def __add_data_column_from_file__(self, - file_name, - ): - """Add data in "file_name" file to dataframe. - - Searches in jobs_bin/data_columns/ - Args: - file_name: - """ - #| - __add_data_column_from_file__ - - #| - Extracting Column Name From File Name - col_name = file_name.split(".")[0] - #__| - - #| - Reading Column Data File - NEW - # column_file = self.root_dir + "/jobs_bin/data_columns/" + file_name - column_file = os.path.join( - self.working_dir, - "jobs_bin/data_columns", - file_name, - ) - - with open(column_file, "r") as fle: - content = fle.readlines() - - content = [x.strip().split("|") for x in content] - - content_new = [] - for line in content: - line_new = {} - line_new["value"] = line[0].strip() - line_new["revision"] = line[1].strip() - line_new["path"] = line[2].strip() - - content_new.append(line_new) - #__| - - #| - Matching Dataframe with New Data Column - df = self.data_frame - - df["full_path"] = df["path"].astype(str) + "_" + \ - df["revision_number"].astype(str) - - column_data_list = [] - for i_ind, (index, row) in enumerate(df.iterrows()): - - row_has_entry = False - for entry in content_new: - - entry_fullpath = entry["path"] + "_" + entry["revision"] - if entry_fullpath == row["full_path"]: - column_data_list.append(entry["value"]) - row_has_entry = True - continue - - if not row_has_entry: - column_data_list.append(np.nan) - - df.drop("full_path", axis=1) - - df[col_name] = column_data_list - #__| - - #__| - - - - - - - - - # ███ ██ ███████ ██ ██ - # ████ ██ ██ ██ ██ - # ██ ██ ██ █████ ██ █ ██ - # ██ ██ ██ ██ ██ ███ ██ - # ██ ████ ███████ ███ ███ - - def add_data_column(self, - function, - column_name="new_column", - revision="auto", - allow_failure=True, - parallel_exec=False, - # allow_failure=False, - ): - """ - Add data column to data frame by iterating thourgh job folders. - - Args: - function: - Set of operations that will be applied to indiviudal job - folders. Must return a scalar quantity that will be added to - data frame. The function should know "what to do" given only a - path that correpsonds to a unique job folder (including revision). - - If the function returns a dict, then various columns will be - added with the column names corresponding to the key name. - - column_name: - Name of new data column - - revision: - The job revision from which data is scraped - "auto" | Selects most recent revision folder - "all" | Adds all revisions to data frame (NOT WORKING) - "previous | Second to last revision" - allow_failure: - If True, a failed method call will result in NaN - """ - #| - __add_data_coumn__ - startTime = datetime.now() - - print("Adding " + str(column_name)) - - def process_entry(entry): - """ - """ - #| - process_entry - path = entry.full_path - path = path + self.cluster.cluster.job_data_dir - - if allow_failure is True: - try: - out = function(path) - except: - out = np.nan - - else: - out = function(path) - - # new_data_col.append(out) - - return(out) - #__| - - if parallel_exec: - - #| - Parallized Execution ***************************************** - from joblib import Parallel, delayed - import multiprocessing - - num_cores = multiprocessing.cpu_count() - print("Number of cores:") - print(num_cores); print(" ") - # new_data_col = Parallel(n_jobs=num_cores)( - new_data_col = Parallel(n_jobs=int(num_cores / 2))( - delayed(process_entry)(i) for i in self.data_frame["Job"] - ) - #__| ************************************************************** - - else: - - #| - Serial Execution ********************************************* - new_data_col = [] - for entry in self.data_frame["Job"]: - out = process_entry(entry) - new_data_col.append(out) - #__| ************************************************************** - - - data_type_list = [type(x) for x in new_data_col] - dict_in_list = any(item == dict for item in data_type_list) - if dict_in_list: - new_col = [] - for x in new_data_col: - if pd.isnull(x) is True: - new_col.append({"NA": np.nan}) - else: - new_col.append(x) - - new_columns_df = pd.DataFrame(new_col) - - df1 = self.data_frame - df2 = new_columns_df - - out_df = pd.concat([df1, df2], axis=1) - self.data_frame = out_df - - else: - self.data_frame[column_name] = new_data_col - - print("Run time ", str(datetime.now() - startTime)) - print("__________________________________"); print("") - - #__| - - - - - # ███ ██ ███████ ██ ██ - # ████ ██ ██ ██ ██ - # ██ ██ ██ █████ ██ █ ██ - # ██ ██ ██ ██ ██ ███ ██ - # ██ ████ ███████ ███ ███ - - - - - - - - - - - - - def job_state_file(self, path_i="."): - """ - Return contents of '.QUEUESTATE' if present in the job directory. - - Args: - path: - """ - #| - job_state_file - file_path = path_i + "/.QUEUESTATE" - if os.path.isfile(file_path): - with open(file_path, "r") as fle: - job_state = fle.read().rstrip() - else: - job_state = None - - return(job_state) - #__| - - - #| - Data Frame Methods - - # COMBAK Move this to dataframe methods - def create_data_sets(self, data_frame, free_variable): - """ - Splinter data_frame into distinct data sets based on columns. - - Returns data sets from the data frame where the data is split by the - job variables. One variable is excluded from this grouping and is - treated as a "continous" variable to be plotted on the x-axis - - ex. Parameter sweep with varying k-points, pw-cutoff, and - lattice-constant. The lattice-constant is designated as the free - variable and so data sets are created for each combination of - k-points and pw-cutoff where each set contains the full range of - latt-const. - """ - #| - create_data_sets - # df = copy.deepcopy(self.data_frame) - df = data_frame - - var_lst = copy.deepcopy(self.tree_level_labels) - var_lst.remove(free_variable) - - df_unique_params = df[var_lst].drop_duplicates() - indices = df_unique_params.index.values - - data_lst = [] - for index in indices: - df_tmp = df_unique_params.ix[[index]] - - #| - Data Labels - data_label_full = "" - for column in df_tmp: - col_i = df_tmp[column] - - col_name = col_i.name - col_val = col_i.iloc[0] - - data_label_i = str(col_name) + ": " + str(col_val) - - data_label_full += data_label_i + " | " - - data_label_full = data_label_full[:-3] - #__| - - i1 = df.set_index(var_lst).index - i2 = df_tmp.set_index(var_lst).index - - df_i = df[i1.isin(i2)] - - data_lst.append({"label": data_label_full, "data": df_i}) - - return(data_lst) - #__| - - def filter_early_revisions(self, dataframe): - """Remove all entries (rows) which aren't the highest revision number. - - Args: - dataframe: - """ - #| - filter_early_revisions - max_rev = dataframe["revision_number"] == dataframe["max_revision"] - data_series_maxrev = dataframe[max_rev] - - return(data_series_maxrev) - #__| - - #__| - - #| - Query Job Status ***************************************************** - - #| - __old__ - def job_state(self, path_i): - """ - Return job state. - - Implentation is cluster dependent. - - Args: - path_i - """ - #| - job_state - job_state = self.cluster.cluster.job_state(path_i=path_i) - - return(job_state) - - #| - OLD - # if not os.path.isdir(path + "/simulation"): - # return("no_sim_folder") - # - # dir_cont = os.listdir(path + "/simulation") - # - # if "completed" in dir_cont: - # return("complete") - # elif "out" not in dir_cont and "err" not in dir_cont: - # return("running") - # else: - # return("error") - #__| - - #__| - - def job_state_2(self, path): - """ - Return job state. - - # COMBAK Deprecated ********************* - - Implentation is cluster dependent. - - Args: - path_i - """ - #| - job_state_2 - # - # #| - Formatting path Depending on Whether It is Full or Relative - # if self.root_dir in path: - # ind = path.find(self.root_dir_short) - # # path = path[ind:] - # full_path = path[ind:] - # else: - # full_path = self.root_dir_short + "/" + path - # #__| - # - # #| - Finding job in jobs.csv file - # jobs_file_path = self.job_queue_dir + "/jobs.csv" - # df = pd.read_csv(jobs_file_path) - # - # job_in_csv = True - # try: - # index = df[df["job_path"] == full_path].index.tolist()[0] - # except: - # job_in_csv = False - # #__| - # - # try: - # - # #| - Attempting to read job_id from file - # with open(path + "/job_id") as fle: - # job_id = fle.read().rstrip() - # #__| - # - # except: - # - # #| - Attempting to read job_id from jobs.csv by matching paths - # if job_in_csv: - # job_id = df.iloc[index]["job_id"] - # #__| - # - # job_queue_dict = AWS_Queues().job_info_batch(job_id) - # - # #| - Handling Case Where Job ID Is Not In Batch System - # if job_queue_dict == "job not in batch system": - # - # if job_in_csv: - # job_stat_from_file = df.iloc[index]["job_status"] - # job_queue_dict = {"job_status": job_stat_from_file} - # - # elif os.path.isfile( path + "/.STATUS"): - # with open(stat_file, "w+") as fle: - # job_status = fle.readline().rstrip() - # - # job_queue_dict = {"job_status": job_status} - # #__| - # - # job_status = job_queue_dict["job_status"] - # - # #| - Writing Job Status to File - # with open(path + "/.STATUS", "w+") as fle: - # fle.write(job_status + "\n") - # #__| - # - # #| - Writing Job Status to Master Jobs Queue File - # if job_in_csv: - # df.at[index, "job_status"] = job_status - # df.to_csv(jobs_file_path, index=False) - # #__| - # - # return(job_status) - #__| - - #__| - - def job_state_3(self, path_i): - """ - Return job state of job_i. - - Args: - path_i - """ - #| - job_state_3 - out_dict = { - "job_ready": self._job_ready(path_i), - "job_pending": self._job_pending(path_i), - "job_running": self._job_running(path_i), - "job_succeeded": self._job_succeeded(path_i), - "job_failed": self._job_failed(path_i), - "job_submitted": self._job_submitted(path_i), - } - - return(out_dict) - #__| - - #| - OLD Methods That Use job_i - - def job_ready(self, job_i, require_READY_tag=True): - """ - Return whether job_i is in READY state (Ready for submission). - - Args: - job_i: - require_READY_tag: - Require a ".READY" file start job - """ - #| - job_ready - path_i = self.var_lst_to_path( - job_i, - job_rev="Auto", - relative_path=False, - ) - - crit_0 = False - if os.path.isfile(path_i + "/.READY"): - crit_0 = True - elif require_READY_tag is False: - crit_0 = True - - crit_1 = False - if not os.path.isfile(path_i + "/.SUBMITTED"): - crit_1 = True - - #| - Having trouble with AWS .READY files not being copied over - # if self.cluster.cluster_sys == "aws": - # crit_ - # - #__| - - crit_list = [crit_0, crit_1] - - if all(crit is True for crit in crit_list): - return(True) - else: - return(False) - #__| - - def job_pending(self, job_i): - """ - Check whether job_i is in PENDING state. - - Args: - job_i: - """ - #| - job_pending - path_i = self.var_lst_to_path(job_i, - job_rev="Auto", - relative_path=False, - ) - - crit_0 = False - job_state = self.cluster.cluster.job_state(path_i=path_i) - if job_state == "PENDING": - crit_0 = True - - crit_1 = False - if self.job_state_file(path_i) == "PENDING": - crit_1 = True - - crit_list = [crit_0, crit_1] - - if all(crit is True for crit in crit_list): - return(True) - else: - return(False) - - - # df["full_path"] = root_dir_beg + "/" + df["root_dir"] + "/" + - # df["path"] + "_" + df["job_revision_number"].astype(str) - # - # index = df.index[df["full_path"] == path_i].tolist() - # df_i = df.iloc[index] - # max_rev = df_i["revision_number"].max() - # df_fin = df_i[df_i["revision_number"] == max_rev] - # assert len(df_fin) == 1 - # - # if df_fin["job_state_2"].iloc[0] == "RUNNABLE": - # return(True) - # else: - # return(False) - #__| - - def job_running(self, job_i): - """ - Check whether job_i is in RUNNING state. - - Args: - job_i: - """ - #| - job_running - path_i = self.var_lst_to_path(job_i, - job_rev="Auto", - relative_path=False, - ) - - crit_0 = True - if os.path.isfile(path_i + "/.READY"): - crit_0 = True - - crit_1 = False - if os.path.isfile(path_i + "/.SUBMITTED"): - crit_1 = True - - crit_2 = False - # if not os.path.isfile(path_i + "/.FINISHED"): - if not os.path.isfile(path_i + "/" + DFT_Jobs_Analysis.finished_fle): - crit_2 = True - - crit_3 = False - job_state = self.cluster.cluster.job_state(path_i=path_i) - if job_state == "RUNNING": - crit_3 = True - - crit_list = [crit_0, crit_1, crit_2, crit_3] - - if all(crit is True for crit in crit_list): - return(True) - else: - return(False) - #__| - - def job_succeeded(self, job_i): - """ - Check whether job_i is in SUCCEEDED state. - - Args: - job_i: - """ - #| - job_succeeded - path_i = self.var_lst_to_path(job_i, - job_rev="Auto", - relative_path=False, - ) - - crit_0 = True - if os.path.isfile(path_i + "/.READY"): - crit_0 = True - - crit_1 = False - if os.path.isfile(path_i + "/.SUBMITTED"): - crit_1 = True - - # Checking for '.FINSISHED' file OR checking batch queue - - crit_2_1 = False - fle_name = path_i + "/" + DFT_Jobs_Analysis.finished_fle - if os.path.isfile(fle_name): - with open(fle_name, "r") as fle: - lines = [line.strip() for line in fle.readlines()] - if "job_completed" in lines: - crit_2_1 = True - - #| - DELETE THIS - # TEMP COMBAK FIXME Delete this after migration to new FINISHED file - # format is done!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - fle_name = path_i + "/" + DFT_Jobs_Analysis.finished_fle - if os.path.isfile(fle_name): - crit_2_1 = True - #__| - - - crit_2_2 = False - job_state = self.cluster.cluster.job_state(path_i=path_i) - if job_state == "SUCCEEDED": - crit_2_2 = True - - if crit_2_2 or crit_2_1: - crit_2 = True - else: - crit_2 = False - - crit_list = [crit_0, crit_1, crit_2] - if all(crit is True for crit in crit_list): - return(True) - else: - return(False) - #__| - - def job_failed(self, job_i): - """ - Check whether job_i is in failed state. - - Args: - job_i: - """ - #| - job_failed - path_i = self.var_lst_to_path(job_i, - job_rev="Auto", - relative_path=False, - ) - - crit_0 = False - job_state = self.cluster.job_state(path_i=path_i) - if job_state == "FAILED": - crit_0 = True - - crit_1 = False - if os.path.isfile(path_i + "/.SUBMITTED"): - crit_1 = True - - crit_2 = False - # if not os.path.isfile(path_i + "/.FINISHED"): - if not os.path.isfile(path_i + "/." + DFT_Jobs_Analysis.finished_fle): - crit_2 = True - - #| - Parsing Error File for "Error" (Sherlock only for now) - if self.cluster.cluster_sys == "sherlock": - error = self.parse_job_error_file(path_i) - if error: - crit_0 = True - #__| - - crit_list = [crit_0, crit_1, crit_2] - - if all(crit is True for crit in crit_list): - return(True) - else: - return(False) - #__| - - def job_submitted(self, path_i): - """ - Check whether job is submitted. - - Args: - path_i - """ - #| - job_submitted - try: - if os.path.isfile(path_i + "/.SUBMITTED"): - return(True) - else: - return(False) - except: - return(False) - #__| - - #__| - - #| - NEW Methods That Use path_i Instead of job_i (Create col in df!!) - def _job_ready(self, path_i, require_READY_tag=True): - """ - Return whether job_i is in READY state. - - Args: - job_i: - require_READY_tag: - Require a ".READY" file start job - """ - #| - job_ready - # path_i = self.var_lst_to_path(job_i, - # ob_rev="Auto", - # relative_path=False, - # ) - - crit_0 = False - if os.path.isfile(path_i + "/.READY"): - crit_0 = True - elif require_READY_tag is False: - crit_0 = True - - crit_1 = False - if not os.path.isfile(path_i + "/.SUBMITTED"): - crit_1 = True - - #| - Having trouble with AWS .READY files not being copied over - # if self.cluster.cluster_sys == "aws": - # crit_ - #__| - - crit_list = [crit_0, crit_1] - - if all(crit is True for crit in crit_list): - return(True) - else: - return(False) - #__| - - def _job_pending(self, path_i): - """ - Return whether job_i is in PENDING state. - - Args: - path_i: - """ - #| - job_pending - # path_i = self.var_lst_to_path(job_i, job_rev="Auto", - # relative_path=False) - - crit_0 = False - job_state = self.cluster.cluster.job_state(path_i=path_i) - - - # print("**************************************************") - # print("self.cluster.cluster.job_state") - # print(job_state) - # print("**************************************************") - - if job_state == "PENDING": - crit_0 = True - - - crit_1 = False - if self.job_state_file(path_i) == "PENDING": - crit_1 = True - - crit_list = [crit_0, crit_1] - - if all(crit is True for crit in crit_list): - return(True) - else: - return(False) - #__| - - def _job_running(self, path_i): - """ - Return whether job_i is in RUNNING state. - - Args: - path_i: - """ - #| - job_running - crit_0 = True - if os.path.isfile(path_i + "/.READY"): - crit_0 = True - - crit_1 = False - if os.path.isfile(path_i + "/.SUBMITTED"): - crit_1 = True - - crit_2 = False - if not os.path.isfile(path_i + "/.FINISHED"): - crit_2 = True - - crit_3 = False - job_state = self.cluster.cluster.job_state(path_i=path_i) - if job_state == "RUNNING": - crit_3 = True - - crit_list = [crit_0, crit_1, crit_2, crit_3] - - if all(crit is True for crit in crit_list): - return(True) - else: - return(False) - #__| - - def _job_succeeded(self, path_i): - """ - Return whether job_i is in SUCCEEDED state. - - Args: - path_i: - """ - #| - job_succeeded - crit_0 = True - if os.path.isfile(path_i + "/.READY"): - crit_0 = True - - crit_1 = False - if os.path.isfile(path_i + "/.SUBMITTED"): - crit_1 = True - - # Checking for '.FINSISHED' file OR checking batch queue - - crit_2_1 = False - if os.path.isfile(path_i + "/.FINISHED"): - crit_2_1 = True - - crit_2_2 = False - job_state = self.cluster.cluster.job_state(path_i=path_i) - if job_state == "SUCCEEDED": - crit_2_2 = True - - if crit_2_2 or crit_2_1: - crit_2 = True - else: - crit_2 = False - - crit_list = [crit_0, crit_1, crit_2] - if all(crit is True for crit in crit_list): - return(True) - else: - return(False) - #__| - - def _job_failed(self, path_i): - """ - Return whether job_i is in FAILED state. - - Args: - path_i: - """ - #| - job_failed - crit_0 = False - job_state = self.cluster.job_state(path_i=path_i) - if job_state == "FAILED": - crit_0 = True - - crit_1 = False - if os.path.isfile(path_i + "/.SUBMITTED"): - crit_1 = True - - crit_2 = False - if not os.path.isfile(path_i + "/.FINISHED"): - crit_2 = True - - - #| - Parsing Error File for "Error" (Sherlock only for now) - - if self.cluster.cluster_sys == "sherlock": - error = self.parse_job_error_file(path_i) - if error: - crit_0 = True - - # if error and self.cluster.cluster_sys == "sherlock": - # # print(error) - # crit_0 = True - #__| - - crit_list = [crit_0, crit_1, crit_2] - - if all(crit is True for crit in crit_list): - return(True) - else: - return(False) - #__| - - def _job_submitted(self, path_i): - """ - Return whether job_i is in SUBMITTED state. - - Args: - path_i: - """ - #| - job_submitted - try: - if os.path.isfile(path_i + "/.SUBMITTED"): - return(True) - else: - return(False) - except: - return(False) - #__| - - #__| - - def parse_job_error_file(self, path_i): - """ - Read error file and searches for "Error" in last line. - - TODO This is very specific to QE jobs so should be moved. - - Args: - path_i - """ - #| - parse_job_error_file - err_file = self.cluster.cluster.error_file - err_file = os.path.join(path_i, err_file) - - error = False - if os.path.isfile(err_file): - with open(err_file) as fle: - lines = [line.strip() for line in fle] - - lines = lines[-4:] - - for line in lines: - - if "KohnShamConvergenceError" in line: - print("KohnShamConvergenceError Occured!! - RF") - error = True - break - elif "DUE TO TIME LIMIT" in line: - print("Job Reached Time Limit!! - RF") - error = True - break - elif "RuntimeError: SCF Calculation failed": - print("RuntimeError: SCF Calculation failed - RF") - error = True - break - else: - error = False - pass - - else: - error = False - - return(error) - #__| - - #__| ********************************************************************** - -#__| ************************************************************************** - - -def parse_job_dirs(dirs_to_parse): - """Parse directory structure for jobs. - - Args: - dirs_to_parse - """ - #| - parse_job_dirs - - #| - Import Modules - # import os - # import sys - # - # import pickle as pickle - #__| - - #| - Script Input - # dirs_to_parse = [ - # "01_surface_calcs", - # "02_surface_coverage", - # "03_OER_Calc", - # "07_diff_coverages_term", - # ] - #__| - - #| - MASTER Loop - master_path_list = [] - for dir_j in dirs_to_parse: - # path_j = os.path.join(os.getcwd(), dir_j) - path_j = dir_j - for root, dirs, files in os.walk(path_j, topdown=True): - for name in dirs: - name_i = os.path.join(root, name) - - dir_root = os.path.join(*name_i.split("/")[0:-1]) - dir_leaf = name_i.split("/")[-1] - - #| - Test that terminal dir name has _1 format - condition_0 = False - if dir_leaf[0] == "_": - condition_0 = True - - condition_1 = False - if len(dir_leaf.split("_")) == 2: - condition_1 = True - - numeric_part = dir_leaf.split("_")[-1] - condition_2 = False - if numeric_part.isdigit(): - condition_2 = True - #__| - - condition_3 = False - if "__old__" not in name_i: - condition_3 = True - - condition_4 = False - if "__temp__" not in name_i: - condition_4 = True - - if all([ - condition_0, - condition_1, - condition_2, - condition_3, - condition_4, - ]): - master_path_list.append("/" + dir_root) - - #__| - - master_path_list_unique = list(set(master_path_list)) - - # for i in master_path_list_unique: print(i) - - #| - NEW | Check that paths contain job_params.json file - for path_i in master_path_list_unique: - if "job_params.json" not in os.listdir(path_i): - print("job_params not in: ", path_i) - - for path_i in master_path_list_unique: - - files_i = os.listdir(path_i) - for file_j in files_i: - - #| - TEMP - condition_list = [] - - # Make sure that 'run' is in the dir name (ex. 3-run) - if "run" in file_j: - condition_list.append(True) - # print("run file here") - else: - condition_list.append(False) - - # Make sure there is a '-' character - if "-" in file_j: - condition_list.append(True) - - # Make sure the first set of characters are numeric - if file_j.split("-")[0].isdigit(): - condition_list.append(True) - else: - condition_list.append(False) - - else: - condition_list.append(False) - - #__| - - if all(condition_list): - print("Found a #-run folder: ", path_i) - - #__| - - return(master_path_list_unique) - - #| - Saving List to Pickle - # with open("181016_jobs_dir_list.pickle", "w") as fle: - # pickle.dump(master_path_list_unique ,fle) - #__| - - #__| - -def compare_parsed_and_user_job_dirs(parsed_dirs, user_dirs): - """ - """ - #| - compare_parsed_and_user_job_dirs - - print(" ") - print(" ") - print("User inputed dir_list len: ", str(len(user_dirs))) - print("Parsed dir_list len: ", str(len(parsed_dirs))) - - print(20 * "_"); print("") - - print("Dirs that were parsed but are not in the user specified list") - print(set(parsed_dirs).difference(set(user_dirs))) - print(20 * "*") - print("Dirs that are in the user list but not in the parsed list") - print(set(user_dirs).difference(set(parsed_dirs))) - - #__| - - - -#| - __old__ - - - - #| - __old__ - - #| - Picking Revision Number(s) To Query - # largest_rev = self.job_revision_number(entry) - # - # if revision == "auto": - # rev = [largest_rev] - # elif revision == "previous": - # if largest_rev == 1: - # rev = [1] - # else: - # rev = [largest_rev - 1] - # elif revision == "all": - # rev = range(self.job_revision_number(entry) + 1) - # else: - # rev = [revision] - #__| - - # def add_data_column(self, - # function, - # column_name="new_column", - # revision="auto", - # allow_failure=True, - # # allow_failure=False, - # ): - # """ - # Add data column to data frame by iterating thourgh job folders. - # - # Args: - # function: - # Set of operations that will be applied to indiviudal job - # folders. Must return a scalar quantity that will be added to - # data frame. The function should know "what to do" given only a - # path that correpsonds to a unique job folder (including revision). - # - # If the function returns a dict, then various columns will be - # added with the column names corresponding to the key name. - # - # column_name: - # Name of new data column - # - # revision: - # The job revision from which data is scraped - # "auto" | Selects most recent revision folder - # "all" | Adds all revisions to data frame (NOT WORKING) - # "previous | Second to last revision" - # allow_failure: - # If True, a failed method call will result in NaN - # """ - # #| - __add_data_coumn__ - # new_data_col = [] - # job_rev_lst = [] - # - # print("Adding " + str(column_name)) - # - # for entry in self.data_frame["variable_list"]: - # - # path = self.var_lst_to_path( - # entry, - # relative_path=False, - # job_rev="False", - # ) - # - # #| - Picking Revision Number(s) To Query - # largest_rev = self.job_revision_number(entry) - # - # if revision == "auto": - # rev = [largest_rev] - # elif revision == "previous": - # if largest_rev == 1: - # rev = [1] - # else: - # rev = [largest_rev - 1] - # elif revision == "all": - # rev = range(self.job_revision_number(entry) + 1) - # else: - # rev = [revision] - # #__| - # - # for rev_num in rev: - # - # #| - Run Function - # path += "_" + str(rev_num) - # - # path = path + self.cluster.cluster.job_data_dir - # - # if allow_failure is True: - # try: - # out = function(path) - # except: - # out = np.nan - # else: - # out = function(path) - # - # new_data_col.append(out) - # job_rev_lst.append(rev_num) - # #__| - # - # data_type_list = [type(x) for x in new_data_col] - # dict_in_list = any(item == dict for item in data_type_list) - # - # if dict_in_list: - # new_col = [] - # for x in new_data_col: - # if pd.isnull(x) is True: - # new_col.append({"NA": np.nan}) - # else: - # new_col.append(x) - # - # new_columns_df = pd.DataFrame(new_col) - # - # df1 = self.data_frame - # df2 = new_columns_df - # - # out_df = pd.concat([df1, df2], axis=1) - # self.data_frame = out_df - # - # else: - # self.data_frame[column_name] = new_data_col - # #__| - # - - #__| - - - - # DEPR - def view_atoms(self, ind): - """ - View last image in atoms object in GUI. - - Args: - ind: - Index of dataframe corresponding to entry of interest. - """ - #| - view_atoms - df = self.data_frame - - path_i = df.iloc[ind]["path"] - rev_num = df.iloc[ind]["revision_number"].astype(str) - full_path = path_i + "_" + rev_num - - print(full_path) - - try: - atoms = df.iloc[ind]["atoms_object"][-1] - view(atoms) - except: - print("Couldn't read atoms object") - #__| - - - # DEPR - # Already implemented in job_setup - def job_revisions(self, path): - """Return number of revision folders for a given job. - - Args: - path: - """ - #| - job_revisions - path = "/".join(path.split("/")[0:-1]) + "/" - - # Attempting to remove duplicate job folders (usually have spaces) - dir_list = [x for x in os.walk(path).next()[1] if " " not in x] - - return(len(dir_list)) - #__| - -#__| +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Class to analyse data using the DFT_Jobs_Setup class. + + +Development Notes: + TODO Automaticall read README files contained within job folders + TODO Delete the duplicate methods for job_status +""" + +#| - Import Modules +import os +import sys + +import pickle +import copy +import glob + +from datetime import datetime + + + +import pandas as pd +import numpy as np + +from ase.visualize import view + +# My Modules +from dft_job_automat.job_setup import DFT_Jobs_Setup +#__| + +class DFT_Jobs_Analysis(DFT_Jobs_Setup): + """Analysis methods for jobs in tree structure. + + # TODO path --> path_i + # TODO Modify .FINISHED implementation + + Parent class to DFT_Jobs_Setup + """ + + #| - DFT_Jobs_Analysis **************************************************** + + #| - Class Variables + finished_fle = ".FINISHED.new" + #__| + + def __init__(self, + tree_level=None, + level_entries=None, + skip_dirs_lst=None, + indiv_dir_lst=None, # <----------------------------------------------- + indiv_job_lst=None, + indiv_job_dict_lst=None, + root_dir=".", + working_dir=".", + update_job_state=False, + load_dataframe=True, + dataframe_dir=None, + job_type_class=None, + methods_to_run=None, + folders_exist=None, + parse_all_revisions=True, + parallel_exec=False, + ): + """Initialize DFT_Jobs_Analysis Instance. + + Args: + system: + tree_level: + level_entries: + skip_dirs_lst: + working_dir: + update_job_state: + Updates job status for all jobs in ensemble. + load_dataframe: + dataframe_dir: + Specify location of dataframe if not in working_dir. + job_type_class: + Job type specific class instance which constains methods + specific to the jobs being run that parse job folders. + methods_to_run : + Additional methods to run on each job dir and return value to + populate data column with. + """ + #| - __init__ + + #| - Instantiate DFT_Jobs_Setup + DFT_Jobs_Setup.__init__(self, + tree_level=tree_level, + level_entries=level_entries, + indiv_dir_lst=indiv_dir_lst, + indiv_job_lst=indiv_job_lst, + indiv_job_dict_lst=indiv_job_dict_lst, + + skip_dirs_lst=skip_dirs_lst, + root_dir=root_dir, + working_dir=working_dir, + folders_exist=folders_exist, + parse_all_revisions=parse_all_revisions, + ) + + #__| + + #| - Class Attributes + self.dataframe_dir = dataframe_dir + self.parallel_exec = parallel_exec + #__| + + #| - General Methods + if update_job_state is True: + print("update_job_state == True") + self.add_data_column( + self.job_state, + column_name="job_state", + parallel_exec=self.parallel_exec, + ) + self.add_data_column( + self.job_state_3, + column_name="N/A", + parallel_exec=self.parallel_exec, + ) + #__| + + #| - Job Type Specific Methods + # method = DFT_Methods().atom_type_num_dict + # self.add_data_column(method, column_name="TEMP", allow_failure=False) + + # TODO | Why is this only write the data frame if the there are job + # methods to run + write_data_frame = False + if load_dataframe is True: + self.__load_dataframe__() + + else: + + #| - job_type_class instance attached methods + if job_type_class is not None: + job_type_inst = job_type_class + + for method in job_type_inst.methods_to_run: + method_ref = getattr(job_type_inst, method) + + self.method = method_ref # COMBAK Is this necessary?? + + self.add_data_column( + method_ref, + column_name=method, + allow_failure=True, + # allow_failure=False, + parallel_exec=self.parallel_exec, + ) + + write_data_frame = True + #__| + + #| - methods_to_run + if methods_to_run is not None: + for method in methods_to_run: + + self.add_data_column( + method, + + # Not sure where this func_name attr. came from + # column_name=method.func_name, + column_name=method.__name__, + + allow_failure=True, + # allow_failure=False, + parallel_exec=self.parallel_exec, + ) + + write_data_frame = True + #__| + + if write_data_frame: + self.__write_dataframe__() + + self.add_all_columns_from_file() + #__| + + #__| + + #| - Job Log ************************************************************** + + def add_jobs_queue_data(self): + """Add jobs queue data to jobs.csv file.""" + #| - add_jobs_queue_data + # COMBAK Not finished + #__| + + def job_queue_info(self, path_i): + """ + Return row corresponding to job in path_i from the job queue dir. + + # FIXME Set up the jobs.csv system to work + + Args: + path_i: + """ + #| - job_queue_info + jobs_file_path = self.job_queue_dir + "/jobs.csv" + df = pd.read_csv(jobs_file_path) + + path_i = path_i[len(self.root_dir):] + full_path = self.root_dir_short + path_i + + # Looking for job path in jobs.csv file + index = df[df["job_path"] == full_path].index.tolist()[0] + + job_info = df.iloc[index].to_dict() + + return(job_info) + #__| + + #__| ********************************************************************** + + def __load_dataframe__(self): + """Attempt to load dataframe.""" + #| - __load_dataframe__ + if self.dataframe_dir is not None: + fle_name = self.dataframe_dir + "/job_dataframe.pickle" + else: + fle_name = self.root_dir + "/jobs_bin/job_dataframe.pickle" + + with open(fle_name, "rb") as fle: + if sys.version_info.major > 2: + df = pickle.load(fle, encoding="latin1") + # NOTE Added encoding="latin1" for p36 support (180415 - RF) + else: + df = pickle.load(fle) + + self.data_frame = df + #__| + + def __write_dataframe__(self): + """ + Write dataframe to file in root_dir/jobs_bin folder. + + Writes dataframe in csv and pickle format. CSV is easily human readable + """ + #| - __write_dataframe__ + df = self.data_frame + + # df.to_csv(self.root_dir + "/jobs_bin/job_dataframe.csv", index=False) + + df_pickle_fle = os.path.join( + self.root_dir, + self.working_dir, + "jobs_bin/job_dataframe.pickle", + ) + # df_pickle_fle = self.root_dir + "/jobs_bin/job_dataframe.pickle" + + with open(df_pickle_fle, "wb") as fle: + pickle.dump(df, fle) + #__| + + def add_all_columns_from_file(self): + """ + Add column to dataframe from files in data_columns folder. + + Files in data_columns folder must have the following format: + 3 columns, value | revision # | path + Columns are separated by the "|" character + File name must end with ".col" extension. + """ + #| - add_all_columns_from_file + # print("lksajkfls0sd7fsdfsd98") + # print(self.root_dir + "/jobs_bin/data_columns") + # print(self.working_dir) + + col_dir = os.path.join( + self.working_dir, + "jobs_bin/data_columns", + ) + "/*.col*" + # print(col_dir) + + dir_list = glob.glob(col_dir) + + col_data_file_list = [dir.split("/")[-1] for dir in dir_list] + + for col_file in col_data_file_list: + self.__add_data_column_from_file__(col_file) + #__| + + def __add_data_column_from_file__(self, + file_name, + ): + """Add data in "file_name" file to dataframe. + + Searches in jobs_bin/data_columns/ + Args: + file_name: + """ + #| - __add_data_column_from_file__ + + #| - Extracting Column Name From File Name + col_name = file_name.split(".")[0] + #__| + + #| - Reading Column Data File - NEW + # column_file = self.root_dir + "/jobs_bin/data_columns/" + file_name + column_file = os.path.join( + self.working_dir, + "jobs_bin/data_columns", + file_name, + ) + + with open(column_file, "r") as fle: + content = fle.readlines() + + content = [x.strip().split("|") for x in content] + + content_new = [] + for line in content: + line_new = {} + line_new["value"] = line[0].strip() + line_new["revision"] = line[1].strip() + line_new["path"] = line[2].strip() + + content_new.append(line_new) + #__| + + #| - Matching Dataframe with New Data Column + df = self.data_frame + + df["full_path"] = df["path"].astype(str) + "_" + \ + df["revision_number"].astype(str) + + column_data_list = [] + for i_ind, (index, row) in enumerate(df.iterrows()): + + row_has_entry = False + for entry in content_new: + + entry_fullpath = entry["path"] + "_" + entry["revision"] + if entry_fullpath == row["full_path"]: + column_data_list.append(entry["value"]) + row_has_entry = True + continue + + if not row_has_entry: + column_data_list.append(np.nan) + + df.drop("full_path", axis=1) + + df[col_name] = column_data_list + #__| + + #__| + + + + + + + + + # ███ ██ ███████ ██ ██ + # ████ ██ ██ ██ ██ + # ██ ██ ██ █████ ██ █ ██ + # ██ ██ ██ ██ ██ ███ ██ + # ██ ████ ███████ ███ ███ + + def add_data_column(self, + function, + column_name="new_column", + revision="auto", + allow_failure=True, + parallel_exec=False, + # allow_failure=False, + ): + """ + Add data column to data frame by iterating thourgh job folders. + + Args: + function: + Set of operations that will be applied to indiviudal job + folders. Must return a scalar quantity that will be added to + data frame. The function should know "what to do" given only a + path that correpsonds to a unique job folder (including revision). + + If the function returns a dict, then various columns will be + added with the column names corresponding to the key name. + + column_name: + Name of new data column + + revision: + The job revision from which data is scraped + "auto" | Selects most recent revision folder + "all" | Adds all revisions to data frame (NOT WORKING) + "previous | Second to last revision" + allow_failure: + If True, a failed method call will result in NaN + """ + #| - __add_data_coumn__ + startTime = datetime.now() + + print("Adding " + str(column_name)) + + def process_entry(entry): + """ + """ + #| - process_entry + path = entry.full_path + path = path + self.cluster.cluster.job_data_dir + + if allow_failure is True: + try: + out = function(path) + except: + out = np.nan + + else: + out = function(path) + + # new_data_col.append(out) + + return(out) + #__| + + if parallel_exec: + + #| - Parallized Execution ***************************************** + from joblib import Parallel, delayed + import multiprocessing + + num_cores = multiprocessing.cpu_count() + print("Number of cores:") + print(num_cores); print(" ") + # new_data_col = Parallel(n_jobs=num_cores)( + new_data_col = Parallel(n_jobs=int(num_cores / 2))( + delayed(process_entry)(i) for i in self.data_frame["Job"] + ) + #__| ************************************************************** + + else: + + #| - Serial Execution ********************************************* + new_data_col = [] + for entry in self.data_frame["Job"]: + out = process_entry(entry) + new_data_col.append(out) + #__| ************************************************************** + + + data_type_list = [type(x) for x in new_data_col] + dict_in_list = any(item == dict for item in data_type_list) + if dict_in_list: + new_col = [] + for x in new_data_col: + if pd.isnull(x) is True: + new_col.append({"NA": np.nan}) + else: + new_col.append(x) + + new_columns_df = pd.DataFrame(new_col) + + df1 = self.data_frame + df2 = new_columns_df + + out_df = pd.concat([df1, df2], axis=1) + self.data_frame = out_df + + else: + self.data_frame[column_name] = new_data_col + + print("Run time ", str(datetime.now() - startTime)) + print("__________________________________"); print("") + + #__| + + + + + # ███ ██ ███████ ██ ██ + # ████ ██ ██ ██ ██ + # ██ ██ ██ █████ ██ █ ██ + # ██ ██ ██ ██ ██ ███ ██ + # ██ ████ ███████ ███ ███ + + + + + + + + + + + + + def job_state_file(self, path_i="."): + """ + Return contents of '.QUEUESTATE' if present in the job directory. + + Args: + path: + """ + #| - job_state_file + file_path = path_i + "/.QUEUESTATE" + if os.path.isfile(file_path): + with open(file_path, "r") as fle: + job_state = fle.read().rstrip() + else: + job_state = None + + return(job_state) + #__| + + + #| - Data Frame Methods + + # COMBAK Move this to dataframe methods + def create_data_sets(self, data_frame, free_variable): + """ + Splinter data_frame into distinct data sets based on columns. + + Returns data sets from the data frame where the data is split by the + job variables. One variable is excluded from this grouping and is + treated as a "continous" variable to be plotted on the x-axis + + ex. Parameter sweep with varying k-points, pw-cutoff, and + lattice-constant. The lattice-constant is designated as the free + variable and so data sets are created for each combination of + k-points and pw-cutoff where each set contains the full range of + latt-const. + """ + #| - create_data_sets + # df = copy.deepcopy(self.data_frame) + df = data_frame + + var_lst = copy.deepcopy(self.tree_level_labels) + var_lst.remove(free_variable) + + df_unique_params = df[var_lst].drop_duplicates() + indices = df_unique_params.index.values + + data_lst = [] + for index in indices: + df_tmp = df_unique_params.ix[[index]] + + #| - Data Labels + data_label_full = "" + for column in df_tmp: + col_i = df_tmp[column] + + col_name = col_i.name + col_val = col_i.iloc[0] + + data_label_i = str(col_name) + ": " + str(col_val) + + data_label_full += data_label_i + " | " + + data_label_full = data_label_full[:-3] + #__| + + i1 = df.set_index(var_lst).index + i2 = df_tmp.set_index(var_lst).index + + df_i = df[i1.isin(i2)] + + data_lst.append({"label": data_label_full, "data": df_i}) + + return(data_lst) + #__| + + def filter_early_revisions(self, dataframe): + """Remove all entries (rows) which aren't the highest revision number. + + Args: + dataframe: + """ + #| - filter_early_revisions + max_rev = dataframe["revision_number"] == dataframe["max_revision"] + data_series_maxrev = dataframe[max_rev] + + return(data_series_maxrev) + #__| + + #__| + + #| - Query Job Status ***************************************************** + + #| - __old__ + def job_state(self, path_i): + """ + Return job state. + + Implentation is cluster dependent. + + Args: + path_i + """ + #| - job_state + job_state = self.cluster.cluster.job_state(path_i=path_i) + + return(job_state) + + #| - OLD + # if not os.path.isdir(path + "/simulation"): + # return("no_sim_folder") + # + # dir_cont = os.listdir(path + "/simulation") + # + # if "completed" in dir_cont: + # return("complete") + # elif "out" not in dir_cont and "err" not in dir_cont: + # return("running") + # else: + # return("error") + #__| + + #__| + + def job_state_2(self, path): + """ + Return job state. + + # COMBAK Deprecated ********************* + + Implentation is cluster dependent. + + Args: + path_i + """ + #| - job_state_2 + # + # #| - Formatting path Depending on Whether It is Full or Relative + # if self.root_dir in path: + # ind = path.find(self.root_dir_short) + # # path = path[ind:] + # full_path = path[ind:] + # else: + # full_path = self.root_dir_short + "/" + path + # #__| + # + # #| - Finding job in jobs.csv file + # jobs_file_path = self.job_queue_dir + "/jobs.csv" + # df = pd.read_csv(jobs_file_path) + # + # job_in_csv = True + # try: + # index = df[df["job_path"] == full_path].index.tolist()[0] + # except: + # job_in_csv = False + # #__| + # + # try: + # + # #| - Attempting to read job_id from file + # with open(path + "/job_id") as fle: + # job_id = fle.read().rstrip() + # #__| + # + # except: + # + # #| - Attempting to read job_id from jobs.csv by matching paths + # if job_in_csv: + # job_id = df.iloc[index]["job_id"] + # #__| + # + # job_queue_dict = AWS_Queues().job_info_batch(job_id) + # + # #| - Handling Case Where Job ID Is Not In Batch System + # if job_queue_dict == "job not in batch system": + # + # if job_in_csv: + # job_stat_from_file = df.iloc[index]["job_status"] + # job_queue_dict = {"job_status": job_stat_from_file} + # + # elif os.path.isfile( path + "/.STATUS"): + # with open(stat_file, "w+") as fle: + # job_status = fle.readline().rstrip() + # + # job_queue_dict = {"job_status": job_status} + # #__| + # + # job_status = job_queue_dict["job_status"] + # + # #| - Writing Job Status to File + # with open(path + "/.STATUS", "w+") as fle: + # fle.write(job_status + "\n") + # #__| + # + # #| - Writing Job Status to Master Jobs Queue File + # if job_in_csv: + # df.at[index, "job_status"] = job_status + # df.to_csv(jobs_file_path, index=False) + # #__| + # + # return(job_status) + #__| + + #__| + + def job_state_3(self, path_i): + """ + Return job state of job_i. + + Args: + path_i + """ + #| - job_state_3 + out_dict = { + "job_ready": self._job_ready(path_i), + "job_pending": self._job_pending(path_i), + "job_running": self._job_running(path_i), + "job_succeeded": self._job_succeeded(path_i), + "job_failed": self._job_failed(path_i), + "job_submitted": self._job_submitted(path_i), + } + + return(out_dict) + #__| + + #| - OLD Methods That Use job_i + + def job_ready(self, job_i, require_READY_tag=True): + """ + Return whether job_i is in READY state (Ready for submission). + + Args: + job_i: + require_READY_tag: + Require a ".READY" file start job + """ + #| - job_ready + path_i = self.var_lst_to_path( + job_i, + job_rev="Auto", + relative_path=False, + ) + + crit_0 = False + if os.path.isfile(path_i + "/.READY"): + crit_0 = True + elif require_READY_tag is False: + crit_0 = True + + crit_1 = False + if not os.path.isfile(path_i + "/.SUBMITTED"): + crit_1 = True + + #| - Having trouble with AWS .READY files not being copied over + # if self.cluster.cluster_sys == "aws": + # crit_ + # + #__| + + crit_list = [crit_0, crit_1] + + if all(crit is True for crit in crit_list): + return(True) + else: + return(False) + #__| + + def job_pending(self, job_i): + """ + Check whether job_i is in PENDING state. + + Args: + job_i: + """ + #| - job_pending + path_i = self.var_lst_to_path(job_i, + job_rev="Auto", + relative_path=False, + ) + + crit_0 = False + job_state = self.cluster.cluster.job_state(path_i=path_i) + if job_state == "PENDING": + crit_0 = True + + crit_1 = False + if self.job_state_file(path_i) == "PENDING": + crit_1 = True + + crit_list = [crit_0, crit_1] + + if all(crit is True for crit in crit_list): + return(True) + else: + return(False) + + + # df["full_path"] = root_dir_beg + "/" + df["root_dir"] + "/" + + # df["path"] + "_" + df["job_revision_number"].astype(str) + # + # index = df.index[df["full_path"] == path_i].tolist() + # df_i = df.iloc[index] + # max_rev = df_i["revision_number"].max() + # df_fin = df_i[df_i["revision_number"] == max_rev] + # assert len(df_fin) == 1 + # + # if df_fin["job_state_2"].iloc[0] == "RUNNABLE": + # return(True) + # else: + # return(False) + #__| + + def job_running(self, job_i): + """ + Check whether job_i is in RUNNING state. + + Args: + job_i: + """ + #| - job_running + path_i = self.var_lst_to_path(job_i, + job_rev="Auto", + relative_path=False, + ) + + crit_0 = True + if os.path.isfile(path_i + "/.READY"): + crit_0 = True + + crit_1 = False + if os.path.isfile(path_i + "/.SUBMITTED"): + crit_1 = True + + crit_2 = False + # if not os.path.isfile(path_i + "/.FINISHED"): + if not os.path.isfile(path_i + "/" + DFT_Jobs_Analysis.finished_fle): + crit_2 = True + + crit_3 = False + job_state = self.cluster.cluster.job_state(path_i=path_i) + if job_state == "RUNNING": + crit_3 = True + + crit_list = [crit_0, crit_1, crit_2, crit_3] + + if all(crit is True for crit in crit_list): + return(True) + else: + return(False) + #__| + + def job_succeeded(self, job_i): + """ + Check whether job_i is in SUCCEEDED state. + + Args: + job_i: + """ + #| - job_succeeded + path_i = self.var_lst_to_path(job_i, + job_rev="Auto", + relative_path=False, + ) + + crit_0 = True + if os.path.isfile(path_i + "/.READY"): + crit_0 = True + + crit_1 = False + if os.path.isfile(path_i + "/.SUBMITTED"): + crit_1 = True + + # Checking for '.FINSISHED' file OR checking batch queue + + crit_2_1 = False + fle_name = path_i + "/" + DFT_Jobs_Analysis.finished_fle + if os.path.isfile(fle_name): + with open(fle_name, "r") as fle: + lines = [line.strip() for line in fle.readlines()] + if "job_completed" in lines: + crit_2_1 = True + + #| - DELETE THIS + # TEMP COMBAK FIXME Delete this after migration to new FINISHED file + # format is done!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + fle_name = path_i + "/" + DFT_Jobs_Analysis.finished_fle + if os.path.isfile(fle_name): + crit_2_1 = True + #__| + + + crit_2_2 = False + job_state = self.cluster.cluster.job_state(path_i=path_i) + if job_state == "SUCCEEDED": + crit_2_2 = True + + if crit_2_2 or crit_2_1: + crit_2 = True + else: + crit_2 = False + + crit_list = [crit_0, crit_1, crit_2] + if all(crit is True for crit in crit_list): + return(True) + else: + return(False) + #__| + + def job_failed(self, job_i): + """ + Check whether job_i is in failed state. + + Args: + job_i: + """ + #| - job_failed + path_i = self.var_lst_to_path(job_i, + job_rev="Auto", + relative_path=False, + ) + + crit_0 = False + job_state = self.cluster.job_state(path_i=path_i) + if job_state == "FAILED": + crit_0 = True + + crit_1 = False + if os.path.isfile(path_i + "/.SUBMITTED"): + crit_1 = True + + crit_2 = False + # if not os.path.isfile(path_i + "/.FINISHED"): + if not os.path.isfile(path_i + "/." + DFT_Jobs_Analysis.finished_fle): + crit_2 = True + + #| - Parsing Error File for "Error" (Sherlock only for now) + if self.cluster.cluster_sys == "sherlock": + error = self.parse_job_error_file(path_i) + if error: + crit_0 = True + #__| + + crit_list = [crit_0, crit_1, crit_2] + + if all(crit is True for crit in crit_list): + return(True) + else: + return(False) + #__| + + def job_submitted(self, path_i): + """ + Check whether job is submitted. + + Args: + path_i + """ + #| - job_submitted + try: + if os.path.isfile(path_i + "/.SUBMITTED"): + return(True) + else: + return(False) + except: + return(False) + #__| + + #__| + + #| - NEW Methods That Use path_i Instead of job_i (Create col in df!!) + def _job_ready(self, path_i, require_READY_tag=True): + """ + Return whether job_i is in READY state. + + Args: + job_i: + require_READY_tag: + Require a ".READY" file start job + """ + #| - job_ready + # path_i = self.var_lst_to_path(job_i, + # ob_rev="Auto", + # relative_path=False, + # ) + + crit_0 = False + if os.path.isfile(path_i + "/.READY"): + crit_0 = True + elif require_READY_tag is False: + crit_0 = True + + crit_1 = False + if not os.path.isfile(path_i + "/.SUBMITTED"): + crit_1 = True + + #| - Having trouble with AWS .READY files not being copied over + # if self.cluster.cluster_sys == "aws": + # crit_ + #__| + + crit_list = [crit_0, crit_1] + + if all(crit is True for crit in crit_list): + return(True) + else: + return(False) + #__| + + def _job_pending(self, path_i): + """ + Return whether job_i is in PENDING state. + + Args: + path_i: + """ + #| - job_pending + # path_i = self.var_lst_to_path(job_i, job_rev="Auto", + # relative_path=False) + + crit_0 = False + job_state = self.cluster.cluster.job_state(path_i=path_i) + + + # print("**************************************************") + # print("self.cluster.cluster.job_state") + # print(job_state) + # print("**************************************************") + + if job_state == "PENDING": + crit_0 = True + + + crit_1 = False + if self.job_state_file(path_i) == "PENDING": + crit_1 = True + + crit_list = [crit_0, crit_1] + + if all(crit is True for crit in crit_list): + return(True) + else: + return(False) + #__| + + def _job_running(self, path_i): + """ + Return whether job_i is in RUNNING state. + + Args: + path_i: + """ + #| - job_running + crit_0 = True + if os.path.isfile(path_i + "/.READY"): + crit_0 = True + + crit_1 = False + if os.path.isfile(path_i + "/.SUBMITTED"): + crit_1 = True + + crit_2 = False + if not os.path.isfile(path_i + "/.FINISHED"): + crit_2 = True + + crit_3 = False + job_state = self.cluster.cluster.job_state(path_i=path_i) + if job_state == "RUNNING": + crit_3 = True + + crit_list = [crit_0, crit_1, crit_2, crit_3] + + if all(crit is True for crit in crit_list): + return(True) + else: + return(False) + #__| + + def _job_succeeded(self, path_i): + """ + Return whether job_i is in SUCCEEDED state. + + Args: + path_i: + """ + #| - job_succeeded + crit_0 = True + if os.path.isfile(path_i + "/.READY"): + crit_0 = True + + crit_1 = False + if os.path.isfile(path_i + "/.SUBMITTED"): + crit_1 = True + + # Checking for '.FINSISHED' file OR checking batch queue + + crit_2_1 = False + if os.path.isfile(path_i + "/.FINISHED"): + crit_2_1 = True + + crit_2_2 = False + job_state = self.cluster.cluster.job_state(path_i=path_i) + if job_state == "SUCCEEDED": + crit_2_2 = True + + if crit_2_2 or crit_2_1: + crit_2 = True + else: + crit_2 = False + + crit_list = [crit_0, crit_1, crit_2] + if all(crit is True for crit in crit_list): + return(True) + else: + return(False) + #__| + + def _job_failed(self, path_i): + """ + Return whether job_i is in FAILED state. + + Args: + path_i: + """ + #| - job_failed + crit_0 = False + job_state = self.cluster.job_state(path_i=path_i) + if job_state == "FAILED": + crit_0 = True + + crit_1 = False + if os.path.isfile(path_i + "/.SUBMITTED"): + crit_1 = True + + crit_2 = False + if not os.path.isfile(path_i + "/.FINISHED"): + crit_2 = True + + + #| - Parsing Error File for "Error" (Sherlock only for now) + + if self.cluster.cluster_sys == "sherlock": + error = self.parse_job_error_file(path_i) + if error: + crit_0 = True + + # if error and self.cluster.cluster_sys == "sherlock": + # # print(error) + # crit_0 = True + #__| + + crit_list = [crit_0, crit_1, crit_2] + + if all(crit is True for crit in crit_list): + return(True) + else: + return(False) + #__| + + def _job_submitted(self, path_i): + """ + Return whether job_i is in SUBMITTED state. + + Args: + path_i: + """ + #| - job_submitted + try: + if os.path.isfile(path_i + "/.SUBMITTED"): + return(True) + else: + return(False) + except: + return(False) + #__| + + #__| + + def parse_job_error_file(self, path_i): + """ + Read error file and searches for "Error" in last line. + + TODO This is very specific to QE jobs so should be moved. + + Args: + path_i + """ + #| - parse_job_error_file + err_file = self.cluster.cluster.error_file + err_file = os.path.join(path_i, err_file) + + error = False + if os.path.isfile(err_file): + with open(err_file) as fle: + lines = [line.strip() for line in fle] + + lines = lines[-4:] + + for line in lines: + + if "KohnShamConvergenceError" in line: + print("KohnShamConvergenceError Occured!! - RF") + error = True + break + elif "DUE TO TIME LIMIT" in line: + print("Job Reached Time Limit!! - RF") + error = True + break + elif "RuntimeError: SCF Calculation failed": + print("RuntimeError: SCF Calculation failed - RF") + error = True + break + else: + error = False + pass + + else: + error = False + + return(error) + #__| + + #__| ********************************************************************** + +#__| ************************************************************************** + + +def parse_job_dirs(dirs_to_parse): + """Parse directory structure for jobs. + + Args: + dirs_to_parse + """ + #| - parse_job_dirs + + #| - Import Modules + # import os + # import sys + # + # import pickle as pickle + #__| + + #| - Script Input + # dirs_to_parse = [ + # "01_surface_calcs", + # "02_surface_coverage", + # "03_OER_Calc", + # "07_diff_coverages_term", + # ] + #__| + + #| - MASTER Loop + master_path_list = [] + for dir_j in dirs_to_parse: + # path_j = os.path.join(os.getcwd(), dir_j) + path_j = dir_j + for root, dirs, files in os.walk(path_j, topdown=True): + for name in dirs: + name_i = os.path.join(root, name) + + dir_root = os.path.join(*name_i.split("/")[0:-1]) + dir_leaf = name_i.split("/")[-1] + + #| - Test that terminal dir name has _1 format + condition_0 = False + if dir_leaf[0] == "_": + condition_0 = True + + condition_1 = False + if len(dir_leaf.split("_")) == 2: + condition_1 = True + + numeric_part = dir_leaf.split("_")[-1] + condition_2 = False + if numeric_part.isdigit(): + condition_2 = True + #__| + + condition_3 = False + if "__old__" not in name_i: + condition_3 = True + + condition_4 = False + if "__temp__" not in name_i: + condition_4 = True + + if all([ + condition_0, + condition_1, + condition_2, + condition_3, + condition_4, + ]): + master_path_list.append("/" + dir_root) + + #__| + + master_path_list_unique = list(set(master_path_list)) + + # for i in master_path_list_unique: print(i) + + #| - NEW | Check that paths contain job_params.json file + for path_i in master_path_list_unique: + if "job_params.json" not in os.listdir(path_i): + print("job_params not in: ", path_i) + + for path_i in master_path_list_unique: + + files_i = os.listdir(path_i) + for file_j in files_i: + + #| - TEMP + condition_list = [] + + # Make sure that 'run' is in the dir name (ex. 3-run) + if "run" in file_j: + condition_list.append(True) + # print("run file here") + else: + condition_list.append(False) + + # Make sure there is a '-' character + if "-" in file_j: + condition_list.append(True) + + # Make sure the first set of characters are numeric + if file_j.split("-")[0].isdigit(): + condition_list.append(True) + else: + condition_list.append(False) + + else: + condition_list.append(False) + + #__| + + if all(condition_list): + print("Found a #-run folder: ", path_i) + + #__| + + return(master_path_list_unique) + + #| - Saving List to Pickle + # with open("181016_jobs_dir_list.pickle", "w") as fle: + # pickle.dump(master_path_list_unique ,fle) + #__| + + #__| + +def compare_parsed_and_user_job_dirs(parsed_dirs, user_dirs): + """ + """ + #| - compare_parsed_and_user_job_dirs + + print(" ") + print(" ") + print("User inputed dir_list len: ", str(len(user_dirs))) + print("Parsed dir_list len: ", str(len(parsed_dirs))) + + print(20 * "_"); print("") + + print("Dirs that were parsed but are not in the user specified list") + print(set(parsed_dirs).difference(set(user_dirs))) + print(20 * "*") + print("Dirs that are in the user list but not in the parsed list") + print(set(user_dirs).difference(set(parsed_dirs))) + + #__| + + + +#| - __old__ + + + + #| - __old__ + + #| - Picking Revision Number(s) To Query + # largest_rev = self.job_revision_number(entry) + # + # if revision == "auto": + # rev = [largest_rev] + # elif revision == "previous": + # if largest_rev == 1: + # rev = [1] + # else: + # rev = [largest_rev - 1] + # elif revision == "all": + # rev = range(self.job_revision_number(entry) + 1) + # else: + # rev = [revision] + #__| + + # def add_data_column(self, + # function, + # column_name="new_column", + # revision="auto", + # allow_failure=True, + # # allow_failure=False, + # ): + # """ + # Add data column to data frame by iterating thourgh job folders. + # + # Args: + # function: + # Set of operations that will be applied to indiviudal job + # folders. Must return a scalar quantity that will be added to + # data frame. The function should know "what to do" given only a + # path that correpsonds to a unique job folder (including revision). + # + # If the function returns a dict, then various columns will be + # added with the column names corresponding to the key name. + # + # column_name: + # Name of new data column + # + # revision: + # The job revision from which data is scraped + # "auto" | Selects most recent revision folder + # "all" | Adds all revisions to data frame (NOT WORKING) + # "previous | Second to last revision" + # allow_failure: + # If True, a failed method call will result in NaN + # """ + # #| - __add_data_coumn__ + # new_data_col = [] + # job_rev_lst = [] + # + # print("Adding " + str(column_name)) + # + # for entry in self.data_frame["variable_list"]: + # + # path = self.var_lst_to_path( + # entry, + # relative_path=False, + # job_rev="False", + # ) + # + # #| - Picking Revision Number(s) To Query + # largest_rev = self.job_revision_number(entry) + # + # if revision == "auto": + # rev = [largest_rev] + # elif revision == "previous": + # if largest_rev == 1: + # rev = [1] + # else: + # rev = [largest_rev - 1] + # elif revision == "all": + # rev = range(self.job_revision_number(entry) + 1) + # else: + # rev = [revision] + # #__| + # + # for rev_num in rev: + # + # #| - Run Function + # path += "_" + str(rev_num) + # + # path = path + self.cluster.cluster.job_data_dir + # + # if allow_failure is True: + # try: + # out = function(path) + # except: + # out = np.nan + # else: + # out = function(path) + # + # new_data_col.append(out) + # job_rev_lst.append(rev_num) + # #__| + # + # data_type_list = [type(x) for x in new_data_col] + # dict_in_list = any(item == dict for item in data_type_list) + # + # if dict_in_list: + # new_col = [] + # for x in new_data_col: + # if pd.isnull(x) is True: + # new_col.append({"NA": np.nan}) + # else: + # new_col.append(x) + # + # new_columns_df = pd.DataFrame(new_col) + # + # df1 = self.data_frame + # df2 = new_columns_df + # + # out_df = pd.concat([df1, df2], axis=1) + # self.data_frame = out_df + # + # else: + # self.data_frame[column_name] = new_data_col + # #__| + # + + #__| + + + + # DEPR + def view_atoms(self, ind): + """ + View last image in atoms object in GUI. + + Args: + ind: + Index of dataframe corresponding to entry of interest. + """ + #| - view_atoms + df = self.data_frame + + path_i = df.iloc[ind]["path"] + rev_num = df.iloc[ind]["revision_number"].astype(str) + full_path = path_i + "_" + rev_num + + print(full_path) + + try: + atoms = df.iloc[ind]["atoms_object"][-1] + view(atoms) + except: + print("Couldn't read atoms object") + #__| + + + # DEPR + # Already implemented in job_setup + def job_revisions(self, path): + """Return number of revision folders for a given job. + + Args: + path: + """ + #| - job_revisions + path = "/".join(path.split("/")[0:-1]) + "/" + + # Attempting to remove duplicate job folders (usually have spaces) + dir_list = [x for x in os.walk(path).next()[1] if " " not in x] + + return(len(dir_list)) + #__| + +#__| diff --git a/dft_job_automat/job_dependencies.py b/dft_job_automat/job_dependencies.py index b0b6d47..b2d279f 100644 --- a/dft_job_automat/job_dependencies.py +++ b/dft_job_automat/job_dependencies.py @@ -1,647 +1,647 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -"""Methods and code to handle jobs that depend on one another.""" - -#| - Import Modules -import sys -import os -import shutil -import copy - -from ase import io -import pandas as pd - -from dft_job_automat.job_analysis import DFT_Jobs_Analysis -from dft_job_automat.job_manager import DFT_Jobs_Manager -#__| - -#| - FUNCTIONS - -def full_path_i(root_dir, step_dir_names, step, path): - """Formats relative path to full path for a given calculation step - """ - #| - full_path_i - path_out = root_dir + "/" + step_dir_names[step - 1] + "/" + path - - return(path_out) - #__| - -def copyfiles_onestep_up( - job_var_lst, - step, - JobsInstances_lst, - files_lst=[], - root_dir_files=None - ): - """ - """ - #| - copyfiles_onestep_up - def copy_if_not_in_dest(source, dest_file): - """ - """ - #| - copy_if_not_in_dest - if not os.path.isfile(dest_file): - - shutil.copy(source, dest_file) - source_fle = source.split("/")[-1] - - print("File " + str(source_fle) + " copied") - else: - pass - - #__| - - - curr_step = JobsInstances_lst[step - 1] - next_step = JobsInstances_lst[step] - - - root_dir = curr_step.root_dir - - dir_curr = curr_step.var_lst_to_path( - job_var_lst, - job_rev="Auto", - relative_path=False, - ) - next_var_lst = copy.deepcopy(next_step.job_var_lst) - - #| - Finding jobs in step+1 whose properties match step's - for curr_property in job_var_lst: - prop_name = curr_property["property"] # force-cutoff - prop_value = curr_property["value"] # 0.001 - - for job in next_step.job_var_lst: - path_i = next_step.var_lst_to_path( - job, - job_rev="Auto", - relative_path=False, - ) - - # match_lst = [] - for next_property in job: - next_prop_name = next_property["property"] - next_prop_value = next_property["value"] - - if next_prop_name == prop_name: - if next_prop_value != prop_value: - - if job in next_var_lst: - next_var_lst.remove(job) - else: - pass - #__| - - for next_job in next_var_lst: - path_i = next_step.var_lst_to_path( - next_job, - job_rev="Auto", - relative_path=False, - ) - - for file_i in files_lst: - - #| - Copy Files to Directory in New Step - if type(file_i) == str: - curr_dir = dir_curr + \ - curr_step.cluster.cluster.job_data_dir + "/" + file_i - copy_if_not_in_dest(curr_dir, path_i + "/" + file_i) - - elif type(file_i) == list: - curr_dir = dir_curr + \ - curr_step.cluster.cluster.job_data_dir + "/" + file_i[0] - copy_if_not_in_dest(curr_dir, path_i + "/" + file_i[1]) - #__| - - - if root_dir_files is not None: - root_dir = curr_step.root_dir - source_dir = root_dir - - dest_dir = path_i - - for file_i in root_dir_files: - #| - Copy Files from Root Dir to New Job Folder - if type(file_i) == str: - copy_if_not_in_dest( - source_dir + "/" + file_i, - dest_dir + "/" + file_i, - ) - - elif type(file_i) == list: - copy_if_not_in_dest( - source_dir + "/" + file_i[0], - dest_dir + "/" + file_i[1], - ) - #__| - - - open(dir_curr + "/.FILES_COPIED", "w") - # file = open(dir_curr + "/.FILES_COPIED", "w") - - #__| - -def create_atoms_list(atoms_name, file_ext, root_dir): - """ - """ - #| - create_atoms_list - atoms_dict = {} - for atom in atoms_name: - atoms_i = io.read(root_dir + "/dir_atoms/" + atom + file_ext) - atoms_dict[atom] = atoms_i - - return(atoms_dict) - #__| - -def create_level_entries_dict(tree_level_labels, tree_level_values): - """ - """ - #| - create_level_entries_dict - level_entries_dict = {} - for index, variable in enumerate(tree_level_labels): - level_entries_dict[variable] = tree_level_values[index] - - return(level_entries_dict) - #__| - -#| - __OLD__ - -def job_runnable(df, root_dir_beg, path_i): - """ - """ - #| - job_runnable - df["full_path"] = root_dir_beg + "/" + df["root_dir"] + "/" + df["path"] + \ - "_" + df["job_revision_number"].astype(str) - - index = df.index[df["full_path"] == path_i].tolist() - df_i = df.iloc[index] - max_rev = df_i["revision_number"].max() - df_fin = df_i[df_i["revision_number"] == max_rev] - assert len(df_fin) == 1 - - if df_fin["job_state_2"].iloc[0] == "RUNNABLE": - return(True) - else: - return(False) - #__| - -def job_failed(df, root_dir_beg, path_i): - """ - """ - #| - job_failed - df["full_path"] = root_dir_beg + "/" + df["root_dir"] + "/" + df["path"] + \ - "_" + df["job_revision_number"].astype(str) - - - index = df.index[df["full_path"] == path_i].tolist() - df_i = df.iloc[index] - max_rev = df_i["revision_number"].max() - df_fin = df_i[df_i["revision_number"] == max_rev] - # assert len(index) == 1 # Checking that job path is unique - assert len(df_fin) == 1 - - - # index = df.index[df["full_path"] == path_i].tolist() - # assert len(index) == 1 # Checking that job path is unique - - # job_state = df.iloc[index[0]]["job_state_2"] - - # if job_state == "FAILED": - # return(True) - - - if df_fin["job_state_2"].iloc[0] == "FAILED": - return(True) - else: - return(False) - - #__| - -#__| - -#__| - -class DFT_Jobs_Workflow: - """Summary line. - - Useful class to set up multiple DFT job in a directory structure. - Must be initialized with tree_level and level_entries inputs - """ - - def __init__(self, - atoms_prefix=".traj", - atoms_list_names=["init"], - model_names=None, - - tree_level_labels_list=None, - tree_level_values_list=None, - indiv_dir_lst_list=None, - indiv_job_lst_list=None, - - setup_function=None, - maint_function=None, - number_of_steps=1, - root_dir=".", - run_jobs=False, - ): - """Initialize DFT_Jobs_Workflow instance. - - Args: - atoms_prefix: - atoms_list_names: - model_names: - - tree_level_labels_list: - tree_level_values_list: - indiv_dir_lst_list: - - setup_function: - maint_function: - number_of_steps: - root_dir: - run_jobs: - """ - #| - __init__ - self.mod_dir = "dir_models" - self.atoms_dir = "dir_atoms" - - self.atoms_ext = atoms_prefix - self.atoms_list_names = atoms_list_names - - self.num_steps = number_of_steps - - self.tree_level_labels_list = self.list_of_None_if_None( - tree_level_labels_list, - ) - - self.tree_level_values_list = self.list_of_None_if_None( - tree_level_values_list, - ) - - self.indiv_dir_lst_list = self.list_of_None_if_None( - indiv_dir_lst_list, - ) - - self.indiv_job_lst_list = self.list_of_None_if_None( - indiv_job_lst_list, - ) - - # self.model_names = model_names - - self.setup_function = setup_function - self.maint_function = maint_function - - self.run_jobs = run_jobs - - self.root_dir = self.__set_cwd__(root_dir) - # self.atoms_dict = create_atoms_list( - # atoms_list_names, - # atoms_prefix, - # self.root_dir, - # ) - - self.step_dir_names = self.__set_step_dir_names__() - self.model_names = self.__set_model_names__(model_names) - - self.jobs_an_list = self.__create_jobs_an__() - - self.__create_parent_dirs__() - self.__prep_dir_sys__() - - self.jobs_man_list = self.__create_jobs_man__() - self.__job_maint__() - #__| - - def list_of_None_if_None(self, input): - """Return list of 'None' of length == # of steps, if input is None - """ - #| - list_of_None_if_None - if input is None: - none_list = [None for i in range(self.num_steps)] - - return(none_list) - else: - return(input) - #__| - - def __set_cwd__(self, root_dir): - """Set the working directory. - - Args: - root_dir: - """ - #| - __set_cwd__ - if root_dir == ".": - root_dir_out = os.getcwd() - else: - root_dir_out = root_dir - - return(root_dir_out) - #__| - - def __set_step_dir_names__(self): - """ - """ - #| - __set_step_dir_names__ - number_of_steps = self.num_steps - step_dir_names = [] - for step_i in range(number_of_steps): - step_dir_name_i = str(step_i + 1) + "STEP" - step_dir_names.append(step_dir_name_i) - - return(step_dir_names) - #__| - - def __set_model_names__(self, model_names): - """Return list of model script names. - - Args: - model_names: - """ - #| - __set_model_names__ - # model_names = self.model_names - if model_names is None: - model_names_list = [] - for step_i in range(self.num_steps): - model_i = str(step_i) + "model.py" - model_names_list.append(model_i) - else: - model_names_list = model_names - - return(model_names_list) - #__| - - def __create_jobs_an__(self): - """Create Jobs_Analysis instances for each step of workflow.""" - #| - __create_jobs_an__ - # print("PREPARING EXTENDED FOLDER SYSTEM") #PERM_PRINT - step_dir_names = self.step_dir_names - master_root_dir = self.root_dir - - Jobs_Inst_list = [] - for step in range(len(step_dir_names)): - step_num = step + 1 - - print("Initializing Job Instance: " + str(step_num)) # PERM_PRINT - - # dir_struct_file = master_root_dir + "/" + step_dir_names[step] + \ - # "/jobs_bin/dir_structure.json" - - level_labels_tmp = self.tree_level_labels_list[step] - level_entries_tmp = self.tree_level_values_list[step] - - indiv_dir_lst_tmp = self.indiv_dir_lst_list[step] - indiv_job_lst_tmp = self.indiv_job_lst_list[step] - - JobsAn = DFT_Jobs_Analysis( - tree_level=level_labels_tmp, - level_entries=level_entries_tmp, - indiv_dir_lst=indiv_dir_lst_tmp, - indiv_job_lst=indiv_job_lst_tmp, - - root_dir=master_root_dir, - working_dir=step_dir_names[step], - update_job_state=False, - load_dataframe=False, - ) - - Jobs_Inst_list.append(JobsAn) - - return(Jobs_Inst_list) - #__| - - def __create_jobs_man__(self): - """Create Jobs_Manager instance(s).""" - #| - __create_jobs_man__ - step_dir_names = self.step_dir_names - master_root_dir = self.root_dir - - Jobs_Inst_list = [] - for step in range(len(step_dir_names)): - # step_num = step + 1 - - level_labels_tmp = self.tree_level_labels_list[step] - level_entries_tmp = self.tree_level_values_list[step] - - indiv_dir_lst_tmp = self.indiv_dir_lst_list[step] - indiv_job_lst_tmp = self.indiv_job_lst_list[step] - - Jobs = DFT_Jobs_Manager( - - - tree_level=level_labels_tmp, - level_entries=level_entries_tmp, - - skip_dirs_lst=None, - indiv_dir_lst=indiv_dir_lst_tmp, # <----------------------------------------------- - indiv_job_lst=indiv_job_lst_tmp, - - root_dir=master_root_dir, - working_dir=step_dir_names[step], - - update_job_state=False, - load_dataframe=False, - - # tree_level=level_labels_tmp, - # level_entries=level_entries_tmp, - # working_dir=master_root_dir + "/" + step_dir_names[step], - # load_dataframe=False, - ) - - Jobs_Inst_list.append(Jobs) - - return(Jobs_Inst_list) - #__| - - def __create_parent_dirs__(self): - """Create parent folders.""" - #| - __create_parent_dirs__ - step_dir_names = self.step_dir_names - master_root_dir = self.root_dir - - for step in range(len(step_dir_names)): - # step_num = step + 1 - - step_folder = master_root_dir + "/" + step_dir_names[step] - if not os.path.isdir(step_folder): - os.makedirs(step_folder) - #__| - - def __prep_dir_sys__(self): - """ - """ - #| - __prep_dir_sys - print("PREPARING EXTENDED FOLDER SYSTEM") # PERM_PRINT - step_dir_names = self.step_dir_names - master_root_dir = self.root_dir - - self.__create_parent_dirs__() - - wf_vars = vars(self) - for step in range(len(step_dir_names)): - # step_num = step + 1 - JobsAn = self.jobs_an_list[step] - - print("Placing Initial Files in Folders | LOOP OVER JOBS") - files_placed_file = master_root_dir + "/" + \ - step_dir_names[step] + "/.FILES_PLACED" - - # if not os.path.isfile(files_placed_file): - if True: - - #| - Create Step Folder Structure - JobsAn.create_dir_struct(create_first_rev_folder="True") - #__| - - for Job_i in JobsAn.Job_list: - path_i = Job_i.full_path - - job_i_params = Job_i.job_params - - self.setup_function(step, path_i, job_i_params, wf_vars) - - # for job_i in JobsAn.job_var_lst: - # path_i = JobsAn.var_lst_to_path( - # job_i, - # job_rev="Auto", - # relative_path=False, - # ) - # - # #| - Job_i Parameters - # job_i_params = {} - # for variable in JobsAn.tree_level_labels: - # job_i_var_j = JobsAn.extract_prop_from_var_lst( - # job_i, - # variable, - # ) - # job_i_params[variable] = job_i_var_j - # #__| - # - # self.setup_function(step, path_i, job_i_params, wf_vars) - - file_name = master_root_dir + "/" + step_dir_names[step] - file = open(file_name + "/.FILES_PLACED", "w") - - # file = open(master_root_dir + "/.FOLDERS_CREATED", "w") - open(master_root_dir + "/.FOLDERS_CREATED", "w") - #__| - - def __job_maint__(self): - """Manage jobs after being submitted. - - Tries to figure out what state the job is in and acts according to - user defined methods - """ - #| - __job_maint__ - step_dir_names = self.step_dir_names - # master_root_dir = self.root_dir - - for step in range(len(step_dir_names)): - step_num = step + 1 - Jobs = self.jobs_man_list[step] - - # df = Jobs.data_frame - tally = {"successes": 0, "failures": 0, "running": 0, "pending": 0} - - #| - PRINT - print("") # PERM_PRINT - print("###########################################################") - - str_i = "########################" - str_i += " STEP " + str(step_num) + " ###########################" - # "######################## STEP " + str(step_num) + - # " ###########################" - print(str_i) - print("###########################################################") - print("Total Jobs: " + str(Jobs.num_jobs)) # PERM_PRINT - #__| - - #| - LOOP OVER JOBS - if self.run_jobs: - - tally = { - "successes": 0, - "failures": 0, - "running": 0, - "pending": 0, - } - - wf_vars = vars(self) - - for Job_i in Jobs.Job_list: - - path_i = Job_i.full_path - job_i_params = Job_i.job_params - - # Why is this being run again #COMBAK - self.setup_function(step, path_i, job_i_params, wf_vars) - - # print(self.maint_function) - # step_i, - # job_i, - # job_i_params, - # wf_vars, - # tally, - - tally = self.maint_function( - step, - path_i, - job_i_params, - wf_vars, - tally, - ) - - #| - __old__ - # for job_i in Jobs.job_var_lst: - # path_i = Jobs.var_lst_to_path( - # job_i, - # job_rev="Auto", - # relative_path=False, - # ) - # - # #| - Job_i Parameters - # job_i_params = {} - # for variable in Jobs.tree_level_labels: - # job_i_param_j = Jobs.extract_prop_from_var_lst( - # job_i, - # variable, - # ) - # - # job_i_params[variable] = job_i_param_j - # #__| - # - # tally = self.maint_function( - # step, - # job_i, - # job_i_params, - # wf_vars, - # tally, - # ) - #__| - - # TODO Check that tally is being incremented by 1 only - print(tally) - print("") - #__| - - #__| - - -#| - Reinitiating the Jobs Instances (Is this needed) -# print("") #PERM_PRINT -# print("Reinitiating the Jobs Instances") #PERM_PRINT -# Jobs_Inst_list = [] -# for step in range(len(step_dir_names)): -# step_num = step + 1 -# -# # print("Initializing Job Instance: " + str(step_num)) -# Jobs = DFT_Jobs_Analysis( -# system="aws", -# tree_level=tree_level_labels_list[step], -# level_entries=level_entries_dict_list[step], -# working_dir=master_root_dir + "/" + step_dir_names[step], -# load_dataframe=False, -# ) -# -# Jobs_Inst_list.append(Jobs) -#__| +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Methods and code to handle jobs that depend on one another.""" + +#| - Import Modules +import sys +import os +import shutil +import copy + +from ase import io +import pandas as pd + +from dft_job_automat.job_analysis import DFT_Jobs_Analysis +from dft_job_automat.job_manager import DFT_Jobs_Manager +#__| + +#| - FUNCTIONS + +def full_path_i(root_dir, step_dir_names, step, path): + """Formats relative path to full path for a given calculation step + """ + #| - full_path_i + path_out = root_dir + "/" + step_dir_names[step - 1] + "/" + path + + return(path_out) + #__| + +def copyfiles_onestep_up( + job_var_lst, + step, + JobsInstances_lst, + files_lst=[], + root_dir_files=None + ): + """ + """ + #| - copyfiles_onestep_up + def copy_if_not_in_dest(source, dest_file): + """ + """ + #| - copy_if_not_in_dest + if not os.path.isfile(dest_file): + + shutil.copy(source, dest_file) + source_fle = source.split("/")[-1] + + print("File " + str(source_fle) + " copied") + else: + pass + + #__| + + + curr_step = JobsInstances_lst[step - 1] + next_step = JobsInstances_lst[step] + + + root_dir = curr_step.root_dir + + dir_curr = curr_step.var_lst_to_path( + job_var_lst, + job_rev="Auto", + relative_path=False, + ) + next_var_lst = copy.deepcopy(next_step.job_var_lst) + + #| - Finding jobs in step+1 whose properties match step's + for curr_property in job_var_lst: + prop_name = curr_property["property"] # force-cutoff + prop_value = curr_property["value"] # 0.001 + + for job in next_step.job_var_lst: + path_i = next_step.var_lst_to_path( + job, + job_rev="Auto", + relative_path=False, + ) + + # match_lst = [] + for next_property in job: + next_prop_name = next_property["property"] + next_prop_value = next_property["value"] + + if next_prop_name == prop_name: + if next_prop_value != prop_value: + + if job in next_var_lst: + next_var_lst.remove(job) + else: + pass + #__| + + for next_job in next_var_lst: + path_i = next_step.var_lst_to_path( + next_job, + job_rev="Auto", + relative_path=False, + ) + + for file_i in files_lst: + + #| - Copy Files to Directory in New Step + if type(file_i) == str: + curr_dir = dir_curr + \ + curr_step.cluster.cluster.job_data_dir + "/" + file_i + copy_if_not_in_dest(curr_dir, path_i + "/" + file_i) + + elif type(file_i) == list: + curr_dir = dir_curr + \ + curr_step.cluster.cluster.job_data_dir + "/" + file_i[0] + copy_if_not_in_dest(curr_dir, path_i + "/" + file_i[1]) + #__| + + + if root_dir_files is not None: + root_dir = curr_step.root_dir + source_dir = root_dir + + dest_dir = path_i + + for file_i in root_dir_files: + #| - Copy Files from Root Dir to New Job Folder + if type(file_i) == str: + copy_if_not_in_dest( + source_dir + "/" + file_i, + dest_dir + "/" + file_i, + ) + + elif type(file_i) == list: + copy_if_not_in_dest( + source_dir + "/" + file_i[0], + dest_dir + "/" + file_i[1], + ) + #__| + + + open(dir_curr + "/.FILES_COPIED", "w") + # file = open(dir_curr + "/.FILES_COPIED", "w") + + #__| + +def create_atoms_list(atoms_name, file_ext, root_dir): + """ + """ + #| - create_atoms_list + atoms_dict = {} + for atom in atoms_name: + atoms_i = io.read(root_dir + "/dir_atoms/" + atom + file_ext) + atoms_dict[atom] = atoms_i + + return(atoms_dict) + #__| + +def create_level_entries_dict(tree_level_labels, tree_level_values): + """ + """ + #| - create_level_entries_dict + level_entries_dict = {} + for index, variable in enumerate(tree_level_labels): + level_entries_dict[variable] = tree_level_values[index] + + return(level_entries_dict) + #__| + +#| - __OLD__ + +def job_runnable(df, root_dir_beg, path_i): + """ + """ + #| - job_runnable + df["full_path"] = root_dir_beg + "/" + df["root_dir"] + "/" + df["path"] + \ + "_" + df["job_revision_number"].astype(str) + + index = df.index[df["full_path"] == path_i].tolist() + df_i = df.iloc[index] + max_rev = df_i["revision_number"].max() + df_fin = df_i[df_i["revision_number"] == max_rev] + assert len(df_fin) == 1 + + if df_fin["job_state_2"].iloc[0] == "RUNNABLE": + return(True) + else: + return(False) + #__| + +def job_failed(df, root_dir_beg, path_i): + """ + """ + #| - job_failed + df["full_path"] = root_dir_beg + "/" + df["root_dir"] + "/" + df["path"] + \ + "_" + df["job_revision_number"].astype(str) + + + index = df.index[df["full_path"] == path_i].tolist() + df_i = df.iloc[index] + max_rev = df_i["revision_number"].max() + df_fin = df_i[df_i["revision_number"] == max_rev] + # assert len(index) == 1 # Checking that job path is unique + assert len(df_fin) == 1 + + + # index = df.index[df["full_path"] == path_i].tolist() + # assert len(index) == 1 # Checking that job path is unique + + # job_state = df.iloc[index[0]]["job_state_2"] + + # if job_state == "FAILED": + # return(True) + + + if df_fin["job_state_2"].iloc[0] == "FAILED": + return(True) + else: + return(False) + + #__| + +#__| + +#__| + +class DFT_Jobs_Workflow: + """Summary line. + + Useful class to set up multiple DFT job in a directory structure. + Must be initialized with tree_level and level_entries inputs + """ + + def __init__(self, + atoms_prefix=".traj", + atoms_list_names=["init"], + model_names=None, + + tree_level_labels_list=None, + tree_level_values_list=None, + indiv_dir_lst_list=None, + indiv_job_lst_list=None, + + setup_function=None, + maint_function=None, + number_of_steps=1, + root_dir=".", + run_jobs=False, + ): + """Initialize DFT_Jobs_Workflow instance. + + Args: + atoms_prefix: + atoms_list_names: + model_names: + + tree_level_labels_list: + tree_level_values_list: + indiv_dir_lst_list: + + setup_function: + maint_function: + number_of_steps: + root_dir: + run_jobs: + """ + #| - __init__ + self.mod_dir = "dir_models" + self.atoms_dir = "dir_atoms" + + self.atoms_ext = atoms_prefix + self.atoms_list_names = atoms_list_names + + self.num_steps = number_of_steps + + self.tree_level_labels_list = self.list_of_None_if_None( + tree_level_labels_list, + ) + + self.tree_level_values_list = self.list_of_None_if_None( + tree_level_values_list, + ) + + self.indiv_dir_lst_list = self.list_of_None_if_None( + indiv_dir_lst_list, + ) + + self.indiv_job_lst_list = self.list_of_None_if_None( + indiv_job_lst_list, + ) + + # self.model_names = model_names + + self.setup_function = setup_function + self.maint_function = maint_function + + self.run_jobs = run_jobs + + self.root_dir = self.__set_cwd__(root_dir) + # self.atoms_dict = create_atoms_list( + # atoms_list_names, + # atoms_prefix, + # self.root_dir, + # ) + + self.step_dir_names = self.__set_step_dir_names__() + self.model_names = self.__set_model_names__(model_names) + + self.jobs_an_list = self.__create_jobs_an__() + + self.__create_parent_dirs__() + self.__prep_dir_sys__() + + self.jobs_man_list = self.__create_jobs_man__() + self.__job_maint__() + #__| + + def list_of_None_if_None(self, input): + """Return list of 'None' of length == # of steps, if input is None + """ + #| - list_of_None_if_None + if input is None: + none_list = [None for i in range(self.num_steps)] + + return(none_list) + else: + return(input) + #__| + + def __set_cwd__(self, root_dir): + """Set the working directory. + + Args: + root_dir: + """ + #| - __set_cwd__ + if root_dir == ".": + root_dir_out = os.getcwd() + else: + root_dir_out = root_dir + + return(root_dir_out) + #__| + + def __set_step_dir_names__(self): + """ + """ + #| - __set_step_dir_names__ + number_of_steps = self.num_steps + step_dir_names = [] + for step_i in range(number_of_steps): + step_dir_name_i = str(step_i + 1) + "STEP" + step_dir_names.append(step_dir_name_i) + + return(step_dir_names) + #__| + + def __set_model_names__(self, model_names): + """Return list of model script names. + + Args: + model_names: + """ + #| - __set_model_names__ + # model_names = self.model_names + if model_names is None: + model_names_list = [] + for step_i in range(self.num_steps): + model_i = str(step_i) + "model.py" + model_names_list.append(model_i) + else: + model_names_list = model_names + + return(model_names_list) + #__| + + def __create_jobs_an__(self): + """Create Jobs_Analysis instances for each step of workflow.""" + #| - __create_jobs_an__ + # print("PREPARING EXTENDED FOLDER SYSTEM") #PERM_PRINT + step_dir_names = self.step_dir_names + master_root_dir = self.root_dir + + Jobs_Inst_list = [] + for step in range(len(step_dir_names)): + step_num = step + 1 + + print("Initializing Job Instance: " + str(step_num)) # PERM_PRINT + + # dir_struct_file = master_root_dir + "/" + step_dir_names[step] + \ + # "/jobs_bin/dir_structure.json" + + level_labels_tmp = self.tree_level_labels_list[step] + level_entries_tmp = self.tree_level_values_list[step] + + indiv_dir_lst_tmp = self.indiv_dir_lst_list[step] + indiv_job_lst_tmp = self.indiv_job_lst_list[step] + + JobsAn = DFT_Jobs_Analysis( + tree_level=level_labels_tmp, + level_entries=level_entries_tmp, + indiv_dir_lst=indiv_dir_lst_tmp, + indiv_job_lst=indiv_job_lst_tmp, + + root_dir=master_root_dir, + working_dir=step_dir_names[step], + update_job_state=False, + load_dataframe=False, + ) + + Jobs_Inst_list.append(JobsAn) + + return(Jobs_Inst_list) + #__| + + def __create_jobs_man__(self): + """Create Jobs_Manager instance(s).""" + #| - __create_jobs_man__ + step_dir_names = self.step_dir_names + master_root_dir = self.root_dir + + Jobs_Inst_list = [] + for step in range(len(step_dir_names)): + # step_num = step + 1 + + level_labels_tmp = self.tree_level_labels_list[step] + level_entries_tmp = self.tree_level_values_list[step] + + indiv_dir_lst_tmp = self.indiv_dir_lst_list[step] + indiv_job_lst_tmp = self.indiv_job_lst_list[step] + + Jobs = DFT_Jobs_Manager( + + + tree_level=level_labels_tmp, + level_entries=level_entries_tmp, + + skip_dirs_lst=None, + indiv_dir_lst=indiv_dir_lst_tmp, # <----------------------------------------------- + indiv_job_lst=indiv_job_lst_tmp, + + root_dir=master_root_dir, + working_dir=step_dir_names[step], + + update_job_state=False, + load_dataframe=False, + + # tree_level=level_labels_tmp, + # level_entries=level_entries_tmp, + # working_dir=master_root_dir + "/" + step_dir_names[step], + # load_dataframe=False, + ) + + Jobs_Inst_list.append(Jobs) + + return(Jobs_Inst_list) + #__| + + def __create_parent_dirs__(self): + """Create parent folders.""" + #| - __create_parent_dirs__ + step_dir_names = self.step_dir_names + master_root_dir = self.root_dir + + for step in range(len(step_dir_names)): + # step_num = step + 1 + + step_folder = master_root_dir + "/" + step_dir_names[step] + if not os.path.isdir(step_folder): + os.makedirs(step_folder) + #__| + + def __prep_dir_sys__(self): + """ + """ + #| - __prep_dir_sys + print("PREPARING EXTENDED FOLDER SYSTEM") # PERM_PRINT + step_dir_names = self.step_dir_names + master_root_dir = self.root_dir + + self.__create_parent_dirs__() + + wf_vars = vars(self) + for step in range(len(step_dir_names)): + # step_num = step + 1 + JobsAn = self.jobs_an_list[step] + + print("Placing Initial Files in Folders | LOOP OVER JOBS") + files_placed_file = master_root_dir + "/" + \ + step_dir_names[step] + "/.FILES_PLACED" + + # if not os.path.isfile(files_placed_file): + if True: + + #| - Create Step Folder Structure + JobsAn.create_dir_struct(create_first_rev_folder="True") + #__| + + for Job_i in JobsAn.Job_list: + path_i = Job_i.full_path + + job_i_params = Job_i.job_params + + self.setup_function(step, path_i, job_i_params, wf_vars) + + # for job_i in JobsAn.job_var_lst: + # path_i = JobsAn.var_lst_to_path( + # job_i, + # job_rev="Auto", + # relative_path=False, + # ) + # + # #| - Job_i Parameters + # job_i_params = {} + # for variable in JobsAn.tree_level_labels: + # job_i_var_j = JobsAn.extract_prop_from_var_lst( + # job_i, + # variable, + # ) + # job_i_params[variable] = job_i_var_j + # #__| + # + # self.setup_function(step, path_i, job_i_params, wf_vars) + + file_name = master_root_dir + "/" + step_dir_names[step] + file = open(file_name + "/.FILES_PLACED", "w") + + # file = open(master_root_dir + "/.FOLDERS_CREATED", "w") + open(master_root_dir + "/.FOLDERS_CREATED", "w") + #__| + + def __job_maint__(self): + """Manage jobs after being submitted. + + Tries to figure out what state the job is in and acts according to + user defined methods + """ + #| - __job_maint__ + step_dir_names = self.step_dir_names + # master_root_dir = self.root_dir + + for step in range(len(step_dir_names)): + step_num = step + 1 + Jobs = self.jobs_man_list[step] + + # df = Jobs.data_frame + tally = {"successes": 0, "failures": 0, "running": 0, "pending": 0} + + #| - PRINT + print("") # PERM_PRINT + print("###########################################################") + + str_i = "########################" + str_i += " STEP " + str(step_num) + " ###########################" + # "######################## STEP " + str(step_num) + + # " ###########################" + print(str_i) + print("###########################################################") + print("Total Jobs: " + str(Jobs.num_jobs)) # PERM_PRINT + #__| + + #| - LOOP OVER JOBS + if self.run_jobs: + + tally = { + "successes": 0, + "failures": 0, + "running": 0, + "pending": 0, + } + + wf_vars = vars(self) + + for Job_i in Jobs.Job_list: + + path_i = Job_i.full_path + job_i_params = Job_i.job_params + + # Why is this being run again #COMBAK + self.setup_function(step, path_i, job_i_params, wf_vars) + + # print(self.maint_function) + # step_i, + # job_i, + # job_i_params, + # wf_vars, + # tally, + + tally = self.maint_function( + step, + path_i, + job_i_params, + wf_vars, + tally, + ) + + #| - __old__ + # for job_i in Jobs.job_var_lst: + # path_i = Jobs.var_lst_to_path( + # job_i, + # job_rev="Auto", + # relative_path=False, + # ) + # + # #| - Job_i Parameters + # job_i_params = {} + # for variable in Jobs.tree_level_labels: + # job_i_param_j = Jobs.extract_prop_from_var_lst( + # job_i, + # variable, + # ) + # + # job_i_params[variable] = job_i_param_j + # #__| + # + # tally = self.maint_function( + # step, + # job_i, + # job_i_params, + # wf_vars, + # tally, + # ) + #__| + + # TODO Check that tally is being incremented by 1 only + print(tally) + print("") + #__| + + #__| + + +#| - Reinitiating the Jobs Instances (Is this needed) +# print("") #PERM_PRINT +# print("Reinitiating the Jobs Instances") #PERM_PRINT +# Jobs_Inst_list = [] +# for step in range(len(step_dir_names)): +# step_num = step + 1 +# +# # print("Initializing Job Instance: " + str(step_num)) +# Jobs = DFT_Jobs_Analysis( +# system="aws", +# tree_level=tree_level_labels_list[step], +# level_entries=level_entries_dict_list[step], +# working_dir=master_root_dir + "/" + step_dir_names[step], +# load_dataframe=False, +# ) +# +# Jobs_Inst_list.append(Jobs) +#__| diff --git a/dft_job_automat/job_manager.py b/dft_job_automat/job_manager.py index 35e3a80..9cfea50 100644 --- a/dft_job_automat/job_manager.py +++ b/dft_job_automat/job_manager.py @@ -1,568 +1,568 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -"""Module to carry out common file operations in jobs directory. - -Author: Raul A. Flores -""" - -#| - Import Modules -import os -import sys - -import shutil -import pandas as pd -import filecmp - -import pickle as pickle - -# My Modules -from dft_job_automat.job_analysis import DFT_Jobs_Analysis -# from aws.aws_class import AWS_Queues -#__| - -class DFT_Jobs_Manager(DFT_Jobs_Analysis): - """ - Summary line. - - Manages job submission, resubmission, revision managmnet, job status, etc. - """ - - #| - DFT_Jobs_Manager ***************************************************** - def __init__(self, - tree_level=None, - level_entries=None, - skip_dirs_lst=None, - indiv_dir_lst=None, # <----------------------------------------------- - indiv_job_lst=None, - root_dir=".", - working_dir=".", - update_job_state=False, - load_dataframe=True, - - dataframe_dir=None, - job_type_class=None, - methods_to_run=None, - folders_exist=None, - parse_all_revisions=True, - ): - """Initialize Jobs_Manager instance. - - Args: - tree_level: - level_entries: - skip_dirs_lst: - working_dir: - update_job_state: - load_dataframe: - - TEMP TEMP - """ - #| - __init__ - - #| - __old__ - # tree_level=None, - # level_entries=None, - # skip_dirs_lst=None, - # indiv_dir_lst=None, # <----------------------------------------------- - # indiv_job_lst=None, - # root_dir=".", - # working_dir=".", - # update_job_state=False, - # load_dataframe=True, - # dataframe_dir=dataframe_dir, - # job_type_class=job_type_class, - # methods_to_run=methods_to_run, - # folders_exist=folders_exist, - # parse_all_revisions=parse_all_revisions, - #__| - - DFT_Jobs_Analysis.__init__(self, - tree_level=tree_level, - level_entries=level_entries, - skip_dirs_lst=skip_dirs_lst, - indiv_dir_lst=indiv_dir_lst, - indiv_job_lst=indiv_job_lst, - root_dir=root_dir, - working_dir=working_dir, - update_job_state=update_job_state, - load_dataframe=load_dataframe, - - dataframe_dir=dataframe_dir, - job_type_class=job_type_class, - methods_to_run=methods_to_run, - folders_exist=folders_exist, - parse_all_revisions=parse_all_revisions, - ) - - #| - __old__ - # # system=system, - # tree_level=tree_level, - # level_entries=level_entries, - # working_dir=working_dir, - # update_job_state=update_job_state, - # load_dataframe=load_dataframe, - # dataframe_dir=None, - # job_type_class=None, - # folders_exist=None, - #__| - - #__| - - def restart_job(self, - job_i, - prev_rev_files_list, - root_dir=".", - file_list=None, - sub_params=None, - source_rev=None, - from_simulation_folder=True, - run_job=False, - ): - """ - Restart job from previous revision. - - # TODO | Make copy_if_not_in_dest a global function or something - - Args: - prev_rev_files_list: - file_list: - job_i - """ - #| - restart_job - # FIXME I've defined this in many places. - def copy_if_not_in_dest(source, dest_file): - """ - Copy file from source to destionation. - - Args: - dest_file: - """ - #| - copy_if_not_in_dest - if not os.path.isfile(dest_file): - - shutil.copy(source, dest_file) - source_fle = source.split("/")[-1] - - print("File " + str(source_fle) + " copied") - else: - pass - #__| - - self.create_job_dir(job_i, revision="Auto") - self.copy_files_from_last_revision( - prev_rev_files_list, - job_i, - revisions="Auto", - source_rev=source_rev, - from_simulation_folder=from_simulation_folder, - ) - - if file_list is not None: - source_dir = root_dir - - dest_dir = self.var_lst_to_path( - job_i, - job_rev="Auto", - relative_path=False, - ) - - for file_i in file_list: - #| - Copy Files from Root Dir to New Job Folder - if type(file_i) == str: - copy_if_not_in_dest( - source_dir + "/" + file_i, - dest_dir + "/" + file_i, - ) - - elif type(file_i) == list: - copy_if_not_in_dest( - source_dir + "/" + file_i[0], - dest_dir + "/" + file_i[1], - ) - #__| - - path_i = self.var_lst_to_path( - job_i, - job_rev="Auto", - relative_path=False, - ) - - if sub_params is None: - params_dict = { - "path_i": path_i - } - else: - params_dict = sub_params - params_dict["path_i"] = path_i - - if run_job: - self.submit_job(**params_dict) - else: - pass - #__| - - def copy_files_from_last_revision(self, - files_list, - job_i, - revisions="Auto", - source_rev=None, - from_simulation_folder=True, - ): - """ - Copy files from last revision. - - Args: - revisions: - [source revision, destination revision] - files_list: - job_i: - revisions: - source_rev: - from_simulation_folder: - If system is AWS, decidedes whether the previous jobs' files - are obtained from the /simulation folder or the origial job dir. - """ - #| - copy_files_from_last_revision - - # COMBAK - def copy_if_not_in_dest(source, dest_file): - """ - Copy file from source to destionation. - - Args: - dest_file: - """ - #| - copy_if_not_in_dest - if not os.path.isfile(dest_file): - - shutil.copy(source, dest_file) - source_fle = source.split("/")[-1] - - print("File " + str(source_fle) + " copied") - else: - pass - #__| - - job_path = self.var_lst_to_path( - job_i, - job_rev=False, - relative_path=False, - ) - rev_num = self.job_revision_number(job_i) - - if revisions == "Auto": - rev_dest = rev_num - - if source_rev is not None: - rev_source = source_rev - else: - rev_source = rev_dest - 1 - - else: - rev_dest = revisions[1] - rev_source = revisions[0] - - dest_dir = job_path + "_" + str(rev_dest) - source_dir = job_path + "_" + str(rev_source) - - for file_i in files_list: - - #| - Copy Files to Directory in New Step - - if from_simulation_folder is True: - data_d = self.cluster.cluster.job_data_dir - else: - data_d = "" - - if type(file_i) == str: - copy_if_not_in_dest( - source_dir + data_d + "/" + file_i, - dest_dir + "/" + file_i, - ) - - elif type(file_i) == list: - copy_if_not_in_dest( - source_dir + data_d + "/" + file_i[0], - dest_dir + "/" + file_i[1], - ) - #__| - - #__| - - def submit_job(self, **kwargs): - """Submit job to appropriate cluster. - - Args: - **kwargs: - """ - #| - submit_job - # path_i = kwargs["path_i"] - - self.cluster.submit_job(**kwargs) - #__| - - def remove_rev_folder(self, revision_number): - """Remove revision job folder in all jobs directories. - - Args: - revision_number: - """ - #| - remove_rev_folder - print("Removing job revision folder " + str(revision_number)) - - for job in self.job_var_lst: - path = self.var_lst_to_path(job) - - shutil.rmtree(path + "_" + str(revision_number)) - #__| - - def restart_job_2(self, prev_rev_file_list=[], root_dir_file_list=[]): - """ - Restart jobs - attempt 2. - - Args: - prev_rev_file_list: - root_dir_file_list: - """ - #| - restart_job_2 - for index, row in self.data_frame.iterrows(): - if row["job_state"] == "error": - #| - Body - job = row["variable_list"] - path = row["path"] - rev_n = self.job_revision_number(job) - - first_path = path + "_1" - prev_path = path + "_" + str(rev_n) - new_path = path + "_" + str(rev_n + 1) - - # if stop == True: - # break - # stop = True - - self.create_job_dir(job, revision="Auto") - - for file in prev_rev_file_list: - - if "out.traj" in file: - dest_path = new_path + "/init.traj" - else: - dest_path = new_path + "/" - - try: - shutil.copy(prev_path + "/" + file, dest_path) - except: - shutil.copy(first_path + "/" + file, dest_path) - - - for file in root_dir_file_list: - file_path = self.root_dir + "/" + file - shutil.copy(file_path, new_path + "/") - - os.system("chmod 777 " + new_path + "/*") - - os.chdir(new_path) - print("Submitting Folder: " + new_path) - - bash_command = "$HOME/matr.io/bin/trisub -q medium -c 4" - os.system(bash_command) - - os.chdir(self.root_dir) - #__| - else: - continue - #__| - - def copy_files_jd(self, file_list, variable_lst, revision="Auto"): - """Copy files to job directory. - - Args: - file_list: - variable_lst: - revision: - """ - #| - copy_files_jd - path = self.var_lst_to_path(variable_lst) - path += "_" + str(self.job_revision_number(variable_lst)) - - for file in file_list: - shutil.copyfile(self.root_dir + "/" + file, path + "/" + file) - - #__| - - def create_job_dir(self, variable_lst, revision="Auto"): - """ - Create indiviudal job folders as leaves within the dir tree. - - Args: - variable_lst: - revision: - """ - #| - create_job_dir - path = self.var_lst_to_path( - variable_lst, - job_rev="False", - relative_path=False, - ) - - # print(path) - if revision == "Auto": - rev = self.job_revision_number(variable_lst) + 1 - path += "_" + str(rev) - - if not os.path.exists(path): - print("Creating revision folder " + str(rev)) # PRINT - os.makedirs(path) - - else: - path += "_" + str(revision) - - if not os.path.exists(path): - os.makedirs(path) - - #__| - - # path variable not needed/used DELETE #NOTE - def submit_jobs(self, path=None, queue="medium", copy_PythonModules=True): - """ - Submit all jobs within data folder. - - Submits the most recent version number in each job folder - - 1. Copies the current model.py into the "model_version" folder - 2. Goes through - """ - #| - submit_jobs - - #| - OLD - # def submit_folder_job(folder_dir, bash_command): - # """ - # """ - # #| - submit_folder_job - # - # - # #| - Submtting Job - # try: - # os.chdir(folder_dir) - # - # if os.path.isfile(".SUBMITTED"): - # print("Directory already submitted, will be skipped") - # os.chdir(self.root_dir) - # return(None) - # else: - # print("tmp - submitting job") - # output = subprocess.check_output(bash_command, shell=True) - # # TEMP - # sub_time = datetime.datetime.now().isoformat() - # - # except: - # os.chdir(self.root_dir) - # print("JOB SKIPPED: " + folder_dir) - # return(None) - # #__| - # - # - # #| - Parsing Submission for Job ID - # output = output.splitlines() - # for line in output: - # if "jobId" in line: - # lst = line.split('"') - # job_id_ind = (lst.index("jobId") + 2) - # jobId = lst[job_id_ind] - # - # # This is not necessary anymore - # elif "jobName" in line: - # lst = line.split('"') - # job_name_ind = (lst.index("jobName") + 2) - # jobName = lst[job_name_ind] - # #__| - # - # - # file = open(".submitted", "w") - # file.close() - # - # os.chdir(self.root_dir) - # - # #| - Querying AWS For Job Info - # job_queue_dict = AWS_Queues(jobId).job_info_batch() - # job_queue_dict["submit_time"] = sub_time - # - # jobs_file_path = self.job_queue_dir + "/jobs.csv" - # - # df_new = pd.DataFrame([job_queue_dict]) - # if os.path.isfile(jobs_file_path): - # df = pd.read_csv(jobs_file_path) - # df = df.append(df_new) - # else: - # df = df_new - # - # df.to_csv(jobs_file_path, index=False) - # #__| - # - # return job_queue_dict - # - # #__| - #__| - - - #| - Create Models Directoy - models_dir = "model_versions" - if not os.path.exists(models_dir): - os.makedirs(models_dir) - - def num_of_files(dir): - num_files = len(os.listdir("model_versions")) - return(num_files) - - lead_cnt = num_of_files("model_versions") - rev_file_path_prev = "model_versions/" + \ - str((lead_cnt)).zfill(2) + "_model.py" - rev_file_path = "model_versions/" + \ - str((lead_cnt + 1)).zfill(2) + "_model.py" - - if num_of_files("model_versions") == 0: - shutil.copyfile("model.py", rev_file_path) - - elif not filecmp.cmp("model.py", rev_file_path_prev): - shutil.copyfile("model.py", rev_file_path) - #__| - - for job in self.job_var_lst: - rev_num = self.job_revision_number(job) - path_i = self.var_lst_to_path(job) + "_" + str(rev_num) - # job_queue_dict = submit_folder_job(path_i, bash_command) - # job_queue_dict = AWS_Queues().submit_job(path=path_i, queue=queue) - - # AWS_Queues().submit_job(path=path_i, queue=queue) - - #__| - - def cancel_jobs(self, state="RUNNABLE"): - """ - Cancel jobs that are in RUNNABLE state. - - Args: - state: - """ - #| - cancel_jobs - jobs_file_path = self.job_queue_dir + "/jobs.csv" - df = pd.read_csv(jobs_file_path) - - df_proj = df[df["job_path"].str.contains(self.root_dir_short)] - - return(df_proj) - #__| - - def update_jobs_queue_file(self): - """ - # COMBAK Set this up. - - TMP - """ - #| - update_jobs_queue_file - tmp = 42 - print(tmp) - #__| - - #__| ********************************************************************** +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Module to carry out common file operations in jobs directory. + +Author: Raul A. Flores +""" + +#| - Import Modules +import os +import sys + +import shutil +import pandas as pd +import filecmp + +import pickle as pickle + +# My Modules +from dft_job_automat.job_analysis import DFT_Jobs_Analysis +# from aws.aws_class import AWS_Queues +#__| + +class DFT_Jobs_Manager(DFT_Jobs_Analysis): + """ + Summary line. + + Manages job submission, resubmission, revision managmnet, job status, etc. + """ + + #| - DFT_Jobs_Manager ***************************************************** + def __init__(self, + tree_level=None, + level_entries=None, + skip_dirs_lst=None, + indiv_dir_lst=None, # <----------------------------------------------- + indiv_job_lst=None, + root_dir=".", + working_dir=".", + update_job_state=False, + load_dataframe=True, + + dataframe_dir=None, + job_type_class=None, + methods_to_run=None, + folders_exist=None, + parse_all_revisions=True, + ): + """Initialize Jobs_Manager instance. + + Args: + tree_level: + level_entries: + skip_dirs_lst: + working_dir: + update_job_state: + load_dataframe: + + TEMP TEMP + """ + #| - __init__ + + #| - __old__ + # tree_level=None, + # level_entries=None, + # skip_dirs_lst=None, + # indiv_dir_lst=None, # <----------------------------------------------- + # indiv_job_lst=None, + # root_dir=".", + # working_dir=".", + # update_job_state=False, + # load_dataframe=True, + # dataframe_dir=dataframe_dir, + # job_type_class=job_type_class, + # methods_to_run=methods_to_run, + # folders_exist=folders_exist, + # parse_all_revisions=parse_all_revisions, + #__| + + DFT_Jobs_Analysis.__init__(self, + tree_level=tree_level, + level_entries=level_entries, + skip_dirs_lst=skip_dirs_lst, + indiv_dir_lst=indiv_dir_lst, + indiv_job_lst=indiv_job_lst, + root_dir=root_dir, + working_dir=working_dir, + update_job_state=update_job_state, + load_dataframe=load_dataframe, + + dataframe_dir=dataframe_dir, + job_type_class=job_type_class, + methods_to_run=methods_to_run, + folders_exist=folders_exist, + parse_all_revisions=parse_all_revisions, + ) + + #| - __old__ + # # system=system, + # tree_level=tree_level, + # level_entries=level_entries, + # working_dir=working_dir, + # update_job_state=update_job_state, + # load_dataframe=load_dataframe, + # dataframe_dir=None, + # job_type_class=None, + # folders_exist=None, + #__| + + #__| + + def restart_job(self, + job_i, + prev_rev_files_list, + root_dir=".", + file_list=None, + sub_params=None, + source_rev=None, + from_simulation_folder=True, + run_job=False, + ): + """ + Restart job from previous revision. + + # TODO | Make copy_if_not_in_dest a global function or something + + Args: + prev_rev_files_list: + file_list: + job_i + """ + #| - restart_job + # FIXME I've defined this in many places. + def copy_if_not_in_dest(source, dest_file): + """ + Copy file from source to destionation. + + Args: + dest_file: + """ + #| - copy_if_not_in_dest + if not os.path.isfile(dest_file): + + shutil.copy(source, dest_file) + source_fle = source.split("/")[-1] + + print("File " + str(source_fle) + " copied") + else: + pass + #__| + + self.create_job_dir(job_i, revision="Auto") + self.copy_files_from_last_revision( + prev_rev_files_list, + job_i, + revisions="Auto", + source_rev=source_rev, + from_simulation_folder=from_simulation_folder, + ) + + if file_list is not None: + source_dir = root_dir + + dest_dir = self.var_lst_to_path( + job_i, + job_rev="Auto", + relative_path=False, + ) + + for file_i in file_list: + #| - Copy Files from Root Dir to New Job Folder + if type(file_i) == str: + copy_if_not_in_dest( + source_dir + "/" + file_i, + dest_dir + "/" + file_i, + ) + + elif type(file_i) == list: + copy_if_not_in_dest( + source_dir + "/" + file_i[0], + dest_dir + "/" + file_i[1], + ) + #__| + + path_i = self.var_lst_to_path( + job_i, + job_rev="Auto", + relative_path=False, + ) + + if sub_params is None: + params_dict = { + "path_i": path_i + } + else: + params_dict = sub_params + params_dict["path_i"] = path_i + + if run_job: + self.submit_job(**params_dict) + else: + pass + #__| + + def copy_files_from_last_revision(self, + files_list, + job_i, + revisions="Auto", + source_rev=None, + from_simulation_folder=True, + ): + """ + Copy files from last revision. + + Args: + revisions: + [source revision, destination revision] + files_list: + job_i: + revisions: + source_rev: + from_simulation_folder: + If system is AWS, decidedes whether the previous jobs' files + are obtained from the /simulation folder or the origial job dir. + """ + #| - copy_files_from_last_revision + + # COMBAK + def copy_if_not_in_dest(source, dest_file): + """ + Copy file from source to destionation. + + Args: + dest_file: + """ + #| - copy_if_not_in_dest + if not os.path.isfile(dest_file): + + shutil.copy(source, dest_file) + source_fle = source.split("/")[-1] + + print("File " + str(source_fle) + " copied") + else: + pass + #__| + + job_path = self.var_lst_to_path( + job_i, + job_rev=False, + relative_path=False, + ) + rev_num = self.job_revision_number(job_i) + + if revisions == "Auto": + rev_dest = rev_num + + if source_rev is not None: + rev_source = source_rev + else: + rev_source = rev_dest - 1 + + else: + rev_dest = revisions[1] + rev_source = revisions[0] + + dest_dir = job_path + "_" + str(rev_dest) + source_dir = job_path + "_" + str(rev_source) + + for file_i in files_list: + + #| - Copy Files to Directory in New Step + + if from_simulation_folder is True: + data_d = self.cluster.cluster.job_data_dir + else: + data_d = "" + + if type(file_i) == str: + copy_if_not_in_dest( + source_dir + data_d + "/" + file_i, + dest_dir + "/" + file_i, + ) + + elif type(file_i) == list: + copy_if_not_in_dest( + source_dir + data_d + "/" + file_i[0], + dest_dir + "/" + file_i[1], + ) + #__| + + #__| + + def submit_job(self, **kwargs): + """Submit job to appropriate cluster. + + Args: + **kwargs: + """ + #| - submit_job + # path_i = kwargs["path_i"] + + self.cluster.submit_job(**kwargs) + #__| + + def remove_rev_folder(self, revision_number): + """Remove revision job folder in all jobs directories. + + Args: + revision_number: + """ + #| - remove_rev_folder + print("Removing job revision folder " + str(revision_number)) + + for job in self.job_var_lst: + path = self.var_lst_to_path(job) + + shutil.rmtree(path + "_" + str(revision_number)) + #__| + + def restart_job_2(self, prev_rev_file_list=[], root_dir_file_list=[]): + """ + Restart jobs - attempt 2. + + Args: + prev_rev_file_list: + root_dir_file_list: + """ + #| - restart_job_2 + for index, row in self.data_frame.iterrows(): + if row["job_state"] == "error": + #| - Body + job = row["variable_list"] + path = row["path"] + rev_n = self.job_revision_number(job) + + first_path = path + "_1" + prev_path = path + "_" + str(rev_n) + new_path = path + "_" + str(rev_n + 1) + + # if stop == True: + # break + # stop = True + + self.create_job_dir(job, revision="Auto") + + for file in prev_rev_file_list: + + if "out.traj" in file: + dest_path = new_path + "/init.traj" + else: + dest_path = new_path + "/" + + try: + shutil.copy(prev_path + "/" + file, dest_path) + except: + shutil.copy(first_path + "/" + file, dest_path) + + + for file in root_dir_file_list: + file_path = self.root_dir + "/" + file + shutil.copy(file_path, new_path + "/") + + os.system("chmod 777 " + new_path + "/*") + + os.chdir(new_path) + print("Submitting Folder: " + new_path) + + bash_command = "$HOME/matr.io/bin/trisub -q medium -c 4" + os.system(bash_command) + + os.chdir(self.root_dir) + #__| + else: + continue + #__| + + def copy_files_jd(self, file_list, variable_lst, revision="Auto"): + """Copy files to job directory. + + Args: + file_list: + variable_lst: + revision: + """ + #| - copy_files_jd + path = self.var_lst_to_path(variable_lst) + path += "_" + str(self.job_revision_number(variable_lst)) + + for file in file_list: + shutil.copyfile(self.root_dir + "/" + file, path + "/" + file) + + #__| + + def create_job_dir(self, variable_lst, revision="Auto"): + """ + Create indiviudal job folders as leaves within the dir tree. + + Args: + variable_lst: + revision: + """ + #| - create_job_dir + path = self.var_lst_to_path( + variable_lst, + job_rev="False", + relative_path=False, + ) + + # print(path) + if revision == "Auto": + rev = self.job_revision_number(variable_lst) + 1 + path += "_" + str(rev) + + if not os.path.exists(path): + print("Creating revision folder " + str(rev)) # PRINT + os.makedirs(path) + + else: + path += "_" + str(revision) + + if not os.path.exists(path): + os.makedirs(path) + + #__| + + # path variable not needed/used DELETE #NOTE + def submit_jobs(self, path=None, queue="medium", copy_PythonModules=True): + """ + Submit all jobs within data folder. + + Submits the most recent version number in each job folder + + 1. Copies the current model.py into the "model_version" folder + 2. Goes through + """ + #| - submit_jobs + + #| - OLD + # def submit_folder_job(folder_dir, bash_command): + # """ + # """ + # #| - submit_folder_job + # + # + # #| - Submtting Job + # try: + # os.chdir(folder_dir) + # + # if os.path.isfile(".SUBMITTED"): + # print("Directory already submitted, will be skipped") + # os.chdir(self.root_dir) + # return(None) + # else: + # print("tmp - submitting job") + # output = subprocess.check_output(bash_command, shell=True) + # # TEMP + # sub_time = datetime.datetime.now().isoformat() + # + # except: + # os.chdir(self.root_dir) + # print("JOB SKIPPED: " + folder_dir) + # return(None) + # #__| + # + # + # #| - Parsing Submission for Job ID + # output = output.splitlines() + # for line in output: + # if "jobId" in line: + # lst = line.split('"') + # job_id_ind = (lst.index("jobId") + 2) + # jobId = lst[job_id_ind] + # + # # This is not necessary anymore + # elif "jobName" in line: + # lst = line.split('"') + # job_name_ind = (lst.index("jobName") + 2) + # jobName = lst[job_name_ind] + # #__| + # + # + # file = open(".submitted", "w") + # file.close() + # + # os.chdir(self.root_dir) + # + # #| - Querying AWS For Job Info + # job_queue_dict = AWS_Queues(jobId).job_info_batch() + # job_queue_dict["submit_time"] = sub_time + # + # jobs_file_path = self.job_queue_dir + "/jobs.csv" + # + # df_new = pd.DataFrame([job_queue_dict]) + # if os.path.isfile(jobs_file_path): + # df = pd.read_csv(jobs_file_path) + # df = df.append(df_new) + # else: + # df = df_new + # + # df.to_csv(jobs_file_path, index=False) + # #__| + # + # return job_queue_dict + # + # #__| + #__| + + + #| - Create Models Directoy + models_dir = "model_versions" + if not os.path.exists(models_dir): + os.makedirs(models_dir) + + def num_of_files(dir): + num_files = len(os.listdir("model_versions")) + return(num_files) + + lead_cnt = num_of_files("model_versions") + rev_file_path_prev = "model_versions/" + \ + str((lead_cnt)).zfill(2) + "_model.py" + rev_file_path = "model_versions/" + \ + str((lead_cnt + 1)).zfill(2) + "_model.py" + + if num_of_files("model_versions") == 0: + shutil.copyfile("model.py", rev_file_path) + + elif not filecmp.cmp("model.py", rev_file_path_prev): + shutil.copyfile("model.py", rev_file_path) + #__| + + for job in self.job_var_lst: + rev_num = self.job_revision_number(job) + path_i = self.var_lst_to_path(job) + "_" + str(rev_num) + # job_queue_dict = submit_folder_job(path_i, bash_command) + # job_queue_dict = AWS_Queues().submit_job(path=path_i, queue=queue) + + # AWS_Queues().submit_job(path=path_i, queue=queue) + + #__| + + def cancel_jobs(self, state="RUNNABLE"): + """ + Cancel jobs that are in RUNNABLE state. + + Args: + state: + """ + #| - cancel_jobs + jobs_file_path = self.job_queue_dir + "/jobs.csv" + df = pd.read_csv(jobs_file_path) + + df_proj = df[df["job_path"].str.contains(self.root_dir_short)] + + return(df_proj) + #__| + + def update_jobs_queue_file(self): + """ + # COMBAK Set this up. + + TMP + """ + #| - update_jobs_queue_file + tmp = 42 + print(tmp) + #__| + + #__| ********************************************************************** diff --git a/dft_job_automat/job_setup.py b/dft_job_automat/job_setup.py index d520d2c..1933989 100644 --- a/dft_job_automat/job_setup.py +++ b/dft_job_automat/job_setup.py @@ -1,1420 +1,1420 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -"""Job automation class. - -Author: Raul A. Flores -""" - -#| - Import Modules -import os -import shutil -import copy - -import itertools -import pickle -import json - -import numpy as np -import pandas as pd - -import ast - -# My Modules -from dft_job_automat.compute_env import ComputerCluster -#__| - - -class Job: - """Encapsulates data and method related to single jobs. - - Still a work in progress - """ - - #| - Job ****************************************************************** - def __init__(self, - path_i=None, - job_params_dict=None, - max_revision=None, - - root_dir=None, - ): - """COMBAK Flesh this out later. - - Args: - path_i: - Path to job folder - job_params_dict: - Job parameter dictionary - max_revision: - Max revisions for unique job, defined by the set of job params - """ - #| - __init__ - - #| - Setting class attributes - self.full_path = path_i - self.job_params_dict = job_params_dict - self.max_revision = max_revision - self.root_dir = root_dir - #__| - - # if job_params_dict is None: - - self.job_params = self.__set_job_parameters__(job_params_dict) - - # print(self.job_params) - # print("____-d-sfs") - # print("") - - # else: - # self.__write_job_parameters__() - - self.revision_number = self.__revision_number__() - #__| - - def write_job_parameters(self): - """ - """ - #| - __write_job_parameters__ - leaf_dir = self.full_path.split("/")[-1] - - if "_" in leaf_dir: - # if leaf_dir[1:].isnumeric(): - if leaf_dir[1:].isdigit(): - leaf_dir = self.full_path.split("/")[-1] - ind_i = self.full_path.rfind(leaf_dir) - path_i = self.full_path[:ind_i - 1] - - - #| - NEW | Trying to remove keys which aren't JSON serializable - def is_jsonable(x): - """ - """ - #| - is_jsonable - try: - json.dumps(x) - return True - except: - return False - #__| - - job_params_dict_cpy = copy.deepcopy(self.job_params_dict) - - keys_to_delete = [] - for key, value in job_params_dict_cpy.items(): - if not is_jsonable(value): - keys_to_delete.append(key) - - if len(keys_to_delete) > 0: - print( - "The following job properties couldn't be JSON serialized", - ", and will be ignored" - ) - print(keys_to_delete) - - for k in keys_to_delete: - job_params_dict_cpy.pop(k, None) - - print(job_params_dict_cpy) - #__| - - - file_path_i = os.path.join(path_i, "job_params.json") - with open(file_path_i, 'w') as outfile: - json.dump( - job_params_dict_cpy, - # self.job_params_dict, - outfile, - indent=2, - ) - #__| - - def __set_job_parameters__(self, job_params_dict): - """ - - Args: - job_params_dict: - """ - #| - __set_job_parameters__ - job_params_from_file = self.__read_job_params_file__() - - if job_params_dict is not None: - # job_params_dict.update(job_params_from_file) - job_params_from_file.update(job_params_dict) - - return(job_params_from_file) - #__| - - def __read_job_params_file__(self): - """Read "job_parameters.json" file from job direcory. - - Development Notes: - Search in the job root dir (one level up from "_" dirs) - - Args: - """ - #| - __read_job_params_file__ - job_params = {} - - # file_path = self.full_path + "/" + "job_parameters.json" - - file_exists = False - - file_path = os.path.join( - self.full_path, - "job_parameters.json") - if os.path.exists(file_path): - file_exists = True - with open(file_path, "r") as fle: - job_params = json.load(fle) - - - ind_i = self.full_path.rfind(self.full_path.split("/")[-1]) - path_i_rt = self.full_path[:ind_i - 1] - - file_path = os.path.join( - # self.full_path[0:-2], - path_i_rt, - "job_parameters.json", - ) - if os.path.exists(file_path): - file_exists = True - with open(file_path, "r") as fle: - job_params = json.load(fle) - - - file_path = os.path.join( - # self.full_path[0:-2], - path_i_rt, - "job_params.json", - ) - if os.path.exists(file_path): - file_exists = True - with open(file_path, "r") as fle: - job_params = json.load(fle) - - if not file_exists: - print("No job_params file found for following job:") - print(self.full_path) - - return(job_params) - #__| - - def __revision_number__(self): - """ - """ - #| - __revision_number__ - # print(self.full_path) - revision_i = int(self.full_path.split("/")[-1].split("_")[-1]) - - return(revision_i) - #__| - - #__| ********************************************************************** - - -class DFT_Jobs_Setup: - """Useful class to set up multiple DFT job in a directory structure. - - Must be initialized with tree_level and level_entries inputs (Not really) - """ - - #| - DFT_Jobs_Setup ******************************************************* - - def __init__(self, - tree_level=None, - level_entries=None, - indiv_dir_lst=None, - indiv_job_lst=None, - indiv_job_dict_lst=None, - skip_dirs_lst=None, - root_dir=".", - working_dir=".", - folders_exist=None, - parse_all_revisions=True, - ): - """Initialize DFT_Jobs_Setup Instance. - - Args: - tree_level: - level_entries: - indiv_dir_lst: - indiv_job_lst: - List of dictionaries representing jobs - skip_dirs_lst: - working_dir: - folders_exist: - """ - #| - __init__ - - #| - Initializing Some Class Attributes - self.order_dict = None - self.job_var_lst = None - self.Job_list = [] - self.sep = "-" - self.level_entries = level_entries - self.tree_level_labels = tree_level - self.level_entries_list = level_entries - self.skip_dirs_lst = skip_dirs_lst - self.indiv_dir_lst = indiv_dir_lst - self.indiv_job_lst = indiv_job_lst - - self.indiv_job_dict_lst = indiv_job_dict_lst - self.parse_all_revisions = parse_all_revisions - #__| - - self.root_dir = self.__set_root_dir__(root_dir) - - self.working_dir = self.__set_working_dir__(working_dir) - - self.cluster = ComputerCluster() - self.jobs_att = self.__load_jobs_attributes__() - self.__create_jobs_bin__() - self.folders_exist = self.__folders_exist__(folders_exist) - - self.load_dir_struct() - self.__create_dir_structure_file__() - self.num_jobs = self.__number_of_jobs__() - self.__Job_list__() - - self.data_frame = self.__gen_datatable__() - - # if self.folders_exist: - # # self.data_frame = self.__generate_data_table__() - - self.check_inputs() - #__| - - def __job_i_param_dict_to_job_var_lst__(self, params_dict): - """Constructs a job_variable list from a dictionary of parameters. - - Args: - params_dict: - """ - #| - __job_i_param_dict_to_job_var_lst__ - assert self.tree_level_labels is not None - - job_var_lst_i = [] - for level_prop in self.tree_level_labels: - level_var_dict = {} - for key_i, value_i in params_dict.items(): - if key_i == level_prop: - level_var_dict["property"] = key_i - level_var_dict["value"] = value_i - - job_var_lst_i.append(level_var_dict) - break - - return(job_var_lst_i) - #__| - - - def write_job_params_json_file(self): - """ - """ - #| - write_job_params_json_file - for Job in self.Job_list: - Job.write_job_parameters() - - #__| - - def create_Jobs_from_dicts_and_paths(self, - jobs_list, - ): - """Populate Job_list attribute manually. - - Args: - jobs_list - List of dictionaries with 'properties' and 'path' keys - - """ - #| - create_Jobs_from_dicts_and_paths - for job_i in jobs_list: - - path_i = job_i["path"] - job_params_dict = job_i["properties"] - - rev_dirs, max_rev = self.__revision_list_and_max__( - path_i, - ) - - for rev_i in rev_dirs: - path_i = os.path.join(path_i, rev_i) - path_i = os.path.normpath(path_i) - - Job_i = Job( - path_i=path_i, - job_params_dict=job_params_dict, - max_revision=max_rev, - root_dir=None, - ) - - self.Job_list.append(Job_i) - #__| - - def __Job_list__(self): - """Create Job list from various input sources.""" - #| - __Job_list__ - - #| - Adding Jobs From Individual Directory List - if self.indiv_dir_lst is not None: - for job_i_dir in self.indiv_dir_lst: - - rev_dirs, max_rev = self.__revision_list_and_max__(job_i_dir) - - print(job_i_dir) - if rev_dirs: - if self.parse_all_revisions is False: - rev_dirs = [rev_dirs[-1]] - - for rev_i in rev_dirs: - path_i = os.path.join(job_i_dir, rev_i) - path_i = os.path.normpath(path_i) - - Job_i = Job( - path_i=path_i, - job_params_dict=None, - max_revision=max_rev, - root_dir=None, - ) - - self.Job_list.append(Job_i) - else: - print("Didn't find any job dirs here:") - print(job_i_dir) - pass - #__| - - #| - Adding Jobs From Enumerated Job Properties Tree - if self.job_var_lst is not None: - for job_i in self.job_var_lst: - job_var_dict = self.__job_i_vars_to_dict__(job_i) - - if self.folders_exist: - path_i = self.var_lst_to_path( - job_i, - job_rev="Auto", - relative_path=False, - ) - - #| - __old__ - # else: - # print("else *s8fs*sdf") - # path_i = os.path.join( - # - # self.var_lst_to_path( - # job_i, - # job_rev="Auto", - # relative_path=False, - # ), - # - # # self.var_lst_to_path( - # # job_i, - # # ), - # - # "_1", - # ) - #__| - - rev_dirs, max_rev = self.__revision_list_and_max__( - # path_i - self.var_lst_to_path( - job_i, - job_rev="None", - relative_path=False, - ) - ) - - Job_i = Job( - path_i=path_i, - job_params_dict=job_var_dict, - max_revision=max_rev, - root_dir=self.root_dir, - ) - - self.Job_list.append(Job_i) - #__| - - #| - TEMP | I don't remember why this is here - indiv_job = self.indiv_job_lst is not None - level_labels = self.tree_level_labels is not None - if indiv_job and level_labels: - print("LSKDJFKLDS_-09sdfsdfs9dfas") - for job_params_i in self.indiv_job_lst: - - job_var_lst_i = self.__job_i_param_dict_to_job_var_lst__( - job_params_i, - ) - - path_i = os.path.join( - self.new_var_lst_to_path(job_var_lst_i), - "_1", - ) - - Job_i = Job( - path_i=path_i, - job_params_dict=job_params_i, - max_revision=None, - root_dir=self.root_dir, - ) - - self.Job_list.append(Job_i) - #__| - - if self.indiv_job_dict_lst is not None: - self.create_Jobs_from_dicts_and_paths( - self.indiv_job_dict_lst, - ) - #__| - - - #| - Misc Methods - - def __job_i_vars_to_dict__(self, job_i_vars): - """ - - Args: - job_i_vars: - """ - #| - __job_i_vars_to_dict__ - job_vars_dict = {} - for prop in job_i_vars: - prop_key = prop["property"] - prop_value = prop["value"] - - job_vars_dict[prop_key] = prop_value - - return(job_vars_dict) - #__| - - def __create_jobs_bin__(self): - """Create /jobs_bin folder if it doesn't exist.""" - #| - __create_jobs_bin__ - folder_dir = os.path.join(self.root_dir, self.working_dir, "jobs_bin") - # folder_dir = self.root_dir + "/jobs_bin" - - if not os.path.exists(folder_dir): - # print("KDJFDI__") - # print(folder_dir) - os.makedirs(folder_dir) - #__| - - def __folders_exist__(self, folders_exist): - """Check whether directory structure exists. - - The alternative is to be creating an instance from a location where - the original job files don't exist but the job dataframe does - """ - #| - __folders_exist__ - # User override - if folders_exist is not None: - return(folders_exist) - - folders_exist = False - - #| - Folders Exist Criteria - crit_0 = False - if os.path.isfile(self.root_dir + "/jobs_bin/.folders_exist"): - crit_0 = True - - crit_1 = False - if os.path.isdir(self.root_dir + "/data"): - crit_1 = True - #__| - - #| - Deciding whether folders exist or not - if crit_0 is True: - pass - if crit_1 is True: - folders_exist = True - else: - folders_exist = False - else: - folders_exist = False - #__| - - return(folders_exist) - #__| - - def __set_root_dir__(self, root_dir_in): - """Returns root directory.""" - #| - __set_root_dir__ - if root_dir_in == ".": - root_dir = os.getcwd() - else: - root_dir = root_dir_in - - return(root_dir) - #__| - - def __set_working_dir__(self, working_dir_in): - """ - """ - #| - __set_working_dir__ - if working_dir_in == ".": - working_dir = "" - else: - working_dir = working_dir_in - - return(working_dir) - #__| - - - def __check_input__(self): - """Check that tree_level and level_entries are of matching length.""" - #| - __check_input__ - tmp = set(self.tree_level_labels) - input_diff = tmp.symmetric_difference(self.level_entries.keys()) - if not input_diff == set(): - undefined_labels = [] - for i in input_diff: - undefined_labels.append(i) - - print("\n") - message = "Did not fill out level entries dict properly" + "\n" - message += "The following properties need to be defined" + "\n" - message += str(undefined_labels) - raise ValueError(message) - #__| - - - def __number_of_jobs__(self): - """Count number of jobs in instance. - - # TODO Should count jobs in job_var_lst and the indiv_dir jobs - # TODO Make distinction between total jobs (including number of - revisions) and just the before revision number - - Depends on number of unique variable list and number of revisions for - each job. - """ - #| - __number_of_jobs__ - num_jobs = 0 - - # Regular jobs - if self.job_var_lst is not None: - num_jobs = len(self.job_var_lst) - - # Individual dir jobs - if self.indiv_dir_lst is not None: - num_jobs += len(self.indiv_dir_lst) - - - return(num_jobs) - #__| - - - def new_var_lst_to_path(self, - variable_lst, - job_rev="False", - relative_path=True, - ): - """ - """ - #| - new_var_lst_to_path - if isinstance(variable_lst, str): - variable_lst = ast.literal_eval(variable_lst) - else: - pass - - level_cnt = 0 - dir_name = "data/" - for level in variable_lst: - level_cnt += 1 - - if self.level_entries is not None: - tmp = self.tree_level_labels[level_cnt - 1] - index = self.level_entries[tmp].index(level["value"]) + 1 - if index < 10: - index = "0" + str(index) - else: - index = str(index) - - beggining = index + self.sep - - else: - index = "" - beggining = index - - #| - REPLACING PERIODS WITH "p" and NEGATIVE SIGNS WITH "n" - # if type(level["value"]) == type(1.23): - if isinstance(level["value"], float): - - # TODO - # NOTE - # Replace the line with the commented out line such that floats - # are rounded in their path representation - - # prop_value = str(round(level["value"], 4)).replace(".", "p") - prop_value = str(level["value"]).replace(".", "p") - - if "-" in str(level["value"]): - prop_value = prop_value.replace("-", "n") - - else: - prop_value = str(level["value"]) - #__| - - dir_name += beggining + prop_value + "/" - - if job_rev == "Auto": - - revision_dirs, highest_rev = self.__revision_list_and_max__( - self.var_lst_to_path(variable_lst), - ) - - dir_name += "_" + str(highest_rev) - - if relative_path is False: - dir_name = os.path.join( - self.root_dir, - self.working_dir, - dir_name, - ) - else: - dir_name = os.path.join( - self.working_dir, - dir_name, - ) - - return(dir_name) - #__| - - def var_lst_to_path(self, - variable_lst, - job_rev="False", - relative_path=True, - ): - """Construct path string from variable list. - - Args: - variable_lst: - Produced from DFT_Jobs_Setup.job_var_lst. - job_rev: - False: - Auto: - """ - #| - var_lst_to_path - if isinstance(variable_lst, str): - variable_lst = ast.literal_eval(variable_lst) - else: - pass - - level_cnt = 0 - dir_name = "data/" - for level in variable_lst: - level_cnt += 1 - tmp = self.tree_level_labels[level_cnt - 1] - index = self.level_entries[tmp].index(level["value"]) + 1 - if index < 10: index = "0" + str(index) - else: index = str(index) - - #| - REPLACING PERIODS WITH "p" and NEGATIVE SIGNS WITH "n" - # if type(level["value"]) == type(1.23): - if isinstance(level["value"], float): - prop_value = str(level["value"]).replace(".", "p") - - if "-" in str(level["value"]): - prop_value = prop_value.replace("-", "n") - - else: - prop_value = str(level["value"]) - #__| - - dir_name += index + self.sep + prop_value + "/" - - # Removing the trailing '/' character - dir_name = dir_name[:-1] - - if job_rev == "Auto": - - revision_dirs, highest_rev = self.__revision_list_and_max__( - self.var_lst_to_path( - variable_lst, - job_rev="False", - relative_path=False, - ), - ) - - # dir_name += "_" + str(highest_rev) - dir_name += "/_" + str(highest_rev) - - if relative_path is False: - dir_name = os.path.join( - self.root_dir, - self.working_dir, - dir_name, - ) - - return(dir_name) - #__| - - def extract_prop_from_var_lst(self, variable_lst, property): - """Extract the property from the variable list. - - Args: - variable_lst: - property: - """ - #| - extract_prop_from_var_lst - # result = {} - for i in variable_lst: - if i["property"] == property: - return i["value"] - #__| - - - #__| - - - #| - Job Variable Tree Methods - - def load_dir_struct(self): - """Attempt to load dir structure from file in root dir if none given. - - job_var_lst is constructed - level_entries_list is constructed - level_entries is constructed - order_dict is constructed - - """ - #| - load_dir_struct - if self.tree_level_labels is None and self.level_entries is None: - self.__load_dir_structure_file__() - - # self.__check_input__() # TEMP had to comment out because of switching - # to new format of input files - - #| - If tree_level_labels and level_entries couldn't be parsed - if self.tree_level_labels is None and self.level_entries is None: - return(None) - #__| - - # FIXME - # if not type(self.level_entries) == list: - # # self.level_entries_list = self.__level_entries_list__() - # level_entries_list = self.__level_entries_list__() - - if type(self.level_entries) == dict: - #| - OLD way - self.order_dict = self.__order_dict__( - self.tree_level_labels, - self.level_entries) - - self.job_var_lst = self.__job_variable_list__( - # self.level_entries_list, - level_entries_list, - self.order_dict) - #__| - - elif type(self.level_entries) == list: - #| - New Way of Inputing Structure Files - tmp = self.__create_level_entries_dict__( - self.tree_level_labels, - self.level_entries, - ) - self.level_entries = tmp - - - self.level_entries_list = self.__level_entries_list__() - - - self.order_dict = self.__order_dict__( - self.tree_level_labels, - self.level_entries) - - self.job_var_lst = self.__job_variable_list__( - # self.level_entries, - self.level_entries_list, - # level_entries_list, - self.order_dict, - ) - #__| - - #__| - - def __load_dir_structure_file__(self): - """Attempt o load dir_structure.json from file.""" - #| - __load_dir_structure_file__ - try: - try: - fle_name = self.root_dir + "/jobs_bin/dir_structure.json" - - with open(fle_name, "r") as dir_struct_f: - data = json.load(dir_struct_f) - - tree_level = data["tree_level_labels"] - level_entries = data["level_entries_dict"] - - if "skip_dirs" in data.keys(): - skip_dirs_lst = data["skip_dirs"] - self.skip_dirs_lst = skip_dirs_lst - - self.tree_level_labels = tree_level - self.level_entries = level_entries - self.level_entries_list = level_entries - - except: - print("Couldn't read /jobs_bin/dir_structure.json") - - try: - - #| - __old__ - tmp = 42 - # print("old - Reading dir_structure.json file \ - # from root_dir") - # - # fle_name = self.root_dir + "/dir_structure.json" - # with open(fle_name, "r") as dir_struct_f: - # data = json.load(dir_struct_f) - # tree_level = data["tree_level_labels"] - # level_entries = data["level_entries_dict"] - # - # if "skip_dirs" in data.keys(): - # skip_dirs_lst = data["skip_dirs"] - # self.skip_dirs_lst = skip_dirs_lst - # - # self.tree_level_labels = tree_level - # self.level_entries = level_entries - #__| - - except: - print("Couldn't read /dir_structure.json") - - pass - - except: - mess = "Error opening 'dir_structure.json' file" - raise IOError(mess) - - #__| - - def __create_level_entries_dict__(self, - tree_level_labels, - tree_level_values, - ): - """ - Create level_entries_dict from labels and values lists. - - Args: - tree_level_labels: - tree_level_values: - """ - #| - create_level_entries_dict - level_entries_dict = {} - for index, variable in enumerate(tree_level_labels): - level_entries_dict[variable] = tree_level_values[index] - - return(level_entries_dict) - #__| - - def __level_entries_list__(self): - """Construct level entries list. - - Construct level_entries_list from level_entries_dict and level_labels - """ - #| - __level_entries_list__ - level_entries_dict = self.level_entries - level_labels = self.tree_level_labels - - level_entries_list = [] - for param_i in level_labels: - # for name, params_list in level_entries_dict.iteritems(): - for name, params_list in level_entries_dict.items(): - if param_i == name: - level_entries_list.append(params_list) - - return(level_entries_list) - #__| - - def __order_dict__(self, tree_level_labels, level_entries): - """Order of properties to correspond to order of tree. - - Creates "order_dict", which contains the depth level for each - descriptor. Each job directory will have a unique descriptor list. - The "order_dict" variable is used to make sure that the ordering of the - descriptors in this list matches the "dir_tree_level" structure. - - Args: - tree_level_labels: - level_entries: - """ - #| - __order_dict__ - order_dict = {} # <-------------------------------------- - - level_cnt = 0 - for level in tree_level_labels: - level_cnt += 1 - for prop in level_entries[level]: - order_dict[prop] = level_cnt - 1 - - return order_dict - - #__| - - def __job_variable_list__(self, level_entries, order_dict): - """Return the job variable list. - - Args: - level_entries: - order_dict: - """ - #| - __job_variable_list__ - all_comb = itertools.product(*level_entries) - - job_dir_lst = [] - for job_dir in all_comb: - final_lst_2 = [] - param_names = self.tree_level_labels - - for ind, prop in enumerate(job_dir): - new_entry = {} - new_entry["property"] = param_names[ind] - new_entry["value"] = job_dir[ind] - final_lst_2.append(new_entry) - - job_dir_lst.append(final_lst_2) - - if self.skip_dirs_lst is not None: - for skip in self.skip_dirs_lst: - job_dir_lst.remove(skip) - - return(job_dir_lst) - #__| - - #__| - - - #| - Create Directory Tree - - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - # NEW - def create_dir_struct(self, create_first_rev_folder="True"): - """Create directory structure according to job variable list & dict. - - Development Notes: - This should really be looping over the jobs_list I think - - Args: - create_first_rev_folder: - """ - #| - create_dir_struct - for Job_i in self.Job_list: - - #| - FOR LOOP BODY - # if create_first_rev_folder == "True": - # path = os.path.join(Job_i.full_path, "_1") - # elif create_first_rev_folder == "False": - # path = Job_i.full_path - - path = Job_i.full_path - - if os.path.exists(path): - # mess = "Path already exists: " + str(path) - # print(mess) - pass - - elif not os.path.exists(path): - os.makedirs(path) - #__| - - #| - folders_exist attribute should be True from now on - # file_name = self.root_dir + "/jobs_bin/.folders_exist" - file_name = os.path.join( - self.root_dir, - self.working_dir, - "jobs_bin/.folders_exist" - ) - - with open(file_name, "w") as fle: - fle.write("\n") - - self.folders_exist = self.__folders_exist__(True) - #__| - - #__| - - def old_create_dir_struct(self, create_first_rev_folder="True"): - """Create directory structure according to job variable list & dict. - - Development Notes: - This should really be looping over the jobs_list I think - - Args: - create_first_rev_folder: - """ - #| - create_dir_struct - for job in self.job_var_lst: - if create_first_rev_folder == "True": - path = self.var_lst_to_path(job) + "_1" - elif create_first_rev_folder == "False": - path = self.var_lst_to_path(job) - - path = self.root_dir + "/" + path - - if os.path.exists(path): - mess = "Path already exists: " + str(path) - print(mess) - - elif not os.path.exists(path): - os.makedirs(path) - - #| - Creating Variable Text Files Through Directoy Structure - for job in self.job_var_lst: - path = self.var_lst_to_path(job) - path = self.root_dir + "/" + path - - file_name = path + "job_dir_level" - with open(file_name, "w") as fle: - fle.write("\n") - - for root, dirs, files in os.walk(self.root_dir + "/data/"): - if "job_dir_level" in files: - continue - - else: - prop_lst = [] - for folder in dirs: - tmp = self.sep.join(folder.split(self.sep)[1:]) - - prop = self.__replace_p_for_per__(tmp) - prop = self.__replace_negative_for_n__(prop) - prop_lst.append(prop) - - for key, value in self.level_entries.items(): - if set(prop_lst) == set(map(str, value)): - - file_name = root + "/properties.txt" - with open(file_name, "w") as fle: - fle.write(key + "\n") - - # f = open(root + "/properties.txt", "w") - # f.write(key + "\n") - # f.close() - #__| - - # self.__create_dir_structure_file__() - - #| - folders_exist attribute should be True from now on - file_name = self.root_dir + "/jobs_bin/.folders_exist" - with open(file_name, "w") as fle: - fle.write("\n") - - self.folders_exist = self.__folders_exist__(True) - #__| - - #__| - - - - - - - - - - - - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - - - - - - - - def check_inputs(self): - """ - """ - #| - check_inputs - if self.tree_level_labels is not None: - assert isinstance(self.tree_level_labels[0], np.ndarray) is False, \ - "Please don't use numpy array types, can't be json serialized" - - if self.level_entries_list is not None: - assert isinstance(self.level_entries_list[0], np.ndarray) is False, \ - "Please don't use numpy array types, can't be json serialized" - #__| - - def __create_dir_structure_file__(self): - """ - Create directory structure file. - - Creates dir structure file from which the parameter list & dict can be - loaded from. - """ - #| - __create_dir_structure_file__ - - dir_structure_data = {} - dir_structure_data["tree_level_labels"] = self.tree_level_labels - dir_structure_data["level_entries_dict"] = self.level_entries_list - # TEMP - dir_structure_data["skip_dirs"] = self.skip_dirs_lst - - fle_name = os.path.join( - self.root_dir, - self.working_dir, - "jobs_bin/dir_structure.json", - ) - - with open(fle_name, "w") as fle: - json.dump(dir_structure_data, fle, indent=2) - #__| - - def __replace_p_for_per__(self, text): - """Replace p in variable with "." character. - - TODO Fails if last letter is a "p" - - Variables with "." character had them previously replaced with a "p" - character to avoid periods in a folder name. - """ - #| - __replace_p_for_per__ - lst = [pos for pos, char in enumerate(text) if char == "p"] - - # Replaces character at lett with a period if both the previous - # and next character are numeric - for lett in lst: - - # COMBAK - # Skip entries which have p at end of text - # Ignores possibility of variables like the following: - # 2. --> 2p (will not go back to 2.) - if lett == len(text) - 1: - continue - - cond_1 = text[lett - 1].isdigit() - cond_2 = text[lett + 1].isdigit() - if cond_1 is True and cond_2 is True: - text = text[:lett] + "." + text[lett + 1:] - - return(text) - #__| - - def __replace_negative_for_n__(self, text): - """Replace variable quantities that are negative with an "n". - - Args: - text: - """ - #| - __replace_negative_for_n__ - lst = [pos for pos, char in enumerate(text) if char == "n"] - - for lett in lst: - if text[lett + 1].isdigit() is True: - text = text[:lett] + "-" + text[lett + 1:] - - return(text) - #__| - - #__| - - - #| - Job Attributes - - def __load_jobs_attributes__(self): - """Load jobs attributes data from file.""" - #| - __load_jobs_attributes__ - job_att_file = self.root_dir + "/jobs_bin/job_attributes.csv" - - if os.path.exists(job_att_file): - with open(job_att_file, "rb") as fle: - jobs_att = pickle.load(fle) - - else: - jobs_att = {} - - return(jobs_att) - #__| - - def append_jobs_attributes(self, attribute): - """ - Append to jobs attributes file. - - Append dictionary key value pair to the jobs_attributes dict. - To be pickled and saved - """ - #| - append_jobs_attributes - att_new = attribute - - self.jobs_att.update(att_new) - - job_att_file = self.root_dir + "/jobs_bin/job_attributes.csv" - pickle.dump(self.jobs_att, open(job_att_file, "wb")) - #__| - - #__| - - def __gen_datatable__(self): - """Initialze data table from the properties of the jobs directory. - - New methods iterates through Job instances - """ - #| - __generate_data_table - rows_list = [] - for Job_i in self.Job_list: - #| - FOR LOOP BODY - entry_param_dict = {} - for prop, value in Job_i.job_params.items(): - entry_param_dict[prop] = value - - entry_param_dict["Job"] = Job_i - entry_param_dict["path"] = Job_i.full_path - entry_param_dict["max_revision"] = Job_i.max_revision - entry_param_dict["revision_number"] = Job_i.revision_number - - rows_list.append(entry_param_dict) - #__| - - data_frame = pd.DataFrame(rows_list) - - return(data_frame) - #__| - - def __revision_list_and_max__(self, path_i): - """Return list of revisions for given job path and highest revision. - - If there are no revision folders or the directory structure hasn't been - created yet the following dummy values will be returned: - ( - ["_1"], - 1, - ) - - Args: - path_i: - """ - #| - __revision_list_and_max__ - if self.folders_exist: - - # dirs = os.listdir(os.path.join(self.working_dir, path_i)) - dirs = os.listdir(path_i) - - revision_dirs = [dir for dir in dirs if dir[0] == "_" and - dir[-1].isdigit() and " " not in dir] - - # dir[1].isdigit() and " " not in dir] - - revision_dirs.sort() - - if len(revision_dirs) == 0: - highest_rev = None - else: - highest_rev = max( - [int(i.split("_")[-1]) for i in revision_dirs], - ) - - return(revision_dirs, highest_rev) - else: - dummy_return = ( - ["_1"], - 1, - ) - - return(dummy_return) - #__| - - def copy_files_jd(self, file_list, variable_lst, revision="Auto"): - """ - Copy files to job directory. - - Args: - file_list: - variable_lst: - revision: - """ - #| - copy_files_jd - path = self.var_lst_to_path(variable_lst) - path += "_" + str(self.job_revision_number(variable_lst)) - - for file in file_list: - shutil.copyfile(self.root_dir + "/" + file, path + "/" + file) - #__| - - - #__| ********************************************************************** - - - - #| - __old__ - # DEPR - def __generate_data_table__(self): - """Initialze data table from the properties of the jobs directory. - - Appends unique row for every job revision - """ - #| - __generate_data_table__ - rows_list = [] - for job in self.job_var_lst: - revisions = self.job_revision_number(job) - for revision in range(revisions + 1)[1:]: - #| - FOR LOOP BODY - entry_param_dict = {} - for prop in job: - entry_param_dict[prop["property"]] = prop["value"] - - entry_param_dict["variable_list"] = job - entry_param_dict["path"] = self.var_lst_to_path(job) - - entry_param_dict["max_revision"] = revisions - entry_param_dict["revision_number"] = revision - - rows_list.append(entry_param_dict) - #__| - - data_frame = pd.DataFrame(rows_list) - - return(data_frame) - #__| - - # DEPR - def job_revision_number_old(self, variable_lst): - """ - Return the largest revision number for the given variable_lst -> job. - - If there are no revision folders or the directory structure hasn't been - created yet 1 will be returned. - - Args: - variable_lst: - """ - #| - job_revision_number - if self.folders_exist: - path = self.var_lst_to_path(variable_lst) - orig_dir = os.getcwd() - os.chdir(self.root_dir + "/" + path) - - dirs = filter(os.path.isdir, os.listdir(os.getcwd())) - - - # COMBAK Does this line break work? - num_jobs = len([dir for dir in dirs if dir[0] == "_" and - dir[1].isdigit() and " " not in dir]) - os.chdir(orig_dir) - - return(num_jobs) - else: - return(1) - - #| - __old__ - # path = self.var_lst_to_path(variable_lst) - # - # path = "/".join(path.split("/")[0:-1]) + "/" - # # Attempting to remove duplicate job folders (usually have spaces) - # dir_list = [x for x in os.walk(path).next()[1] if " " not in x] - # - # return(len(dir_list)) - # - #__| - - #__| - - - #__| +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Job automation class. + +Author: Raul A. Flores +""" + +#| - Import Modules +import os +import shutil +import copy + +import itertools +import pickle +import json + +import numpy as np +import pandas as pd + +import ast + +# My Modules +from dft_job_automat.compute_env import ComputerCluster +#__| + + +class Job: + """Encapsulates data and method related to single jobs. + + Still a work in progress + """ + + #| - Job ****************************************************************** + def __init__(self, + path_i=None, + job_params_dict=None, + max_revision=None, + + root_dir=None, + ): + """COMBAK Flesh this out later. + + Args: + path_i: + Path to job folder + job_params_dict: + Job parameter dictionary + max_revision: + Max revisions for unique job, defined by the set of job params + """ + #| - __init__ + + #| - Setting class attributes + self.full_path = path_i + self.job_params_dict = job_params_dict + self.max_revision = max_revision + self.root_dir = root_dir + #__| + + # if job_params_dict is None: + + self.job_params = self.__set_job_parameters__(job_params_dict) + + # print(self.job_params) + # print("____-d-sfs") + # print("") + + # else: + # self.__write_job_parameters__() + + self.revision_number = self.__revision_number__() + #__| + + def write_job_parameters(self): + """ + """ + #| - __write_job_parameters__ + leaf_dir = self.full_path.split("/")[-1] + + if "_" in leaf_dir: + # if leaf_dir[1:].isnumeric(): + if leaf_dir[1:].isdigit(): + leaf_dir = self.full_path.split("/")[-1] + ind_i = self.full_path.rfind(leaf_dir) + path_i = self.full_path[:ind_i - 1] + + + #| - NEW | Trying to remove keys which aren't JSON serializable + def is_jsonable(x): + """ + """ + #| - is_jsonable + try: + json.dumps(x) + return True + except: + return False + #__| + + job_params_dict_cpy = copy.deepcopy(self.job_params_dict) + + keys_to_delete = [] + for key, value in job_params_dict_cpy.items(): + if not is_jsonable(value): + keys_to_delete.append(key) + + if len(keys_to_delete) > 0: + print( + "The following job properties couldn't be JSON serialized", + ", and will be ignored" + ) + print(keys_to_delete) + + for k in keys_to_delete: + job_params_dict_cpy.pop(k, None) + + print(job_params_dict_cpy) + #__| + + + file_path_i = os.path.join(path_i, "job_params.json") + with open(file_path_i, 'w') as outfile: + json.dump( + job_params_dict_cpy, + # self.job_params_dict, + outfile, + indent=2, + ) + #__| + + def __set_job_parameters__(self, job_params_dict): + """ + + Args: + job_params_dict: + """ + #| - __set_job_parameters__ + job_params_from_file = self.__read_job_params_file__() + + if job_params_dict is not None: + # job_params_dict.update(job_params_from_file) + job_params_from_file.update(job_params_dict) + + return(job_params_from_file) + #__| + + def __read_job_params_file__(self): + """Read "job_parameters.json" file from job direcory. + + Development Notes: + Search in the job root dir (one level up from "_" dirs) + + Args: + """ + #| - __read_job_params_file__ + job_params = {} + + # file_path = self.full_path + "/" + "job_parameters.json" + + file_exists = False + + file_path = os.path.join( + self.full_path, + "job_parameters.json") + if os.path.exists(file_path): + file_exists = True + with open(file_path, "r") as fle: + job_params = json.load(fle) + + + ind_i = self.full_path.rfind(self.full_path.split("/")[-1]) + path_i_rt = self.full_path[:ind_i - 1] + + file_path = os.path.join( + # self.full_path[0:-2], + path_i_rt, + "job_parameters.json", + ) + if os.path.exists(file_path): + file_exists = True + with open(file_path, "r") as fle: + job_params = json.load(fle) + + + file_path = os.path.join( + # self.full_path[0:-2], + path_i_rt, + "job_params.json", + ) + if os.path.exists(file_path): + file_exists = True + with open(file_path, "r") as fle: + job_params = json.load(fle) + + if not file_exists: + print("No job_params file found for following job:") + print(self.full_path) + + return(job_params) + #__| + + def __revision_number__(self): + """ + """ + #| - __revision_number__ + # print(self.full_path) + revision_i = int(self.full_path.split("/")[-1].split("_")[-1]) + + return(revision_i) + #__| + + #__| ********************************************************************** + + +class DFT_Jobs_Setup: + """Useful class to set up multiple DFT job in a directory structure. + + Must be initialized with tree_level and level_entries inputs (Not really) + """ + + #| - DFT_Jobs_Setup ******************************************************* + + def __init__(self, + tree_level=None, + level_entries=None, + indiv_dir_lst=None, + indiv_job_lst=None, + indiv_job_dict_lst=None, + skip_dirs_lst=None, + root_dir=".", + working_dir=".", + folders_exist=None, + parse_all_revisions=True, + ): + """Initialize DFT_Jobs_Setup Instance. + + Args: + tree_level: + level_entries: + indiv_dir_lst: + indiv_job_lst: + List of dictionaries representing jobs + skip_dirs_lst: + working_dir: + folders_exist: + """ + #| - __init__ + + #| - Initializing Some Class Attributes + self.order_dict = None + self.job_var_lst = None + self.Job_list = [] + self.sep = "-" + self.level_entries = level_entries + self.tree_level_labels = tree_level + self.level_entries_list = level_entries + self.skip_dirs_lst = skip_dirs_lst + self.indiv_dir_lst = indiv_dir_lst + self.indiv_job_lst = indiv_job_lst + + self.indiv_job_dict_lst = indiv_job_dict_lst + self.parse_all_revisions = parse_all_revisions + #__| + + self.root_dir = self.__set_root_dir__(root_dir) + + self.working_dir = self.__set_working_dir__(working_dir) + + self.cluster = ComputerCluster() + self.jobs_att = self.__load_jobs_attributes__() + self.__create_jobs_bin__() + self.folders_exist = self.__folders_exist__(folders_exist) + + self.load_dir_struct() + self.__create_dir_structure_file__() + self.num_jobs = self.__number_of_jobs__() + self.__Job_list__() + + self.data_frame = self.__gen_datatable__() + + # if self.folders_exist: + # # self.data_frame = self.__generate_data_table__() + + self.check_inputs() + #__| + + def __job_i_param_dict_to_job_var_lst__(self, params_dict): + """Constructs a job_variable list from a dictionary of parameters. + + Args: + params_dict: + """ + #| - __job_i_param_dict_to_job_var_lst__ + assert self.tree_level_labels is not None + + job_var_lst_i = [] + for level_prop in self.tree_level_labels: + level_var_dict = {} + for key_i, value_i in params_dict.items(): + if key_i == level_prop: + level_var_dict["property"] = key_i + level_var_dict["value"] = value_i + + job_var_lst_i.append(level_var_dict) + break + + return(job_var_lst_i) + #__| + + + def write_job_params_json_file(self): + """ + """ + #| - write_job_params_json_file + for Job in self.Job_list: + Job.write_job_parameters() + + #__| + + def create_Jobs_from_dicts_and_paths(self, + jobs_list, + ): + """Populate Job_list attribute manually. + + Args: + jobs_list + List of dictionaries with 'properties' and 'path' keys + + """ + #| - create_Jobs_from_dicts_and_paths + for job_i in jobs_list: + + path_i = job_i["path"] + job_params_dict = job_i["properties"] + + rev_dirs, max_rev = self.__revision_list_and_max__( + path_i, + ) + + for rev_i in rev_dirs: + path_i = os.path.join(path_i, rev_i) + path_i = os.path.normpath(path_i) + + Job_i = Job( + path_i=path_i, + job_params_dict=job_params_dict, + max_revision=max_rev, + root_dir=None, + ) + + self.Job_list.append(Job_i) + #__| + + def __Job_list__(self): + """Create Job list from various input sources.""" + #| - __Job_list__ + + #| - Adding Jobs From Individual Directory List + if self.indiv_dir_lst is not None: + for job_i_dir in self.indiv_dir_lst: + + rev_dirs, max_rev = self.__revision_list_and_max__(job_i_dir) + + print(job_i_dir) + if rev_dirs: + if self.parse_all_revisions is False: + rev_dirs = [rev_dirs[-1]] + + for rev_i in rev_dirs: + path_i = os.path.join(job_i_dir, rev_i) + path_i = os.path.normpath(path_i) + + Job_i = Job( + path_i=path_i, + job_params_dict=None, + max_revision=max_rev, + root_dir=None, + ) + + self.Job_list.append(Job_i) + else: + print("Didn't find any job dirs here:") + print(job_i_dir) + pass + #__| + + #| - Adding Jobs From Enumerated Job Properties Tree + if self.job_var_lst is not None: + for job_i in self.job_var_lst: + job_var_dict = self.__job_i_vars_to_dict__(job_i) + + if self.folders_exist: + path_i = self.var_lst_to_path( + job_i, + job_rev="Auto", + relative_path=False, + ) + + #| - __old__ + # else: + # print("else *s8fs*sdf") + # path_i = os.path.join( + # + # self.var_lst_to_path( + # job_i, + # job_rev="Auto", + # relative_path=False, + # ), + # + # # self.var_lst_to_path( + # # job_i, + # # ), + # + # "_1", + # ) + #__| + + rev_dirs, max_rev = self.__revision_list_and_max__( + # path_i + self.var_lst_to_path( + job_i, + job_rev="None", + relative_path=False, + ) + ) + + Job_i = Job( + path_i=path_i, + job_params_dict=job_var_dict, + max_revision=max_rev, + root_dir=self.root_dir, + ) + + self.Job_list.append(Job_i) + #__| + + #| - TEMP | I don't remember why this is here + indiv_job = self.indiv_job_lst is not None + level_labels = self.tree_level_labels is not None + if indiv_job and level_labels: + print("LSKDJFKLDS_-09sdfsdfs9dfas") + for job_params_i in self.indiv_job_lst: + + job_var_lst_i = self.__job_i_param_dict_to_job_var_lst__( + job_params_i, + ) + + path_i = os.path.join( + self.new_var_lst_to_path(job_var_lst_i), + "_1", + ) + + Job_i = Job( + path_i=path_i, + job_params_dict=job_params_i, + max_revision=None, + root_dir=self.root_dir, + ) + + self.Job_list.append(Job_i) + #__| + + if self.indiv_job_dict_lst is not None: + self.create_Jobs_from_dicts_and_paths( + self.indiv_job_dict_lst, + ) + #__| + + + #| - Misc Methods + + def __job_i_vars_to_dict__(self, job_i_vars): + """ + + Args: + job_i_vars: + """ + #| - __job_i_vars_to_dict__ + job_vars_dict = {} + for prop in job_i_vars: + prop_key = prop["property"] + prop_value = prop["value"] + + job_vars_dict[prop_key] = prop_value + + return(job_vars_dict) + #__| + + def __create_jobs_bin__(self): + """Create /jobs_bin folder if it doesn't exist.""" + #| - __create_jobs_bin__ + folder_dir = os.path.join(self.root_dir, self.working_dir, "jobs_bin") + # folder_dir = self.root_dir + "/jobs_bin" + + if not os.path.exists(folder_dir): + # print("KDJFDI__") + # print(folder_dir) + os.makedirs(folder_dir) + #__| + + def __folders_exist__(self, folders_exist): + """Check whether directory structure exists. + + The alternative is to be creating an instance from a location where + the original job files don't exist but the job dataframe does + """ + #| - __folders_exist__ + # User override + if folders_exist is not None: + return(folders_exist) + + folders_exist = False + + #| - Folders Exist Criteria + crit_0 = False + if os.path.isfile(self.root_dir + "/jobs_bin/.folders_exist"): + crit_0 = True + + crit_1 = False + if os.path.isdir(self.root_dir + "/data"): + crit_1 = True + #__| + + #| - Deciding whether folders exist or not + if crit_0 is True: + pass + if crit_1 is True: + folders_exist = True + else: + folders_exist = False + else: + folders_exist = False + #__| + + return(folders_exist) + #__| + + def __set_root_dir__(self, root_dir_in): + """Returns root directory.""" + #| - __set_root_dir__ + if root_dir_in == ".": + root_dir = os.getcwd() + else: + root_dir = root_dir_in + + return(root_dir) + #__| + + def __set_working_dir__(self, working_dir_in): + """ + """ + #| - __set_working_dir__ + if working_dir_in == ".": + working_dir = "" + else: + working_dir = working_dir_in + + return(working_dir) + #__| + + + def __check_input__(self): + """Check that tree_level and level_entries are of matching length.""" + #| - __check_input__ + tmp = set(self.tree_level_labels) + input_diff = tmp.symmetric_difference(self.level_entries.keys()) + if not input_diff == set(): + undefined_labels = [] + for i in input_diff: + undefined_labels.append(i) + + print("\n") + message = "Did not fill out level entries dict properly" + "\n" + message += "The following properties need to be defined" + "\n" + message += str(undefined_labels) + raise ValueError(message) + #__| + + + def __number_of_jobs__(self): + """Count number of jobs in instance. + + # TODO Should count jobs in job_var_lst and the indiv_dir jobs + # TODO Make distinction between total jobs (including number of + revisions) and just the before revision number + + Depends on number of unique variable list and number of revisions for + each job. + """ + #| - __number_of_jobs__ + num_jobs = 0 + + # Regular jobs + if self.job_var_lst is not None: + num_jobs = len(self.job_var_lst) + + # Individual dir jobs + if self.indiv_dir_lst is not None: + num_jobs += len(self.indiv_dir_lst) + + + return(num_jobs) + #__| + + + def new_var_lst_to_path(self, + variable_lst, + job_rev="False", + relative_path=True, + ): + """ + """ + #| - new_var_lst_to_path + if isinstance(variable_lst, str): + variable_lst = ast.literal_eval(variable_lst) + else: + pass + + level_cnt = 0 + dir_name = "data/" + for level in variable_lst: + level_cnt += 1 + + if self.level_entries is not None: + tmp = self.tree_level_labels[level_cnt - 1] + index = self.level_entries[tmp].index(level["value"]) + 1 + if index < 10: + index = "0" + str(index) + else: + index = str(index) + + beggining = index + self.sep + + else: + index = "" + beggining = index + + #| - REPLACING PERIODS WITH "p" and NEGATIVE SIGNS WITH "n" + # if type(level["value"]) == type(1.23): + if isinstance(level["value"], float): + + # TODO + # NOTE + # Replace the line with the commented out line such that floats + # are rounded in their path representation + + # prop_value = str(round(level["value"], 4)).replace(".", "p") + prop_value = str(level["value"]).replace(".", "p") + + if "-" in str(level["value"]): + prop_value = prop_value.replace("-", "n") + + else: + prop_value = str(level["value"]) + #__| + + dir_name += beggining + prop_value + "/" + + if job_rev == "Auto": + + revision_dirs, highest_rev = self.__revision_list_and_max__( + self.var_lst_to_path(variable_lst), + ) + + dir_name += "_" + str(highest_rev) + + if relative_path is False: + dir_name = os.path.join( + self.root_dir, + self.working_dir, + dir_name, + ) + else: + dir_name = os.path.join( + self.working_dir, + dir_name, + ) + + return(dir_name) + #__| + + def var_lst_to_path(self, + variable_lst, + job_rev="False", + relative_path=True, + ): + """Construct path string from variable list. + + Args: + variable_lst: + Produced from DFT_Jobs_Setup.job_var_lst. + job_rev: + False: + Auto: + """ + #| - var_lst_to_path + if isinstance(variable_lst, str): + variable_lst = ast.literal_eval(variable_lst) + else: + pass + + level_cnt = 0 + dir_name = "data/" + for level in variable_lst: + level_cnt += 1 + tmp = self.tree_level_labels[level_cnt - 1] + index = self.level_entries[tmp].index(level["value"]) + 1 + if index < 10: index = "0" + str(index) + else: index = str(index) + + #| - REPLACING PERIODS WITH "p" and NEGATIVE SIGNS WITH "n" + # if type(level["value"]) == type(1.23): + if isinstance(level["value"], float): + prop_value = str(level["value"]).replace(".", "p") + + if "-" in str(level["value"]): + prop_value = prop_value.replace("-", "n") + + else: + prop_value = str(level["value"]) + #__| + + dir_name += index + self.sep + prop_value + "/" + + # Removing the trailing '/' character + dir_name = dir_name[:-1] + + if job_rev == "Auto": + + revision_dirs, highest_rev = self.__revision_list_and_max__( + self.var_lst_to_path( + variable_lst, + job_rev="False", + relative_path=False, + ), + ) + + # dir_name += "_" + str(highest_rev) + dir_name += "/_" + str(highest_rev) + + if relative_path is False: + dir_name = os.path.join( + self.root_dir, + self.working_dir, + dir_name, + ) + + return(dir_name) + #__| + + def extract_prop_from_var_lst(self, variable_lst, property): + """Extract the property from the variable list. + + Args: + variable_lst: + property: + """ + #| - extract_prop_from_var_lst + # result = {} + for i in variable_lst: + if i["property"] == property: + return i["value"] + #__| + + + #__| + + + #| - Job Variable Tree Methods + + def load_dir_struct(self): + """Attempt to load dir structure from file in root dir if none given. + + job_var_lst is constructed + level_entries_list is constructed + level_entries is constructed + order_dict is constructed + + """ + #| - load_dir_struct + if self.tree_level_labels is None and self.level_entries is None: + self.__load_dir_structure_file__() + + # self.__check_input__() # TEMP had to comment out because of switching + # to new format of input files + + #| - If tree_level_labels and level_entries couldn't be parsed + if self.tree_level_labels is None and self.level_entries is None: + return(None) + #__| + + # FIXME + # if not type(self.level_entries) == list: + # # self.level_entries_list = self.__level_entries_list__() + # level_entries_list = self.__level_entries_list__() + + if type(self.level_entries) == dict: + #| - OLD way + self.order_dict = self.__order_dict__( + self.tree_level_labels, + self.level_entries) + + self.job_var_lst = self.__job_variable_list__( + # self.level_entries_list, + level_entries_list, + self.order_dict) + #__| + + elif type(self.level_entries) == list: + #| - New Way of Inputing Structure Files + tmp = self.__create_level_entries_dict__( + self.tree_level_labels, + self.level_entries, + ) + self.level_entries = tmp + + + self.level_entries_list = self.__level_entries_list__() + + + self.order_dict = self.__order_dict__( + self.tree_level_labels, + self.level_entries) + + self.job_var_lst = self.__job_variable_list__( + # self.level_entries, + self.level_entries_list, + # level_entries_list, + self.order_dict, + ) + #__| + + #__| + + def __load_dir_structure_file__(self): + """Attempt o load dir_structure.json from file.""" + #| - __load_dir_structure_file__ + try: + try: + fle_name = self.root_dir + "/jobs_bin/dir_structure.json" + + with open(fle_name, "r") as dir_struct_f: + data = json.load(dir_struct_f) + + tree_level = data["tree_level_labels"] + level_entries = data["level_entries_dict"] + + if "skip_dirs" in data.keys(): + skip_dirs_lst = data["skip_dirs"] + self.skip_dirs_lst = skip_dirs_lst + + self.tree_level_labels = tree_level + self.level_entries = level_entries + self.level_entries_list = level_entries + + except: + print("Couldn't read /jobs_bin/dir_structure.json") + + try: + + #| - __old__ + tmp = 42 + # print("old - Reading dir_structure.json file \ + # from root_dir") + # + # fle_name = self.root_dir + "/dir_structure.json" + # with open(fle_name, "r") as dir_struct_f: + # data = json.load(dir_struct_f) + # tree_level = data["tree_level_labels"] + # level_entries = data["level_entries_dict"] + # + # if "skip_dirs" in data.keys(): + # skip_dirs_lst = data["skip_dirs"] + # self.skip_dirs_lst = skip_dirs_lst + # + # self.tree_level_labels = tree_level + # self.level_entries = level_entries + #__| + + except: + print("Couldn't read /dir_structure.json") + + pass + + except: + mess = "Error opening 'dir_structure.json' file" + raise IOError(mess) + + #__| + + def __create_level_entries_dict__(self, + tree_level_labels, + tree_level_values, + ): + """ + Create level_entries_dict from labels and values lists. + + Args: + tree_level_labels: + tree_level_values: + """ + #| - create_level_entries_dict + level_entries_dict = {} + for index, variable in enumerate(tree_level_labels): + level_entries_dict[variable] = tree_level_values[index] + + return(level_entries_dict) + #__| + + def __level_entries_list__(self): + """Construct level entries list. + + Construct level_entries_list from level_entries_dict and level_labels + """ + #| - __level_entries_list__ + level_entries_dict = self.level_entries + level_labels = self.tree_level_labels + + level_entries_list = [] + for param_i in level_labels: + # for name, params_list in level_entries_dict.iteritems(): + for name, params_list in level_entries_dict.items(): + if param_i == name: + level_entries_list.append(params_list) + + return(level_entries_list) + #__| + + def __order_dict__(self, tree_level_labels, level_entries): + """Order of properties to correspond to order of tree. + + Creates "order_dict", which contains the depth level for each + descriptor. Each job directory will have a unique descriptor list. + The "order_dict" variable is used to make sure that the ordering of the + descriptors in this list matches the "dir_tree_level" structure. + + Args: + tree_level_labels: + level_entries: + """ + #| - __order_dict__ + order_dict = {} # <-------------------------------------- + + level_cnt = 0 + for level in tree_level_labels: + level_cnt += 1 + for prop in level_entries[level]: + order_dict[prop] = level_cnt - 1 + + return order_dict + + #__| + + def __job_variable_list__(self, level_entries, order_dict): + """Return the job variable list. + + Args: + level_entries: + order_dict: + """ + #| - __job_variable_list__ + all_comb = itertools.product(*level_entries) + + job_dir_lst = [] + for job_dir in all_comb: + final_lst_2 = [] + param_names = self.tree_level_labels + + for ind, prop in enumerate(job_dir): + new_entry = {} + new_entry["property"] = param_names[ind] + new_entry["value"] = job_dir[ind] + final_lst_2.append(new_entry) + + job_dir_lst.append(final_lst_2) + + if self.skip_dirs_lst is not None: + for skip in self.skip_dirs_lst: + job_dir_lst.remove(skip) + + return(job_dir_lst) + #__| + + #__| + + + #| - Create Directory Tree + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + # NEW + def create_dir_struct(self, create_first_rev_folder="True"): + """Create directory structure according to job variable list & dict. + + Development Notes: + This should really be looping over the jobs_list I think + + Args: + create_first_rev_folder: + """ + #| - create_dir_struct + for Job_i in self.Job_list: + + #| - FOR LOOP BODY + # if create_first_rev_folder == "True": + # path = os.path.join(Job_i.full_path, "_1") + # elif create_first_rev_folder == "False": + # path = Job_i.full_path + + path = Job_i.full_path + + if os.path.exists(path): + # mess = "Path already exists: " + str(path) + # print(mess) + pass + + elif not os.path.exists(path): + os.makedirs(path) + #__| + + #| - folders_exist attribute should be True from now on + # file_name = self.root_dir + "/jobs_bin/.folders_exist" + file_name = os.path.join( + self.root_dir, + self.working_dir, + "jobs_bin/.folders_exist" + ) + + with open(file_name, "w") as fle: + fle.write("\n") + + self.folders_exist = self.__folders_exist__(True) + #__| + + #__| + + def old_create_dir_struct(self, create_first_rev_folder="True"): + """Create directory structure according to job variable list & dict. + + Development Notes: + This should really be looping over the jobs_list I think + + Args: + create_first_rev_folder: + """ + #| - create_dir_struct + for job in self.job_var_lst: + if create_first_rev_folder == "True": + path = self.var_lst_to_path(job) + "_1" + elif create_first_rev_folder == "False": + path = self.var_lst_to_path(job) + + path = self.root_dir + "/" + path + + if os.path.exists(path): + mess = "Path already exists: " + str(path) + print(mess) + + elif not os.path.exists(path): + os.makedirs(path) + + #| - Creating Variable Text Files Through Directoy Structure + for job in self.job_var_lst: + path = self.var_lst_to_path(job) + path = self.root_dir + "/" + path + + file_name = path + "job_dir_level" + with open(file_name, "w") as fle: + fle.write("\n") + + for root, dirs, files in os.walk(self.root_dir + "/data/"): + if "job_dir_level" in files: + continue + + else: + prop_lst = [] + for folder in dirs: + tmp = self.sep.join(folder.split(self.sep)[1:]) + + prop = self.__replace_p_for_per__(tmp) + prop = self.__replace_negative_for_n__(prop) + prop_lst.append(prop) + + for key, value in self.level_entries.items(): + if set(prop_lst) == set(map(str, value)): + + file_name = root + "/properties.txt" + with open(file_name, "w") as fle: + fle.write(key + "\n") + + # f = open(root + "/properties.txt", "w") + # f.write(key + "\n") + # f.close() + #__| + + # self.__create_dir_structure_file__() + + #| - folders_exist attribute should be True from now on + file_name = self.root_dir + "/jobs_bin/.folders_exist" + with open(file_name, "w") as fle: + fle.write("\n") + + self.folders_exist = self.__folders_exist__(True) + #__| + + #__| + + + + + + + + + + + + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + + + + + + + def check_inputs(self): + """ + """ + #| - check_inputs + if self.tree_level_labels is not None: + assert isinstance(self.tree_level_labels[0], np.ndarray) is False, \ + "Please don't use numpy array types, can't be json serialized" + + if self.level_entries_list is not None: + assert isinstance(self.level_entries_list[0], np.ndarray) is False, \ + "Please don't use numpy array types, can't be json serialized" + #__| + + def __create_dir_structure_file__(self): + """ + Create directory structure file. + + Creates dir structure file from which the parameter list & dict can be + loaded from. + """ + #| - __create_dir_structure_file__ + + dir_structure_data = {} + dir_structure_data["tree_level_labels"] = self.tree_level_labels + dir_structure_data["level_entries_dict"] = self.level_entries_list + # TEMP + dir_structure_data["skip_dirs"] = self.skip_dirs_lst + + fle_name = os.path.join( + self.root_dir, + self.working_dir, + "jobs_bin/dir_structure.json", + ) + + with open(fle_name, "w") as fle: + json.dump(dir_structure_data, fle, indent=2) + #__| + + def __replace_p_for_per__(self, text): + """Replace p in variable with "." character. + + TODO Fails if last letter is a "p" + + Variables with "." character had them previously replaced with a "p" + character to avoid periods in a folder name. + """ + #| - __replace_p_for_per__ + lst = [pos for pos, char in enumerate(text) if char == "p"] + + # Replaces character at lett with a period if both the previous + # and next character are numeric + for lett in lst: + + # COMBAK + # Skip entries which have p at end of text + # Ignores possibility of variables like the following: + # 2. --> 2p (will not go back to 2.) + if lett == len(text) - 1: + continue + + cond_1 = text[lett - 1].isdigit() + cond_2 = text[lett + 1].isdigit() + if cond_1 is True and cond_2 is True: + text = text[:lett] + "." + text[lett + 1:] + + return(text) + #__| + + def __replace_negative_for_n__(self, text): + """Replace variable quantities that are negative with an "n". + + Args: + text: + """ + #| - __replace_negative_for_n__ + lst = [pos for pos, char in enumerate(text) if char == "n"] + + for lett in lst: + if text[lett + 1].isdigit() is True: + text = text[:lett] + "-" + text[lett + 1:] + + return(text) + #__| + + #__| + + + #| - Job Attributes + + def __load_jobs_attributes__(self): + """Load jobs attributes data from file.""" + #| - __load_jobs_attributes__ + job_att_file = self.root_dir + "/jobs_bin/job_attributes.csv" + + if os.path.exists(job_att_file): + with open(job_att_file, "rb") as fle: + jobs_att = pickle.load(fle) + + else: + jobs_att = {} + + return(jobs_att) + #__| + + def append_jobs_attributes(self, attribute): + """ + Append to jobs attributes file. + + Append dictionary key value pair to the jobs_attributes dict. + To be pickled and saved + """ + #| - append_jobs_attributes + att_new = attribute + + self.jobs_att.update(att_new) + + job_att_file = self.root_dir + "/jobs_bin/job_attributes.csv" + pickle.dump(self.jobs_att, open(job_att_file, "wb")) + #__| + + #__| + + def __gen_datatable__(self): + """Initialze data table from the properties of the jobs directory. + + New methods iterates through Job instances + """ + #| - __generate_data_table + rows_list = [] + for Job_i in self.Job_list: + #| - FOR LOOP BODY + entry_param_dict = {} + for prop, value in Job_i.job_params.items(): + entry_param_dict[prop] = value + + entry_param_dict["Job"] = Job_i + entry_param_dict["path"] = Job_i.full_path + entry_param_dict["max_revision"] = Job_i.max_revision + entry_param_dict["revision_number"] = Job_i.revision_number + + rows_list.append(entry_param_dict) + #__| + + data_frame = pd.DataFrame(rows_list) + + return(data_frame) + #__| + + def __revision_list_and_max__(self, path_i): + """Return list of revisions for given job path and highest revision. + + If there are no revision folders or the directory structure hasn't been + created yet the following dummy values will be returned: + ( + ["_1"], + 1, + ) + + Args: + path_i: + """ + #| - __revision_list_and_max__ + if self.folders_exist: + + # dirs = os.listdir(os.path.join(self.working_dir, path_i)) + dirs = os.listdir(path_i) + + revision_dirs = [dir for dir in dirs if dir[0] == "_" and + dir[-1].isdigit() and " " not in dir] + + # dir[1].isdigit() and " " not in dir] + + revision_dirs.sort() + + if len(revision_dirs) == 0: + highest_rev = None + else: + highest_rev = max( + [int(i.split("_")[-1]) for i in revision_dirs], + ) + + return(revision_dirs, highest_rev) + else: + dummy_return = ( + ["_1"], + 1, + ) + + return(dummy_return) + #__| + + def copy_files_jd(self, file_list, variable_lst, revision="Auto"): + """ + Copy files to job directory. + + Args: + file_list: + variable_lst: + revision: + """ + #| - copy_files_jd + path = self.var_lst_to_path(variable_lst) + path += "_" + str(self.job_revision_number(variable_lst)) + + for file in file_list: + shutil.copyfile(self.root_dir + "/" + file, path + "/" + file) + #__| + + + #__| ********************************************************************** + + + + #| - __old__ + # DEPR + def __generate_data_table__(self): + """Initialze data table from the properties of the jobs directory. + + Appends unique row for every job revision + """ + #| - __generate_data_table__ + rows_list = [] + for job in self.job_var_lst: + revisions = self.job_revision_number(job) + for revision in range(revisions + 1)[1:]: + #| - FOR LOOP BODY + entry_param_dict = {} + for prop in job: + entry_param_dict[prop["property"]] = prop["value"] + + entry_param_dict["variable_list"] = job + entry_param_dict["path"] = self.var_lst_to_path(job) + + entry_param_dict["max_revision"] = revisions + entry_param_dict["revision_number"] = revision + + rows_list.append(entry_param_dict) + #__| + + data_frame = pd.DataFrame(rows_list) + + return(data_frame) + #__| + + # DEPR + def job_revision_number_old(self, variable_lst): + """ + Return the largest revision number for the given variable_lst -> job. + + If there are no revision folders or the directory structure hasn't been + created yet 1 will be returned. + + Args: + variable_lst: + """ + #| - job_revision_number + if self.folders_exist: + path = self.var_lst_to_path(variable_lst) + orig_dir = os.getcwd() + os.chdir(self.root_dir + "/" + path) + + dirs = filter(os.path.isdir, os.listdir(os.getcwd())) + + + # COMBAK Does this line break work? + num_jobs = len([dir for dir in dirs if dir[0] == "_" and + dir[1].isdigit() and " " not in dir]) + os.chdir(orig_dir) + + return(num_jobs) + else: + return(1) + + #| - __old__ + # path = self.var_lst_to_path(variable_lst) + # + # path = "/".join(path.split("/")[0:-1]) + "/" + # # Attempting to remove duplicate job folders (usually have spaces) + # dir_list = [x for x in os.walk(path).next()[1] if " " not in x] + # + # return(len(dir_list)) + # + #__| + + #__| + + + #__| diff --git a/dft_job_automat/job_types_classes/data_frame_methods.py b/dft_job_automat/job_types_classes/data_frame_methods.py index 08c0808..baadeb7 100644 --- a/dft_job_automat/job_types_classes/data_frame_methods.py +++ b/dft_job_automat/job_types_classes/data_frame_methods.py @@ -1,80 +1,80 @@ -#!/usr/bin/env python - -"""Dataframe methods. - -Author: Raul A. Flores - -Development Notes: -""" - -#| - IMPORT MODULES -import os -import shutil -#__| - -class DataFrame_Methods(): - """Summary line.""" - - #| - DataFrame_Methods **************************************************** - def __init__(self, dataframe): - """ - Initialize with dataframe. - - Args: - dataframe: - Pandas dataframe object created by jobs_setup, jobs_analysis - classes - """ - #| - __init__ - self.df = dataframe - #__| - - def create_atoms_objects(self, - outdir="atoms_objects", - # atoms_row="init_atoms", - atoms_row="atoms_object", - image=-1, - ): - """ - Create directory of atoms objects corresponding to job folders. - - Args: - outdir: - Places atoms objects in folder named 'atoms_objects' - atoms_row: - image: - """ - #| - create_atoms_objects - df = self.df - - if not os.path.exists(outdir): - os.makedirs(outdir) - else: - err_mess = "atoms folder already created, " - err_mess += "delete or move folder and run command again" - raise RuntimeError(err_mess) - - if atoms_row in list(df): - pass - else: - atoms_row = "init_atoms" - print("Couldn't find " + atoms_row + ", using 'init_atoms' instead") - - for index, row in df.iterrows(): - atoms_i = row[atoms_row] - - print(atoms_i) - if type(atoms_i) == list: - atoms_i = atoms_i[image] - - if atoms_i is not None: - file_name = row["path"][5:].replace("/", "_") + ".traj" - atoms_i.write(file_name) - print(file_name) - shutil.move(file_name, outdir + "/" + file_name) - - else: - pass - #__| - - #__| ********************************************************************** +#!/usr/bin/env python + +"""Dataframe methods. + +Author: Raul A. Flores + +Development Notes: +""" + +#| - IMPORT MODULES +import os +import shutil +#__| + +class DataFrame_Methods(): + """Summary line.""" + + #| - DataFrame_Methods **************************************************** + def __init__(self, dataframe): + """ + Initialize with dataframe. + + Args: + dataframe: + Pandas dataframe object created by jobs_setup, jobs_analysis + classes + """ + #| - __init__ + self.df = dataframe + #__| + + def create_atoms_objects(self, + outdir="atoms_objects", + # atoms_row="init_atoms", + atoms_row="atoms_object", + image=-1, + ): + """ + Create directory of atoms objects corresponding to job folders. + + Args: + outdir: + Places atoms objects in folder named 'atoms_objects' + atoms_row: + image: + """ + #| - create_atoms_objects + df = self.df + + if not os.path.exists(outdir): + os.makedirs(outdir) + else: + err_mess = "atoms folder already created, " + err_mess += "delete or move folder and run command again" + raise RuntimeError(err_mess) + + if atoms_row in list(df): + pass + else: + atoms_row = "init_atoms" + print("Couldn't find " + atoms_row + ", using 'init_atoms' instead") + + for index, row in df.iterrows(): + atoms_i = row[atoms_row] + + print(atoms_i) + if type(atoms_i) == list: + atoms_i = atoms_i[image] + + if atoms_i is not None: + file_name = row["path"][5:].replace("/", "_") + ".traj" + atoms_i.write(file_name) + print(file_name) + shutil.move(file_name, outdir + "/" + file_name) + + else: + pass + #__| + + #__| ********************************************************************** diff --git a/dft_job_automat/job_types_classes/dft_methods.py b/dft_job_automat/job_types_classes/dft_methods.py index 6241112..58879fd 100644 --- a/dft_job_automat/job_types_classes/dft_methods.py +++ b/dft_job_automat/job_types_classes/dft_methods.py @@ -1,393 +1,393 @@ -#!/usr/bin/env python - -"""Class defining methods to extract/manipulate data in vasp raman job folders. - -Development Notes: - TODO Figure out how to pass additional parameters to these methods - Make methods work for VASP and QE by using teh DFT_code attribute -""" - -#| - Import Modules -import os -import pickle as pickle -import json - -from ase import io -# from ase.io.trajectory import Trajectory - -# My Modules -# from ase_modules.ase_methods import number_of_atoms -from ase_modules.ase_methods import create_species_element_dict - -from quantum_espresso.qe_methods import magmom_charge_data -#__| - -class DFT_Methods(): - """Methods and analysis to perform within DFT jobs folders.""" - - #| - DFT_Methods ********************************************************** - def __init__(self, - methods_to_run=[], - DFT_code="QE", # VASP - ): - """Initialize DFT_Methods instance with methods_to_run list. - - Args: - methods_to_run: - """ - #| - __init__ - self.methods_to_run = methods_to_run - self.DFT_code = DFT_code - #__| - - def pdos_data(self, path_i): - """Read pdos.pickle file and return data. - - Args: - path_i: - """ - #| - pdos_data - fle_name = "dir_pdos/dos.pickle" - if os.path.exists(path_i + "/" + fle_name): - # with open(path_i + "/" + fle_name, "r") as fle: - # NOTE Added "rb" & encoding="latin1" for python3 support - with open(path_i + "/" + fle_name, "rb") as fle: - data = pickle.load(fle, encoding="latin1") - - return(data) - #__| - - def bands_data(self, path_i): - """Read band_disp.pickle file and return data. - - Args: - path_i: - """ - #| - bands_data - fle_name = "dir_bands/band_disp.pickle" - # print(path_i + "/" + fle_name) - if os.path.exists(path_i + "/" + fle_name): - with open(path_i + "/" + fle_name, "rb") as fle: - data = pickle.load(fle, encoding="latin1") - - return(data) - #__| - - def magmom_charge_history(self, path_i, log="calcdir/log"): - """Return atomic charges and magmoms thourgh SCF convergence history. - - Args: - path_i - """ - #| - magmom_charge_history - df = magmom_charge_data(path_i=path_i, log=log) - imp_col = ["atom_num", "iteration", "element"] - - magmom_history_df = df.filter(items=imp_col + ["magmom"]) - charge_history_df = df.filter(items=imp_col + ["charge"]) - - out_dict = {} - out_dict["magmom_history"] = magmom_history_df - out_dict["charge_history"] = charge_history_df - - return(out_dict) - #__| - - def gibbs_energy(self, path_i): - """Read gibbs free energy from file. - - Included raw electronic energy and whatever correctios were applied. - - Args: - path_i - """ - #| - gibbs_energy - gibbs_e = None - - fle_name = "g_energy.out" - if os.path.exists(path_i + "/" + fle_name): - with open(path_i + "/" + fle_name, "r") as fle: - gibbs_e = float(fle.read().strip()) - - return(gibbs_e) - #__| - - def gibbs_correction(self, path_i): - """Return gibbs free energy correction. - - Args: - path_i - """ - #| - gibbs_correction - gibbs_corr = 0. - - fle_name = "dir_vib/gibbs_corr.out" - if os.path.exists(path_i + "/" + fle_name): - with open(path_i + "/" + fle_name, "r") as fle: - gibbs_corr = float(fle.read().strip()) - - return(gibbs_corr) - #__| - - def elec_energy(self, path_i, atoms_file="out_opt.traj"): - """Read electronic energy from ASE atoms object. - - Args: - path_i: - atoms_file: - """ - #| - elec_energy - energy = None - - try: - file_dir = os.path.join( - path_i, - "dir_opt/elec_e.out", - ) - with open(file_dir, "r") as fle: - energy = float(fle.read().strip()) - except: - pass - - - #| - Non-favored methods - try: - atoms = self.atoms_object(path_i)[-1] - energy = atoms.get_potential_energy() - except: - pass - - try: - atoms = io.read(path_i + "/" + "out_opt.traj") - energy = atoms.get_potential_energy() - except: - pass - #__| - - return(energy) - #__| - - def atoms_object(self, path_i): - """Attempt to read and return atoms object. - - Args: - path_i: - """ - #| - atoms_object - # atoms_file_names = ["out_opt.traj", "out.traj"] - # 'out.traj' should be read first - - atoms_file_names = [ - "out.traj", - "out_opt.traj", - "OUTCAR", # VASP - ] - - for file_name in atoms_file_names: - try: - - #| - try to read atoms - if self.DFT_code == "VASP": - - cwd = os.getcwd() - os.chdir(path_i) - - traj = io.read( - os.path.join(path_i, file_name), - index=":", - ) - - os.chdir(cwd) - - else: - - traj = io.read( - os.path.join(path_i, file_name), - index=":", - ) - - break - #__| - - except: - traj = None - - return(traj) - #__| - - - def outcar(self, path_i): - """Attempt to read and return outcar. - - Args: - path_i: - """ - #| - atoms_object - line_list = [] - with open(os.path.join(path_i, "OUTCAR")) as fle: - for line in fle: - line = line.rstrip() - line_list.append(line) - - return(line_list) - - #| - __old__ - # for file_name in atoms_file_names: - # try: - # - # #| - try to read atoms - # if self.DFT_code == "VASP": - # - # cwd = os.getcwd() - # os.chdir(path_i) - # - # traj = io.read( - # os.path.join(path_i, file_name), - # index=":", - # ) - # - # os.chdir(cwd) - # - # else: - # traj = io.read( - # os.path.join(path_i, file_name), - # index=":", - # ) - # - # break - # #__| - # - # except: - # traj = None - # - # return(traj) - #__| - - #__| - - - def incar(self, path_i): - """ - """ - #| - incar - line_list = [] - with open(os.path.join(path_i, "INCAR")) as fle: - for line in fle: - line = line.rstrip() - line_list.append(line) - - return(line_list) - #__| - - def init_atoms(self, path_i): - """Attempt to read and return initial atoms object. - - Args: - path_i: - """ - #| - init_atoms - traj = None - - atoms_file_names = [ - "init.traj", - "init.POSCAR", - "out_opt.traj", - "init.cif", - ] - - for file_name in atoms_file_names: - try: - traj = io.read(path_i + "/" + file_name) - break - - except: - pass - - return(traj) - #__| - - def parse_error_file(self, path_i): - """Parse QE ase-espresso error file for keywords indicating failure. - - TODO Move this from job_analysis to here - - - Args: - path_i: - """ - #| - parse_error_file - tmp = 42 - print(tmp) - #__| - - def atom_type_num_dict(self, path_i): - """Return dictionary containing atomic count for each element. - - Args: - path_i: - """ - #| - atom_type_num_dict - atoms = None - atoms_file_names = ["out_opt.traj", "out.traj"] - for file_name in atoms_file_names: - try: - print(path_i + "/" + file_name) - atoms = io.read(path_i + "/" + file_name) - break - - except: - pass - - # print(atoms) - # atoms = io.read(path_i + "/out.traj") - - # print("dft_methods") - out_dict = create_species_element_dict( - atoms, - include_all_elems=False, - elems_to_always_include=None, - ) - - print("dft_methods - atom_type_num_dict") - print(out_dict) - # out_dict = number_of_atoms(atoms) - - return([out_dict]) - #__| - - - # def dft_params(path_i): - def dft_params(self, path_i): - """Attempt to read dft_params.json file. - - Note: Current workflow moved dft_params file to dir_dft_params folder - when the job completes. Must check job folder and this one. - - Note: Should revisions to the dft_params.json file be read? Only the - most recent? Only the original one? - - Args: - path_i - """ - #| - dft_params - file_path_1 = os.path.join( - path_i, - path_i, - "dft-params.json", - ) - - file_path_2 = os.path.join( - path_i, - "dir_dft_params", - "dft-params.json", - ) - - if os.path.isfile(file_path_1): - dft_params_dict = json.load(open(file_path_1, "r")) - elif os.path.isfile(file_path_2): - dft_params_dict = json.load(open(file_path_2, "r")) - - return(dft_params_dict) - #__| - - #__| ********************************************************************** +#!/usr/bin/env python + +"""Class defining methods to extract/manipulate data in vasp raman job folders. + +Development Notes: + TODO Figure out how to pass additional parameters to these methods + Make methods work for VASP and QE by using teh DFT_code attribute +""" + +#| - Import Modules +import os +import pickle as pickle +import json + +from ase import io +# from ase.io.trajectory import Trajectory + +# My Modules +# from ase_modules.ase_methods import number_of_atoms +from ase_modules.ase_methods import create_species_element_dict + +from quantum_espresso.qe_methods import magmom_charge_data +#__| + +class DFT_Methods(): + """Methods and analysis to perform within DFT jobs folders.""" + + #| - DFT_Methods ********************************************************** + def __init__(self, + methods_to_run=[], + DFT_code="QE", # VASP + ): + """Initialize DFT_Methods instance with methods_to_run list. + + Args: + methods_to_run: + """ + #| - __init__ + self.methods_to_run = methods_to_run + self.DFT_code = DFT_code + #__| + + def pdos_data(self, path_i): + """Read pdos.pickle file and return data. + + Args: + path_i: + """ + #| - pdos_data + fle_name = "dir_pdos/dos.pickle" + if os.path.exists(path_i + "/" + fle_name): + # with open(path_i + "/" + fle_name, "r") as fle: + # NOTE Added "rb" & encoding="latin1" for python3 support + with open(path_i + "/" + fle_name, "rb") as fle: + data = pickle.load(fle, encoding="latin1") + + return(data) + #__| + + def bands_data(self, path_i): + """Read band_disp.pickle file and return data. + + Args: + path_i: + """ + #| - bands_data + fle_name = "dir_bands/band_disp.pickle" + # print(path_i + "/" + fle_name) + if os.path.exists(path_i + "/" + fle_name): + with open(path_i + "/" + fle_name, "rb") as fle: + data = pickle.load(fle, encoding="latin1") + + return(data) + #__| + + def magmom_charge_history(self, path_i, log="calcdir/log"): + """Return atomic charges and magmoms thourgh SCF convergence history. + + Args: + path_i + """ + #| - magmom_charge_history + df = magmom_charge_data(path_i=path_i, log=log) + imp_col = ["atom_num", "iteration", "element"] + + magmom_history_df = df.filter(items=imp_col + ["magmom"]) + charge_history_df = df.filter(items=imp_col + ["charge"]) + + out_dict = {} + out_dict["magmom_history"] = magmom_history_df + out_dict["charge_history"] = charge_history_df + + return(out_dict) + #__| + + def gibbs_energy(self, path_i): + """Read gibbs free energy from file. + + Included raw electronic energy and whatever correctios were applied. + + Args: + path_i + """ + #| - gibbs_energy + gibbs_e = None + + fle_name = "g_energy.out" + if os.path.exists(path_i + "/" + fle_name): + with open(path_i + "/" + fle_name, "r") as fle: + gibbs_e = float(fle.read().strip()) + + return(gibbs_e) + #__| + + def gibbs_correction(self, path_i): + """Return gibbs free energy correction. + + Args: + path_i + """ + #| - gibbs_correction + gibbs_corr = 0. + + fle_name = "dir_vib/gibbs_corr.out" + if os.path.exists(path_i + "/" + fle_name): + with open(path_i + "/" + fle_name, "r") as fle: + gibbs_corr = float(fle.read().strip()) + + return(gibbs_corr) + #__| + + def elec_energy(self, path_i, atoms_file="out_opt.traj"): + """Read electronic energy from ASE atoms object. + + Args: + path_i: + atoms_file: + """ + #| - elec_energy + energy = None + + try: + file_dir = os.path.join( + path_i, + "dir_opt/elec_e.out", + ) + with open(file_dir, "r") as fle: + energy = float(fle.read().strip()) + except: + pass + + + #| - Non-favored methods + try: + atoms = self.atoms_object(path_i)[-1] + energy = atoms.get_potential_energy() + except: + pass + + try: + atoms = io.read(path_i + "/" + "out_opt.traj") + energy = atoms.get_potential_energy() + except: + pass + #__| + + return(energy) + #__| + + def atoms_object(self, path_i): + """Attempt to read and return atoms object. + + Args: + path_i: + """ + #| - atoms_object + # atoms_file_names = ["out_opt.traj", "out.traj"] + # 'out.traj' should be read first + + atoms_file_names = [ + "out.traj", + "out_opt.traj", + "OUTCAR", # VASP + ] + + for file_name in atoms_file_names: + try: + + #| - try to read atoms + if self.DFT_code == "VASP": + + cwd = os.getcwd() + os.chdir(path_i) + + traj = io.read( + os.path.join(path_i, file_name), + index=":", + ) + + os.chdir(cwd) + + else: + + traj = io.read( + os.path.join(path_i, file_name), + index=":", + ) + + break + #__| + + except: + traj = None + + return(traj) + #__| + + + def outcar(self, path_i): + """Attempt to read and return outcar. + + Args: + path_i: + """ + #| - atoms_object + line_list = [] + with open(os.path.join(path_i, "OUTCAR")) as fle: + for line in fle: + line = line.rstrip() + line_list.append(line) + + return(line_list) + + #| - __old__ + # for file_name in atoms_file_names: + # try: + # + # #| - try to read atoms + # if self.DFT_code == "VASP": + # + # cwd = os.getcwd() + # os.chdir(path_i) + # + # traj = io.read( + # os.path.join(path_i, file_name), + # index=":", + # ) + # + # os.chdir(cwd) + # + # else: + # traj = io.read( + # os.path.join(path_i, file_name), + # index=":", + # ) + # + # break + # #__| + # + # except: + # traj = None + # + # return(traj) + #__| + + #__| + + + def incar(self, path_i): + """ + """ + #| - incar + line_list = [] + with open(os.path.join(path_i, "INCAR")) as fle: + for line in fle: + line = line.rstrip() + line_list.append(line) + + return(line_list) + #__| + + def init_atoms(self, path_i): + """Attempt to read and return initial atoms object. + + Args: + path_i: + """ + #| - init_atoms + traj = None + + atoms_file_names = [ + "init.traj", + "init.POSCAR", + "out_opt.traj", + "init.cif", + ] + + for file_name in atoms_file_names: + try: + traj = io.read(path_i + "/" + file_name) + break + + except: + pass + + return(traj) + #__| + + def parse_error_file(self, path_i): + """Parse QE ase-espresso error file for keywords indicating failure. + + TODO Move this from job_analysis to here + + + Args: + path_i: + """ + #| - parse_error_file + tmp = 42 + print(tmp) + #__| + + def atom_type_num_dict(self, path_i): + """Return dictionary containing atomic count for each element. + + Args: + path_i: + """ + #| - atom_type_num_dict + atoms = None + atoms_file_names = ["out_opt.traj", "out.traj"] + for file_name in atoms_file_names: + try: + print(path_i + "/" + file_name) + atoms = io.read(path_i + "/" + file_name) + break + + except: + pass + + # print(atoms) + # atoms = io.read(path_i + "/out.traj") + + # print("dft_methods") + out_dict = create_species_element_dict( + atoms, + include_all_elems=False, + elems_to_always_include=None, + ) + + print("dft_methods - atom_type_num_dict") + print(out_dict) + # out_dict = number_of_atoms(atoms) + + return([out_dict]) + #__| + + + # def dft_params(path_i): + def dft_params(self, path_i): + """Attempt to read dft_params.json file. + + Note: Current workflow moved dft_params file to dir_dft_params folder + when the job completes. Must check job folder and this one. + + Note: Should revisions to the dft_params.json file be read? Only the + most recent? Only the original one? + + Args: + path_i + """ + #| - dft_params + file_path_1 = os.path.join( + path_i, + path_i, + "dft-params.json", + ) + + file_path_2 = os.path.join( + path_i, + "dir_dft_params", + "dft-params.json", + ) + + if os.path.isfile(file_path_1): + dft_params_dict = json.load(open(file_path_1, "r")) + elif os.path.isfile(file_path_2): + dft_params_dict = json.load(open(file_path_2, "r")) + + return(dft_params_dict) + #__| + + #__| ********************************************************************** diff --git a/dft_job_automat/job_types_classes/raman_methods.py b/dft_job_automat/job_types_classes/raman_methods.py index 0b5130e..1178369 100644 --- a/dft_job_automat/job_types_classes/raman_methods.py +++ b/dft_job_automat/job_types_classes/raman_methods.py @@ -1,98 +1,98 @@ -"""Class defining methods to extract/manipulate data in vasp raman job folders.""" - -#| - Import Modules -# from dft_job_automat.job_setup import DFT_Jobs_Setup -# from aws.aws_class import AWS_Queues -import pandas as pd -pd.options.display.max_colwidth = 250 - -import os -# from ase import io -import numpy as np -# import pickle -# import boto3 -# import subprocess -#__| - -class Raman_Vasp(): - """Summary line. - TEMP - """ - - def __init__(self, methods_to_run=[]): - """TMP_docstring. - TEMP TEMP - - Args: - """ - #| - __init__ - self.tmp = 42 - self.methods_to_run = methods_to_run - #__| - - def tmp_meth(self, path_i): - """ - """ - #| - tmp_meth - return("tmp - tmp_meth") - #__| - - def read_modes_file(self, path_i): - """ - """ - #| - read_modes_file - # raman_dat_file = path_i + "/simulation/vasp_raman.dat" - # print("3:" + path_i) - - raman_dat_file = path_i + "/vasp_raman.dat" - - # print(raman_dat_file) - - data_list = [] - if os.path.isfile(raman_dat_file): - # print("*(^)") - try: - with open(raman_dat_file) as fle: - lines = fle.read().splitlines() - - if not lines: - data_list = np.nan - elif len(lines) == 1: - data_list = np.nan - - else: - # print(len(lines)) - for line_num, line in enumerate(lines): - if line_num == 0: - continue - - line = line.split() - - line_data_dict = {} - line_data_dict["mode_number"] = int(line[0]) - line_data_dict["frequency"] = float(line[1]) - line_data_dict["alpha"] = float(line[2]) - line_data_dict["beta2"] = float(line[3]) - line_data_dict["activity"] = float(line[4]) - - data_list.append(line_data_dict) - - except: - # print("##@!@!@") - data_list = np.nan - print("Couldn't open vasp_raman.dat") - - else: - # print("&&*&(())") - data_list = np.nan - - # Can't handle multiple modes at the same time right now. - if pd.isnull(data_list) == False: - assert len(data_list) == 1 - - if len(data_list) == 1: - data_list = data_list[0] - - return(data_list) - - #__| +"""Class defining methods to extract/manipulate data in vasp raman job folders.""" + +#| - Import Modules +# from dft_job_automat.job_setup import DFT_Jobs_Setup +# from aws.aws_class import AWS_Queues +import pandas as pd +pd.options.display.max_colwidth = 250 + +import os +# from ase import io +import numpy as np +# import pickle +# import boto3 +# import subprocess +#__| + +class Raman_Vasp(): + """Summary line. + TEMP + """ + + def __init__(self, methods_to_run=[]): + """TMP_docstring. + TEMP TEMP + + Args: + """ + #| - __init__ + self.tmp = 42 + self.methods_to_run = methods_to_run + #__| + + def tmp_meth(self, path_i): + """ + """ + #| - tmp_meth + return("tmp - tmp_meth") + #__| + + def read_modes_file(self, path_i): + """ + """ + #| - read_modes_file + # raman_dat_file = path_i + "/simulation/vasp_raman.dat" + # print("3:" + path_i) + + raman_dat_file = path_i + "/vasp_raman.dat" + + # print(raman_dat_file) + + data_list = [] + if os.path.isfile(raman_dat_file): + # print("*(^)") + try: + with open(raman_dat_file) as fle: + lines = fle.read().splitlines() + + if not lines: + data_list = np.nan + elif len(lines) == 1: + data_list = np.nan + + else: + # print(len(lines)) + for line_num, line in enumerate(lines): + if line_num == 0: + continue + + line = line.split() + + line_data_dict = {} + line_data_dict["mode_number"] = int(line[0]) + line_data_dict["frequency"] = float(line[1]) + line_data_dict["alpha"] = float(line[2]) + line_data_dict["beta2"] = float(line[3]) + line_data_dict["activity"] = float(line[4]) + + data_list.append(line_data_dict) + + except: + # print("##@!@!@") + data_list = np.nan + print("Couldn't open vasp_raman.dat") + + else: + # print("&&*&(())") + data_list = np.nan + + # Can't handle multiple modes at the same time right now. + if pd.isnull(data_list) == False: + assert len(data_list) == 1 + + if len(data_list) == 1: + data_list = data_list[0] + + return(data_list) + + #__| diff --git a/dft_post_analysis/bands.py b/dft_post_analysis/bands.py index 064c552..61e1096 100644 --- a/dft_post_analysis/bands.py +++ b/dft_post_analysis/bands.py @@ -1,277 +1,277 @@ -#!/usr/bin/env python - -"""Plot bands. - -Author: Johanness Voss mostly -""" - -#| - IMPORT MODULES -import copy -from itertools import compress - -import numpy as np -import plotly.graph_objs as go - -from misc_modules.numpy_methods import make_filter_list -#__| - -#| - Methods -def plot_band_series( - x_data, - y_data, - showlegend=False, - ): - """Plot band data series. - - Args: - x_data: - y_data: - """ - #| - plot_dos_series - # trace = go.Scatter( - trace = go.Scattergl( - x=x_data, - y=y_data, - hoverinfo="none", - showlegend=showlegend, - name="Bands", - legendgroup="bands_group", - line=dict( - color=('rgb(22, 96, 167)'), - width=1, - ) - ) - - return(trace) - #__| - -#__| - -def filter_bands_data(bands_data, percent_keep=0.6): - """Filter bands data series to lower memory cost. - - Args: - bands_data: - percent_keep: - """ - #| - filter_bands_data - len_data = len(bands_data[2]) - filter_list = make_filter_list(len_data, percent_keep) - - if type(bands_data[4]) is tuple: - bands = bands_data[4][0] - else: - bands = bands_data[4] - - shape_len = len(bands.shape) - - if shape_len == 3: - spinpol = True - elif shape_len == 2: - spinpol = False - - new_bands_data = () - - new_bands_data += (bands_data[0],) - new_bands_data += (bands_data[1],) - new_bands_data += (np.array(list(compress(bands_data[2], filter_list))),) - new_bands_data += (bands_data[3],) - -# spinpol = True - if spinpol: - new_data = [] - for spin in bands: - spin_i_new = [] - for series_i in spin.T: - tmp = np.array(list(compress(series_i, filter_list))) - spin_i_new.append(tmp) - - spin_i_new = np.array(spin_i_new).T - new_data.append(spin_i_new) - - else: - spin_i_new = [] - for series_i in bands.T: - tmp = np.array(list(compress(series_i, filter_list))) - spin_i_new.append(tmp) - - new_data = np.array(spin_i_new).T - - new_bands_data += (np.array(new_data),) - - return(new_bands_data) - #__| - -def plot_bands( - bands_data, - plot_title="Projected Density of States", - ): - """Create bands plot data. - - Args: - bands_data: - plot_title: - """ - #| - plot_bands - - #| - SCRIPT PARAMETERS - # COMBAK - emin = -20 - emax = 20 - plot_title = "Band diagram" - #__| - - s, k, x, X, e = bands_data - - # symbols = [t.replace('Gamma', '$\Gamma$') for t in s] - symbols = [t.replace("Gamma", "G") for t in s] - - #| - Checking if Atomic Projections Present - # If atomic projections in "e" variable - if isinstance(e, tuple) and len(e) == 2: - # For the time being I'll just redefine e - - e = e[0] - #__| - - #| - Checking for Spin Polarization - # If spinpol = True, then e will have added dimension - if e.shape[0] == 2: - spinpol = True - else: - spinpol = False - #__| - - data_list = [] - - #| - Plotting Bands - if spinpol is False: - - #| - Spinpol: False - for n in range(len(e[0])): - if n == 0: - showleg = True - else: - showleg = False - - data_list.append(plot_band_series(x, e[:, n], showlegend=showleg)) - #__| - - elif spinpol is True: - #| - Spinpol: True - for n in range(len(e[0][0])): - if n == 0: - showleg = True - else: - showleg = False - - data_list.append( - plot_band_series(x, e[0][:, n], showlegend=showleg), - ) - - data_list.append( - plot_band_series(x, e[1][:, n], showlegend=showleg), - ) - #__| - - #__| - - #| - Plot y=0 (Fermi Level) - fermi_level = go.Scattergl( - x=[X[0], X[-1]], - y=[0, 0], - mode="lines", - hoverinfo="none", - showlegend=False, - line=dict( - color=("black"), - width=1, - dash="dash", - ) - ) - - data_list.append(fermi_level) - #__| - - #| - Plot Vertical Lines at Special K-Points - for p in X: - trace = go.Scattergl( - x=[p, p], - y=[emin, emax], - hoverinfo="none", - showlegend=False, - mode="lines", - line=dict( - color=("red"), - width=1, - ) - ) - data_list.append(trace) - #__| - - #| - Plotly - - #| - Plot Settings - plot_title_size = 18 - tick_lab_size = 16 - axes_lab_size = 18 - legend_size = 18 - #__| - - #| - Plot Layout - layout = { - "title": plot_title, - "showlegend": False, - "font": { - "family": "Courier New, monospace", - "size": plot_title_size, - "color": "black", - }, - - #| - Axes -------------------------------------------------------------- - "yaxis": { - "title": "Energy [eV]", - "range": [emin, emax], - "zeroline": True, - "titlefont": dict(size=axes_lab_size), - "showgrid": False, - "tickfont": dict( - size=tick_lab_size, - ), - }, - - "xaxis": { - "range": [0, X[-1]], - "zeroline": False, - # "ticktext": s, - "ticktext": symbols, - # "ticktext": ['G', 'X', 'W', 'K', 'L', 'G'], - # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - "tickvals": X, - "tickfont": dict( - size=tick_lab_size, - ), - }, - - - #__| ------------------------------------------------------------------- - - #| - Legend ------------------------------------------------------------ - "legend": { - "traceorder": "normal", - "font": dict(size=legend_size) - }, - #__| ------------------------------------------------------------------- - - #| - Plot Size - "width": 200 * 4., - "height": 200 * 3., - #__| - - } - #__| - - #__| - - return(data_list, layout) - #__| +#!/usr/bin/env python + +"""Plot bands. + +Author: Johanness Voss mostly +""" + +#| - IMPORT MODULES +import copy +from itertools import compress + +import numpy as np +import plotly.graph_objs as go + +from misc_modules.numpy_methods import make_filter_list +#__| + +#| - Methods +def plot_band_series( + x_data, + y_data, + showlegend=False, + ): + """Plot band data series. + + Args: + x_data: + y_data: + """ + #| - plot_dos_series + # trace = go.Scatter( + trace = go.Scattergl( + x=x_data, + y=y_data, + hoverinfo="none", + showlegend=showlegend, + name="Bands", + legendgroup="bands_group", + line=dict( + color=('rgb(22, 96, 167)'), + width=1, + ) + ) + + return(trace) + #__| + +#__| + +def filter_bands_data(bands_data, percent_keep=0.6): + """Filter bands data series to lower memory cost. + + Args: + bands_data: + percent_keep: + """ + #| - filter_bands_data + len_data = len(bands_data[2]) + filter_list = make_filter_list(len_data, percent_keep) + + if type(bands_data[4]) is tuple: + bands = bands_data[4][0] + else: + bands = bands_data[4] + + shape_len = len(bands.shape) + + if shape_len == 3: + spinpol = True + elif shape_len == 2: + spinpol = False + + new_bands_data = () + + new_bands_data += (bands_data[0],) + new_bands_data += (bands_data[1],) + new_bands_data += (np.array(list(compress(bands_data[2], filter_list))),) + new_bands_data += (bands_data[3],) + +# spinpol = True + if spinpol: + new_data = [] + for spin in bands: + spin_i_new = [] + for series_i in spin.T: + tmp = np.array(list(compress(series_i, filter_list))) + spin_i_new.append(tmp) + + spin_i_new = np.array(spin_i_new).T + new_data.append(spin_i_new) + + else: + spin_i_new = [] + for series_i in bands.T: + tmp = np.array(list(compress(series_i, filter_list))) + spin_i_new.append(tmp) + + new_data = np.array(spin_i_new).T + + new_bands_data += (np.array(new_data),) + + return(new_bands_data) + #__| + +def plot_bands( + bands_data, + plot_title="Projected Density of States", + ): + """Create bands plot data. + + Args: + bands_data: + plot_title: + """ + #| - plot_bands + + #| - SCRIPT PARAMETERS + # COMBAK + emin = -20 + emax = 20 + plot_title = "Band diagram" + #__| + + s, k, x, X, e = bands_data + + # symbols = [t.replace('Gamma', '$\Gamma$') for t in s] + symbols = [t.replace("Gamma", "G") for t in s] + + #| - Checking if Atomic Projections Present + # If atomic projections in "e" variable + if isinstance(e, tuple) and len(e) == 2: + # For the time being I'll just redefine e + + e = e[0] + #__| + + #| - Checking for Spin Polarization + # If spinpol = True, then e will have added dimension + if e.shape[0] == 2: + spinpol = True + else: + spinpol = False + #__| + + data_list = [] + + #| - Plotting Bands + if spinpol is False: + + #| - Spinpol: False + for n in range(len(e[0])): + if n == 0: + showleg = True + else: + showleg = False + + data_list.append(plot_band_series(x, e[:, n], showlegend=showleg)) + #__| + + elif spinpol is True: + #| - Spinpol: True + for n in range(len(e[0][0])): + if n == 0: + showleg = True + else: + showleg = False + + data_list.append( + plot_band_series(x, e[0][:, n], showlegend=showleg), + ) + + data_list.append( + plot_band_series(x, e[1][:, n], showlegend=showleg), + ) + #__| + + #__| + + #| - Plot y=0 (Fermi Level) + fermi_level = go.Scattergl( + x=[X[0], X[-1]], + y=[0, 0], + mode="lines", + hoverinfo="none", + showlegend=False, + line=dict( + color=("black"), + width=1, + dash="dash", + ) + ) + + data_list.append(fermi_level) + #__| + + #| - Plot Vertical Lines at Special K-Points + for p in X: + trace = go.Scattergl( + x=[p, p], + y=[emin, emax], + hoverinfo="none", + showlegend=False, + mode="lines", + line=dict( + color=("red"), + width=1, + ) + ) + data_list.append(trace) + #__| + + #| - Plotly + + #| - Plot Settings + plot_title_size = 18 + tick_lab_size = 16 + axes_lab_size = 18 + legend_size = 18 + #__| + + #| - Plot Layout + layout = { + "title": plot_title, + "showlegend": False, + "font": { + "family": "Courier New, monospace", + "size": plot_title_size, + "color": "black", + }, + + #| - Axes -------------------------------------------------------------- + "yaxis": { + "title": "Energy [eV]", + "range": [emin, emax], + "zeroline": True, + "titlefont": dict(size=axes_lab_size), + "showgrid": False, + "tickfont": dict( + size=tick_lab_size, + ), + }, + + "xaxis": { + "range": [0, X[-1]], + "zeroline": False, + # "ticktext": s, + "ticktext": symbols, + # "ticktext": ['G', 'X', 'W', 'K', 'L', 'G'], + # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], + "tickvals": X, + "tickfont": dict( + size=tick_lab_size, + ), + }, + + + #__| ------------------------------------------------------------------- + + #| - Legend ------------------------------------------------------------ + "legend": { + "traceorder": "normal", + "font": dict(size=legend_size) + }, + #__| ------------------------------------------------------------------- + + #| - Plot Size + "width": 200 * 4., + "height": 200 * 3., + #__| + + } + #__| + + #__| + + return(data_list, layout) + #__| diff --git a/dft_post_analysis/charge_density.py b/dft_post_analysis/charge_density.py index 4f48c45..30b9e7b 100644 --- a/dft_post_analysis/charge_density.py +++ b/dft_post_analysis/charge_density.py @@ -1,459 +1,459 @@ -#!/usr/bin/env python - -"""Charge density class. - -Author: Raul A. Flores -""" - -#| - Import Modules -# import os -# import sys -import random -import pickle - -import pandas as pd -import numpy as np -from ase.io.cube import read_cube -# , write_cube -# read_cube_data, - -# import plotly as py -import plotly.graph_objs as go -#__| - -class ChargeDensity(object): - """docstring for ChargeDensity.""" - - #| - ChargeDensity ******************************************************** - def __init__(self, - cube_filename, - master_data_filter=0.98, - lower_bound_density_filter=0.025, - - wrap_atoms=True, - working_dir=".", - ): - """Initialize ChargeDensity instance. - - Args: - cube_filename: - master_data_filter: - Fraction of data to be removed randomly - lower_bound_density_filter: - Lower bound of normalized density value to be discarded - working_dir: - """ - #| - __init__ - - #| - Define User Attributes - self.cube_filename = cube_filename - self.master_data_filter = master_data_filter - self.lower_bound_density_filter = lower_bound_density_filter - self.wrap_atoms = wrap_atoms - self.working_dir = working_dir - #__| - - ( - self.atoms, - self.cd_data, - self.origin, - ) = self.__load_cube_file__() - - - self.master_data_df = self.__process_data__() - - # self.__save_dataframe__() - - self.num_data_points = self.__number_of_data_points__() - - self.__filter_data__() - self.__norm_electron_density__() - self.__filter_low_density__() - # self.__keep_only_edges__() - #__| - - def __load_cube_file__(self): - """Load charge density cube file.""" - #| - __load_cube_file__ - filename = self.cube_filename - - with open(filename, "r") as fle: - data_master = read_cube(fle) - - atoms = data_master["atoms"] - cd_data = data_master["data"] - origin = data_master["origin"] - - if self.wrap_atoms: - atoms.wrap(pbc=True) - - return(atoms, cd_data, origin) - #__| - - def __process_data__(self): - """Create dataframe from charge density data grid.""" - #| - __process_data__ - cd_data = self.cd_data - atoms = self.atoms - - master_data_list = [] - for index, dens_i in np.ndenumerate(cd_data): - data_i = {} - data_i["x_ind"] = index[0] - data_i["y_ind"] = index[1] - data_i["z_ind"] = index[2] - data_i["density"] = dens_i - - master_data_list.append(data_i) - - df = pd.DataFrame(master_data_list) - - df["x_coord_norm"] = df["x_ind"] / df["x_ind"].max() - df["y_coord_norm"] = df["y_ind"] / df["y_ind"].max() - df["z_coord_norm"] = df["z_ind"] / df["z_ind"].max() - - df["x_coord"] = df["x_coord_norm"] * atoms.cell[:, 0].sum() - df["y_coord"] = df["y_coord_norm"] * atoms.cell[:, 1].sum() - df["z_coord"] = df["z_coord_norm"] * atoms.cell[:, 2].sum() - - def multiply_by_unit_cell(row, atoms=None): - coord = np.array([ - row["x_coord_norm"], - row["y_coord_norm"], - row["z_coord_norm"], - ]) - - scaled_cell_vectors = (atoms.cell.T * coord).T - - new_coord = np.array([ - scaled_cell_vectors[:, 0].sum(), - scaled_cell_vectors[:, 1].sum(), - scaled_cell_vectors[:, 2].sum(), - ]) - - # new_coord = atoms.cell.dot(coord) - - return(new_coord[0], new_coord[1], new_coord[2]) - - ( - df["x_coord"], - df["y_coord"], - df["z_coord"], - ) = zip(*df.apply(multiply_by_unit_cell, axis=1, atoms=atoms)) - - return(df) - #__| - - def __number_of_data_points__(self): - """Return the number of individual density data points.""" - #| - __number_of_data_points__ - master_data_df = self.master_data_df - - num_data_points = len(master_data_df) - - return(num_data_points) - #__| - - def __filter_data__(self): - """Filter data randomly to decrease the data set size.""" - #| - __filter_data__ - master_data_df = self.master_data_df - num_data_points = self.num_data_points - master_data_filter = self.master_data_filter - - bool_list = [] - for data_i in range(num_data_points): - rand_i = random.random() - if rand_i > master_data_filter: - bool_list.append(True) - else: - bool_list.append(False) - - df_filtered = master_data_df[bool_list] - - self.master_data_df = df_filtered - #__| - - def __norm_electron_density__(self): - """Normalize electron density from 0 to 1.""" - #| - __norm_electron_density__ - df = self.master_data_df - - max_density = df.density.max() - df["norm_dens"] = df["density"] / max_density - #__| - - def __filter_low_density__(self): - """Filter low density entries from the data.""" - #| - __filter_low_density__ - df = self.master_data_df - lower_bound_density_filter = self.lower_bound_density_filter - - df = df[df["norm_dens"] > lower_bound_density_filter] - - self.master_data_df = df - #__| - - def __keep_only_edges__(self): - """Only keep the outer surface points for clarity.""" - #| - __keep_only_edges__ - df = self.master_data_df - - df_a = df[df["x_ind"] == df.x_ind.max()] - df_b = df[df["y_ind"] == df.y_ind.max()] - df_c = df[df["z_ind"] == df.z_ind.max()] - - df_1 = df[df["x_ind"] == 0] - df_2 = df[df["y_ind"] == 0] - df_3 = df[df["z_ind"] == 0] - - df_surf = pd.concat( - [ - df_a, df_b, df_c, - df_1, df_2, df_3, - ] - ) - - self.master_data_df = df_surf - #__| - - def __save_dataframe__(self): - """Save dataframe to pickle file. - - COMBAK impliment this to save time - """ - #| - __save_dataframe__ - df = self.master_data_df - working_dir = self.working_dir - - with open(working_dir + "/dataframe.pickle", "w") as fle: - pickle.dump(df, fle) - #__| - - def __load_dataframe__(self): - """Load dataframe from pickle file. - - COMBAK and finish this - """ - #| - __load_dataframe__ - tmp = 42 - - #__| - - def create_charge_density_plotting_trace(self, - opacity=0.4, - size=4, - ): - """Create plotly trace from charge density distribution. - - Args: - opacity: - size: - or - Either a float to represent a constant size - or - "variable", to scale individual marker size with charge density - - """ - #| - create_charge_density_plotting_trace - df = self.master_data_df - - if size == "variable": - size = df["norm_dens"] * 13. - - trace1 = go.Scatter3d( - - x=df["x_coord"], - y=df["y_coord"], - z=df["z_coord"], - - # x=df["x_coord_norm"], - # y=df["y_coord_norm"], - # z=df["z_coord_norm"], - - # x=df["x_ind"], - # y=df["y_ind"], - # z=df["z_ind"], - - mode='markers', - text=df["norm_dens"], - opacity=opacity, - marker=dict( - size=size, - color=df["norm_dens"], - - colorscale=[ - [0., 'rgb(255, 200, 200, 0.1)'], - [1.0, 'rgb(255, 0, 0, 0.9)'], - ], - ) - ) - - return(trace1) - #__| - - def create_unit_cell_plotting_trace(self, - color="red", - width=1., - ): - """TEMP. - - Args: - color - """ - #| - create_unit_cell_plotting_trace - atoms = self.atoms - - def unit_cell_leg_trace( - point_0, - point_1, - color="red", - width=1., - ): - """Create trace for unit cell line. - - Args: - point_0: - point_1: - color: - width: - """ - #| - unit_cell_leg_trace - line_i = np.array([ - point_0, - point_1, - ]) - - trace_i = go.Scatter3d( - x=line_i[:, 0], y=line_i[:, 1], z=line_i[:, 2], - mode="lines", - line=dict( - color=color, - width=width, - ) - ) - - return(trace_i) - #__| - - line_trace_list = [ - - #| - Origin to 3 adjacent corners - unit_cell_leg_trace( - np.array([0., 0., 0.]), - atoms.cell[0], - ), - - unit_cell_leg_trace( - np.array([0., 0., 0.]), - atoms.cell[1], - ), - - unit_cell_leg_trace( - np.array([0., 0., 0.]), - atoms.cell[2], - ), - #__| - - #| - Farthest corner and 3 adjacent cornerse - unit_cell_leg_trace( - atoms.cell[0] + atoms.cell[1] + atoms.cell[2], - atoms.cell[0] + atoms.cell[2] - ), - - unit_cell_leg_trace( - atoms.cell[0] + atoms.cell[1] + atoms.cell[2], - atoms.cell[1] + atoms.cell[2] - ), - - unit_cell_leg_trace( - atoms.cell[0] + atoms.cell[1] + atoms.cell[2], - atoms.cell[0] + atoms.cell[1] - ), - #__| - - #| - TEMP - unit_cell_leg_trace( - atoms.cell[1] + atoms.cell[2], - atoms.cell[1], - color=color, - ), - - unit_cell_leg_trace( - atoms.cell[0] + atoms.cell[2], - atoms.cell[0], - color=color, - ), - #__| - - #| - TEMP - unit_cell_leg_trace( - atoms.cell[2], - atoms.cell[0] + atoms.cell[2], - color=color, - - ), - - unit_cell_leg_trace( - atoms.cell[2], - atoms.cell[1] + atoms.cell[2], - color=color, - ), - #__| - - #| - TEMP - unit_cell_leg_trace( - atoms.cell[0] + atoms.cell[1], - atoms.cell[0], - color=color, - ), - - unit_cell_leg_trace( - atoms.cell[0] + atoms.cell[1], - atoms.cell[1], - color=color, - ), - #__| - - ] - - return(line_trace_list) - #__| - - def create_atoms_plotting_trace(self, - size=12, - ): - """Create atom positions plotly trace. - - Args: - size: - """ - #| - create_atoms_plotting_trace - atoms = self.atoms - - element_color_dict = {} - element_color_dict["Fe"] = "orange" - element_color_dict["C"] = "grey" - element_color_dict["N"] = "blue" - - color_list = [] - for atom in atoms: - elem = atom.symbol - color_list.append(element_color_dict[elem]) - - trace_i = go.Scatter3d( - x=atoms.positions[:, 0], - y=atoms.positions[:, 1], - z=atoms.positions[:, 2], - mode='markers', - - marker=dict( - size=size, - color=color_list, - ) - ) - - return(trace_i) - #__| - - #__| ********************************************************************** +#!/usr/bin/env python + +"""Charge density class. + +Author: Raul A. Flores +""" + +#| - Import Modules +# import os +# import sys +import random +import pickle + +import pandas as pd +import numpy as np +from ase.io.cube import read_cube +# , write_cube +# read_cube_data, + +# import plotly as py +import plotly.graph_objs as go +#__| + +class ChargeDensity(object): + """docstring for ChargeDensity.""" + + #| - ChargeDensity ******************************************************** + def __init__(self, + cube_filename, + master_data_filter=0.98, + lower_bound_density_filter=0.025, + + wrap_atoms=True, + working_dir=".", + ): + """Initialize ChargeDensity instance. + + Args: + cube_filename: + master_data_filter: + Fraction of data to be removed randomly + lower_bound_density_filter: + Lower bound of normalized density value to be discarded + working_dir: + """ + #| - __init__ + + #| - Define User Attributes + self.cube_filename = cube_filename + self.master_data_filter = master_data_filter + self.lower_bound_density_filter = lower_bound_density_filter + self.wrap_atoms = wrap_atoms + self.working_dir = working_dir + #__| + + ( + self.atoms, + self.cd_data, + self.origin, + ) = self.__load_cube_file__() + + + self.master_data_df = self.__process_data__() + + # self.__save_dataframe__() + + self.num_data_points = self.__number_of_data_points__() + + self.__filter_data__() + self.__norm_electron_density__() + self.__filter_low_density__() + # self.__keep_only_edges__() + #__| + + def __load_cube_file__(self): + """Load charge density cube file.""" + #| - __load_cube_file__ + filename = self.cube_filename + + with open(filename, "r") as fle: + data_master = read_cube(fle) + + atoms = data_master["atoms"] + cd_data = data_master["data"] + origin = data_master["origin"] + + if self.wrap_atoms: + atoms.wrap(pbc=True) + + return(atoms, cd_data, origin) + #__| + + def __process_data__(self): + """Create dataframe from charge density data grid.""" + #| - __process_data__ + cd_data = self.cd_data + atoms = self.atoms + + master_data_list = [] + for index, dens_i in np.ndenumerate(cd_data): + data_i = {} + data_i["x_ind"] = index[0] + data_i["y_ind"] = index[1] + data_i["z_ind"] = index[2] + data_i["density"] = dens_i + + master_data_list.append(data_i) + + df = pd.DataFrame(master_data_list) + + df["x_coord_norm"] = df["x_ind"] / df["x_ind"].max() + df["y_coord_norm"] = df["y_ind"] / df["y_ind"].max() + df["z_coord_norm"] = df["z_ind"] / df["z_ind"].max() + + df["x_coord"] = df["x_coord_norm"] * atoms.cell[:, 0].sum() + df["y_coord"] = df["y_coord_norm"] * atoms.cell[:, 1].sum() + df["z_coord"] = df["z_coord_norm"] * atoms.cell[:, 2].sum() + + def multiply_by_unit_cell(row, atoms=None): + coord = np.array([ + row["x_coord_norm"], + row["y_coord_norm"], + row["z_coord_norm"], + ]) + + scaled_cell_vectors = (atoms.cell.T * coord).T + + new_coord = np.array([ + scaled_cell_vectors[:, 0].sum(), + scaled_cell_vectors[:, 1].sum(), + scaled_cell_vectors[:, 2].sum(), + ]) + + # new_coord = atoms.cell.dot(coord) + + return(new_coord[0], new_coord[1], new_coord[2]) + + ( + df["x_coord"], + df["y_coord"], + df["z_coord"], + ) = zip(*df.apply(multiply_by_unit_cell, axis=1, atoms=atoms)) + + return(df) + #__| + + def __number_of_data_points__(self): + """Return the number of individual density data points.""" + #| - __number_of_data_points__ + master_data_df = self.master_data_df + + num_data_points = len(master_data_df) + + return(num_data_points) + #__| + + def __filter_data__(self): + """Filter data randomly to decrease the data set size.""" + #| - __filter_data__ + master_data_df = self.master_data_df + num_data_points = self.num_data_points + master_data_filter = self.master_data_filter + + bool_list = [] + for data_i in range(num_data_points): + rand_i = random.random() + if rand_i > master_data_filter: + bool_list.append(True) + else: + bool_list.append(False) + + df_filtered = master_data_df[bool_list] + + self.master_data_df = df_filtered + #__| + + def __norm_electron_density__(self): + """Normalize electron density from 0 to 1.""" + #| - __norm_electron_density__ + df = self.master_data_df + + max_density = df.density.max() + df["norm_dens"] = df["density"] / max_density + #__| + + def __filter_low_density__(self): + """Filter low density entries from the data.""" + #| - __filter_low_density__ + df = self.master_data_df + lower_bound_density_filter = self.lower_bound_density_filter + + df = df[df["norm_dens"] > lower_bound_density_filter] + + self.master_data_df = df + #__| + + def __keep_only_edges__(self): + """Only keep the outer surface points for clarity.""" + #| - __keep_only_edges__ + df = self.master_data_df + + df_a = df[df["x_ind"] == df.x_ind.max()] + df_b = df[df["y_ind"] == df.y_ind.max()] + df_c = df[df["z_ind"] == df.z_ind.max()] + + df_1 = df[df["x_ind"] == 0] + df_2 = df[df["y_ind"] == 0] + df_3 = df[df["z_ind"] == 0] + + df_surf = pd.concat( + [ + df_a, df_b, df_c, + df_1, df_2, df_3, + ] + ) + + self.master_data_df = df_surf + #__| + + def __save_dataframe__(self): + """Save dataframe to pickle file. + + COMBAK impliment this to save time + """ + #| - __save_dataframe__ + df = self.master_data_df + working_dir = self.working_dir + + with open(working_dir + "/dataframe.pickle", "w") as fle: + pickle.dump(df, fle) + #__| + + def __load_dataframe__(self): + """Load dataframe from pickle file. + + COMBAK and finish this + """ + #| - __load_dataframe__ + tmp = 42 + + #__| + + def create_charge_density_plotting_trace(self, + opacity=0.4, + size=4, + ): + """Create plotly trace from charge density distribution. + + Args: + opacity: + size: + or + Either a float to represent a constant size + or + "variable", to scale individual marker size with charge density + + """ + #| - create_charge_density_plotting_trace + df = self.master_data_df + + if size == "variable": + size = df["norm_dens"] * 13. + + trace1 = go.Scatter3d( + + x=df["x_coord"], + y=df["y_coord"], + z=df["z_coord"], + + # x=df["x_coord_norm"], + # y=df["y_coord_norm"], + # z=df["z_coord_norm"], + + # x=df["x_ind"], + # y=df["y_ind"], + # z=df["z_ind"], + + mode='markers', + text=df["norm_dens"], + opacity=opacity, + marker=dict( + size=size, + color=df["norm_dens"], + + colorscale=[ + [0., 'rgb(255, 200, 200, 0.1)'], + [1.0, 'rgb(255, 0, 0, 0.9)'], + ], + ) + ) + + return(trace1) + #__| + + def create_unit_cell_plotting_trace(self, + color="red", + width=1., + ): + """TEMP. + + Args: + color + """ + #| - create_unit_cell_plotting_trace + atoms = self.atoms + + def unit_cell_leg_trace( + point_0, + point_1, + color="red", + width=1., + ): + """Create trace for unit cell line. + + Args: + point_0: + point_1: + color: + width: + """ + #| - unit_cell_leg_trace + line_i = np.array([ + point_0, + point_1, + ]) + + trace_i = go.Scatter3d( + x=line_i[:, 0], y=line_i[:, 1], z=line_i[:, 2], + mode="lines", + line=dict( + color=color, + width=width, + ) + ) + + return(trace_i) + #__| + + line_trace_list = [ + + #| - Origin to 3 adjacent corners + unit_cell_leg_trace( + np.array([0., 0., 0.]), + atoms.cell[0], + ), + + unit_cell_leg_trace( + np.array([0., 0., 0.]), + atoms.cell[1], + ), + + unit_cell_leg_trace( + np.array([0., 0., 0.]), + atoms.cell[2], + ), + #__| + + #| - Farthest corner and 3 adjacent cornerse + unit_cell_leg_trace( + atoms.cell[0] + atoms.cell[1] + atoms.cell[2], + atoms.cell[0] + atoms.cell[2] + ), + + unit_cell_leg_trace( + atoms.cell[0] + atoms.cell[1] + atoms.cell[2], + atoms.cell[1] + atoms.cell[2] + ), + + unit_cell_leg_trace( + atoms.cell[0] + atoms.cell[1] + atoms.cell[2], + atoms.cell[0] + atoms.cell[1] + ), + #__| + + #| - TEMP + unit_cell_leg_trace( + atoms.cell[1] + atoms.cell[2], + atoms.cell[1], + color=color, + ), + + unit_cell_leg_trace( + atoms.cell[0] + atoms.cell[2], + atoms.cell[0], + color=color, + ), + #__| + + #| - TEMP + unit_cell_leg_trace( + atoms.cell[2], + atoms.cell[0] + atoms.cell[2], + color=color, + + ), + + unit_cell_leg_trace( + atoms.cell[2], + atoms.cell[1] + atoms.cell[2], + color=color, + ), + #__| + + #| - TEMP + unit_cell_leg_trace( + atoms.cell[0] + atoms.cell[1], + atoms.cell[0], + color=color, + ), + + unit_cell_leg_trace( + atoms.cell[0] + atoms.cell[1], + atoms.cell[1], + color=color, + ), + #__| + + ] + + return(line_trace_list) + #__| + + def create_atoms_plotting_trace(self, + size=12, + ): + """Create atom positions plotly trace. + + Args: + size: + """ + #| - create_atoms_plotting_trace + atoms = self.atoms + + element_color_dict = {} + element_color_dict["Fe"] = "orange" + element_color_dict["C"] = "grey" + element_color_dict["N"] = "blue" + + color_list = [] + for atom in atoms: + elem = atom.symbol + color_list.append(element_color_dict[elem]) + + trace_i = go.Scatter3d( + x=atoms.positions[:, 0], + y=atoms.positions[:, 1], + z=atoms.positions[:, 2], + mode='markers', + + marker=dict( + size=size, + color=color_list, + ) + ) + + return(trace_i) + #__| + + #__| ********************************************************************** diff --git a/dft_post_analysis/dos.py b/dft_post_analysis/dos.py index 7a9f35f..e56f9ca 100644 --- a/dft_post_analysis/dos.py +++ b/dft_post_analysis/dos.py @@ -1,398 +1,398 @@ -#!/usr/bin/env python - -"""Plot projected density of states data. - -Author: Raul A. Flores - -Development Notes: - TODO Include the atoms object so that I can reference atom types -""" - -#| - Import Modules -import copy -from itertools import compress - -import numpy as np -import pandas as pd -import plotly.graph_objs as go - -from misc_modules.numpy_methods import make_filter_list -#__| - -#| - Methods -def plot_dos_series( - x_data, - y_data, - name, - group=None, - ): - """Plot DOS data series. - - Args: - - """ - #| - plot_dos_series - trace = go.Scatter( - x=x_data, - y=y_data, - name=name, - text=name, - fill="tozerox", - hoverinfo="y+text", - legendgroup=group, - ) - - return(trace) - #__| - -#__| - -def filter_pdos_data(pdos_data, percent_keep=0.4): - """Filter dos and pdos data series to lower memory cost. - - Args: - pdos_data: - percent_keep: - Fraction of data to keep, the rest is discarded - """ - #| - filter_pdos_data - len_data = len(pdos_data[0]) - filter_list = make_filter_list(len_data, percent_keep) - - # -------------------------------------------------------------------------------------- - - new_pdos_data = () - - # ************************** - new_pdos_data += (np.array(list(compress(pdos_data[0], filter_list))),) - - # ************************** - len_data = len(pdos_data[1]) - if len_data == 2: - tuple_2 = [ - np.array(list(compress(pdos_data[1][0], filter_list))), - np.array(list(compress(pdos_data[1][1], filter_list))) - ] - - else: - tuple_2 = np.array(list(compress(pdos_data[1], filter_list))) - - - new_pdos_data += (tuple_2,) - - # ************************** - new_list = [] - for i_ind, atom_i in enumerate(pdos_data[2]): - dict_i = {} - for key, value in atom_i.items(): - - series_list_new = [] - for j_ind, data_series_i in enumerate(value): - tmp = np.array(list(compress(data_series_i, filter_list))) - series_list_new.append(tmp) - - dict_i[key] = series_list_new - - new_list.append(dict_i) - - new_pdos_data += (new_list,) - - - return(new_pdos_data) - #__| - -def plot_pdos_dos( - pdos_data, - atoms, - filter_dict=None, - group=None, - e_range=[-6, 3], # COMBAK - plot_title="Projected Density of States", - ): - """Create PDOS plot data. - - Args: - pdos_data: - filter_dict: - atoms: - """ - #| - plot_pdos_dos - energies, dos, pdos = pdos_data - - #| - Determing Whether Calclation Is Spin Polarized - if len(dos) != 2: - spinpol = False - elif len(dos) == 2: - spinpol = True - #__| - - #| - Data Processing - - #| - Total Density of State - dos_data = [] - if spinpol: - dos_tot_u = dos[0] - dos_tot_d = dos[1] - assert len(energies) == len(dos_tot_u) - assert len(energies) == len(dos_tot_d) - - # Plot Total DOS Spin Up - trace = go.Scatter( - x=dos_tot_u, - y=energies, - name="DOS (spin up)", - fill="tozerox", - hoverinfo="y+text", - ) - dos_data.append(trace) - - # Plot Total DOS Spin Down - trace = go.Scatter( - x=dos_tot_d, - y=energies, - name="DOS (spin down)", - fill="tozerox", - hoverinfo="y+text", - ) - dos_data.append(trace) - - else: - dos_tot = dos - assert len(energies) == len(dos_tot) - - trace = go.Scatter( - x=dos_tot, - y=energies, - - name="DOS", - ) - - dos_data.append(trace) - - #__| - - #| - Atomic Projected Density of State - pdos_master_data = [] - - if spinpol: - #| - Spinpol: True - for pdos_i, atom_i in zip(pdos, atoms): - elem_i = atom_i.symbol - ind_i = atom_i.index - - #| - Data Format Type Dict - type_dict = {} - - type_dict["p"] = [ - "sum-up", - "sum-down", - - "pz-up", - "pz-down", - - "px-up", - "px-down", - - "py-up", - "py-down", - ] - - type_dict["s"] = [ - "sum-up", - "sum-down", - - "s-up", - "s-down", - ] - - type_dict["d"] = [ - "sum-up", - "sum-down", - - "dz2-up", - "dz2-down", - - "dzx-up", - "dzx-down", - - "dzy-up", - "dzy-down", - - "dx2-y2 up", - "dx2-y2 down", - - "dxy up", - "dxy down", - ] - #__| - - # for band_j, dos_j in pdos_i.iteritems(): - for band_j, dos_j in pdos_i.items(): - - for k_ind, type_k in enumerate(type_dict[band_j]): - - row_i = { - "band": band_j, - "element": elem_i, - "atom_ind": ind_i, - "type": type_k, - "pdos": dos_j[k_ind], - } - - pdos_master_data.append(row_i) - #__| - - else: - #| - Spinpol: False - - #| - Data Format Type Dict - type_dict = {} - type_dict["p"] = [ - "sum", - "pz", - "px", - "py", - ] - - type_dict["s"] = [ - "sum", - "s", - ] - - type_dict["d"] = [ - "sum", - "dz2", - "dzx", - "dzy", - "dx2-y2", - "dxy", - ] - #__| - - pdos_master_data = [] - for pdos_i, atom_i in zip(pdos, atoms): - - elem_i = atom_i.symbol - ind_i = atom_i.index - - for band_j, dos_j in pdos_i.items(): - for k_ind, type_k in enumerate(type_dict[band_j]): - row_i = { - "band": band_j, - "element": elem_i, - "atom_ind": ind_i, - "type": type_k, - "pdos": dos_j[k_ind], - } - - pdos_master_data.append(row_i) - #__| - - #__| - - df = pd.DataFrame(pdos_master_data) - #__| - - #| - Data Analysis - df["name"] = df["element"] + df["atom_ind"].astype(str) + " | " + \ - df["band"] + df["type"] - - df["max_dens"] = df["pdos"].map(lambda x: x.max()) - max_dens = df["max_dens"].max() - - # Filter Data - if filter_dict is None: - filter_dict = {} - - for key, value in filter_dict.items(): - df = df[df[key].isin(value)] - - #__| - - #| - Plotly Scatter Plot Creation - data = [] - for index, row in df.iterrows(): - if group is not None: - group_col = row[group] - else: - group_col = None - - data_i = plot_dos_series( - row["pdos"], - energies, - row["name"], - group=group_col, - ) - - data.append(data_i) - - pdos_data_out = data - #__| - - - - #| - Plotting - - #| - Plot Settings - plot_title_size = 20 - tick_lab_size = 16 - axes_lab_size = 18 - legend_size = 18 - #__| - - #| - Plot Layout - layout = { - "title": plot_title, - "font": { - "family": "Courier New, monospace", - "size": plot_title_size, - "color": "black", - }, - - #| - Axes ------------------------------------------------------------- - "yaxis": { - "title": "E - Efermi [eV]", - "zeroline": True, - "titlefont": dict(size=axes_lab_size), - "showgrid": False, - "range": e_range, - - "tickfont": dict( - size=tick_lab_size, - ), - # gridwidth = 2, - }, - - "xaxis": { - "title": "Density of States", - "zeroline": False, - "titlefont": dict(size=axes_lab_size), - - "tickfont": dict( - size=tick_lab_size, - ), - "showticklabels": False, - "range": [0, max_dens], - }, - #__| ------------------------------------------------------------------ - - #| - Legend ----------------------------------------------------------- - "legend": { - "traceorder": "normal", - "font": dict(size=legend_size) - }, - - #__| ------------------------------------------------------------------ - - #| - Plot Size - # "width": 200 * 4., - # "height": 200 * 3., - #__| - - } - #__| - - #__| - - return(dos_data, pdos_data_out, layout) - #__| +#!/usr/bin/env python + +"""Plot projected density of states data. + +Author: Raul A. Flores + +Development Notes: + TODO Include the atoms object so that I can reference atom types +""" + +#| - Import Modules +import copy +from itertools import compress + +import numpy as np +import pandas as pd +import plotly.graph_objs as go + +from misc_modules.numpy_methods import make_filter_list +#__| + +#| - Methods +def plot_dos_series( + x_data, + y_data, + name, + group=None, + ): + """Plot DOS data series. + + Args: + + """ + #| - plot_dos_series + trace = go.Scatter( + x=x_data, + y=y_data, + name=name, + text=name, + fill="tozerox", + hoverinfo="y+text", + legendgroup=group, + ) + + return(trace) + #__| + +#__| + +def filter_pdos_data(pdos_data, percent_keep=0.4): + """Filter dos and pdos data series to lower memory cost. + + Args: + pdos_data: + percent_keep: + Fraction of data to keep, the rest is discarded + """ + #| - filter_pdos_data + len_data = len(pdos_data[0]) + filter_list = make_filter_list(len_data, percent_keep) + + # -------------------------------------------------------------------------------------- + + new_pdos_data = () + + # ************************** + new_pdos_data += (np.array(list(compress(pdos_data[0], filter_list))),) + + # ************************** + len_data = len(pdos_data[1]) + if len_data == 2: + tuple_2 = [ + np.array(list(compress(pdos_data[1][0], filter_list))), + np.array(list(compress(pdos_data[1][1], filter_list))) + ] + + else: + tuple_2 = np.array(list(compress(pdos_data[1], filter_list))) + + + new_pdos_data += (tuple_2,) + + # ************************** + new_list = [] + for i_ind, atom_i in enumerate(pdos_data[2]): + dict_i = {} + for key, value in atom_i.items(): + + series_list_new = [] + for j_ind, data_series_i in enumerate(value): + tmp = np.array(list(compress(data_series_i, filter_list))) + series_list_new.append(tmp) + + dict_i[key] = series_list_new + + new_list.append(dict_i) + + new_pdos_data += (new_list,) + + + return(new_pdos_data) + #__| + +def plot_pdos_dos( + pdos_data, + atoms, + filter_dict=None, + group=None, + e_range=[-6, 3], # COMBAK + plot_title="Projected Density of States", + ): + """Create PDOS plot data. + + Args: + pdos_data: + filter_dict: + atoms: + """ + #| - plot_pdos_dos + energies, dos, pdos = pdos_data + + #| - Determing Whether Calclation Is Spin Polarized + if len(dos) != 2: + spinpol = False + elif len(dos) == 2: + spinpol = True + #__| + + #| - Data Processing + + #| - Total Density of State + dos_data = [] + if spinpol: + dos_tot_u = dos[0] + dos_tot_d = dos[1] + assert len(energies) == len(dos_tot_u) + assert len(energies) == len(dos_tot_d) + + # Plot Total DOS Spin Up + trace = go.Scatter( + x=dos_tot_u, + y=energies, + name="DOS (spin up)", + fill="tozerox", + hoverinfo="y+text", + ) + dos_data.append(trace) + + # Plot Total DOS Spin Down + trace = go.Scatter( + x=dos_tot_d, + y=energies, + name="DOS (spin down)", + fill="tozerox", + hoverinfo="y+text", + ) + dos_data.append(trace) + + else: + dos_tot = dos + assert len(energies) == len(dos_tot) + + trace = go.Scatter( + x=dos_tot, + y=energies, + + name="DOS", + ) + + dos_data.append(trace) + + #__| + + #| - Atomic Projected Density of State + pdos_master_data = [] + + if spinpol: + #| - Spinpol: True + for pdos_i, atom_i in zip(pdos, atoms): + elem_i = atom_i.symbol + ind_i = atom_i.index + + #| - Data Format Type Dict + type_dict = {} + + type_dict["p"] = [ + "sum-up", + "sum-down", + + "pz-up", + "pz-down", + + "px-up", + "px-down", + + "py-up", + "py-down", + ] + + type_dict["s"] = [ + "sum-up", + "sum-down", + + "s-up", + "s-down", + ] + + type_dict["d"] = [ + "sum-up", + "sum-down", + + "dz2-up", + "dz2-down", + + "dzx-up", + "dzx-down", + + "dzy-up", + "dzy-down", + + "dx2-y2 up", + "dx2-y2 down", + + "dxy up", + "dxy down", + ] + #__| + + # for band_j, dos_j in pdos_i.iteritems(): + for band_j, dos_j in pdos_i.items(): + + for k_ind, type_k in enumerate(type_dict[band_j]): + + row_i = { + "band": band_j, + "element": elem_i, + "atom_ind": ind_i, + "type": type_k, + "pdos": dos_j[k_ind], + } + + pdos_master_data.append(row_i) + #__| + + else: + #| - Spinpol: False + + #| - Data Format Type Dict + type_dict = {} + type_dict["p"] = [ + "sum", + "pz", + "px", + "py", + ] + + type_dict["s"] = [ + "sum", + "s", + ] + + type_dict["d"] = [ + "sum", + "dz2", + "dzx", + "dzy", + "dx2-y2", + "dxy", + ] + #__| + + pdos_master_data = [] + for pdos_i, atom_i in zip(pdos, atoms): + + elem_i = atom_i.symbol + ind_i = atom_i.index + + for band_j, dos_j in pdos_i.items(): + for k_ind, type_k in enumerate(type_dict[band_j]): + row_i = { + "band": band_j, + "element": elem_i, + "atom_ind": ind_i, + "type": type_k, + "pdos": dos_j[k_ind], + } + + pdos_master_data.append(row_i) + #__| + + #__| + + df = pd.DataFrame(pdos_master_data) + #__| + + #| - Data Analysis + df["name"] = df["element"] + df["atom_ind"].astype(str) + " | " + \ + df["band"] + df["type"] + + df["max_dens"] = df["pdos"].map(lambda x: x.max()) + max_dens = df["max_dens"].max() + + # Filter Data + if filter_dict is None: + filter_dict = {} + + for key, value in filter_dict.items(): + df = df[df[key].isin(value)] + + #__| + + #| - Plotly Scatter Plot Creation + data = [] + for index, row in df.iterrows(): + if group is not None: + group_col = row[group] + else: + group_col = None + + data_i = plot_dos_series( + row["pdos"], + energies, + row["name"], + group=group_col, + ) + + data.append(data_i) + + pdos_data_out = data + #__| + + + + #| - Plotting + + #| - Plot Settings + plot_title_size = 20 + tick_lab_size = 16 + axes_lab_size = 18 + legend_size = 18 + #__| + + #| - Plot Layout + layout = { + "title": plot_title, + "font": { + "family": "Courier New, monospace", + "size": plot_title_size, + "color": "black", + }, + + #| - Axes ------------------------------------------------------------- + "yaxis": { + "title": "E - Efermi [eV]", + "zeroline": True, + "titlefont": dict(size=axes_lab_size), + "showgrid": False, + "range": e_range, + + "tickfont": dict( + size=tick_lab_size, + ), + # gridwidth = 2, + }, + + "xaxis": { + "title": "Density of States", + "zeroline": False, + "titlefont": dict(size=axes_lab_size), + + "tickfont": dict( + size=tick_lab_size, + ), + "showticklabels": False, + "range": [0, max_dens], + }, + #__| ------------------------------------------------------------------ + + #| - Legend ----------------------------------------------------------- + "legend": { + "traceorder": "normal", + "font": dict(size=legend_size) + }, + + #__| ------------------------------------------------------------------ + + #| - Plot Size + # "width": 200 * 4., + # "height": 200 * 3., + #__| + + } + #__| + + #__| + + return(dos_data, pdos_data_out, layout) + #__| diff --git a/dft_post_analysis/dos_bands_combined.py b/dft_post_analysis/dos_bands_combined.py index 5e2df8b..9c2587c 100644 --- a/dft_post_analysis/dos_bands_combined.py +++ b/dft_post_analysis/dos_bands_combined.py @@ -1,83 +1,83 @@ -#!/usr/bin/env python - -"""Plot pdos and bands side-by-side. - -Author: Raul A. Flores -""" - -#| - IMPORT MODULES -from plotly import tools -#__| - - -# pdos_data_out, -# bands_data, -# dos_layout, -# bands_layout, -# plot_title=plot_title, -# subplot_titles=("C-PDOS (N adjacent)", "Bands"), - -def plot_pdos_bands( - pdos_data, - dos_data, - bands_data, - - pdos_layout, - bands_layout, - - e_range=[-15, 10], - - plot_dos=True, - plot_title="PDOS and Band Diagram", - subplot_titles=("PDOS", "Bands"), - ): - """Plots pdos and bands in adjacent subplots. - - Args: - pdos_data: - bands_data: - pdos_layout: - bands_layout: - """ - #| - plot_pdos_bands - # TEMP_PRINT - print("KSDKFJDSJIFJSIDJFISD") - - fig = tools.make_subplots( - rows=1, - cols=2, - shared_yaxes=True, - subplot_titles=subplot_titles, - ) - - for trace_i in pdos_data: - fig.append_trace(trace_i, 1, 1) - - if plot_dos: - for trace_i in dos_data: - fig.append_trace(trace_i, 1, 1) - - for trace_i in bands_data: - fig.append_trace(trace_i, 1, 2) - - fig["layout"].update( - # height=600, - # width=600, - - title=plot_title, - - # xaxis1=pdos_layout["xaxis"], - # xaxis2=bands_layout["xaxis"], - - font={ - "family": "Courier New, monospace", - "size": 18, - "color": "black", - }, - ) - - fig["layout"]["yaxis"].update(bands_layout["yaxis"]) - fig["layout"]["yaxis"]["range"] = e_range - - return(fig) - #__| +#!/usr/bin/env python + +"""Plot pdos and bands side-by-side. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +from plotly import tools +#__| + + +# pdos_data_out, +# bands_data, +# dos_layout, +# bands_layout, +# plot_title=plot_title, +# subplot_titles=("C-PDOS (N adjacent)", "Bands"), + +def plot_pdos_bands( + pdos_data, + dos_data, + bands_data, + + pdos_layout, + bands_layout, + + e_range=[-15, 10], + + plot_dos=True, + plot_title="PDOS and Band Diagram", + subplot_titles=("PDOS", "Bands"), + ): + """Plots pdos and bands in adjacent subplots. + + Args: + pdos_data: + bands_data: + pdos_layout: + bands_layout: + """ + #| - plot_pdos_bands + # TEMP_PRINT + print("KSDKFJDSJIFJSIDJFISD") + + fig = tools.make_subplots( + rows=1, + cols=2, + shared_yaxes=True, + subplot_titles=subplot_titles, + ) + + for trace_i in pdos_data: + fig.append_trace(trace_i, 1, 1) + + if plot_dos: + for trace_i in dos_data: + fig.append_trace(trace_i, 1, 1) + + for trace_i in bands_data: + fig.append_trace(trace_i, 1, 2) + + fig["layout"].update( + # height=600, + # width=600, + + title=plot_title, + + # xaxis1=pdos_layout["xaxis"], + # xaxis2=bands_layout["xaxis"], + + font={ + "family": "Courier New, monospace", + "size": 18, + "color": "black", + }, + ) + + fig["layout"]["yaxis"].update(bands_layout["yaxis"]) + fig["layout"]["yaxis"]["range"] = e_range + + return(fig) + #__| diff --git a/dft_post_analysis/wf.py b/dft_post_analysis/wf.py index 364cc74..d229eb4 100644 --- a/dft_post_analysis/wf.py +++ b/dft_post_analysis/wf.py @@ -1,115 +1,115 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -"""Calculate and return work function for periodic slab. - -Author(s): I got the script from Colin but I think Karen wrote these methods -""" - -#| - Import Modules -# from ase.units import Bohr -# from ase.io import read -import numpy as np -import os -#__| - -def find_max_empty_space(atoms, edir=3): - """Return scaled midpoint coordinate of largest empty space. - - Assuming periodic boundary conditions, finds the largest - continuous segment of free, unoccupied space and returns its midpoint - in scaled coordinates (0 to 1) in the edir direction (default z). - """ - #| - find_max_empty_space - # 0-indexed direction - position_array = atoms.get_scaled_positions()[..., edir - 1] - position_array.sort() - differences = np.diff(position_array) - # through the PBC - differences = np.append( - differences, - position_array[0] + 1 - position_array[-1], - ) - max_diff_index = np.argmax(differences) - if max_diff_index == len(position_array) - 1: - out = (position_array[0] + 1 + position_array[-1]) / 2 % 1 - return(out) - else: - out = (position_array[max_diff_index] + - position_array[max_diff_index + 1]) / 2. - return(out) - #__| - -def calc_wf(atoms, outdir): - """Calculate work function of slab. - - Args: - atoms: - outdir: - """ - #| - calc_wf - hartree = 27.21138505 - rydberg = 0.5 * hartree - bohr = 0.52917721092 - - # rydberg_over_bohr = rydberg / bohr - - # Pick a good place to sample vacuum level - edir = 3 - cell_length = atoms.cell[edir - 1][edir - 1] / bohr - - vacuum_pos_raw = find_max_empty_space(atoms, edir) - - vacuum_pos = vacuum_pos_raw * cell_length - avg_out = open("%s/avg.out" % outdir, "r") - record = False - average_data = [] - lines = list(avg_out) - for line in lines: - # just start reading it in at 0 - if len(line.split()) == 3 and line.split()[0] == "0.000000000": - record = True - elif len(line.split()) == 0: - record = False - if record is True: - average_data.append([float(i) for i in line.split()]) - - #vacuum_energy = average_data[np.abs(np.array(average_data)[..., 0] - - # vacuum_pos).argmin()][2] - - # Get the latest Fermi energy - fermi_data = os.popen('grep -n "Fermi" %s/log | tail -1' % outdir, "r") - fermi_energy = float(fermi_data.readline().split()[-2]) - fermi_data.close() - eopreg = 0.025 - - # we use cell_length*eopreg*3 here since the work functions seem to - # converge at that distance rather than *1 or *2 - vac1guess = vacuum_pos - cell_length * eopreg * 2.5 - vac2guess = vacuum_pos + cell_length * eopreg * 2.5 - if vac1guess < 0: - #look for where we're closest to zero - vac_pos1 = np.abs(cell_length + vacuum_pos - cell_length * - eopreg * 2.5 - np.array(average_data)[..., 0]).argmin() - #print 'shifted vac1 for %s'%outdir - else: - vac_pos1 = np.abs(np.array(average_data)[..., 0] - - vacuum_pos + cell_length * eopreg * 2.5).argmin() - #print 'normal vac1' - if vac2guess > cell_length: - vac_pos2 = np.abs(vacuum_pos + cell_length * eopreg * 2.5 - - cell_length - np.array(average_data)[..., 0]).argmin() - #print 'shifted vac2 for %s'%outdir - else: - vac_pos2 = np.abs(np.array(average_data)[..., 0] - vacuum_pos - - cell_length * eopreg * 2.5).argmin() - #print 'normal vac2' - vacuum_energy1 = average_data[vac_pos1][1] - vacuum_energy2 = average_data[vac_pos2][1] - wf = [ - vacuum_energy1 * rydberg - fermi_energy, - vacuum_energy2 * rydberg - fermi_energy, - ] - - return(wf) - #__| +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Calculate and return work function for periodic slab. + +Author(s): I got the script from Colin but I think Karen wrote these methods +""" + +#| - Import Modules +# from ase.units import Bohr +# from ase.io import read +import numpy as np +import os +#__| + +def find_max_empty_space(atoms, edir=3): + """Return scaled midpoint coordinate of largest empty space. + + Assuming periodic boundary conditions, finds the largest + continuous segment of free, unoccupied space and returns its midpoint + in scaled coordinates (0 to 1) in the edir direction (default z). + """ + #| - find_max_empty_space + # 0-indexed direction + position_array = atoms.get_scaled_positions()[..., edir - 1] + position_array.sort() + differences = np.diff(position_array) + # through the PBC + differences = np.append( + differences, + position_array[0] + 1 - position_array[-1], + ) + max_diff_index = np.argmax(differences) + if max_diff_index == len(position_array) - 1: + out = (position_array[0] + 1 + position_array[-1]) / 2 % 1 + return(out) + else: + out = (position_array[max_diff_index] + + position_array[max_diff_index + 1]) / 2. + return(out) + #__| + +def calc_wf(atoms, outdir): + """Calculate work function of slab. + + Args: + atoms: + outdir: + """ + #| - calc_wf + hartree = 27.21138505 + rydberg = 0.5 * hartree + bohr = 0.52917721092 + + # rydberg_over_bohr = rydberg / bohr + + # Pick a good place to sample vacuum level + edir = 3 + cell_length = atoms.cell[edir - 1][edir - 1] / bohr + + vacuum_pos_raw = find_max_empty_space(atoms, edir) + + vacuum_pos = vacuum_pos_raw * cell_length + avg_out = open("%s/avg.out" % outdir, "r") + record = False + average_data = [] + lines = list(avg_out) + for line in lines: + # just start reading it in at 0 + if len(line.split()) == 3 and line.split()[0] == "0.000000000": + record = True + elif len(line.split()) == 0: + record = False + if record is True: + average_data.append([float(i) for i in line.split()]) + + #vacuum_energy = average_data[np.abs(np.array(average_data)[..., 0] - + # vacuum_pos).argmin()][2] + + # Get the latest Fermi energy + fermi_data = os.popen('grep -n "Fermi" %s/log | tail -1' % outdir, "r") + fermi_energy = float(fermi_data.readline().split()[-2]) + fermi_data.close() + eopreg = 0.025 + + # we use cell_length*eopreg*3 here since the work functions seem to + # converge at that distance rather than *1 or *2 + vac1guess = vacuum_pos - cell_length * eopreg * 2.5 + vac2guess = vacuum_pos + cell_length * eopreg * 2.5 + if vac1guess < 0: + #look for where we're closest to zero + vac_pos1 = np.abs(cell_length + vacuum_pos - cell_length * + eopreg * 2.5 - np.array(average_data)[..., 0]).argmin() + #print 'shifted vac1 for %s'%outdir + else: + vac_pos1 = np.abs(np.array(average_data)[..., 0] - + vacuum_pos + cell_length * eopreg * 2.5).argmin() + #print 'normal vac1' + if vac2guess > cell_length: + vac_pos2 = np.abs(vacuum_pos + cell_length * eopreg * 2.5 - + cell_length - np.array(average_data)[..., 0]).argmin() + #print 'shifted vac2 for %s'%outdir + else: + vac_pos2 = np.abs(np.array(average_data)[..., 0] - vacuum_pos - + cell_length * eopreg * 2.5).argmin() + #print 'normal vac2' + vacuum_energy1 = average_data[vac_pos1][1] + vacuum_energy2 = average_data[vac_pos2][1] + wf = [ + vacuum_energy1 * rydberg - fermi_energy, + vacuum_energy2 * rydberg - fermi_energy, + ] + + return(wf) + #__| diff --git a/docs/Makefile b/docs/Makefile index 590948a..0ff3643 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,20 +1,20 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SPHINXPROJ = ResearchPythonModules -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = ResearchPythonModules +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/docs/all-about-me.rst b/docs/all-about-me.rst index 3d0575a..bc4e63f 100644 --- a/docs/all-about-me.rst +++ b/docs/all-about-me.rst @@ -1,11 +1,11 @@ -############ -All about me -############ - -I'm Raul A. Flores, a graduate student that doesn't have any idea how to use Sphinx or readthedocs. \_ ;) __/ - -I've contributed to: - -* django CMS -* Arkestra -* Django +############ +All about me +############ + +I'm Raul A. Flores, a graduate student that doesn't have any idea how to use Sphinx or readthedocs. \_ ;) __/ + +I've contributed to: + +* django CMS +* Arkestra +* Django diff --git a/docs/ase_modules/ase_modules.rst b/docs/ase_modules/ase_modules.rst index 9c4f524..187a5c5 100644 --- a/docs/ase_modules/ase_modules.rst +++ b/docs/ase_modules/ase_modules.rst @@ -1,13 +1,13 @@ -.. _ase_modules: - -======= -Modules -======= - - -List of all modules: - -.. toctree:: - :maxdepth: 2 - - dft_job_automat +.. _ase_modules: + +======= +Modules +======= + + +List of all modules: + +.. toctree:: + :maxdepth: 2 + + dft_job_automat diff --git a/docs/ase_modules/dft_job_automat.rst b/docs/ase_modules/dft_job_automat.rst index bc123a2..b8e6399 100644 --- a/docs/ase_modules/dft_job_automat.rst +++ b/docs/ase_modules/dft_job_automat.rst @@ -1,8 +1,8 @@ -.. _dft_job_automat: - -================== -DFT Job Automation -================== - -The object is a collection of atoms. Here -is how to define a CO molecule +.. _dft_job_automat: + +================== +DFT Job Automation +================== + +The object is a collection of atoms. Here +is how to define a CO molecule diff --git a/docs/ase_modules/tmp_ase_modules0 b/docs/ase_modules/tmp_ase_modules0 index 8d1da71..e56660f 100644 --- a/docs/ase_modules/tmp_ase_modules0 +++ b/docs/ase_modules/tmp_ase_modules0 @@ -1,85 +1,85 @@ -.. _ase_modules: - -======= -Modules -======= - -Quick links: - -.. list-table:: - - * - :mod:`ase (Atom) ` - - :mod:`ase (Atoms) ` - - :mod:`~ase.build` - - :mod:`~ase.calculators` - * - :mod:`~ase.collections` - - :mod:`~ase.constraints` - - :mod:`~ase.db` - - :mod:`~ase.dft` - * - :mod:`~ase.data` - - :mod:`~ase.ga` - - :mod:`~ase.geometry` - - :mod:`~ase.gui` - * - :mod:`~ase.io` - - :mod:`~ase.lattice` - - :mod:`~ase.md` - - :mod:`~ase.neb` - * - :mod:`~ase.neighborlist` - - :mod:`~ase.optimize` - - :mod:`~ase.parallel` - - :mod:`~ase.phasediagram` - * - :mod:`~ase.phonons` - - :mod:`~ase.spacegroup` - - :mod:`~ase.transport` - - :mod:`~ase.thermochemistry` - * - :mod:`~ase.units` - - :mod:`~ase.utils` - - :mod:`~ase.vibrations` - - :mod:`~ase.visualize` - - -.. seealso:: - - * :ref:`tutorials` - * :ref:`cli` - * :git:`Source code <>` - * Presentation about ASE: :download:`ase-talk.pdf` - - -List of all modules: - -.. toctree:: - :maxdepth: 2 - - atoms - units - io/io - build/build - eos - collections - data - optimize - md - constraints - spacegroup/spacegroup - neighborlist - geometry - db/db - neb - ga - gui/gui - lattice - cluster/cluster - visualize/visualize - calculators/calculators - dft/dft - vibrations/vibrations - phonons - phasediagram/phasediagram - thermochemistry/thermochemistry - utils - parallel - dimer - atom - transport/transport - calculators/qmmm +.. _ase_modules: + +======= +Modules +======= + +Quick links: + +.. list-table:: + + * - :mod:`ase (Atom) ` + - :mod:`ase (Atoms) ` + - :mod:`~ase.build` + - :mod:`~ase.calculators` + * - :mod:`~ase.collections` + - :mod:`~ase.constraints` + - :mod:`~ase.db` + - :mod:`~ase.dft` + * - :mod:`~ase.data` + - :mod:`~ase.ga` + - :mod:`~ase.geometry` + - :mod:`~ase.gui` + * - :mod:`~ase.io` + - :mod:`~ase.lattice` + - :mod:`~ase.md` + - :mod:`~ase.neb` + * - :mod:`~ase.neighborlist` + - :mod:`~ase.optimize` + - :mod:`~ase.parallel` + - :mod:`~ase.phasediagram` + * - :mod:`~ase.phonons` + - :mod:`~ase.spacegroup` + - :mod:`~ase.transport` + - :mod:`~ase.thermochemistry` + * - :mod:`~ase.units` + - :mod:`~ase.utils` + - :mod:`~ase.vibrations` + - :mod:`~ase.visualize` + + +.. seealso:: + + * :ref:`tutorials` + * :ref:`cli` + * :git:`Source code <>` + * Presentation about ASE: :download:`ase-talk.pdf` + + +List of all modules: + +.. toctree:: + :maxdepth: 2 + + atoms + units + io/io + build/build + eos + collections + data + optimize + md + constraints + spacegroup/spacegroup + neighborlist + geometry + db/db + neb + ga + gui/gui + lattice + cluster/cluster + visualize/visualize + calculators/calculators + dft/dft + vibrations/vibrations + phonons + phasediagram/phasediagram + thermochemistry/thermochemistry + utils + parallel + dimer + atom + transport/transport + calculators/qmmm diff --git a/docs/ase_modules/tmp_dft_job_automat0 b/docs/ase_modules/tmp_dft_job_automat0 index 30b4546..768bffb 100644 --- a/docs/ase_modules/tmp_dft_job_automat0 +++ b/docs/ase_modules/tmp_dft_job_automat0 @@ -1,9 +1,9 @@ -.. module:: ase.atoms -.. module:: ase - -================ -The Atoms object -================ - -The :class:`Atoms` object is a collection of atoms. Here -is how to define a CO molecule:: +.. module:: ase.atoms +.. module:: ase + +================ +The Atoms object +================ + +The :class:`Atoms` object is a collection of atoms. Here +is how to define a CO molecule:: diff --git a/docs/conf.py b/docs/conf.py index 6c1a2a9..ea9ae56 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,172 +1,172 @@ -# -*- coding: utf-8 -*- -# -# Configuration file for the Sphinx documentation builder. -# -# This file does only contain a selection of the most common options. For a -# full list see the documentation: -# http://www.sphinx-doc.org/en/stable/config - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. - -import os -import sys - -# sys.path.insert(0, os.path.abspath('.'), os.path.abspath('./ase_modules')) -sys.path.insert(0, os.path.abspath('.')) -sys.path.append(os.path.abspath('./ase_modules')) - -# -- Project information ----------------------------------------------------- - -project = u'Research Python Modules' -copyright = u'2018, Raul A. Flores' -author = u'Raul A. Flores' - -# The short X.Y version -version = u'' -# The full version, including alpha/beta/rc tags -release = u'0.10' - - -# -- General configuration --------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.doctest', - 'sphinx.ext.todo', - 'sphinx.ext.coverage', - 'sphinx.ext.mathjax', - 'sphinx.ext.viewcode', -] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path . -exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store'] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -# html_theme = 'alabaster' # COMBAK Uncomment if not working - - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Custom sidebar templates, must be a dictionary that maps document names -# to template names. -# -# The default sidebars (for documents that don't match any pattern) are -# defined by theme itself. Builtin themes are using these templates by -# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', -# 'searchbox.html']``. -# -# html_sidebars = {} - - -# -- Options for HTMLHelp output --------------------------------------------- - -# Output file base name for HTML help builder. -htmlhelp_basename = 'ResearchPythonModulesdoc' - - -# -- Options for LaTeX output ------------------------------------------------ - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'ResearchPythonModules.tex', u'Research Python Modules Documentation', - u'Raul A. Flores', 'manual'), -] - - -# -- Options for manual page output ------------------------------------------ - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'researchpythonmodules', u'Research Python Modules Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ---------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'ResearchPythonModules', u'Research Python Modules Documentation', - author, 'ResearchPythonModules', 'One line description of project.', - 'Miscellaneous'), -] - - -# -- Extension configuration ------------------------------------------------- - -# -- Options for todo extension ---------------------------------------------- - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = True +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/stable/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. + +import os +import sys + +# sys.path.insert(0, os.path.abspath('.'), os.path.abspath('./ase_modules')) +sys.path.insert(0, os.path.abspath('.')) +sys.path.append(os.path.abspath('./ase_modules')) + +# -- Project information ----------------------------------------------------- + +project = u'Research Python Modules' +copyright = u'2018, Raul A. Flores' +author = u'Raul A. Flores' + +# The short X.Y version +version = u'' +# The full version, including alpha/beta/rc tags +release = u'0.10' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.mathjax', + 'sphinx.ext.viewcode', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path . +exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +# html_theme = 'alabaster' # COMBAK Uncomment if not working + + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'ResearchPythonModulesdoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'ResearchPythonModules.tex', u'Research Python Modules Documentation', + u'Raul A. Flores', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'researchpythonmodules', u'Research Python Modules Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'ResearchPythonModules', u'Research Python Modules Documentation', + author, 'ResearchPythonModules', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Extension configuration ------------------------------------------------- + +# -- Options for todo extension ---------------------------------------------- + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True diff --git a/docs/index.rst b/docs/index.rst index 6d7744f..faf0514 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,40 +1,40 @@ -.. Research Python Modules documentation master file, created by - sphinx-quickstart on Wed Apr 4 10:20:57 2018. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - -Welcome to Research Python Modules's documentation! -=================================================== - -.. This text will not be shown - (but, for instance, in HTML might be - rendered as an HTML comment) - - about - install - tutorials/tutorials - ase/ase - cmdline - tips - gallery/gallery - releasenotes - contact - development/development - faq - - -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - ase_modules/ase_modules - all-about-me - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` +.. Research Python Modules documentation master file, created by + sphinx-quickstart on Wed Apr 4 10:20:57 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Research Python Modules's documentation! +=================================================== + +.. This text will not be shown + (but, for instance, in HTML might be + rendered as an HTML comment) + + about + install + tutorials/tutorials + ase/ase + cmdline + tips + gallery/gallery + releasenotes + contact + development/development + faq + + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + ase_modules/ase_modules + all-about-me + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/make.bat b/docs/make.bat index ca98b17..b5ab026 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -1,36 +1,36 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build -set SPHINXPROJ=ResearchPythonModules - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% - -:end -popd +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build +set SPHINXPROJ=ResearchPythonModules + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/energetics/dft_energy.py b/energetics/dft_energy.py index 7ddf511..3bdceb5 100644 --- a/energetics/dft_energy.py +++ b/energetics/dft_energy.py @@ -1,418 +1,418 @@ -#!/usr/bin/env python - -"""Encapsulate DFT energy methods. - -Author: Raul A. Flores - -Development: - NOTE Take into account BEEF ensemble of energies -""" - -#| - Import Modules -import os -import sys -#__| - - -class Energy(object): - """ - """ - - #| - Energy *************************************************************** - def __init__(self, - gibbs_e=None, - internal_e=None, - enthalpy_e=None, - helmholtz_e=None, - electronic_e=None, - zero_point_e=None, - Cv_trans_term=None, - Cv_rot_term=None, - Cv_vib_term=None, - Cv_to_Cp=None, - entropy_term=None, - PV_term=None, - # main_energy="gibbs", - ): - """Initialize system energy quantities. - - TODO: Wrap all math operations around my custom methods that check for - None exeptions - - Args: - electronic_e: - zero_point_e: - trans_e: - rot_e: - vib_e: - """ - #| - __init__ - self.gibbs_e = gibbs_e - self.internal_e = internal_e - self.enthalpy_e = enthalpy_e - self.helmholtz_e = helmholtz_e - - self.electronic_e = electronic_e - self.zero_point_e = zero_point_e - - self.Cv_trans_term = Cv_trans_term - self.Cv_rot_term = Cv_rot_term - self.Cv_vib_term = Cv_vib_term - self.Cv_to_Cp = Cv_to_Cp - - self.entropy_term = entropy_term - self.PV_term = PV_term - - if self.internal_e is None: - self.internal_e = self.calc_internal_energy() - - if self.enthalpy_e is None: - self.enthalpy_e = self.calc_enthalpy_energy() - - if self.gibbs_e is None: - self.gibbs_e = self.calc_gibbs_free_energy() - #__| - - - def __str__(self): - """ - """ - #| - __str__ - mess = "Gibbs Free Energy: " + str(self.gibbs_e) + "\n" - mess += "Electronic Energy: " + str(self.electronic_e) + "\n" - - return(mess) - #__| - - def __repr__(self): - """Representation of instance when printed to stdout.""" - #| - __repr__ - mess = "Electronic Energy: " + str(self.electronic_e) + "\n" - mess += "Enthalpy Energy: " + str(self.enthalpy_e) + "\n" - mess += "Gibbs Free Energy: " + str(self.gibbs_e) + "\n" - - return(mess) - #__| - - def __sub__(self, other): - """ - """ - #| - __sub__ - - def subtract_mine(a, b): - """Return a - b. - - Return None if either of the terms are None - - Args: - a: - b: - """ - #| - subtract_mine - if a is None or b is None: - return(None) - else: - out = a - b - - return(out) - #__| - - - if isinstance(other, Energy): - print("Divisor is Energy class instance!!!") - - electronic_e_new = subtract_mine( - self.electronic_e, - other.electronic_e) - - enthalpy_e_new = subtract_mine( - self.enthalpy_e, - other.enthalpy_e) - - gibbs_e_new = subtract_mine( - self.gibbs_e, - other.gibbs_e) - - # electronic_e_new = self.electronic_e - other.electronic_e - # enthalpy_e_new = self.enthalpy_e - other.enthalpy_e - # gibbs_e_new = self.gibbs_e - other.gibbs_e - - - elif isinstance(other, float) or isinstance(other, int): - - - electronic_e_new = subtract_mine(self.electronic_e, float(other)) - enthalpy_e_new = subtract_mine(self.enthalpy_e, float(other)) - gibbs_e_new = subtract_mine(self.gibbs_e, float(other)) - - - # electronic_e_new = self.electronic_e - float(other) - # enthalpy_e_new = self.enthalpy_e - float(other) - # gibbs_e_new = self.gibbs_e - float(other) - - else: - print("type:") - print(type(other)) - raise NotImplementedError( - "Haven't figured out how to subract to the Energy class yet" - ) - - E_dict={ - "enthalpy_e": enthalpy_e_new, - "gibbs_e": gibbs_e_new, - "electronic_e": electronic_e_new, - } - - out_Energy = Energy(**E_dict) - - return(out_Energy) - #__| - - def __add__(self, other): - """ - """ - #| - __add__ - return (self.gibbs_e + other.gibbs_e) - #__| - - def __truediv__(self, other): - """ - """ - #| - __truediv__ - - if isinstance(other, Energy): - electronic_e_new = self.electronic_e / other.electronic_e - enthalpy_e_new = self.enthalpy_e / other.enthalpy_e - gibbs_e_new = self.gibbs_e / other.gibbs_e - - elif isinstance(other, float) or isinstance(other, int): - electronic_e_new = self.electronic_e / float(other) - enthalpy_e_new = self.enthalpy_e / float(other) - gibbs_e_new = self.gibbs_e / float(other) - - else: - raise NotImplementedError( - "Haven't figured out how to divide my Energy class by that yet" - ) - - E_dict={ - "electronic_e": electronic_e_new, - "enthalpy_e": enthalpy_e_new, - "gibbs_e": gibbs_e_new, - } - - out_Energy = Energy(**E_dict) - - return(out_Energy) - #__| - - def __floordiv__(self, other): - """ - """ - #| - __floordiv__ - print("__floordiv__") - return (self.gibbs_e / other.gibbs_e) - #__| - - - - @staticmethod - def add_entries(entries_list): - """Adds entries in entries_list. - - Converts NoneType to 0 - - Args: - entries_list: - """ - #| - add_entries - sum_tot = 0. - for entry in entries_list: - if entry is None: - summand = 0. - else: - summand = entry - sum_tot += summand - - return(sum_tot) - #__| - - def calc_internal_energy(self): - """Calculate internal energy. - - Args: - - """ - #| - internal_energy - energy_list = [ - self.electronic_e, - self.zero_point_e, - self.Cv_trans_term, - self.Cv_rot_term, - self.Cv_vib_term, - self.Cv_to_Cp, - ] - - internal_energy = self.add_entries(energy_list) - - return(internal_energy) - #__| - - def calc_enthalpy_energy(self): - """ - """ - #| - calc_enthalpy_energy - energy_list = [ - self.internal_e, - self.PV_term, - ] - - enthalpy_e = self.add_entries(energy_list) - - return(enthalpy_e) - #__| - - def calc_gibbs_free_energy(self): - """ - """ - #| - calc_gibbs_free_energy - if self.entropy_term is not None: - entropy_term = -self.entropy_term - else: - entropy_term = None - - energy_list = [ - self.enthalpy_e, - entropy_term, - ] - - gibbs_e = self.add_entries(energy_list) - - return(gibbs_e) - #__| - - #__| ********************************************************************** - - -class Element_Refs(): - """docstring for [object Object]. - - /u/if/flores12/02_ref_energies/h2/_3 - - Notes: - - * Water formation energy: - G_Liq: | -237.14 kJ/mol --> -2.457784 eV (-4.915567) - G_Gas: | -228.61 kJ/mol --> -2.369376 eV (-4.738753) - -------------------------------------------------------- - H_Liq: | −285.8 kJ/mol --> -2.96211 eV (-5.92422) - H_Gas: | −241.818 kJ/mol --> -2.506268 eV (-5.012535) - - """ - - #| - Element_Refs ********************************************************* - - def __init__(self, - H2O_dict={ - # "gibbs_e": -476.54410902835434, - "gibbs_e": -476.630481653821, - "electronic_e": -476.6430744328504, - }, - - H2_dict={ - # "gibbs_e": -32.956123446117, - "gibbs_e": -32.956123446117, - "electronic_e": -32.9203465588979, - }, - - O2_dict={ - "gibbs_e": -883.1904356, - "electronic_e": -882.7384356, - }, - - # COMBAK I only have the electronic energy for now - N2_dict={ - "gibbs_e": -553.638294974, - "electronic_e": -553.638294974, - }, - - - # H2O Formation Energy from H2 and O2 ********************************* - H2O_form_e_dict={ - "gibbs_e": -2.4583, - "enthalpy_e": -2.96211, - }, - - # H2O_form_gibbs=-2.4583, - - oxygen_ref="H2O", # "H2O" or "O2" - hydrogen_ref="H2", - - # reference_states_dict={ - # "H": "H2", - # "O": "H2O", - # } - - ): - """Initialize instance. - - # Directories of gas phase DFT jobs (QE): - H2O, H2, and O2 energies were obtained from: - /scratch/users/flores12/gas_phase_molec/BEEF-vdW - H2: - /scratch/users/flores12/gas_phase_molec/BEEF-vdW/h2/_4 - H2O: - /scratch/users/flores12/gas_phase_molec/BEEF-vdW/h2o/_3 - O2: - /scratch/users/flores12/gas_phase_molec/BEEF-vdW/o2/_3 - - Args: - G_H2O: - G_H2: - G_O2: - H2O_form_gibbs: - oxygen_ref and hydrogen_ref: - States of 0 energy, reference for each element type - Conventionally for ORR/OER I use a H2, H2O reference state, - such that H2O has 0 energy - """ - #| - __init__ - self.En_H2O = Energy(**H2O_dict) - self.En_H2 = Energy(**H2_dict) - self.En_O2 = Energy(**O2_dict) - self.En_N2 = Energy(**N2_dict) - - self.oxygen_ref = oxygen_ref - self.hydrogen_ref = hydrogen_ref - - # self.H2O_form_gibbs = Energy(gibbs_e=H2O_form_gibbs) - self.H2O_form_gibbs = Energy(**H2O_form_e_dict) - - self.E_O_ref, self.E_H_ref = self.calc_ref_energies() - #__| - - def calc_ref_energies(self): - """ - """ - #| - calc_ref_energies - - if self.hydrogen_ref == "H2": - # hyd_ref = self.En_H2 / 2. - hyd_ref = self.En_H2 / 2. - else: - print("Non H2 H reference state! Do more work here") - - - if self.oxygen_ref == "H2O": - oxy_ref = self.En_H2O - self.En_H2 - - elif self.oxygen_ref == "O2": - oxy_ref = self.En_H2O - self.En_H2 - self.H2O_form_gibbs - - # tmp = oxy_ref - self.H2O_form_gibbs - # print(tmp) - - return(oxy_ref, hyd_ref) - #__| - - #__| ********************************************************************** +#!/usr/bin/env python + +"""Encapsulate DFT energy methods. + +Author: Raul A. Flores + +Development: + NOTE Take into account BEEF ensemble of energies +""" + +#| - Import Modules +import os +import sys +#__| + + +class Energy(object): + """ + """ + + #| - Energy *************************************************************** + def __init__(self, + gibbs_e=None, + internal_e=None, + enthalpy_e=None, + helmholtz_e=None, + electronic_e=None, + zero_point_e=None, + Cv_trans_term=None, + Cv_rot_term=None, + Cv_vib_term=None, + Cv_to_Cp=None, + entropy_term=None, + PV_term=None, + # main_energy="gibbs", + ): + """Initialize system energy quantities. + + TODO: Wrap all math operations around my custom methods that check for + None exeptions + + Args: + electronic_e: + zero_point_e: + trans_e: + rot_e: + vib_e: + """ + #| - __init__ + self.gibbs_e = gibbs_e + self.internal_e = internal_e + self.enthalpy_e = enthalpy_e + self.helmholtz_e = helmholtz_e + + self.electronic_e = electronic_e + self.zero_point_e = zero_point_e + + self.Cv_trans_term = Cv_trans_term + self.Cv_rot_term = Cv_rot_term + self.Cv_vib_term = Cv_vib_term + self.Cv_to_Cp = Cv_to_Cp + + self.entropy_term = entropy_term + self.PV_term = PV_term + + if self.internal_e is None: + self.internal_e = self.calc_internal_energy() + + if self.enthalpy_e is None: + self.enthalpy_e = self.calc_enthalpy_energy() + + if self.gibbs_e is None: + self.gibbs_e = self.calc_gibbs_free_energy() + #__| + + + def __str__(self): + """ + """ + #| - __str__ + mess = "Gibbs Free Energy: " + str(self.gibbs_e) + "\n" + mess += "Electronic Energy: " + str(self.electronic_e) + "\n" + + return(mess) + #__| + + def __repr__(self): + """Representation of instance when printed to stdout.""" + #| - __repr__ + mess = "Electronic Energy: " + str(self.electronic_e) + "\n" + mess += "Enthalpy Energy: " + str(self.enthalpy_e) + "\n" + mess += "Gibbs Free Energy: " + str(self.gibbs_e) + "\n" + + return(mess) + #__| + + def __sub__(self, other): + """ + """ + #| - __sub__ + + def subtract_mine(a, b): + """Return a - b. + + Return None if either of the terms are None + + Args: + a: + b: + """ + #| - subtract_mine + if a is None or b is None: + return(None) + else: + out = a - b + + return(out) + #__| + + + if isinstance(other, Energy): + print("Divisor is Energy class instance!!!") + + electronic_e_new = subtract_mine( + self.electronic_e, + other.electronic_e) + + enthalpy_e_new = subtract_mine( + self.enthalpy_e, + other.enthalpy_e) + + gibbs_e_new = subtract_mine( + self.gibbs_e, + other.gibbs_e) + + # electronic_e_new = self.electronic_e - other.electronic_e + # enthalpy_e_new = self.enthalpy_e - other.enthalpy_e + # gibbs_e_new = self.gibbs_e - other.gibbs_e + + + elif isinstance(other, float) or isinstance(other, int): + + + electronic_e_new = subtract_mine(self.electronic_e, float(other)) + enthalpy_e_new = subtract_mine(self.enthalpy_e, float(other)) + gibbs_e_new = subtract_mine(self.gibbs_e, float(other)) + + + # electronic_e_new = self.electronic_e - float(other) + # enthalpy_e_new = self.enthalpy_e - float(other) + # gibbs_e_new = self.gibbs_e - float(other) + + else: + print("type:") + print(type(other)) + raise NotImplementedError( + "Haven't figured out how to subract to the Energy class yet" + ) + + E_dict={ + "enthalpy_e": enthalpy_e_new, + "gibbs_e": gibbs_e_new, + "electronic_e": electronic_e_new, + } + + out_Energy = Energy(**E_dict) + + return(out_Energy) + #__| + + def __add__(self, other): + """ + """ + #| - __add__ + return (self.gibbs_e + other.gibbs_e) + #__| + + def __truediv__(self, other): + """ + """ + #| - __truediv__ + + if isinstance(other, Energy): + electronic_e_new = self.electronic_e / other.electronic_e + enthalpy_e_new = self.enthalpy_e / other.enthalpy_e + gibbs_e_new = self.gibbs_e / other.gibbs_e + + elif isinstance(other, float) or isinstance(other, int): + electronic_e_new = self.electronic_e / float(other) + enthalpy_e_new = self.enthalpy_e / float(other) + gibbs_e_new = self.gibbs_e / float(other) + + else: + raise NotImplementedError( + "Haven't figured out how to divide my Energy class by that yet" + ) + + E_dict={ + "electronic_e": electronic_e_new, + "enthalpy_e": enthalpy_e_new, + "gibbs_e": gibbs_e_new, + } + + out_Energy = Energy(**E_dict) + + return(out_Energy) + #__| + + def __floordiv__(self, other): + """ + """ + #| - __floordiv__ + print("__floordiv__") + return (self.gibbs_e / other.gibbs_e) + #__| + + + + @staticmethod + def add_entries(entries_list): + """Adds entries in entries_list. + + Converts NoneType to 0 + + Args: + entries_list: + """ + #| - add_entries + sum_tot = 0. + for entry in entries_list: + if entry is None: + summand = 0. + else: + summand = entry + sum_tot += summand + + return(sum_tot) + #__| + + def calc_internal_energy(self): + """Calculate internal energy. + + Args: + + """ + #| - internal_energy + energy_list = [ + self.electronic_e, + self.zero_point_e, + self.Cv_trans_term, + self.Cv_rot_term, + self.Cv_vib_term, + self.Cv_to_Cp, + ] + + internal_energy = self.add_entries(energy_list) + + return(internal_energy) + #__| + + def calc_enthalpy_energy(self): + """ + """ + #| - calc_enthalpy_energy + energy_list = [ + self.internal_e, + self.PV_term, + ] + + enthalpy_e = self.add_entries(energy_list) + + return(enthalpy_e) + #__| + + def calc_gibbs_free_energy(self): + """ + """ + #| - calc_gibbs_free_energy + if self.entropy_term is not None: + entropy_term = -self.entropy_term + else: + entropy_term = None + + energy_list = [ + self.enthalpy_e, + entropy_term, + ] + + gibbs_e = self.add_entries(energy_list) + + return(gibbs_e) + #__| + + #__| ********************************************************************** + + +class Element_Refs(): + """docstring for [object Object]. + + /u/if/flores12/02_ref_energies/h2/_3 + + Notes: + + * Water formation energy: + G_Liq: | -237.14 kJ/mol --> -2.457784 eV (-4.915567) + G_Gas: | -228.61 kJ/mol --> -2.369376 eV (-4.738753) + -------------------------------------------------------- + H_Liq: | −285.8 kJ/mol --> -2.96211 eV (-5.92422) + H_Gas: | −241.818 kJ/mol --> -2.506268 eV (-5.012535) + + """ + + #| - Element_Refs ********************************************************* + + def __init__(self, + H2O_dict={ + # "gibbs_e": -476.54410902835434, + "gibbs_e": -476.630481653821, + "electronic_e": -476.6430744328504, + }, + + H2_dict={ + # "gibbs_e": -32.956123446117, + "gibbs_e": -32.956123446117, + "electronic_e": -32.9203465588979, + }, + + O2_dict={ + "gibbs_e": -883.1904356, + "electronic_e": -882.7384356, + }, + + # COMBAK I only have the electronic energy for now + N2_dict={ + "gibbs_e": -553.638294974, + "electronic_e": -553.638294974, + }, + + + # H2O Formation Energy from H2 and O2 ********************************* + H2O_form_e_dict={ + "gibbs_e": -2.4583, + "enthalpy_e": -2.96211, + }, + + # H2O_form_gibbs=-2.4583, + + oxygen_ref="H2O", # "H2O" or "O2" + hydrogen_ref="H2", + + # reference_states_dict={ + # "H": "H2", + # "O": "H2O", + # } + + ): + """Initialize instance. + + # Directories of gas phase DFT jobs (QE): + H2O, H2, and O2 energies were obtained from: + /scratch/users/flores12/gas_phase_molec/BEEF-vdW + H2: + /scratch/users/flores12/gas_phase_molec/BEEF-vdW/h2/_4 + H2O: + /scratch/users/flores12/gas_phase_molec/BEEF-vdW/h2o/_3 + O2: + /scratch/users/flores12/gas_phase_molec/BEEF-vdW/o2/_3 + + Args: + G_H2O: + G_H2: + G_O2: + H2O_form_gibbs: + oxygen_ref and hydrogen_ref: + States of 0 energy, reference for each element type + Conventionally for ORR/OER I use a H2, H2O reference state, + such that H2O has 0 energy + """ + #| - __init__ + self.En_H2O = Energy(**H2O_dict) + self.En_H2 = Energy(**H2_dict) + self.En_O2 = Energy(**O2_dict) + self.En_N2 = Energy(**N2_dict) + + self.oxygen_ref = oxygen_ref + self.hydrogen_ref = hydrogen_ref + + # self.H2O_form_gibbs = Energy(gibbs_e=H2O_form_gibbs) + self.H2O_form_gibbs = Energy(**H2O_form_e_dict) + + self.E_O_ref, self.E_H_ref = self.calc_ref_energies() + #__| + + def calc_ref_energies(self): + """ + """ + #| - calc_ref_energies + + if self.hydrogen_ref == "H2": + # hyd_ref = self.En_H2 / 2. + hyd_ref = self.En_H2 / 2. + else: + print("Non H2 H reference state! Do more work here") + + + if self.oxygen_ref == "H2O": + oxy_ref = self.En_H2O - self.En_H2 + + elif self.oxygen_ref == "O2": + oxy_ref = self.En_H2O - self.En_H2 - self.H2O_form_gibbs + + # tmp = oxy_ref - self.H2O_form_gibbs + # print(tmp) + + return(oxy_ref, hyd_ref) + #__| + + #__| ********************************************************************** diff --git a/energetics/formation_energy.py b/energetics/formation_energy.py index c2e2cd1..9556aa8 100644 --- a/energetics/formation_energy.py +++ b/energetics/formation_energy.py @@ -1,108 +1,108 @@ -#!/usr/bin/env python - -"""General method to calculate formation energies. - -Author: Raul A. Flores -""" - -#| - Import Modules -import numpy as np - -from ase_modules.ase_methods import create_species_element_dict -#__| - -def calc_formation_energy( - atoms, - energy, - reference_states, - normalize_per_atom=True, - ): - """Calculate formation energy of structure on a per atom basis. - - reference states = [ - { - "energy": , - "element_dict": {"H": 1, "Ir": 2}, - }, - { - - }, - ... - ] - - Args: - atoms: - energy: - reference_dict: - normalize_per_atom: - """ - #| - calc_formation_energy - atoms.info["element_dict"] = create_species_element_dict(atoms) - - num_atoms = atoms.get_number_of_atoms() - - # ordered_elems = list(atoms.info["element_dict"]) - # ordered_elems.sort() - - - #| - Finding List of Unique Elements Defined by reference_states list - ref_state_elem_list = [] - for i in reference_states: - ref_i_elems = list(i["element_dict"]) - ref_state_elem_list.extend(ref_i_elems) - - ordered_elems = list(set(ref_state_elem_list)) - ordered_elems.sort() - #__| - - - #| - Constructing the A matrix - a_matrix = [] - for ref_state_i in reference_states: - ref_i_comp_vect = [] - for elem_i in ordered_elems: - if elem_i in list(ref_state_i["element_dict"]): - elem_i_num = ref_state_i["element_dict"][elem_i] - ref_i_comp_vect.append(elem_i_num) - else: - ref_i_comp_vect.append(0.) - - a_matrix.append(np.array(ref_i_comp_vect)) - a_matrix = np.array(a_matrix).transpose() - #__| - - #| - Constructing the b vector - # phi = 1. - b_vect = [] - for elem_i in ordered_elems: - if elem_i in list(atoms.info["element_dict"]): - elem_i_num = atoms.info["element_dict"][elem_i] - b_vect.append(elem_i_num) - else: - b_vect.append(0.) - - b_vect = np.array(b_vect) - #__| - - #| - Solve linear system of equations - x = np.linalg.solve( - a_matrix, - b_vect, - ) - #__| - - #| - Calculate Formation Energy - ref_e_sum = 0. - for coeff_i, ref_i in zip(x, reference_states): - ref_i_contribution = coeff_i * ref_i["elec_e"] - ref_e_sum += ref_i_contribution - - form_e = energy - ref_e_sum - - if normalize_per_atom: - form_e = form_e / num_atoms - #__| - - - return(form_e) - #__| +#!/usr/bin/env python + +"""General method to calculate formation energies. + +Author: Raul A. Flores +""" + +#| - Import Modules +import numpy as np + +from ase_modules.ase_methods import create_species_element_dict +#__| + +def calc_formation_energy( + atoms, + energy, + reference_states, + normalize_per_atom=True, + ): + """Calculate formation energy of structure on a per atom basis. + + reference states = [ + { + "energy": , + "element_dict": {"H": 1, "Ir": 2}, + }, + { + + }, + ... + ] + + Args: + atoms: + energy: + reference_dict: + normalize_per_atom: + """ + #| - calc_formation_energy + atoms.info["element_dict"] = create_species_element_dict(atoms) + + num_atoms = atoms.get_number_of_atoms() + + # ordered_elems = list(atoms.info["element_dict"]) + # ordered_elems.sort() + + + #| - Finding List of Unique Elements Defined by reference_states list + ref_state_elem_list = [] + for i in reference_states: + ref_i_elems = list(i["element_dict"]) + ref_state_elem_list.extend(ref_i_elems) + + ordered_elems = list(set(ref_state_elem_list)) + ordered_elems.sort() + #__| + + + #| - Constructing the A matrix + a_matrix = [] + for ref_state_i in reference_states: + ref_i_comp_vect = [] + for elem_i in ordered_elems: + if elem_i in list(ref_state_i["element_dict"]): + elem_i_num = ref_state_i["element_dict"][elem_i] + ref_i_comp_vect.append(elem_i_num) + else: + ref_i_comp_vect.append(0.) + + a_matrix.append(np.array(ref_i_comp_vect)) + a_matrix = np.array(a_matrix).transpose() + #__| + + #| - Constructing the b vector + # phi = 1. + b_vect = [] + for elem_i in ordered_elems: + if elem_i in list(atoms.info["element_dict"]): + elem_i_num = atoms.info["element_dict"][elem_i] + b_vect.append(elem_i_num) + else: + b_vect.append(0.) + + b_vect = np.array(b_vect) + #__| + + #| - Solve linear system of equations + x = np.linalg.solve( + a_matrix, + b_vect, + ) + #__| + + #| - Calculate Formation Energy + ref_e_sum = 0. + for coeff_i, ref_i in zip(x, reference_states): + ref_i_contribution = coeff_i * ref_i["elec_e"] + ref_e_sum += ref_i_contribution + + form_e = energy - ref_e_sum + + if normalize_per_atom: + form_e = form_e / num_atoms + #__| + + + return(form_e) + #__| diff --git a/misc_modules/misc_methods.py b/misc_modules/misc_methods.py index 9b8cf64..400163a 100644 --- a/misc_modules/misc_methods.py +++ b/misc_modules/misc_methods.py @@ -1,133 +1,133 @@ -"""Miscellaneous and helpful methods for everday work. - -TEMP -TEMP -""" - -#| - IMPORT MODULES -import os - -# import sys -#__| - - -def even_spaced_range(start_finish, spacing): - """ - Produces evenly spaced list between "start" and "finish" with the interval - between each entry defined by "spacing". - Includes start and finish at the beginning and end, respecively, regardless - of whether finish is naturally reached. - - - Args: - start_finish: - List with start and end points of ENCUT_range - ex. [1, 87] - spacing: - """ - #| - even_spaced_range - out_list = [] - entry_i = start_finish[0] - while entry_i < start_finish[1]: - out_list.append(entry_i) - entry_i += spacing - out_list.append(start_finish[1]) - - return(out_list) - #__| - - -def merge_two_dicts(x, y): - """ - """ - #| - merge_two_dicts - z = x.copy() # start with x's keys and values - z.update(y) # modifies z with y's keys and values & returns None - - return z - #__| - - -import collections - -def dict_merge(dct, merge_dct): - """ Recursive dict merge. Inspired by :meth:``dict.update()``, instead of - updating only top-level keys, dict_merge recurses down into dicts nested - to an arbitrary depth, updating keys. The ``merge_dct`` is merged into - ``dct``. - - :param dct: dict onto which the merge is executed - :param merge_dct: dct merged into dct - :return: None - - Obtained from: - https://gist.github.com/angstwad/bf22d1822c38a92ec0a9 - """ - #| - dict_merge - # for k, v in merge_dct.iteritems(): - for k, v in merge_dct.items(): - if (k in dct and isinstance(dct[k], dict) and isinstance(merge_dct[k], collections.Mapping)): - dict_merge(dct[k], merge_dct[k]) - else: - dct[k] = merge_dct[k] - #__| - -#| - File and Directory Management - -def remove_file_from_all_folders( - file_name_list, - remove_files=False, - show_file_size=True, - root_dir=".", - ): - """Removes charge files (CHG and CHGCAR) from Raman DFT job folders. - - Args: - file_name_list: - remove_files: Whether to perform file deletion or not. - root_dir: Starting directory, assumed to be current directory - """ - #| - remove_file_from_all_folders - total_disk_usage = 0. - for dirName, subdirList, fileList in os.walk(root_dir): - for file_name in file_name_list: - if file_name in fileList: - print(dirName) - # print(subdirList) - # print(fileList) - # print(file_name) - - file_path_i = os.path.join( - dirName, - file_name, - ) - - if show_file_size: - file_size_i = os.stat(file_path_i).st_size * 1E-6 - print("File size: ", str(file_size_i), " MB") - - total_disk_usage += file_size_i - - print("_________") - - if remove_files: - try: - os.remove(file_path_i) - print("File removed!!") - except: - pass - - - if show_file_size: - if total_disk_usage > 1E3: - total_disk_usage_print = total_disk_usage * 1E-3 - unit = "GB" - else: - total_disk_usage_print = total_disk_usage - unit = "MB" - - print("Total Disk Usage: ", str(total_disk_usage_print), "", unit) - #__| - - -#__| +"""Miscellaneous and helpful methods for everday work. + +TEMP +TEMP +""" + +#| - IMPORT MODULES +import os + +# import sys +#__| + + +def even_spaced_range(start_finish, spacing): + """ + Produces evenly spaced list between "start" and "finish" with the interval + between each entry defined by "spacing". + Includes start and finish at the beginning and end, respecively, regardless + of whether finish is naturally reached. + + + Args: + start_finish: + List with start and end points of ENCUT_range + ex. [1, 87] + spacing: + """ + #| - even_spaced_range + out_list = [] + entry_i = start_finish[0] + while entry_i < start_finish[1]: + out_list.append(entry_i) + entry_i += spacing + out_list.append(start_finish[1]) + + return(out_list) + #__| + + +def merge_two_dicts(x, y): + """ + """ + #| - merge_two_dicts + z = x.copy() # start with x's keys and values + z.update(y) # modifies z with y's keys and values & returns None + + return z + #__| + + +import collections + +def dict_merge(dct, merge_dct): + """ Recursive dict merge. Inspired by :meth:``dict.update()``, instead of + updating only top-level keys, dict_merge recurses down into dicts nested + to an arbitrary depth, updating keys. The ``merge_dct`` is merged into + ``dct``. + + :param dct: dict onto which the merge is executed + :param merge_dct: dct merged into dct + :return: None + + Obtained from: + https://gist.github.com/angstwad/bf22d1822c38a92ec0a9 + """ + #| - dict_merge + # for k, v in merge_dct.iteritems(): + for k, v in merge_dct.items(): + if (k in dct and isinstance(dct[k], dict) and isinstance(merge_dct[k], collections.Mapping)): + dict_merge(dct[k], merge_dct[k]) + else: + dct[k] = merge_dct[k] + #__| + +#| - File and Directory Management + +def remove_file_from_all_folders( + file_name_list, + remove_files=False, + show_file_size=True, + root_dir=".", + ): + """Removes charge files (CHG and CHGCAR) from Raman DFT job folders. + + Args: + file_name_list: + remove_files: Whether to perform file deletion or not. + root_dir: Starting directory, assumed to be current directory + """ + #| - remove_file_from_all_folders + total_disk_usage = 0. + for dirName, subdirList, fileList in os.walk(root_dir): + for file_name in file_name_list: + if file_name in fileList: + print(dirName) + # print(subdirList) + # print(fileList) + # print(file_name) + + file_path_i = os.path.join( + dirName, + file_name, + ) + + if show_file_size: + file_size_i = os.stat(file_path_i).st_size * 1E-6 + print("File size: ", str(file_size_i), " MB") + + total_disk_usage += file_size_i + + print("_________") + + if remove_files: + try: + os.remove(file_path_i) + print("File removed!!") + except: + pass + + + if show_file_size: + if total_disk_usage > 1E3: + total_disk_usage_print = total_disk_usage * 1E-3 + unit = "GB" + else: + total_disk_usage_print = total_disk_usage + unit = "MB" + + print("Total Disk Usage: ", str(total_disk_usage_print), "", unit) + #__| + + +#__| diff --git a/misc_modules/numpy_methods.py b/misc_modules/numpy_methods.py index b8ab996..a8af1c3 100644 --- a/misc_modules/numpy_methods.py +++ b/misc_modules/numpy_methods.py @@ -1,55 +1,55 @@ -#| - IMPORT MODULES -import numpy as np -#__| - -def unit_vector(vector): - """ Returns the unit vector of the vector. - - https://stackoverflow.com/questions/2827393/angles-between-two-n-dimensional-vectors-in-python - """ - #| - unit_vector - return vector / np.linalg.norm(vector) - #__| - -def angle_between(v1, v2): - """ Returns the angle in radians between vectors 'v1' and 'v2':: - - >>> angle_between((1, 0, 0), (0, 1, 0)) - 1.5707963267948966 - >>> angle_between((1, 0, 0), (1, 0, 0)) - 0.0 - >>> angle_between((1, 0, 0), (-1, 0, 0)) - 3.141592653589793 - https://stackoverflow.com/questions/2827393/angles-between-two-n-dimensional-vectors-in-python - """ - #| - angle_between - v1_u = unit_vector(v1) - v2_u = unit_vector(v2) - - return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0)) - #__| - -def smooth_data_series(y_data, box_pts): - """Smooth data series by convolution - """ - #| - smooth_data_series - box = np.ones(box_pts) / box_pts - y_smooth = np.convolve(y_data, box, mode="same") - return(y_smooth) - #__| - -def make_filter_list(len_data, percent_keep): - """ - """ - #| - filter_list - -# len_data = len(pdos_data[0]) - - filter_list = np.random.choice( - [True, False], - size=len_data, - p=[percent_keep, 1. - percent_keep] - ) - - return(filter_list) - #__| +#| - IMPORT MODULES +import numpy as np +#__| + +def unit_vector(vector): + """ Returns the unit vector of the vector. + + https://stackoverflow.com/questions/2827393/angles-between-two-n-dimensional-vectors-in-python + """ + #| - unit_vector + return vector / np.linalg.norm(vector) + #__| + +def angle_between(v1, v2): + """ Returns the angle in radians between vectors 'v1' and 'v2':: + + >>> angle_between((1, 0, 0), (0, 1, 0)) + 1.5707963267948966 + >>> angle_between((1, 0, 0), (1, 0, 0)) + 0.0 + >>> angle_between((1, 0, 0), (-1, 0, 0)) + 3.141592653589793 + https://stackoverflow.com/questions/2827393/angles-between-two-n-dimensional-vectors-in-python + """ + #| - angle_between + v1_u = unit_vector(v1) + v2_u = unit_vector(v2) + + return np.arccos(np.clip(np.dot(v1_u, v2_u), -1.0, 1.0)) + #__| + +def smooth_data_series(y_data, box_pts): + """Smooth data series by convolution + """ + #| - smooth_data_series + box = np.ones(box_pts) / box_pts + y_smooth = np.convolve(y_data, box, mode="same") + return(y_smooth) + #__| + +def make_filter_list(len_data, percent_keep): + """ + """ + #| - filter_list + +# len_data = len(pdos_data[0]) + + filter_list = np.random.choice( + [True, False], + size=len_data, + p=[percent_keep, 1. - percent_keep] + ) + + return(filter_list) + #__| diff --git a/misc_modules/pandas_methods.py b/misc_modules/pandas_methods.py index bc072ff..ddd06a3 100644 --- a/misc_modules/pandas_methods.py +++ b/misc_modules/pandas_methods.py @@ -1,116 +1,116 @@ -"""My custom pandas methods and protocols. - - -Author: Raul A. Flores -""" - -__author__ = "Raul A. Flores" -__copyright__ = "NaN" -__version__ = "0.1" -__maintainer__ = "Raul A. Flores" -__email__ = "flores12@stanford.edu; raulf2012@gmail.com" -__date__ = "181115" - -def reorder_df_columns(col_order_list, df): - """ - """ - #| - show - - #| - __old__ - # col_order_list = [ - # # Main system variables - # "bulk_system", - # "facet", - # "adsorbate", - # "coverage_type", - # "ooh_direction", - # - # # Energetics - # "ads_e", - # "elec_energy", - # - # # Magnetic Moments - # "magmoms", - # "total_magmom", - # "abs_magmom", - # - # "path_short", - # - # "name_i", - # - # "max_force", - # "sum_force", - # "elem_num_dict", - # - # "incar", - # "incar_parsed", - # - # # Atom properties - # "init_atoms", - # "atoms_object", - # "N_atoms", - # - # "dipole_correction", - # "u_correction", - # - # # Low priority - # "job_type", - # "max_revision", - # "revision_number", - # "success", - # "coverage", - # - # - # "path", - # "name_i_2", - # "name_i_3", - # - # - # # Not needed columns - # "Job", - # "layers", - # ] - #__| - - col_order_list.reverse() - - df_col_list = list(df) - for col_i in col_order_list: - - if col_i in df_col_list: - df_col_list.remove(col_i) - df_col_list.insert(0, col_i) - else: - pass - - df = df[df_col_list] - - return(df) - #__| - - - -def drop_columns(df=None, columns=None, keep_or_drop="keep"): - """ - """ - #| - drop_columns - if keep_or_drop == "keep": - cols_to_keep = columns - - columns_to_drop = [] - for col_i in df.columns: - if col_i not in cols_to_keep: - columns_to_drop.append(col_i) - - df_out = df.drop(columns=columns_to_drop) - - elif keep_or_drop == "drop": - cols_to_drop = columns - - df_out = df.drop(columns=cols_to_drop) - - else: - raise ValueError('BAD BAD BAD') - - return(df_out) - #__| +"""My custom pandas methods and protocols. + + +Author: Raul A. Flores +""" + +__author__ = "Raul A. Flores" +__copyright__ = "NaN" +__version__ = "0.1" +__maintainer__ = "Raul A. Flores" +__email__ = "flores12@stanford.edu; raulf2012@gmail.com" +__date__ = "181115" + +def reorder_df_columns(col_order_list, df): + """ + """ + #| - show + + #| - __old__ + # col_order_list = [ + # # Main system variables + # "bulk_system", + # "facet", + # "adsorbate", + # "coverage_type", + # "ooh_direction", + # + # # Energetics + # "ads_e", + # "elec_energy", + # + # # Magnetic Moments + # "magmoms", + # "total_magmom", + # "abs_magmom", + # + # "path_short", + # + # "name_i", + # + # "max_force", + # "sum_force", + # "elem_num_dict", + # + # "incar", + # "incar_parsed", + # + # # Atom properties + # "init_atoms", + # "atoms_object", + # "N_atoms", + # + # "dipole_correction", + # "u_correction", + # + # # Low priority + # "job_type", + # "max_revision", + # "revision_number", + # "success", + # "coverage", + # + # + # "path", + # "name_i_2", + # "name_i_3", + # + # + # # Not needed columns + # "Job", + # "layers", + # ] + #__| + + col_order_list.reverse() + + df_col_list = list(df) + for col_i in col_order_list: + + if col_i in df_col_list: + df_col_list.remove(col_i) + df_col_list.insert(0, col_i) + else: + pass + + df = df[df_col_list] + + return(df) + #__| + + + +def drop_columns(df=None, columns=None, keep_or_drop="keep"): + """ + """ + #| - drop_columns + if keep_or_drop == "keep": + cols_to_keep = columns + + columns_to_drop = [] + for col_i in df.columns: + if col_i not in cols_to_keep: + columns_to_drop.append(col_i) + + df_out = df.drop(columns=columns_to_drop) + + elif keep_or_drop == "drop": + cols_to_drop = columns + + df_out = df.drop(columns=cols_to_drop) + + else: + raise ValueError('BAD BAD BAD') + + return(df_out) + #__| diff --git a/misc_modules/plotly_methods.py b/misc_modules/plotly_methods.py index f5a09d5..4526793 100644 --- a/misc_modules/plotly_methods.py +++ b/misc_modules/plotly_methods.py @@ -1,60 +1,60 @@ -#!/usr/bin/env python - -"""Plotly methods. - -Author: Raul A. Flores -""" - -#| - Import Modules -import json -# import numpy as np - -from plotly.utils import PlotlyJSONEncoder -import plotly.graph_objs as go -#__| - -def plotlyfig2json(fig, fpath=None): - """Serialize a plotly figure object to JSON so it can be persisted to disk. - - Figure's persisted as JSON can be rebuilt using the plotly JSON chart API: - - Code obtained from: - https://github.com/plotly/plotly.py/issues/579 - - http://help.plot.ly/json-chart-schema/ - - If `fpath` is provided, JSON is written to file. - - Modified from https://github.com/nteract/nteract/issues/1229 - """ - #| - plotlyfig2json - redata = json.loads(json.dumps(fig.data, cls=PlotlyJSONEncoder)) - relayout = json.loads(json.dumps(fig.layout, cls=PlotlyJSONEncoder)) - - fig_json = json.dumps({'data': redata, 'layout': relayout}) - - if fpath: - with open(fpath, 'w') as f: - f.write(fig_json) - else: - return fig_json - #__| - -def plotlyfromjson(fpath): - """Render a plotly figure from a json file. - - Code obtained from: - https://github.com/plotly/plotly.py/issues/579 - - Args: - fpath: - """ - #| - plotlyfromjson - with open(fpath, 'r') as f: - v = json.loads(f.read()) - - fig = go.Figure(data=v['data'], layout=v['layout']) - - return(fig) - # iplot(fig, show_link=False) - #__| +#!/usr/bin/env python + +"""Plotly methods. + +Author: Raul A. Flores +""" + +#| - Import Modules +import json +# import numpy as np + +from plotly.utils import PlotlyJSONEncoder +import plotly.graph_objs as go +#__| + +def plotlyfig2json(fig, fpath=None): + """Serialize a plotly figure object to JSON so it can be persisted to disk. + + Figure's persisted as JSON can be rebuilt using the plotly JSON chart API: + + Code obtained from: + https://github.com/plotly/plotly.py/issues/579 + + http://help.plot.ly/json-chart-schema/ + + If `fpath` is provided, JSON is written to file. + + Modified from https://github.com/nteract/nteract/issues/1229 + """ + #| - plotlyfig2json + redata = json.loads(json.dumps(fig.data, cls=PlotlyJSONEncoder)) + relayout = json.loads(json.dumps(fig.layout, cls=PlotlyJSONEncoder)) + + fig_json = json.dumps({'data': redata, 'layout': relayout}) + + if fpath: + with open(fpath, 'w') as f: + f.write(fig_json) + else: + return fig_json + #__| + +def plotlyfromjson(fpath): + """Render a plotly figure from a json file. + + Code obtained from: + https://github.com/plotly/plotly.py/issues/579 + + Args: + fpath: + """ + #| - plotlyfromjson + with open(fpath, 'r') as f: + v = json.loads(f.read()) + + fig = go.Figure(data=v['data'], layout=v['layout']) + + return(fig) + # iplot(fig, show_link=False) + #__| diff --git a/oxr_reaction/adsorbate_scaling.py b/oxr_reaction/adsorbate_scaling.py index 29a64fe..072e1ef 100644 --- a/oxr_reaction/adsorbate_scaling.py +++ b/oxr_reaction/adsorbate_scaling.py @@ -1,339 +1,339 @@ -#!/usr/bin/env python - -"""ORR/OER adsorbate energy scaling class and methods. - -Author: Raul A. Flores -""" - - -#| - IMPORT MODULES -# import numpy as np -# -# import pandas as pd -# pd.options.mode.chained_assignment = None -# -# from sklearn.linear_model import LinearRegression -# -# # import plotly.plotly as py -# import plotly.graph_objs as go -# -# -# from orr_reaction.orr_series import ORR_Free_E_Series -#__| - - -class Adsorbate_Scaling: - """ORR/OER adsorbates' dG/E of adsorption scaling. - - Development Notes: - """ - - #| - Adsorbate_Scaling **************************************************** - - def __init__(self, - tmp=42 - ): - """ - """ - #| - __init__ - self.tmp = tmp - - #__| - - def tmp_meth(self, - ): - """ - """ - #| - tmp - tmp = 42 - return(tmp) - #__| - - #__| ********************************************************************** - - -def get_g_ooh(m_ooh, b_ooh, g_oh): - """ - """ - #| - get_g_ooh - g_ooh = m_ooh * g_oh + b_ooh - return(g_ooh) - #__| - -def get_g_o(m_o, b_o, g_oh): - """ - """ - #| - get_g_o - g_o = m_o * g_oh + b_o - return(g_o) - #__| - -def get_g_oh(m_oh, b_oh, g_oh): - """ - """ - #| - get_g_oh - g_oh = m_oh * g_oh + b_oh - return(g_oh) - #__| - -def lim_U_i( - g_oh=None, - g_o_minus_g_oh=None, - - mech_step=None, # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' - gas_molec_dict=None, - scaling_dict=None, - rxn_direction="forward", - ): - """ - Calculate the following mechanistic step of the OER/ORR: - O2 + (H+ + e-) --> *OOH - - Args: - g_oh: - gas_molec_dict: - scaling_dict: - rxn_direction: - """ - #| - lim_U_i - - #| - Checking Input Types - if g_oh is None and g_o_minus_g_oh is None: - raise ValueError("Need to provide either g_oh or g_o_minus_g_oh") - - if g_oh is not None and g_o_minus_g_oh is not None: - raise ValueError("Please don't provide both g_oh and g_o_minus_g_oh") - - assert gas_molec_dict is not None, "Please provide gas_molec_dict" - assert scaling_dict is not None, "Please provide the scaling_dict" - assert mech_step is not None, "Please provide the step to calculate" - #__| - - #| - linear fit and gas molecule data - m_ooh = scaling_dict["ooh"]["m"] - b_ooh = scaling_dict["ooh"]["b"] - - m_o = scaling_dict["o"]["m"] - b_o = scaling_dict["o"]["b"] - - m_oh = scaling_dict["oh"]["m"] - b_oh = scaling_dict["oh"]["b"] - - - g_o2 = gas_molec_dict["o2"] - g_h2 = gas_molec_dict["h2"] - g_h2o = gas_molec_dict["h2o"] - #__| - - if g_o_minus_g_oh is not None: - """ - (G_O-G_OH) = m_o*G_OH + b_o - (G_OH) - (G_O-G_OH) - b_o = G_OH*(m_o - 1) - G_OH = [(G_O-G_OH) - b_o] / (m_o - 1) - """ - g_oh = (g_o_minus_g_oh - b_o) / (m_o - 1) - - elif g_oh is not None: - g_oh = g_oh - - #| - Calculating Limiting Potential for all legs - if mech_step == "o2_to_ooh": - lim_U_out = get_g_ooh(m_ooh, b_ooh, g_oh) + \ - - g_o2 - - elif mech_step == "ooh_to_o": - lim_U_out = get_g_o(m_o, b_o, g_oh) + \ - g_h2o + \ - - get_g_ooh(m_ooh, b_ooh, g_oh) - - elif mech_step == "o_to_oh": - lim_U_out = get_g_oh(m_oh, b_oh, g_oh) + \ - - get_g_o(m_o, b_o, g_oh) - - elif mech_step == "oh_to_h2o": - lim_U_out = g_h2o + \ - - get_g_oh(m_oh, b_oh, g_oh) - else: - raise ValueError("Woops, error here (9sdfijsd9)") - #__| - - if rxn_direction == "forward": - lim_U_out = - lim_U_out - elif rxn_direction == "reverse": - lim_U_out = + lim_U_out - - return(lim_U_out) - #__| - - - - -#| - __old__ - -# def lim_U_o2_to_ooh(g_oh, -# gas_molec_dict, scaling_dict, rxn_direction="forward"): -# """ -# Calculate the following mechanistic step of the OER/ORR: -# O2 + (H+ + e-) --> *OOH -# -# Args: -# g_oh: -# gas_molec_dict: -# scaling_dict: -# rxn_direction: -# """ -# #| - lim_U_o2_to_ooh -# -# #| - linear fit and gas molecule data -# m_ooh = scaling_dict["ooh"]["m"] -# b_ooh = scaling_dict["ooh"]["b"] -# -# m_o = scaling_dict["o"]["m"] -# b_o = scaling_dict["o"]["b"] -# -# m_oh = scaling_dict["oh"]["m"] -# b_oh = scaling_dict["oh"]["b"] -# -# -# g_o2 = gas_molec_dict["o2"] -# g_h2 = gas_molec_dict["h2"] -# g_h2o = gas_molec_dict["h2o"] -# #__| -# -# -# if False: -# -# g_oh = (TMP - b_o) / (m_o - 1) -# -# lim_U_out = get_g_ooh(m_ooh, b_ooh, g_oh) - g_o2 -# -# if rxn_direction == "forward": -# lim_U_out = - lim_U_out -# elif rxn_direction == "reverse": -# lim_U_out = + lim_U_out -# -# return(lim_U_out) -# #__| -# -# def lim_U_ooh_to_o(g_oh, -# gas_molec_dict, scaling_dict, rxn_direction="forward"): -# """ -# Calculate the following mechanistic step of the OER/ORR: -# *OOH + (H+ + e-) --> *O + H2O -# -# Args: -# g_oh: -# gas_molec_dict: -# scaling_dict: -# rxn_direction: -# """ -# #| - lim_U_ooh_to_o -# -# #| - linear fit and gas molecule data -# m_ooh = scaling_dict["ooh"]["m"] -# b_ooh = scaling_dict["ooh"]["b"] -# -# m_o = scaling_dict["o"]["m"] -# b_o = scaling_dict["o"]["b"] -# -# m_oh = scaling_dict["oh"]["m"] -# b_oh = scaling_dict["oh"]["b"] -# -# -# g_o2 = gas_molec_dict["o2"] -# g_h2 = gas_molec_dict["h2"] -# g_h2o = gas_molec_dict["h2o"] -# #__| -# -# lim_U_out = get_g_o(m_o, -# b_o, g_oh) + g_h2o - get_g_ooh(m_ooh, b_ooh, g_oh) -# -# if rxn_direction == "forward": -# lim_U_out = - lim_U_out -# elif rxn_direction == "reverse": -# lim_U_out = + lim_U_out -# -# return(lim_U_out) -# #__| -# -# def lim_U_o_to_oh(g_oh, -# gas_molec_dict, scaling_dict, rxn_direction="forward"): -# """ -# Calculate the following mechanistic step of the OER/ORR: -# O* + (H+ + e-) --> *OH -# -# Args: -# g_oh: -# gas_molec_dict: -# scaling_dict: -# rxn_direction: -# """ -# #| - lim_U_o_to_oh -# -# #| - linear fit and gas molecule data -# m_ooh = scaling_dict["ooh"]["m"] -# b_ooh = scaling_dict["ooh"]["b"] -# -# m_o = scaling_dict["o"]["m"] -# b_o = scaling_dict["o"]["b"] -# -# m_oh = scaling_dict["oh"]["m"] -# b_oh = scaling_dict["oh"]["b"] -# -# -# g_o2 = gas_molec_dict["o2"] -# g_h2 = gas_molec_dict["h2"] -# g_h2o = gas_molec_dict["h2o"] -# #__| -# -# lim_U_out = get_g_oh(m_oh, b_oh, g_oh) - get_g_o(m_o, b_o, g_oh) -# -# if rxn_direction == "forward": -# lim_U_out = - lim_U_out -# elif rxn_direction == "reverse": -# lim_U_out = + lim_U_out -# -# return(lim_U_out) -# #__| -# -# def lim_U_oh_to_h2o(g_oh, -# gas_molec_dict, scaling_dict, rxn_direction="forward"): -# """ -# Calculate the following mechanistic step of the OER/ORR: -# *OH + (H+ + e-) --> H2O -# -# Args: -# g_oh: -# gas_molec_dict: -# scaling_dict: -# rxn_direction: -# """ -# #| - lim_U_oh_to_h2o -# -# #| - linear fit and gas molecule data -# m_ooh = scaling_dict["ooh"]["m"] -# b_ooh = scaling_dict["ooh"]["b"] -# -# m_o = scaling_dict["o"]["m"] -# b_o = scaling_dict["o"]["b"] -# -# m_oh = scaling_dict["oh"]["m"] -# b_oh = scaling_dict["oh"]["b"] -# -# -# g_o2 = gas_molec_dict["o2"] -# g_h2 = gas_molec_dict["h2"] -# g_h2o = gas_molec_dict["h2o"] -# #__| -# -# lim_U_out = g_h2o - get_g_oh(m_oh, b_oh, g_oh) -# -# if rxn_direction == "forward": -# lim_U_out = - lim_U_out -# elif rxn_direction == "reverse": -# lim_U_out = + lim_U_out -# -# return(lim_U_out) -# #__| -# -#__| +#!/usr/bin/env python + +"""ORR/OER adsorbate energy scaling class and methods. + +Author: Raul A. Flores +""" + + +#| - IMPORT MODULES +# import numpy as np +# +# import pandas as pd +# pd.options.mode.chained_assignment = None +# +# from sklearn.linear_model import LinearRegression +# +# # import plotly.plotly as py +# import plotly.graph_objs as go +# +# +# from orr_reaction.orr_series import ORR_Free_E_Series +#__| + + +class Adsorbate_Scaling: + """ORR/OER adsorbates' dG/E of adsorption scaling. + + Development Notes: + """ + + #| - Adsorbate_Scaling **************************************************** + + def __init__(self, + tmp=42 + ): + """ + """ + #| - __init__ + self.tmp = tmp + + #__| + + def tmp_meth(self, + ): + """ + """ + #| - tmp + tmp = 42 + return(tmp) + #__| + + #__| ********************************************************************** + + +def get_g_ooh(m_ooh, b_ooh, g_oh): + """ + """ + #| - get_g_ooh + g_ooh = m_ooh * g_oh + b_ooh + return(g_ooh) + #__| + +def get_g_o(m_o, b_o, g_oh): + """ + """ + #| - get_g_o + g_o = m_o * g_oh + b_o + return(g_o) + #__| + +def get_g_oh(m_oh, b_oh, g_oh): + """ + """ + #| - get_g_oh + g_oh = m_oh * g_oh + b_oh + return(g_oh) + #__| + +def lim_U_i( + g_oh=None, + g_o_minus_g_oh=None, + + mech_step=None, # 'o2_to_ooh', 'ooh_to_o', 'o_to_oh', 'oh_to_h2o' + gas_molec_dict=None, + scaling_dict=None, + rxn_direction="forward", + ): + """ + Calculate the following mechanistic step of the OER/ORR: + O2 + (H+ + e-) --> *OOH + + Args: + g_oh: + gas_molec_dict: + scaling_dict: + rxn_direction: + """ + #| - lim_U_i + + #| - Checking Input Types + if g_oh is None and g_o_minus_g_oh is None: + raise ValueError("Need to provide either g_oh or g_o_minus_g_oh") + + if g_oh is not None and g_o_minus_g_oh is not None: + raise ValueError("Please don't provide both g_oh and g_o_minus_g_oh") + + assert gas_molec_dict is not None, "Please provide gas_molec_dict" + assert scaling_dict is not None, "Please provide the scaling_dict" + assert mech_step is not None, "Please provide the step to calculate" + #__| + + #| - linear fit and gas molecule data + m_ooh = scaling_dict["ooh"]["m"] + b_ooh = scaling_dict["ooh"]["b"] + + m_o = scaling_dict["o"]["m"] + b_o = scaling_dict["o"]["b"] + + m_oh = scaling_dict["oh"]["m"] + b_oh = scaling_dict["oh"]["b"] + + + g_o2 = gas_molec_dict["o2"] + g_h2 = gas_molec_dict["h2"] + g_h2o = gas_molec_dict["h2o"] + #__| + + if g_o_minus_g_oh is not None: + """ + (G_O-G_OH) = m_o*G_OH + b_o - (G_OH) + (G_O-G_OH) - b_o = G_OH*(m_o - 1) + G_OH = [(G_O-G_OH) - b_o] / (m_o - 1) + """ + g_oh = (g_o_minus_g_oh - b_o) / (m_o - 1) + + elif g_oh is not None: + g_oh = g_oh + + #| - Calculating Limiting Potential for all legs + if mech_step == "o2_to_ooh": + lim_U_out = get_g_ooh(m_ooh, b_ooh, g_oh) + \ + - g_o2 + + elif mech_step == "ooh_to_o": + lim_U_out = get_g_o(m_o, b_o, g_oh) + \ + g_h2o + \ + - get_g_ooh(m_ooh, b_ooh, g_oh) + + elif mech_step == "o_to_oh": + lim_U_out = get_g_oh(m_oh, b_oh, g_oh) + \ + - get_g_o(m_o, b_o, g_oh) + + elif mech_step == "oh_to_h2o": + lim_U_out = g_h2o + \ + - get_g_oh(m_oh, b_oh, g_oh) + else: + raise ValueError("Woops, error here (9sdfijsd9)") + #__| + + if rxn_direction == "forward": + lim_U_out = - lim_U_out + elif rxn_direction == "reverse": + lim_U_out = + lim_U_out + + return(lim_U_out) + #__| + + + + +#| - __old__ + +# def lim_U_o2_to_ooh(g_oh, +# gas_molec_dict, scaling_dict, rxn_direction="forward"): +# """ +# Calculate the following mechanistic step of the OER/ORR: +# O2 + (H+ + e-) --> *OOH +# +# Args: +# g_oh: +# gas_molec_dict: +# scaling_dict: +# rxn_direction: +# """ +# #| - lim_U_o2_to_ooh +# +# #| - linear fit and gas molecule data +# m_ooh = scaling_dict["ooh"]["m"] +# b_ooh = scaling_dict["ooh"]["b"] +# +# m_o = scaling_dict["o"]["m"] +# b_o = scaling_dict["o"]["b"] +# +# m_oh = scaling_dict["oh"]["m"] +# b_oh = scaling_dict["oh"]["b"] +# +# +# g_o2 = gas_molec_dict["o2"] +# g_h2 = gas_molec_dict["h2"] +# g_h2o = gas_molec_dict["h2o"] +# #__| +# +# +# if False: +# +# g_oh = (TMP - b_o) / (m_o - 1) +# +# lim_U_out = get_g_ooh(m_ooh, b_ooh, g_oh) - g_o2 +# +# if rxn_direction == "forward": +# lim_U_out = - lim_U_out +# elif rxn_direction == "reverse": +# lim_U_out = + lim_U_out +# +# return(lim_U_out) +# #__| +# +# def lim_U_ooh_to_o(g_oh, +# gas_molec_dict, scaling_dict, rxn_direction="forward"): +# """ +# Calculate the following mechanistic step of the OER/ORR: +# *OOH + (H+ + e-) --> *O + H2O +# +# Args: +# g_oh: +# gas_molec_dict: +# scaling_dict: +# rxn_direction: +# """ +# #| - lim_U_ooh_to_o +# +# #| - linear fit and gas molecule data +# m_ooh = scaling_dict["ooh"]["m"] +# b_ooh = scaling_dict["ooh"]["b"] +# +# m_o = scaling_dict["o"]["m"] +# b_o = scaling_dict["o"]["b"] +# +# m_oh = scaling_dict["oh"]["m"] +# b_oh = scaling_dict["oh"]["b"] +# +# +# g_o2 = gas_molec_dict["o2"] +# g_h2 = gas_molec_dict["h2"] +# g_h2o = gas_molec_dict["h2o"] +# #__| +# +# lim_U_out = get_g_o(m_o, +# b_o, g_oh) + g_h2o - get_g_ooh(m_ooh, b_ooh, g_oh) +# +# if rxn_direction == "forward": +# lim_U_out = - lim_U_out +# elif rxn_direction == "reverse": +# lim_U_out = + lim_U_out +# +# return(lim_U_out) +# #__| +# +# def lim_U_o_to_oh(g_oh, +# gas_molec_dict, scaling_dict, rxn_direction="forward"): +# """ +# Calculate the following mechanistic step of the OER/ORR: +# O* + (H+ + e-) --> *OH +# +# Args: +# g_oh: +# gas_molec_dict: +# scaling_dict: +# rxn_direction: +# """ +# #| - lim_U_o_to_oh +# +# #| - linear fit and gas molecule data +# m_ooh = scaling_dict["ooh"]["m"] +# b_ooh = scaling_dict["ooh"]["b"] +# +# m_o = scaling_dict["o"]["m"] +# b_o = scaling_dict["o"]["b"] +# +# m_oh = scaling_dict["oh"]["m"] +# b_oh = scaling_dict["oh"]["b"] +# +# +# g_o2 = gas_molec_dict["o2"] +# g_h2 = gas_molec_dict["h2"] +# g_h2o = gas_molec_dict["h2o"] +# #__| +# +# lim_U_out = get_g_oh(m_oh, b_oh, g_oh) - get_g_o(m_o, b_o, g_oh) +# +# if rxn_direction == "forward": +# lim_U_out = - lim_U_out +# elif rxn_direction == "reverse": +# lim_U_out = + lim_U_out +# +# return(lim_U_out) +# #__| +# +# def lim_U_oh_to_h2o(g_oh, +# gas_molec_dict, scaling_dict, rxn_direction="forward"): +# """ +# Calculate the following mechanistic step of the OER/ORR: +# *OH + (H+ + e-) --> H2O +# +# Args: +# g_oh: +# gas_molec_dict: +# scaling_dict: +# rxn_direction: +# """ +# #| - lim_U_oh_to_h2o +# +# #| - linear fit and gas molecule data +# m_ooh = scaling_dict["ooh"]["m"] +# b_ooh = scaling_dict["ooh"]["b"] +# +# m_o = scaling_dict["o"]["m"] +# b_o = scaling_dict["o"]["b"] +# +# m_oh = scaling_dict["oh"]["m"] +# b_oh = scaling_dict["oh"]["b"] +# +# +# g_o2 = gas_molec_dict["o2"] +# g_h2 = gas_molec_dict["h2"] +# g_h2o = gas_molec_dict["h2o"] +# #__| +# +# lim_U_out = g_h2o - get_g_oh(m_oh, b_oh, g_oh) +# +# if rxn_direction == "forward": +# lim_U_out = - lim_U_out +# elif rxn_direction == "reverse": +# lim_U_out = + lim_U_out +# +# return(lim_U_out) +# #__| +# +#__| diff --git a/oxr_reaction/oxr_methods.py b/oxr_reaction/oxr_methods.py index 31ffc62..7f56a15 100644 --- a/oxr_reaction/oxr_methods.py +++ b/oxr_reaction/oxr_methods.py @@ -1,550 +1,550 @@ -#!/usr/bin/env python - -"""ORR energetics classes and methods. - -Author: Raul A. Flores -""" - -#| - IMPORT MODULES -import copy -import numpy as np -import pandas as pd - -from plotly.graph_objs import Scatter - -pd.options.mode.chained_assignment = None - -from oxr_reaction.oxr_series import ORR_Free_E_Series -#__| - -#| - __old__ -def plotly_fed_layout( - plot_title="FED", - plot_title_size=18, - tick_lab_size=16, - axes_lab_size=18, - legend_size=18, - ): - """ - """ - #| - plotly_fed_layout - xax_labels = ["O2", "OOH", "O", "OH", "H2O"] - layout = { - - "title": plot_title, - - "font": { - "family": "Courier New, monospace", - "size": plot_title_size, - "color": "black", - }, - - #| - Axes -------------------------------------------------------------- - "yaxis": { - "title": "Free Energy [eV]", - "zeroline": True, - "titlefont": dict(size=axes_lab_size), - "showgrid": False, - "tickfont": dict( - size=tick_lab_size, - ), - }, - - "xaxis": { - "title": "Reaction Coordinate", - "zeroline": True, - "titlefont": dict(size=axes_lab_size), - "showgrid": False, - - # "showticklabels": False, - - "ticktext": xax_labels, - "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - - "tickfont": dict( - size=tick_lab_size, - ), - }, - #__| ------------------------------------------------------------------- - - #| - Legend ------------------------------------------------------------ - "legend": { - "traceorder": "normal", - "font": dict(size=legend_size) - }, - #__| ------------------------------------------------------------------- - - #| - Plot Size - # "width": 200 * 4., - # "height": 200 * 3., - #__| - - } - - return(layout) - - #__| - -#__| - - -def calc_ads_e( - df_row, - bare_raw_e, - correction=0., - oxy_ref_e=-443.70964, - hyd_ref_e=-16.46018, - ): - """Calculate adsorption energies from raw DFT energetics. - - Default oxygen reference energy is based on water - - Args: - df_row: Pandas dataframe row - bare_raw_e: Bare slab raw DFT energy - correction: Energy correction (ZPE, entropy, solvation, etc.) - oxy_ref_e: - hyd_ref_e: - """ - #| - calc_ads_e - row = df_row - bare_slab = bare_raw_e - oxy_ref = oxy_ref_e - hyd_ref = hyd_ref_e - - #| - Oxygen & Hydrogen Atom Count - atoms_col = "atom_type_num_dict" - if atoms_col in list(row.index): - try: - num_O = row[atoms_col][0]["O"] - except: - num_O = 0 - - try: - num_H = row[atoms_col][0]["H"] - except: - num_H = 0 - - else: - - if row["adsorbate"] == "ooh": - num_O = 2 - num_H = 1 - elif row["adsorbate"] == "o": - num_O = 1 - num_H = 0 - elif row["adsorbate"] == "oh": - num_O = 1 - num_H = 1 - elif row["adsorbate"] == "bare": - num_O = 0 - num_H = 0 - #__| - - # print("oxy_ref: ", oxy_ref) - # print("hyd_ref:", hyd_ref) - - try: - raw_e = row["elec_energy"] - ads_e_i = raw_e - (bare_slab + num_O * oxy_ref + num_H * hyd_ref) - ads_e_i += correction - - # ads_e_i = raw_e - bare_slab - num_O * oxy_ref - num_H * hyd_ref - # ads_e_i += correction - except: - ads_e_i = None - - return(ads_e_i) - #__| - -def df_calc_adsorption_e( - df, - - oxy_ref, - hyd_ref, - - bare_slab_e, - bare_slab_var=None, - - corrections_mode="df_column", # 'corr_dict', 'df_column', None - corrections_column="gibbs_correction", - - corrections_dict=None, - ): - """Calculate and add adsorption energy column to data_frame. - - Args: - df: - """ - #| - df_calc_adsorption_e - ads_e_list = [] - for index, row in df.iterrows(): - bare_e = bare_slab_e - - #| - Correction - corr = 0. - # corr = fe_corr_dict[row["adsorbate"]] - - if corrections_mode == "df_column": - corr = row[corrections_column] - - # If "df_column" method return 0. then try to use correction_dict - if corr == 0.: - if corrections_dict is not None: - corr = corrections_dict[row["adsorbate"]] - - elif corrections_mode == "corr_dict" and corrections_dict is not None: - corr = corrections_dict[row["adsorbate"]] - else: - print("No correction being applied") - corr = 0. - #__| - - if type(bare_slab_e) == dict: - bare_e = bare_slab_e[row[bare_slab_var]] - - elif type(bare_slab_e) == float: - bare_e = bare_slab_e - - ads_e_i = calc_ads_e( - row, - # bare_slab, - bare_e, - correction=corr, - oxy_ref_e=oxy_ref, - hyd_ref_e=hyd_ref, - ) - ads_e_list.append(ads_e_i) - - df["ads_e"] = np.array(ads_e_list) - #__| - -def lowest_e_path( - df, - jobs_variables, - color_list, - create_ideal_series=True, - opt_name=None, - bias=0., - manual_props="*TEMP*", - plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", - smart_format=None, - ): - """Find the lowest energy pathway FED. - - COMBAK - - From a set of FE pathways corresponding to different sites, the lowest - energy states will be selected to construct a new FED. - - Args: - df: - jobs_variables: - Result of Jobs.tree_level_labels - color_list: - bias: - - """ - #| - lowest_e_path - - #| - Grouping By Adsorbate Type - df = copy.deepcopy(df) - groupby = copy.deepcopy(jobs_variables) - - groupby.remove("site") - groupby.remove("adsorbate") - - data_master = {} - if groupby == []: - series_list = [] - for ads_i in df.groupby("adsorbate"): - - min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] - series_list.append(min_e_row) - - df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T - data_master[manual_props] = df_i - - else: - for group_i in df.groupby(groupby): - series_list = [] - for ads_i in group_i[1].groupby("adsorbate"): - - min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] - series_list.append(min_e_row) - - df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T - data_master[group_i[0]] = df_i - - #__| - - #| - Creating Data Sets - - #| - Creating FED Datasets - data_list = [] - # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): - for i_cnt, (key, fe_dict) in enumerate(data_master.items()): - - ORR = ORR_Free_E_Plot( - free_energy_df=fe_dict, - ) - - dat_lst = ORR.plot_fed_series( - bias=bias, - opt_name=opt_name, - properties=key, - color_list=color_list, - i_cnt=i_cnt, - hover_text_col="site", - smart_format=smart_format, - ) - - data_list.extend(dat_lst) - #__| - - #| - Creating Ideal FED Dataset - if create_ideal_series: - e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) - - dat_ideal = ORR.create_plotly_series( - e_list_ideal, - group="Ideal", - name="Ideal", - color=color_list[-1], - plot_mode="full_lines", - ) - - dat_lst = data_list + dat_ideal - - else: - - dat_lst = data_list - - - #__| - - # dat_lst = data_list + dat_ideal - - #__| - - #| - Plotting - - #| - Plot Settings - plot_title_size = 18 - tick_lab_size = 16 - axes_lab_size = 18 - legend_size = 18 - #__| - - #| - Plot Layout - # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] - # layout = { - # - # "title": plot_title, - # - # "font": { - # "family": "Courier New, monospace", - # "size": plot_title_size, - # "color": "black", - # }, - # - # #| - Axes -------------------------------------------------------------- - # "yaxis": { - # "title": "Free Energy [eV]", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # - # "xaxis": { - # "title": "Reaction Coordinate", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # - # # "showticklabels": False, - # - # "ticktext": xax_labels, - # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - # - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Legend ------------------------------------------------------------ - # "legend": { - # "traceorder": "normal", - # "font": dict(size=legend_size) - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Plot Size - # # "width": 200 * 4., - # # "height": 200 * 3., - # #__| - # - # } - #__| - - layout = plotly_fed_layout(plot_title=plot_title) - - #__| - - return(dat_lst, layout) - - #__| - -def plot_all_states( - df, - jobs_variables, - color_list, - bias=0., - hover_text_col="site", - create_ideal_series=True, - plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", - smart_format=None, - ): - """ - - Args: - df: - jobs_variables: - color_list: - bias: - plot_title: - """ - #| - plot_all_states - - #| - Grouping By Adsorbate Type - - groupby = copy.deepcopy(jobs_variables) - # groupby = copy.deepcopy(Jojobs_variablesbs.tree_level_labels) - groupby.remove("adsorbate") - - data_master = {} - for group_i in df.groupby(groupby): - - data_master[group_i[0]] = group_i[1] - #__| - - #| - Creating Data Sets - - #| - Creating FED Datasets - data_list = [] - # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): - for i_cnt, (key, fe_dict) in enumerate(data_master.items()): - ORR = ORR_Free_E_Plot( - free_energy_df=fe_dict, - ) - - dat_lst = ORR.plot_fed_series( - bias=bias, - properties=key, - color_list=color_list, - i_cnt=i_cnt, - # hover_text_col="site" - hover_text_col=hover_text_col, - plot_mode="states_only", - smart_format=smart_format, - ) - - data_list.extend(dat_lst) - #__| - - #| - Creating Ideal FED Dataset - if create_ideal_series: - - e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) - - dat_ideal = ORR.create_plotly_series( - e_list_ideal, - group="Ideal", - name="Ideal", - color="red", - plot_mode="full_lines", - ) - - dat_lst = data_list + dat_ideal - #__| - - else: - dat_lst = data_list - - #__| - - #| - Plotting - - #| - Plot Settings - plot_title_size = 18 - tick_lab_size = 16 - axes_lab_size = 18 - legend_size = 12 - #__| - - #| - Plot Layout - # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] - # layout = { - # - # "title": plot_title, - # - # "font": { - # "family": "Courier New, monospace", - # "size": plot_title_size, - # "color": "black", - # }, - # - # #| - Axes -------------------------------------------------------------- - # "yaxis": { - # "title": "Free Energy [eV]", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # - # "xaxis": { - # "title": "Reaction Coordinate", - # "zeroline": True, - # "titlefont": dict(size=axes_lab_size), - # "showgrid": False, - # - # # "showticklabels": False, - # - # "ticktext": xax_labels, - # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - # - # "tickfont": dict( - # size=tick_lab_size, - # ), - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Legend ------------------------------------------------------------ - # "legend": { - # "traceorder": "normal", - # "font": dict(size=legend_size) - # }, - # #__| ------------------------------------------------------------------- - # - # #| - Plot Size - # "width": 200 * 4., - # "height": 200 * 3., - # #__| - # - # } - #__| - - layout = plotly_fed_layout(plot_title=plot_title) - - return(dat_lst, layout) - - #__| - - #__| +#!/usr/bin/env python + +"""ORR energetics classes and methods. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import copy +import numpy as np +import pandas as pd + +from plotly.graph_objs import Scatter + +pd.options.mode.chained_assignment = None + +from oxr_reaction.oxr_series import ORR_Free_E_Series +#__| + +#| - __old__ +def plotly_fed_layout( + plot_title="FED", + plot_title_size=18, + tick_lab_size=16, + axes_lab_size=18, + legend_size=18, + ): + """ + """ + #| - plotly_fed_layout + xax_labels = ["O2", "OOH", "O", "OH", "H2O"] + layout = { + + "title": plot_title, + + "font": { + "family": "Courier New, monospace", + "size": plot_title_size, + "color": "black", + }, + + #| - Axes -------------------------------------------------------------- + "yaxis": { + "title": "Free Energy [eV]", + "zeroline": True, + "titlefont": dict(size=axes_lab_size), + "showgrid": False, + "tickfont": dict( + size=tick_lab_size, + ), + }, + + "xaxis": { + "title": "Reaction Coordinate", + "zeroline": True, + "titlefont": dict(size=axes_lab_size), + "showgrid": False, + + # "showticklabels": False, + + "ticktext": xax_labels, + "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], + + "tickfont": dict( + size=tick_lab_size, + ), + }, + #__| ------------------------------------------------------------------- + + #| - Legend ------------------------------------------------------------ + "legend": { + "traceorder": "normal", + "font": dict(size=legend_size) + }, + #__| ------------------------------------------------------------------- + + #| - Plot Size + # "width": 200 * 4., + # "height": 200 * 3., + #__| + + } + + return(layout) + + #__| + +#__| + + +def calc_ads_e( + df_row, + bare_raw_e, + correction=0., + oxy_ref_e=-443.70964, + hyd_ref_e=-16.46018, + ): + """Calculate adsorption energies from raw DFT energetics. + + Default oxygen reference energy is based on water + + Args: + df_row: Pandas dataframe row + bare_raw_e: Bare slab raw DFT energy + correction: Energy correction (ZPE, entropy, solvation, etc.) + oxy_ref_e: + hyd_ref_e: + """ + #| - calc_ads_e + row = df_row + bare_slab = bare_raw_e + oxy_ref = oxy_ref_e + hyd_ref = hyd_ref_e + + #| - Oxygen & Hydrogen Atom Count + atoms_col = "atom_type_num_dict" + if atoms_col in list(row.index): + try: + num_O = row[atoms_col][0]["O"] + except: + num_O = 0 + + try: + num_H = row[atoms_col][0]["H"] + except: + num_H = 0 + + else: + + if row["adsorbate"] == "ooh": + num_O = 2 + num_H = 1 + elif row["adsorbate"] == "o": + num_O = 1 + num_H = 0 + elif row["adsorbate"] == "oh": + num_O = 1 + num_H = 1 + elif row["adsorbate"] == "bare": + num_O = 0 + num_H = 0 + #__| + + # print("oxy_ref: ", oxy_ref) + # print("hyd_ref:", hyd_ref) + + try: + raw_e = row["elec_energy"] + ads_e_i = raw_e - (bare_slab + num_O * oxy_ref + num_H * hyd_ref) + ads_e_i += correction + + # ads_e_i = raw_e - bare_slab - num_O * oxy_ref - num_H * hyd_ref + # ads_e_i += correction + except: + ads_e_i = None + + return(ads_e_i) + #__| + +def df_calc_adsorption_e( + df, + + oxy_ref, + hyd_ref, + + bare_slab_e, + bare_slab_var=None, + + corrections_mode="df_column", # 'corr_dict', 'df_column', None + corrections_column="gibbs_correction", + + corrections_dict=None, + ): + """Calculate and add adsorption energy column to data_frame. + + Args: + df: + """ + #| - df_calc_adsorption_e + ads_e_list = [] + for index, row in df.iterrows(): + bare_e = bare_slab_e + + #| - Correction + corr = 0. + # corr = fe_corr_dict[row["adsorbate"]] + + if corrections_mode == "df_column": + corr = row[corrections_column] + + # If "df_column" method return 0. then try to use correction_dict + if corr == 0.: + if corrections_dict is not None: + corr = corrections_dict[row["adsorbate"]] + + elif corrections_mode == "corr_dict" and corrections_dict is not None: + corr = corrections_dict[row["adsorbate"]] + else: + print("No correction being applied") + corr = 0. + #__| + + if type(bare_slab_e) == dict: + bare_e = bare_slab_e[row[bare_slab_var]] + + elif type(bare_slab_e) == float: + bare_e = bare_slab_e + + ads_e_i = calc_ads_e( + row, + # bare_slab, + bare_e, + correction=corr, + oxy_ref_e=oxy_ref, + hyd_ref_e=hyd_ref, + ) + ads_e_list.append(ads_e_i) + + df["ads_e"] = np.array(ads_e_list) + #__| + +def lowest_e_path( + df, + jobs_variables, + color_list, + create_ideal_series=True, + opt_name=None, + bias=0., + manual_props="*TEMP*", + plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", + smart_format=None, + ): + """Find the lowest energy pathway FED. + + COMBAK + + From a set of FE pathways corresponding to different sites, the lowest + energy states will be selected to construct a new FED. + + Args: + df: + jobs_variables: + Result of Jobs.tree_level_labels + color_list: + bias: + + """ + #| - lowest_e_path + + #| - Grouping By Adsorbate Type + df = copy.deepcopy(df) + groupby = copy.deepcopy(jobs_variables) + + groupby.remove("site") + groupby.remove("adsorbate") + + data_master = {} + if groupby == []: + series_list = [] + for ads_i in df.groupby("adsorbate"): + + min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] + series_list.append(min_e_row) + + df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T + data_master[manual_props] = df_i + + else: + for group_i in df.groupby(groupby): + series_list = [] + for ads_i in group_i[1].groupby("adsorbate"): + + min_e_row = ads_i[1].loc[ads_i[1]["ads_e"].idxmin()] + series_list.append(min_e_row) + + df_i = pd.DataFrame.from_items([(s.name, s) for s in series_list]).T + data_master[group_i[0]] = df_i + + #__| + + #| - Creating Data Sets + + #| - Creating FED Datasets + data_list = [] + # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): + for i_cnt, (key, fe_dict) in enumerate(data_master.items()): + + ORR = ORR_Free_E_Plot( + free_energy_df=fe_dict, + ) + + dat_lst = ORR.plot_fed_series( + bias=bias, + opt_name=opt_name, + properties=key, + color_list=color_list, + i_cnt=i_cnt, + hover_text_col="site", + smart_format=smart_format, + ) + + data_list.extend(dat_lst) + #__| + + #| - Creating Ideal FED Dataset + if create_ideal_series: + e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) + + dat_ideal = ORR.create_plotly_series( + e_list_ideal, + group="Ideal", + name="Ideal", + color=color_list[-1], + plot_mode="full_lines", + ) + + dat_lst = data_list + dat_ideal + + else: + + dat_lst = data_list + + + #__| + + # dat_lst = data_list + dat_ideal + + #__| + + #| - Plotting + + #| - Plot Settings + plot_title_size = 18 + tick_lab_size = 16 + axes_lab_size = 18 + legend_size = 18 + #__| + + #| - Plot Layout + # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] + # layout = { + # + # "title": plot_title, + # + # "font": { + # "family": "Courier New, monospace", + # "size": plot_title_size, + # "color": "black", + # }, + # + # #| - Axes -------------------------------------------------------------- + # "yaxis": { + # "title": "Free Energy [eV]", + # "zeroline": True, + # "titlefont": dict(size=axes_lab_size), + # "showgrid": False, + # "tickfont": dict( + # size=tick_lab_size, + # ), + # }, + # + # "xaxis": { + # "title": "Reaction Coordinate", + # "zeroline": True, + # "titlefont": dict(size=axes_lab_size), + # "showgrid": False, + # + # # "showticklabels": False, + # + # "ticktext": xax_labels, + # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], + # + # "tickfont": dict( + # size=tick_lab_size, + # ), + # }, + # #__| ------------------------------------------------------------------- + # + # #| - Legend ------------------------------------------------------------ + # "legend": { + # "traceorder": "normal", + # "font": dict(size=legend_size) + # }, + # #__| ------------------------------------------------------------------- + # + # #| - Plot Size + # # "width": 200 * 4., + # # "height": 200 * 3., + # #__| + # + # } + #__| + + layout = plotly_fed_layout(plot_title=plot_title) + + #__| + + return(dat_lst, layout) + + #__| + +def plot_all_states( + df, + jobs_variables, + color_list, + bias=0., + hover_text_col="site", + create_ideal_series=True, + plot_title="Free Energy Diagram for the Oxygen Reduction Reaction", + smart_format=None, + ): + """ + + Args: + df: + jobs_variables: + color_list: + bias: + plot_title: + """ + #| - plot_all_states + + #| - Grouping By Adsorbate Type + + groupby = copy.deepcopy(jobs_variables) + # groupby = copy.deepcopy(Jojobs_variablesbs.tree_level_labels) + groupby.remove("adsorbate") + + data_master = {} + for group_i in df.groupby(groupby): + + data_master[group_i[0]] = group_i[1] + #__| + + #| - Creating Data Sets + + #| - Creating FED Datasets + data_list = [] + # for i_cnt, (key, fe_dict) in enumerate(data_master.iteritems()): + for i_cnt, (key, fe_dict) in enumerate(data_master.items()): + ORR = ORR_Free_E_Plot( + free_energy_df=fe_dict, + ) + + dat_lst = ORR.plot_fed_series( + bias=bias, + properties=key, + color_list=color_list, + i_cnt=i_cnt, + # hover_text_col="site" + hover_text_col=hover_text_col, + plot_mode="states_only", + smart_format=smart_format, + ) + + data_list.extend(dat_lst) + #__| + + #| - Creating Ideal FED Dataset + if create_ideal_series: + + e_list_ideal = ORR.apply_bias(bias, ORR.ideal_energy) + + dat_ideal = ORR.create_plotly_series( + e_list_ideal, + group="Ideal", + name="Ideal", + color="red", + plot_mode="full_lines", + ) + + dat_lst = data_list + dat_ideal + #__| + + else: + dat_lst = data_list + + #__| + + #| - Plotting + + #| - Plot Settings + plot_title_size = 18 + tick_lab_size = 16 + axes_lab_size = 18 + legend_size = 12 + #__| + + #| - Plot Layout + # xax_labels = ["O2", "OOH", "O", "OH", "H2O"] + # layout = { + # + # "title": plot_title, + # + # "font": { + # "family": "Courier New, monospace", + # "size": plot_title_size, + # "color": "black", + # }, + # + # #| - Axes -------------------------------------------------------------- + # "yaxis": { + # "title": "Free Energy [eV]", + # "zeroline": True, + # "titlefont": dict(size=axes_lab_size), + # "showgrid": False, + # "tickfont": dict( + # size=tick_lab_size, + # ), + # }, + # + # "xaxis": { + # "title": "Reaction Coordinate", + # "zeroline": True, + # "titlefont": dict(size=axes_lab_size), + # "showgrid": False, + # + # # "showticklabels": False, + # + # "ticktext": xax_labels, + # "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], + # + # "tickfont": dict( + # size=tick_lab_size, + # ), + # }, + # #__| ------------------------------------------------------------------- + # + # #| - Legend ------------------------------------------------------------ + # "legend": { + # "traceorder": "normal", + # "font": dict(size=legend_size) + # }, + # #__| ------------------------------------------------------------------- + # + # #| - Plot Size + # "width": 200 * 4., + # "height": 200 * 3., + # #__| + # + # } + #__| + + layout = plotly_fed_layout(plot_title=plot_title) + + return(dat_lst, layout) + + #__| + + #__| diff --git a/oxr_reaction/oxr_rxn.py b/oxr_reaction/oxr_rxn.py index 3f6a347..a1d83ae 100644 --- a/oxr_reaction/oxr_rxn.py +++ b/oxr_reaction/oxr_rxn.py @@ -1,242 +1,242 @@ -#!/usr/bin/env python - -"""ORR energetics classes and methods. - -Author: Raul A. Flores -""" - -#| - IMPORT MODULES -import numpy as np -import pandas as pd - -from sklearn.linear_model import LinearRegression - -import plotly.graph_objs as go - -pd.options.mode.chained_assignment = None - -from oxr_reaction.oxr_series import ORR_Free_E_Series -from oxr_reaction.adsorbate_scaling import lim_U_i -# from oxr_reaction.oxr_rxn import ORR_Free_E_Plot -#__| - - -class ORR_Free_E_Plot: - """ORR free energy diagram class. - - ACTUALLY THIS IS GOING TO BE A GENERAL ORR/OER CLASS NOW!!!!!!!!!!!!!!!!!!! - - Development Notes: - TODO Rename this base class to OXR_BASE or something - TODO Should we consider the case where the bulk energy is not 0, and - we have to normalize all of the species energies by it? - """ - - #| - ORR_Free_E_Plot ****************************************************** - - def __init__(self, - free_energy_df=None, - ORR_Free_E_series_list=None, - state_title="adsorbate", - free_e_title="ads_e", - num_states=5, - smart_format=None, - bias=0., - color_list=None, - hover_text_col=None, - rxn_type="ORR", # ORR and OER - - # system_properties=None, - # opt_name=None, - # properties=None, - # i_cnt=0, - # plot_mode="all", - # smart_format=None, - # Plotting ************************************************************ - # show_H_e_pairs_annotations=True, - # show_legend=True, - ): - """ - Input variables to class instance. - - Args: - free_energy_df: - Pandas dataframe containing the adsorbates as rows - Required columns, adsorbate, free energy - system_properties: - state_title: - free_e_title: - - rxn_type: - ORR or OER - """ - #| - __init__ - - #| - Setting Instance Attributes - self.fe_df = free_energy_df - # self.sys_props = system_properties - self.state_title = state_title - self.fe_title = free_e_title - self.num_states = num_states - - # self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] - # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] #COMBAK Is this being used anymore - - self.bias = bias - self.color_list = color_list - self.hover_text_col = hover_text_col - self.smart_format = smart_format - - # self.show_H_e_pairs_annotations = show_H_e_pairs_annotations - # self.show_legend = show_legend - - # *********************************** - # COMBAK, moving to FED class, remove later - self.plot_states_sep = 0.3 - self.plot_states_width = 1. - - self.rxn_type = rxn_type - #__| - - - if self.rxn_type == "ORR": - self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] - self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - - elif self.rxn_type == "OER": - self.rxn_mech_states = ["bulk", "oh", "o", "ooh", "bulk"] - self.ideal_energy = [0, 1.23, 2.46, 3.69, 4.92] - - # self.rxn_x_coord_array = self.create_rxn_coord_array( - # self.num_states, - # spacing=self.plot_states_sep, - # step_size=self.plot_states_width, - # ) - # - # self.mid_state_x_array = self.create_mid_state_x_array() - # # x_array_data = self.rxn_x_coord_array - - if ORR_Free_E_series_list is None: - self.series_list = [] - else: - self.series_list = ORR_Free_E_series_list - - #| - __old__ - # if free_energy_df is not None: - # self.add_bulk_entry() - # self.fill_missing_data() - # - # self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk - # self.energy_lst = self.rxn_energy_lst() - # self.num_of_elec = range(self.num_of_states)[::-1] - # self.overpotential = self.calc_overpotential()[0] - # self.limiting_step = self.calc_overpotential()[1] - # # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - # self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() - # self.overpotential_h2o2 = self.calc_overpotential_h2o2() - #__| - - #__| - - def __create_series_name__(self, series_i): - """ - """ - #| - __create_series_name__ - - if series_i.properties is not None: - name_i = "" - for key, value in series_i.properties.items(): - - # TODO | This is an old feature, get rid of it - if key == "coverage": - continue - - name_i += str(key) + ": " + str(value) + " | " - - else: - name_i = "" - - return(name_i) - #__| - - def __create_smart_format_dict__(self, property_dict, smart_format_dict): - """Create smart format dictionary. - - Args: - property_dict: - smart_format_dict: - """ - #| - __create_smart_format_dict__ - if property_dict is None: - return({}) - - format_dict = {} - for key_i, value_i in property_dict.items(): - for format_i in smart_format_dict: - if list(format_i[0])[0] == key_i: - if list(format_i[0].values())[0] == value_i: - format_dict.update(format_i[1]) - - return(format_dict) - #__| - - def add_series(self, - fe_df, - plot_mode="all", - name_i=None, - group=None, - opt_name=None, - smart_format=True, - format_dict=None, - overpotential_type="ORR", - system_properties=None, - property_key_list=None, - add_overpot=True, - color=None, - overpotential_given=False, - ): - """Add ORR_Free_E_Series instance to ORR_Free_E_Plot.series_list. - - Note: It would be much better to simply take all of the - ORR_Free_E_Series arguments as a **kwargs term. - - Args: - TEMP - """ - #| - add_series - if smart_format: - smart_format_i = self.smart_format - else: - smart_format_i = None - - ORR_Series = ORR_Free_E_Series( - free_energy_df=fe_df, - properties=system_properties, - property_key_list=property_key_list, - state_title=self.state_title, - free_e_title=self.fe_title, - group=group, - bias=self.bias, - # rxn_x_coord_array=self.rxn_x_coord_array, - name_i=name_i, - opt_name=opt_name, # ####### - - color_list=self.color_list, - color=color, - hover_text_col=self.hover_text_col, - plot_mode=plot_mode, # ########## - smart_format=smart_format_i, - format_dict=format_dict, - add_overpot=add_overpot, - rxn_type=self.rxn_type, - overpotential_given=overpotential_given, - - # properties=opt_name, - # overpotential_type=self.rxn_type, - # i_cnt=0, # ########## - ) - - self.series_list.append(ORR_Series) - #__| - - #__| ********************************************************************** +#!/usr/bin/env python + +"""ORR energetics classes and methods. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import numpy as np +import pandas as pd + +from sklearn.linear_model import LinearRegression + +import plotly.graph_objs as go + +pd.options.mode.chained_assignment = None + +from oxr_reaction.oxr_series import ORR_Free_E_Series +from oxr_reaction.adsorbate_scaling import lim_U_i +# from oxr_reaction.oxr_rxn import ORR_Free_E_Plot +#__| + + +class ORR_Free_E_Plot: + """ORR free energy diagram class. + + ACTUALLY THIS IS GOING TO BE A GENERAL ORR/OER CLASS NOW!!!!!!!!!!!!!!!!!!! + + Development Notes: + TODO Rename this base class to OXR_BASE or something + TODO Should we consider the case where the bulk energy is not 0, and + we have to normalize all of the species energies by it? + """ + + #| - ORR_Free_E_Plot ****************************************************** + + def __init__(self, + free_energy_df=None, + ORR_Free_E_series_list=None, + state_title="adsorbate", + free_e_title="ads_e", + num_states=5, + smart_format=None, + bias=0., + color_list=None, + hover_text_col=None, + rxn_type="ORR", # ORR and OER + + # system_properties=None, + # opt_name=None, + # properties=None, + # i_cnt=0, + # plot_mode="all", + # smart_format=None, + # Plotting ************************************************************ + # show_H_e_pairs_annotations=True, + # show_legend=True, + ): + """ + Input variables to class instance. + + Args: + free_energy_df: + Pandas dataframe containing the adsorbates as rows + Required columns, adsorbate, free energy + system_properties: + state_title: + free_e_title: + + rxn_type: + ORR or OER + """ + #| - __init__ + + #| - Setting Instance Attributes + self.fe_df = free_energy_df + # self.sys_props = system_properties + self.state_title = state_title + self.fe_title = free_e_title + self.num_states = num_states + + # self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] + # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] #COMBAK Is this being used anymore + + self.bias = bias + self.color_list = color_list + self.hover_text_col = hover_text_col + self.smart_format = smart_format + + # self.show_H_e_pairs_annotations = show_H_e_pairs_annotations + # self.show_legend = show_legend + + # *********************************** + # COMBAK, moving to FED class, remove later + self.plot_states_sep = 0.3 + self.plot_states_width = 1. + + self.rxn_type = rxn_type + #__| + + + if self.rxn_type == "ORR": + self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] + self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] + + elif self.rxn_type == "OER": + self.rxn_mech_states = ["bulk", "oh", "o", "ooh", "bulk"] + self.ideal_energy = [0, 1.23, 2.46, 3.69, 4.92] + + # self.rxn_x_coord_array = self.create_rxn_coord_array( + # self.num_states, + # spacing=self.plot_states_sep, + # step_size=self.plot_states_width, + # ) + # + # self.mid_state_x_array = self.create_mid_state_x_array() + # # x_array_data = self.rxn_x_coord_array + + if ORR_Free_E_series_list is None: + self.series_list = [] + else: + self.series_list = ORR_Free_E_series_list + + #| - __old__ + # if free_energy_df is not None: + # self.add_bulk_entry() + # self.fill_missing_data() + # + # self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk + # self.energy_lst = self.rxn_energy_lst() + # self.num_of_elec = range(self.num_of_states)[::-1] + # self.overpotential = self.calc_overpotential()[0] + # self.limiting_step = self.calc_overpotential()[1] + # # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] + # self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() + # self.overpotential_h2o2 = self.calc_overpotential_h2o2() + #__| + + #__| + + def __create_series_name__(self, series_i): + """ + """ + #| - __create_series_name__ + + if series_i.properties is not None: + name_i = "" + for key, value in series_i.properties.items(): + + # TODO | This is an old feature, get rid of it + if key == "coverage": + continue + + name_i += str(key) + ": " + str(value) + " | " + + else: + name_i = "" + + return(name_i) + #__| + + def __create_smart_format_dict__(self, property_dict, smart_format_dict): + """Create smart format dictionary. + + Args: + property_dict: + smart_format_dict: + """ + #| - __create_smart_format_dict__ + if property_dict is None: + return({}) + + format_dict = {} + for key_i, value_i in property_dict.items(): + for format_i in smart_format_dict: + if list(format_i[0])[0] == key_i: + if list(format_i[0].values())[0] == value_i: + format_dict.update(format_i[1]) + + return(format_dict) + #__| + + def add_series(self, + fe_df, + plot_mode="all", + name_i=None, + group=None, + opt_name=None, + smart_format=True, + format_dict=None, + overpotential_type="ORR", + system_properties=None, + property_key_list=None, + add_overpot=True, + color=None, + overpotential_given=False, + ): + """Add ORR_Free_E_Series instance to ORR_Free_E_Plot.series_list. + + Note: It would be much better to simply take all of the + ORR_Free_E_Series arguments as a **kwargs term. + + Args: + TEMP + """ + #| - add_series + if smart_format: + smart_format_i = self.smart_format + else: + smart_format_i = None + + ORR_Series = ORR_Free_E_Series( + free_energy_df=fe_df, + properties=system_properties, + property_key_list=property_key_list, + state_title=self.state_title, + free_e_title=self.fe_title, + group=group, + bias=self.bias, + # rxn_x_coord_array=self.rxn_x_coord_array, + name_i=name_i, + opt_name=opt_name, # ####### + + color_list=self.color_list, + color=color, + hover_text_col=self.hover_text_col, + plot_mode=plot_mode, # ########## + smart_format=smart_format_i, + format_dict=format_dict, + add_overpot=add_overpot, + rxn_type=self.rxn_type, + overpotential_given=overpotential_given, + + # properties=opt_name, + # overpotential_type=self.rxn_type, + # i_cnt=0, # ########## + ) + + self.series_list.append(ORR_Series) + #__| + + #__| ********************************************************************** diff --git a/oxr_reaction/oxr_series.py b/oxr_reaction/oxr_series.py index 143faa0..991560f 100644 --- a/oxr_reaction/oxr_series.py +++ b/oxr_reaction/oxr_series.py @@ -1,643 +1,643 @@ -#!/usr/bin/env python - -"""ORR energetics classes and methods. - -Author: Raul A. Flores -""" - -#| - IMPORT MODULES -import copy - -import numpy as np -import pandas as pd - -from plotly.graph_objs import Scatter -pd.options.mode.chained_assignment = None -#__| - -class ORR_Free_E_Series(): - """ORR free energy diagram series class. - - Still a work in progress - Take a 2nd look at how the bulk/bare state is being taken care of - - # TODO Break series name with a '
' so that the legend entries have a - line break - # TODO Figure out which class attributes aren't being used anymore - # TODO Calculate *OOH from scaling, as an option (Colin does this) - - # TODO | The color_list approach is not good - """ - - #| - ORR_Free_E_Series **************************************************** - def __init__(self, - free_energy_df=None, - state_title="adsorbate", - free_e_title="ads_e", - bias=0., - group=None, - name_i=None, - opt_name=None, - properties=None, - property_key_list=None, - color_list=None, - color=None, - hover_text_col=None, - plot_mode="all", - smart_format=None, - format_dict=None, - add_overpot=True, - rxn_type="ORR", - fill_missing_data_w_scaling=True, - overpotential_given=False, - ): - """ - Input variables to class instance. - - TODO: Make sure that format_dict is used if it's supplied by user - - Args: - free_energy_df: - Pandas dataframe containing the adsorbates as rows - Required columns, adsorbate, free energy - state_title: - free_e_title: - bias: - opt_name: - Optional name - string to append to the beginning of the plot series name - properties: - color_list: - hover_text_col: - plot_mode: - smart_format: - format_dict: - overpotential_given: - If true then the overpotential is given explicitely in the - input dataframe with name "overpotential" - """ - #| - __init__ - - #| - Setting Instance Attributes - self.fe_df = free_energy_df - # self.sys_props = system_properties - - self.group = group - self.state_title = state_title - self.fe_title = free_e_title - - self.bias = bias - - # self.rxn_x_coord_array = rxn_x_coord_array - # print(self.rxn_x_coord_array) # TEMP | PRINT - - self.name_i = name_i - self.opt_name = opt_name - - self.properties = properties - - self.color_list = color_list - self.color = color - self.hover_text_col = hover_text_col - self.plot_mode = plot_mode - self.smart_format = smart_format - self.format_dict = format_dict - - # self.overpotential_type = overpotential_type - self.rxn_type = rxn_type - - self.add_overpot = add_overpot - self.overpotential_given = overpotential_given - - # self.i_cnt = i_cnt - #__| - - if self.rxn_type == "ORR": - self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] - self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - - elif self.rxn_type == "OER": - self.rxn_mech_states = ["bulk", "oh", "o", "ooh", "bulk"] - self.ideal_energy = [0, 1.23, 2.46, 3.69, 4.92] - - self.property_key_list = property_key_list - - # Doing this with a class method instead of in the analysis script - if properties is None: - self.properties = self.__create_property_dict__() - - if free_energy_df is not None: - self.add_bulk_entry() - self.fill_missing_data() - - # TEMP | Active Development - self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk - self.num_of_states_new = self.__num_of_states__() - - self.energy_lst = self.rxn_energy_lst() - # self.energy_lst_new = self.rxn_energy_lst_new() - - self.num_of_elec = range(self.num_of_states)[::-1] - self.overpotential = self.calc_overpotential()[0] - self.limiting_step = self.calc_overpotential()[1] - # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] - self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() - self.overpotential_h2o2 = self.calc_overpotential_h2o2() - self.overpotential_OER = self.calc_overpotential_OER()[0] - - self.energy_states_dict = self.__energy_states_dict__() - - if fill_missing_data_w_scaling: - self.__fill_nan_values__() - - # TODO | Put this outside of the if-statement - self.series_name = self.__series_plot_name__( - opt_name=self.opt_name, - properties=self.properties, - overpotential_type=self.rxn_type, - add_overpot=self.add_overpot, - ) - #__| - - def __fill_nan_values__(self): - """Fill nan adsorption energy values from scaling relations.""" - #| - tmp - energy_dict = self.energy_states_dict - if True in list(np.isnan(list(energy_dict.values()))): - - print("There is a nan in the energy dict!!!") - - if np.isnan(energy_dict["ooh"]): - if not np.isnan(energy_dict["oh"]): - print("*OOH energy set by *OH and standard scaling") - ooh_new = 1 * energy_dict["oh"] + 3.2 - energy_dict["ooh"] = ooh_new - - if np.isnan(energy_dict["o"]): - if not np.isnan(energy_dict["oh"]): - print("*O energy set by *OH and standard scaling") - o_new = 2 * energy_dict["oh"] + 0. - energy_dict["o"] = o_new - - if np.isnan(energy_dict["oh"]): - if not np.isnan(energy_dict["ooh"]): - print("*OH energy set by *OOH and standard scaling") - oh_new = energy_dict["ooh"] - 3.2 - energy_dict["oh"] = oh_new - - self.energy_states_dict = energy_dict - #__| - - def __num_of_states__(self): - """Return number of unique states. - - Looks at the uniqe number of entries in the 'adsorbate' column of the - data frame. The correct number of states for the OER and/or ORR - reaction are 4, only 2 states are needed for the peroxide reaction. - """ - #| - __num_of_states - df_i = self.fe_df - - num_of_states = len(set(df_i["adsorbate"].tolist())) - - err_mess = "There are not enough unique calcs (less than 4)" - assert num_of_states >= 4, err_mess - - return(num_of_states) - #__| - - def __energy_states_dict__(self): - """ - """ - #| - __energy_states_dict__ - - energy_lst = self.energy_lst - rxn_mech_states = self.rxn_mech_states - - energy_states_dict = dict(zip(rxn_mech_states, energy_lst)) - energy_states_dict.pop("bulk", None) - - return(energy_states_dict) - # energy_states_dict - #__| - - def __create_property_dict__(self): - """ - """ - #| - __create_property_dict__ - df_i = self.fe_df - - def all_same_val(df_i, prop_i, val_1): - """ - """ - #| - all_same_val - out_list = [] - for i in df_i[prop_i].tolist(): - if i == val_1: - out_list.append(True) - else: - out_list.append(False) - - out_i = all(out_list) - return(out_i) - - # [True if i == val_1 else False for i in - # df_i[prop_i].tolist()], - #__| - - if self.property_key_list is not None: - prop_dict_i = {} - for prop_i in self.property_key_list: - val_1 = df_i[prop_i].tolist()[0] - - all_same_value = all_same_val(df_i, prop_i, val_1) - # all_same_value = all( - # [True if i == val_1 else False for i in - # df_i[prop_i].tolist()], - # ) - - if all_same_value: - prop_dict_i[prop_i] = str(val_1) - else: - prop_dict_i[prop_i] = str(None) - - return(prop_dict_i) - else: - return({}) - #__| - - def add_bulk_entry(self, - bulk_e=0.0, - ): - """ - Append a row entry to data frame corresponding to bulk state. - - Args: - bulk_e: - """ - #| - add_bulk_entry - df = self.fe_df - bulk_df = pd.DataFrame([{ - "adsorbate": "bulk", - "ads_e": bulk_e, - }]) - - # TEMP - # df = df.append(bulk_df, ignore_index=True) - df = df.append(bulk_df, ignore_index=True, sort=True) - - self.fe_df = df - #__| - - def rxn_energy_lst_h2o2(self): - """Construct energy list of h2o2 FED.""" - #| - rxn_energy_lst_h2o2 - # h2o2_e = 3.52 - - df = self.fe_df - - free_energy_list = [] - for index, row in df.iterrows(): - if row["adsorbate"] == "bulk" or row["adsorbate"] == "ooh": - free_energy_list.append(row["ads_e"]) - - # TODO | Make this parse the reaction array instead of reaction list - # Checking length of energy list - if len(free_energy_list) != 2: - # raise ValueError("Not the correct # of steps for H2O2") - print("Not the correct # of steps for H2O2") - - free_energy_list[0] += 4.92 - free_energy_list.append(3.52) - - return(free_energy_list) - #__| - - def property_list(self, column_name): - """General method to create a list from a column in the dataframe. - - The length of the list will correspond to the steps in the ORR - mechanism. - - Args: - column_name: - """ - #| - property_list - df = self.fe_df - - property_list = [] - for state in self.rxn_mech_states: - tmp = df.loc[df[self.state_title] == state] - tmp1 = tmp.iloc[0][column_name] - property_list.append(tmp1) - - # free_energy_list[0] += 4.92 - - return(property_list) - #__| - - def fill_missing_data(self): - """ - """ - #| - fill_missing_data - df = self.fe_df - df_missing_data = pd.DataFrame() - for state in self.rxn_mech_states: - df_state = df.loc[df[self.state_title] == state] - - #| - If df is missing state fill in row with NaN for energy - if df_state.empty: - df_state = pd.DataFrame([{ - self.state_title: state, - self.fe_title: np.nan, - }]) - df_missing_data = df_missing_data.append(df_state) - #__| - - self.fe_df = self.fe_df.append(df_missing_data, sort=True) - #__| - - def rxn_energy_lst(self): - """List corresponding to the steps of ORR. - - (1. O2, 2. *OOH, 3. *O, 4. *OH, 5. 2H2O) - """ - #| - rxn_energy_lst - df = self.fe_df - - free_energy_list = [] - for state in self.rxn_mech_states: - df_state = df.loc[df[self.state_title] == state] - - # print(df_state) - - #| - __old__ - # Not sure what this was trying to accomplish - # if len(df_state) == 2: - # state_energy_list = [] - # for j_cnt, row_j in df_state.iterrows(): - # energy_j = row_j[self.fe_title] - # state_energy_list.append(energy_j) - #__| - - #| - If df is missing state fill in row with NaN for energy - if df_state.empty: - df_state = pd.DataFrame([{ - self.state_title: state, - self.fe_title: np.nan, - }]) - #__| - - # This just takes the first species - # If you feed a df with more than one entry per species, then - # this will stupidly choose the first one - state_energy_1 = df_state.iloc[0][self.fe_title] - - #| - __old__ - # if type(state_energy_1) != float: - # print(type(state_energy_1)) - # print("DSKFJKLSDJFSjk_d--_d-d-_D_D_d-d-d-d-d___D_D_D_") - # print( - # "state_energy_1: ", - # str(state_energy_1), - # ) - # - # print( - # "type: ", - # str(type(state_energy_1)) - # ) - # - # print(isinstance(state_energy_1, np.float)) - # print(float(state_energy_1)) - # print(type(float(state_energy_1))) - # print(np.isnan(state_energy_1)) - # if isinstance(state_energy_1, np.float) is False: - # print("lkjfksjd") - #__| - - free_energy_list.append(state_energy_1) - - if self.rxn_type == "ORR": - free_energy_list[0] += 4.92 - elif self.rxn_type == "OER": - free_energy_list[-1] += 4.92 - else: - free_energy_list[0] += 4.92 - - return(free_energy_list) - #__| - - def rxn_energy_lst_new(self): - """ - """ - #| - rxn_energy_lst_new - df = self.fe_df - free_energy_list = [] - for state in self.rxn_mech_states: - df_state = df.loc[df[self.state_title] == state] - - #| - If df is missing state fill in row with NaN for energy - if df_state.empty: - df_state = pd.DataFrame([{ - self.state_title: state, - self.fe_title: np.nan, - }]) - #__| - - state_energy_list = [] - for j_cnt, row_j in df_state.iterrows(): - energy_j = row_j[self.fe_title] - state_energy_list.append(energy_j) - - free_energy_list.append(state_energy_list) - - # tmp1 = df_state.iloc[0][self.fe_title] - # free_energy_list.append(tmp1) - - if self.rxn_type == "ORR": - free_energy_list_0_new = [i + 4.92 for i in free_energy_list[0]] - free_energy_list[0] = free_energy_list_0_new - - # free_energy_list[0] += 4.92 - - elif self.rxn_type == "OER": - # free_energy_list[-1] += 4.92 - free_energy_list_new = [i + 4.92 for i in free_energy_list[-1]] - free_energy_list[-1] = free_energy_list_new - - else: - free_energy_list[0] += 4.92 - - return(free_energy_list) - #__| - - def apply_bias(self, bias, energy_list): - """Apply bias to free energies. - - Applies a potential to every species in the 4 and 2-electron process - and adjusts their free energies accordingly - """ - #| - apply_bias - if self.rxn_type == "ORR": - flip_energy_list = False - bool_flip = -1 - elif self.rxn_type == "OER": - flip_energy_list = True - bool_flip = +1 - - e_lst = energy_list - - mod_free_e_lst = [] # Free energy reaction path at applied bias - for en, elec in zip(e_lst, range(len(e_lst))[::bool_flip]): - mod_free_e_lst.append(en - elec * bias) - - return(mod_free_e_lst) - #__| - - def calc_overpotential(self): - """ - Calculate overpotential for 4e- process. - - Returns the limiting overpotential for the given species and the - limiting reaction step in the form of a list, species_A -> species_B is - [species_A, species_B] - """ - #| - calc_overpotential - if self.overpotential_given: - out_list = [None, None] - if "overpotential" in list(self.fe_df): - overpot_i = self.fe_df["overpotential"].tolist()[0] - out_list[0] = overpot_i - else: - print("No 'overpotential' column in df") - - else: - rxn_spec = self.rxn_mech_states - - overpotential_lst = [] - for energy_i in enumerate(self.energy_lst[:-1]): - energy_i_plus1 = self.energy_lst[energy_i[0] + 1] - overpotential_i = 1.23 + energy_i_plus1 - energy_i[1] - overpotential_lst.append(overpotential_i) - - overpotential = max(overpotential_lst) - # overpotential = min(overpotential_lst) - - lim_step_index = overpotential_lst.index(overpotential) - - limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] - out_list = [overpotential, limiting_step] - - return(out_list) - #__| - - def calc_overpotential_OER(self): - """Calculate the OER overpotential of a ORR series.""" - #| - calc_overpotential_OER - rxn_spec = self.rxn_mech_states - - overpotential_lst = [] - for energy_i in enumerate(self.energy_lst[:-1]): - energy_i_plus1 = self.energy_lst[energy_i[0] + 1] - overpotential_i = energy_i_plus1 - energy_i[1] - 1.23 - overpotential_lst.append(overpotential_i) - - overpotential = max(overpotential_lst) - lim_step_index = overpotential_lst.index(overpotential) - - limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] - out_list = [overpotential, limiting_step] - - return(out_list) - #__| - - def calc_overpotential_h2o2(self): - """ - Calculate overpotential for 2e- process. - - The overpotential for the 2e- process depends only on the energy of the - *OOH intermediate - """ - #| - calc_overpotential_h2o2 - df = self.fe_df - ooh_row = df[df["adsorbate"] == "ooh"] - ooh_ads_e = ooh_row.iloc[0]["ads_e"] - - op_4e = ooh_ads_e - 4.22 - - return(op_4e) - #__| - - def __series_plot_name__(self, - opt_name=None, - properties=None, - overpotential_type="ORR", - add_overpot=True, - use_key_in_name=False, - ): - """Create name for series. - - Args: - bias: - opt_name: - properties: - color_list: - hover_text_col: - plot_mode: - smart_format: - overpotential_type: - """ - #| - __series_plot_name__ - - #| - Getting appropriate Overpotential - if add_overpot: - if overpotential_type == "ORR": - overpot_i = self.overpotential - elif overpotential_type == "OER": - overpot_i = self.overpotential_OER - elif overpotential_type == "H2O2": - overpot_i = self.overpotential_h2o2 - else: - overpot_i = self.overpotential - else: - overpot_i = "" - #__| - - #| - Connecting properties key: values into string - if properties is not None: - properties_string_name = "" - for key_i, value_i in properties.items(): - - if use_key_in_name is True: - properties_string_name += str(key_i) - properties_string_name += "_" - properties_string_name += str(value_i) - - properties_string_name += " | " - - # Removing the trailig ' | ' - properties_string_name = properties_string_name[0:-3] - else: - properties_string_name = "" - #__| - - #| - Data Series Name - if opt_name is not None: - name_i = opt_name + ": " + properties_string_name - - else: - name_i = properties_string_name - - if add_overpot: - name_i += " (OP: " + str(round(overpot_i, 2)) + ")" - - #__| - - # NEW | If name_i given, then just use that - if self.name_i is not None: - return(self.name_i) - - return(name_i) - #__| - - #__| +#!/usr/bin/env python + +"""ORR energetics classes and methods. + +Author: Raul A. Flores +""" + +#| - IMPORT MODULES +import copy + +import numpy as np +import pandas as pd + +from plotly.graph_objs import Scatter +pd.options.mode.chained_assignment = None +#__| + +class ORR_Free_E_Series(): + """ORR free energy diagram series class. + + Still a work in progress + Take a 2nd look at how the bulk/bare state is being taken care of + + # TODO Break series name with a '
' so that the legend entries have a + line break + # TODO Figure out which class attributes aren't being used anymore + # TODO Calculate *OOH from scaling, as an option (Colin does this) + + # TODO | The color_list approach is not good + """ + + #| - ORR_Free_E_Series **************************************************** + def __init__(self, + free_energy_df=None, + state_title="adsorbate", + free_e_title="ads_e", + bias=0., + group=None, + name_i=None, + opt_name=None, + properties=None, + property_key_list=None, + color_list=None, + color=None, + hover_text_col=None, + plot_mode="all", + smart_format=None, + format_dict=None, + add_overpot=True, + rxn_type="ORR", + fill_missing_data_w_scaling=True, + overpotential_given=False, + ): + """ + Input variables to class instance. + + TODO: Make sure that format_dict is used if it's supplied by user + + Args: + free_energy_df: + Pandas dataframe containing the adsorbates as rows + Required columns, adsorbate, free energy + state_title: + free_e_title: + bias: + opt_name: + Optional name + string to append to the beginning of the plot series name + properties: + color_list: + hover_text_col: + plot_mode: + smart_format: + format_dict: + overpotential_given: + If true then the overpotential is given explicitely in the + input dataframe with name "overpotential" + """ + #| - __init__ + + #| - Setting Instance Attributes + self.fe_df = free_energy_df + # self.sys_props = system_properties + + self.group = group + self.state_title = state_title + self.fe_title = free_e_title + + self.bias = bias + + # self.rxn_x_coord_array = rxn_x_coord_array + # print(self.rxn_x_coord_array) # TEMP | PRINT + + self.name_i = name_i + self.opt_name = opt_name + + self.properties = properties + + self.color_list = color_list + self.color = color + self.hover_text_col = hover_text_col + self.plot_mode = plot_mode + self.smart_format = smart_format + self.format_dict = format_dict + + # self.overpotential_type = overpotential_type + self.rxn_type = rxn_type + + self.add_overpot = add_overpot + self.overpotential_given = overpotential_given + + # self.i_cnt = i_cnt + #__| + + if self.rxn_type == "ORR": + self.rxn_mech_states = ["bulk", "ooh", "o", "oh", "bulk"] + self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] + + elif self.rxn_type == "OER": + self.rxn_mech_states = ["bulk", "oh", "o", "ooh", "bulk"] + self.ideal_energy = [0, 1.23, 2.46, 3.69, 4.92] + + self.property_key_list = property_key_list + + # Doing this with a class method instead of in the analysis script + if properties is None: + self.properties = self.__create_property_dict__() + + if free_energy_df is not None: + self.add_bulk_entry() + self.fill_missing_data() + + # TEMP | Active Development + self.num_of_states = len(self.fe_df) + 1 # bulk, OOH, O, OH, bulk + self.num_of_states_new = self.__num_of_states__() + + self.energy_lst = self.rxn_energy_lst() + # self.energy_lst_new = self.rxn_energy_lst_new() + + self.num_of_elec = range(self.num_of_states)[::-1] + self.overpotential = self.calc_overpotential()[0] + self.limiting_step = self.calc_overpotential()[1] + # self.ideal_energy = [4.92, 3.69, 2.46, 1.23, 0] + self.energy_lst_h2o2 = self.rxn_energy_lst_h2o2() + self.overpotential_h2o2 = self.calc_overpotential_h2o2() + self.overpotential_OER = self.calc_overpotential_OER()[0] + + self.energy_states_dict = self.__energy_states_dict__() + + if fill_missing_data_w_scaling: + self.__fill_nan_values__() + + # TODO | Put this outside of the if-statement + self.series_name = self.__series_plot_name__( + opt_name=self.opt_name, + properties=self.properties, + overpotential_type=self.rxn_type, + add_overpot=self.add_overpot, + ) + #__| + + def __fill_nan_values__(self): + """Fill nan adsorption energy values from scaling relations.""" + #| - tmp + energy_dict = self.energy_states_dict + if True in list(np.isnan(list(energy_dict.values()))): + + print("There is a nan in the energy dict!!!") + + if np.isnan(energy_dict["ooh"]): + if not np.isnan(energy_dict["oh"]): + print("*OOH energy set by *OH and standard scaling") + ooh_new = 1 * energy_dict["oh"] + 3.2 + energy_dict["ooh"] = ooh_new + + if np.isnan(energy_dict["o"]): + if not np.isnan(energy_dict["oh"]): + print("*O energy set by *OH and standard scaling") + o_new = 2 * energy_dict["oh"] + 0. + energy_dict["o"] = o_new + + if np.isnan(energy_dict["oh"]): + if not np.isnan(energy_dict["ooh"]): + print("*OH energy set by *OOH and standard scaling") + oh_new = energy_dict["ooh"] - 3.2 + energy_dict["oh"] = oh_new + + self.energy_states_dict = energy_dict + #__| + + def __num_of_states__(self): + """Return number of unique states. + + Looks at the uniqe number of entries in the 'adsorbate' column of the + data frame. The correct number of states for the OER and/or ORR + reaction are 4, only 2 states are needed for the peroxide reaction. + """ + #| - __num_of_states + df_i = self.fe_df + + num_of_states = len(set(df_i["adsorbate"].tolist())) + + err_mess = "There are not enough unique calcs (less than 4)" + assert num_of_states >= 4, err_mess + + return(num_of_states) + #__| + + def __energy_states_dict__(self): + """ + """ + #| - __energy_states_dict__ + + energy_lst = self.energy_lst + rxn_mech_states = self.rxn_mech_states + + energy_states_dict = dict(zip(rxn_mech_states, energy_lst)) + energy_states_dict.pop("bulk", None) + + return(energy_states_dict) + # energy_states_dict + #__| + + def __create_property_dict__(self): + """ + """ + #| - __create_property_dict__ + df_i = self.fe_df + + def all_same_val(df_i, prop_i, val_1): + """ + """ + #| - all_same_val + out_list = [] + for i in df_i[prop_i].tolist(): + if i == val_1: + out_list.append(True) + else: + out_list.append(False) + + out_i = all(out_list) + return(out_i) + + # [True if i == val_1 else False for i in + # df_i[prop_i].tolist()], + #__| + + if self.property_key_list is not None: + prop_dict_i = {} + for prop_i in self.property_key_list: + val_1 = df_i[prop_i].tolist()[0] + + all_same_value = all_same_val(df_i, prop_i, val_1) + # all_same_value = all( + # [True if i == val_1 else False for i in + # df_i[prop_i].tolist()], + # ) + + if all_same_value: + prop_dict_i[prop_i] = str(val_1) + else: + prop_dict_i[prop_i] = str(None) + + return(prop_dict_i) + else: + return({}) + #__| + + def add_bulk_entry(self, + bulk_e=0.0, + ): + """ + Append a row entry to data frame corresponding to bulk state. + + Args: + bulk_e: + """ + #| - add_bulk_entry + df = self.fe_df + bulk_df = pd.DataFrame([{ + "adsorbate": "bulk", + "ads_e": bulk_e, + }]) + + # TEMP + # df = df.append(bulk_df, ignore_index=True) + df = df.append(bulk_df, ignore_index=True, sort=True) + + self.fe_df = df + #__| + + def rxn_energy_lst_h2o2(self): + """Construct energy list of h2o2 FED.""" + #| - rxn_energy_lst_h2o2 + # h2o2_e = 3.52 + + df = self.fe_df + + free_energy_list = [] + for index, row in df.iterrows(): + if row["adsorbate"] == "bulk" or row["adsorbate"] == "ooh": + free_energy_list.append(row["ads_e"]) + + # TODO | Make this parse the reaction array instead of reaction list + # Checking length of energy list + if len(free_energy_list) != 2: + # raise ValueError("Not the correct # of steps for H2O2") + print("Not the correct # of steps for H2O2") + + free_energy_list[0] += 4.92 + free_energy_list.append(3.52) + + return(free_energy_list) + #__| + + def property_list(self, column_name): + """General method to create a list from a column in the dataframe. + + The length of the list will correspond to the steps in the ORR + mechanism. + + Args: + column_name: + """ + #| - property_list + df = self.fe_df + + property_list = [] + for state in self.rxn_mech_states: + tmp = df.loc[df[self.state_title] == state] + tmp1 = tmp.iloc[0][column_name] + property_list.append(tmp1) + + # free_energy_list[0] += 4.92 + + return(property_list) + #__| + + def fill_missing_data(self): + """ + """ + #| - fill_missing_data + df = self.fe_df + df_missing_data = pd.DataFrame() + for state in self.rxn_mech_states: + df_state = df.loc[df[self.state_title] == state] + + #| - If df is missing state fill in row with NaN for energy + if df_state.empty: + df_state = pd.DataFrame([{ + self.state_title: state, + self.fe_title: np.nan, + }]) + df_missing_data = df_missing_data.append(df_state) + #__| + + self.fe_df = self.fe_df.append(df_missing_data, sort=True) + #__| + + def rxn_energy_lst(self): + """List corresponding to the steps of ORR. + + (1. O2, 2. *OOH, 3. *O, 4. *OH, 5. 2H2O) + """ + #| - rxn_energy_lst + df = self.fe_df + + free_energy_list = [] + for state in self.rxn_mech_states: + df_state = df.loc[df[self.state_title] == state] + + # print(df_state) + + #| - __old__ + # Not sure what this was trying to accomplish + # if len(df_state) == 2: + # state_energy_list = [] + # for j_cnt, row_j in df_state.iterrows(): + # energy_j = row_j[self.fe_title] + # state_energy_list.append(energy_j) + #__| + + #| - If df is missing state fill in row with NaN for energy + if df_state.empty: + df_state = pd.DataFrame([{ + self.state_title: state, + self.fe_title: np.nan, + }]) + #__| + + # This just takes the first species + # If you feed a df with more than one entry per species, then + # this will stupidly choose the first one + state_energy_1 = df_state.iloc[0][self.fe_title] + + #| - __old__ + # if type(state_energy_1) != float: + # print(type(state_energy_1)) + # print("DSKFJKLSDJFSjk_d--_d-d-_D_D_d-d-d-d-d___D_D_D_") + # print( + # "state_energy_1: ", + # str(state_energy_1), + # ) + # + # print( + # "type: ", + # str(type(state_energy_1)) + # ) + # + # print(isinstance(state_energy_1, np.float)) + # print(float(state_energy_1)) + # print(type(float(state_energy_1))) + # print(np.isnan(state_energy_1)) + # if isinstance(state_energy_1, np.float) is False: + # print("lkjfksjd") + #__| + + free_energy_list.append(state_energy_1) + + if self.rxn_type == "ORR": + free_energy_list[0] += 4.92 + elif self.rxn_type == "OER": + free_energy_list[-1] += 4.92 + else: + free_energy_list[0] += 4.92 + + return(free_energy_list) + #__| + + def rxn_energy_lst_new(self): + """ + """ + #| - rxn_energy_lst_new + df = self.fe_df + free_energy_list = [] + for state in self.rxn_mech_states: + df_state = df.loc[df[self.state_title] == state] + + #| - If df is missing state fill in row with NaN for energy + if df_state.empty: + df_state = pd.DataFrame([{ + self.state_title: state, + self.fe_title: np.nan, + }]) + #__| + + state_energy_list = [] + for j_cnt, row_j in df_state.iterrows(): + energy_j = row_j[self.fe_title] + state_energy_list.append(energy_j) + + free_energy_list.append(state_energy_list) + + # tmp1 = df_state.iloc[0][self.fe_title] + # free_energy_list.append(tmp1) + + if self.rxn_type == "ORR": + free_energy_list_0_new = [i + 4.92 for i in free_energy_list[0]] + free_energy_list[0] = free_energy_list_0_new + + # free_energy_list[0] += 4.92 + + elif self.rxn_type == "OER": + # free_energy_list[-1] += 4.92 + free_energy_list_new = [i + 4.92 for i in free_energy_list[-1]] + free_energy_list[-1] = free_energy_list_new + + else: + free_energy_list[0] += 4.92 + + return(free_energy_list) + #__| + + def apply_bias(self, bias, energy_list): + """Apply bias to free energies. + + Applies a potential to every species in the 4 and 2-electron process + and adjusts their free energies accordingly + """ + #| - apply_bias + if self.rxn_type == "ORR": + flip_energy_list = False + bool_flip = -1 + elif self.rxn_type == "OER": + flip_energy_list = True + bool_flip = +1 + + e_lst = energy_list + + mod_free_e_lst = [] # Free energy reaction path at applied bias + for en, elec in zip(e_lst, range(len(e_lst))[::bool_flip]): + mod_free_e_lst.append(en - elec * bias) + + return(mod_free_e_lst) + #__| + + def calc_overpotential(self): + """ + Calculate overpotential for 4e- process. + + Returns the limiting overpotential for the given species and the + limiting reaction step in the form of a list, species_A -> species_B is + [species_A, species_B] + """ + #| - calc_overpotential + if self.overpotential_given: + out_list = [None, None] + if "overpotential" in list(self.fe_df): + overpot_i = self.fe_df["overpotential"].tolist()[0] + out_list[0] = overpot_i + else: + print("No 'overpotential' column in df") + + else: + rxn_spec = self.rxn_mech_states + + overpotential_lst = [] + for energy_i in enumerate(self.energy_lst[:-1]): + energy_i_plus1 = self.energy_lst[energy_i[0] + 1] + overpotential_i = 1.23 + energy_i_plus1 - energy_i[1] + overpotential_lst.append(overpotential_i) + + overpotential = max(overpotential_lst) + # overpotential = min(overpotential_lst) + + lim_step_index = overpotential_lst.index(overpotential) + + limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] + out_list = [overpotential, limiting_step] + + return(out_list) + #__| + + def calc_overpotential_OER(self): + """Calculate the OER overpotential of a ORR series.""" + #| - calc_overpotential_OER + rxn_spec = self.rxn_mech_states + + overpotential_lst = [] + for energy_i in enumerate(self.energy_lst[:-1]): + energy_i_plus1 = self.energy_lst[energy_i[0] + 1] + overpotential_i = energy_i_plus1 - energy_i[1] - 1.23 + overpotential_lst.append(overpotential_i) + + overpotential = max(overpotential_lst) + lim_step_index = overpotential_lst.index(overpotential) + + limiting_step = [rxn_spec[lim_step_index], rxn_spec[lim_step_index + 1]] + out_list = [overpotential, limiting_step] + + return(out_list) + #__| + + def calc_overpotential_h2o2(self): + """ + Calculate overpotential for 2e- process. + + The overpotential for the 2e- process depends only on the energy of the + *OOH intermediate + """ + #| - calc_overpotential_h2o2 + df = self.fe_df + ooh_row = df[df["adsorbate"] == "ooh"] + ooh_ads_e = ooh_row.iloc[0]["ads_e"] + + op_4e = ooh_ads_e - 4.22 + + return(op_4e) + #__| + + def __series_plot_name__(self, + opt_name=None, + properties=None, + overpotential_type="ORR", + add_overpot=True, + use_key_in_name=False, + ): + """Create name for series. + + Args: + bias: + opt_name: + properties: + color_list: + hover_text_col: + plot_mode: + smart_format: + overpotential_type: + """ + #| - __series_plot_name__ + + #| - Getting appropriate Overpotential + if add_overpot: + if overpotential_type == "ORR": + overpot_i = self.overpotential + elif overpotential_type == "OER": + overpot_i = self.overpotential_OER + elif overpotential_type == "H2O2": + overpot_i = self.overpotential_h2o2 + else: + overpot_i = self.overpotential + else: + overpot_i = "" + #__| + + #| - Connecting properties key: values into string + if properties is not None: + properties_string_name = "" + for key_i, value_i in properties.items(): + + if use_key_in_name is True: + properties_string_name += str(key_i) + properties_string_name += "_" + properties_string_name += str(value_i) + + properties_string_name += " | " + + # Removing the trailig ' | ' + properties_string_name = properties_string_name[0:-3] + else: + properties_string_name = "" + #__| + + #| - Data Series Name + if opt_name is not None: + name_i = opt_name + ": " + properties_string_name + + else: + name_i = properties_string_name + + if add_overpot: + name_i += " (OP: " + str(round(overpot_i, 2)) + ")" + + #__| + + # NEW | If name_i given, then just use that + if self.name_i is not None: + return(self.name_i) + + return(name_i) + #__| + + #__| diff --git a/periodic_table.json b/periodic_table.json index 164a615..3fc7e63 100644 --- a/periodic_table.json +++ b/periodic_table.json @@ -1,9636 +1,9636 @@ -{ - "Ac": { - "Atomic mass": 227.0, - "Atomic no": 89, - "Atomic orbitals": { - "1s": -3443.110367, - "2p": -572.7627, - "2s": -592.622878, - "3d": -119.541743, - "3p": -137.654394, - "3s": -147.320716, - "4d": -23.57061, - "4f": -12.278225, - "4p": -31.761846, - "4s": -36.15826, - "5d": -3.222752, - "5p": -6.06511, - "5s": -7.713078, - "6d": -0.137786, - "6p": -0.744524, - "6s": -1.19698, - "7s": -0.126551 - }, - "Atomic radius": 1.95, - "Atomic radius calculated": "no data", - "Boiling point": "3573 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "10070 kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].6d1.7s2", - "Ionic radii": { - "3": 1.26 - }, - "Liquid range": "2250 K", - "Melting point": "1323 K", - "Mendeleev no": 48, - "Mineral hardness": "no data", - "Molar volume": "22.55 cm3", - "Name": "Actinium", - "Oxidation states": [ - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.26, - "ionic_radius": 1.12 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "12 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.1, - "Youngs modulus": "no data GPa" - }, - "Ag": { - "Atomic mass": 107.8682, - "Atomic no": 47, - "Atomic orbitals": { - "1s": -900.324578, - "2p": -120.913351, - "2s": -129.859807, - "3d": -13.367803, - "3p": -20.06763, - "3s": -23.678437, - "4d": -0.298706, - "4p": -2.086602, - "4s": -3.22309, - "5s": -0.157407 - }, - "Atomic radius": 1.6, - "Atomic radius calculated": 1.65, - "Boiling point": "2435 K", - "Brinell hardness": "24.5 MN m-2", - "Bulk modulus": "100 GPa", - "Coefficient of linear thermal expansion": "18.9 x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "no data K", - "Density of solid": "10490 kg m-3", - "Electrical resistivity": "1.63 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s1", - "ICSD oxidation states": [ - 1, - 2, - 3 - ], - "Ionic radii": { - "1": 1.29, - "2": 1.08, - "3": 0.89 - }, - "Liquid range": "1200.07 K", - "Melting point": "1234.93 K", - "Mendeleev no": 71, - "Mineral hardness": "2.5", - "Molar volume": "10.27 cm3", - "Name": "Silver", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "0.37", - "Reflectivity": "97 %", - "Refractive index": "no data", - "Rigidity modulus": "30 GPa", - "Shannon radii": { - "1": { - "II": { - "": { - "crystal_radius": 0.81, - "ionic_radius": 0.67 - } - }, - "IV": { - "": { - "crystal_radius": 1.14, - "ionic_radius": 1.0 - } - }, - "IVSQ": { - "": { - "crystal_radius": 1.16, - "ionic_radius": 1.02 - } - }, - "V": { - "": { - "crystal_radius": 1.23, - "ionic_radius": 1.09 - } - }, - "VI": { - "": { - "crystal_radius": 1.29, - "ionic_radius": 1.15 - } - }, - "VII": { - "": { - "crystal_radius": 1.36, - "ionic_radius": 1.22 - } - }, - "VIII": { - "": { - "crystal_radius": 1.42, - "ionic_radius": 1.28 - } - } - }, - "2": { - "IVSQ": { - "": { - "crystal_radius": 0.93, - "ionic_radius": 0.79 - } - }, - "VI": { - "": { - "crystal_radius": 1.08, - "ionic_radius": 0.94 - } - } - }, - "3": { - "IVSQ": { - "": { - "crystal_radius": 0.81, - "ionic_radius": 0.67 - } - }, - "VI": { - "": { - "crystal_radius": 0.89, - "ionic_radius": 0.75 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "430 W m-1 K-1", - "Van der waals radius": 1.72, - "Velocity of sound": "2600 m s-1", - "Vickers hardness": "251 MN m-2", - "X": 1.93, - "Youngs modulus": "83 GPa" - }, - "Al": { - "Atomic mass": 26.9815386, - "Atomic no": 13, - "Atomic orbitals": { - "1s": -55.156044, - "2p": -2.564018, - "2s": -3.934827, - "3p": -0.102545, - "3s": -0.286883 - }, - "Atomic radius": 1.25, - "Atomic radius calculated": 1.18, - "Boiling point": "2792 K", - "Brinell hardness": "245 MN m-2", - "Bulk modulus": "76 GPa", - "Coefficient of linear thermal expansion": "23.1 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "2700 kg m-3", - "Electrical resistivity": "2.7 10-8 Ω m", - "Electronic structure": "[Ne].3s2.3p1", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "3": 0.675 - }, - "Liquid range": "1858.53 K", - "Melting point": "933.47 K", - "Mendeleev no": 80, - "Mineral hardness": "2.75", - "Molar volume": "10.00 cm3", - "Name": "Aluminum", - "Oxidation states": [ - 1, - 3 - ], - "Poissons ratio": "0.35", - "Reflectivity": "71 %", - "Refractive index": "no data", - "Rigidity modulus": "26 GPa", - "Shannon radii": { - "3": { - "IV": { - "": { - "crystal_radius": 0.53, - "ionic_radius": 0.39 - } - }, - "V": { - "": { - "crystal_radius": 0.62, - "ionic_radius": 0.48 - } - }, - "VI": { - "": { - "crystal_radius": 0.675, - "ionic_radius": 0.535 - } - } - } - }, - "Superconduction temperature": "1.175 K", - "Thermal conductivity": "235 W m-1 K-1", - "Van der waals radius": 1.84, - "Velocity of sound": "5100 m s-1", - "Vickers hardness": "167 MN m-2", - "X": 1.61, - "Youngs modulus": "70 GPa", - "NMR Quadrupole Moment": { - "Al-27": 146.6 - } - }, - "Am": { - "Atomic mass": 243.0, - "Atomic no": 95, - "Atomic orbitals": "no data", - "Atomic radius": 1.75, - "Atomic radius calculated": "no data", - "Boiling point": "2880 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f7.7s2", - "Ionic radii": { - "2": 1.4, - "3": 1.115, - "4": 0.99 - }, - "Liquid range": "1431 K", - "Melting point": "1449 K", - "Mendeleev no": 42, - "Mineral hardness": "no data", - "Molar volume": "17.63 cm3", - "Name": "Americium", - "Oxidation states": [ - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "2": { - "VII": { - "": { - "crystal_radius": 1.35, - "ionic_radius": 1.21 - } - }, - "VIII": { - "": { - "crystal_radius": 1.4, - "ionic_radius": 1.26 - } - }, - "IX": { - "": { - "crystal_radius": 1.45, - "ionic_radius": 1.31 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.115, - "ionic_radius": 0.975 - } - }, - "VIII": { - "": { - "crystal_radius": 1.23, - "ionic_radius": 1.09 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.99, - "ionic_radius": 0.85 - } - }, - "VIII": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - } - } - }, - "Superconduction temperature": "0.6 K", - "Thermal conductivity": "10 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Ar": { - "Atomic mass": 39.948, - "Atomic no": 18, - "Atomic orbitals": { - "1s": -113.800134, - "2p": -8.443439, - "2s": -10.794172, - "3p": -0.38233, - "3s": -0.883384 - }, - "Atomic radius": 0.71, - "Atomic radius calculated": 0.71, - "Boiling point": "87.3 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Critical temperature": "150.8 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Ne].3s2.3p6", - "Liquid range": "3.5 K", - "Max oxidation state": 0.0, - "Melting point": "83.8 K", - "Mendeleev no": 3, - "Min oxidation state": 0.0, - "Mineral hardness": "no data", - "Molar volume": "22.56 cm3", - "Name": "Argon", - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000281", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.01772 W m-1 K-1", - "Van der waals radius": 1.88, - "Velocity of sound": "319 m s-1", - "Vickers hardness": "no data MN m-2", - "Youngs modulus": "no data GPa" - }, - "As": { - "Atomic mass": 74.9216, - "Atomic no": 33, - "Atomic orbitals": { - "1s": -423.336658, - "2p": -47.527869, - "2s": -53.093086, - "3d": -1.542767, - "3p": -4.851725, - "3s": -6.730755, - "4p": -0.197497, - "4s": -0.52367 - }, - "Atomic radius": 1.15, - "Atomic radius calculated": 1.14, - "Boiling point": "887 K", - "Brinell hardness": "1440 MN m-2", - "Bulk modulus": "22 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -3, - 3, - 5 - ], - "Critical temperature": "1700 K", - "Density of solid": "5727 kg m-3", - "Electrical resistivity": "33 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2.4p3", - "ICSD oxidation states": [ - 2, - 3, - 5, - -2, - -3, - -1 - ], - "Ionic radii": { - "3": 0.72, - "5": 0.6 - }, - "Liquid range": "203 K", - "Melting point": "1090 K", - "Mendeleev no": 89, - "Mineral hardness": "3.5", - "Molar volume": "12.95 cm3", - "Name": "Arsenic", - "Oxidation states": [ - -3, - 2, - 3, - 5 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.001552", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.475, - "ionic_radius": 0.335 - } - }, - "VI": { - "": { - "crystal_radius": 0.6, - "ionic_radius": 0.46 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "50 W m-1 K-1", - "Van der waals radius": 1.85, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.18, - "Youngs modulus": "8 GPa" - }, - "At": { - "Atomic mass": 210.0, - "Atomic no": 85, - "Atomic orbitals": { - "1s": -3127.390276, - "2p": -513.044243, - "2s": -531.81835, - "3d": -103.060375, - "3p": -119.995013, - "3s": -129.035542, - "4d": -18.295162, - "4f": -8.063483, - "4p": -25.778264, - "4s": -29.809515, - "5d": -1.643758, - "5p": -4.027061, - "5s": -5.453383, - "6p": -0.255453, - "6s": -0.560189 - }, - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -1, - 1 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2.6p5", - "Ionic radii": { - "7": 0.76 - }, - "Liquid range": "no data K", - "Melting point": "575 K", - "Mendeleev no": 96, - "Mineral hardness": "no data", - "Molar volume": "no data cm3", - "Name": "Astatine", - "Oxidation states": [ - -1, - 1, - 3, - 5 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "7": { - "VI": { - "": { - "crystal_radius": 0.76, - "ionic_radius": 0.62 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "2 (estimate)W m-1 K-1", - "Van der waals radius": 2.02, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.2, - "Youngs modulus": "no data GPa" - }, - "Au": { - "Atomic mass": 196.966569, - "Atomic no": 79, - "Atomic orbitals": { - "1s": -2683.508245, - "2p": -430.725701, - "2s": -447.888973, - "3d": -81.511751, - "3p": -96.707, - "3s": -104.824516, - "4d": -12.131815, - "4f": -3.486824, - "4p": -18.578652, - "4s": -22.078357, - "5d": -0.304738, - "5p": -2.002495, - "5s": -3.113936, - "6s": -0.162334 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.74, - "Boiling point": "3129 K", - "Brinell hardness": "2450 MN m-2", - "Bulk modulus": "220 GPa", - "Coefficient of linear thermal expansion": "14.2 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "19300 kg m-3", - "Electrical resistivity": "2.2 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s1", - "Ionic radii": { - "1": 1.51, - "3": 0.99, - "5": 0.71 - }, - "Liquid range": "1791.67 K", - "Melting point": "1337.33 K", - "Mendeleev no": 70, - "Mineral hardness": "2.5", - "Molar volume": "10.21 cm3", - "Name": "Gold", - "Oxidation states": [ - -1, - 1, - 2, - 3, - 5 - ], - "Poissons ratio": "0.44", - "Reflectivity": "95 %", - "Refractive index": "no data", - "Rigidity modulus": "27 GPa", - "Shannon radii": { - "1": { - "VI": { - "": { - "crystal_radius": 1.51, - "ionic_radius": 1.37 - } - } - }, - "3": { - "IVSQ": { - "": { - "crystal_radius": 0.82, - "ionic_radius": 0.68 - } - }, - "VI": { - "": { - "crystal_radius": 0.99, - "ionic_radius": 0.85 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "320 W m-1 K-1", - "Van der waals radius": 1.66, - "Velocity of sound": "1740 m s-1", - "Vickers hardness": "216 MN m-2", - "X": 2.54, - "Youngs modulus": "78 GPa" - }, - "B": { - "Atomic mass": 10.811, - "Atomic no": 5, - "Atomic orbitals": { - "1s": -6.564347, - "2p": -0.136603, - "2s": -0.344701 - }, - "Atomic radius": 0.85, - "Atomic radius calculated": 0.87, - "Boiling point": "4200 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "320 GPa", - "Coefficient of linear thermal expansion": "6 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "2460 kg m-3", - "Electrical resistivity": "> 101210-8 Ω m", - "Electronic structure": "[He].2s2.2p1", - "ICSD oxidation states": [ - 3, - -3 - ], - "Ionic radii": { - "3": 0.41 - }, - "Liquid range": "1851 K", - "Melting point": "2349 K", - "Mendeleev no": 86, - "Mineral hardness": "9.3", - "Molar volume": "4.39 cm3", - "Name": "Boron", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "III": { - "": { - "crystal_radius": 0.15, - "ionic_radius": 0.01 - } - }, - "IV": { - "": { - "crystal_radius": 0.25, - "ionic_radius": 0.11 - } - }, - "VI": { - "": { - "crystal_radius": 0.41, - "ionic_radius": 0.27 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "27 W m-1 K-1", - "Van der waals radius": 1.92, - "Velocity of sound": "16200 m s-1", - "Vickers hardness": "49000 MN m-2", - "X": 2.04, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "B-10": 84.59, - "B-11": 40.59 - } - }, - "Ba": { - "Atomic mass": 137.327, - "Atomic no": 56, - "Atomic orbitals": { - "1s": -1305.743258, - "2p": -189.598483, - "2s": -200.844444, - "3d": -28.528933, - "3p": -37.536931, - "3s": -42.359434, - "4d": -3.432441, - "4p": -6.497622, - "4s": -8.257061, - "5p": -0.698605, - "5s": -1.157159, - "6s": -0.118967 - }, - "Atomic radius": 2.15, - "Atomic radius calculated": 2.53, - "Boiling point": "2143 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "9.6 GPa", - "Coefficient of linear thermal expansion": "20.6 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "3510 kg m-3", - "Electrical resistivity": "34 10-8 Ω m", - "Electronic structure": "[Xe].6s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 1.49 - }, - "Liquid range": "1143 K", - "Melting point": "1000 K", - "Mendeleev no": 14, - "Mineral hardness": "1.25", - "Molar volume": "38.16 cm3", - "Name": "Barium", - "Oxidation states": [ - 2 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "4.9 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.49, - "ionic_radius": 1.35 - } - }, - "VII": { - "": { - "crystal_radius": 1.52, - "ionic_radius": 1.38 - } - }, - "VIII": { - "": { - "crystal_radius": 1.56, - "ionic_radius": 1.42 - } - }, - "IX": { - "": { - "crystal_radius": 1.61, - "ionic_radius": 1.47 - } - }, - "X": { - "": { - "crystal_radius": 1.66, - "ionic_radius": 1.52 - } - }, - "XI": { - "": { - "crystal_radius": 1.71, - "ionic_radius": 1.57 - } - }, - "XII": { - "": { - "crystal_radius": 1.75, - "ionic_radius": 1.61 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "18 W m-1 K-1", - "Van der waals radius": 2.68, - "Velocity of sound": "1620 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.89, - "Youngs modulus": "13 GPa" - }, - "Be": { - "Atomic mass": 9.012182, - "Atomic no": 4, - "Atomic orbitals": { - "1s": -3.856411, - "2s": -0.205744 - }, - "Atomic radius": 1.05, - "Atomic radius calculated": 1.12, - "Boiling point": "2742 K", - "Brinell hardness": "600 MN m-2", - "Bulk modulus": "130 GPa", - "Coefficient of linear thermal expansion": "11.3 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "1848 kg m-3", - "Electrical resistivity": "3.8 10-8 Ω m", - "Electronic structure": "[He].2s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 0.59 - }, - "Liquid range": "1182 K", - "Melting point": "1560 K", - "Mendeleev no": 77, - "Mineral hardness": "5.5", - "Molar volume": "4.85 cm3", - "Name": "Beryllium", - "Oxidation states": [ - 2 - ], - "Poissons ratio": "0.032", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "132 GPa", - "Shannon radii": { - "2": { - "III": { - "": { - "crystal_radius": 0.3, - "ionic_radius": 0.16 - } - }, - "IV": { - "": { - "crystal_radius": 0.41, - "ionic_radius": 0.27 - } - }, - "VI": { - "": { - "crystal_radius": 0.59, - "ionic_radius": 0.45 - } - } - } - }, - "Superconduction temperature": "0.026 K", - "Thermal conductivity": "190 W m-1 K-1", - "Van der waals radius": 1.53, - "Velocity of sound": "13000 m s-1", - "Vickers hardness": "1670 MN m-2", - "X": 1.57, - "Youngs modulus": "287 GPa", - "NMR Quadrupole Moment": { - "Be-9": 52.88 - } - }, - "Bi": { - "Atomic mass": 208.9804, - "Atomic no": 83, - "Atomic orbitals": { - "1s": -2975.550959, - "2p": -484.716359, - "2s": -502.950758, - "3d": -95.532476, - "3p": -111.883393, - "3s": -120.613998, - "4d": -16.084817, - "4f": -6.382744, - "4p": -23.218641, - "4s": -27.07034, - "5d": -1.139408, - "5p": -3.293637, - "5s": -4.611934, - "6p": -0.180198, - "6s": -0.426129 - }, - "Atomic radius": 1.6, - "Atomic radius calculated": 1.43, - "Boiling point": "1837 K", - "Brinell hardness": "94.2 MN m-2", - "Bulk modulus": "31 GPa", - "Coefficient of linear thermal expansion": "13.4 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "9780 kg m-3", - "Electrical resistivity": "130 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2.6p3", - "ICSD oxidation states": [ - 1, - 2, - 3, - 5 - ], - "Ionic radii": { - "3": 1.17, - "5": 0.9 - }, - "Liquid range": "1292.6 K", - "Melting point": "544.4 K", - "Mendeleev no": 87, - "Mineral hardness": "2.25", - "Molar volume": "21.31 cm3", - "Name": "Bismuth", - "Oxidation states": [ - -3, - 3, - 5 - ], - "Poissons ratio": "0.33", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "12 GPa", - "Shannon radii": { - "3": { - "V": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - }, - "VI": { - "": { - "crystal_radius": 1.17, - "ionic_radius": 1.03 - } - }, - "VIII": { - "": { - "crystal_radius": 1.31, - "ionic_radius": 1.17 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "8 W m-1 K-1", - "Van der waals radius": 2.07, - "Velocity of sound": "1790 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.02, - "Youngs modulus": "32 GPa" - }, - "Bk": { - "Atomic mass": 247.0, - "Atomic no": 97, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "14780 kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f9.7s2", - "Ionic radii": { - "3": 1.1, - "4": 0.97 - }, - "Liquid range": "no data K", - "Melting point": "1259 K", - "Mendeleev no": 40, - "Mineral hardness": "no data", - "Molar volume": "16.84 cm3", - "Name": "Berkelium", - "Oxidation states": [ - 3, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.97, - "ionic_radius": 0.83 - } - }, - "VIII": { - "": { - "crystal_radius": 1.07, - "ionic_radius": 0.93 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "10 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Br": { - "Atomic mass": 79.904, - "Atomic no": 35, - "Atomic orbitals": { - "1s": -480.182643, - "2p": -55.67796, - "2s": -61.710022, - "3d": -2.52211, - "3p": -6.298805, - "3s": -8.409057, - "4p": -0.295334, - "4s": -0.720066 - }, - "Atomic radius": 1.15, - "Atomic radius calculated": 0.94, - "Boiling point": "332 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "1.9 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -1, - 1, - 3, - 5, - 7 - ], - "Critical temperature": "586 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "> 101810-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2.4p5", - "ICSD oxidation states": [ - 5, - -1 - ], - "Ionic radii": { - "-1": 1.82, - "3": 0.73, - "5": 0.45, - "7": 0.53 - }, - "Liquid range": "66.2 K", - "Melting point": "265.8 K", - "Mendeleev no": 98, - "Mineral hardness": "no data", - "Molar volume": "19.78 cm3", - "Name": "Bromine", - "Oxidation states": [ - -1, - 1, - 3, - 4, - 5, - 7 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.001132", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-1": { - "VI": { - "": { - "crystal_radius": 1.82, - "ionic_radius": 1.96 - } - } - }, - "3": { - "IVSQ": { - "": { - "crystal_radius": 0.73, - "ionic_radius": 0.59 - } - } - }, - "5": { - "IIIPY": { - "": { - "crystal_radius": 0.45, - "ionic_radius": 0.31 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.39, - "ionic_radius": 0.25 - } - }, - "VI": { - "": { - "crystal_radius": 0.53, - "ionic_radius": 0.39 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.12 W m-1 K-1", - "Van der waals radius": 1.85, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.96, - "Youngs modulus": "no data GPa" - }, - "C": { - "Atomic mass": 12.0107, - "Atomic no": 6, - "Atomic orbitals": { - "1s": -9.947718, - "2p": -0.199186, - "2s": -0.500866 - }, - "Atomic radius": 0.7, - "Atomic radius calculated": 0.67, - "Boiling point": "4300 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "33 GPa", - "Coefficient of linear thermal expansion": "7.1 x10-6K-1", - "Common oxidation states": [ - -4, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "2267 kg m-3", - "Electrical resistivity": "about 1000 - direction dependent10-8 Ω m", - "Electronic structure": "[He].2s2.2p2", - "ICSD oxidation states": [ - 2, - 3, - 4, - -4, - -3, - -2 - ], - "Ionic radii": { - "4": 0.3 - }, - "Liquid range": "500 K", - "Melting point": "3800 K", - "Mendeleev no": 95, - "Mineral hardness": "0.5 (graphite; diamond is 10.0)(no units)", - "Molar volume": "5.29 cm3", - "Name": "Carbon", - "Oxidation states": [ - -4, - -3, - -2, - -1, - 1, - 2, - 3, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "27 %", - "Refractive index": "2.417 (diamond)(no units)", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "4": { - "III": { - "": { - "crystal_radius": 0.06, - "ionic_radius": -0.08 - } - }, - "IV": { - "": { - "crystal_radius": 0.29, - "ionic_radius": 0.15 - } - }, - "VI": { - "": { - "crystal_radius": 0.3, - "ionic_radius": 0.16 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "140 W m-1 K-1", - "Van der waals radius": 1.7, - "Velocity of sound": "18350 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.55, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "C-11": 33.27 - } - }, - "Ca": { - "Atomic mass": 40.078, - "Atomic no": 20, - "Atomic orbitals": { - "1s": -143.935181, - "2p": -12.285376, - "2s": -15.046905, - "3p": -1.030572, - "3s": -1.706331, - "4s": -0.141411 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": 1.94, - "Boiling point": "1757 K", - "Brinell hardness": "167 MN m-2", - "Bulk modulus": "17 GPa", - "Coefficient of linear thermal expansion": "22.3 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "1550 kg m-3", - "Electrical resistivity": "3.4 10-8 Ω m", - "Electronic structure": "[Ar].4s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 1.14 - }, - "Liquid range": "642 K", - "Melting point": "1115 K", - "Mendeleev no": 16, - "Mineral hardness": "1.75", - "Molar volume": "26.20 cm3", - "Name": "Calcium", - "Oxidation states": [ - 2 - ], - "Poissons ratio": "0.31", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "7.4 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.14, - "ionic_radius": 1.0 - } - }, - "VII": { - "": { - "crystal_radius": 1.2, - "ionic_radius": 1.06 - } - }, - "VIII": { - "": { - "crystal_radius": 1.26, - "ionic_radius": 1.12 - } - }, - "IX": { - "": { - "crystal_radius": 1.32, - "ionic_radius": 1.18 - } - }, - "X": { - "": { - "crystal_radius": 1.37, - "ionic_radius": 1.23 - } - }, - "XII": { - "": { - "crystal_radius": 1.48, - "ionic_radius": 1.34 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "200 W m-1 K-1", - "Van der waals radius": 2.31, - "Velocity of sound": "3810 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.0, - "Youngs modulus": "20 GPa", - "NMR Quadrupole Moment": { - "Ca-41": -66.5, - "Ca-43": -40.8 - } - }, - "Cd": { - "Atomic mass": 112.411, - "Atomic no": 48, - "Atomic orbitals": { - "1s": -941.476646, - "2p": -127.63512, - "2s": -136.83249, - "3d": -14.685252, - "3p": -21.637522, - "3s": -25.379908, - "4d": -0.47053, - "4p": -2.39526, - "4s": -3.596069, - "5s": -0.204228 - }, - "Atomic radius": 1.55, - "Atomic radius calculated": 1.61, - "Boiling point": "1040 K", - "Brinell hardness": "203 MN m-2", - "Bulk modulus": "42 GPa", - "Coefficient of linear thermal expansion": "30.8 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "8650 kg m-3", - "Electrical resistivity": "7 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 1.09 - }, - "Liquid range": "445.78 K", - "Melting point": "594.22 K", - "Mendeleev no": 75, - "Mineral hardness": "2.0", - "Molar volume": "13.00 cm3", - "Name": "Cadmium", - "Oxidation states": [ - 1, - 2 - ], - "Poissons ratio": "0.30", - "Reflectivity": "67 %", - "Refractive index": "no data", - "Rigidity modulus": "19 GPa", - "Shannon radii": { - "2": { - "IV": { - "": { - "crystal_radius": 0.92, - "ionic_radius": 0.78 - } - }, - "V": { - "": { - "crystal_radius": 1.01, - "ionic_radius": 0.87 - } - }, - "VI": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - }, - "VII": { - "": { - "crystal_radius": 1.17, - "ionic_radius": 1.03 - } - }, - "VIII": { - "": { - "crystal_radius": 1.24, - "ionic_radius": 1.1 - } - }, - "XII": { - "": { - "crystal_radius": 1.45, - "ionic_radius": 1.31 - } - } - } - }, - "Superconduction temperature": "0.517 K", - "Thermal conductivity": "97 W m-1 K-1", - "Van der waals radius": 1.58, - "Velocity of sound": "2310 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.69, - "Youngs modulus": "50 GPa" - }, - "Ce": { - "Atomic mass": 140.116, - "Atomic no": 58, - "Atomic orbitals": { - "1s": -1406.148284, - "2p": -206.925148, - "2s": -218.684842, - "3d": -32.412569, - "3p": -41.938282, - "3s": -47.035283, - "4d": -4.192548, - "4f": -0.337442, - "4p": -7.532106, - "4s": -9.432744, - "5d": -0.14055, - "5p": -0.85011, - "5s": -1.369728, - "6s": -0.133974 - }, - "Atomic radius": 1.85, - "Atomic radius calculated": "no data", - "Boiling point": "3633 K", - "Brinell hardness": "412 MN m-2", - "Bulk modulus": "22 GPa", - "Coefficient of linear thermal expansion": "6.3 x10-6K-1", - "Common oxidation states": [ - 3, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "6689 kg m-3", - "Electrical resistivity": "74 10-8 Ω m", - "Electronic structure": "[Xe].4f1.5d1.6s2", - "ICSD oxidation states": [ - 3, - 4 - ], - "Ionic radii": { - "3": 1.15, - "4": 1.01 - }, - "Liquid range": "2565 K", - "Melting point": "1068 K", - "Mendeleev no": 32, - "Mineral hardness": "2.5", - "Molar volume": "20.69 cm3", - "Name": "Cerium", - "Oxidation states": [ - 2, - 3, - 4 - ], - "Poissons ratio": "0.24", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "14 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.15, - "ionic_radius": 1.01 - } - }, - "VII": { - "": { - "crystal_radius": 1.21, - "ionic_radius": 1.07 - } - }, - "VIII": { - "": { - "crystal_radius": 1.283, - "ionic_radius": 1.143 - } - }, - "IX": { - "": { - "crystal_radius": 1.336, - "ionic_radius": 1.196 - } - }, - "X": { - "": { - "crystal_radius": 1.39, - "ionic_radius": 1.25 - } - }, - "XII": { - "": { - "crystal_radius": 1.48, - "ionic_radius": 1.34 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 1.01, - "ionic_radius": 0.87 - } - }, - "VIII": { - "": { - "crystal_radius": 1.11, - "ionic_radius": 0.97 - } - }, - "X": { - "": { - "crystal_radius": 1.21, - "ionic_radius": 1.07 - } - }, - "XII": { - "": { - "crystal_radius": 1.28, - "ionic_radius": 1.14 - } - } - } - }, - "Superconduction temperature": "0.022 (under pressure)K", - "Thermal conductivity": "11 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2100 m s-1", - "Vickers hardness": "270 MN m-2", - "X": 1.12, - "Youngs modulus": "34 GPa" - }, - "Cf": { - "Atomic mass": 251.0, - "Atomic no": 98, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "15100 kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f10.7s2", - "Ionic radii": { - "3": 1.09, - "4": 0.961 - }, - "Liquid range": "no data K", - "Melting point": "1173 K", - "Mendeleev no": 39, - "Mineral hardness": "no data", - "Molar volume": "16.50 cm3", - "Name": "Californium", - "Oxidation states": [ - 2, - 3, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.961, - "ionic_radius": 0.821 - } - }, - "VIII": { - "": { - "crystal_radius": 1.06, - "ionic_radius": 0.92 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Cl": { - "Atomic mass": 35.453, - "Atomic no": 17, - "Atomic orbitals": { - "1s": -100.369229, - "2p": -7.039982, - "2s": -9.187993, - "3p": -0.32038, - "3s": -0.754458 - }, - "Atomic radius": 1.0, - "Atomic radius calculated": 0.79, - "Boiling point": "239.11 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "1.1 (liquid)GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -1, - 1, - 3, - 5, - 7 - ], - "Critical temperature": "417 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "> 101010-8 Ω m", - "Electronic structure": "[Ne].3s2.3p5", - "ICSD oxidation states": [ - -1 - ], - "Ionic radii": { - "-1": 1.67, - "5": 0.26, - "7": 0.41 - }, - "Liquid range": "67.51 K", - "Melting point": "171.6 K", - "Mendeleev no": 99, - "Mineral hardness": "no data", - "Molar volume": "17.39 cm3", - "Name": "Chlorine", - "Oxidation states": [ - -1, - 1, - 2, - 3, - 4, - 5, - 6, - 7 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000773", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-1": { - "VI": { - "": { - "crystal_radius": 1.67, - "ionic_radius": 1.81 - } - } - }, - "5": { - "IIIPY": { - "": { - "crystal_radius": 0.26, - "ionic_radius": 0.12 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.22, - "ionic_radius": 0.08 - } - }, - "VI": { - "": { - "crystal_radius": 0.41, - "ionic_radius": 0.27 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.0089 W m-1 K-1", - "Van der waals radius": 1.75, - "Velocity of sound": "206 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 3.16, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "Cl-35": -81.65, - "Cl-37": -64.35 - } - }, - "Cm": { - "Atomic mass": 247.0, - "Atomic no": 96, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "3383 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "13510 kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f7.6d1.7s2", - "Ionic radii": { - "3": 1.11, - "4": 0.99 - }, - "Liquid range": "1770 K", - "Melting point": "1613 K", - "Mendeleev no": 41, - "Mineral hardness": "no data", - "Molar volume": "18.05 cm3", - "Name": "Curium", - "Oxidation states": [ - 3, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.11, - "ionic_radius": 0.97 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.99, - "ionic_radius": 0.85 - } - }, - "VIII": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "8.8 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Co": { - "Atomic mass": 58.933195, - "Atomic no": 27, - "Atomic orbitals": { - "1s": -275.616639, - "2p": -28.152095, - "2s": -32.379758, - "3d": -0.322368, - "3p": -2.388285, - "3s": -3.651812, - "4s": -0.204497 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.52, - "Boiling point": "3200 K", - "Brinell hardness": "700 MN m-2", - "Bulk modulus": "180 GPa", - "Coefficient of linear thermal expansion": "13.0 x10-6K-1", - "Common oxidation states": [ - 2, - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "8900 kg m-3", - "Electrical resistivity": "6 10-8 Ω m", - "Electronic structure": "[Ar].3d7.4s2", - "ICSD oxidation states": [ - 1, - 2, - 3, - 4 - ], - "Ionic radii": { - "2": 0.885, - "3": 0.75, - "4": 0.67 - }, - "Ionic radii hs": { - "2": 0.885, - "3": 0.75, - "4": 0.67 - }, - "Ionic radii ls": { - "2": 0.79, - "3": 0.685 - }, - "Liquid range": "1432 K", - "Melting point": "1768 K", - "Mendeleev no": 64, - "Mineral hardness": "5.0", - "Molar volume": "6.67 cm3", - "Name": "Cobalt", - "Oxidation states": [ - -1, - 1, - 2, - 3, - 4, - 5 - ], - "Poissons ratio": "0.31", - "Reflectivity": "67 %", - "Refractive index": "no data", - "Rigidity modulus": "75 GPa", - "Shannon radii": { - "2": { - "IV": { - "High Spin": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - }, - "V": { - "": { - "crystal_radius": 0.81, - "ionic_radius": 0.67 - } - }, - "VI": { - "Low Spin": { - "crystal_radius": 0.79, - "ionic_radius": 0.65 - }, - "High Spin": { - "crystal_radius": 0.885, - "ionic_radius": 0.745 - } - }, - "VIII": { - "": { - "crystal_radius": 1.04, - "ionic_radius": 0.9 - } - } - }, - "3": { - "VI": { - "High Spin": { - "crystal_radius": 0.75, - "ionic_radius": 0.61 - }, - "Low Spin": { - "crystal_radius": 0.685, - "ionic_radius": 0.545 - } - } - }, - "4": { - "IV": { - "": { - "crystal_radius": 0.54, - "ionic_radius": 0.4 - } - }, - "VI": { - "High Spin": { - "crystal_radius": 0.67, - "ionic_radius": 0.53 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "100 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4720 m s-1", - "Vickers hardness": "1043 MN m-2", - "X": 1.88, - "Youngs modulus": "209 GPa", - "NMR Quadrupole Moment": { - "Co-59": 420.3 - } - }, - "Cr": { - "Atomic mass": 51.9961, - "Atomic no": 24, - "Atomic orbitals": { - "1s": -213.881191, - "2p": -20.526273, - "2s": -24.113457, - "3d": -0.118123, - "3p": -1.65423, - "3s": -2.649085, - "4s": -0.150445 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.66, - "Boiling point": "2944 K", - "Brinell hardness": "1120 MN m-2", - "Bulk modulus": "160 GPa", - "Coefficient of linear thermal expansion": "4.9 x10-6K-1", - "Common oxidation states": [ - 3, - 6 - ], - "Critical temperature": "no data K", - "Density of solid": "7140 kg m-3", - "Electrical resistivity": "12.7 10-8 Ω m", - "Electronic structure": "[Ar].3d5.4s1", - "ICSD oxidation states": [ - 2, - 3, - 4, - 5, - 6 - ], - "Ionic radii": { - "2": 0.94 - }, - "Ionic radii hs": { - "2": 0.94 - }, - "Ionic radii ls": { - "2": 0.87, - "3": 0.755, - "4": 0.69, - "5": 0.63, - "6": 0.58 - }, - "Liquid range": "764 K", - "Melting point": "2180 K", - "Mendeleev no": 57, - "Mineral hardness": "8.5", - "Molar volume": "7.23 cm3", - "Name": "Chromium", - "Oxidation states": [ - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.21", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "115 GPa", - "Shannon radii": { - "2": { - "VI": { - "Low Spin": { - "crystal_radius": 0.87, - "ionic_radius": 0.73 - }, - "High Spin": { - "crystal_radius": 0.94, - "ionic_radius": 0.8 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 0.755, - "ionic_radius": 0.615 - } - } - }, - "4": { - "IV": { - "": { - "crystal_radius": 0.55, - "ionic_radius": 0.41 - } - }, - "VI": { - "": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.485, - "ionic_radius": 0.345 - } - }, - "VI": { - "": { - "crystal_radius": 0.63, - "ionic_radius": 0.49 - } - }, - "VIII": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.4, - "ionic_radius": 0.26 - } - }, - "VI": { - "": { - "crystal_radius": 0.58, - "ionic_radius": 0.44 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "94 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "5940 m s-1", - "Vickers hardness": "1060 MN m-2", - "X": 1.66, - "Youngs modulus": "279 GPa", - "NMR Quadrupole Moment": { - "Cr-53": -150.5 - } - }, - "Cs": { - "Atomic mass": 132.9054519, - "Atomic no": 55, - "Atomic orbitals": { - "1s": -1256.738791, - "2p": -180.995344, - "2s": -191.981873, - "3d": -26.418398, - "3p": -35.166423, - "3s": -39.851584, - "4d": -2.848386, - "4p": -5.769326, - "4s": -7.455966, - "5p": -0.504903, - "5s": -0.915819, - "6s": -0.078699 - }, - "Atomic radius": 2.6, - "Atomic radius calculated": 2.98, - "Boiling point": "944 K", - "Brinell hardness": "0.14 MN m-2", - "Bulk modulus": "1.6 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "1938 K", - "Density of solid": "1879 kg m-3", - "Electrical resistivity": "21 10-8 Ω m", - "Electronic structure": "[Xe].6s1", - "ICSD oxidation states": [ - 1 - ], - "Ionic radii": { - "1": 1.81 - }, - "Liquid range": "642.41 K", - "Melting point": "301.59 K", - "Mendeleev no": 8, - "Mineral hardness": "0.2", - "Molar volume": "70.94 cm3", - "Name": "Cesium", - "Oxidation states": [ - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "1": { - "VI": { - "": { - "crystal_radius": 1.81, - "ionic_radius": 1.67 - } - }, - "VIII": { - "": { - "crystal_radius": 1.88, - "ionic_radius": 1.74 - } - }, - "IX": { - "": { - "crystal_radius": 1.92, - "ionic_radius": 1.78 - } - }, - "X": { - "": { - "crystal_radius": 1.95, - "ionic_radius": 1.81 - } - }, - "XI": { - "": { - "crystal_radius": 1.99, - "ionic_radius": 1.85 - } - }, - "XII": { - "": { - "crystal_radius": 2.02, - "ionic_radius": 1.88 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "36 W m-1 K-1", - "Van der waals radius": 3.43, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.79, - "Youngs modulus": "1.7 GPa" - }, - "Cu": { - "Atomic mass": 63.546, - "Atomic no": 29, - "Atomic orbitals": { - "1s": -320.78852, - "2p": -33.481247, - "2s": -38.14131, - "3d": -0.202272, - "3p": -2.609244, - "3s": -4.057453, - "4s": -0.172056 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.45, - "Boiling point": "3200 K", - "Brinell hardness": "874 MN m-2", - "Bulk modulus": "140 GPa", - "Coefficient of linear thermal expansion": "16.5 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "8920 kg m-3", - "Electrical resistivity": "1.72 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s1", - "ICSD oxidation states": [ - 1, - 2, - 3 - ], - "Ionic radii": { - "1": 0.91, - "2": 0.87, - "3": 0.68 - }, - "Liquid range": "1842.23 K", - "Melting point": "1357.77 K", - "Mendeleev no": 72, - "Mineral hardness": "3.0", - "Molar volume": "7.11 cm3", - "Name": "Copper", - "Oxidation states": [ - 1, - 2, - 3, - 4 - ], - "Poissons ratio": "0.34", - "Reflectivity": "90 %", - "Refractive index": "no data", - "Rigidity modulus": "48 GPa", - "Shannon radii": { - "1": { - "II": { - "": { - "crystal_radius": 0.6, - "ionic_radius": 0.46 - } - }, - "IV": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - }, - "VI": { - "": { - "crystal_radius": 0.91, - "ionic_radius": 0.77 - } - } - }, - "2": { - "IV": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - }, - "IVSQ": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - }, - "V": { - "": { - "crystal_radius": 0.79, - "ionic_radius": 0.65 - } - }, - "VI": { - "": { - "crystal_radius": 0.87, - "ionic_radius": 0.73 - } - } - }, - "3": { - "VI": { - "Low Spin": { - "crystal_radius": 0.68, - "ionic_radius": 0.54 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "400 W m-1 K-1", - "Van der waals radius": 1.4, - "Velocity of sound": "3570 m s-1", - "Vickers hardness": "369 MN m-2", - "X": 1.9, - "Youngs modulus": "130 GPa", - "NMR Quadrupole Moment": { - "Cu-63": -220.15, - "Cu-65": -204.14 - } - }, - "Dy": { - "Atomic mass": 162.5, - "Atomic no": 66, - "Atomic orbitals": { - "1s": -1843.229585, - "2p": -281.558531, - "2s": -295.342856, - "3d": -47.4867, - "3p": -59.091931, - "3s": -65.299442, - "4d": -5.686352, - "4f": -0.265302, - "4p": -10.094091, - "4s": -12.551251, - "5p": -0.90349, - "5s": -1.547977, - "6s": -0.132769 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": 2.28, - "Boiling point": "2840 K", - "Brinell hardness": "500 MN m-2", - "Bulk modulus": "41 GPa", - "Coefficient of linear thermal expansion": "9.9 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "8551 kg m-3", - "Electrical resistivity": "92.6 10-8 Ω m", - "Electronic structure": "[Xe].4f10.6s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "2": 1.21, - "3": 1.052 - }, - "Liquid range": "1160 K", - "Melting point": "1680 K", - "Mendeleev no": 24, - "Mineral hardness": "no data", - "Molar volume": "19.01 cm3", - "Name": "Dysprosium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.25", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "25 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.21, - "ionic_radius": 1.07 - } - }, - "VII": { - "": { - "crystal_radius": 1.27, - "ionic_radius": 1.13 - } - }, - "VIII": { - "": { - "crystal_radius": 1.33, - "ionic_radius": 1.19 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.052, - "ionic_radius": 0.912 - } - }, - "VII": { - "": { - "crystal_radius": 1.11, - "ionic_radius": 0.97 - } - }, - "VIII": { - "": { - "crystal_radius": 1.167, - "ionic_radius": 1.027 - } - }, - "IX": { - "": { - "crystal_radius": 1.223, - "ionic_radius": 1.083 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "11 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2710 m s-1", - "Vickers hardness": "540 MN m-2", - "X": 1.22, - "Youngs modulus": "61 GPa" - }, - "Er": { - "Atomic mass": 167.259, - "Atomic no": 68, - "Atomic orbitals": { - "1s": -1961.799176, - "2p": -302.01827, - "2s": -316.310631, - "3d": -51.682149, - "3p": -63.818655, - "3s": -70.310142, - "4d": -6.127443, - "4f": -0.278577, - "4p": -10.819574, - "4s": -13.423547, - "5p": -0.935202, - "5s": -1.616073, - "6s": -0.134905 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": 2.26, - "Boiling point": "3141 K", - "Brinell hardness": "814 MN m-2", - "Bulk modulus": "44 GPa", - "Coefficient of linear thermal expansion": "12.2 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "9066 kg m-3", - "Electrical resistivity": "86.0 10-8 Ω m", - "Electronic structure": "[Xe].4f12.6s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "3": 1.03 - }, - "Liquid range": "1371 K", - "Melting point": "1802 K", - "Mendeleev no": 22, - "Mineral hardness": "no data", - "Molar volume": "18.46 cm3", - "Name": "Erbium", - "Oxidation states": [ - 3 - ], - "Poissons ratio": "0.24", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "28 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.03, - "ionic_radius": 0.89 - } - }, - "VII": { - "": { - "crystal_radius": 1.085, - "ionic_radius": 0.945 - } - }, - "VIII": { - "": { - "crystal_radius": 1.144, - "ionic_radius": 1.004 - } - }, - "IX": { - "": { - "crystal_radius": 1.202, - "ionic_radius": 1.062 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "15 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2830 m s-1", - "Vickers hardness": "589 MN m-2", - "X": 1.24, - "Youngs modulus": "70 GPa" - }, - "Es": { - "Atomic mass": 252.0, - "Atomic no": 99, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f11.7s2", - "Liquid range": "no data K", - "Melting point": "1133 K", - "Mendeleev no": 38, - "Mineral hardness": "no data", - "Molar volume": "28.52 cm3", - "Name": "Einsteinium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Eu": { - "Atomic mass": 151.964, - "Atomic no": 63, - "Atomic orbitals": { - "1s": -1672.309322, - "2p": -252.176697, - "2s": -265.199534, - "3d": -41.465518, - "3p": -52.281987, - "3s": -58.068128, - "4d": -5.03242, - "4f": -0.232773, - "4p": -9.025455, - "4s": -11.267747, - "5p": -0.853575, - "5s": -1.444087, - "6s": -0.129426 - }, - "Atomic radius": 1.85, - "Atomic radius calculated": 2.31, - "Boiling point": "1800 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "8.3 GPa", - "Coefficient of linear thermal expansion": "35 x10-6K-1", - "Common oxidation states": [ - 2, - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "5244 kg m-3", - "Electrical resistivity": "90 10-8 Ω m", - "Electronic structure": "[Xe].4f7.6s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "2": 1.31, - "3": 1.087 - }, - "Liquid range": "701 K", - "Melting point": "1099 K", - "Mendeleev no": 18, - "Mineral hardness": "no data", - "Molar volume": "28.97 cm3", - "Name": "Europium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.15", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "7.9 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.31, - "ionic_radius": 1.17 - } - }, - "VII": { - "": { - "crystal_radius": 1.34, - "ionic_radius": 1.2 - } - }, - "VIII": { - "": { - "crystal_radius": 1.39, - "ionic_radius": 1.25 - } - }, - "IX": { - "": { - "crystal_radius": 1.44, - "ionic_radius": 1.3 - } - }, - "X": { - "": { - "crystal_radius": 1.49, - "ionic_radius": 1.35 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.087, - "ionic_radius": 0.947 - } - }, - "VII": { - "": { - "crystal_radius": 1.15, - "ionic_radius": 1.01 - } - }, - "VIII": { - "": { - "crystal_radius": 1.206, - "ionic_radius": 1.066 - } - }, - "IX": { - "": { - "crystal_radius": 1.26, - "ionic_radius": 1.12 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "14 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "167 MN m-2", - "X": 1.2, - "Youngs modulus": "18 GPa" - }, - "F": { - "Atomic mass": 18.9984032, - "Atomic no": 9, - "Atomic orbitals": { - "1s": -24.189391, - "2p": -0.415606, - "2s": -1.086859 - }, - "Atomic radius": 0.5, - "Atomic radius calculated": 0.42, - "Boiling point": "85.03 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -1 - ], - "Critical temperature": "144 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[He].2s2.2p5", - "ICSD oxidation states": [ - -1 - ], - "Ionic radii": { - "-1": 1.19, - "7": 0.22 - }, - "Liquid range": "31.5 K", - "Melting point": "53.53 K", - "Mendeleev no": 102, - "Mineral hardness": "no data", - "Molar volume": "11.20 cm3", - "Name": "Fluorine", - "Oxidation states": [ - -1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000195", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-1": { - "II": { - "": { - "crystal_radius": 1.145, - "ionic_radius": 1.285 - } - }, - "III": { - "": { - "crystal_radius": 1.16, - "ionic_radius": 1.3 - } - }, - "IV": { - "": { - "crystal_radius": 1.17, - "ionic_radius": 1.31 - } - }, - "VI": { - "": { - "crystal_radius": 1.19, - "ionic_radius": 1.33 - } - } - }, - "7": { - "VI": { - "": { - "crystal_radius": 0.22, - "ionic_radius": 0.08 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.0277 W m-1 K-1", - "Van der waals radius": 1.47, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 3.98, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "F-19": -94.2 - } - }, - "Fe": { - "Atomic mass": 55.845, - "Atomic no": 26, - "Atomic orbitals": { - "1s": -254.225505, - "2p": -25.551766, - "2s": -29.56486, - "3d": -0.295049, - "3p": -2.187523, - "3s": -3.360621, - "4s": -0.197978 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.56, - "Boiling point": "3134 K", - "Brinell hardness": "490 MN m-2", - "Bulk modulus": "170 GPa", - "Coefficient of linear thermal expansion": "11.8 x10-6K-1", - "Common oxidation states": [ - 2, - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "7874 kg m-3", - "Electrical resistivity": "10 10-8 Ω m", - "Electronic structure": "[Ar].3d6.4s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "2": 0.92, - "3": 0.785 - }, - "Ionic radii hs": { - "2": 0.92, - "3": 0.785 - }, - "Ionic radii ls": { - "2": 0.75, - "3": 0.69, - "4": 0.725, - "6": 0.39 - }, - "Liquid range": "1323 K", - "Melting point": "1811 K", - "Mendeleev no": 61, - "Mineral hardness": "4.0", - "Molar volume": "7.09 cm3", - "Name": "Iron", - "Oxidation states": [ - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.29", - "Reflectivity": "65 %", - "Refractive index": "no data", - "Rigidity modulus": "82 GPa", - "Shannon radii": { - "2": { - "IV": { - "High Spin": { - "crystal_radius": 0.77, - "ionic_radius": 0.63 - } - }, - "IVSQ": { - "High Spin": { - "crystal_radius": 0.78, - "ionic_radius": 0.64 - } - }, - "VI": { - "Low Spin": { - "crystal_radius": 0.75, - "ionic_radius": 0.61 - }, - "High Spin": { - "crystal_radius": 0.92, - "ionic_radius": 0.78 - } - }, - "VIII": { - "High Spin": { - "crystal_radius": 1.06, - "ionic_radius": 0.92 - } - } - }, - "3": { - "IV": { - "High Spin": { - "crystal_radius": 0.63, - "ionic_radius": 0.49 - } - }, - "V": { - "": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - }, - "VI": { - "Low Spin": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - }, - "High Spin": { - "crystal_radius": 0.785, - "ionic_radius": 0.645 - } - }, - "VIII": { - "High Spin": { - "crystal_radius": 0.92, - "ionic_radius": 0.78 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.725, - "ionic_radius": 0.585 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.39, - "ionic_radius": 0.25 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "80 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4910 m s-1", - "Vickers hardness": "608 MN m-2", - "X": 1.83, - "Youngs modulus": "211 GPa", - "NMR Quadrupole Moment": { - "Fe-57": 160.0 - } - }, - "Fm": { - "Atomic mass": 257.0, - "Atomic no": 100, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f12.7s2", - "Liquid range": "no data K", - "Melting point": "about 1800 K", - "Mendeleev no": 37, - "Mineral hardness": "no data", - "Molar volume": "no data cm3", - "Name": "Fermium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Fr": { - "Atomic mass": 223.0, - "Atomic no": 87, - "Atomic orbitals": { - "1s": -3283.263399, - "2p": -542.41424, - "2s": -561.73045, - "3d": -111.085223, - "3p": -128.607136, - "3s": -137.959632, - "4d": -20.812462, - "4f": -10.050648, - "4p": -28.648131, - "4s": -32.861013, - "5d": -2.360991, - "5p": -4.97328, - "5s": -6.509516, - "6p": -0.466197, - "6s": -0.841848, - "7s": -0.076176 - }, - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].7s1", - "Ionic radii": { - "1": 1.94 - }, - "Liquid range": "no data K", - "Melting point": "maybe about 300 K", - "Mendeleev no": 7, - "Mineral hardness": "no data", - "Molar volume": "no data cm3", - "Name": "Francium", - "Oxidation states": [ - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "1": { - "VI": { - "": { - "crystal_radius": 1.94, - "ionic_radius": 1.8 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": 3.48, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.7, - "Youngs modulus": "no data GPa" - }, - "Ga": { - "Atomic mass": 69.723, - "Atomic no": 31, - "Atomic orbitals": { - "1s": -370.170639, - "2p": -40.093339, - "2s": -45.200869, - "3d": -0.736204, - "3p": -3.584666, - "3s": -5.241645, - "4p": -0.101634, - "4s": -0.328019 - }, - "Atomic radius": 1.3, - "Atomic radius calculated": 1.36, - "Boiling point": "2477 K", - "Brinell hardness": "60 MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "120 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "5904 kg m-3", - "Electrical resistivity": "about 14 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2.4p1", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "3": 0.76 - }, - "Liquid range": "2174.09 K", - "Melting point": "302.91 K", - "Mendeleev no": 81, - "Mineral hardness": "1.5", - "Molar volume": "11.80 cm3", - "Name": "Gallium", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "IV": { - "": { - "crystal_radius": 0.61, - "ionic_radius": 0.47 - } - }, - "V": { - "": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - } - }, - "VI": { - "": { - "crystal_radius": 0.76, - "ionic_radius": 0.62 - } - } - } - }, - "Superconduction temperature": "1.083 K", - "Thermal conductivity": "29 W m-1 K-1", - "Van der waals radius": 1.87, - "Velocity of sound": "2740 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.81, - "Youngs modulus": "no data GPa" - }, - "Gd": { - "Atomic mass": 157.25, - "Atomic no": 64, - "Atomic orbitals": { - "1s": -1728.625195, - "2p": -262.081616, - "2s": -275.36313, - "3d": -43.754556, - "3p": -54.836922, - "3s": -60.764408, - "4d": -5.531835, - "4f": -0.489012, - "4p": -9.669866, - "4s": -11.986486, - "5d": -0.12722, - "5p": -0.978749, - "5s": -1.608477, - "6s": -0.143627 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": 2.33, - "Boiling point": "3523 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "38 GPa", - "Coefficient of linear thermal expansion": "9.4 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "7901 kg m-3", - "Electrical resistivity": "131 10-8 Ω m", - "Electronic structure": "[Xe].4f7.5d1.6s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "3": 1.075 - }, - "Liquid range": "1938 K", - "Melting point": "1585 K", - "Mendeleev no": 27, - "Mineral hardness": "no data", - "Molar volume": "19.90 cm3", - "Name": "Gadolinium", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "0.26", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "22 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.078, - "ionic_radius": 0.938 - } - }, - "VII": { - "": { - "crystal_radius": 1.14, - "ionic_radius": 1.0 - } - }, - "VIII": { - "": { - "crystal_radius": 1.193, - "ionic_radius": 1.053 - } - }, - "IX": { - "": { - "crystal_radius": 1.247, - "ionic_radius": 1.107 - } - } - } - }, - "Superconduction temperature": "1.083 K", - "Thermal conductivity": "11 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2680 m s-1", - "Vickers hardness": "570 MN m-2", - "X": 1.2, - "Youngs modulus": "55 GPa" - }, - "Ge": { - "Atomic mass": 72.64, - "Atomic no": 32, - "Atomic orbitals": { - "1s": -396.292991, - "2p": -43.720129, - "2s": -49.055282, - "3d": -1.117316, - "3p": -4.194822, - "3s": -5.961472, - "4p": -0.149882, - "4s": -0.426523 - }, - "Atomic radius": 1.25, - "Atomic radius calculated": 1.25, - "Boiling point": "3093 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "6 x10-6K-1", - "Common oxidation states": [ - -4, - 2, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "5323 kg m-3", - "Electrical resistivity": "about 50000 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2.4p2", - "ICSD oxidation states": [ - 2, - 3, - 4 - ], - "Ionic radii": { - "2": 0.87, - "4": 0.67 - }, - "Liquid range": "1881.6 K", - "Melting point": "1211.4 K", - "Mendeleev no": 84, - "Mineral hardness": "6.0", - "Molar volume": "13.63 cm3", - "Name": "Germanium", - "Oxidation states": [ - -4, - 1, - 2, - 3, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 0.87, - "ionic_radius": 0.73 - } - } - }, - "4": { - "IV": { - "": { - "crystal_radius": 0.53, - "ionic_radius": 0.39 - } - }, - "VI": { - "": { - "crystal_radius": 0.67, - "ionic_radius": 0.53 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "60 W m-1 K-1", - "Van der waals radius": 2.11, - "Velocity of sound": "5400 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.01, - "Youngs modulus": "no data GPa" - }, - "H": { - "Atomic mass": 1.00794, - "Atomic no": 1, - "Atomic orbitals": { - "1s": -0.233471 - }, - "Atomic radius": 0.25, - "Atomic radius calculated": 0.53, - "Boiling point": "20.28 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -1, - 1 - ], - "Critical temperature": "33 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "1s1", - "ICSD oxidation states": [ - 1, - -1 - ], - "Liquid range": "6.27 K", - "Melting point": "14.01 K", - "Mendeleev no": 103, - "Mineral hardness": "no data", - "Molar volume": "11.42 cm3", - "Name": "Hydrogen", - "Oxidation states": [ - -1, - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000132 (gas; liquid 1.12)(no units)", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "1": { - "I": { - "": { - "crystal_radius": -0.24, - "ionic_radius": -0.38 - } - }, - "II": { - "": { - "crystal_radius": -0.04, - "ionic_radius": -0.18 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.1805 W m-1 K-1", - "Van der waals radius": 1.2, - "Velocity of sound": "1270 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.2, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "H-2": 2.86 - } - }, - "He": { - "Atomic mass": 4.002602, - "Atomic no": 2, - "Atomic orbitals": { - "1s": -0.570425 - }, - "Atomic radius": "no data", - "Atomic radius calculated": 0.31, - "Boiling point": "4.22 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Critical temperature": "5.19 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "1s2", - "Liquid range": "3.27 K", - "Max oxidation state": 0.0, - "Melting point": "0.95 K", - "Mendeleev no": 1, - "Min oxidation state": 0.0, - "Mineral hardness": "no data", - "Molar volume": "21.0 cm3", - "Name": "Helium", - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000035 (gas; liquid 1.028)(no units)", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.1513 W m-1 K-1", - "Van der waals radius": 1.4, - "Velocity of sound": "970 m s-1", - "Vickers hardness": "no data MN m-2", - "Youngs modulus": "no data GPa" - }, - "Hf": { - "Atomic mass": 178.49, - "Atomic no": 72, - "Atomic orbitals": { - "1s": -2210.65199, - "2p": -345.687023, - "2s": -361.006527, - "3d": -61.231443, - "3p": -74.452656, - "3s": -81.522812, - "4d": -7.676638, - "4f": -0.871574, - "4p": -12.971211, - "4s": -15.883625, - "5d": -0.143805, - "5p": -1.246441, - "5s": -2.049828, - "6s": -0.166465 - }, - "Atomic radius": 1.55, - "Atomic radius calculated": 2.08, - "Boiling point": "4876 K", - "Brinell hardness": "1700 MN m-2", - "Bulk modulus": "110 GPa", - "Coefficient of linear thermal expansion": "5.9 x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "13310 kg m-3", - "Electrical resistivity": "34 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d2.6s2", - "ICSD oxidation states": [ - 4 - ], - "Ionic radii": { - "4": 0.85 - }, - "Liquid range": "2370 K", - "Melting point": "2506 K", - "Mendeleev no": 50, - "Mineral hardness": "5.5", - "Molar volume": "13.44 cm3", - "Name": "Hafnium", - "Oxidation states": [ - 2, - 3, - 4 - ], - "Poissons ratio": "0.37", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "30 GPa", - "Shannon radii": { - "4": { - "IV": { - "": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - }, - "VI": { - "": { - "crystal_radius": 0.85, - "ionic_radius": 0.71 - } - }, - "VII": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - }, - "VIII": { - "": { - "crystal_radius": 0.97, - "ionic_radius": 0.83 - } - } - } - }, - "Superconduction temperature": "0.128 K", - "Thermal conductivity": "23 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "3010 m s-1", - "Vickers hardness": "1760 MN m-2", - "X": 1.3, - "Youngs modulus": "78 GPa" - }, - "Hg": { - "Atomic mass": 200.59, - "Atomic no": 80, - "Atomic orbitals": { - "1s": -2755.022637, - "2p": -443.848676, - "2s": -461.27864, - "3d": -84.845492, - "3p": -100.328031, - "3s": -108.597921, - "4d": -13.019221, - "4f": -4.110291, - "4p": -19.636187, - "4s": -23.222921, - "5d": -0.452552, - "5p": -2.261975, - "5s": -3.423486, - "6s": -0.205137 - }, - "Atomic radius": 1.5, - "Atomic radius calculated": 1.71, - "Boiling point": "629.88 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "25 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 1, - 2 - ], - "Critical temperature": "1750 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "96 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2", - "ICSD oxidation states": [ - 1, - 2 - ], - "Ionic radii": { - "1": 1.33, - "2": 1.16 - }, - "Liquid range": "395.56 K", - "Melting point": "234.32 K", - "Mendeleev no": 74, - "Mineral hardness": "1.5", - "Molar volume": "14.09 cm3", - "Name": "Mercury", - "Oxidation states": [ - 1, - 2, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "73 %", - "Refractive index": "1.000933", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "1": { - "III": { - "": { - "crystal_radius": 1.11, - "ionic_radius": 0.97 - } - }, - "VI": { - "": { - "crystal_radius": 1.33, - "ionic_radius": 1.19 - } - } - }, - "2": { - "II": { - "": { - "crystal_radius": 0.83, - "ionic_radius": 0.69 - } - }, - "IV": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - }, - "VI": { - "": { - "crystal_radius": 1.16, - "ionic_radius": 1.02 - } - }, - "VIII": { - "": { - "crystal_radius": 1.28, - "ionic_radius": 1.14 - } - } - } - }, - "Superconduction temperature": "3.95 K", - "Thermal conductivity": "8.3 W m-1 K-1", - "Van der waals radius": 1.55, - "Velocity of sound": "1407 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.0, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "Hg-201": 387.6 - } - }, - "Ho": { - "Atomic mass": 164.93032, - "Atomic no": 67, - "Atomic orbitals": { - "1s": -1902.051908, - "2p": -291.700994, - "2s": -305.739294, - "3d": -49.565996, - "3p": -61.436304, - "3s": -67.785492, - "4d": -5.906195, - "4f": -0.272677, - "4p": -10.455303, - "4s": -12.985498, - "5p": -0.919463, - "5s": -1.582088, - "6s": -0.133845 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": "no data", - "Boiling point": "2993 K", - "Brinell hardness": "746 MN m-2", - "Bulk modulus": "40 GPa", - "Coefficient of linear thermal expansion": "11.2 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "8795 kg m-3", - "Electrical resistivity": "81.4 10-8 Ω m", - "Electronic structure": "[Xe].4f11.6s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "3": 1.041 - }, - "Liquid range": "1259 K", - "Melting point": "1734 K", - "Mendeleev no": 23, - "Mineral hardness": "no data", - "Molar volume": "18.74 cm3", - "Name": "Holmium", - "Oxidation states": [ - 3 - ], - "Poissons ratio": "0.23", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "26 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.041, - "ionic_radius": 0.901 - } - }, - "VIII": { - "": { - "crystal_radius": 1.155, - "ionic_radius": 1.015 - } - }, - "IX": { - "": { - "crystal_radius": 1.212, - "ionic_radius": 1.072 - } - }, - "X": { - "": { - "crystal_radius": 1.26, - "ionic_radius": 1.12 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "16 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2760 m s-1", - "Vickers hardness": "481 MN m-2", - "X": 1.23, - "Youngs modulus": "65 GPa" - }, - "I": { - "Atomic mass": 126.90447, - "Atomic no": 53, - "Atomic orbitals": { - "1s": -1161.787047, - "2p": -164.603788, - "2s": -175.073804, - "3d": -22.600693, - "3p": -30.831092, - "3s": -35.243351, - "4d": -1.938179, - "4p": -4.572522, - "4s": -6.115811, - "5p": -0.267904, - "5s": -0.596339 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.15, - "Boiling point": "457.4 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "7.7 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -1, - 1, - 3, - 5, - 7 - ], - "Critical temperature": "819 K", - "Density of solid": "4940 kg m-3", - "Electrical resistivity": "> 101510-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2.5p5", - "ICSD oxidation states": [ - 5, - -1 - ], - "Ionic radii": { - "-1": 2.06, - "5": 1.09, - "7": 0.67 - }, - "Liquid range": "70.55 K", - "Melting point": "386.85 K", - "Mendeleev no": 97, - "Mineral hardness": "no data", - "Molar volume": "25.72 cm3", - "Name": "Iodine", - "Oxidation states": [ - -1, - 1, - 3, - 5, - 7 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-1": { - "VI": { - "": { - "crystal_radius": 2.06, - "ionic_radius": 2.2 - } - } - }, - "5": { - "IIIPY": { - "": { - "crystal_radius": 0.58, - "ionic_radius": 0.44 - } - }, - "VI": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.56, - "ionic_radius": 0.42 - } - }, - "VI": { - "": { - "crystal_radius": 0.67, - "ionic_radius": 0.53 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.449 W m-1 K-1", - "Van der waals radius": 1.98, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.66, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "I-127": -696.12, - "I-129": -604.1 - } - }, - "In": { - "Atomic mass": 114.818, - "Atomic no": 49, - "Atomic orbitals": { - "1s": -983.647445, - "2p": -134.628845, - "2s": -144.078357, - "3d": -16.139823, - "3p": -23.345778, - "3s": -27.2206, - "4d": -0.730481, - "4p": -2.795832, - "4s": -4.062639, - "5p": -0.101782, - "5s": -0.290497 - }, - "Atomic radius": 1.55, - "Atomic radius calculated": 1.56, - "Boiling point": "2345 K", - "Brinell hardness": "8.83 MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "32.1 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "7310 kg m-3", - "Electrical resistivity": "8 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2.5p1", - "ICSD oxidation states": [ - 1, - 2, - 3 - ], - "Ionic radii": { - "3": 0.94 - }, - "Liquid range": "1915.25 K", - "Melting point": "429.75 K", - "Mendeleev no": 79, - "Mineral hardness": "1.2", - "Molar volume": "15.76 cm3", - "Name": "Indium", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "IV": { - "": { - "crystal_radius": 0.76, - "ionic_radius": 0.62 - } - }, - "VI": { - "": { - "crystal_radius": 0.94, - "ionic_radius": 0.8 - } - }, - "VIII": { - "": { - "crystal_radius": 1.06, - "ionic_radius": 0.92 - } - } - } - }, - "Superconduction temperature": "3.41 K", - "Thermal conductivity": "82 W m-1 K-1", - "Van der waals radius": 1.93, - "Velocity of sound": "1215 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.78, - "Youngs modulus": "11 GPa", - "NMR Quadrupole Moment": { - "In-113": 759.8, - "In-115": 770.8 - } - }, - "Ir": { - "Atomic mass": 192.217, - "Atomic no": 77, - "Atomic orbitals": { - "1s": -2543.761342, - "2p": -405.526834, - "2s": -422.159424, - "3d": -75.485027, - "3p": -90.108427, - "3s": -97.923081, - "4d": -10.856593, - "4f": -2.738339, - "4p": -16.966578, - "4s": -20.29429, - "5d": -0.335189, - "5p": -1.883349, - "5s": -2.909174, - "6s": -0.195511 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.8, - "Boiling point": "4701 K", - "Brinell hardness": "1670 MN m-2", - "Bulk modulus": "320 GPa", - "Coefficient of linear thermal expansion": "6.4 x10-6K-1", - "Common oxidation states": [ - 3, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "22650 kg m-3", - "Electrical resistivity": "4.7 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d7.6s2", - "ICSD oxidation states": [ - 3, - 4, - 5 - ], - "Ionic radii": { - "3": 0.82, - "4": 0.765, - "5": 0.71 - }, - "Liquid range": "1962 K", - "Melting point": "2739 K", - "Mendeleev no": 66, - "Mineral hardness": "6.5", - "Molar volume": "8.52 cm3", - "Name": "Iridium", - "Oxidation states": [ - -3, - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.26", - "Reflectivity": "78 %", - "Refractive index": "no data", - "Rigidity modulus": "210 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.82, - "ionic_radius": 0.68 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.765, - "ionic_radius": 0.625 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - } - } - }, - "Superconduction temperature": "0.11 K", - "Thermal conductivity": "150 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4825 m s-1", - "Vickers hardness": "1760 MN m-2", - "X": 2.2, - "Youngs modulus": "528 GPa" - }, - "K": { - "Atomic mass": 39.0983, - "Atomic no": 19, - "Atomic orbitals": { - "1s": -128.414957, - "2p": -10.283851, - "2s": -12.839001, - "3p": -0.693776, - "3s": -1.281897, - "4s": -0.088815 - }, - "Atomic radius": 2.2, - "Atomic radius calculated": 2.43, - "Boiling point": "1032 K", - "Brinell hardness": "0.363 MN m-2", - "Bulk modulus": "3.1 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "2223 K", - "Density of solid": "856 kg m-3", - "Electrical resistivity": "7.5 10-8 Ω m", - "Electronic structure": "[Ar].4s1", - "ICSD oxidation states": [ - 1 - ], - "Ionic radii": { - "1": 1.52 - }, - "Liquid range": "695.47 K", - "Melting point": "336.53 K", - "Mendeleev no": 10, - "Mineral hardness": "0.4", - "Molar volume": "45.94 cm3", - "Name": "Potassium", - "Oxidation states": [ - -1, - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "1.3 GPa", - "Shannon radii": { - "1": { - "IV": { - "": { - "crystal_radius": 1.51, - "ionic_radius": 1.37 - } - }, - "VI": { - "": { - "crystal_radius": 1.52, - "ionic_radius": 1.38 - } - }, - "VII": { - "": { - "crystal_radius": 1.6, - "ionic_radius": 1.46 - } - }, - "VIII": { - "": { - "crystal_radius": 1.65, - "ionic_radius": 1.51 - } - }, - "IX": { - "": { - "crystal_radius": 1.69, - "ionic_radius": 1.55 - } - }, - "X": { - "": { - "crystal_radius": 1.73, - "ionic_radius": 1.59 - } - }, - "XII": { - "": { - "crystal_radius": 1.78, - "ionic_radius": 1.64 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "100 W m-1 K-1", - "Van der waals radius": 2.75, - "Velocity of sound": "2000 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.82, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "K-39": 58.5, - "K-40": -73.0, - "K-41": 71.1 - } - }, - "Kr": { - "Atomic mass": 83.798, - "Atomic no": 36, - "Atomic orbitals": { - "1s": -509.982989, - "2p": -60.017328, - "2s": -66.285953, - "3d": -3.074109, - "3p": -7.086634, - "3s": -9.315192, - "4p": -0.34634, - "4s": -0.820574 - }, - "Atomic radius": "no data", - "Atomic radius calculated": 0.88, - "Boiling point": "119.93 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Critical temperature": "209.4 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2.4p6", - "Liquid range": "4.14 K", - "Max oxidation state": 0.0, - "Melting point": "115.79 K", - "Mendeleev no": 4, - "Min oxidation state": 0.0, - "Mineral hardness": "no data", - "Molar volume": "27.99 cm3", - "Name": "Krypton", - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000427", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.00943 W m-1 K-1", - "Van der waals radius": 2.02, - "Velocity of sound": "1120 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 3.0, - "Youngs modulus": "no data GPa" - }, - "La": { - "Atomic mass": 138.90547, - "Atomic no": 57, - "Atomic orbitals": { - "1s": -1355.622446, - "2p": -198.325243, - "2s": -209.831151, - "3d": -30.626696, - "3p": -39.895838, - "3s": -44.856283, - "4d": -3.95801, - "4p": -7.167724, - "4s": -9.000543, - "5d": -0.141085, - "5p": -0.824498, - "5s": -1.324936, - "6s": -0.132233 - }, - "Atomic radius": 1.95, - "Atomic radius calculated": "no data", - "Boiling point": "3743 K", - "Brinell hardness": "363 MN m-2", - "Bulk modulus": "28 GPa", - "Coefficient of linear thermal expansion": "12.1 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "6146 kg m-3", - "Electrical resistivity": "61.5 10-8 Ω m", - "Electronic structure": "[Xe].5d1.6s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "3": 1.172 - }, - "Liquid range": "2550 K", - "Melting point": "1193 K", - "Mendeleev no": 33, - "Mineral hardness": "2.5", - "Molar volume": "22.39 cm3", - "Name": "Lanthanum", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.28", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "14 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.172, - "ionic_radius": 1.032 - } - }, - "VII": { - "": { - "crystal_radius": 1.24, - "ionic_radius": 1.1 - } - }, - "VIII": { - "": { - "crystal_radius": 1.3, - "ionic_radius": 1.16 - } - }, - "IX": { - "": { - "crystal_radius": 1.356, - "ionic_radius": 1.216 - } - }, - "X": { - "": { - "crystal_radius": 1.41, - "ionic_radius": 1.27 - } - }, - "XII": { - "": { - "crystal_radius": 1.5, - "ionic_radius": 1.36 - } - } - } - }, - "Superconduction temperature": "6.00 K", - "Thermal conductivity": "13 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2475 m s-1", - "Vickers hardness": "491 MN m-2", - "X": 1.1, - "Youngs modulus": "37 GPa", - "NMR Quadrupole Moment": { - "La-139": 200.6 - } - }, - "Li": { - "Atomic mass": 6.941, - "Atomic no": 3, - "Atomic orbitals": { - "1s": -1.878564, - "2s": -0.10554 - }, - "Atomic radius": 1.45, - "Atomic radius calculated": 1.67, - "Boiling point": "1615 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "11 GPa", - "Coefficient of linear thermal expansion": "46 x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "3223 K", - "Density of solid": "535 kg m-3", - "Electrical resistivity": "9.5 10-8 Ω m", - "Electronic structure": "[He].2s1", - "ICSD oxidation states": [ - 1 - ], - "Ionic radii": { - "1": 0.9 - }, - "Liquid range": "1161.31 K", - "Melting point": "453.69 K", - "Mendeleev no": 12, - "Mineral hardness": "0.6", - "Molar volume": "13.02 cm3", - "Name": "Lithium", - "Oxidation states": [ - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "4.2 GPa", - "Shannon radii": { - "1": { - "IV": { - "": { - "crystal_radius": 0.73, - "ionic_radius": 0.59 - } - }, - "VI": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - }, - "VIII": { - "": { - "crystal_radius": 1.06, - "ionic_radius": 0.92 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "85 W m-1 K-1", - "Van der waals radius": 1.82, - "Velocity of sound": "6000 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.98, - "Youngs modulus": "4.9 GPa", - "NMR Quadrupole Moment": { - "Li-6": -0.808, - "Li-7": -40.1 - } - }, - "Lr": { - "Atomic mass": 262.0, - "Atomic no": 103, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f14.7s2.7p1 (tentative)", - "Liquid range": "no data K", - "Melting point": "about 1900 K", - "Mendeleev no": 34, - "Mineral hardness": "no data", - "Molar volume": "no data cm3", - "Name": "Lawrencium", - "Oxidation states": [ - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Lu": { - "Atomic mass": 174.967, - "Atomic no": 71, - "Atomic orbitals": { - "1s": -2146.885351, - "2p": -334.330902, - "2s": -349.390492, - "3d": -58.592982, - "3p": -71.538779, - "3s": -78.462398, - "4d": -7.113364, - "4f": -0.568096, - "4p": -12.250904, - "4s": -15.08337, - "5d": -0.103686, - "5p": -1.111991, - "5s": -1.872086, - "6s": -0.155112 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": 2.17, - "Boiling point": "3675 K", - "Brinell hardness": "893 MN m-2", - "Bulk modulus": "48 GPa", - "Coefficient of linear thermal expansion": "9.9 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "9841 kg m-3", - "Electrical resistivity": "58 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d1.6s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "3": 1.001 - }, - "Liquid range": "1750 K", - "Melting point": "1925 K", - "Mendeleev no": 20, - "Mineral hardness": "no data", - "Molar volume": "17.78 cm3", - "Name": "Lutetium", - "Oxidation states": [ - 3 - ], - "Poissons ratio": "0.26", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "27 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.001, - "ionic_radius": 0.861 - } - }, - "VIII": { - "": { - "crystal_radius": 1.117, - "ionic_radius": 0.977 - } - }, - "IX": { - "": { - "crystal_radius": 1.172, - "ionic_radius": 1.032 - } - } - } - }, - "Superconduction temperature": "0.022 K", - "Thermal conductivity": "16 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "1160 MN m-2", - "X": 1.27, - "Youngs modulus": "69 GPa" - }, - "Md": { - "Atomic mass": 258.0, - "Atomic no": 101, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f13.7s2", - "Liquid range": "no data K", - "Melting point": "about 1100 K", - "Mendeleev no": 36, - "Mineral hardness": "no data", - "Molar volume": "no data cm3", - "Name": "Mendelevium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Mg": { - "Atomic mass": 24.305, - "Atomic no": 12, - "Atomic orbitals": { - "1s": -45.973167, - "2p": -1.71897, - "2s": -2.903746, - "3s": -0.175427 - }, - "Atomic radius": 1.5, - "Atomic radius calculated": 1.45, - "Boiling point": "1363 K", - "Brinell hardness": "260 MN m-2", - "Bulk modulus": "45 GPa", - "Coefficient of linear thermal expansion": "8.2 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "1738 kg m-3", - "Electrical resistivity": "4.4 10-8 Ω m", - "Electronic structure": "[Ne].3s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 0.86 - }, - "Liquid range": "440 K", - "Melting point": "923 K", - "Mendeleev no": 73, - "Mineral hardness": "2.5", - "Molar volume": "14.00 cm3", - "Name": "Magnesium", - "Oxidation states": [ - 1, - 2 - ], - "Poissons ratio": "0.29", - "Reflectivity": "74 %", - "Refractive index": "no data", - "Rigidity modulus": "17 GPa", - "Shannon radii": { - "2": { - "IV": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - }, - "V": { - "": { - "crystal_radius": 0.8, - "ionic_radius": 0.66 - } - }, - "VI": { - "": { - "crystal_radius": 0.86, - "ionic_radius": 0.72 - } - }, - "VIII": { - "": { - "crystal_radius": 1.03, - "ionic_radius": 0.89 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "160 W m-1 K-1", - "Van der waals radius": 1.73, - "Velocity of sound": "4602 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.31, - "Youngs modulus": "45 GPa", - "NMR Quadrupole Moment": { - "Mg-25": 199.4 - } - }, - "Mn": { - "Atomic mass": 54.938045, - "Atomic no": 25, - "Atomic orbitals": { - "1s": -233.696912, - "2p": -23.066297, - "2s": -26.866646, - "3d": -0.26654, - "3p": -1.99145, - "3s": -3.076637, - "4s": -0.191136 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.61, - "Boiling point": "2334 K", - "Brinell hardness": "196 MN m-2", - "Bulk modulus": "120 GPa", - "Coefficient of linear thermal expansion": "21.7 x10-6K-1", - "Common oxidation states": [ - 2, - 4, - 7 - ], - "Critical temperature": "no data K", - "Density of solid": "7470 kg m-3", - "Electrical resistivity": "144 10-8 Ω m", - "Electronic structure": "[Ar].3d5.4s2", - "ICSD oxidation states": [ - 2, - 3, - 4, - 7 - ], - "Ionic radii": { - "2": 0.97, - "3": 0.785, - "4": 0.67, - "5": 0.47, - "6": 0.395, - "7": 0.6 - }, - "Ionic radii hs": { - "2": 0.97, - "3": 0.785 - }, - "Ionic radii ls": { - "2": 0.81, - "3": 0.72, - "4": 0.67, - "5": 0.47, - "6": 0.395, - "7": 0.6 - }, - "Liquid range": "815 K", - "Melting point": "1519 K", - "Mendeleev no": 60, - "Mineral hardness": "6.0", - "Molar volume": "7.35 cm3", - "Name": "Manganese", - "Oxidation states": [ - -3, - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6, - 7 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "2": { - "IV": { - "High Spin": { - "crystal_radius": 0.8, - "ionic_radius": 0.66 - } - }, - "V": { - "High Spin": { - "crystal_radius": 0.89, - "ionic_radius": 0.75 - } - }, - "VI": { - "Low Spin": { - "crystal_radius": 0.81, - "ionic_radius": 0.67 - }, - "High Spin": { - "crystal_radius": 0.97, - "ionic_radius": 0.83 - } - }, - "VII": { - "High Spin": { - "crystal_radius": 1.04, - "ionic_radius": 0.9 - } - }, - "VIII": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - } - }, - "3": { - "V": { - "": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - }, - "VI": { - "Low Spin": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - }, - "High Spin": { - "crystal_radius": 0.785, - "ionic_radius": 0.645 - } - } - }, - "4": { - "IV": { - "": { - "crystal_radius": 0.53, - "ionic_radius": 0.39 - } - }, - "VI": { - "": { - "crystal_radius": 0.67, - "ionic_radius": 0.53 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.47, - "ionic_radius": 0.33 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.395, - "ionic_radius": 0.255 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.39, - "ionic_radius": 0.25 - } - }, - "VI": { - "": { - "crystal_radius": 0.6, - "ionic_radius": 0.46 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "7.8 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "5150 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.55, - "Youngs modulus": "198 GPa", - "NMR Quadrupole Moment": { - "Mn-55": 330.1 - } - }, - "Mo": { - "Atomic mass": 95.94, - "Atomic no": 42, - "Atomic orbitals": { - "1s": -709.232119, - "2p": -90.791541, - "2s": -98.503638, - "3d": -8.257721, - "3p": -13.71481, - "3s": -16.681545, - "4d": -0.153347, - "4p": -1.39005, - "4s": -2.234824, - "5s": -0.14788 - }, - "Atomic radius": 1.45, - "Atomic radius calculated": 1.9, - "Boiling point": "4912 K", - "Brinell hardness": "1500 MN m-2", - "Bulk modulus": "230 GPa", - "Coefficient of linear thermal expansion": "4.8 x10-6K-1", - "Common oxidation states": [ - 4, - 6 - ], - "Critical temperature": "no data K", - "Density of solid": "10280 kg m-3", - "Electrical resistivity": "5.5 10-8 Ω m", - "Electronic structure": "[Kr].4d5.5s1", - "ICSD oxidation states": [ - 2, - 3, - 4, - 5, - 6 - ], - "Ionic radii": { - "3": 0.83, - "4": 0.79, - "5": 0.75, - "6": 0.73 - }, - "Liquid range": "2016 K", - "Melting point": "2896 K", - "Mendeleev no": 56, - "Mineral hardness": "5.5", - "Molar volume": "9.38 cm3", - "Name": "Molybdenum", - "Oxidation states": [ - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.31", - "Reflectivity": "58 %", - "Refractive index": "no data", - "Rigidity modulus": "20 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.83, - "ionic_radius": 0.69 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.79, - "ionic_radius": 0.65 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.6, - "ionic_radius": 0.46 - } - }, - "VI": { - "": { - "crystal_radius": 0.75, - "ionic_radius": 0.61 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.55, - "ionic_radius": 0.41 - } - }, - "V": { - "": { - "crystal_radius": 0.64, - "ionic_radius": 0.5 - } - }, - "VI": { - "": { - "crystal_radius": 0.73, - "ionic_radius": 0.59 - } - }, - "VII": { - "": { - "crystal_radius": 0.87, - "ionic_radius": 0.73 - } - } - } - }, - "Superconduction temperature": "0.915 K", - "Thermal conductivity": "139 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "6190 m s-1", - "Vickers hardness": "1530 MN m-2", - "X": 2.16, - "Youngs modulus": "329 GPa" - }, - "N": { - "Atomic mass": 14.0067, - "Atomic no": 7, - "Atomic orbitals": { - "1s": -14.011501, - "2p": -0.266297, - "2s": -0.676151 - }, - "Atomic radius": 0.65, - "Atomic radius calculated": 0.56, - "Boiling point": "77.36 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -3, - 3, - 5 - ], - "Critical temperature": "126.2 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[He].2s2.2p3", - "ICSD oxidation states": [ - 1, - 3, - 5, - -1, - -3, - -2 - ], - "Ionic radii": { - "-3": 1.32, - "3": 0.3, - "5": 0.27 - }, - "Liquid range": "14.31 K", - "Melting point": "63.05 K", - "Mendeleev no": 100, - "Mineral hardness": "no data", - "Molar volume": "13.54 cm3", - "Name": "Nitrogen", - "Oxidation states": [ - -3, - -2, - -1, - 1, - 2, - 3, - 4, - 5 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000298 (gas; liquid 1.197)(no units)", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-3": { - "IV": { - "": { - "crystal_radius": 1.32, - "ionic_radius": 1.46 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 0.3, - "ionic_radius": 0.16 - } - } - }, - "5": { - "III": { - "": { - "crystal_radius": 0.044, - "ionic_radius": -0.104 - } - }, - "VI": { - "": { - "crystal_radius": 0.27, - "ionic_radius": 0.13 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.02583 W m-1 K-1", - "Van der waals radius": 1.55, - "Velocity of sound": "333.6 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 3.04, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "N-14": 20.44 - } - }, - "Na": { - "Atomic mass": 22.98976928, - "Atomic no": 11, - "Atomic orbitals": { - "1s": -37.719975, - "2p": -1.060636, - "2s": -2.063401, - "3s": -0.103415 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": 1.9, - "Boiling point": "1156 K", - "Brinell hardness": "0.69 MN m-2", - "Bulk modulus": "6.3 GPa", - "Coefficient of linear thermal expansion": "71 x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "2573 K", - "Density of solid": "968 kg m-3", - "Electrical resistivity": "4.9 10-8 Ω m", - "Electronic structure": "[Ne].3s1", - "ICSD oxidation states": [ - 1 - ], - "Ionic radii": { - "1": 1.16 - }, - "Liquid range": "785.13 K", - "Melting point": "370.87 K", - "Mendeleev no": 11, - "Mineral hardness": "0.5", - "Molar volume": "23.78 cm3", - "Name": "Sodium", - "Oxidation states": [ - -1, - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "3.3 GPa", - "Shannon radii": { - "1": { - "IV": { - "": { - "crystal_radius": 1.13, - "ionic_radius": 0.99 - } - }, - "V": { - "": { - "crystal_radius": 1.14, - "ionic_radius": 1.0 - } - }, - "VI": { - "": { - "crystal_radius": 1.16, - "ionic_radius": 1.02 - } - }, - "VII": { - "": { - "crystal_radius": 1.26, - "ionic_radius": 1.12 - } - }, - "VIII": { - "": { - "crystal_radius": 1.32, - "ionic_radius": 1.18 - } - }, - "IX": { - "": { - "crystal_radius": 1.38, - "ionic_radius": 1.24 - } - }, - "XII": { - "": { - "crystal_radius": 1.53, - "ionic_radius": 1.39 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "140 W m-1 K-1", - "Van der waals radius": 2.27, - "Velocity of sound": "3200 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.93, - "Youngs modulus": "10 GPa", - "NMR Quadrupole Moment": { - "Na-23": 104.1 - } - }, - "Nb": { - "Atomic mass": 92.90638, - "Atomic no": 41, - "Atomic orbitals": { - "1s": -673.76253, - "2p": -85.272175, - "2s": -92.74086, - "3d": -7.339839, - "3p": -12.552855, - "3s": -15.393727, - "4d": -0.125252, - "4p": -1.250049, - "4s": -2.036693, - "5s": -0.144272 - }, - "Atomic radius": 1.45, - "Atomic radius calculated": 1.98, - "Boiling point": "5017 K", - "Brinell hardness": "736 MN m-2", - "Bulk modulus": "170 GPa", - "Coefficient of linear thermal expansion": "7.3 x10-6K-1", - "Common oxidation states": [ - 5 - ], - "Critical temperature": "no data K", - "Density of solid": "8570 kg m-3", - "Electrical resistivity": "15.2 10-8 Ω m", - "Electronic structure": "[Kr].4d4.5s1", - "ICSD oxidation states": [ - 2, - 3, - 4, - 5 - ], - "Ionic radii": { - "3": 0.86, - "4": 0.82, - "5": 0.78 - }, - "Liquid range": "2267 K", - "Melting point": "2750 K", - "Mendeleev no": 53, - "Mineral hardness": "6.0", - "Molar volume": "10.83 cm3", - "Name": "Niobium", - "Oxidation states": [ - -1, - 2, - 3, - 4, - 5 - ], - "Poissons ratio": "0.40", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "38 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.86, - "ionic_radius": 0.72 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.82, - "ionic_radius": 0.68 - } - }, - "VIII": { - "": { - "crystal_radius": 0.93, - "ionic_radius": 0.79 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.62, - "ionic_radius": 0.48 - } - }, - "VI": { - "": { - "crystal_radius": 0.78, - "ionic_radius": 0.64 - } - }, - "VII": { - "": { - "crystal_radius": 0.83, - "ionic_radius": 0.69 - } - }, - "VIII": { - "": { - "crystal_radius": 0.88, - "ionic_radius": 0.74 - } - } - } - }, - "Superconduction temperature": "9.25 K", - "Thermal conductivity": "54 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "3480 m s-1", - "Vickers hardness": "1320 MN m-2", - "X": 1.6, - "Youngs modulus": "105 GPa" - }, - "Nd": { - "Atomic mass": 144.242, - "Atomic no": 60, - "Atomic orbitals": { - "1s": -1509.698955, - "2p": -224.351816, - "2s": -236.613572, - "3d": -35.754515, - "3p": -45.791219, - "3s": -51.161263, - "4d": -4.377027, - "4f": -0.179508, - "4p": -7.96782, - "4s": -10.000891, - "5p": -0.798503, - "5s": -1.334934, - "6s": -0.125796 - }, - "Atomic radius": 1.85, - "Atomic radius calculated": 2.06, - "Boiling point": "3373 K", - "Brinell hardness": "265 MN m-2", - "Bulk modulus": "32 GPa", - "Coefficient of linear thermal expansion": "9.6 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "6800 kg m-3", - "Electrical resistivity": "64.3 10-8 Ω m", - "Electronic structure": "[Xe].4f4.6s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "2": 1.43, - "3": 1.123 - }, - "Liquid range": "2076 K", - "Melting point": "1297 K", - "Mendeleev no": 30, - "Mineral hardness": "no data", - "Molar volume": "20.59 cm3", - "Name": "Neodymium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.28", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "16 GPa", - "Shannon radii": { - "2": { - "VIII": { - "": { - "crystal_radius": 1.43, - "ionic_radius": 1.29 - } - }, - "IX": { - "": { - "crystal_radius": 1.49, - "ionic_radius": 1.35 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.123, - "ionic_radius": 0.983 - } - }, - "VIII": { - "": { - "crystal_radius": 1.249, - "ionic_radius": 1.109 - } - }, - "IX": { - "": { - "crystal_radius": 1.303, - "ionic_radius": 1.163 - } - }, - "XII": { - "": { - "crystal_radius": 1.41, - "ionic_radius": 1.27 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "17 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2330 m s-1", - "Vickers hardness": "343 MN m-2", - "X": 1.14, - "Youngs modulus": "41 GPa" - }, - "Ne": { - "Atomic mass": 20.1797, - "Atomic no": 10, - "Atomic orbitals": { - "1s": -30.305855, - "2p": -0.498034, - "2s": -1.322809 - }, - "Atomic radius": "no data", - "Atomic radius calculated": 0.38, - "Boiling point": "27.07 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Critical temperature": "44.4 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[He].2s2.2p6", - "Liquid range": "2.51 K", - "Max oxidation state": 0.0, - "Melting point": "24.56 K", - "Mendeleev no": 2, - "Min oxidation state": 0.0, - "Mineral hardness": "no data", - "Molar volume": "13.23 cm3", - "Name": "Neon", - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000067", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.0491 W m-1 K-1", - "Van der waals radius": 1.54, - "Velocity of sound": "936 m s-1", - "Vickers hardness": "no data MN m-2", - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "Ne-21": 101.55 - } - }, - "Ni": { - "Atomic mass": 58.6934, - "Atomic no": 28, - "Atomic orbitals": { - "1s": -297.870824, - "2p": -30.868027, - "2s": -35.312112, - "3d": -0.348699, - "3p": -2.594158, - "3s": -3.950717, - "4s": -0.210764 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.49, - "Boiling point": "3186 K", - "Brinell hardness": "700 MN m-2", - "Bulk modulus": "180 GPa", - "Coefficient of linear thermal expansion": "13.4 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "8908 kg m-3", - "Electrical resistivity": "7.2 10-8 Ω m", - "Electronic structure": "[Ar].3d8.4s2", - "ICSD oxidation states": [ - 1, - 2, - 3, - 4 - ], - "Ionic radii": { - "3": 0.74 - }, - "Ionic radii hs": { - "3": 0.74 - }, - "Ionic radii ls": { - "2": 0.83, - "3": 0.7, - "4": 0.62 - }, - "Liquid range": "1458 K", - "Melting point": "1728 K", - "Mendeleev no": 67, - "Mineral hardness": "4.0", - "Molar volume": "6.59 cm3", - "Name": "Nickel", - "Oxidation states": [ - -1, - 1, - 2, - 3, - 4 - ], - "Poissons ratio": "0.31", - "Reflectivity": "72 %", - "Refractive index": "no data", - "Rigidity modulus": "76 GPa", - "Shannon radii": { - "2": { - "IV": { - "": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - } - }, - "IVSQ": { - "": { - "crystal_radius": 0.63, - "ionic_radius": 0.49 - } - }, - "V": { - "": { - "crystal_radius": 0.77, - "ionic_radius": 0.63 - } - }, - "VI": { - "": { - "crystal_radius": 0.83, - "ionic_radius": 0.69 - } - } - }, - "3": { - "VI": { - "Low Spin": { - "crystal_radius": 0.7, - "ionic_radius": 0.56 - }, - "High Spin": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - } - }, - "4": { - "VI": { - "Low Spin": { - "crystal_radius": 0.62, - "ionic_radius": 0.48 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "91 W m-1 K-1", - "Van der waals radius": 1.63, - "Velocity of sound": "4970 m s-1", - "Vickers hardness": "638 MN m-2", - "X": 1.91, - "Youngs modulus": "200 GPa", - "NMR Quadrupole Moment": { - "Ni-61": 162.15 - } - }, - "No": { - "Atomic mass": 259.0, - "Atomic no": 102, - "Atomic orbitals": "no data", - "Atomic radius": "no data", - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Rn].5f14.7s2", - "Liquid range": "no data K", - "Melting point": "about 1100 K", - "Mendeleev no": 35, - "Mineral hardness": "no data", - "Molar volume": "no data cm3", - "Name": "Nobelium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.24, - "ionic_radius": 1.1 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "no data W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.3, - "Youngs modulus": "no data GPa" - }, - "Np": { - "Atomic mass": 237.0, - "Atomic no": 93, - "Atomic orbitals": "no data", - "Atomic radius": 1.75, - "Atomic radius calculated": "no data", - "Boiling point": "4273 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 5 - ], - "Critical temperature": "no data K", - "Density of solid": "20450 kg m-3", - "Electrical resistivity": "120 10-8 Ω m", - "Electronic structure": "[Rn].5f4.6d1.7s2", - "Ionic radii": { - "2": 1.24, - "3": 1.15, - "4": 1.01, - "5": 0.89, - "6": 0.86, - "7": 0.85 - }, - "Liquid range": "3363 K", - "Melting point": "910 K", - "Mendeleev no": 44, - "Mineral hardness": "no data", - "Molar volume": "11.59 cm3", - "Name": "Neptunium", - "Oxidation states": [ - 3, - 4, - 5, - 6, - 7 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.24, - "ionic_radius": 1.1 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.15, - "ionic_radius": 1.01 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 1.01, - "ionic_radius": 0.87 - } - }, - "VIII": { - "": { - "crystal_radius": 1.12, - "ionic_radius": 0.98 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.89, - "ionic_radius": 0.75 - } - } - }, - "6": { - "VI": { - "": { - "crystal_radius": 0.86, - "ionic_radius": 0.72 - } - } - }, - "7": { - "VI": { - "": { - "crystal_radius": 0.85, - "ionic_radius": 0.71 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "6 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.36, - "Youngs modulus": "no data GPa" - }, - "O": { - "Atomic mass": 15.9994, - "Atomic no": 8, - "Atomic orbitals": { - "1s": -18.758245, - "2p": -0.338381, - "2s": -0.871362 - }, - "Atomic radius": 0.6, - "Atomic radius calculated": 0.48, - "Boiling point": "90.2 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -2 - ], - "Critical temperature": "154.6 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[He].2s2.2p4", - "ICSD oxidation states": [ - -2 - ], - "Ionic radii": { - "-2": 1.26 - }, - "Liquid range": "35.4 K", - "Melting point": "54.8 K", - "Mendeleev no": 101, - "Mineral hardness": "no data", - "Molar volume": "17.36 cm3", - "Name": "Oxygen", - "Oxidation states": [ - -2, - -1, - 1, - 2 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000271 (gas; liquid 1.221)(no units)", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-2": { - "II": { - "": { - "crystal_radius": 1.21, - "ionic_radius": 1.35 - } - }, - "III": { - "": { - "crystal_radius": 1.22, - "ionic_radius": 1.36 - } - }, - "IV": { - "": { - "crystal_radius": 1.24, - "ionic_radius": 1.38 - } - }, - "VI": { - "": { - "crystal_radius": 1.26, - "ionic_radius": 1.4 - } - }, - "VIII": { - "": { - "crystal_radius": 1.28, - "ionic_radius": 1.42 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.02658 W m-1 K-1", - "Van der waals radius": 1.52, - "Velocity of sound": "317.5 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 3.44, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "O-17": -25.58 - } - }, - "Os": { - "Atomic mass": 190.23, - "Atomic no": 76, - "Atomic orbitals": { - "1s": -2475.238617, - "2p": -393.15408, - "2s": -409.522396, - "3d": -72.497183, - "3p": -86.837047, - "3s": -94.501324, - "4d": -10.176082, - "4f": -2.321175, - "4p": -16.119671, - "4s": -19.362527, - "5d": -0.296791, - "5p": -1.757404, - "5s": -2.738293, - "6s": -0.191489 - }, - "Atomic radius": 1.3, - "Atomic radius calculated": 1.85, - "Boiling point": "5285 K", - "Brinell hardness": "3920 MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "5.1 x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "22610 kg m-3", - "Electrical resistivity": "8.1 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d6.6s2", - "Ionic radii": { - "4": 0.77, - "5": 0.715, - "6": 0.685, - "7": 0.665, - "8": 0.53 - }, - "Liquid range": "1979 K", - "Melting point": "3306 K", - "Mendeleev no": 63, - "Mineral hardness": "7.0", - "Molar volume": "8.42 cm3", - "Name": "Osmium", - "Oxidation states": [ - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8 - ], - "Poissons ratio": "0.25", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "222 GPa", - "Shannon radii": { - "4": { - "VI": { - "": { - "crystal_radius": 0.77, - "ionic_radius": 0.63 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.715, - "ionic_radius": 0.575 - } - } - }, - "6": { - "V": { - "": { - "crystal_radius": 0.63, - "ionic_radius": 0.49 - } - }, - "VI": { - "": { - "crystal_radius": 0.685, - "ionic_radius": 0.545 - } - } - }, - "7": { - "VI": { - "": { - "crystal_radius": 0.665, - "ionic_radius": 0.525 - } - } - }, - "8": { - "IV": { - "": { - "crystal_radius": 0.53, - "ionic_radius": 0.39 - } - } - } - }, - "Superconduction temperature": "0.66 K", - "Thermal conductivity": "88 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4940 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.2, - "Youngs modulus": "no data GPa" - }, - "P": { - "Atomic mass": 30.973762, - "Atomic no": 15, - "Atomic orbitals": { - "1s": -76.061897, - "2p": -4.576617, - "2s": -6.329346, - "3p": -0.20608, - "3s": -0.512364 - }, - "Atomic radius": 1.0, - "Atomic radius calculated": 0.98, - "Boiling point": "550 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "11 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -3, - 3, - 5 - ], - "Critical temperature": "994 K", - "Density of solid": "1823 kg m-3", - "Electrical resistivity": "about 10 10-8 Ω m", - "Electronic structure": "[Ne].3s2.3p3", - "ICSD oxidation states": [ - 3, - 4, - 5, - -2, - -3, - -1 - ], - "Ionic radii": { - "3": 0.58, - "5": 0.52 - }, - "Liquid range": "232.7 K", - "Melting point": "(white P) 317.3 K", - "Mendeleev no": 90, - "Mineral hardness": "no data", - "Molar volume": "17.02 cm3", - "Name": "Phosphorus", - "Oxidation states": [ - -3, - -2, - -1, - 1, - 2, - 3, - 4, - 5 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.001212", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.58, - "ionic_radius": 0.44 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.31, - "ionic_radius": 0.17 - } - }, - "V": { - "": { - "crystal_radius": 0.43, - "ionic_radius": 0.29 - } - }, - "VI": { - "": { - "crystal_radius": 0.52, - "ionic_radius": 0.38 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.236 W m-1 K-1", - "Van der waals radius": 1.8, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.19, - "Youngs modulus": "no data GPa" - }, - "Pa": { - "Atomic mass": 231.03588, - "Atomic no": 91, - "Atomic orbitals": { - "1s": -3606.333629, - "2p": -603.470278, - "2s": -623.870431, - "3d": -127.781168, - "3p": -146.485678, - "3s": -156.466742, - "4d": -25.933121, - "4f": -14.105747, - "4p": -34.48293, - "4s": -39.064507, - "5d": -3.659928, - "5f": -0.316813, - "5p": -6.709821, - "5s": -8.463463, - "6d": -0.142481, - "6p": -0.799756, - "6s": -1.287232, - "7s": -0.129653 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": "no data", - "Boiling point": "no data K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 5 - ], - "Critical temperature": "no data K", - "Density of solid": "15370 kg m-3", - "Electrical resistivity": "18 10-8 Ω m", - "Electronic structure": "[Rn].5f2.6d1.7s2", - "Ionic radii": { - "3": 1.16, - "4": 1.04, - "5": 0.92 - }, - "Liquid range": "no data K", - "Melting point": "1841 K", - "Mendeleev no": 46, - "Mineral hardness": "no data", - "Molar volume": "15.18 cm3", - "Name": "Protactinium", - "Oxidation states": [ - 3, - 4, - 5 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.18, - "ionic_radius": 1.04 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 1.04, - "ionic_radius": 0.9 - } - }, - "VIII": { - "": { - "crystal_radius": 1.15, - "ionic_radius": 1.01 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.92, - "ionic_radius": 0.78 - } - }, - "VIII": { - "": { - "crystal_radius": 1.05, - "ionic_radius": 0.91 - } - }, - "IX": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - } - } - }, - "Superconduction temperature": "1.4 K", - "Thermal conductivity": "47 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.5, - "Youngs modulus": "no data GPa" - }, - "Pb": { - "Atomic mass": 207.2, - "Atomic no": 82, - "Atomic orbitals": { - "1s": -2901.078061, - "2p": -470.877785, - "2s": -488.843335, - "3d": -91.889924, - "3p": -107.950391, - "3s": -116.526852, - "4d": -15.030026, - "4f": -5.592532, - "4p": -21.990564, - "4s": -25.75333, - "5d": -0.902393, - "5p": -2.941657, - "5s": -4.206797, - "6p": -0.141831, - "6s": -0.357187 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": 1.54, - "Boiling point": "2022 K", - "Brinell hardness": "38.3 MN m-2", - "Bulk modulus": "46 GPa", - "Coefficient of linear thermal expansion": "28.9 x10-6K-1", - "Common oxidation states": [ - 2, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "11340 kg m-3", - "Electrical resistivity": "21 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2.6p2", - "ICSD oxidation states": [ - 2, - 4 - ], - "Ionic radii": { - "2": 1.33, - "4": 0.915 - }, - "Liquid range": "1421.39 K", - "Melting point": "600.61 K", - "Mendeleev no": 82, - "Mineral hardness": "1.5", - "Molar volume": "18.26 cm3", - "Name": "Lead", - "Oxidation states": [ - -4, - 2, - 4 - ], - "Poissons ratio": "0.44", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "5.6 GPa", - "Shannon radii": { - "2": { - "IVPY": { - "": { - "crystal_radius": 1.12, - "ionic_radius": 0.98 - } - }, - "VI": { - "": { - "crystal_radius": 1.33, - "ionic_radius": 1.19 - } - }, - "VII": { - "": { - "crystal_radius": 1.37, - "ionic_radius": 1.23 - } - }, - "VIII": { - "": { - "crystal_radius": 1.43, - "ionic_radius": 1.29 - } - }, - "IX": { - "": { - "crystal_radius": 1.49, - "ionic_radius": 1.35 - } - }, - "X": { - "": { - "crystal_radius": 1.54, - "ionic_radius": 1.4 - } - }, - "XI": { - "": { - "crystal_radius": 1.59, - "ionic_radius": 1.45 - } - }, - "XII": { - "": { - "crystal_radius": 1.63, - "ionic_radius": 1.49 - } - } - }, - "4": { - "IV": { - "": { - "crystal_radius": 0.79, - "ionic_radius": 0.65 - } - }, - "V": { - "": { - "crystal_radius": 0.87, - "ionic_radius": 0.73 - } - }, - "VI": { - "": { - "crystal_radius": 0.915, - "ionic_radius": 0.775 - } - }, - "VIII": { - "": { - "crystal_radius": 1.08, - "ionic_radius": 0.94 - } - } - } - }, - "Superconduction temperature": "7.2 K", - "Thermal conductivity": "35 W m-1 K-1", - "Van der waals radius": 2.02, - "Velocity of sound": "1260 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.33, - "Youngs modulus": "16 GPa" - }, - "Pd": { - "Atomic mass": 106.42, - "Atomic no": 46, - "Atomic orbitals": { - "1s": -860.134909, - "2p": -114.408286, - "2s": -123.105078, - "3d": -12.132197, - "3p": -18.580798, - "3s": -22.060898, - "4d": -0.160771, - "4p": -1.815215, - "4s": -2.889173 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.69, - "Boiling point": "3236 K", - "Brinell hardness": "37.3 MN m-2", - "Bulk modulus": "180 GPa", - "Coefficient of linear thermal expansion": "11.8 x10-6K-1", - "Common oxidation states": [ - 2, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "12023 kg m-3", - "Electrical resistivity": "10.8 10-8 Ω m", - "Electronic structure": "[Kr].4d10", - "ICSD oxidation states": [ - 2, - 4 - ], - "Ionic radii": { - "1": 0.73, - "2": 1.0, - "3": 0.9, - "4": 0.755 - }, - "Liquid range": "1407.95 K", - "Melting point": "1828.05 K", - "Mendeleev no": 69, - "Mineral hardness": "4.75", - "Molar volume": "8.56 cm3", - "Name": "Palladium", - "Oxidation states": [ - 2, - 4 - ], - "Poissons ratio": "0.39", - "Reflectivity": "72 %", - "Refractive index": "no data", - "Rigidity modulus": "44 GPa", - "Shannon radii": { - "1": { - "II": { - "": { - "crystal_radius": 0.73, - "ionic_radius": 0.59 - } - } - }, - "2": { - "IVSQ": { - "": { - "crystal_radius": 0.78, - "ionic_radius": 0.64 - } - }, - "VI": { - "": { - "crystal_radius": 1.0, - "ionic_radius": 0.86 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.755, - "ionic_radius": 0.615 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "72 W m-1 K-1", - "Van der waals radius": 1.63, - "Velocity of sound": "3070 m s-1", - "Vickers hardness": "461 MN m-2", - "X": 2.2, - "Youngs modulus": "121 GPa" - }, - "Pm": { - "Atomic mass": 145.0, - "Atomic no": 61, - "Atomic orbitals": { - "1s": -1562.980284, - "2p": -233.455114, - "2s": -245.970548, - "3d": -37.625433, - "3p": -47.921132, - "3s": -53.429311, - "4d": -4.596822, - "4f": -0.200159, - "4p": -8.320495, - "4s": -10.422756, - "5p": -0.817702, - "5s": -1.372265, - "6s": -0.127053 - }, - "Atomic radius": 1.85, - "Atomic radius calculated": 2.05, - "Boiling point": "3273 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "33 GPa", - "Coefficient of linear thermal expansion": "11 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "7264 kg m-3", - "Electrical resistivity": "about 75 10-8 Ω m", - "Electronic structure": "[Xe].4f5.6s2", - "Ionic radii": { - "3": 1.11 - }, - "Liquid range": "1900 K", - "Melting point": "1373 K", - "Mendeleev no": 29, - "Mineral hardness": "no data", - "Molar volume": "20.23 cm3", - "Name": "Promethium", - "Oxidation states": [ - 3 - ], - "Poissons ratio": "0.28", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "18 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.11, - "ionic_radius": 0.97 - } - }, - "VIII": { - "": { - "crystal_radius": 1.233, - "ionic_radius": 1.093 - } - }, - "IX": { - "": { - "crystal_radius": 1.284, - "ionic_radius": 1.144 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "15 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.13, - "Youngs modulus": "46 GPa" - }, - "Po": { - "Atomic mass": 210.0, - "Atomic no": 84, - "Atomic orbitals": { - "1s": -3050.988417, - "2p": -498.77192, - "2s": -517.275843, - "3d": -99.256068, - "3p": -115.898384, - "3s": -124.783683, - "4d": -17.173307, - "4f": -7.206499, - "4p": -24.481337, - "4s": -28.42254, - "5d": -1.386458, - "5p": -3.655382, - "5s": -5.027447, - "6p": -0.217889, - "6s": -0.493528 - }, - "Atomic radius": 1.9, - "Atomic radius calculated": 1.35, - "Boiling point": "1235 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -2, - 2, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "9196 kg m-3", - "Electrical resistivity": "40 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2.6p4", - "Ionic radii": { - "4": 1.08, - "6": 0.81 - }, - "Liquid range": "708 K", - "Melting point": "527 K", - "Mendeleev no": 91, - "Mineral hardness": "no data", - "Molar volume": "22.97 cm3", - "Name": "Polonium", - "Oxidation states": [ - -2, - 2, - 4, - 6 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "4": { - "VI": { - "": { - "crystal_radius": 1.08, - "ionic_radius": 0.94 - } - }, - "VIII": { - "": { - "crystal_radius": 1.22, - "ionic_radius": 1.08 - } - } - }, - "6": { - "VI": { - "": { - "crystal_radius": 0.81, - "ionic_radius": 0.67 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "20 W m-1 K-1", - "Van der waals radius": 1.97, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.0, - "Youngs modulus": "no data GPa" - }, - "Pr": { - "Atomic mass": 140.90765, - "Atomic no": 59, - "Atomic orbitals": { - "1s": -1457.338067, - "2p": -215.418313, - "2s": -227.426363, - "3d": -33.913996, - "3p": -43.692548, - "3s": -48.924994, - "4d": -4.154228, - "4f": -0.155138, - "4p": -7.613108, - "4s": -9.577447, - "5p": -0.778046, - "5s": -1.296106, - "6s": -0.124465 - }, - "Atomic radius": 1.85, - "Atomic radius calculated": 2.47, - "Boiling point": "3563 K", - "Brinell hardness": "481 MN m-2", - "Bulk modulus": "29 GPa", - "Coefficient of linear thermal expansion": "6.7 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "6640 kg m-3", - "Electrical resistivity": "70 10-8 Ω m", - "Electronic structure": "[Xe].4f3.6s2", - "ICSD oxidation states": [ - 3, - 4 - ], - "Ionic radii": { - "3": 1.13, - "4": 0.99 - }, - "Liquid range": "2355 K", - "Melting point": "1208 K", - "Mendeleev no": 31, - "Mineral hardness": "no data", - "Molar volume": "20.80 cm3", - "Name": "Praseodymium", - "Oxidation states": [ - 2, - 3, - 4 - ], - "Poissons ratio": "0.28", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "15 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.13, - "ionic_radius": 0.99 - } - }, - "VIII": { - "": { - "crystal_radius": 1.266, - "ionic_radius": 1.126 - } - }, - "IX": { - "": { - "crystal_radius": 1.319, - "ionic_radius": 1.179 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.99, - "ionic_radius": 0.85 - } - }, - "VIII": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "13 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2280 m s-1", - "Vickers hardness": "400 MN m-2", - "X": 1.13, - "Youngs modulus": "37 GPa" - }, - "Pt": { - "Atomic mass": 195.084, - "Atomic no": 78, - "Atomic orbitals": { - "1s": -2613.096532, - "2p": -417.96053, - "2s": -434.858003, - "3d": -78.400271, - "3p": -93.309108, - "3s": -101.274869, - "4d": -11.419476, - "4f": -3.038049, - "4p": -17.697297, - "4s": -21.110651, - "5d": -0.273634, - "5p": -1.884256, - "5s": -2.950526, - "6s": -0.161308 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.77, - "Boiling point": "4098 K", - "Brinell hardness": "392 MN m-2", - "Bulk modulus": "230 GPa", - "Coefficient of linear thermal expansion": "8.8 x10-6K-1", - "Common oxidation states": [ - 2, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "21090 kg m-3", - "Electrical resistivity": "10.6 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d9.6s1", - "Ionic radii": { - "2": 0.94, - "4": 0.765, - "5": 0.71 - }, - "Liquid range": "2056.6 K", - "Melting point": "2041.4 K", - "Mendeleev no": 68, - "Mineral hardness": "3.5", - "Molar volume": "9.09 cm3", - "Name": "Platinum", - "Oxidation states": [ - -2, - 2, - 4, - 5, - 6 - ], - "Poissons ratio": "0.38", - "Reflectivity": "73 %", - "Refractive index": "no data", - "Rigidity modulus": "61 GPa", - "Shannon radii": { - "2": { - "IVSQ": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - }, - "VI": { - "": { - "crystal_radius": 0.94, - "ionic_radius": 0.8 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.765, - "ionic_radius": 0.625 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.71, - "ionic_radius": 0.57 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "72 W m-1 K-1", - "Van der waals radius": 1.75, - "Velocity of sound": "2680 m s-1", - "Vickers hardness": "549 MN m-2", - "X": 2.28, - "Youngs modulus": "168 GPa" - }, - "Pu": { - "Atomic mass": 244.0, - "Atomic no": 94, - "Atomic orbitals": "no data", - "Atomic radius": 1.75, - "Atomic radius calculated": "no data", - "Boiling point": "3503 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "19816 kg m-3", - "Electrical resistivity": "150 10-8 Ω m", - "Electronic structure": "[Rn].5f6.7s2", - "Ionic radii": { - "3": 1.14, - "4": 1.0, - "5": 0.88, - "6": 0.85 - }, - "Liquid range": "2590.5 K", - "Melting point": "912.5 K", - "Mendeleev no": 43, - "Mineral hardness": "no data", - "Molar volume": "12.29 cm3", - "Name": "Plutonium", - "Oxidation states": [ - 3, - 4, - 5, - 6, - 7 - ], - "Poissons ratio": "0.21", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "43 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.14, - "ionic_radius": 1.0 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 1.0, - "ionic_radius": 0.86 - } - }, - "VIII": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.88, - "ionic_radius": 0.74 - } - } - }, - "6": { - "VI": { - "": { - "crystal_radius": 0.85, - "ionic_radius": 0.71 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "6 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2260 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.28, - "Youngs modulus": "96 GPa" - }, - "Ra": { - "Atomic mass": 226.0, - "Atomic no": 88, - "Atomic orbitals": { - "1s": -3362.736563, - "2p": -557.513214, - "2s": -577.101208, - "3d": -115.306476, - "3p": -133.12325, - "3s": -142.632426, - "4d": -22.208125, - "4f": -11.181066, - "4p": -30.221208, - "4s": -34.525628, - "5d": -2.819853, - "5p": -5.547203, - "5s": -7.139137, - "6p": -0.634674, - "6s": -1.05135, - "7s": -0.113732 - }, - "Atomic radius": 2.15, - "Atomic radius calculated": "no data", - "Boiling point": "2010 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "5000 kg m-3", - "Electrical resistivity": "100 10-8 Ω m", - "Electronic structure": "[Rn].7s2", - "Ionic radii": { - "2": 1.62 - }, - "Liquid range": "1037 K", - "Melting point": "973 K", - "Mendeleev no": 13, - "Mineral hardness": "no data", - "Molar volume": "41.09 cm3", - "Name": "Radium", - "Oxidation states": [ - 2 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "2": { - "VIII": { - "": { - "crystal_radius": 1.62, - "ionic_radius": 1.48 - } - }, - "XII": { - "": { - "crystal_radius": 1.84, - "ionic_radius": 1.7 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "19 W m-1 K-1", - "Van der waals radius": 2.83, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.9, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "Ra-223": 1210.3 - } - }, - "Rb": { - "Atomic mass": 85.4678, - "Atomic no": 37, - "Atomic orbitals": { - "1s": -540.957115, - "2p": -64.784678, - "2s": -71.291202, - "3d": -3.915508, - "3p": -8.165416, - "3s": -10.513861, - "4p": -0.59217, - "4s": -1.135051, - "5s": -0.085375 - }, - "Atomic radius": 2.35, - "Atomic radius calculated": 2.65, - "Boiling point": "961 K", - "Brinell hardness": "0.216 MN m-2", - "Bulk modulus": "2.5 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 1 - ], - "Critical temperature": "2093 K", - "Density of solid": "1532 kg m-3", - "Electrical resistivity": "13.3 10-8 Ω m", - "Electronic structure": "[Kr].5s1", - "ICSD oxidation states": [ - 1 - ], - "Ionic radii": { - "1": 1.66 - }, - "Liquid range": "648.54 K", - "Melting point": "312.46 K", - "Mendeleev no": 9, - "Mineral hardness": "0.3", - "Molar volume": "55.76 cm3", - "Name": "Rubidium", - "Oxidation states": [ - 1 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "1": { - "VI": { - "": { - "crystal_radius": 1.66, - "ionic_radius": 1.52 - } - }, - "VII": { - "": { - "crystal_radius": 1.7, - "ionic_radius": 1.56 - } - }, - "VIII": { - "": { - "crystal_radius": 1.75, - "ionic_radius": 1.61 - } - }, - "IX": { - "": { - "crystal_radius": 1.77, - "ionic_radius": 1.63 - } - }, - "X": { - "": { - "crystal_radius": 1.8, - "ionic_radius": 1.66 - } - }, - "XI": { - "": { - "crystal_radius": 1.83, - "ionic_radius": 1.69 - } - }, - "XII": { - "": { - "crystal_radius": 1.86, - "ionic_radius": 1.72 - } - }, - "XIV": { - "": { - "crystal_radius": 1.97, - "ionic_radius": 1.83 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "58 W m-1 K-1", - "Van der waals radius": 3.03, - "Velocity of sound": "1300 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.82, - "Youngs modulus": "2.4 GPa" - }, - "Re": { - "Atomic mass": 186.207, - "Atomic no": 75, - "Atomic orbitals": { - "1s": -2407.665572, - "2p": -380.982869, - "2s": -397.087707, - "3d": -69.57676, - "3p": -83.634578, - "3s": -91.149193, - "4d": -9.516816, - "4f": -1.92508, - "4p": -15.295495, - "4s": -18.454325, - "5d": -0.258639, - "5p": -1.631227, - "5s": -2.567348, - "6s": -0.186859 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.88, - "Boiling point": "5869 K", - "Brinell hardness": "1320 MN m-2", - "Bulk modulus": "370 GPa", - "Coefficient of linear thermal expansion": "6.2 x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "21020 kg m-3", - "Electrical resistivity": "18 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d5.6s2", - "ICSD oxidation states": [ - 3, - 4, - 5, - 6, - 7 - ], - "Ionic radii": { - "4": 0.77, - "5": 0.72, - "6": 0.69, - "7": 0.67 - }, - "Liquid range": "2410 K", - "Melting point": "3459 K", - "Mendeleev no": 58, - "Mineral hardness": "7.0", - "Molar volume": "8.86 cm3", - "Name": "Rhenium", - "Oxidation states": [ - -3, - -1, - 1, - 2, - 3, - 4, - 5, - 6, - 7 - ], - "Poissons ratio": "0.30", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "178 GPa", - "Shannon radii": { - "4": { - "VI": { - "": { - "crystal_radius": 0.77, - "ionic_radius": 0.63 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - } - }, - "6": { - "VI": { - "": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.52, - "ionic_radius": 0.38 - } - }, - "VI": { - "": { - "crystal_radius": 0.67, - "ionic_radius": 0.53 - } - } - } - }, - "Superconduction temperature": "1.70 K", - "Thermal conductivity": "48 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4700 m s-1", - "Vickers hardness": "2450 MN m-2", - "X": 1.9, - "Youngs modulus": "463 GPa" - }, - "Rh": { - "Atomic mass": 102.9055, - "Atomic no": 45, - "Atomic orbitals": { - "1s": -821.136773, - "2p": -108.357665, - "2s": -116.80695, - "3d": -11.21725, - "3p": -17.415299, - "3s": -20.765603, - "4d": -0.239422, - "4p": -1.806456, - "4s": -2.825505, - "5s": -0.154624 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.73, - "Boiling point": "3968 K", - "Brinell hardness": "1100 MN m-2", - "Bulk modulus": "380 GPa", - "Coefficient of linear thermal expansion": "8.2 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "12450 kg m-3", - "Electrical resistivity": "4.3 10-8 Ω m", - "Electronic structure": "[Kr].4d8.5s1", - "ICSD oxidation states": [ - 3, - 4 - ], - "Ionic radii": { - "3": 0.805, - "4": 0.74, - "5": 0.69 - }, - "Liquid range": "1731 K", - "Melting point": "2237 K", - "Mendeleev no": 65, - "Mineral hardness": "6.0", - "Molar volume": "8.28 cm3", - "Name": "Rhodium", - "Oxidation states": [ - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.26", - "Reflectivity": "84 %", - "Refractive index": "no data", - "Rigidity modulus": "150 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.805, - "ionic_radius": 0.665 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "150 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4700 m s-1", - "Vickers hardness": "1246 MN m-2", - "X": 2.28, - "Youngs modulus": "275 GPa" - }, - "Rn": { - "Atomic mass": 220.0, - "Atomic no": 86, - "Atomic orbitals": { - "1s": -3204.756288, - "2p": -527.533025, - "2s": -546.57796, - "3d": -106.945006, - "3p": -124.172862, - "3s": -133.369144, - "4d": -19.449994, - "4f": -8.953318, - "4p": -27.108985, - "4s": -31.230804, - "5d": -1.911329, - "5p": -4.408702, - "5s": -5.889683, - "6p": -0.29318, - "6s": -0.62657 - }, - "Atomic radius": "no data", - "Atomic radius calculated": 1.2, - "Boiling point": "211.3 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Critical temperature": "377 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2.6p6", - "Liquid range": "9.3 K", - "Max oxidation state": 0.0, - "Melting point": "202 K", - "Mendeleev no": 6, - "Min oxidation state": 0.0, - "Mineral hardness": "no data", - "Molar volume": "50.50 cm3", - "Name": "Radon", - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.00361 W m-1 K-1", - "Van der waals radius": 2.2, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.2, - "Youngs modulus": "no data GPa" - }, - "Ru": { - "Atomic mass": 101.07, - "Atomic no": 44, - "Atomic orbitals": { - "1s": -782.918621, - "2p": -102.333649, - "2s": -110.536054, - "3d": -10.195668, - "3p": -16.145217, - "3s": -19.366692, - "4d": -0.210375, - "4p": -1.667549, - "4s": -2.628363, - "5s": -0.152834 - }, - "Atomic radius": 1.3, - "Atomic radius calculated": 1.78, - "Boiling point": "4423 K", - "Brinell hardness": "2160 MN m-2", - "Bulk modulus": "220 GPa", - "Coefficient of linear thermal expansion": "6.4 x10-6K-1", - "Common oxidation states": [ - 3, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "12370 kg m-3", - "Electrical resistivity": "7.1 10-8 Ω m", - "Electronic structure": "[Kr].4d7.5s1", - "ICSD oxidation states": [ - 2, - 3, - 4, - 5, - 6 - ], - "Ionic radii": { - "3": 0.82, - "4": 0.76, - "5": 0.705, - "7": 0.52, - "8": 0.5 - }, - "Liquid range": "1816 K", - "Melting point": "2607 K", - "Mendeleev no": 62, - "Mineral hardness": "6.5", - "Molar volume": "8.17 cm3", - "Name": "Ruthenium", - "Oxidation states": [ - -2, - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8 - ], - "Poissons ratio": "0.30", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "173 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.82, - "ionic_radius": 0.68 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.76, - "ionic_radius": 0.62 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.705, - "ionic_radius": 0.565 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.52, - "ionic_radius": 0.38 - } - } - }, - "8": { - "IV": { - "": { - "crystal_radius": 0.5, - "ionic_radius": 0.36 - } - } - } - }, - "Superconduction temperature": "0.49 K", - "Thermal conductivity": "120 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "5970 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.2, - "Youngs modulus": "447 GPa" - }, - "S": { - "Atomic mass": 32.065, - "Atomic no": 16, - "Atomic orbitals": { - "1s": -87.789937, - "2p": -5.751257, - "2s": -7.69994, - "3p": -0.261676, - "3s": -0.630912 - }, - "Atomic radius": 1.0, - "Atomic radius calculated": 0.88, - "Boiling point": "717.87 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "7.7 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -2, - 2, - 4, - 6 - ], - "Critical temperature": "1314 K", - "Density of solid": "1960 kg m-3", - "Electrical resistivity": "> 102310-8 Ω m", - "Electronic structure": "[Ne].3s2.3p4", - "ICSD oxidation states": [ - -1, - 2, - 4, - -2, - 6 - ], - "Ionic radii": { - "-2": 1.7, - "4": 0.51, - "6": 0.43 - }, - "Liquid range": "329.51 K", - "Melting point": "388.36 K", - "Mendeleev no": 94, - "Mineral hardness": "2.0", - "Molar volume": "15.53 cm3", - "Name": "Sulfur", - "Oxidation states": [ - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.001111", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "-2": { - "VI": { - "": { - "crystal_radius": 1.7, - "ionic_radius": 1.84 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.51, - "ionic_radius": 0.37 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.26, - "ionic_radius": 0.12 - } - }, - "VI": { - "": { - "crystal_radius": 0.43, - "ionic_radius": 0.29 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.205 W m-1 K-1", - "Van der waals radius": 1.8, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.58, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "S-33": -67.8, - "S-35": 47.1 - } - }, - "Sb": { - "Atomic mass": 121.76, - "Atomic no": 51, - "Atomic orbitals": { - "1s": -1070.823495, - "2p": -149.214271, - "2s": -159.171745, - "3d": -19.239895, - "3p": -26.956184, - "3s": -31.098242, - "4d": -1.297338, - "4p": -3.646579, - "4s": -5.04964, - "5p": -0.185623, - "5s": -0.445605 - }, - "Atomic radius": 1.45, - "Atomic radius calculated": 1.33, - "Boiling point": "1860 K", - "Brinell hardness": "294 MN m-2", - "Bulk modulus": "42 GPa", - "Coefficient of linear thermal expansion": "11 x10-6K-1", - "Common oxidation states": [ - -3, - 3, - 5 - ], - "Critical temperature": "no data K", - "Density of solid": "6697 kg m-3", - "Electrical resistivity": "40 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2.5p3", - "ICSD oxidation states": [ - -2, - 3, - 5, - -1, - -3 - ], - "Ionic radii": { - "3": 0.9, - "5": 0.76 - }, - "Liquid range": "956.22 K", - "Melting point": "903.78 K", - "Mendeleev no": 88, - "Mineral hardness": "3.0", - "Molar volume": "18.19 cm3", - "Name": "Antimony", - "Oxidation states": [ - -3, - 3, - 5 - ], - "Poissons ratio": "no data", - "Reflectivity": "55 %", - "Refractive index": "no data", - "Rigidity modulus": "20 GPa", - "Shannon radii": { - "3": { - "IVPY": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - }, - "V": { - "": { - "crystal_radius": 0.94, - "ionic_radius": 0.8 - } - }, - "VI": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "24 W m-1 K-1", - "Van der waals radius": 2.06, - "Velocity of sound": "3420 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.05, - "Youngs modulus": "55 GPa", - "NMR Quadrupole Moment": { - "Sb-121": -543.11, - "Sb-123": -692.14 - } - }, - "Sc": { - "Atomic mass": 44.955912, - "Atomic no": 21, - "Atomic orbitals": { - "1s": -160.184109, - "2p": -14.240006, - "2s": -17.206464, - "3d": -0.13108, - "3p": -1.233165, - "3s": -1.988378, - "4s": -0.156478 - }, - "Atomic radius": 1.6, - "Atomic radius calculated": 1.84, - "Boiling point": "3103 K", - "Brinell hardness": "750 MN m-2", - "Bulk modulus": "57 GPa", - "Coefficient of linear thermal expansion": "10.2 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "2985 kg m-3", - "Electrical resistivity": "about 55 10-8 Ω m", - "Electronic structure": "[Ar].3d1.4s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "3": 0.885 - }, - "Liquid range": "1289 K", - "Melting point": "1814 K", - "Mendeleev no": 19, - "Mineral hardness": "no data", - "Molar volume": "15.00 cm3", - "Name": "Scandium", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "0.28", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "29 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.885, - "ionic_radius": 0.745 - } - }, - "VIII": { - "": { - "crystal_radius": 1.01, - "ionic_radius": 0.87 - } - } - } - }, - "Superconduction temperature": "0.05 (under pressure)K", - "Thermal conductivity": "16 W m-1 K-1", - "Van der waals radius": 2.11, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.36, - "Youngs modulus": "74 GPa", - "NMR Quadrupole Moment": { - "Sc-45": -220.2 - } - }, - "Se": { - "Atomic mass": 78.96, - "Atomic no": 34, - "Atomic orbitals": { - "1s": -451.300258, - "2p": -51.514388, - "2s": -57.311948, - "3d": -2.011392, - "3p": -5.553517, - "3s": -7.547186, - "4p": -0.245806, - "4s": -0.621248 - }, - "Atomic radius": 1.15, - "Atomic radius calculated": 1.03, - "Boiling point": "958 K", - "Brinell hardness": "736 MN m-2", - "Bulk modulus": "8.3 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -2, - 2, - 4, - 6 - ], - "Critical temperature": "1766 K", - "Density of solid": "4819 kg m-3", - "Electrical resistivity": "high 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2.4p4", - "ICSD oxidation states": [ - -1, - 4, - -2, - 6 - ], - "Ionic radii": { - "-2": 1.84, - "4": 0.64, - "6": 0.56 - }, - "Liquid range": "464 K", - "Melting point": "494 K", - "Mendeleev no": 93, - "Mineral hardness": "2.0", - "Molar volume": "16.42 cm3", - "Name": "Selenium", - "Oxidation states": [ - -2, - 2, - 4, - 6 - ], - "Poissons ratio": "0.33", - "Reflectivity": "no data %", - "Refractive index": "1.000895", - "Rigidity modulus": "3.7 GPa", - "Shannon radii": { - "-2": { - "VI": { - "": { - "crystal_radius": 1.84, - "ionic_radius": 1.98 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.64, - "ionic_radius": 0.5 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.42, - "ionic_radius": 0.28 - } - }, - "VI": { - "": { - "crystal_radius": 0.56, - "ionic_radius": 0.42 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.52 W m-1 K-1", - "Van der waals radius": 1.9, - "Velocity of sound": "3350 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.55, - "Youngs modulus": "10 GPa" - }, - "Si": { - "Atomic mass": 28.0855, - "Atomic no": 14, - "Atomic orbitals": { - "1s": -65.184426, - "2p": -3.514938, - "2s": -5.075056, - "3p": -0.153293, - "3s": -0.398139 - }, - "Atomic radius": 1.1, - "Atomic radius calculated": 1.11, - "Boiling point": "3173 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "100 GPa", - "Coefficient of linear thermal expansion": "2.6 x10-6K-1", - "Common oxidation states": [ - -4, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "2330 kg m-3", - "Electrical resistivity": "about 100000 10-8 Ω m", - "Electronic structure": "[Ne].3s2.3p2", - "ICSD oxidation states": [ - -4, - 4 - ], - "Ionic radii": { - "4": 0.54 - }, - "Liquid range": "1486 K", - "Melting point": "1687 K", - "Mendeleev no": 85, - "Mineral hardness": "6.5", - "Molar volume": "12.06 cm3", - "Name": "Silicon", - "Oxidation states": [ - -4, - -3, - -2, - -1, - 1, - 2, - 3, - 4 - ], - "Poissons ratio": "no data", - "Reflectivity": "28 %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "4": { - "IV": { - "": { - "crystal_radius": 0.4, - "ionic_radius": 0.26 - } - }, - "VI": { - "": { - "crystal_radius": 0.54, - "ionic_radius": 0.4 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "150 W m-1 K-1", - "Van der waals radius": 2.1, - "Velocity of sound": "2200 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.9, - "Youngs modulus": "47 GPa" - }, - "Sm": { - "Atomic mass": 150.36, - "Atomic no": 62, - "Atomic orbitals": { - "1s": -1617.183426, - "2p": -242.729726, - "2s": -255.498846, - "3d": -39.528656, - "3p": -50.08426, - "3s": -55.731133, - "4d": -4.814978, - "4f": -0.21776, - "4p": -8.672685, - "4s": -10.844667, - "5p": -0.835987, - "5s": -1.408552, - "6s": -0.128259 - }, - "Atomic radius": 1.85, - "Atomic radius calculated": 2.38, - "Boiling point": "2076 K", - "Brinell hardness": "441 MN m-2", - "Bulk modulus": "38 GPa", - "Coefficient of linear thermal expansion": "12.7 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "7353 kg m-3", - "Electrical resistivity": "94 10-8 Ω m", - "Electronic structure": "[Xe].4f6.6s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "2": 1.36, - "3": 1.0979999999999999 - }, - "Liquid range": "731 K", - "Melting point": "1345 K", - "Mendeleev no": 28, - "Mineral hardness": "no data", - "Molar volume": "19.98 cm3", - "Name": "Samarium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.27", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "20 GPa", - "Shannon radii": { - "2": { - "VII": { - "": { - "crystal_radius": 1.36, - "ionic_radius": 1.22 - } - }, - "VIII": { - "": { - "crystal_radius": 1.41, - "ionic_radius": 1.27 - } - }, - "IX": { - "": { - "crystal_radius": 1.46, - "ionic_radius": 1.32 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.098, - "ionic_radius": 0.958 - } - }, - "VII": { - "": { - "crystal_radius": 1.16, - "ionic_radius": 1.02 - } - }, - "VIII": { - "": { - "crystal_radius": 1.219, - "ionic_radius": 1.079 - } - }, - "IX": { - "": { - "crystal_radius": 1.272, - "ionic_radius": 1.132 - } - }, - "XII": { - "": { - "crystal_radius": 1.38, - "ionic_radius": 1.24 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "13 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2130 m s-1", - "Vickers hardness": "412 MN m-2", - "X": 1.17, - "Youngs modulus": "50 GPa" - }, - "Sn": { - "Atomic mass": 118.71, - "Atomic no": 50, - "Atomic orbitals": { - "1s": -1026.762169, - "2p": -141.821093, - "2s": -151.523991, - "3d": -17.657276, - "3p": -25.117913, - "3s": -29.125969, - "4d": -1.004952, - "4p": -3.211998, - "4s": -4.546335, - "5p": -0.14445, - "5s": -0.369349 - }, - "Atomic radius": 1.45, - "Atomic radius calculated": 1.45, - "Boiling point": "2875 K", - "Brinell hardness": "51 MN m-2", - "Bulk modulus": "58 GPa", - "Coefficient of linear thermal expansion": "22 x10-6K-1", - "Common oxidation states": [ - -4, - 2, - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "7310 kg m-3", - "Electrical resistivity": "11.5 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2.5p2", - "ICSD oxidation states": [ - 2, - 3, - 4 - ], - "Ionic radii": { - "4": 0.83 - }, - "Liquid range": "2369.92 K", - "Melting point": "505.08 K", - "Mendeleev no": 83, - "Mineral hardness": "1.5", - "Molar volume": "16.29 cm3", - "Name": "Tin", - "Oxidation states": [ - -4, - 2, - 4 - ], - "Poissons ratio": "0.36", - "Reflectivity": "54 %", - "Refractive index": "no data", - "Rigidity modulus": "18 GPa", - "Shannon radii": { - "4": { - "IV": { - "": { - "crystal_radius": 0.69, - "ionic_radius": 0.55 - } - }, - "V": { - "": { - "crystal_radius": 0.76, - "ionic_radius": 0.62 - } - }, - "VI": { - "": { - "crystal_radius": 0.83, - "ionic_radius": 0.69 - } - }, - "VII": { - "": { - "crystal_radius": 0.89, - "ionic_radius": 0.75 - } - }, - "VIII": { - "": { - "crystal_radius": 0.95, - "ionic_radius": 0.81 - } - } - } - }, - "Superconduction temperature": "3.72 K", - "Thermal conductivity": "67 W m-1 K-1", - "Van der waals radius": 2.17, - "Velocity of sound": "2500 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.96, - "Youngs modulus": "50 GPa", - "NMR Quadrupole Moment": { - "Sn-119": -132.1 - } - }, - "Sr": { - "Atomic mass": 87.62, - "Atomic no": 38, - "Atomic orbitals": { - "1s": -572.870169, - "2p": -69.745941, - "2s": -76.491823, - "3d": -4.813498, - "3p": -9.301863, - "3s": -11.771585, - "4p": -0.844489, - "4s": -1.455317, - "5s": -0.131793 - }, - "Atomic radius": 2.0, - "Atomic radius calculated": 2.19, - "Boiling point": "1655 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "22.5 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "2630 kg m-3", - "Electrical resistivity": "13.5 10-8 Ω m", - "Electronic structure": "[Kr].5s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 1.32 - }, - "Liquid range": "605 K", - "Melting point": "1050 K", - "Mendeleev no": 15, - "Mineral hardness": "1.5", - "Molar volume": "33.94 cm3", - "Name": "Strontium", - "Oxidation states": [ - 2 - ], - "Poissons ratio": "0.28", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "6.1 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.32, - "ionic_radius": 1.18 - } - }, - "VII": { - "": { - "crystal_radius": 1.35, - "ionic_radius": 1.21 - } - }, - "VIII": { - "": { - "crystal_radius": 1.4, - "ionic_radius": 1.26 - } - }, - "IX": { - "": { - "crystal_radius": 1.45, - "ionic_radius": 1.31 - } - }, - "X": { - "": { - "crystal_radius": 1.5, - "ionic_radius": 1.36 - } - }, - "XII": { - "": { - "crystal_radius": 1.58, - "ionic_radius": 1.44 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "35 W m-1 K-1", - "Van der waals radius": 2.49, - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 0.95, - "Youngs modulus": "no data GPa", - "NMR Quadrupole Moment": { - "Sr-87": 305.2 - } - }, - "Ta": { - "Atomic mass": 180.94788, - "Atomic no": 73, - "Atomic orbitals": { - "1s": -2275.371387, - "2p": -357.248334, - "2s": -372.828724, - "3d": -63.942521, - "3p": -77.440942, - "3s": -84.658467, - "4d": -8.265848, - "4f": -1.199347, - "4p": -13.71981, - "4s": -16.713337, - "5d": -0.182464, - "5p": -1.37653, - "5s": -2.223807, - "6s": -0.174814 - }, - "Atomic radius": 1.45, - "Atomic radius calculated": 2.0, - "Boiling point": "5731 K", - "Brinell hardness": "800 MN m-2", - "Bulk modulus": "200 GPa", - "Coefficient of linear thermal expansion": "6.3 x10-6K-1", - "Common oxidation states": [ - 5 - ], - "Critical temperature": "no data K", - "Density of solid": "16650 kg m-3", - "Electrical resistivity": "13.5 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d3.6s2", - "ICSD oxidation states": [ - 3, - 4, - 5 - ], - "Ionic radii": { - "3": 0.86, - "4": 0.82, - "5": 0.78 - }, - "Liquid range": "2441 K", - "Melting point": "3290 K", - "Mendeleev no": 52, - "Mineral hardness": "6.5", - "Molar volume": "10.85 cm3", - "Name": "Tantalum", - "Oxidation states": [ - -1, - 2, - 3, - 4, - 5 - ], - "Poissons ratio": "0.34", - "Reflectivity": "78 %", - "Refractive index": "no data", - "Rigidity modulus": "69 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 0.86, - "ionic_radius": 0.72 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.82, - "ionic_radius": 0.68 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.78, - "ionic_radius": 0.64 - } - }, - "VII": { - "": { - "crystal_radius": 0.83, - "ionic_radius": 0.69 - } - }, - "VIII": { - "": { - "crystal_radius": 0.88, - "ionic_radius": 0.74 - } - } - } - }, - "Superconduction temperature": "4.47 K", - "Thermal conductivity": "57 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "3400 m s-1", - "Vickers hardness": "873 MN m-2", - "X": 1.5, - "Youngs modulus": "186 GPa" - }, - "Tb": { - "Atomic mass": 158.92535, - "Atomic no": 65, - "Atomic orbitals": { - "1s": -1785.331942, - "2p": -271.590585, - "2s": -285.121013, - "3d": -45.443863, - "3p": -56.785113, - "3s": -62.851563, - "4d": -5.467662, - "4f": -0.256311, - "4p": -9.735637, - "4s": -12.120486, - "5p": -0.88723, - "5s": -1.513669, - "6s": -0.131677 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": 2.25, - "Boiling point": "3503 K", - "Brinell hardness": "677 MN m-2", - "Bulk modulus": "38.7 GPa", - "Coefficient of linear thermal expansion": "10.3 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "8219 kg m-3", - "Electrical resistivity": "115 10-8 Ω m", - "Electronic structure": "[Xe].4f9.6s2", - "ICSD oxidation states": [ - 3, - 4 - ], - "Ionic radii": { - "3": 1.063, - "4": 0.9 - }, - "Liquid range": "1874 K", - "Melting point": "1629 K", - "Mendeleev no": 26, - "Mineral hardness": "no data", - "Molar volume": "19.30 cm3", - "Name": "Terbium", - "Oxidation states": [ - 1, - 3, - 4 - ], - "Poissons ratio": "0.26", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "22 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.063, - "ionic_radius": 0.923 - } - }, - "VII": { - "": { - "crystal_radius": 1.12, - "ionic_radius": 0.98 - } - }, - "VIII": { - "": { - "crystal_radius": 1.18, - "ionic_radius": 1.04 - } - }, - "IX": { - "": { - "crystal_radius": 1.235, - "ionic_radius": 1.095 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - }, - "VIII": { - "": { - "crystal_radius": 1.02, - "ionic_radius": 0.88 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "11 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2620 m s-1", - "Vickers hardness": "863 MN m-2", - "X": 1.1, - "Youngs modulus": "56 GPa" - }, - "Tc": { - "Atomic mass": 98.0, - "Atomic no": 43, - "Atomic orbitals": { - "1s": -745.742024, - "2p": -96.61021, - "2s": -104.567508, - "3d": -9.33986, - "3p": -15.041738, - "3s": -18.135303, - "4d": -0.270262, - "4p": -1.64323, - "4s": -2.550712, - "5s": -0.183636 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.83, - "Boiling point": "4538 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - 4, - 7 - ], - "Critical temperature": "no data K", - "Density of solid": "11500 kg m-3", - "Electrical resistivity": "about 22 10-8 Ω m", - "Electronic structure": "[Kr].4d5.5s2", - "Ionic radii": { - "4": 0.785, - "5": 0.74, - "7": 0.7 - }, - "Liquid range": "2108 K", - "Melting point": "2430 K", - "Mendeleev no": 59, - "Mineral hardness": "no data", - "Molar volume": "8.63 cm3", - "Name": "Technetium", - "Oxidation states": [ - -3, - -1, - 1, - 2, - 3, - 4, - 5, - 6, - 7 - ], - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "4": { - "VI": { - "": { - "crystal_radius": 0.785, - "ionic_radius": 0.645 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - } - }, - "7": { - "IV": { - "": { - "crystal_radius": 0.51, - "ionic_radius": 0.37 - } - }, - "VI": { - "": { - "crystal_radius": 0.7, - "ionic_radius": 0.56 - } - } - } - }, - "Superconduction temperature": "7.8 K", - "Thermal conductivity": "51 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.9, - "Youngs modulus": "no data GPa" - }, - "Te": { - "Atomic mass": 127.6, - "Atomic no": 52, - "Atomic orbitals": { - "1s": -1115.831819, - "2p": -156.808583, - "2s": -167.021776, - "3d": -20.887801, - "3p": -28.860685, - "3s": -33.137485, - "4d": -1.608381, - "4p": -4.100084, - "4s": -5.572846, - "5p": -0.226594, - "5s": -0.520997 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.23, - "Boiling point": "1261 K", - "Brinell hardness": "180 MN m-2", - "Bulk modulus": "65 GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Common oxidation states": [ - -2, - 2, - 4, - 6 - ], - "Critical temperature": "no data K", - "Density of solid": "6240 kg m-3", - "Electrical resistivity": "about 10000 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2.5p4", - "ICSD oxidation states": [ - -2, - 4, - -1, - 6 - ], - "Ionic radii": { - "-2": 2.07, - "4": 1.11, - "6": 0.7 - }, - "Liquid range": "538.34 K", - "Melting point": "722.66 K", - "Mendeleev no": 92, - "Mineral hardness": "2.25", - "Molar volume": "20.46 cm3", - "Name": "Tellurium", - "Oxidation states": [ - -2, - 2, - 4, - 5, - 6 - ], - "Poissons ratio": "no data", - "Reflectivity": "50 %", - "Refractive index": "1.000991", - "Rigidity modulus": "16 GPa", - "Shannon radii": { - "-2": { - "VI": { - "": { - "crystal_radius": 2.07, - "ionic_radius": 2.21 - } - } - }, - "4": { - "III": { - "": { - "crystal_radius": 0.66, - "ionic_radius": 0.52 - } - }, - "IV": { - "": { - "crystal_radius": 0.8, - "ionic_radius": 0.66 - } - }, - "VI": { - "": { - "crystal_radius": 1.11, - "ionic_radius": 0.97 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.57, - "ionic_radius": 0.43 - } - }, - "VI": { - "": { - "crystal_radius": 0.7, - "ionic_radius": 0.56 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "3 W m-1 K-1", - "Van der waals radius": 2.06, - "Velocity of sound": "2610 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.1, - "Youngs modulus": "43 GPa" - }, - "Th": { - "Atomic mass": 232.03806, - "Atomic no": 90, - "Atomic orbitals": { - "1s": -3524.439052, - "2p": -588.218112, - "2s": -608.350958, - "3d": -123.846396, - "3p": -142.25581, - "3s": -152.079741, - "4d": -24.955184, - "4f": -13.397389, - "4p": -33.325252, - "4s": -37.814094, - "5d": -3.625729, - "5p": -6.58281, - "5s": -8.287057, - "6d": -0.172896, - "6p": -0.846921, - "6s": -1.333769, - "7s": -0.135872 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": "no data", - "Boiling point": "5093 K", - "Brinell hardness": "400 MN m-2", - "Bulk modulus": "54 GPa", - "Coefficient of linear thermal expansion": "11.0 x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "11724 kg m-3", - "Electrical resistivity": "15 10-8 Ω m", - "Electronic structure": "[Rn].6d2.7s2", - "ICSD oxidation states": [ - 4 - ], - "Ionic radii": { - "4": 1.08 - }, - "Liquid range": "2978 K", - "Melting point": "2115 K", - "Mendeleev no": 47, - "Mineral hardness": "3.0", - "Molar volume": "19.80 cm3", - "Name": "Thorium", - "Oxidation states": [ - 2, - 3, - 4 - ], - "Poissons ratio": "0.27", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "31 GPa", - "Shannon radii": { - "4": { - "VI": { - "": { - "crystal_radius": 1.08, - "ionic_radius": 0.94 - } - }, - "VIII": { - "": { - "crystal_radius": 1.19, - "ionic_radius": 1.05 - } - }, - "IX": { - "": { - "crystal_radius": 1.23, - "ionic_radius": 1.09 - } - }, - "X": { - "": { - "crystal_radius": 1.27, - "ionic_radius": 1.13 - } - }, - "XI": { - "": { - "crystal_radius": 1.32, - "ionic_radius": 1.18 - } - }, - "XII": { - "": { - "crystal_radius": 1.35, - "ionic_radius": 1.21 - } - } - } - }, - "Superconduction temperature": "1.38 K", - "Thermal conductivity": "54 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "2490 m s-1", - "Vickers hardness": "350 MN m-2", - "X": 1.3, - "Youngs modulus": "79 GPa" - }, - "Ti": { - "Atomic mass": 47.867, - "Atomic no": 22, - "Atomic orbitals": { - "1s": -177.276643, - "2p": -16.285339, - "2s": -19.457901, - "3d": -0.17001, - "3p": -1.422947, - "3s": -2.258007, - "4s": -0.167106 - }, - "Atomic radius": 1.4, - "Atomic radius calculated": 1.76, - "Boiling point": "3560 K", - "Brinell hardness": "716 MN m-2", - "Bulk modulus": "110 GPa", - "Coefficient of linear thermal expansion": "8.6 x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "4507 kg m-3", - "Electrical resistivity": "about 40 10-8 Ω m", - "Electronic structure": "[Ar].3d2.4s2", - "ICSD oxidation states": [ - 2, - 3, - 4 - ], - "Ionic radii": { - "2": 1.0, - "3": 0.81, - "4": 0.745 - }, - "Liquid range": "1619 K", - "Melting point": "1941 K", - "Mendeleev no": 51, - "Mineral hardness": "6.0", - "Molar volume": "10.64 cm3", - "Name": "Titanium", - "Oxidation states": [ - -1, - 2, - 3, - 4 - ], - "Poissons ratio": "0.32", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "44 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.0, - "ionic_radius": 0.86 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 0.81, - "ionic_radius": 0.67 - } - } - }, - "4": { - "IV": { - "": { - "crystal_radius": 0.56, - "ionic_radius": 0.42 - } - }, - "V": { - "": { - "crystal_radius": 0.65, - "ionic_radius": 0.51 - } - }, - "VI": { - "": { - "crystal_radius": 0.745, - "ionic_radius": 0.605 - } - }, - "VIII": { - "": { - "crystal_radius": 0.88, - "ionic_radius": 0.74 - } - } - } - }, - "Superconduction temperature": "0.40 K", - "Thermal conductivity": "22 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4140 m s-1", - "Vickers hardness": "970 MN m-2", - "X": 1.54, - "Youngs modulus": "116 GPa", - "NMR Quadrupole Moment": { - "Ti-47": 302.1, - "Ti-49": 247.11 - } - }, - "Tl": { - "Atomic mass": 204.3833, - "Atomic no": 81, - "Atomic orbitals": { - "1s": -2827.569408, - "2p": -457.255971, - "2s": -474.953368, - "3d": -88.328299, - "3p": -104.099296, - "3s": -112.52218, - "4d": -14.008848, - "4f": -4.835747, - "4p": -20.797078, - "4s": -24.471512, - "5d": -0.674544, - "5p": -2.59873, - "5s": -3.811512, - "6p": -0.101507, - "6s": -0.28502 - }, - "Atomic radius": 1.9, - "Atomic radius calculated": 1.56, - "Boiling point": "1746 K", - "Brinell hardness": "26.4 MN m-2", - "Bulk modulus": "43 GPa", - "Coefficient of linear thermal expansion": "29.9 x10-6K-1", - "Common oxidation states": [ - 1, - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "11850 kg m-3", - "Electrical resistivity": "15 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d10.6s2.6p1", - "ICSD oxidation states": [ - 1, - 3 - ], - "Ionic radii": { - "1": 1.64, - "3": 1.025 - }, - "Liquid range": "1169 K", - "Melting point": "577 K", - "Mendeleev no": 78, - "Mineral hardness": "1.2", - "Molar volume": "17.22 cm3", - "Name": "Thallium", - "Oxidation states": [ - 1, - 3 - ], - "Poissons ratio": "0.45", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "2.8 GPa", - "Shannon radii": { - "1": { - "VI": { - "": { - "crystal_radius": 1.64, - "ionic_radius": 1.5 - } - }, - "VIII": { - "": { - "crystal_radius": 1.73, - "ionic_radius": 1.59 - } - }, - "XII": { - "": { - "crystal_radius": 1.84, - "ionic_radius": 1.7 - } - } - }, - "3": { - "IV": { - "": { - "crystal_radius": 0.89, - "ionic_radius": 0.75 - } - }, - "VI": { - "": { - "crystal_radius": 1.025, - "ionic_radius": 0.885 - } - }, - "VIII": { - "": { - "crystal_radius": 1.12, - "ionic_radius": 0.98 - } - } - } - }, - "Superconduction temperature": "2.38 K", - "Thermal conductivity": "46 W m-1 K-1", - "Van der waals radius": 1.96, - "Velocity of sound": "818 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.62, - "Youngs modulus": "8 GPa" - }, - "Tm": { - "Atomic mass": 168.93421, - "Atomic no": 69, - "Atomic orbitals": { - "1s": -2022.471608, - "2p": -312.510608, - "2s": -327.05712, - "3d": -53.835494, - "3p": -66.239338, - "3s": -72.873753, - "4d": -6.350307, - "4f": -0.28312, - "4p": -11.187151, - "4s": -13.865665, - "5p": -0.950748, - "5s": -1.64999, - "6s": -0.135953 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": 2.22, - "Boiling point": "2223 K", - "Brinell hardness": "471 MN m-2", - "Bulk modulus": "45 GPa", - "Coefficient of linear thermal expansion": "13.3 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "9321 kg m-3", - "Electrical resistivity": "67.6 10-8 Ω m", - "Electronic structure": "[Xe].4f13.6s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "2": 1.17, - "3": 1.02 - }, - "Liquid range": "405 K", - "Melting point": "1818 K", - "Mendeleev no": 21, - "Mineral hardness": "no data", - "Molar volume": "19.1 cm3", - "Name": "Thulium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.21", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "31 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.17, - "ionic_radius": 1.03 - } - }, - "VII": { - "": { - "crystal_radius": 1.23, - "ionic_radius": 1.09 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.02, - "ionic_radius": 0.88 - } - }, - "VIII": { - "": { - "crystal_radius": 1.134, - "ionic_radius": 0.994 - } - }, - "IX": { - "": { - "crystal_radius": 1.192, - "ionic_radius": 1.052 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "17 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "no data m s-1", - "Vickers hardness": "520 MN m-2", - "X": 1.25, - "Youngs modulus": "74 GPa" - }, - "U": { - "Atomic mass": 238.02891, - "Atomic no": 92, - "Atomic orbitals": { - "1s": -3689.355141, - "2p": -619.10855, - "2s": -639.778728, - "3d": -131.977358, - "3p": -150.97898, - "3s": -161.118073, - "4d": -27.123212, - "4f": -15.02746, - "4p": -35.853321, - "4s": -40.528084, - "5d": -3.866175, - "5f": -0.366543, - "5p": -7.018092, - "5s": -8.824089, - "6d": -0.14319, - "6p": -0.822538, - "6s": -1.325976, - "7s": -0.130948 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": "no data", - "Boiling point": "4200 K", - "Brinell hardness": "2400 MN m-2", - "Bulk modulus": "100 GPa", - "Coefficient of linear thermal expansion": "13.9 x10-6K-1", - "Common oxidation states": [ - 6 - ], - "Critical temperature": "no data K", - "Density of solid": "19050 kg m-3", - "Electrical resistivity": "28 10-8 Ω m", - "Electronic structure": "[Rn].5f3.6d1.7s2", - "ICSD oxidation states": [ - 3, - 4, - 5, - 6 - ], - "Ionic radii": { - "3": 1.165, - "4": 1.03, - "5": 0.9, - "6": 0.87 - }, - "Liquid range": "2794.7 K", - "Melting point": "1405.3 K", - "Mendeleev no": 45, - "Mineral hardness": "6.0", - "Molar volume": "12.49 cm3", - "Name": "Uranium", - "Oxidation states": [ - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.23", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "111 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.165, - "ionic_radius": 1.025 - } - } - }, - "4": { - "VI": { - "": { - "crystal_radius": 1.03, - "ionic_radius": 0.89 - } - }, - "VII": { - "": { - "crystal_radius": 1.09, - "ionic_radius": 0.95 - } - }, - "VIII": { - "": { - "crystal_radius": 1.14, - "ionic_radius": 1.0 - } - }, - "IX": { - "": { - "crystal_radius": 1.19, - "ionic_radius": 1.05 - } - }, - "XII": { - "": { - "crystal_radius": 1.31, - "ionic_radius": 1.17 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.9, - "ionic_radius": 0.76 - } - }, - "VII": { - "": { - "crystal_radius": 0.98, - "ionic_radius": 0.84 - } - } - }, - "6": { - "II": { - "": { - "crystal_radius": 0.59, - "ionic_radius": 0.45 - } - }, - "IV": { - "": { - "crystal_radius": 0.66, - "ionic_radius": 0.52 - } - }, - "VI": { - "": { - "crystal_radius": 0.87, - "ionic_radius": 0.73 - } - }, - "VII": { - "": { - "crystal_radius": 0.95, - "ionic_radius": 0.81 - } - }, - "VIII": { - "": { - "crystal_radius": 1.0, - "ionic_radius": 0.86 - } - } - } - }, - "Superconduction temperature": "0.2 K", - "Thermal conductivity": "27 W m-1 K-1", - "Van der waals radius": 1.86, - "Velocity of sound": "3155 m s-1", - "Vickers hardness": "1960 MN m-2", - "X": 1.38, - "Youngs modulus": "208 GPa" - }, - "V": { - "Atomic mass": 50.9415, - "Atomic no": 23, - "Atomic orbitals": { - "1s": -195.224014, - "2p": -18.435189, - "2s": -21.815346, - "3d": -0.204634, - "3p": -1.610516, - "3s": -2.526904, - "4s": -0.175968 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.71, - "Boiling point": "3680 K", - "Brinell hardness": "628 MN m-2", - "Bulk modulus": "160 GPa", - "Coefficient of linear thermal expansion": "8.4 x10-6K-1", - "Common oxidation states": [ - 5 - ], - "Critical temperature": "no data K", - "Density of solid": "6110 kg m-3", - "Electrical resistivity": "20 10-8 Ω m", - "Electronic structure": "[Ar].3d3.4s2", - "ICSD oxidation states": [ - 2, - 3, - 4, - 5 - ], - "Ionic radii": { - "2": 0.93, - "3": 0.78, - "4": 0.72, - "5": 0.68 - }, - "Liquid range": "1497 K", - "Melting point": "2183 K", - "Mendeleev no": 54, - "Mineral hardness": "7.0", - "Molar volume": "8.32 cm3", - "Name": "Vanadium", - "Oxidation states": [ - -1, - 1, - 2, - 3, - 4, - 5 - ], - "Poissons ratio": "0.37", - "Reflectivity": "61 %", - "Refractive index": "no data", - "Rigidity modulus": "47 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 0.93, - "ionic_radius": 0.79 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 0.78, - "ionic_radius": 0.64 - } - } - }, - "4": { - "V": { - "": { - "crystal_radius": 0.67, - "ionic_radius": 0.53 - } - }, - "VI": { - "": { - "crystal_radius": 0.72, - "ionic_radius": 0.58 - } - }, - "VIII": { - "": { - "crystal_radius": 0.86, - "ionic_radius": 0.72 - } - } - }, - "5": { - "IV": { - "": { - "crystal_radius": 0.495, - "ionic_radius": 0.355 - } - }, - "V": { - "": { - "crystal_radius": 0.6, - "ionic_radius": 0.46 - } - }, - "VI": { - "": { - "crystal_radius": 0.68, - "ionic_radius": 0.54 - } - } - } - }, - "Superconduction temperature": "5.40 K", - "Thermal conductivity": "31 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "4560 m s-1", - "Vickers hardness": "628 MN m-2", - "X": 1.63, - "Youngs modulus": "128 GPa", - "NMR Quadrupole Moment": { - "V-50": 210.4, - "V-51": -52.1 - } - }, - "W": { - "Atomic mass": 183.84, - "Atomic no": 74, - "Atomic orbitals": { - "1s": -2341.042887, - "2p": -369.013973, - "2s": -384.856157, - "3d": -66.724787, - "3p": -80.502102, - "3s": -87.867792, - "4d": -8.879693, - "4f": -1.550835, - "4p": -14.495102, - "4s": -17.570797, - "5d": -0.220603, - "5p": -1.504457, - "5s": -2.396018, - "6s": -0.181413 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.93, - "Boiling point": "5828 K", - "Brinell hardness": "2570 MN m-2", - "Bulk modulus": "310 GPa", - "Coefficient of linear thermal expansion": "4.5 x10-6K-1", - "Common oxidation states": [ - 4, - 6 - ], - "Critical temperature": "no data K", - "Density of solid": "19250 kg m-3", - "Electrical resistivity": "5.4 10-8 Ω m", - "Electronic structure": "[Xe].4f14.5d4.6s2", - "ICSD oxidation states": [ - 2, - 3, - 4, - 5, - 6 - ], - "Ionic radii": { - "4": 0.8, - "5": 0.76, - "6": 0.74 - }, - "Liquid range": "2133 K", - "Melting point": "3695 K", - "Mendeleev no": 55, - "Mineral hardness": "7.5", - "Molar volume": "9.47 cm3", - "Name": "Tungsten", - "Oxidation states": [ - -2, - -1, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "Poissons ratio": "0.28", - "Reflectivity": "62 %", - "Refractive index": "no data", - "Rigidity modulus": "161 GPa", - "Shannon radii": { - "4": { - "VI": { - "": { - "crystal_radius": 0.8, - "ionic_radius": 0.66 - } - } - }, - "5": { - "VI": { - "": { - "crystal_radius": 0.76, - "ionic_radius": 0.62 - } - } - }, - "6": { - "IV": { - "": { - "crystal_radius": 0.56, - "ionic_radius": 0.42 - } - }, - "V": { - "": { - "crystal_radius": 0.65, - "ionic_radius": 0.51 - } - }, - "VI": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - } - } - }, - "Superconduction temperature": "0.015 K", - "Thermal conductivity": "170 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "5174 m s-1", - "Vickers hardness": "3430 MN m-2", - "X": 2.36, - "Youngs modulus": "411 GPa" - }, - "Xe": { - "Atomic mass": 131.293, - "Atomic no": 54, - "Atomic orbitals": { - "1s": -1208.688993, - "2p": -172.599583, - "2s": -183.327495, - "3d": -24.37823, - "3p": -32.867042, - "3s": -37.415454, - "4d": -2.286666, - "4p": -5.063802, - "4s": -6.67834, - "5p": -0.309835, - "5s": -0.672086 - }, - "Atomic radius": "no data", - "Atomic radius calculated": 1.08, - "Boiling point": "165.1 K", - "Brinell hardness": "no data MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "no data x10-6K-1", - "Critical temperature": "289.7 K", - "Density of solid": "no data kg m-3", - "Electrical resistivity": "no data 10-8 Ω m", - "Electronic structure": "[Kr].4d10.5s2.5p6", - "Ionic radii": { - "8": 0.62 - }, - "Liquid range": "3.7 K", - "Max oxidation state": 8.0, - "Melting point": "161.4 K", - "Mendeleev no": 5, - "Min oxidation state": 2.0, - "Mineral hardness": "no data", - "Molar volume": "35.92 cm3", - "Name": "Xenon", - "Poissons ratio": "no data", - "Reflectivity": "no data %", - "Refractive index": "1.000702", - "Rigidity modulus": "no data GPa", - "Shannon radii": { - "8": { - "IV": { - "": { - "crystal_radius": 0.54, - "ionic_radius": 0.4 - } - }, - "VI": { - "": { - "crystal_radius": 0.62, - "ionic_radius": 0.48 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "0.00565 W m-1 K-1", - "Van der waals radius": 2.16, - "Velocity of sound": "1090 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 2.6, - "Youngs modulus": "no data GPa" - }, - "Y": { - "Atomic mass": 88.90585, - "Atomic no": 39, - "Atomic orbitals": { - "1s": -605.631981, - "2p": -74.803201, - "2s": -81.789102, - "3d": -5.671499, - "3p": -10.399926, - "3s": -12.992217, - "4d": -0.108691, - "4p": -1.02449, - "4s": -1.697124, - "5s": -0.150727 - }, - "Atomic radius": 1.8, - "Atomic radius calculated": 2.12, - "Boiling point": "3609 K", - "Brinell hardness": "589 MN m-2", - "Bulk modulus": "41 GPa", - "Coefficient of linear thermal expansion": "10.6 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "4472 kg m-3", - "Electrical resistivity": "about 60 10-8 Ω m", - "Electronic structure": "[Kr].4d1.5s2", - "ICSD oxidation states": [ - 3 - ], - "Ionic radii": { - "3": 1.04 - }, - "Liquid range": "1810 K", - "Melting point": "1799 K", - "Mendeleev no": 25, - "Mineral hardness": "no data", - "Molar volume": "19.88 cm3", - "Name": "Yttrium", - "Oxidation states": [ - 1, - 2, - 3 - ], - "Poissons ratio": "0.24", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "26 GPa", - "Shannon radii": { - "3": { - "VI": { - "": { - "crystal_radius": 1.04, - "ionic_radius": 0.9 - } - }, - "VII": { - "": { - "crystal_radius": 1.1, - "ionic_radius": 0.96 - } - }, - "VIII": { - "": { - "crystal_radius": 1.159, - "ionic_radius": 1.019 - } - }, - "IX": { - "": { - "crystal_radius": 1.215, - "ionic_radius": 1.075 - } - } - } - }, - "Superconduction temperature": "1.3 (under pressure)K", - "Thermal conductivity": "17 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "3300 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.22, - "Youngs modulus": "64 GPa" - }, - "Yb": { - "Atomic mass": 173.04, - "Atomic no": 70, - "Atomic orbitals": { - "1s": -2084.069389, - "2p": -323.178219, - "2s": -337.978976, - "3d": -56.026315, - "3p": -68.698655, - "3s": -75.47663, - "4d": -6.574963, - "4f": -0.286408, - "4p": -11.558246, - "4s": -14.312076, - "5p": -0.966137, - "5s": -1.683886, - "6s": -0.136989 - }, - "Atomic radius": 1.75, - "Atomic radius calculated": 2.22, - "Boiling point": "1469 K", - "Brinell hardness": "343 MN m-2", - "Bulk modulus": "31 GPa", - "Coefficient of linear thermal expansion": "26.3 x10-6K-1", - "Common oxidation states": [ - 3 - ], - "Critical temperature": "no data K", - "Density of solid": "6570 kg m-3", - "Electrical resistivity": "25.0 10-8 Ω m", - "Electronic structure": "[Xe].4f14.6s2", - "ICSD oxidation states": [ - 2, - 3 - ], - "Ionic radii": { - "2": 1.16, - "3": 1.008 - }, - "Liquid range": "372 K", - "Melting point": "1097 K", - "Mendeleev no": 17, - "Mineral hardness": "no data", - "Molar volume": "24.84 cm3", - "Name": "Ytterbium", - "Oxidation states": [ - 2, - 3 - ], - "Poissons ratio": "0.21", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "9.9 GPa", - "Shannon radii": { - "2": { - "VI": { - "": { - "crystal_radius": 1.16, - "ionic_radius": 1.02 - } - }, - "VII": { - "": { - "crystal_radius": 1.22, - "ionic_radius": 1.08 - } - }, - "VIII": { - "": { - "crystal_radius": 1.28, - "ionic_radius": 1.14 - } - } - }, - "3": { - "VI": { - "": { - "crystal_radius": 1.008, - "ionic_radius": 0.868 - } - }, - "VII": { - "": { - "crystal_radius": 1.065, - "ionic_radius": 0.925 - } - }, - "VIII": { - "": { - "crystal_radius": 1.125, - "ionic_radius": 0.985 - } - }, - "IX": { - "": { - "crystal_radius": 1.182, - "ionic_radius": 1.042 - } - } - } - }, - "Superconduction temperature": "no data K", - "Thermal conductivity": "39 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "1590 m s-1", - "Vickers hardness": "206 MN m-2", - "X": 1.1, - "Youngs modulus": "24 GPa" - }, - "Zn": { - "Atomic mass": 65.409, - "Atomic no": 30, - "Atomic orbitals": { - "1s": -344.969756, - "2p": -36.648765, - "2s": -41.531323, - "3d": -0.398944, - "3p": -3.022363, - "3s": -4.573041, - "4s": -0.222725 - }, - "Atomic radius": 1.35, - "Atomic radius calculated": 1.42, - "Boiling point": "1180 K", - "Brinell hardness": "412 MN m-2", - "Bulk modulus": "70 GPa", - "Coefficient of linear thermal expansion": "30.2 x10-6K-1", - "Common oxidation states": [ - 2 - ], - "Critical temperature": "no data K", - "Density of solid": "7140 kg m-3", - "Electrical resistivity": "6.0 10-8 Ω m", - "Electronic structure": "[Ar].3d10.4s2", - "ICSD oxidation states": [ - 2 - ], - "Ionic radii": { - "2": 0.88 - }, - "Liquid range": "487.32 K", - "Melting point": "692.68 K", - "Mendeleev no": 76, - "Mineral hardness": "2.5", - "Molar volume": "9.16 cm3", - "Name": "Zinc", - "Oxidation states": [ - 1, - 2 - ], - "Poissons ratio": "0.25", - "Reflectivity": "80 %", - "Refractive index": "1.002050", - "Rigidity modulus": "43 GPa", - "Shannon radii": { - "2": { - "IV": { - "": { - "crystal_radius": 0.74, - "ionic_radius": 0.6 - } - }, - "V": { - "": { - "crystal_radius": 0.82, - "ionic_radius": 0.68 - } - }, - "VI": { - "": { - "crystal_radius": 0.88, - "ionic_radius": 0.74 - } - }, - "VIII": { - "": { - "crystal_radius": 1.04, - "ionic_radius": 0.9 - } - } - } - }, - "Superconduction temperature": "0.85 K", - "Thermal conductivity": "120 W m-1 K-1", - "Van der waals radius": 1.39, - "Velocity of sound": "3700 m s-1", - "Vickers hardness": "no data MN m-2", - "X": 1.65, - "Youngs modulus": "108 GPa", - "NMR Quadrupole Moment": { - "Zn-67": 150.15 - } - }, - "Zr": { - "Atomic mass": 91.224, - "Atomic no": 40, - "Atomic orbitals": { - "1s": -639.292236, - "2p": -80.010043, - "2s": -87.237062, - "3d": -6.544643, - "3p": -11.514415, - "3s": -14.230432, - "4d": -0.150673, - "4p": -1.186597, - "4s": -1.918971, - "5s": -0.162391 - }, - "Atomic radius": 1.55, - "Atomic radius calculated": 2.06, - "Boiling point": "4682 K", - "Brinell hardness": "650 MN m-2", - "Bulk modulus": "no data GPa", - "Coefficient of linear thermal expansion": "5.7 x10-6K-1", - "Common oxidation states": [ - 4 - ], - "Critical temperature": "no data K", - "Density of solid": "6511 kg m-3", - "Electrical resistivity": "43.3 10-8 Ω m", - "Electronic structure": "[Kr].4d2.5s2", - "ICSD oxidation states": [ - 2, - 3, - 4 - ], - "Ionic radii": { - "4": 0.86 - }, - "Liquid range": "2554 K", - "Melting point": "2128 K", - "Mendeleev no": 49, - "Mineral hardness": "5.0", - "Molar volume": "14.02 cm3", - "Name": "Zirconium", - "Oxidation states": [ - 1, - 2, - 3, - 4 - ], - "Poissons ratio": "0.34", - "Reflectivity": "no data %", - "Refractive index": "no data", - "Rigidity modulus": "33 GPa", - "Shannon radii": { - "4": { - "IV": { - "": { - "crystal_radius": 0.73, - "ionic_radius": 0.59 - } - }, - "V": { - "": { - "crystal_radius": 0.8, - "ionic_radius": 0.66 - } - }, - "VI": { - "": { - "crystal_radius": 0.86, - "ionic_radius": 0.72 - } - }, - "VII": { - "": { - "crystal_radius": 0.92, - "ionic_radius": 0.78 - } - }, - "VIII": { - "": { - "crystal_radius": 0.98, - "ionic_radius": 0.84 - } - }, - "IX": { - "": { - "crystal_radius": 1.03, - "ionic_radius": 0.89 - } - } - } - }, - "Superconduction temperature": "0.61 K", - "Thermal conductivity": "23 W m-1 K-1", - "Van der waals radius": "no data", - "Velocity of sound": "3800 m s-1", - "Vickers hardness": "903 MN m-2", - "X": 1.33, - "Youngs modulus": "68 GPa" - } +{ + "Ac": { + "Atomic mass": 227.0, + "Atomic no": 89, + "Atomic orbitals": { + "1s": -3443.110367, + "2p": -572.7627, + "2s": -592.622878, + "3d": -119.541743, + "3p": -137.654394, + "3s": -147.320716, + "4d": -23.57061, + "4f": -12.278225, + "4p": -31.761846, + "4s": -36.15826, + "5d": -3.222752, + "5p": -6.06511, + "5s": -7.713078, + "6d": -0.137786, + "6p": -0.744524, + "6s": -1.19698, + "7s": -0.126551 + }, + "Atomic radius": 1.95, + "Atomic radius calculated": "no data", + "Boiling point": "3573 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "10070 kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].6d1.7s2", + "Ionic radii": { + "3": 1.26 + }, + "Liquid range": "2250 K", + "Melting point": "1323 K", + "Mendeleev no": 48, + "Mineral hardness": "no data", + "Molar volume": "22.55 cm3", + "Name": "Actinium", + "Oxidation states": [ + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.26, + "ionic_radius": 1.12 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "12 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.1, + "Youngs modulus": "no data GPa" + }, + "Ag": { + "Atomic mass": 107.8682, + "Atomic no": 47, + "Atomic orbitals": { + "1s": -900.324578, + "2p": -120.913351, + "2s": -129.859807, + "3d": -13.367803, + "3p": -20.06763, + "3s": -23.678437, + "4d": -0.298706, + "4p": -2.086602, + "4s": -3.22309, + "5s": -0.157407 + }, + "Atomic radius": 1.6, + "Atomic radius calculated": 1.65, + "Boiling point": "2435 K", + "Brinell hardness": "24.5 MN m-2", + "Bulk modulus": "100 GPa", + "Coefficient of linear thermal expansion": "18.9 x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "no data K", + "Density of solid": "10490 kg m-3", + "Electrical resistivity": "1.63 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s1", + "ICSD oxidation states": [ + 1, + 2, + 3 + ], + "Ionic radii": { + "1": 1.29, + "2": 1.08, + "3": 0.89 + }, + "Liquid range": "1200.07 K", + "Melting point": "1234.93 K", + "Mendeleev no": 71, + "Mineral hardness": "2.5", + "Molar volume": "10.27 cm3", + "Name": "Silver", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "0.37", + "Reflectivity": "97 %", + "Refractive index": "no data", + "Rigidity modulus": "30 GPa", + "Shannon radii": { + "1": { + "II": { + "": { + "crystal_radius": 0.81, + "ionic_radius": 0.67 + } + }, + "IV": { + "": { + "crystal_radius": 1.14, + "ionic_radius": 1.0 + } + }, + "IVSQ": { + "": { + "crystal_radius": 1.16, + "ionic_radius": 1.02 + } + }, + "V": { + "": { + "crystal_radius": 1.23, + "ionic_radius": 1.09 + } + }, + "VI": { + "": { + "crystal_radius": 1.29, + "ionic_radius": 1.15 + } + }, + "VII": { + "": { + "crystal_radius": 1.36, + "ionic_radius": 1.22 + } + }, + "VIII": { + "": { + "crystal_radius": 1.42, + "ionic_radius": 1.28 + } + } + }, + "2": { + "IVSQ": { + "": { + "crystal_radius": 0.93, + "ionic_radius": 0.79 + } + }, + "VI": { + "": { + "crystal_radius": 1.08, + "ionic_radius": 0.94 + } + } + }, + "3": { + "IVSQ": { + "": { + "crystal_radius": 0.81, + "ionic_radius": 0.67 + } + }, + "VI": { + "": { + "crystal_radius": 0.89, + "ionic_radius": 0.75 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "430 W m-1 K-1", + "Van der waals radius": 1.72, + "Velocity of sound": "2600 m s-1", + "Vickers hardness": "251 MN m-2", + "X": 1.93, + "Youngs modulus": "83 GPa" + }, + "Al": { + "Atomic mass": 26.9815386, + "Atomic no": 13, + "Atomic orbitals": { + "1s": -55.156044, + "2p": -2.564018, + "2s": -3.934827, + "3p": -0.102545, + "3s": -0.286883 + }, + "Atomic radius": 1.25, + "Atomic radius calculated": 1.18, + "Boiling point": "2792 K", + "Brinell hardness": "245 MN m-2", + "Bulk modulus": "76 GPa", + "Coefficient of linear thermal expansion": "23.1 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "2700 kg m-3", + "Electrical resistivity": "2.7 10-8 Ω m", + "Electronic structure": "[Ne].3s2.3p1", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "3": 0.675 + }, + "Liquid range": "1858.53 K", + "Melting point": "933.47 K", + "Mendeleev no": 80, + "Mineral hardness": "2.75", + "Molar volume": "10.00 cm3", + "Name": "Aluminum", + "Oxidation states": [ + 1, + 3 + ], + "Poissons ratio": "0.35", + "Reflectivity": "71 %", + "Refractive index": "no data", + "Rigidity modulus": "26 GPa", + "Shannon radii": { + "3": { + "IV": { + "": { + "crystal_radius": 0.53, + "ionic_radius": 0.39 + } + }, + "V": { + "": { + "crystal_radius": 0.62, + "ionic_radius": 0.48 + } + }, + "VI": { + "": { + "crystal_radius": 0.675, + "ionic_radius": 0.535 + } + } + } + }, + "Superconduction temperature": "1.175 K", + "Thermal conductivity": "235 W m-1 K-1", + "Van der waals radius": 1.84, + "Velocity of sound": "5100 m s-1", + "Vickers hardness": "167 MN m-2", + "X": 1.61, + "Youngs modulus": "70 GPa", + "NMR Quadrupole Moment": { + "Al-27": 146.6 + } + }, + "Am": { + "Atomic mass": 243.0, + "Atomic no": 95, + "Atomic orbitals": "no data", + "Atomic radius": 1.75, + "Atomic radius calculated": "no data", + "Boiling point": "2880 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f7.7s2", + "Ionic radii": { + "2": 1.4, + "3": 1.115, + "4": 0.99 + }, + "Liquid range": "1431 K", + "Melting point": "1449 K", + "Mendeleev no": 42, + "Mineral hardness": "no data", + "Molar volume": "17.63 cm3", + "Name": "Americium", + "Oxidation states": [ + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "2": { + "VII": { + "": { + "crystal_radius": 1.35, + "ionic_radius": 1.21 + } + }, + "VIII": { + "": { + "crystal_radius": 1.4, + "ionic_radius": 1.26 + } + }, + "IX": { + "": { + "crystal_radius": 1.45, + "ionic_radius": 1.31 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.115, + "ionic_radius": 0.975 + } + }, + "VIII": { + "": { + "crystal_radius": 1.23, + "ionic_radius": 1.09 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.99, + "ionic_radius": 0.85 + } + }, + "VIII": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + } + } + }, + "Superconduction temperature": "0.6 K", + "Thermal conductivity": "10 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Ar": { + "Atomic mass": 39.948, + "Atomic no": 18, + "Atomic orbitals": { + "1s": -113.800134, + "2p": -8.443439, + "2s": -10.794172, + "3p": -0.38233, + "3s": -0.883384 + }, + "Atomic radius": 0.71, + "Atomic radius calculated": 0.71, + "Boiling point": "87.3 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Critical temperature": "150.8 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Ne].3s2.3p6", + "Liquid range": "3.5 K", + "Max oxidation state": 0.0, + "Melting point": "83.8 K", + "Mendeleev no": 3, + "Min oxidation state": 0.0, + "Mineral hardness": "no data", + "Molar volume": "22.56 cm3", + "Name": "Argon", + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000281", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.01772 W m-1 K-1", + "Van der waals radius": 1.88, + "Velocity of sound": "319 m s-1", + "Vickers hardness": "no data MN m-2", + "Youngs modulus": "no data GPa" + }, + "As": { + "Atomic mass": 74.9216, + "Atomic no": 33, + "Atomic orbitals": { + "1s": -423.336658, + "2p": -47.527869, + "2s": -53.093086, + "3d": -1.542767, + "3p": -4.851725, + "3s": -6.730755, + "4p": -0.197497, + "4s": -0.52367 + }, + "Atomic radius": 1.15, + "Atomic radius calculated": 1.14, + "Boiling point": "887 K", + "Brinell hardness": "1440 MN m-2", + "Bulk modulus": "22 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -3, + 3, + 5 + ], + "Critical temperature": "1700 K", + "Density of solid": "5727 kg m-3", + "Electrical resistivity": "33 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2.4p3", + "ICSD oxidation states": [ + 2, + 3, + 5, + -2, + -3, + -1 + ], + "Ionic radii": { + "3": 0.72, + "5": 0.6 + }, + "Liquid range": "203 K", + "Melting point": "1090 K", + "Mendeleev no": 89, + "Mineral hardness": "3.5", + "Molar volume": "12.95 cm3", + "Name": "Arsenic", + "Oxidation states": [ + -3, + 2, + 3, + 5 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.001552", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.475, + "ionic_radius": 0.335 + } + }, + "VI": { + "": { + "crystal_radius": 0.6, + "ionic_radius": 0.46 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "50 W m-1 K-1", + "Van der waals radius": 1.85, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.18, + "Youngs modulus": "8 GPa" + }, + "At": { + "Atomic mass": 210.0, + "Atomic no": 85, + "Atomic orbitals": { + "1s": -3127.390276, + "2p": -513.044243, + "2s": -531.81835, + "3d": -103.060375, + "3p": -119.995013, + "3s": -129.035542, + "4d": -18.295162, + "4f": -8.063483, + "4p": -25.778264, + "4s": -29.809515, + "5d": -1.643758, + "5p": -4.027061, + "5s": -5.453383, + "6p": -0.255453, + "6s": -0.560189 + }, + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -1, + 1 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2.6p5", + "Ionic radii": { + "7": 0.76 + }, + "Liquid range": "no data K", + "Melting point": "575 K", + "Mendeleev no": 96, + "Mineral hardness": "no data", + "Molar volume": "no data cm3", + "Name": "Astatine", + "Oxidation states": [ + -1, + 1, + 3, + 5 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "7": { + "VI": { + "": { + "crystal_radius": 0.76, + "ionic_radius": 0.62 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "2 (estimate)W m-1 K-1", + "Van der waals radius": 2.02, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.2, + "Youngs modulus": "no data GPa" + }, + "Au": { + "Atomic mass": 196.966569, + "Atomic no": 79, + "Atomic orbitals": { + "1s": -2683.508245, + "2p": -430.725701, + "2s": -447.888973, + "3d": -81.511751, + "3p": -96.707, + "3s": -104.824516, + "4d": -12.131815, + "4f": -3.486824, + "4p": -18.578652, + "4s": -22.078357, + "5d": -0.304738, + "5p": -2.002495, + "5s": -3.113936, + "6s": -0.162334 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.74, + "Boiling point": "3129 K", + "Brinell hardness": "2450 MN m-2", + "Bulk modulus": "220 GPa", + "Coefficient of linear thermal expansion": "14.2 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "19300 kg m-3", + "Electrical resistivity": "2.2 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s1", + "Ionic radii": { + "1": 1.51, + "3": 0.99, + "5": 0.71 + }, + "Liquid range": "1791.67 K", + "Melting point": "1337.33 K", + "Mendeleev no": 70, + "Mineral hardness": "2.5", + "Molar volume": "10.21 cm3", + "Name": "Gold", + "Oxidation states": [ + -1, + 1, + 2, + 3, + 5 + ], + "Poissons ratio": "0.44", + "Reflectivity": "95 %", + "Refractive index": "no data", + "Rigidity modulus": "27 GPa", + "Shannon radii": { + "1": { + "VI": { + "": { + "crystal_radius": 1.51, + "ionic_radius": 1.37 + } + } + }, + "3": { + "IVSQ": { + "": { + "crystal_radius": 0.82, + "ionic_radius": 0.68 + } + }, + "VI": { + "": { + "crystal_radius": 0.99, + "ionic_radius": 0.85 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "320 W m-1 K-1", + "Van der waals radius": 1.66, + "Velocity of sound": "1740 m s-1", + "Vickers hardness": "216 MN m-2", + "X": 2.54, + "Youngs modulus": "78 GPa" + }, + "B": { + "Atomic mass": 10.811, + "Atomic no": 5, + "Atomic orbitals": { + "1s": -6.564347, + "2p": -0.136603, + "2s": -0.344701 + }, + "Atomic radius": 0.85, + "Atomic radius calculated": 0.87, + "Boiling point": "4200 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "320 GPa", + "Coefficient of linear thermal expansion": "6 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "2460 kg m-3", + "Electrical resistivity": "> 101210-8 Ω m", + "Electronic structure": "[He].2s2.2p1", + "ICSD oxidation states": [ + 3, + -3 + ], + "Ionic radii": { + "3": 0.41 + }, + "Liquid range": "1851 K", + "Melting point": "2349 K", + "Mendeleev no": 86, + "Mineral hardness": "9.3", + "Molar volume": "4.39 cm3", + "Name": "Boron", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "III": { + "": { + "crystal_radius": 0.15, + "ionic_radius": 0.01 + } + }, + "IV": { + "": { + "crystal_radius": 0.25, + "ionic_radius": 0.11 + } + }, + "VI": { + "": { + "crystal_radius": 0.41, + "ionic_radius": 0.27 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "27 W m-1 K-1", + "Van der waals radius": 1.92, + "Velocity of sound": "16200 m s-1", + "Vickers hardness": "49000 MN m-2", + "X": 2.04, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "B-10": 84.59, + "B-11": 40.59 + } + }, + "Ba": { + "Atomic mass": 137.327, + "Atomic no": 56, + "Atomic orbitals": { + "1s": -1305.743258, + "2p": -189.598483, + "2s": -200.844444, + "3d": -28.528933, + "3p": -37.536931, + "3s": -42.359434, + "4d": -3.432441, + "4p": -6.497622, + "4s": -8.257061, + "5p": -0.698605, + "5s": -1.157159, + "6s": -0.118967 + }, + "Atomic radius": 2.15, + "Atomic radius calculated": 2.53, + "Boiling point": "2143 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "9.6 GPa", + "Coefficient of linear thermal expansion": "20.6 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "3510 kg m-3", + "Electrical resistivity": "34 10-8 Ω m", + "Electronic structure": "[Xe].6s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 1.49 + }, + "Liquid range": "1143 K", + "Melting point": "1000 K", + "Mendeleev no": 14, + "Mineral hardness": "1.25", + "Molar volume": "38.16 cm3", + "Name": "Barium", + "Oxidation states": [ + 2 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "4.9 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.49, + "ionic_radius": 1.35 + } + }, + "VII": { + "": { + "crystal_radius": 1.52, + "ionic_radius": 1.38 + } + }, + "VIII": { + "": { + "crystal_radius": 1.56, + "ionic_radius": 1.42 + } + }, + "IX": { + "": { + "crystal_radius": 1.61, + "ionic_radius": 1.47 + } + }, + "X": { + "": { + "crystal_radius": 1.66, + "ionic_radius": 1.52 + } + }, + "XI": { + "": { + "crystal_radius": 1.71, + "ionic_radius": 1.57 + } + }, + "XII": { + "": { + "crystal_radius": 1.75, + "ionic_radius": 1.61 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "18 W m-1 K-1", + "Van der waals radius": 2.68, + "Velocity of sound": "1620 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.89, + "Youngs modulus": "13 GPa" + }, + "Be": { + "Atomic mass": 9.012182, + "Atomic no": 4, + "Atomic orbitals": { + "1s": -3.856411, + "2s": -0.205744 + }, + "Atomic radius": 1.05, + "Atomic radius calculated": 1.12, + "Boiling point": "2742 K", + "Brinell hardness": "600 MN m-2", + "Bulk modulus": "130 GPa", + "Coefficient of linear thermal expansion": "11.3 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "1848 kg m-3", + "Electrical resistivity": "3.8 10-8 Ω m", + "Electronic structure": "[He].2s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 0.59 + }, + "Liquid range": "1182 K", + "Melting point": "1560 K", + "Mendeleev no": 77, + "Mineral hardness": "5.5", + "Molar volume": "4.85 cm3", + "Name": "Beryllium", + "Oxidation states": [ + 2 + ], + "Poissons ratio": "0.032", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "132 GPa", + "Shannon radii": { + "2": { + "III": { + "": { + "crystal_radius": 0.3, + "ionic_radius": 0.16 + } + }, + "IV": { + "": { + "crystal_radius": 0.41, + "ionic_radius": 0.27 + } + }, + "VI": { + "": { + "crystal_radius": 0.59, + "ionic_radius": 0.45 + } + } + } + }, + "Superconduction temperature": "0.026 K", + "Thermal conductivity": "190 W m-1 K-1", + "Van der waals radius": 1.53, + "Velocity of sound": "13000 m s-1", + "Vickers hardness": "1670 MN m-2", + "X": 1.57, + "Youngs modulus": "287 GPa", + "NMR Quadrupole Moment": { + "Be-9": 52.88 + } + }, + "Bi": { + "Atomic mass": 208.9804, + "Atomic no": 83, + "Atomic orbitals": { + "1s": -2975.550959, + "2p": -484.716359, + "2s": -502.950758, + "3d": -95.532476, + "3p": -111.883393, + "3s": -120.613998, + "4d": -16.084817, + "4f": -6.382744, + "4p": -23.218641, + "4s": -27.07034, + "5d": -1.139408, + "5p": -3.293637, + "5s": -4.611934, + "6p": -0.180198, + "6s": -0.426129 + }, + "Atomic radius": 1.6, + "Atomic radius calculated": 1.43, + "Boiling point": "1837 K", + "Brinell hardness": "94.2 MN m-2", + "Bulk modulus": "31 GPa", + "Coefficient of linear thermal expansion": "13.4 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "9780 kg m-3", + "Electrical resistivity": "130 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2.6p3", + "ICSD oxidation states": [ + 1, + 2, + 3, + 5 + ], + "Ionic radii": { + "3": 1.17, + "5": 0.9 + }, + "Liquid range": "1292.6 K", + "Melting point": "544.4 K", + "Mendeleev no": 87, + "Mineral hardness": "2.25", + "Molar volume": "21.31 cm3", + "Name": "Bismuth", + "Oxidation states": [ + -3, + 3, + 5 + ], + "Poissons ratio": "0.33", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "12 GPa", + "Shannon radii": { + "3": { + "V": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + }, + "VI": { + "": { + "crystal_radius": 1.17, + "ionic_radius": 1.03 + } + }, + "VIII": { + "": { + "crystal_radius": 1.31, + "ionic_radius": 1.17 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "8 W m-1 K-1", + "Van der waals radius": 2.07, + "Velocity of sound": "1790 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.02, + "Youngs modulus": "32 GPa" + }, + "Bk": { + "Atomic mass": 247.0, + "Atomic no": 97, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "14780 kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f9.7s2", + "Ionic radii": { + "3": 1.1, + "4": 0.97 + }, + "Liquid range": "no data K", + "Melting point": "1259 K", + "Mendeleev no": 40, + "Mineral hardness": "no data", + "Molar volume": "16.84 cm3", + "Name": "Berkelium", + "Oxidation states": [ + 3, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.97, + "ionic_radius": 0.83 + } + }, + "VIII": { + "": { + "crystal_radius": 1.07, + "ionic_radius": 0.93 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "10 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Br": { + "Atomic mass": 79.904, + "Atomic no": 35, + "Atomic orbitals": { + "1s": -480.182643, + "2p": -55.67796, + "2s": -61.710022, + "3d": -2.52211, + "3p": -6.298805, + "3s": -8.409057, + "4p": -0.295334, + "4s": -0.720066 + }, + "Atomic radius": 1.15, + "Atomic radius calculated": 0.94, + "Boiling point": "332 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "1.9 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -1, + 1, + 3, + 5, + 7 + ], + "Critical temperature": "586 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "> 101810-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2.4p5", + "ICSD oxidation states": [ + 5, + -1 + ], + "Ionic radii": { + "-1": 1.82, + "3": 0.73, + "5": 0.45, + "7": 0.53 + }, + "Liquid range": "66.2 K", + "Melting point": "265.8 K", + "Mendeleev no": 98, + "Mineral hardness": "no data", + "Molar volume": "19.78 cm3", + "Name": "Bromine", + "Oxidation states": [ + -1, + 1, + 3, + 4, + 5, + 7 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.001132", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-1": { + "VI": { + "": { + "crystal_radius": 1.82, + "ionic_radius": 1.96 + } + } + }, + "3": { + "IVSQ": { + "": { + "crystal_radius": 0.73, + "ionic_radius": 0.59 + } + } + }, + "5": { + "IIIPY": { + "": { + "crystal_radius": 0.45, + "ionic_radius": 0.31 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.39, + "ionic_radius": 0.25 + } + }, + "VI": { + "": { + "crystal_radius": 0.53, + "ionic_radius": 0.39 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.12 W m-1 K-1", + "Van der waals radius": 1.85, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.96, + "Youngs modulus": "no data GPa" + }, + "C": { + "Atomic mass": 12.0107, + "Atomic no": 6, + "Atomic orbitals": { + "1s": -9.947718, + "2p": -0.199186, + "2s": -0.500866 + }, + "Atomic radius": 0.7, + "Atomic radius calculated": 0.67, + "Boiling point": "4300 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "33 GPa", + "Coefficient of linear thermal expansion": "7.1 x10-6K-1", + "Common oxidation states": [ + -4, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "2267 kg m-3", + "Electrical resistivity": "about 1000 - direction dependent10-8 Ω m", + "Electronic structure": "[He].2s2.2p2", + "ICSD oxidation states": [ + 2, + 3, + 4, + -4, + -3, + -2 + ], + "Ionic radii": { + "4": 0.3 + }, + "Liquid range": "500 K", + "Melting point": "3800 K", + "Mendeleev no": 95, + "Mineral hardness": "0.5 (graphite; diamond is 10.0)(no units)", + "Molar volume": "5.29 cm3", + "Name": "Carbon", + "Oxidation states": [ + -4, + -3, + -2, + -1, + 1, + 2, + 3, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "27 %", + "Refractive index": "2.417 (diamond)(no units)", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "4": { + "III": { + "": { + "crystal_radius": 0.06, + "ionic_radius": -0.08 + } + }, + "IV": { + "": { + "crystal_radius": 0.29, + "ionic_radius": 0.15 + } + }, + "VI": { + "": { + "crystal_radius": 0.3, + "ionic_radius": 0.16 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "140 W m-1 K-1", + "Van der waals radius": 1.7, + "Velocity of sound": "18350 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.55, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "C-11": 33.27 + } + }, + "Ca": { + "Atomic mass": 40.078, + "Atomic no": 20, + "Atomic orbitals": { + "1s": -143.935181, + "2p": -12.285376, + "2s": -15.046905, + "3p": -1.030572, + "3s": -1.706331, + "4s": -0.141411 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": 1.94, + "Boiling point": "1757 K", + "Brinell hardness": "167 MN m-2", + "Bulk modulus": "17 GPa", + "Coefficient of linear thermal expansion": "22.3 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "1550 kg m-3", + "Electrical resistivity": "3.4 10-8 Ω m", + "Electronic structure": "[Ar].4s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 1.14 + }, + "Liquid range": "642 K", + "Melting point": "1115 K", + "Mendeleev no": 16, + "Mineral hardness": "1.75", + "Molar volume": "26.20 cm3", + "Name": "Calcium", + "Oxidation states": [ + 2 + ], + "Poissons ratio": "0.31", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "7.4 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.14, + "ionic_radius": 1.0 + } + }, + "VII": { + "": { + "crystal_radius": 1.2, + "ionic_radius": 1.06 + } + }, + "VIII": { + "": { + "crystal_radius": 1.26, + "ionic_radius": 1.12 + } + }, + "IX": { + "": { + "crystal_radius": 1.32, + "ionic_radius": 1.18 + } + }, + "X": { + "": { + "crystal_radius": 1.37, + "ionic_radius": 1.23 + } + }, + "XII": { + "": { + "crystal_radius": 1.48, + "ionic_radius": 1.34 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "200 W m-1 K-1", + "Van der waals radius": 2.31, + "Velocity of sound": "3810 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.0, + "Youngs modulus": "20 GPa", + "NMR Quadrupole Moment": { + "Ca-41": -66.5, + "Ca-43": -40.8 + } + }, + "Cd": { + "Atomic mass": 112.411, + "Atomic no": 48, + "Atomic orbitals": { + "1s": -941.476646, + "2p": -127.63512, + "2s": -136.83249, + "3d": -14.685252, + "3p": -21.637522, + "3s": -25.379908, + "4d": -0.47053, + "4p": -2.39526, + "4s": -3.596069, + "5s": -0.204228 + }, + "Atomic radius": 1.55, + "Atomic radius calculated": 1.61, + "Boiling point": "1040 K", + "Brinell hardness": "203 MN m-2", + "Bulk modulus": "42 GPa", + "Coefficient of linear thermal expansion": "30.8 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "8650 kg m-3", + "Electrical resistivity": "7 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 1.09 + }, + "Liquid range": "445.78 K", + "Melting point": "594.22 K", + "Mendeleev no": 75, + "Mineral hardness": "2.0", + "Molar volume": "13.00 cm3", + "Name": "Cadmium", + "Oxidation states": [ + 1, + 2 + ], + "Poissons ratio": "0.30", + "Reflectivity": "67 %", + "Refractive index": "no data", + "Rigidity modulus": "19 GPa", + "Shannon radii": { + "2": { + "IV": { + "": { + "crystal_radius": 0.92, + "ionic_radius": 0.78 + } + }, + "V": { + "": { + "crystal_radius": 1.01, + "ionic_radius": 0.87 + } + }, + "VI": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + }, + "VII": { + "": { + "crystal_radius": 1.17, + "ionic_radius": 1.03 + } + }, + "VIII": { + "": { + "crystal_radius": 1.24, + "ionic_radius": 1.1 + } + }, + "XII": { + "": { + "crystal_radius": 1.45, + "ionic_radius": 1.31 + } + } + } + }, + "Superconduction temperature": "0.517 K", + "Thermal conductivity": "97 W m-1 K-1", + "Van der waals radius": 1.58, + "Velocity of sound": "2310 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.69, + "Youngs modulus": "50 GPa" + }, + "Ce": { + "Atomic mass": 140.116, + "Atomic no": 58, + "Atomic orbitals": { + "1s": -1406.148284, + "2p": -206.925148, + "2s": -218.684842, + "3d": -32.412569, + "3p": -41.938282, + "3s": -47.035283, + "4d": -4.192548, + "4f": -0.337442, + "4p": -7.532106, + "4s": -9.432744, + "5d": -0.14055, + "5p": -0.85011, + "5s": -1.369728, + "6s": -0.133974 + }, + "Atomic radius": 1.85, + "Atomic radius calculated": "no data", + "Boiling point": "3633 K", + "Brinell hardness": "412 MN m-2", + "Bulk modulus": "22 GPa", + "Coefficient of linear thermal expansion": "6.3 x10-6K-1", + "Common oxidation states": [ + 3, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "6689 kg m-3", + "Electrical resistivity": "74 10-8 Ω m", + "Electronic structure": "[Xe].4f1.5d1.6s2", + "ICSD oxidation states": [ + 3, + 4 + ], + "Ionic radii": { + "3": 1.15, + "4": 1.01 + }, + "Liquid range": "2565 K", + "Melting point": "1068 K", + "Mendeleev no": 32, + "Mineral hardness": "2.5", + "Molar volume": "20.69 cm3", + "Name": "Cerium", + "Oxidation states": [ + 2, + 3, + 4 + ], + "Poissons ratio": "0.24", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "14 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.15, + "ionic_radius": 1.01 + } + }, + "VII": { + "": { + "crystal_radius": 1.21, + "ionic_radius": 1.07 + } + }, + "VIII": { + "": { + "crystal_radius": 1.283, + "ionic_radius": 1.143 + } + }, + "IX": { + "": { + "crystal_radius": 1.336, + "ionic_radius": 1.196 + } + }, + "X": { + "": { + "crystal_radius": 1.39, + "ionic_radius": 1.25 + } + }, + "XII": { + "": { + "crystal_radius": 1.48, + "ionic_radius": 1.34 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 1.01, + "ionic_radius": 0.87 + } + }, + "VIII": { + "": { + "crystal_radius": 1.11, + "ionic_radius": 0.97 + } + }, + "X": { + "": { + "crystal_radius": 1.21, + "ionic_radius": 1.07 + } + }, + "XII": { + "": { + "crystal_radius": 1.28, + "ionic_radius": 1.14 + } + } + } + }, + "Superconduction temperature": "0.022 (under pressure)K", + "Thermal conductivity": "11 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2100 m s-1", + "Vickers hardness": "270 MN m-2", + "X": 1.12, + "Youngs modulus": "34 GPa" + }, + "Cf": { + "Atomic mass": 251.0, + "Atomic no": 98, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "15100 kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f10.7s2", + "Ionic radii": { + "3": 1.09, + "4": 0.961 + }, + "Liquid range": "no data K", + "Melting point": "1173 K", + "Mendeleev no": 39, + "Mineral hardness": "no data", + "Molar volume": "16.50 cm3", + "Name": "Californium", + "Oxidation states": [ + 2, + 3, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.961, + "ionic_radius": 0.821 + } + }, + "VIII": { + "": { + "crystal_radius": 1.06, + "ionic_radius": 0.92 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Cl": { + "Atomic mass": 35.453, + "Atomic no": 17, + "Atomic orbitals": { + "1s": -100.369229, + "2p": -7.039982, + "2s": -9.187993, + "3p": -0.32038, + "3s": -0.754458 + }, + "Atomic radius": 1.0, + "Atomic radius calculated": 0.79, + "Boiling point": "239.11 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "1.1 (liquid)GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -1, + 1, + 3, + 5, + 7 + ], + "Critical temperature": "417 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "> 101010-8 Ω m", + "Electronic structure": "[Ne].3s2.3p5", + "ICSD oxidation states": [ + -1 + ], + "Ionic radii": { + "-1": 1.67, + "5": 0.26, + "7": 0.41 + }, + "Liquid range": "67.51 K", + "Melting point": "171.6 K", + "Mendeleev no": 99, + "Mineral hardness": "no data", + "Molar volume": "17.39 cm3", + "Name": "Chlorine", + "Oxidation states": [ + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000773", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-1": { + "VI": { + "": { + "crystal_radius": 1.67, + "ionic_radius": 1.81 + } + } + }, + "5": { + "IIIPY": { + "": { + "crystal_radius": 0.26, + "ionic_radius": 0.12 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.22, + "ionic_radius": 0.08 + } + }, + "VI": { + "": { + "crystal_radius": 0.41, + "ionic_radius": 0.27 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.0089 W m-1 K-1", + "Van der waals radius": 1.75, + "Velocity of sound": "206 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 3.16, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "Cl-35": -81.65, + "Cl-37": -64.35 + } + }, + "Cm": { + "Atomic mass": 247.0, + "Atomic no": 96, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "3383 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "13510 kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f7.6d1.7s2", + "Ionic radii": { + "3": 1.11, + "4": 0.99 + }, + "Liquid range": "1770 K", + "Melting point": "1613 K", + "Mendeleev no": 41, + "Mineral hardness": "no data", + "Molar volume": "18.05 cm3", + "Name": "Curium", + "Oxidation states": [ + 3, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.11, + "ionic_radius": 0.97 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.99, + "ionic_radius": 0.85 + } + }, + "VIII": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "8.8 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Co": { + "Atomic mass": 58.933195, + "Atomic no": 27, + "Atomic orbitals": { + "1s": -275.616639, + "2p": -28.152095, + "2s": -32.379758, + "3d": -0.322368, + "3p": -2.388285, + "3s": -3.651812, + "4s": -0.204497 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.52, + "Boiling point": "3200 K", + "Brinell hardness": "700 MN m-2", + "Bulk modulus": "180 GPa", + "Coefficient of linear thermal expansion": "13.0 x10-6K-1", + "Common oxidation states": [ + 2, + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "8900 kg m-3", + "Electrical resistivity": "6 10-8 Ω m", + "Electronic structure": "[Ar].3d7.4s2", + "ICSD oxidation states": [ + 1, + 2, + 3, + 4 + ], + "Ionic radii": { + "2": 0.885, + "3": 0.75, + "4": 0.67 + }, + "Ionic radii hs": { + "2": 0.885, + "3": 0.75, + "4": 0.67 + }, + "Ionic radii ls": { + "2": 0.79, + "3": 0.685 + }, + "Liquid range": "1432 K", + "Melting point": "1768 K", + "Mendeleev no": 64, + "Mineral hardness": "5.0", + "Molar volume": "6.67 cm3", + "Name": "Cobalt", + "Oxidation states": [ + -1, + 1, + 2, + 3, + 4, + 5 + ], + "Poissons ratio": "0.31", + "Reflectivity": "67 %", + "Refractive index": "no data", + "Rigidity modulus": "75 GPa", + "Shannon radii": { + "2": { + "IV": { + "High Spin": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + }, + "V": { + "": { + "crystal_radius": 0.81, + "ionic_radius": 0.67 + } + }, + "VI": { + "Low Spin": { + "crystal_radius": 0.79, + "ionic_radius": 0.65 + }, + "High Spin": { + "crystal_radius": 0.885, + "ionic_radius": 0.745 + } + }, + "VIII": { + "": { + "crystal_radius": 1.04, + "ionic_radius": 0.9 + } + } + }, + "3": { + "VI": { + "High Spin": { + "crystal_radius": 0.75, + "ionic_radius": 0.61 + }, + "Low Spin": { + "crystal_radius": 0.685, + "ionic_radius": 0.545 + } + } + }, + "4": { + "IV": { + "": { + "crystal_radius": 0.54, + "ionic_radius": 0.4 + } + }, + "VI": { + "High Spin": { + "crystal_radius": 0.67, + "ionic_radius": 0.53 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "100 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4720 m s-1", + "Vickers hardness": "1043 MN m-2", + "X": 1.88, + "Youngs modulus": "209 GPa", + "NMR Quadrupole Moment": { + "Co-59": 420.3 + } + }, + "Cr": { + "Atomic mass": 51.9961, + "Atomic no": 24, + "Atomic orbitals": { + "1s": -213.881191, + "2p": -20.526273, + "2s": -24.113457, + "3d": -0.118123, + "3p": -1.65423, + "3s": -2.649085, + "4s": -0.150445 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.66, + "Boiling point": "2944 K", + "Brinell hardness": "1120 MN m-2", + "Bulk modulus": "160 GPa", + "Coefficient of linear thermal expansion": "4.9 x10-6K-1", + "Common oxidation states": [ + 3, + 6 + ], + "Critical temperature": "no data K", + "Density of solid": "7140 kg m-3", + "Electrical resistivity": "12.7 10-8 Ω m", + "Electronic structure": "[Ar].3d5.4s1", + "ICSD oxidation states": [ + 2, + 3, + 4, + 5, + 6 + ], + "Ionic radii": { + "2": 0.94 + }, + "Ionic radii hs": { + "2": 0.94 + }, + "Ionic radii ls": { + "2": 0.87, + "3": 0.755, + "4": 0.69, + "5": 0.63, + "6": 0.58 + }, + "Liquid range": "764 K", + "Melting point": "2180 K", + "Mendeleev no": 57, + "Mineral hardness": "8.5", + "Molar volume": "7.23 cm3", + "Name": "Chromium", + "Oxidation states": [ + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.21", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "115 GPa", + "Shannon radii": { + "2": { + "VI": { + "Low Spin": { + "crystal_radius": 0.87, + "ionic_radius": 0.73 + }, + "High Spin": { + "crystal_radius": 0.94, + "ionic_radius": 0.8 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 0.755, + "ionic_radius": 0.615 + } + } + }, + "4": { + "IV": { + "": { + "crystal_radius": 0.55, + "ionic_radius": 0.41 + } + }, + "VI": { + "": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.485, + "ionic_radius": 0.345 + } + }, + "VI": { + "": { + "crystal_radius": 0.63, + "ionic_radius": 0.49 + } + }, + "VIII": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.4, + "ionic_radius": 0.26 + } + }, + "VI": { + "": { + "crystal_radius": 0.58, + "ionic_radius": 0.44 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "94 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "5940 m s-1", + "Vickers hardness": "1060 MN m-2", + "X": 1.66, + "Youngs modulus": "279 GPa", + "NMR Quadrupole Moment": { + "Cr-53": -150.5 + } + }, + "Cs": { + "Atomic mass": 132.9054519, + "Atomic no": 55, + "Atomic orbitals": { + "1s": -1256.738791, + "2p": -180.995344, + "2s": -191.981873, + "3d": -26.418398, + "3p": -35.166423, + "3s": -39.851584, + "4d": -2.848386, + "4p": -5.769326, + "4s": -7.455966, + "5p": -0.504903, + "5s": -0.915819, + "6s": -0.078699 + }, + "Atomic radius": 2.6, + "Atomic radius calculated": 2.98, + "Boiling point": "944 K", + "Brinell hardness": "0.14 MN m-2", + "Bulk modulus": "1.6 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "1938 K", + "Density of solid": "1879 kg m-3", + "Electrical resistivity": "21 10-8 Ω m", + "Electronic structure": "[Xe].6s1", + "ICSD oxidation states": [ + 1 + ], + "Ionic radii": { + "1": 1.81 + }, + "Liquid range": "642.41 K", + "Melting point": "301.59 K", + "Mendeleev no": 8, + "Mineral hardness": "0.2", + "Molar volume": "70.94 cm3", + "Name": "Cesium", + "Oxidation states": [ + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "1": { + "VI": { + "": { + "crystal_radius": 1.81, + "ionic_radius": 1.67 + } + }, + "VIII": { + "": { + "crystal_radius": 1.88, + "ionic_radius": 1.74 + } + }, + "IX": { + "": { + "crystal_radius": 1.92, + "ionic_radius": 1.78 + } + }, + "X": { + "": { + "crystal_radius": 1.95, + "ionic_radius": 1.81 + } + }, + "XI": { + "": { + "crystal_radius": 1.99, + "ionic_radius": 1.85 + } + }, + "XII": { + "": { + "crystal_radius": 2.02, + "ionic_radius": 1.88 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "36 W m-1 K-1", + "Van der waals radius": 3.43, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.79, + "Youngs modulus": "1.7 GPa" + }, + "Cu": { + "Atomic mass": 63.546, + "Atomic no": 29, + "Atomic orbitals": { + "1s": -320.78852, + "2p": -33.481247, + "2s": -38.14131, + "3d": -0.202272, + "3p": -2.609244, + "3s": -4.057453, + "4s": -0.172056 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.45, + "Boiling point": "3200 K", + "Brinell hardness": "874 MN m-2", + "Bulk modulus": "140 GPa", + "Coefficient of linear thermal expansion": "16.5 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "8920 kg m-3", + "Electrical resistivity": "1.72 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s1", + "ICSD oxidation states": [ + 1, + 2, + 3 + ], + "Ionic radii": { + "1": 0.91, + "2": 0.87, + "3": 0.68 + }, + "Liquid range": "1842.23 K", + "Melting point": "1357.77 K", + "Mendeleev no": 72, + "Mineral hardness": "3.0", + "Molar volume": "7.11 cm3", + "Name": "Copper", + "Oxidation states": [ + 1, + 2, + 3, + 4 + ], + "Poissons ratio": "0.34", + "Reflectivity": "90 %", + "Refractive index": "no data", + "Rigidity modulus": "48 GPa", + "Shannon radii": { + "1": { + "II": { + "": { + "crystal_radius": 0.6, + "ionic_radius": 0.46 + } + }, + "IV": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + }, + "VI": { + "": { + "crystal_radius": 0.91, + "ionic_radius": 0.77 + } + } + }, + "2": { + "IV": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + }, + "IVSQ": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + }, + "V": { + "": { + "crystal_radius": 0.79, + "ionic_radius": 0.65 + } + }, + "VI": { + "": { + "crystal_radius": 0.87, + "ionic_radius": 0.73 + } + } + }, + "3": { + "VI": { + "Low Spin": { + "crystal_radius": 0.68, + "ionic_radius": 0.54 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "400 W m-1 K-1", + "Van der waals radius": 1.4, + "Velocity of sound": "3570 m s-1", + "Vickers hardness": "369 MN m-2", + "X": 1.9, + "Youngs modulus": "130 GPa", + "NMR Quadrupole Moment": { + "Cu-63": -220.15, + "Cu-65": -204.14 + } + }, + "Dy": { + "Atomic mass": 162.5, + "Atomic no": 66, + "Atomic orbitals": { + "1s": -1843.229585, + "2p": -281.558531, + "2s": -295.342856, + "3d": -47.4867, + "3p": -59.091931, + "3s": -65.299442, + "4d": -5.686352, + "4f": -0.265302, + "4p": -10.094091, + "4s": -12.551251, + "5p": -0.90349, + "5s": -1.547977, + "6s": -0.132769 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": 2.28, + "Boiling point": "2840 K", + "Brinell hardness": "500 MN m-2", + "Bulk modulus": "41 GPa", + "Coefficient of linear thermal expansion": "9.9 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "8551 kg m-3", + "Electrical resistivity": "92.6 10-8 Ω m", + "Electronic structure": "[Xe].4f10.6s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "2": 1.21, + "3": 1.052 + }, + "Liquid range": "1160 K", + "Melting point": "1680 K", + "Mendeleev no": 24, + "Mineral hardness": "no data", + "Molar volume": "19.01 cm3", + "Name": "Dysprosium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.25", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "25 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.21, + "ionic_radius": 1.07 + } + }, + "VII": { + "": { + "crystal_radius": 1.27, + "ionic_radius": 1.13 + } + }, + "VIII": { + "": { + "crystal_radius": 1.33, + "ionic_radius": 1.19 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.052, + "ionic_radius": 0.912 + } + }, + "VII": { + "": { + "crystal_radius": 1.11, + "ionic_radius": 0.97 + } + }, + "VIII": { + "": { + "crystal_radius": 1.167, + "ionic_radius": 1.027 + } + }, + "IX": { + "": { + "crystal_radius": 1.223, + "ionic_radius": 1.083 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "11 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2710 m s-1", + "Vickers hardness": "540 MN m-2", + "X": 1.22, + "Youngs modulus": "61 GPa" + }, + "Er": { + "Atomic mass": 167.259, + "Atomic no": 68, + "Atomic orbitals": { + "1s": -1961.799176, + "2p": -302.01827, + "2s": -316.310631, + "3d": -51.682149, + "3p": -63.818655, + "3s": -70.310142, + "4d": -6.127443, + "4f": -0.278577, + "4p": -10.819574, + "4s": -13.423547, + "5p": -0.935202, + "5s": -1.616073, + "6s": -0.134905 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": 2.26, + "Boiling point": "3141 K", + "Brinell hardness": "814 MN m-2", + "Bulk modulus": "44 GPa", + "Coefficient of linear thermal expansion": "12.2 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "9066 kg m-3", + "Electrical resistivity": "86.0 10-8 Ω m", + "Electronic structure": "[Xe].4f12.6s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "3": 1.03 + }, + "Liquid range": "1371 K", + "Melting point": "1802 K", + "Mendeleev no": 22, + "Mineral hardness": "no data", + "Molar volume": "18.46 cm3", + "Name": "Erbium", + "Oxidation states": [ + 3 + ], + "Poissons ratio": "0.24", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "28 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.03, + "ionic_radius": 0.89 + } + }, + "VII": { + "": { + "crystal_radius": 1.085, + "ionic_radius": 0.945 + } + }, + "VIII": { + "": { + "crystal_radius": 1.144, + "ionic_radius": 1.004 + } + }, + "IX": { + "": { + "crystal_radius": 1.202, + "ionic_radius": 1.062 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "15 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2830 m s-1", + "Vickers hardness": "589 MN m-2", + "X": 1.24, + "Youngs modulus": "70 GPa" + }, + "Es": { + "Atomic mass": 252.0, + "Atomic no": 99, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f11.7s2", + "Liquid range": "no data K", + "Melting point": "1133 K", + "Mendeleev no": 38, + "Mineral hardness": "no data", + "Molar volume": "28.52 cm3", + "Name": "Einsteinium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Eu": { + "Atomic mass": 151.964, + "Atomic no": 63, + "Atomic orbitals": { + "1s": -1672.309322, + "2p": -252.176697, + "2s": -265.199534, + "3d": -41.465518, + "3p": -52.281987, + "3s": -58.068128, + "4d": -5.03242, + "4f": -0.232773, + "4p": -9.025455, + "4s": -11.267747, + "5p": -0.853575, + "5s": -1.444087, + "6s": -0.129426 + }, + "Atomic radius": 1.85, + "Atomic radius calculated": 2.31, + "Boiling point": "1800 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "8.3 GPa", + "Coefficient of linear thermal expansion": "35 x10-6K-1", + "Common oxidation states": [ + 2, + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "5244 kg m-3", + "Electrical resistivity": "90 10-8 Ω m", + "Electronic structure": "[Xe].4f7.6s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "2": 1.31, + "3": 1.087 + }, + "Liquid range": "701 K", + "Melting point": "1099 K", + "Mendeleev no": 18, + "Mineral hardness": "no data", + "Molar volume": "28.97 cm3", + "Name": "Europium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.15", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "7.9 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.31, + "ionic_radius": 1.17 + } + }, + "VII": { + "": { + "crystal_radius": 1.34, + "ionic_radius": 1.2 + } + }, + "VIII": { + "": { + "crystal_radius": 1.39, + "ionic_radius": 1.25 + } + }, + "IX": { + "": { + "crystal_radius": 1.44, + "ionic_radius": 1.3 + } + }, + "X": { + "": { + "crystal_radius": 1.49, + "ionic_radius": 1.35 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.087, + "ionic_radius": 0.947 + } + }, + "VII": { + "": { + "crystal_radius": 1.15, + "ionic_radius": 1.01 + } + }, + "VIII": { + "": { + "crystal_radius": 1.206, + "ionic_radius": 1.066 + } + }, + "IX": { + "": { + "crystal_radius": 1.26, + "ionic_radius": 1.12 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "14 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "167 MN m-2", + "X": 1.2, + "Youngs modulus": "18 GPa" + }, + "F": { + "Atomic mass": 18.9984032, + "Atomic no": 9, + "Atomic orbitals": { + "1s": -24.189391, + "2p": -0.415606, + "2s": -1.086859 + }, + "Atomic radius": 0.5, + "Atomic radius calculated": 0.42, + "Boiling point": "85.03 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -1 + ], + "Critical temperature": "144 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[He].2s2.2p5", + "ICSD oxidation states": [ + -1 + ], + "Ionic radii": { + "-1": 1.19, + "7": 0.22 + }, + "Liquid range": "31.5 K", + "Melting point": "53.53 K", + "Mendeleev no": 102, + "Mineral hardness": "no data", + "Molar volume": "11.20 cm3", + "Name": "Fluorine", + "Oxidation states": [ + -1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000195", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-1": { + "II": { + "": { + "crystal_radius": 1.145, + "ionic_radius": 1.285 + } + }, + "III": { + "": { + "crystal_radius": 1.16, + "ionic_radius": 1.3 + } + }, + "IV": { + "": { + "crystal_radius": 1.17, + "ionic_radius": 1.31 + } + }, + "VI": { + "": { + "crystal_radius": 1.19, + "ionic_radius": 1.33 + } + } + }, + "7": { + "VI": { + "": { + "crystal_radius": 0.22, + "ionic_radius": 0.08 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.0277 W m-1 K-1", + "Van der waals radius": 1.47, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 3.98, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "F-19": -94.2 + } + }, + "Fe": { + "Atomic mass": 55.845, + "Atomic no": 26, + "Atomic orbitals": { + "1s": -254.225505, + "2p": -25.551766, + "2s": -29.56486, + "3d": -0.295049, + "3p": -2.187523, + "3s": -3.360621, + "4s": -0.197978 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.56, + "Boiling point": "3134 K", + "Brinell hardness": "490 MN m-2", + "Bulk modulus": "170 GPa", + "Coefficient of linear thermal expansion": "11.8 x10-6K-1", + "Common oxidation states": [ + 2, + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "7874 kg m-3", + "Electrical resistivity": "10 10-8 Ω m", + "Electronic structure": "[Ar].3d6.4s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "2": 0.92, + "3": 0.785 + }, + "Ionic radii hs": { + "2": 0.92, + "3": 0.785 + }, + "Ionic radii ls": { + "2": 0.75, + "3": 0.69, + "4": 0.725, + "6": 0.39 + }, + "Liquid range": "1323 K", + "Melting point": "1811 K", + "Mendeleev no": 61, + "Mineral hardness": "4.0", + "Molar volume": "7.09 cm3", + "Name": "Iron", + "Oxidation states": [ + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.29", + "Reflectivity": "65 %", + "Refractive index": "no data", + "Rigidity modulus": "82 GPa", + "Shannon radii": { + "2": { + "IV": { + "High Spin": { + "crystal_radius": 0.77, + "ionic_radius": 0.63 + } + }, + "IVSQ": { + "High Spin": { + "crystal_radius": 0.78, + "ionic_radius": 0.64 + } + }, + "VI": { + "Low Spin": { + "crystal_radius": 0.75, + "ionic_radius": 0.61 + }, + "High Spin": { + "crystal_radius": 0.92, + "ionic_radius": 0.78 + } + }, + "VIII": { + "High Spin": { + "crystal_radius": 1.06, + "ionic_radius": 0.92 + } + } + }, + "3": { + "IV": { + "High Spin": { + "crystal_radius": 0.63, + "ionic_radius": 0.49 + } + }, + "V": { + "": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + }, + "VI": { + "Low Spin": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + }, + "High Spin": { + "crystal_radius": 0.785, + "ionic_radius": 0.645 + } + }, + "VIII": { + "High Spin": { + "crystal_radius": 0.92, + "ionic_radius": 0.78 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.725, + "ionic_radius": 0.585 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.39, + "ionic_radius": 0.25 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "80 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4910 m s-1", + "Vickers hardness": "608 MN m-2", + "X": 1.83, + "Youngs modulus": "211 GPa", + "NMR Quadrupole Moment": { + "Fe-57": 160.0 + } + }, + "Fm": { + "Atomic mass": 257.0, + "Atomic no": 100, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f12.7s2", + "Liquid range": "no data K", + "Melting point": "about 1800 K", + "Mendeleev no": 37, + "Mineral hardness": "no data", + "Molar volume": "no data cm3", + "Name": "Fermium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Fr": { + "Atomic mass": 223.0, + "Atomic no": 87, + "Atomic orbitals": { + "1s": -3283.263399, + "2p": -542.41424, + "2s": -561.73045, + "3d": -111.085223, + "3p": -128.607136, + "3s": -137.959632, + "4d": -20.812462, + "4f": -10.050648, + "4p": -28.648131, + "4s": -32.861013, + "5d": -2.360991, + "5p": -4.97328, + "5s": -6.509516, + "6p": -0.466197, + "6s": -0.841848, + "7s": -0.076176 + }, + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].7s1", + "Ionic radii": { + "1": 1.94 + }, + "Liquid range": "no data K", + "Melting point": "maybe about 300 K", + "Mendeleev no": 7, + "Mineral hardness": "no data", + "Molar volume": "no data cm3", + "Name": "Francium", + "Oxidation states": [ + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "1": { + "VI": { + "": { + "crystal_radius": 1.94, + "ionic_radius": 1.8 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": 3.48, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.7, + "Youngs modulus": "no data GPa" + }, + "Ga": { + "Atomic mass": 69.723, + "Atomic no": 31, + "Atomic orbitals": { + "1s": -370.170639, + "2p": -40.093339, + "2s": -45.200869, + "3d": -0.736204, + "3p": -3.584666, + "3s": -5.241645, + "4p": -0.101634, + "4s": -0.328019 + }, + "Atomic radius": 1.3, + "Atomic radius calculated": 1.36, + "Boiling point": "2477 K", + "Brinell hardness": "60 MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "120 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "5904 kg m-3", + "Electrical resistivity": "about 14 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2.4p1", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "3": 0.76 + }, + "Liquid range": "2174.09 K", + "Melting point": "302.91 K", + "Mendeleev no": 81, + "Mineral hardness": "1.5", + "Molar volume": "11.80 cm3", + "Name": "Gallium", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "IV": { + "": { + "crystal_radius": 0.61, + "ionic_radius": 0.47 + } + }, + "V": { + "": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + } + }, + "VI": { + "": { + "crystal_radius": 0.76, + "ionic_radius": 0.62 + } + } + } + }, + "Superconduction temperature": "1.083 K", + "Thermal conductivity": "29 W m-1 K-1", + "Van der waals radius": 1.87, + "Velocity of sound": "2740 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.81, + "Youngs modulus": "no data GPa" + }, + "Gd": { + "Atomic mass": 157.25, + "Atomic no": 64, + "Atomic orbitals": { + "1s": -1728.625195, + "2p": -262.081616, + "2s": -275.36313, + "3d": -43.754556, + "3p": -54.836922, + "3s": -60.764408, + "4d": -5.531835, + "4f": -0.489012, + "4p": -9.669866, + "4s": -11.986486, + "5d": -0.12722, + "5p": -0.978749, + "5s": -1.608477, + "6s": -0.143627 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": 2.33, + "Boiling point": "3523 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "38 GPa", + "Coefficient of linear thermal expansion": "9.4 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "7901 kg m-3", + "Electrical resistivity": "131 10-8 Ω m", + "Electronic structure": "[Xe].4f7.5d1.6s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "3": 1.075 + }, + "Liquid range": "1938 K", + "Melting point": "1585 K", + "Mendeleev no": 27, + "Mineral hardness": "no data", + "Molar volume": "19.90 cm3", + "Name": "Gadolinium", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "0.26", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "22 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.078, + "ionic_radius": 0.938 + } + }, + "VII": { + "": { + "crystal_radius": 1.14, + "ionic_radius": 1.0 + } + }, + "VIII": { + "": { + "crystal_radius": 1.193, + "ionic_radius": 1.053 + } + }, + "IX": { + "": { + "crystal_radius": 1.247, + "ionic_radius": 1.107 + } + } + } + }, + "Superconduction temperature": "1.083 K", + "Thermal conductivity": "11 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2680 m s-1", + "Vickers hardness": "570 MN m-2", + "X": 1.2, + "Youngs modulus": "55 GPa" + }, + "Ge": { + "Atomic mass": 72.64, + "Atomic no": 32, + "Atomic orbitals": { + "1s": -396.292991, + "2p": -43.720129, + "2s": -49.055282, + "3d": -1.117316, + "3p": -4.194822, + "3s": -5.961472, + "4p": -0.149882, + "4s": -0.426523 + }, + "Atomic radius": 1.25, + "Atomic radius calculated": 1.25, + "Boiling point": "3093 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "6 x10-6K-1", + "Common oxidation states": [ + -4, + 2, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "5323 kg m-3", + "Electrical resistivity": "about 50000 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2.4p2", + "ICSD oxidation states": [ + 2, + 3, + 4 + ], + "Ionic radii": { + "2": 0.87, + "4": 0.67 + }, + "Liquid range": "1881.6 K", + "Melting point": "1211.4 K", + "Mendeleev no": 84, + "Mineral hardness": "6.0", + "Molar volume": "13.63 cm3", + "Name": "Germanium", + "Oxidation states": [ + -4, + 1, + 2, + 3, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 0.87, + "ionic_radius": 0.73 + } + } + }, + "4": { + "IV": { + "": { + "crystal_radius": 0.53, + "ionic_radius": 0.39 + } + }, + "VI": { + "": { + "crystal_radius": 0.67, + "ionic_radius": 0.53 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "60 W m-1 K-1", + "Van der waals radius": 2.11, + "Velocity of sound": "5400 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.01, + "Youngs modulus": "no data GPa" + }, + "H": { + "Atomic mass": 1.00794, + "Atomic no": 1, + "Atomic orbitals": { + "1s": -0.233471 + }, + "Atomic radius": 0.25, + "Atomic radius calculated": 0.53, + "Boiling point": "20.28 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -1, + 1 + ], + "Critical temperature": "33 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "1s1", + "ICSD oxidation states": [ + 1, + -1 + ], + "Liquid range": "6.27 K", + "Melting point": "14.01 K", + "Mendeleev no": 103, + "Mineral hardness": "no data", + "Molar volume": "11.42 cm3", + "Name": "Hydrogen", + "Oxidation states": [ + -1, + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000132 (gas; liquid 1.12)(no units)", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "1": { + "I": { + "": { + "crystal_radius": -0.24, + "ionic_radius": -0.38 + } + }, + "II": { + "": { + "crystal_radius": -0.04, + "ionic_radius": -0.18 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.1805 W m-1 K-1", + "Van der waals radius": 1.2, + "Velocity of sound": "1270 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.2, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "H-2": 2.86 + } + }, + "He": { + "Atomic mass": 4.002602, + "Atomic no": 2, + "Atomic orbitals": { + "1s": -0.570425 + }, + "Atomic radius": "no data", + "Atomic radius calculated": 0.31, + "Boiling point": "4.22 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Critical temperature": "5.19 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "1s2", + "Liquid range": "3.27 K", + "Max oxidation state": 0.0, + "Melting point": "0.95 K", + "Mendeleev no": 1, + "Min oxidation state": 0.0, + "Mineral hardness": "no data", + "Molar volume": "21.0 cm3", + "Name": "Helium", + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000035 (gas; liquid 1.028)(no units)", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.1513 W m-1 K-1", + "Van der waals radius": 1.4, + "Velocity of sound": "970 m s-1", + "Vickers hardness": "no data MN m-2", + "Youngs modulus": "no data GPa" + }, + "Hf": { + "Atomic mass": 178.49, + "Atomic no": 72, + "Atomic orbitals": { + "1s": -2210.65199, + "2p": -345.687023, + "2s": -361.006527, + "3d": -61.231443, + "3p": -74.452656, + "3s": -81.522812, + "4d": -7.676638, + "4f": -0.871574, + "4p": -12.971211, + "4s": -15.883625, + "5d": -0.143805, + "5p": -1.246441, + "5s": -2.049828, + "6s": -0.166465 + }, + "Atomic radius": 1.55, + "Atomic radius calculated": 2.08, + "Boiling point": "4876 K", + "Brinell hardness": "1700 MN m-2", + "Bulk modulus": "110 GPa", + "Coefficient of linear thermal expansion": "5.9 x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "13310 kg m-3", + "Electrical resistivity": "34 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d2.6s2", + "ICSD oxidation states": [ + 4 + ], + "Ionic radii": { + "4": 0.85 + }, + "Liquid range": "2370 K", + "Melting point": "2506 K", + "Mendeleev no": 50, + "Mineral hardness": "5.5", + "Molar volume": "13.44 cm3", + "Name": "Hafnium", + "Oxidation states": [ + 2, + 3, + 4 + ], + "Poissons ratio": "0.37", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "30 GPa", + "Shannon radii": { + "4": { + "IV": { + "": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + }, + "VI": { + "": { + "crystal_radius": 0.85, + "ionic_radius": 0.71 + } + }, + "VII": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + }, + "VIII": { + "": { + "crystal_radius": 0.97, + "ionic_radius": 0.83 + } + } + } + }, + "Superconduction temperature": "0.128 K", + "Thermal conductivity": "23 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "3010 m s-1", + "Vickers hardness": "1760 MN m-2", + "X": 1.3, + "Youngs modulus": "78 GPa" + }, + "Hg": { + "Atomic mass": 200.59, + "Atomic no": 80, + "Atomic orbitals": { + "1s": -2755.022637, + "2p": -443.848676, + "2s": -461.27864, + "3d": -84.845492, + "3p": -100.328031, + "3s": -108.597921, + "4d": -13.019221, + "4f": -4.110291, + "4p": -19.636187, + "4s": -23.222921, + "5d": -0.452552, + "5p": -2.261975, + "5s": -3.423486, + "6s": -0.205137 + }, + "Atomic radius": 1.5, + "Atomic radius calculated": 1.71, + "Boiling point": "629.88 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "25 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 1, + 2 + ], + "Critical temperature": "1750 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "96 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2", + "ICSD oxidation states": [ + 1, + 2 + ], + "Ionic radii": { + "1": 1.33, + "2": 1.16 + }, + "Liquid range": "395.56 K", + "Melting point": "234.32 K", + "Mendeleev no": 74, + "Mineral hardness": "1.5", + "Molar volume": "14.09 cm3", + "Name": "Mercury", + "Oxidation states": [ + 1, + 2, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "73 %", + "Refractive index": "1.000933", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "1": { + "III": { + "": { + "crystal_radius": 1.11, + "ionic_radius": 0.97 + } + }, + "VI": { + "": { + "crystal_radius": 1.33, + "ionic_radius": 1.19 + } + } + }, + "2": { + "II": { + "": { + "crystal_radius": 0.83, + "ionic_radius": 0.69 + } + }, + "IV": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + }, + "VI": { + "": { + "crystal_radius": 1.16, + "ionic_radius": 1.02 + } + }, + "VIII": { + "": { + "crystal_radius": 1.28, + "ionic_radius": 1.14 + } + } + } + }, + "Superconduction temperature": "3.95 K", + "Thermal conductivity": "8.3 W m-1 K-1", + "Van der waals radius": 1.55, + "Velocity of sound": "1407 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.0, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "Hg-201": 387.6 + } + }, + "Ho": { + "Atomic mass": 164.93032, + "Atomic no": 67, + "Atomic orbitals": { + "1s": -1902.051908, + "2p": -291.700994, + "2s": -305.739294, + "3d": -49.565996, + "3p": -61.436304, + "3s": -67.785492, + "4d": -5.906195, + "4f": -0.272677, + "4p": -10.455303, + "4s": -12.985498, + "5p": -0.919463, + "5s": -1.582088, + "6s": -0.133845 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": "no data", + "Boiling point": "2993 K", + "Brinell hardness": "746 MN m-2", + "Bulk modulus": "40 GPa", + "Coefficient of linear thermal expansion": "11.2 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "8795 kg m-3", + "Electrical resistivity": "81.4 10-8 Ω m", + "Electronic structure": "[Xe].4f11.6s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "3": 1.041 + }, + "Liquid range": "1259 K", + "Melting point": "1734 K", + "Mendeleev no": 23, + "Mineral hardness": "no data", + "Molar volume": "18.74 cm3", + "Name": "Holmium", + "Oxidation states": [ + 3 + ], + "Poissons ratio": "0.23", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "26 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.041, + "ionic_radius": 0.901 + } + }, + "VIII": { + "": { + "crystal_radius": 1.155, + "ionic_radius": 1.015 + } + }, + "IX": { + "": { + "crystal_radius": 1.212, + "ionic_radius": 1.072 + } + }, + "X": { + "": { + "crystal_radius": 1.26, + "ionic_radius": 1.12 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "16 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2760 m s-1", + "Vickers hardness": "481 MN m-2", + "X": 1.23, + "Youngs modulus": "65 GPa" + }, + "I": { + "Atomic mass": 126.90447, + "Atomic no": 53, + "Atomic orbitals": { + "1s": -1161.787047, + "2p": -164.603788, + "2s": -175.073804, + "3d": -22.600693, + "3p": -30.831092, + "3s": -35.243351, + "4d": -1.938179, + "4p": -4.572522, + "4s": -6.115811, + "5p": -0.267904, + "5s": -0.596339 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.15, + "Boiling point": "457.4 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "7.7 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -1, + 1, + 3, + 5, + 7 + ], + "Critical temperature": "819 K", + "Density of solid": "4940 kg m-3", + "Electrical resistivity": "> 101510-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2.5p5", + "ICSD oxidation states": [ + 5, + -1 + ], + "Ionic radii": { + "-1": 2.06, + "5": 1.09, + "7": 0.67 + }, + "Liquid range": "70.55 K", + "Melting point": "386.85 K", + "Mendeleev no": 97, + "Mineral hardness": "no data", + "Molar volume": "25.72 cm3", + "Name": "Iodine", + "Oxidation states": [ + -1, + 1, + 3, + 5, + 7 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-1": { + "VI": { + "": { + "crystal_radius": 2.06, + "ionic_radius": 2.2 + } + } + }, + "5": { + "IIIPY": { + "": { + "crystal_radius": 0.58, + "ionic_radius": 0.44 + } + }, + "VI": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.56, + "ionic_radius": 0.42 + } + }, + "VI": { + "": { + "crystal_radius": 0.67, + "ionic_radius": 0.53 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.449 W m-1 K-1", + "Van der waals radius": 1.98, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.66, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "I-127": -696.12, + "I-129": -604.1 + } + }, + "In": { + "Atomic mass": 114.818, + "Atomic no": 49, + "Atomic orbitals": { + "1s": -983.647445, + "2p": -134.628845, + "2s": -144.078357, + "3d": -16.139823, + "3p": -23.345778, + "3s": -27.2206, + "4d": -0.730481, + "4p": -2.795832, + "4s": -4.062639, + "5p": -0.101782, + "5s": -0.290497 + }, + "Atomic radius": 1.55, + "Atomic radius calculated": 1.56, + "Boiling point": "2345 K", + "Brinell hardness": "8.83 MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "32.1 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "7310 kg m-3", + "Electrical resistivity": "8 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2.5p1", + "ICSD oxidation states": [ + 1, + 2, + 3 + ], + "Ionic radii": { + "3": 0.94 + }, + "Liquid range": "1915.25 K", + "Melting point": "429.75 K", + "Mendeleev no": 79, + "Mineral hardness": "1.2", + "Molar volume": "15.76 cm3", + "Name": "Indium", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "IV": { + "": { + "crystal_radius": 0.76, + "ionic_radius": 0.62 + } + }, + "VI": { + "": { + "crystal_radius": 0.94, + "ionic_radius": 0.8 + } + }, + "VIII": { + "": { + "crystal_radius": 1.06, + "ionic_radius": 0.92 + } + } + } + }, + "Superconduction temperature": "3.41 K", + "Thermal conductivity": "82 W m-1 K-1", + "Van der waals radius": 1.93, + "Velocity of sound": "1215 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.78, + "Youngs modulus": "11 GPa", + "NMR Quadrupole Moment": { + "In-113": 759.8, + "In-115": 770.8 + } + }, + "Ir": { + "Atomic mass": 192.217, + "Atomic no": 77, + "Atomic orbitals": { + "1s": -2543.761342, + "2p": -405.526834, + "2s": -422.159424, + "3d": -75.485027, + "3p": -90.108427, + "3s": -97.923081, + "4d": -10.856593, + "4f": -2.738339, + "4p": -16.966578, + "4s": -20.29429, + "5d": -0.335189, + "5p": -1.883349, + "5s": -2.909174, + "6s": -0.195511 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.8, + "Boiling point": "4701 K", + "Brinell hardness": "1670 MN m-2", + "Bulk modulus": "320 GPa", + "Coefficient of linear thermal expansion": "6.4 x10-6K-1", + "Common oxidation states": [ + 3, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "22650 kg m-3", + "Electrical resistivity": "4.7 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d7.6s2", + "ICSD oxidation states": [ + 3, + 4, + 5 + ], + "Ionic radii": { + "3": 0.82, + "4": 0.765, + "5": 0.71 + }, + "Liquid range": "1962 K", + "Melting point": "2739 K", + "Mendeleev no": 66, + "Mineral hardness": "6.5", + "Molar volume": "8.52 cm3", + "Name": "Iridium", + "Oxidation states": [ + -3, + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.26", + "Reflectivity": "78 %", + "Refractive index": "no data", + "Rigidity modulus": "210 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.82, + "ionic_radius": 0.68 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.765, + "ionic_radius": 0.625 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + } + } + }, + "Superconduction temperature": "0.11 K", + "Thermal conductivity": "150 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4825 m s-1", + "Vickers hardness": "1760 MN m-2", + "X": 2.2, + "Youngs modulus": "528 GPa" + }, + "K": { + "Atomic mass": 39.0983, + "Atomic no": 19, + "Atomic orbitals": { + "1s": -128.414957, + "2p": -10.283851, + "2s": -12.839001, + "3p": -0.693776, + "3s": -1.281897, + "4s": -0.088815 + }, + "Atomic radius": 2.2, + "Atomic radius calculated": 2.43, + "Boiling point": "1032 K", + "Brinell hardness": "0.363 MN m-2", + "Bulk modulus": "3.1 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "2223 K", + "Density of solid": "856 kg m-3", + "Electrical resistivity": "7.5 10-8 Ω m", + "Electronic structure": "[Ar].4s1", + "ICSD oxidation states": [ + 1 + ], + "Ionic radii": { + "1": 1.52 + }, + "Liquid range": "695.47 K", + "Melting point": "336.53 K", + "Mendeleev no": 10, + "Mineral hardness": "0.4", + "Molar volume": "45.94 cm3", + "Name": "Potassium", + "Oxidation states": [ + -1, + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "1.3 GPa", + "Shannon radii": { + "1": { + "IV": { + "": { + "crystal_radius": 1.51, + "ionic_radius": 1.37 + } + }, + "VI": { + "": { + "crystal_radius": 1.52, + "ionic_radius": 1.38 + } + }, + "VII": { + "": { + "crystal_radius": 1.6, + "ionic_radius": 1.46 + } + }, + "VIII": { + "": { + "crystal_radius": 1.65, + "ionic_radius": 1.51 + } + }, + "IX": { + "": { + "crystal_radius": 1.69, + "ionic_radius": 1.55 + } + }, + "X": { + "": { + "crystal_radius": 1.73, + "ionic_radius": 1.59 + } + }, + "XII": { + "": { + "crystal_radius": 1.78, + "ionic_radius": 1.64 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "100 W m-1 K-1", + "Van der waals radius": 2.75, + "Velocity of sound": "2000 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.82, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "K-39": 58.5, + "K-40": -73.0, + "K-41": 71.1 + } + }, + "Kr": { + "Atomic mass": 83.798, + "Atomic no": 36, + "Atomic orbitals": { + "1s": -509.982989, + "2p": -60.017328, + "2s": -66.285953, + "3d": -3.074109, + "3p": -7.086634, + "3s": -9.315192, + "4p": -0.34634, + "4s": -0.820574 + }, + "Atomic radius": "no data", + "Atomic radius calculated": 0.88, + "Boiling point": "119.93 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Critical temperature": "209.4 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2.4p6", + "Liquid range": "4.14 K", + "Max oxidation state": 0.0, + "Melting point": "115.79 K", + "Mendeleev no": 4, + "Min oxidation state": 0.0, + "Mineral hardness": "no data", + "Molar volume": "27.99 cm3", + "Name": "Krypton", + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000427", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.00943 W m-1 K-1", + "Van der waals radius": 2.02, + "Velocity of sound": "1120 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 3.0, + "Youngs modulus": "no data GPa" + }, + "La": { + "Atomic mass": 138.90547, + "Atomic no": 57, + "Atomic orbitals": { + "1s": -1355.622446, + "2p": -198.325243, + "2s": -209.831151, + "3d": -30.626696, + "3p": -39.895838, + "3s": -44.856283, + "4d": -3.95801, + "4p": -7.167724, + "4s": -9.000543, + "5d": -0.141085, + "5p": -0.824498, + "5s": -1.324936, + "6s": -0.132233 + }, + "Atomic radius": 1.95, + "Atomic radius calculated": "no data", + "Boiling point": "3743 K", + "Brinell hardness": "363 MN m-2", + "Bulk modulus": "28 GPa", + "Coefficient of linear thermal expansion": "12.1 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "6146 kg m-3", + "Electrical resistivity": "61.5 10-8 Ω m", + "Electronic structure": "[Xe].5d1.6s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "3": 1.172 + }, + "Liquid range": "2550 K", + "Melting point": "1193 K", + "Mendeleev no": 33, + "Mineral hardness": "2.5", + "Molar volume": "22.39 cm3", + "Name": "Lanthanum", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.28", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "14 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.172, + "ionic_radius": 1.032 + } + }, + "VII": { + "": { + "crystal_radius": 1.24, + "ionic_radius": 1.1 + } + }, + "VIII": { + "": { + "crystal_radius": 1.3, + "ionic_radius": 1.16 + } + }, + "IX": { + "": { + "crystal_radius": 1.356, + "ionic_radius": 1.216 + } + }, + "X": { + "": { + "crystal_radius": 1.41, + "ionic_radius": 1.27 + } + }, + "XII": { + "": { + "crystal_radius": 1.5, + "ionic_radius": 1.36 + } + } + } + }, + "Superconduction temperature": "6.00 K", + "Thermal conductivity": "13 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2475 m s-1", + "Vickers hardness": "491 MN m-2", + "X": 1.1, + "Youngs modulus": "37 GPa", + "NMR Quadrupole Moment": { + "La-139": 200.6 + } + }, + "Li": { + "Atomic mass": 6.941, + "Atomic no": 3, + "Atomic orbitals": { + "1s": -1.878564, + "2s": -0.10554 + }, + "Atomic radius": 1.45, + "Atomic radius calculated": 1.67, + "Boiling point": "1615 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "11 GPa", + "Coefficient of linear thermal expansion": "46 x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "3223 K", + "Density of solid": "535 kg m-3", + "Electrical resistivity": "9.5 10-8 Ω m", + "Electronic structure": "[He].2s1", + "ICSD oxidation states": [ + 1 + ], + "Ionic radii": { + "1": 0.9 + }, + "Liquid range": "1161.31 K", + "Melting point": "453.69 K", + "Mendeleev no": 12, + "Mineral hardness": "0.6", + "Molar volume": "13.02 cm3", + "Name": "Lithium", + "Oxidation states": [ + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "4.2 GPa", + "Shannon radii": { + "1": { + "IV": { + "": { + "crystal_radius": 0.73, + "ionic_radius": 0.59 + } + }, + "VI": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + }, + "VIII": { + "": { + "crystal_radius": 1.06, + "ionic_radius": 0.92 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "85 W m-1 K-1", + "Van der waals radius": 1.82, + "Velocity of sound": "6000 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.98, + "Youngs modulus": "4.9 GPa", + "NMR Quadrupole Moment": { + "Li-6": -0.808, + "Li-7": -40.1 + } + }, + "Lr": { + "Atomic mass": 262.0, + "Atomic no": 103, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f14.7s2.7p1 (tentative)", + "Liquid range": "no data K", + "Melting point": "about 1900 K", + "Mendeleev no": 34, + "Mineral hardness": "no data", + "Molar volume": "no data cm3", + "Name": "Lawrencium", + "Oxidation states": [ + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Lu": { + "Atomic mass": 174.967, + "Atomic no": 71, + "Atomic orbitals": { + "1s": -2146.885351, + "2p": -334.330902, + "2s": -349.390492, + "3d": -58.592982, + "3p": -71.538779, + "3s": -78.462398, + "4d": -7.113364, + "4f": -0.568096, + "4p": -12.250904, + "4s": -15.08337, + "5d": -0.103686, + "5p": -1.111991, + "5s": -1.872086, + "6s": -0.155112 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": 2.17, + "Boiling point": "3675 K", + "Brinell hardness": "893 MN m-2", + "Bulk modulus": "48 GPa", + "Coefficient of linear thermal expansion": "9.9 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "9841 kg m-3", + "Electrical resistivity": "58 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d1.6s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "3": 1.001 + }, + "Liquid range": "1750 K", + "Melting point": "1925 K", + "Mendeleev no": 20, + "Mineral hardness": "no data", + "Molar volume": "17.78 cm3", + "Name": "Lutetium", + "Oxidation states": [ + 3 + ], + "Poissons ratio": "0.26", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "27 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.001, + "ionic_radius": 0.861 + } + }, + "VIII": { + "": { + "crystal_radius": 1.117, + "ionic_radius": 0.977 + } + }, + "IX": { + "": { + "crystal_radius": 1.172, + "ionic_radius": 1.032 + } + } + } + }, + "Superconduction temperature": "0.022 K", + "Thermal conductivity": "16 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "1160 MN m-2", + "X": 1.27, + "Youngs modulus": "69 GPa" + }, + "Md": { + "Atomic mass": 258.0, + "Atomic no": 101, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f13.7s2", + "Liquid range": "no data K", + "Melting point": "about 1100 K", + "Mendeleev no": 36, + "Mineral hardness": "no data", + "Molar volume": "no data cm3", + "Name": "Mendelevium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Mg": { + "Atomic mass": 24.305, + "Atomic no": 12, + "Atomic orbitals": { + "1s": -45.973167, + "2p": -1.71897, + "2s": -2.903746, + "3s": -0.175427 + }, + "Atomic radius": 1.5, + "Atomic radius calculated": 1.45, + "Boiling point": "1363 K", + "Brinell hardness": "260 MN m-2", + "Bulk modulus": "45 GPa", + "Coefficient of linear thermal expansion": "8.2 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "1738 kg m-3", + "Electrical resistivity": "4.4 10-8 Ω m", + "Electronic structure": "[Ne].3s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 0.86 + }, + "Liquid range": "440 K", + "Melting point": "923 K", + "Mendeleev no": 73, + "Mineral hardness": "2.5", + "Molar volume": "14.00 cm3", + "Name": "Magnesium", + "Oxidation states": [ + 1, + 2 + ], + "Poissons ratio": "0.29", + "Reflectivity": "74 %", + "Refractive index": "no data", + "Rigidity modulus": "17 GPa", + "Shannon radii": { + "2": { + "IV": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + }, + "V": { + "": { + "crystal_radius": 0.8, + "ionic_radius": 0.66 + } + }, + "VI": { + "": { + "crystal_radius": 0.86, + "ionic_radius": 0.72 + } + }, + "VIII": { + "": { + "crystal_radius": 1.03, + "ionic_radius": 0.89 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "160 W m-1 K-1", + "Van der waals radius": 1.73, + "Velocity of sound": "4602 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.31, + "Youngs modulus": "45 GPa", + "NMR Quadrupole Moment": { + "Mg-25": 199.4 + } + }, + "Mn": { + "Atomic mass": 54.938045, + "Atomic no": 25, + "Atomic orbitals": { + "1s": -233.696912, + "2p": -23.066297, + "2s": -26.866646, + "3d": -0.26654, + "3p": -1.99145, + "3s": -3.076637, + "4s": -0.191136 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.61, + "Boiling point": "2334 K", + "Brinell hardness": "196 MN m-2", + "Bulk modulus": "120 GPa", + "Coefficient of linear thermal expansion": "21.7 x10-6K-1", + "Common oxidation states": [ + 2, + 4, + 7 + ], + "Critical temperature": "no data K", + "Density of solid": "7470 kg m-3", + "Electrical resistivity": "144 10-8 Ω m", + "Electronic structure": "[Ar].3d5.4s2", + "ICSD oxidation states": [ + 2, + 3, + 4, + 7 + ], + "Ionic radii": { + "2": 0.97, + "3": 0.785, + "4": 0.67, + "5": 0.47, + "6": 0.395, + "7": 0.6 + }, + "Ionic radii hs": { + "2": 0.97, + "3": 0.785 + }, + "Ionic radii ls": { + "2": 0.81, + "3": 0.72, + "4": 0.67, + "5": 0.47, + "6": 0.395, + "7": 0.6 + }, + "Liquid range": "815 K", + "Melting point": "1519 K", + "Mendeleev no": 60, + "Mineral hardness": "6.0", + "Molar volume": "7.35 cm3", + "Name": "Manganese", + "Oxidation states": [ + -3, + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "2": { + "IV": { + "High Spin": { + "crystal_radius": 0.8, + "ionic_radius": 0.66 + } + }, + "V": { + "High Spin": { + "crystal_radius": 0.89, + "ionic_radius": 0.75 + } + }, + "VI": { + "Low Spin": { + "crystal_radius": 0.81, + "ionic_radius": 0.67 + }, + "High Spin": { + "crystal_radius": 0.97, + "ionic_radius": 0.83 + } + }, + "VII": { + "High Spin": { + "crystal_radius": 1.04, + "ionic_radius": 0.9 + } + }, + "VIII": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + } + }, + "3": { + "V": { + "": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + }, + "VI": { + "Low Spin": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + }, + "High Spin": { + "crystal_radius": 0.785, + "ionic_radius": 0.645 + } + } + }, + "4": { + "IV": { + "": { + "crystal_radius": 0.53, + "ionic_radius": 0.39 + } + }, + "VI": { + "": { + "crystal_radius": 0.67, + "ionic_radius": 0.53 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.47, + "ionic_radius": 0.33 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.395, + "ionic_radius": 0.255 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.39, + "ionic_radius": 0.25 + } + }, + "VI": { + "": { + "crystal_radius": 0.6, + "ionic_radius": 0.46 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "7.8 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "5150 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.55, + "Youngs modulus": "198 GPa", + "NMR Quadrupole Moment": { + "Mn-55": 330.1 + } + }, + "Mo": { + "Atomic mass": 95.94, + "Atomic no": 42, + "Atomic orbitals": { + "1s": -709.232119, + "2p": -90.791541, + "2s": -98.503638, + "3d": -8.257721, + "3p": -13.71481, + "3s": -16.681545, + "4d": -0.153347, + "4p": -1.39005, + "4s": -2.234824, + "5s": -0.14788 + }, + "Atomic radius": 1.45, + "Atomic radius calculated": 1.9, + "Boiling point": "4912 K", + "Brinell hardness": "1500 MN m-2", + "Bulk modulus": "230 GPa", + "Coefficient of linear thermal expansion": "4.8 x10-6K-1", + "Common oxidation states": [ + 4, + 6 + ], + "Critical temperature": "no data K", + "Density of solid": "10280 kg m-3", + "Electrical resistivity": "5.5 10-8 Ω m", + "Electronic structure": "[Kr].4d5.5s1", + "ICSD oxidation states": [ + 2, + 3, + 4, + 5, + 6 + ], + "Ionic radii": { + "3": 0.83, + "4": 0.79, + "5": 0.75, + "6": 0.73 + }, + "Liquid range": "2016 K", + "Melting point": "2896 K", + "Mendeleev no": 56, + "Mineral hardness": "5.5", + "Molar volume": "9.38 cm3", + "Name": "Molybdenum", + "Oxidation states": [ + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.31", + "Reflectivity": "58 %", + "Refractive index": "no data", + "Rigidity modulus": "20 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.83, + "ionic_radius": 0.69 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.79, + "ionic_radius": 0.65 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.6, + "ionic_radius": 0.46 + } + }, + "VI": { + "": { + "crystal_radius": 0.75, + "ionic_radius": 0.61 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.55, + "ionic_radius": 0.41 + } + }, + "V": { + "": { + "crystal_radius": 0.64, + "ionic_radius": 0.5 + } + }, + "VI": { + "": { + "crystal_radius": 0.73, + "ionic_radius": 0.59 + } + }, + "VII": { + "": { + "crystal_radius": 0.87, + "ionic_radius": 0.73 + } + } + } + }, + "Superconduction temperature": "0.915 K", + "Thermal conductivity": "139 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "6190 m s-1", + "Vickers hardness": "1530 MN m-2", + "X": 2.16, + "Youngs modulus": "329 GPa" + }, + "N": { + "Atomic mass": 14.0067, + "Atomic no": 7, + "Atomic orbitals": { + "1s": -14.011501, + "2p": -0.266297, + "2s": -0.676151 + }, + "Atomic radius": 0.65, + "Atomic radius calculated": 0.56, + "Boiling point": "77.36 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -3, + 3, + 5 + ], + "Critical temperature": "126.2 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[He].2s2.2p3", + "ICSD oxidation states": [ + 1, + 3, + 5, + -1, + -3, + -2 + ], + "Ionic radii": { + "-3": 1.32, + "3": 0.3, + "5": 0.27 + }, + "Liquid range": "14.31 K", + "Melting point": "63.05 K", + "Mendeleev no": 100, + "Mineral hardness": "no data", + "Molar volume": "13.54 cm3", + "Name": "Nitrogen", + "Oxidation states": [ + -3, + -2, + -1, + 1, + 2, + 3, + 4, + 5 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000298 (gas; liquid 1.197)(no units)", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-3": { + "IV": { + "": { + "crystal_radius": 1.32, + "ionic_radius": 1.46 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 0.3, + "ionic_radius": 0.16 + } + } + }, + "5": { + "III": { + "": { + "crystal_radius": 0.044, + "ionic_radius": -0.104 + } + }, + "VI": { + "": { + "crystal_radius": 0.27, + "ionic_radius": 0.13 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.02583 W m-1 K-1", + "Van der waals radius": 1.55, + "Velocity of sound": "333.6 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 3.04, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "N-14": 20.44 + } + }, + "Na": { + "Atomic mass": 22.98976928, + "Atomic no": 11, + "Atomic orbitals": { + "1s": -37.719975, + "2p": -1.060636, + "2s": -2.063401, + "3s": -0.103415 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": 1.9, + "Boiling point": "1156 K", + "Brinell hardness": "0.69 MN m-2", + "Bulk modulus": "6.3 GPa", + "Coefficient of linear thermal expansion": "71 x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "2573 K", + "Density of solid": "968 kg m-3", + "Electrical resistivity": "4.9 10-8 Ω m", + "Electronic structure": "[Ne].3s1", + "ICSD oxidation states": [ + 1 + ], + "Ionic radii": { + "1": 1.16 + }, + "Liquid range": "785.13 K", + "Melting point": "370.87 K", + "Mendeleev no": 11, + "Mineral hardness": "0.5", + "Molar volume": "23.78 cm3", + "Name": "Sodium", + "Oxidation states": [ + -1, + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "3.3 GPa", + "Shannon radii": { + "1": { + "IV": { + "": { + "crystal_radius": 1.13, + "ionic_radius": 0.99 + } + }, + "V": { + "": { + "crystal_radius": 1.14, + "ionic_radius": 1.0 + } + }, + "VI": { + "": { + "crystal_radius": 1.16, + "ionic_radius": 1.02 + } + }, + "VII": { + "": { + "crystal_radius": 1.26, + "ionic_radius": 1.12 + } + }, + "VIII": { + "": { + "crystal_radius": 1.32, + "ionic_radius": 1.18 + } + }, + "IX": { + "": { + "crystal_radius": 1.38, + "ionic_radius": 1.24 + } + }, + "XII": { + "": { + "crystal_radius": 1.53, + "ionic_radius": 1.39 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "140 W m-1 K-1", + "Van der waals radius": 2.27, + "Velocity of sound": "3200 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.93, + "Youngs modulus": "10 GPa", + "NMR Quadrupole Moment": { + "Na-23": 104.1 + } + }, + "Nb": { + "Atomic mass": 92.90638, + "Atomic no": 41, + "Atomic orbitals": { + "1s": -673.76253, + "2p": -85.272175, + "2s": -92.74086, + "3d": -7.339839, + "3p": -12.552855, + "3s": -15.393727, + "4d": -0.125252, + "4p": -1.250049, + "4s": -2.036693, + "5s": -0.144272 + }, + "Atomic radius": 1.45, + "Atomic radius calculated": 1.98, + "Boiling point": "5017 K", + "Brinell hardness": "736 MN m-2", + "Bulk modulus": "170 GPa", + "Coefficient of linear thermal expansion": "7.3 x10-6K-1", + "Common oxidation states": [ + 5 + ], + "Critical temperature": "no data K", + "Density of solid": "8570 kg m-3", + "Electrical resistivity": "15.2 10-8 Ω m", + "Electronic structure": "[Kr].4d4.5s1", + "ICSD oxidation states": [ + 2, + 3, + 4, + 5 + ], + "Ionic radii": { + "3": 0.86, + "4": 0.82, + "5": 0.78 + }, + "Liquid range": "2267 K", + "Melting point": "2750 K", + "Mendeleev no": 53, + "Mineral hardness": "6.0", + "Molar volume": "10.83 cm3", + "Name": "Niobium", + "Oxidation states": [ + -1, + 2, + 3, + 4, + 5 + ], + "Poissons ratio": "0.40", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "38 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.86, + "ionic_radius": 0.72 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.82, + "ionic_radius": 0.68 + } + }, + "VIII": { + "": { + "crystal_radius": 0.93, + "ionic_radius": 0.79 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.62, + "ionic_radius": 0.48 + } + }, + "VI": { + "": { + "crystal_radius": 0.78, + "ionic_radius": 0.64 + } + }, + "VII": { + "": { + "crystal_radius": 0.83, + "ionic_radius": 0.69 + } + }, + "VIII": { + "": { + "crystal_radius": 0.88, + "ionic_radius": 0.74 + } + } + } + }, + "Superconduction temperature": "9.25 K", + "Thermal conductivity": "54 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "3480 m s-1", + "Vickers hardness": "1320 MN m-2", + "X": 1.6, + "Youngs modulus": "105 GPa" + }, + "Nd": { + "Atomic mass": 144.242, + "Atomic no": 60, + "Atomic orbitals": { + "1s": -1509.698955, + "2p": -224.351816, + "2s": -236.613572, + "3d": -35.754515, + "3p": -45.791219, + "3s": -51.161263, + "4d": -4.377027, + "4f": -0.179508, + "4p": -7.96782, + "4s": -10.000891, + "5p": -0.798503, + "5s": -1.334934, + "6s": -0.125796 + }, + "Atomic radius": 1.85, + "Atomic radius calculated": 2.06, + "Boiling point": "3373 K", + "Brinell hardness": "265 MN m-2", + "Bulk modulus": "32 GPa", + "Coefficient of linear thermal expansion": "9.6 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "6800 kg m-3", + "Electrical resistivity": "64.3 10-8 Ω m", + "Electronic structure": "[Xe].4f4.6s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "2": 1.43, + "3": 1.123 + }, + "Liquid range": "2076 K", + "Melting point": "1297 K", + "Mendeleev no": 30, + "Mineral hardness": "no data", + "Molar volume": "20.59 cm3", + "Name": "Neodymium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.28", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "16 GPa", + "Shannon radii": { + "2": { + "VIII": { + "": { + "crystal_radius": 1.43, + "ionic_radius": 1.29 + } + }, + "IX": { + "": { + "crystal_radius": 1.49, + "ionic_radius": 1.35 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.123, + "ionic_radius": 0.983 + } + }, + "VIII": { + "": { + "crystal_radius": 1.249, + "ionic_radius": 1.109 + } + }, + "IX": { + "": { + "crystal_radius": 1.303, + "ionic_radius": 1.163 + } + }, + "XII": { + "": { + "crystal_radius": 1.41, + "ionic_radius": 1.27 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "17 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2330 m s-1", + "Vickers hardness": "343 MN m-2", + "X": 1.14, + "Youngs modulus": "41 GPa" + }, + "Ne": { + "Atomic mass": 20.1797, + "Atomic no": 10, + "Atomic orbitals": { + "1s": -30.305855, + "2p": -0.498034, + "2s": -1.322809 + }, + "Atomic radius": "no data", + "Atomic radius calculated": 0.38, + "Boiling point": "27.07 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Critical temperature": "44.4 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[He].2s2.2p6", + "Liquid range": "2.51 K", + "Max oxidation state": 0.0, + "Melting point": "24.56 K", + "Mendeleev no": 2, + "Min oxidation state": 0.0, + "Mineral hardness": "no data", + "Molar volume": "13.23 cm3", + "Name": "Neon", + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000067", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.0491 W m-1 K-1", + "Van der waals radius": 1.54, + "Velocity of sound": "936 m s-1", + "Vickers hardness": "no data MN m-2", + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "Ne-21": 101.55 + } + }, + "Ni": { + "Atomic mass": 58.6934, + "Atomic no": 28, + "Atomic orbitals": { + "1s": -297.870824, + "2p": -30.868027, + "2s": -35.312112, + "3d": -0.348699, + "3p": -2.594158, + "3s": -3.950717, + "4s": -0.210764 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.49, + "Boiling point": "3186 K", + "Brinell hardness": "700 MN m-2", + "Bulk modulus": "180 GPa", + "Coefficient of linear thermal expansion": "13.4 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "8908 kg m-3", + "Electrical resistivity": "7.2 10-8 Ω m", + "Electronic structure": "[Ar].3d8.4s2", + "ICSD oxidation states": [ + 1, + 2, + 3, + 4 + ], + "Ionic radii": { + "3": 0.74 + }, + "Ionic radii hs": { + "3": 0.74 + }, + "Ionic radii ls": { + "2": 0.83, + "3": 0.7, + "4": 0.62 + }, + "Liquid range": "1458 K", + "Melting point": "1728 K", + "Mendeleev no": 67, + "Mineral hardness": "4.0", + "Molar volume": "6.59 cm3", + "Name": "Nickel", + "Oxidation states": [ + -1, + 1, + 2, + 3, + 4 + ], + "Poissons ratio": "0.31", + "Reflectivity": "72 %", + "Refractive index": "no data", + "Rigidity modulus": "76 GPa", + "Shannon radii": { + "2": { + "IV": { + "": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + } + }, + "IVSQ": { + "": { + "crystal_radius": 0.63, + "ionic_radius": 0.49 + } + }, + "V": { + "": { + "crystal_radius": 0.77, + "ionic_radius": 0.63 + } + }, + "VI": { + "": { + "crystal_radius": 0.83, + "ionic_radius": 0.69 + } + } + }, + "3": { + "VI": { + "Low Spin": { + "crystal_radius": 0.7, + "ionic_radius": 0.56 + }, + "High Spin": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + } + }, + "4": { + "VI": { + "Low Spin": { + "crystal_radius": 0.62, + "ionic_radius": 0.48 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "91 W m-1 K-1", + "Van der waals radius": 1.63, + "Velocity of sound": "4970 m s-1", + "Vickers hardness": "638 MN m-2", + "X": 1.91, + "Youngs modulus": "200 GPa", + "NMR Quadrupole Moment": { + "Ni-61": 162.15 + } + }, + "No": { + "Atomic mass": 259.0, + "Atomic no": 102, + "Atomic orbitals": "no data", + "Atomic radius": "no data", + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Rn].5f14.7s2", + "Liquid range": "no data K", + "Melting point": "about 1100 K", + "Mendeleev no": 35, + "Mineral hardness": "no data", + "Molar volume": "no data cm3", + "Name": "Nobelium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.24, + "ionic_radius": 1.1 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "no data W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.3, + "Youngs modulus": "no data GPa" + }, + "Np": { + "Atomic mass": 237.0, + "Atomic no": 93, + "Atomic orbitals": "no data", + "Atomic radius": 1.75, + "Atomic radius calculated": "no data", + "Boiling point": "4273 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 5 + ], + "Critical temperature": "no data K", + "Density of solid": "20450 kg m-3", + "Electrical resistivity": "120 10-8 Ω m", + "Electronic structure": "[Rn].5f4.6d1.7s2", + "Ionic radii": { + "2": 1.24, + "3": 1.15, + "4": 1.01, + "5": 0.89, + "6": 0.86, + "7": 0.85 + }, + "Liquid range": "3363 K", + "Melting point": "910 K", + "Mendeleev no": 44, + "Mineral hardness": "no data", + "Molar volume": "11.59 cm3", + "Name": "Neptunium", + "Oxidation states": [ + 3, + 4, + 5, + 6, + 7 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.24, + "ionic_radius": 1.1 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.15, + "ionic_radius": 1.01 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 1.01, + "ionic_radius": 0.87 + } + }, + "VIII": { + "": { + "crystal_radius": 1.12, + "ionic_radius": 0.98 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.89, + "ionic_radius": 0.75 + } + } + }, + "6": { + "VI": { + "": { + "crystal_radius": 0.86, + "ionic_radius": 0.72 + } + } + }, + "7": { + "VI": { + "": { + "crystal_radius": 0.85, + "ionic_radius": 0.71 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "6 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.36, + "Youngs modulus": "no data GPa" + }, + "O": { + "Atomic mass": 15.9994, + "Atomic no": 8, + "Atomic orbitals": { + "1s": -18.758245, + "2p": -0.338381, + "2s": -0.871362 + }, + "Atomic radius": 0.6, + "Atomic radius calculated": 0.48, + "Boiling point": "90.2 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -2 + ], + "Critical temperature": "154.6 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[He].2s2.2p4", + "ICSD oxidation states": [ + -2 + ], + "Ionic radii": { + "-2": 1.26 + }, + "Liquid range": "35.4 K", + "Melting point": "54.8 K", + "Mendeleev no": 101, + "Mineral hardness": "no data", + "Molar volume": "17.36 cm3", + "Name": "Oxygen", + "Oxidation states": [ + -2, + -1, + 1, + 2 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000271 (gas; liquid 1.221)(no units)", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-2": { + "II": { + "": { + "crystal_radius": 1.21, + "ionic_radius": 1.35 + } + }, + "III": { + "": { + "crystal_radius": 1.22, + "ionic_radius": 1.36 + } + }, + "IV": { + "": { + "crystal_radius": 1.24, + "ionic_radius": 1.38 + } + }, + "VI": { + "": { + "crystal_radius": 1.26, + "ionic_radius": 1.4 + } + }, + "VIII": { + "": { + "crystal_radius": 1.28, + "ionic_radius": 1.42 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.02658 W m-1 K-1", + "Van der waals radius": 1.52, + "Velocity of sound": "317.5 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 3.44, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "O-17": -25.58 + } + }, + "Os": { + "Atomic mass": 190.23, + "Atomic no": 76, + "Atomic orbitals": { + "1s": -2475.238617, + "2p": -393.15408, + "2s": -409.522396, + "3d": -72.497183, + "3p": -86.837047, + "3s": -94.501324, + "4d": -10.176082, + "4f": -2.321175, + "4p": -16.119671, + "4s": -19.362527, + "5d": -0.296791, + "5p": -1.757404, + "5s": -2.738293, + "6s": -0.191489 + }, + "Atomic radius": 1.3, + "Atomic radius calculated": 1.85, + "Boiling point": "5285 K", + "Brinell hardness": "3920 MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "5.1 x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "22610 kg m-3", + "Electrical resistivity": "8.1 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d6.6s2", + "Ionic radii": { + "4": 0.77, + "5": 0.715, + "6": 0.685, + "7": 0.665, + "8": 0.53 + }, + "Liquid range": "1979 K", + "Melting point": "3306 K", + "Mendeleev no": 63, + "Mineral hardness": "7.0", + "Molar volume": "8.42 cm3", + "Name": "Osmium", + "Oxidation states": [ + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "Poissons ratio": "0.25", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "222 GPa", + "Shannon radii": { + "4": { + "VI": { + "": { + "crystal_radius": 0.77, + "ionic_radius": 0.63 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.715, + "ionic_radius": 0.575 + } + } + }, + "6": { + "V": { + "": { + "crystal_radius": 0.63, + "ionic_radius": 0.49 + } + }, + "VI": { + "": { + "crystal_radius": 0.685, + "ionic_radius": 0.545 + } + } + }, + "7": { + "VI": { + "": { + "crystal_radius": 0.665, + "ionic_radius": 0.525 + } + } + }, + "8": { + "IV": { + "": { + "crystal_radius": 0.53, + "ionic_radius": 0.39 + } + } + } + }, + "Superconduction temperature": "0.66 K", + "Thermal conductivity": "88 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4940 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.2, + "Youngs modulus": "no data GPa" + }, + "P": { + "Atomic mass": 30.973762, + "Atomic no": 15, + "Atomic orbitals": { + "1s": -76.061897, + "2p": -4.576617, + "2s": -6.329346, + "3p": -0.20608, + "3s": -0.512364 + }, + "Atomic radius": 1.0, + "Atomic radius calculated": 0.98, + "Boiling point": "550 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "11 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -3, + 3, + 5 + ], + "Critical temperature": "994 K", + "Density of solid": "1823 kg m-3", + "Electrical resistivity": "about 10 10-8 Ω m", + "Electronic structure": "[Ne].3s2.3p3", + "ICSD oxidation states": [ + 3, + 4, + 5, + -2, + -3, + -1 + ], + "Ionic radii": { + "3": 0.58, + "5": 0.52 + }, + "Liquid range": "232.7 K", + "Melting point": "(white P) 317.3 K", + "Mendeleev no": 90, + "Mineral hardness": "no data", + "Molar volume": "17.02 cm3", + "Name": "Phosphorus", + "Oxidation states": [ + -3, + -2, + -1, + 1, + 2, + 3, + 4, + 5 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.001212", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.58, + "ionic_radius": 0.44 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.31, + "ionic_radius": 0.17 + } + }, + "V": { + "": { + "crystal_radius": 0.43, + "ionic_radius": 0.29 + } + }, + "VI": { + "": { + "crystal_radius": 0.52, + "ionic_radius": 0.38 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.236 W m-1 K-1", + "Van der waals radius": 1.8, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.19, + "Youngs modulus": "no data GPa" + }, + "Pa": { + "Atomic mass": 231.03588, + "Atomic no": 91, + "Atomic orbitals": { + "1s": -3606.333629, + "2p": -603.470278, + "2s": -623.870431, + "3d": -127.781168, + "3p": -146.485678, + "3s": -156.466742, + "4d": -25.933121, + "4f": -14.105747, + "4p": -34.48293, + "4s": -39.064507, + "5d": -3.659928, + "5f": -0.316813, + "5p": -6.709821, + "5s": -8.463463, + "6d": -0.142481, + "6p": -0.799756, + "6s": -1.287232, + "7s": -0.129653 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": "no data", + "Boiling point": "no data K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 5 + ], + "Critical temperature": "no data K", + "Density of solid": "15370 kg m-3", + "Electrical resistivity": "18 10-8 Ω m", + "Electronic structure": "[Rn].5f2.6d1.7s2", + "Ionic radii": { + "3": 1.16, + "4": 1.04, + "5": 0.92 + }, + "Liquid range": "no data K", + "Melting point": "1841 K", + "Mendeleev no": 46, + "Mineral hardness": "no data", + "Molar volume": "15.18 cm3", + "Name": "Protactinium", + "Oxidation states": [ + 3, + 4, + 5 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.18, + "ionic_radius": 1.04 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 1.04, + "ionic_radius": 0.9 + } + }, + "VIII": { + "": { + "crystal_radius": 1.15, + "ionic_radius": 1.01 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.92, + "ionic_radius": 0.78 + } + }, + "VIII": { + "": { + "crystal_radius": 1.05, + "ionic_radius": 0.91 + } + }, + "IX": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + } + } + }, + "Superconduction temperature": "1.4 K", + "Thermal conductivity": "47 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.5, + "Youngs modulus": "no data GPa" + }, + "Pb": { + "Atomic mass": 207.2, + "Atomic no": 82, + "Atomic orbitals": { + "1s": -2901.078061, + "2p": -470.877785, + "2s": -488.843335, + "3d": -91.889924, + "3p": -107.950391, + "3s": -116.526852, + "4d": -15.030026, + "4f": -5.592532, + "4p": -21.990564, + "4s": -25.75333, + "5d": -0.902393, + "5p": -2.941657, + "5s": -4.206797, + "6p": -0.141831, + "6s": -0.357187 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": 1.54, + "Boiling point": "2022 K", + "Brinell hardness": "38.3 MN m-2", + "Bulk modulus": "46 GPa", + "Coefficient of linear thermal expansion": "28.9 x10-6K-1", + "Common oxidation states": [ + 2, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "11340 kg m-3", + "Electrical resistivity": "21 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2.6p2", + "ICSD oxidation states": [ + 2, + 4 + ], + "Ionic radii": { + "2": 1.33, + "4": 0.915 + }, + "Liquid range": "1421.39 K", + "Melting point": "600.61 K", + "Mendeleev no": 82, + "Mineral hardness": "1.5", + "Molar volume": "18.26 cm3", + "Name": "Lead", + "Oxidation states": [ + -4, + 2, + 4 + ], + "Poissons ratio": "0.44", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "5.6 GPa", + "Shannon radii": { + "2": { + "IVPY": { + "": { + "crystal_radius": 1.12, + "ionic_radius": 0.98 + } + }, + "VI": { + "": { + "crystal_radius": 1.33, + "ionic_radius": 1.19 + } + }, + "VII": { + "": { + "crystal_radius": 1.37, + "ionic_radius": 1.23 + } + }, + "VIII": { + "": { + "crystal_radius": 1.43, + "ionic_radius": 1.29 + } + }, + "IX": { + "": { + "crystal_radius": 1.49, + "ionic_radius": 1.35 + } + }, + "X": { + "": { + "crystal_radius": 1.54, + "ionic_radius": 1.4 + } + }, + "XI": { + "": { + "crystal_radius": 1.59, + "ionic_radius": 1.45 + } + }, + "XII": { + "": { + "crystal_radius": 1.63, + "ionic_radius": 1.49 + } + } + }, + "4": { + "IV": { + "": { + "crystal_radius": 0.79, + "ionic_radius": 0.65 + } + }, + "V": { + "": { + "crystal_radius": 0.87, + "ionic_radius": 0.73 + } + }, + "VI": { + "": { + "crystal_radius": 0.915, + "ionic_radius": 0.775 + } + }, + "VIII": { + "": { + "crystal_radius": 1.08, + "ionic_radius": 0.94 + } + } + } + }, + "Superconduction temperature": "7.2 K", + "Thermal conductivity": "35 W m-1 K-1", + "Van der waals radius": 2.02, + "Velocity of sound": "1260 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.33, + "Youngs modulus": "16 GPa" + }, + "Pd": { + "Atomic mass": 106.42, + "Atomic no": 46, + "Atomic orbitals": { + "1s": -860.134909, + "2p": -114.408286, + "2s": -123.105078, + "3d": -12.132197, + "3p": -18.580798, + "3s": -22.060898, + "4d": -0.160771, + "4p": -1.815215, + "4s": -2.889173 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.69, + "Boiling point": "3236 K", + "Brinell hardness": "37.3 MN m-2", + "Bulk modulus": "180 GPa", + "Coefficient of linear thermal expansion": "11.8 x10-6K-1", + "Common oxidation states": [ + 2, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "12023 kg m-3", + "Electrical resistivity": "10.8 10-8 Ω m", + "Electronic structure": "[Kr].4d10", + "ICSD oxidation states": [ + 2, + 4 + ], + "Ionic radii": { + "1": 0.73, + "2": 1.0, + "3": 0.9, + "4": 0.755 + }, + "Liquid range": "1407.95 K", + "Melting point": "1828.05 K", + "Mendeleev no": 69, + "Mineral hardness": "4.75", + "Molar volume": "8.56 cm3", + "Name": "Palladium", + "Oxidation states": [ + 2, + 4 + ], + "Poissons ratio": "0.39", + "Reflectivity": "72 %", + "Refractive index": "no data", + "Rigidity modulus": "44 GPa", + "Shannon radii": { + "1": { + "II": { + "": { + "crystal_radius": 0.73, + "ionic_radius": 0.59 + } + } + }, + "2": { + "IVSQ": { + "": { + "crystal_radius": 0.78, + "ionic_radius": 0.64 + } + }, + "VI": { + "": { + "crystal_radius": 1.0, + "ionic_radius": 0.86 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.755, + "ionic_radius": 0.615 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "72 W m-1 K-1", + "Van der waals radius": 1.63, + "Velocity of sound": "3070 m s-1", + "Vickers hardness": "461 MN m-2", + "X": 2.2, + "Youngs modulus": "121 GPa" + }, + "Pm": { + "Atomic mass": 145.0, + "Atomic no": 61, + "Atomic orbitals": { + "1s": -1562.980284, + "2p": -233.455114, + "2s": -245.970548, + "3d": -37.625433, + "3p": -47.921132, + "3s": -53.429311, + "4d": -4.596822, + "4f": -0.200159, + "4p": -8.320495, + "4s": -10.422756, + "5p": -0.817702, + "5s": -1.372265, + "6s": -0.127053 + }, + "Atomic radius": 1.85, + "Atomic radius calculated": 2.05, + "Boiling point": "3273 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "33 GPa", + "Coefficient of linear thermal expansion": "11 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "7264 kg m-3", + "Electrical resistivity": "about 75 10-8 Ω m", + "Electronic structure": "[Xe].4f5.6s2", + "Ionic radii": { + "3": 1.11 + }, + "Liquid range": "1900 K", + "Melting point": "1373 K", + "Mendeleev no": 29, + "Mineral hardness": "no data", + "Molar volume": "20.23 cm3", + "Name": "Promethium", + "Oxidation states": [ + 3 + ], + "Poissons ratio": "0.28", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "18 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.11, + "ionic_radius": 0.97 + } + }, + "VIII": { + "": { + "crystal_radius": 1.233, + "ionic_radius": 1.093 + } + }, + "IX": { + "": { + "crystal_radius": 1.284, + "ionic_radius": 1.144 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "15 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.13, + "Youngs modulus": "46 GPa" + }, + "Po": { + "Atomic mass": 210.0, + "Atomic no": 84, + "Atomic orbitals": { + "1s": -3050.988417, + "2p": -498.77192, + "2s": -517.275843, + "3d": -99.256068, + "3p": -115.898384, + "3s": -124.783683, + "4d": -17.173307, + "4f": -7.206499, + "4p": -24.481337, + "4s": -28.42254, + "5d": -1.386458, + "5p": -3.655382, + "5s": -5.027447, + "6p": -0.217889, + "6s": -0.493528 + }, + "Atomic radius": 1.9, + "Atomic radius calculated": 1.35, + "Boiling point": "1235 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -2, + 2, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "9196 kg m-3", + "Electrical resistivity": "40 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2.6p4", + "Ionic radii": { + "4": 1.08, + "6": 0.81 + }, + "Liquid range": "708 K", + "Melting point": "527 K", + "Mendeleev no": 91, + "Mineral hardness": "no data", + "Molar volume": "22.97 cm3", + "Name": "Polonium", + "Oxidation states": [ + -2, + 2, + 4, + 6 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "4": { + "VI": { + "": { + "crystal_radius": 1.08, + "ionic_radius": 0.94 + } + }, + "VIII": { + "": { + "crystal_radius": 1.22, + "ionic_radius": 1.08 + } + } + }, + "6": { + "VI": { + "": { + "crystal_radius": 0.81, + "ionic_radius": 0.67 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "20 W m-1 K-1", + "Van der waals radius": 1.97, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.0, + "Youngs modulus": "no data GPa" + }, + "Pr": { + "Atomic mass": 140.90765, + "Atomic no": 59, + "Atomic orbitals": { + "1s": -1457.338067, + "2p": -215.418313, + "2s": -227.426363, + "3d": -33.913996, + "3p": -43.692548, + "3s": -48.924994, + "4d": -4.154228, + "4f": -0.155138, + "4p": -7.613108, + "4s": -9.577447, + "5p": -0.778046, + "5s": -1.296106, + "6s": -0.124465 + }, + "Atomic radius": 1.85, + "Atomic radius calculated": 2.47, + "Boiling point": "3563 K", + "Brinell hardness": "481 MN m-2", + "Bulk modulus": "29 GPa", + "Coefficient of linear thermal expansion": "6.7 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "6640 kg m-3", + "Electrical resistivity": "70 10-8 Ω m", + "Electronic structure": "[Xe].4f3.6s2", + "ICSD oxidation states": [ + 3, + 4 + ], + "Ionic radii": { + "3": 1.13, + "4": 0.99 + }, + "Liquid range": "2355 K", + "Melting point": "1208 K", + "Mendeleev no": 31, + "Mineral hardness": "no data", + "Molar volume": "20.80 cm3", + "Name": "Praseodymium", + "Oxidation states": [ + 2, + 3, + 4 + ], + "Poissons ratio": "0.28", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "15 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.13, + "ionic_radius": 0.99 + } + }, + "VIII": { + "": { + "crystal_radius": 1.266, + "ionic_radius": 1.126 + } + }, + "IX": { + "": { + "crystal_radius": 1.319, + "ionic_radius": 1.179 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.99, + "ionic_radius": 0.85 + } + }, + "VIII": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "13 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2280 m s-1", + "Vickers hardness": "400 MN m-2", + "X": 1.13, + "Youngs modulus": "37 GPa" + }, + "Pt": { + "Atomic mass": 195.084, + "Atomic no": 78, + "Atomic orbitals": { + "1s": -2613.096532, + "2p": -417.96053, + "2s": -434.858003, + "3d": -78.400271, + "3p": -93.309108, + "3s": -101.274869, + "4d": -11.419476, + "4f": -3.038049, + "4p": -17.697297, + "4s": -21.110651, + "5d": -0.273634, + "5p": -1.884256, + "5s": -2.950526, + "6s": -0.161308 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.77, + "Boiling point": "4098 K", + "Brinell hardness": "392 MN m-2", + "Bulk modulus": "230 GPa", + "Coefficient of linear thermal expansion": "8.8 x10-6K-1", + "Common oxidation states": [ + 2, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "21090 kg m-3", + "Electrical resistivity": "10.6 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d9.6s1", + "Ionic radii": { + "2": 0.94, + "4": 0.765, + "5": 0.71 + }, + "Liquid range": "2056.6 K", + "Melting point": "2041.4 K", + "Mendeleev no": 68, + "Mineral hardness": "3.5", + "Molar volume": "9.09 cm3", + "Name": "Platinum", + "Oxidation states": [ + -2, + 2, + 4, + 5, + 6 + ], + "Poissons ratio": "0.38", + "Reflectivity": "73 %", + "Refractive index": "no data", + "Rigidity modulus": "61 GPa", + "Shannon radii": { + "2": { + "IVSQ": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + }, + "VI": { + "": { + "crystal_radius": 0.94, + "ionic_radius": 0.8 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.765, + "ionic_radius": 0.625 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.71, + "ionic_radius": 0.57 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "72 W m-1 K-1", + "Van der waals radius": 1.75, + "Velocity of sound": "2680 m s-1", + "Vickers hardness": "549 MN m-2", + "X": 2.28, + "Youngs modulus": "168 GPa" + }, + "Pu": { + "Atomic mass": 244.0, + "Atomic no": 94, + "Atomic orbitals": "no data", + "Atomic radius": 1.75, + "Atomic radius calculated": "no data", + "Boiling point": "3503 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "19816 kg m-3", + "Electrical resistivity": "150 10-8 Ω m", + "Electronic structure": "[Rn].5f6.7s2", + "Ionic radii": { + "3": 1.14, + "4": 1.0, + "5": 0.88, + "6": 0.85 + }, + "Liquid range": "2590.5 K", + "Melting point": "912.5 K", + "Mendeleev no": 43, + "Mineral hardness": "no data", + "Molar volume": "12.29 cm3", + "Name": "Plutonium", + "Oxidation states": [ + 3, + 4, + 5, + 6, + 7 + ], + "Poissons ratio": "0.21", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "43 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.14, + "ionic_radius": 1.0 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 1.0, + "ionic_radius": 0.86 + } + }, + "VIII": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.88, + "ionic_radius": 0.74 + } + } + }, + "6": { + "VI": { + "": { + "crystal_radius": 0.85, + "ionic_radius": 0.71 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "6 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2260 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.28, + "Youngs modulus": "96 GPa" + }, + "Ra": { + "Atomic mass": 226.0, + "Atomic no": 88, + "Atomic orbitals": { + "1s": -3362.736563, + "2p": -557.513214, + "2s": -577.101208, + "3d": -115.306476, + "3p": -133.12325, + "3s": -142.632426, + "4d": -22.208125, + "4f": -11.181066, + "4p": -30.221208, + "4s": -34.525628, + "5d": -2.819853, + "5p": -5.547203, + "5s": -7.139137, + "6p": -0.634674, + "6s": -1.05135, + "7s": -0.113732 + }, + "Atomic radius": 2.15, + "Atomic radius calculated": "no data", + "Boiling point": "2010 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "5000 kg m-3", + "Electrical resistivity": "100 10-8 Ω m", + "Electronic structure": "[Rn].7s2", + "Ionic radii": { + "2": 1.62 + }, + "Liquid range": "1037 K", + "Melting point": "973 K", + "Mendeleev no": 13, + "Mineral hardness": "no data", + "Molar volume": "41.09 cm3", + "Name": "Radium", + "Oxidation states": [ + 2 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "2": { + "VIII": { + "": { + "crystal_radius": 1.62, + "ionic_radius": 1.48 + } + }, + "XII": { + "": { + "crystal_radius": 1.84, + "ionic_radius": 1.7 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "19 W m-1 K-1", + "Van der waals radius": 2.83, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.9, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "Ra-223": 1210.3 + } + }, + "Rb": { + "Atomic mass": 85.4678, + "Atomic no": 37, + "Atomic orbitals": { + "1s": -540.957115, + "2p": -64.784678, + "2s": -71.291202, + "3d": -3.915508, + "3p": -8.165416, + "3s": -10.513861, + "4p": -0.59217, + "4s": -1.135051, + "5s": -0.085375 + }, + "Atomic radius": 2.35, + "Atomic radius calculated": 2.65, + "Boiling point": "961 K", + "Brinell hardness": "0.216 MN m-2", + "Bulk modulus": "2.5 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 1 + ], + "Critical temperature": "2093 K", + "Density of solid": "1532 kg m-3", + "Electrical resistivity": "13.3 10-8 Ω m", + "Electronic structure": "[Kr].5s1", + "ICSD oxidation states": [ + 1 + ], + "Ionic radii": { + "1": 1.66 + }, + "Liquid range": "648.54 K", + "Melting point": "312.46 K", + "Mendeleev no": 9, + "Mineral hardness": "0.3", + "Molar volume": "55.76 cm3", + "Name": "Rubidium", + "Oxidation states": [ + 1 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "1": { + "VI": { + "": { + "crystal_radius": 1.66, + "ionic_radius": 1.52 + } + }, + "VII": { + "": { + "crystal_radius": 1.7, + "ionic_radius": 1.56 + } + }, + "VIII": { + "": { + "crystal_radius": 1.75, + "ionic_radius": 1.61 + } + }, + "IX": { + "": { + "crystal_radius": 1.77, + "ionic_radius": 1.63 + } + }, + "X": { + "": { + "crystal_radius": 1.8, + "ionic_radius": 1.66 + } + }, + "XI": { + "": { + "crystal_radius": 1.83, + "ionic_radius": 1.69 + } + }, + "XII": { + "": { + "crystal_radius": 1.86, + "ionic_radius": 1.72 + } + }, + "XIV": { + "": { + "crystal_radius": 1.97, + "ionic_radius": 1.83 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "58 W m-1 K-1", + "Van der waals radius": 3.03, + "Velocity of sound": "1300 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.82, + "Youngs modulus": "2.4 GPa" + }, + "Re": { + "Atomic mass": 186.207, + "Atomic no": 75, + "Atomic orbitals": { + "1s": -2407.665572, + "2p": -380.982869, + "2s": -397.087707, + "3d": -69.57676, + "3p": -83.634578, + "3s": -91.149193, + "4d": -9.516816, + "4f": -1.92508, + "4p": -15.295495, + "4s": -18.454325, + "5d": -0.258639, + "5p": -1.631227, + "5s": -2.567348, + "6s": -0.186859 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.88, + "Boiling point": "5869 K", + "Brinell hardness": "1320 MN m-2", + "Bulk modulus": "370 GPa", + "Coefficient of linear thermal expansion": "6.2 x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "21020 kg m-3", + "Electrical resistivity": "18 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d5.6s2", + "ICSD oxidation states": [ + 3, + 4, + 5, + 6, + 7 + ], + "Ionic radii": { + "4": 0.77, + "5": 0.72, + "6": 0.69, + "7": 0.67 + }, + "Liquid range": "2410 K", + "Melting point": "3459 K", + "Mendeleev no": 58, + "Mineral hardness": "7.0", + "Molar volume": "8.86 cm3", + "Name": "Rhenium", + "Oxidation states": [ + -3, + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "Poissons ratio": "0.30", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "178 GPa", + "Shannon radii": { + "4": { + "VI": { + "": { + "crystal_radius": 0.77, + "ionic_radius": 0.63 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + } + }, + "6": { + "VI": { + "": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.52, + "ionic_radius": 0.38 + } + }, + "VI": { + "": { + "crystal_radius": 0.67, + "ionic_radius": 0.53 + } + } + } + }, + "Superconduction temperature": "1.70 K", + "Thermal conductivity": "48 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4700 m s-1", + "Vickers hardness": "2450 MN m-2", + "X": 1.9, + "Youngs modulus": "463 GPa" + }, + "Rh": { + "Atomic mass": 102.9055, + "Atomic no": 45, + "Atomic orbitals": { + "1s": -821.136773, + "2p": -108.357665, + "2s": -116.80695, + "3d": -11.21725, + "3p": -17.415299, + "3s": -20.765603, + "4d": -0.239422, + "4p": -1.806456, + "4s": -2.825505, + "5s": -0.154624 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.73, + "Boiling point": "3968 K", + "Brinell hardness": "1100 MN m-2", + "Bulk modulus": "380 GPa", + "Coefficient of linear thermal expansion": "8.2 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "12450 kg m-3", + "Electrical resistivity": "4.3 10-8 Ω m", + "Electronic structure": "[Kr].4d8.5s1", + "ICSD oxidation states": [ + 3, + 4 + ], + "Ionic radii": { + "3": 0.805, + "4": 0.74, + "5": 0.69 + }, + "Liquid range": "1731 K", + "Melting point": "2237 K", + "Mendeleev no": 65, + "Mineral hardness": "6.0", + "Molar volume": "8.28 cm3", + "Name": "Rhodium", + "Oxidation states": [ + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.26", + "Reflectivity": "84 %", + "Refractive index": "no data", + "Rigidity modulus": "150 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.805, + "ionic_radius": 0.665 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "150 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4700 m s-1", + "Vickers hardness": "1246 MN m-2", + "X": 2.28, + "Youngs modulus": "275 GPa" + }, + "Rn": { + "Atomic mass": 220.0, + "Atomic no": 86, + "Atomic orbitals": { + "1s": -3204.756288, + "2p": -527.533025, + "2s": -546.57796, + "3d": -106.945006, + "3p": -124.172862, + "3s": -133.369144, + "4d": -19.449994, + "4f": -8.953318, + "4p": -27.108985, + "4s": -31.230804, + "5d": -1.911329, + "5p": -4.408702, + "5s": -5.889683, + "6p": -0.29318, + "6s": -0.62657 + }, + "Atomic radius": "no data", + "Atomic radius calculated": 1.2, + "Boiling point": "211.3 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Critical temperature": "377 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2.6p6", + "Liquid range": "9.3 K", + "Max oxidation state": 0.0, + "Melting point": "202 K", + "Mendeleev no": 6, + "Min oxidation state": 0.0, + "Mineral hardness": "no data", + "Molar volume": "50.50 cm3", + "Name": "Radon", + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.00361 W m-1 K-1", + "Van der waals radius": 2.2, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.2, + "Youngs modulus": "no data GPa" + }, + "Ru": { + "Atomic mass": 101.07, + "Atomic no": 44, + "Atomic orbitals": { + "1s": -782.918621, + "2p": -102.333649, + "2s": -110.536054, + "3d": -10.195668, + "3p": -16.145217, + "3s": -19.366692, + "4d": -0.210375, + "4p": -1.667549, + "4s": -2.628363, + "5s": -0.152834 + }, + "Atomic radius": 1.3, + "Atomic radius calculated": 1.78, + "Boiling point": "4423 K", + "Brinell hardness": "2160 MN m-2", + "Bulk modulus": "220 GPa", + "Coefficient of linear thermal expansion": "6.4 x10-6K-1", + "Common oxidation states": [ + 3, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "12370 kg m-3", + "Electrical resistivity": "7.1 10-8 Ω m", + "Electronic structure": "[Kr].4d7.5s1", + "ICSD oxidation states": [ + 2, + 3, + 4, + 5, + 6 + ], + "Ionic radii": { + "3": 0.82, + "4": 0.76, + "5": 0.705, + "7": 0.52, + "8": 0.5 + }, + "Liquid range": "1816 K", + "Melting point": "2607 K", + "Mendeleev no": 62, + "Mineral hardness": "6.5", + "Molar volume": "8.17 cm3", + "Name": "Ruthenium", + "Oxidation states": [ + -2, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "Poissons ratio": "0.30", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "173 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.82, + "ionic_radius": 0.68 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.76, + "ionic_radius": 0.62 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.705, + "ionic_radius": 0.565 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.52, + "ionic_radius": 0.38 + } + } + }, + "8": { + "IV": { + "": { + "crystal_radius": 0.5, + "ionic_radius": 0.36 + } + } + } + }, + "Superconduction temperature": "0.49 K", + "Thermal conductivity": "120 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "5970 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.2, + "Youngs modulus": "447 GPa" + }, + "S": { + "Atomic mass": 32.065, + "Atomic no": 16, + "Atomic orbitals": { + "1s": -87.789937, + "2p": -5.751257, + "2s": -7.69994, + "3p": -0.261676, + "3s": -0.630912 + }, + "Atomic radius": 1.0, + "Atomic radius calculated": 0.88, + "Boiling point": "717.87 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "7.7 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -2, + 2, + 4, + 6 + ], + "Critical temperature": "1314 K", + "Density of solid": "1960 kg m-3", + "Electrical resistivity": "> 102310-8 Ω m", + "Electronic structure": "[Ne].3s2.3p4", + "ICSD oxidation states": [ + -1, + 2, + 4, + -2, + 6 + ], + "Ionic radii": { + "-2": 1.7, + "4": 0.51, + "6": 0.43 + }, + "Liquid range": "329.51 K", + "Melting point": "388.36 K", + "Mendeleev no": 94, + "Mineral hardness": "2.0", + "Molar volume": "15.53 cm3", + "Name": "Sulfur", + "Oxidation states": [ + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.001111", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "-2": { + "VI": { + "": { + "crystal_radius": 1.7, + "ionic_radius": 1.84 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.51, + "ionic_radius": 0.37 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.26, + "ionic_radius": 0.12 + } + }, + "VI": { + "": { + "crystal_radius": 0.43, + "ionic_radius": 0.29 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.205 W m-1 K-1", + "Van der waals radius": 1.8, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.58, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "S-33": -67.8, + "S-35": 47.1 + } + }, + "Sb": { + "Atomic mass": 121.76, + "Atomic no": 51, + "Atomic orbitals": { + "1s": -1070.823495, + "2p": -149.214271, + "2s": -159.171745, + "3d": -19.239895, + "3p": -26.956184, + "3s": -31.098242, + "4d": -1.297338, + "4p": -3.646579, + "4s": -5.04964, + "5p": -0.185623, + "5s": -0.445605 + }, + "Atomic radius": 1.45, + "Atomic radius calculated": 1.33, + "Boiling point": "1860 K", + "Brinell hardness": "294 MN m-2", + "Bulk modulus": "42 GPa", + "Coefficient of linear thermal expansion": "11 x10-6K-1", + "Common oxidation states": [ + -3, + 3, + 5 + ], + "Critical temperature": "no data K", + "Density of solid": "6697 kg m-3", + "Electrical resistivity": "40 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2.5p3", + "ICSD oxidation states": [ + -2, + 3, + 5, + -1, + -3 + ], + "Ionic radii": { + "3": 0.9, + "5": 0.76 + }, + "Liquid range": "956.22 K", + "Melting point": "903.78 K", + "Mendeleev no": 88, + "Mineral hardness": "3.0", + "Molar volume": "18.19 cm3", + "Name": "Antimony", + "Oxidation states": [ + -3, + 3, + 5 + ], + "Poissons ratio": "no data", + "Reflectivity": "55 %", + "Refractive index": "no data", + "Rigidity modulus": "20 GPa", + "Shannon radii": { + "3": { + "IVPY": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + }, + "V": { + "": { + "crystal_radius": 0.94, + "ionic_radius": 0.8 + } + }, + "VI": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "24 W m-1 K-1", + "Van der waals radius": 2.06, + "Velocity of sound": "3420 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.05, + "Youngs modulus": "55 GPa", + "NMR Quadrupole Moment": { + "Sb-121": -543.11, + "Sb-123": -692.14 + } + }, + "Sc": { + "Atomic mass": 44.955912, + "Atomic no": 21, + "Atomic orbitals": { + "1s": -160.184109, + "2p": -14.240006, + "2s": -17.206464, + "3d": -0.13108, + "3p": -1.233165, + "3s": -1.988378, + "4s": -0.156478 + }, + "Atomic radius": 1.6, + "Atomic radius calculated": 1.84, + "Boiling point": "3103 K", + "Brinell hardness": "750 MN m-2", + "Bulk modulus": "57 GPa", + "Coefficient of linear thermal expansion": "10.2 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "2985 kg m-3", + "Electrical resistivity": "about 55 10-8 Ω m", + "Electronic structure": "[Ar].3d1.4s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "3": 0.885 + }, + "Liquid range": "1289 K", + "Melting point": "1814 K", + "Mendeleev no": 19, + "Mineral hardness": "no data", + "Molar volume": "15.00 cm3", + "Name": "Scandium", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "0.28", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "29 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.885, + "ionic_radius": 0.745 + } + }, + "VIII": { + "": { + "crystal_radius": 1.01, + "ionic_radius": 0.87 + } + } + } + }, + "Superconduction temperature": "0.05 (under pressure)K", + "Thermal conductivity": "16 W m-1 K-1", + "Van der waals radius": 2.11, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.36, + "Youngs modulus": "74 GPa", + "NMR Quadrupole Moment": { + "Sc-45": -220.2 + } + }, + "Se": { + "Atomic mass": 78.96, + "Atomic no": 34, + "Atomic orbitals": { + "1s": -451.300258, + "2p": -51.514388, + "2s": -57.311948, + "3d": -2.011392, + "3p": -5.553517, + "3s": -7.547186, + "4p": -0.245806, + "4s": -0.621248 + }, + "Atomic radius": 1.15, + "Atomic radius calculated": 1.03, + "Boiling point": "958 K", + "Brinell hardness": "736 MN m-2", + "Bulk modulus": "8.3 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -2, + 2, + 4, + 6 + ], + "Critical temperature": "1766 K", + "Density of solid": "4819 kg m-3", + "Electrical resistivity": "high 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2.4p4", + "ICSD oxidation states": [ + -1, + 4, + -2, + 6 + ], + "Ionic radii": { + "-2": 1.84, + "4": 0.64, + "6": 0.56 + }, + "Liquid range": "464 K", + "Melting point": "494 K", + "Mendeleev no": 93, + "Mineral hardness": "2.0", + "Molar volume": "16.42 cm3", + "Name": "Selenium", + "Oxidation states": [ + -2, + 2, + 4, + 6 + ], + "Poissons ratio": "0.33", + "Reflectivity": "no data %", + "Refractive index": "1.000895", + "Rigidity modulus": "3.7 GPa", + "Shannon radii": { + "-2": { + "VI": { + "": { + "crystal_radius": 1.84, + "ionic_radius": 1.98 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.64, + "ionic_radius": 0.5 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.42, + "ionic_radius": 0.28 + } + }, + "VI": { + "": { + "crystal_radius": 0.56, + "ionic_radius": 0.42 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.52 W m-1 K-1", + "Van der waals radius": 1.9, + "Velocity of sound": "3350 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.55, + "Youngs modulus": "10 GPa" + }, + "Si": { + "Atomic mass": 28.0855, + "Atomic no": 14, + "Atomic orbitals": { + "1s": -65.184426, + "2p": -3.514938, + "2s": -5.075056, + "3p": -0.153293, + "3s": -0.398139 + }, + "Atomic radius": 1.1, + "Atomic radius calculated": 1.11, + "Boiling point": "3173 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "100 GPa", + "Coefficient of linear thermal expansion": "2.6 x10-6K-1", + "Common oxidation states": [ + -4, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "2330 kg m-3", + "Electrical resistivity": "about 100000 10-8 Ω m", + "Electronic structure": "[Ne].3s2.3p2", + "ICSD oxidation states": [ + -4, + 4 + ], + "Ionic radii": { + "4": 0.54 + }, + "Liquid range": "1486 K", + "Melting point": "1687 K", + "Mendeleev no": 85, + "Mineral hardness": "6.5", + "Molar volume": "12.06 cm3", + "Name": "Silicon", + "Oxidation states": [ + -4, + -3, + -2, + -1, + 1, + 2, + 3, + 4 + ], + "Poissons ratio": "no data", + "Reflectivity": "28 %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "4": { + "IV": { + "": { + "crystal_radius": 0.4, + "ionic_radius": 0.26 + } + }, + "VI": { + "": { + "crystal_radius": 0.54, + "ionic_radius": 0.4 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "150 W m-1 K-1", + "Van der waals radius": 2.1, + "Velocity of sound": "2200 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.9, + "Youngs modulus": "47 GPa" + }, + "Sm": { + "Atomic mass": 150.36, + "Atomic no": 62, + "Atomic orbitals": { + "1s": -1617.183426, + "2p": -242.729726, + "2s": -255.498846, + "3d": -39.528656, + "3p": -50.08426, + "3s": -55.731133, + "4d": -4.814978, + "4f": -0.21776, + "4p": -8.672685, + "4s": -10.844667, + "5p": -0.835987, + "5s": -1.408552, + "6s": -0.128259 + }, + "Atomic radius": 1.85, + "Atomic radius calculated": 2.38, + "Boiling point": "2076 K", + "Brinell hardness": "441 MN m-2", + "Bulk modulus": "38 GPa", + "Coefficient of linear thermal expansion": "12.7 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "7353 kg m-3", + "Electrical resistivity": "94 10-8 Ω m", + "Electronic structure": "[Xe].4f6.6s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "2": 1.36, + "3": 1.0979999999999999 + }, + "Liquid range": "731 K", + "Melting point": "1345 K", + "Mendeleev no": 28, + "Mineral hardness": "no data", + "Molar volume": "19.98 cm3", + "Name": "Samarium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.27", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "20 GPa", + "Shannon radii": { + "2": { + "VII": { + "": { + "crystal_radius": 1.36, + "ionic_radius": 1.22 + } + }, + "VIII": { + "": { + "crystal_radius": 1.41, + "ionic_radius": 1.27 + } + }, + "IX": { + "": { + "crystal_radius": 1.46, + "ionic_radius": 1.32 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.098, + "ionic_radius": 0.958 + } + }, + "VII": { + "": { + "crystal_radius": 1.16, + "ionic_radius": 1.02 + } + }, + "VIII": { + "": { + "crystal_radius": 1.219, + "ionic_radius": 1.079 + } + }, + "IX": { + "": { + "crystal_radius": 1.272, + "ionic_radius": 1.132 + } + }, + "XII": { + "": { + "crystal_radius": 1.38, + "ionic_radius": 1.24 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "13 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2130 m s-1", + "Vickers hardness": "412 MN m-2", + "X": 1.17, + "Youngs modulus": "50 GPa" + }, + "Sn": { + "Atomic mass": 118.71, + "Atomic no": 50, + "Atomic orbitals": { + "1s": -1026.762169, + "2p": -141.821093, + "2s": -151.523991, + "3d": -17.657276, + "3p": -25.117913, + "3s": -29.125969, + "4d": -1.004952, + "4p": -3.211998, + "4s": -4.546335, + "5p": -0.14445, + "5s": -0.369349 + }, + "Atomic radius": 1.45, + "Atomic radius calculated": 1.45, + "Boiling point": "2875 K", + "Brinell hardness": "51 MN m-2", + "Bulk modulus": "58 GPa", + "Coefficient of linear thermal expansion": "22 x10-6K-1", + "Common oxidation states": [ + -4, + 2, + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "7310 kg m-3", + "Electrical resistivity": "11.5 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2.5p2", + "ICSD oxidation states": [ + 2, + 3, + 4 + ], + "Ionic radii": { + "4": 0.83 + }, + "Liquid range": "2369.92 K", + "Melting point": "505.08 K", + "Mendeleev no": 83, + "Mineral hardness": "1.5", + "Molar volume": "16.29 cm3", + "Name": "Tin", + "Oxidation states": [ + -4, + 2, + 4 + ], + "Poissons ratio": "0.36", + "Reflectivity": "54 %", + "Refractive index": "no data", + "Rigidity modulus": "18 GPa", + "Shannon radii": { + "4": { + "IV": { + "": { + "crystal_radius": 0.69, + "ionic_radius": 0.55 + } + }, + "V": { + "": { + "crystal_radius": 0.76, + "ionic_radius": 0.62 + } + }, + "VI": { + "": { + "crystal_radius": 0.83, + "ionic_radius": 0.69 + } + }, + "VII": { + "": { + "crystal_radius": 0.89, + "ionic_radius": 0.75 + } + }, + "VIII": { + "": { + "crystal_radius": 0.95, + "ionic_radius": 0.81 + } + } + } + }, + "Superconduction temperature": "3.72 K", + "Thermal conductivity": "67 W m-1 K-1", + "Van der waals radius": 2.17, + "Velocity of sound": "2500 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.96, + "Youngs modulus": "50 GPa", + "NMR Quadrupole Moment": { + "Sn-119": -132.1 + } + }, + "Sr": { + "Atomic mass": 87.62, + "Atomic no": 38, + "Atomic orbitals": { + "1s": -572.870169, + "2p": -69.745941, + "2s": -76.491823, + "3d": -4.813498, + "3p": -9.301863, + "3s": -11.771585, + "4p": -0.844489, + "4s": -1.455317, + "5s": -0.131793 + }, + "Atomic radius": 2.0, + "Atomic radius calculated": 2.19, + "Boiling point": "1655 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "22.5 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "2630 kg m-3", + "Electrical resistivity": "13.5 10-8 Ω m", + "Electronic structure": "[Kr].5s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 1.32 + }, + "Liquid range": "605 K", + "Melting point": "1050 K", + "Mendeleev no": 15, + "Mineral hardness": "1.5", + "Molar volume": "33.94 cm3", + "Name": "Strontium", + "Oxidation states": [ + 2 + ], + "Poissons ratio": "0.28", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "6.1 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.32, + "ionic_radius": 1.18 + } + }, + "VII": { + "": { + "crystal_radius": 1.35, + "ionic_radius": 1.21 + } + }, + "VIII": { + "": { + "crystal_radius": 1.4, + "ionic_radius": 1.26 + } + }, + "IX": { + "": { + "crystal_radius": 1.45, + "ionic_radius": 1.31 + } + }, + "X": { + "": { + "crystal_radius": 1.5, + "ionic_radius": 1.36 + } + }, + "XII": { + "": { + "crystal_radius": 1.58, + "ionic_radius": 1.44 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "35 W m-1 K-1", + "Van der waals radius": 2.49, + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 0.95, + "Youngs modulus": "no data GPa", + "NMR Quadrupole Moment": { + "Sr-87": 305.2 + } + }, + "Ta": { + "Atomic mass": 180.94788, + "Atomic no": 73, + "Atomic orbitals": { + "1s": -2275.371387, + "2p": -357.248334, + "2s": -372.828724, + "3d": -63.942521, + "3p": -77.440942, + "3s": -84.658467, + "4d": -8.265848, + "4f": -1.199347, + "4p": -13.71981, + "4s": -16.713337, + "5d": -0.182464, + "5p": -1.37653, + "5s": -2.223807, + "6s": -0.174814 + }, + "Atomic radius": 1.45, + "Atomic radius calculated": 2.0, + "Boiling point": "5731 K", + "Brinell hardness": "800 MN m-2", + "Bulk modulus": "200 GPa", + "Coefficient of linear thermal expansion": "6.3 x10-6K-1", + "Common oxidation states": [ + 5 + ], + "Critical temperature": "no data K", + "Density of solid": "16650 kg m-3", + "Electrical resistivity": "13.5 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d3.6s2", + "ICSD oxidation states": [ + 3, + 4, + 5 + ], + "Ionic radii": { + "3": 0.86, + "4": 0.82, + "5": 0.78 + }, + "Liquid range": "2441 K", + "Melting point": "3290 K", + "Mendeleev no": 52, + "Mineral hardness": "6.5", + "Molar volume": "10.85 cm3", + "Name": "Tantalum", + "Oxidation states": [ + -1, + 2, + 3, + 4, + 5 + ], + "Poissons ratio": "0.34", + "Reflectivity": "78 %", + "Refractive index": "no data", + "Rigidity modulus": "69 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 0.86, + "ionic_radius": 0.72 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.82, + "ionic_radius": 0.68 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.78, + "ionic_radius": 0.64 + } + }, + "VII": { + "": { + "crystal_radius": 0.83, + "ionic_radius": 0.69 + } + }, + "VIII": { + "": { + "crystal_radius": 0.88, + "ionic_radius": 0.74 + } + } + } + }, + "Superconduction temperature": "4.47 K", + "Thermal conductivity": "57 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "3400 m s-1", + "Vickers hardness": "873 MN m-2", + "X": 1.5, + "Youngs modulus": "186 GPa" + }, + "Tb": { + "Atomic mass": 158.92535, + "Atomic no": 65, + "Atomic orbitals": { + "1s": -1785.331942, + "2p": -271.590585, + "2s": -285.121013, + "3d": -45.443863, + "3p": -56.785113, + "3s": -62.851563, + "4d": -5.467662, + "4f": -0.256311, + "4p": -9.735637, + "4s": -12.120486, + "5p": -0.88723, + "5s": -1.513669, + "6s": -0.131677 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": 2.25, + "Boiling point": "3503 K", + "Brinell hardness": "677 MN m-2", + "Bulk modulus": "38.7 GPa", + "Coefficient of linear thermal expansion": "10.3 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "8219 kg m-3", + "Electrical resistivity": "115 10-8 Ω m", + "Electronic structure": "[Xe].4f9.6s2", + "ICSD oxidation states": [ + 3, + 4 + ], + "Ionic radii": { + "3": 1.063, + "4": 0.9 + }, + "Liquid range": "1874 K", + "Melting point": "1629 K", + "Mendeleev no": 26, + "Mineral hardness": "no data", + "Molar volume": "19.30 cm3", + "Name": "Terbium", + "Oxidation states": [ + 1, + 3, + 4 + ], + "Poissons ratio": "0.26", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "22 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.063, + "ionic_radius": 0.923 + } + }, + "VII": { + "": { + "crystal_radius": 1.12, + "ionic_radius": 0.98 + } + }, + "VIII": { + "": { + "crystal_radius": 1.18, + "ionic_radius": 1.04 + } + }, + "IX": { + "": { + "crystal_radius": 1.235, + "ionic_radius": 1.095 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + }, + "VIII": { + "": { + "crystal_radius": 1.02, + "ionic_radius": 0.88 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "11 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2620 m s-1", + "Vickers hardness": "863 MN m-2", + "X": 1.1, + "Youngs modulus": "56 GPa" + }, + "Tc": { + "Atomic mass": 98.0, + "Atomic no": 43, + "Atomic orbitals": { + "1s": -745.742024, + "2p": -96.61021, + "2s": -104.567508, + "3d": -9.33986, + "3p": -15.041738, + "3s": -18.135303, + "4d": -0.270262, + "4p": -1.64323, + "4s": -2.550712, + "5s": -0.183636 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.83, + "Boiling point": "4538 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + 4, + 7 + ], + "Critical temperature": "no data K", + "Density of solid": "11500 kg m-3", + "Electrical resistivity": "about 22 10-8 Ω m", + "Electronic structure": "[Kr].4d5.5s2", + "Ionic radii": { + "4": 0.785, + "5": 0.74, + "7": 0.7 + }, + "Liquid range": "2108 K", + "Melting point": "2430 K", + "Mendeleev no": 59, + "Mineral hardness": "no data", + "Molar volume": "8.63 cm3", + "Name": "Technetium", + "Oxidation states": [ + -3, + -1, + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "4": { + "VI": { + "": { + "crystal_radius": 0.785, + "ionic_radius": 0.645 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + } + }, + "7": { + "IV": { + "": { + "crystal_radius": 0.51, + "ionic_radius": 0.37 + } + }, + "VI": { + "": { + "crystal_radius": 0.7, + "ionic_radius": 0.56 + } + } + } + }, + "Superconduction temperature": "7.8 K", + "Thermal conductivity": "51 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.9, + "Youngs modulus": "no data GPa" + }, + "Te": { + "Atomic mass": 127.6, + "Atomic no": 52, + "Atomic orbitals": { + "1s": -1115.831819, + "2p": -156.808583, + "2s": -167.021776, + "3d": -20.887801, + "3p": -28.860685, + "3s": -33.137485, + "4d": -1.608381, + "4p": -4.100084, + "4s": -5.572846, + "5p": -0.226594, + "5s": -0.520997 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.23, + "Boiling point": "1261 K", + "Brinell hardness": "180 MN m-2", + "Bulk modulus": "65 GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Common oxidation states": [ + -2, + 2, + 4, + 6 + ], + "Critical temperature": "no data K", + "Density of solid": "6240 kg m-3", + "Electrical resistivity": "about 10000 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2.5p4", + "ICSD oxidation states": [ + -2, + 4, + -1, + 6 + ], + "Ionic radii": { + "-2": 2.07, + "4": 1.11, + "6": 0.7 + }, + "Liquid range": "538.34 K", + "Melting point": "722.66 K", + "Mendeleev no": 92, + "Mineral hardness": "2.25", + "Molar volume": "20.46 cm3", + "Name": "Tellurium", + "Oxidation states": [ + -2, + 2, + 4, + 5, + 6 + ], + "Poissons ratio": "no data", + "Reflectivity": "50 %", + "Refractive index": "1.000991", + "Rigidity modulus": "16 GPa", + "Shannon radii": { + "-2": { + "VI": { + "": { + "crystal_radius": 2.07, + "ionic_radius": 2.21 + } + } + }, + "4": { + "III": { + "": { + "crystal_radius": 0.66, + "ionic_radius": 0.52 + } + }, + "IV": { + "": { + "crystal_radius": 0.8, + "ionic_radius": 0.66 + } + }, + "VI": { + "": { + "crystal_radius": 1.11, + "ionic_radius": 0.97 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.57, + "ionic_radius": 0.43 + } + }, + "VI": { + "": { + "crystal_radius": 0.7, + "ionic_radius": 0.56 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "3 W m-1 K-1", + "Van der waals radius": 2.06, + "Velocity of sound": "2610 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.1, + "Youngs modulus": "43 GPa" + }, + "Th": { + "Atomic mass": 232.03806, + "Atomic no": 90, + "Atomic orbitals": { + "1s": -3524.439052, + "2p": -588.218112, + "2s": -608.350958, + "3d": -123.846396, + "3p": -142.25581, + "3s": -152.079741, + "4d": -24.955184, + "4f": -13.397389, + "4p": -33.325252, + "4s": -37.814094, + "5d": -3.625729, + "5p": -6.58281, + "5s": -8.287057, + "6d": -0.172896, + "6p": -0.846921, + "6s": -1.333769, + "7s": -0.135872 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": "no data", + "Boiling point": "5093 K", + "Brinell hardness": "400 MN m-2", + "Bulk modulus": "54 GPa", + "Coefficient of linear thermal expansion": "11.0 x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "11724 kg m-3", + "Electrical resistivity": "15 10-8 Ω m", + "Electronic structure": "[Rn].6d2.7s2", + "ICSD oxidation states": [ + 4 + ], + "Ionic radii": { + "4": 1.08 + }, + "Liquid range": "2978 K", + "Melting point": "2115 K", + "Mendeleev no": 47, + "Mineral hardness": "3.0", + "Molar volume": "19.80 cm3", + "Name": "Thorium", + "Oxidation states": [ + 2, + 3, + 4 + ], + "Poissons ratio": "0.27", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "31 GPa", + "Shannon radii": { + "4": { + "VI": { + "": { + "crystal_radius": 1.08, + "ionic_radius": 0.94 + } + }, + "VIII": { + "": { + "crystal_radius": 1.19, + "ionic_radius": 1.05 + } + }, + "IX": { + "": { + "crystal_radius": 1.23, + "ionic_radius": 1.09 + } + }, + "X": { + "": { + "crystal_radius": 1.27, + "ionic_radius": 1.13 + } + }, + "XI": { + "": { + "crystal_radius": 1.32, + "ionic_radius": 1.18 + } + }, + "XII": { + "": { + "crystal_radius": 1.35, + "ionic_radius": 1.21 + } + } + } + }, + "Superconduction temperature": "1.38 K", + "Thermal conductivity": "54 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "2490 m s-1", + "Vickers hardness": "350 MN m-2", + "X": 1.3, + "Youngs modulus": "79 GPa" + }, + "Ti": { + "Atomic mass": 47.867, + "Atomic no": 22, + "Atomic orbitals": { + "1s": -177.276643, + "2p": -16.285339, + "2s": -19.457901, + "3d": -0.17001, + "3p": -1.422947, + "3s": -2.258007, + "4s": -0.167106 + }, + "Atomic radius": 1.4, + "Atomic radius calculated": 1.76, + "Boiling point": "3560 K", + "Brinell hardness": "716 MN m-2", + "Bulk modulus": "110 GPa", + "Coefficient of linear thermal expansion": "8.6 x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "4507 kg m-3", + "Electrical resistivity": "about 40 10-8 Ω m", + "Electronic structure": "[Ar].3d2.4s2", + "ICSD oxidation states": [ + 2, + 3, + 4 + ], + "Ionic radii": { + "2": 1.0, + "3": 0.81, + "4": 0.745 + }, + "Liquid range": "1619 K", + "Melting point": "1941 K", + "Mendeleev no": 51, + "Mineral hardness": "6.0", + "Molar volume": "10.64 cm3", + "Name": "Titanium", + "Oxidation states": [ + -1, + 2, + 3, + 4 + ], + "Poissons ratio": "0.32", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "44 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.0, + "ionic_radius": 0.86 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 0.81, + "ionic_radius": 0.67 + } + } + }, + "4": { + "IV": { + "": { + "crystal_radius": 0.56, + "ionic_radius": 0.42 + } + }, + "V": { + "": { + "crystal_radius": 0.65, + "ionic_radius": 0.51 + } + }, + "VI": { + "": { + "crystal_radius": 0.745, + "ionic_radius": 0.605 + } + }, + "VIII": { + "": { + "crystal_radius": 0.88, + "ionic_radius": 0.74 + } + } + } + }, + "Superconduction temperature": "0.40 K", + "Thermal conductivity": "22 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4140 m s-1", + "Vickers hardness": "970 MN m-2", + "X": 1.54, + "Youngs modulus": "116 GPa", + "NMR Quadrupole Moment": { + "Ti-47": 302.1, + "Ti-49": 247.11 + } + }, + "Tl": { + "Atomic mass": 204.3833, + "Atomic no": 81, + "Atomic orbitals": { + "1s": -2827.569408, + "2p": -457.255971, + "2s": -474.953368, + "3d": -88.328299, + "3p": -104.099296, + "3s": -112.52218, + "4d": -14.008848, + "4f": -4.835747, + "4p": -20.797078, + "4s": -24.471512, + "5d": -0.674544, + "5p": -2.59873, + "5s": -3.811512, + "6p": -0.101507, + "6s": -0.28502 + }, + "Atomic radius": 1.9, + "Atomic radius calculated": 1.56, + "Boiling point": "1746 K", + "Brinell hardness": "26.4 MN m-2", + "Bulk modulus": "43 GPa", + "Coefficient of linear thermal expansion": "29.9 x10-6K-1", + "Common oxidation states": [ + 1, + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "11850 kg m-3", + "Electrical resistivity": "15 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d10.6s2.6p1", + "ICSD oxidation states": [ + 1, + 3 + ], + "Ionic radii": { + "1": 1.64, + "3": 1.025 + }, + "Liquid range": "1169 K", + "Melting point": "577 K", + "Mendeleev no": 78, + "Mineral hardness": "1.2", + "Molar volume": "17.22 cm3", + "Name": "Thallium", + "Oxidation states": [ + 1, + 3 + ], + "Poissons ratio": "0.45", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "2.8 GPa", + "Shannon radii": { + "1": { + "VI": { + "": { + "crystal_radius": 1.64, + "ionic_radius": 1.5 + } + }, + "VIII": { + "": { + "crystal_radius": 1.73, + "ionic_radius": 1.59 + } + }, + "XII": { + "": { + "crystal_radius": 1.84, + "ionic_radius": 1.7 + } + } + }, + "3": { + "IV": { + "": { + "crystal_radius": 0.89, + "ionic_radius": 0.75 + } + }, + "VI": { + "": { + "crystal_radius": 1.025, + "ionic_radius": 0.885 + } + }, + "VIII": { + "": { + "crystal_radius": 1.12, + "ionic_radius": 0.98 + } + } + } + }, + "Superconduction temperature": "2.38 K", + "Thermal conductivity": "46 W m-1 K-1", + "Van der waals radius": 1.96, + "Velocity of sound": "818 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.62, + "Youngs modulus": "8 GPa" + }, + "Tm": { + "Atomic mass": 168.93421, + "Atomic no": 69, + "Atomic orbitals": { + "1s": -2022.471608, + "2p": -312.510608, + "2s": -327.05712, + "3d": -53.835494, + "3p": -66.239338, + "3s": -72.873753, + "4d": -6.350307, + "4f": -0.28312, + "4p": -11.187151, + "4s": -13.865665, + "5p": -0.950748, + "5s": -1.64999, + "6s": -0.135953 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": 2.22, + "Boiling point": "2223 K", + "Brinell hardness": "471 MN m-2", + "Bulk modulus": "45 GPa", + "Coefficient of linear thermal expansion": "13.3 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "9321 kg m-3", + "Electrical resistivity": "67.6 10-8 Ω m", + "Electronic structure": "[Xe].4f13.6s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "2": 1.17, + "3": 1.02 + }, + "Liquid range": "405 K", + "Melting point": "1818 K", + "Mendeleev no": 21, + "Mineral hardness": "no data", + "Molar volume": "19.1 cm3", + "Name": "Thulium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.21", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "31 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.17, + "ionic_radius": 1.03 + } + }, + "VII": { + "": { + "crystal_radius": 1.23, + "ionic_radius": 1.09 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.02, + "ionic_radius": 0.88 + } + }, + "VIII": { + "": { + "crystal_radius": 1.134, + "ionic_radius": 0.994 + } + }, + "IX": { + "": { + "crystal_radius": 1.192, + "ionic_radius": 1.052 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "17 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "no data m s-1", + "Vickers hardness": "520 MN m-2", + "X": 1.25, + "Youngs modulus": "74 GPa" + }, + "U": { + "Atomic mass": 238.02891, + "Atomic no": 92, + "Atomic orbitals": { + "1s": -3689.355141, + "2p": -619.10855, + "2s": -639.778728, + "3d": -131.977358, + "3p": -150.97898, + "3s": -161.118073, + "4d": -27.123212, + "4f": -15.02746, + "4p": -35.853321, + "4s": -40.528084, + "5d": -3.866175, + "5f": -0.366543, + "5p": -7.018092, + "5s": -8.824089, + "6d": -0.14319, + "6p": -0.822538, + "6s": -1.325976, + "7s": -0.130948 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": "no data", + "Boiling point": "4200 K", + "Brinell hardness": "2400 MN m-2", + "Bulk modulus": "100 GPa", + "Coefficient of linear thermal expansion": "13.9 x10-6K-1", + "Common oxidation states": [ + 6 + ], + "Critical temperature": "no data K", + "Density of solid": "19050 kg m-3", + "Electrical resistivity": "28 10-8 Ω m", + "Electronic structure": "[Rn].5f3.6d1.7s2", + "ICSD oxidation states": [ + 3, + 4, + 5, + 6 + ], + "Ionic radii": { + "3": 1.165, + "4": 1.03, + "5": 0.9, + "6": 0.87 + }, + "Liquid range": "2794.7 K", + "Melting point": "1405.3 K", + "Mendeleev no": 45, + "Mineral hardness": "6.0", + "Molar volume": "12.49 cm3", + "Name": "Uranium", + "Oxidation states": [ + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.23", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "111 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.165, + "ionic_radius": 1.025 + } + } + }, + "4": { + "VI": { + "": { + "crystal_radius": 1.03, + "ionic_radius": 0.89 + } + }, + "VII": { + "": { + "crystal_radius": 1.09, + "ionic_radius": 0.95 + } + }, + "VIII": { + "": { + "crystal_radius": 1.14, + "ionic_radius": 1.0 + } + }, + "IX": { + "": { + "crystal_radius": 1.19, + "ionic_radius": 1.05 + } + }, + "XII": { + "": { + "crystal_radius": 1.31, + "ionic_radius": 1.17 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.9, + "ionic_radius": 0.76 + } + }, + "VII": { + "": { + "crystal_radius": 0.98, + "ionic_radius": 0.84 + } + } + }, + "6": { + "II": { + "": { + "crystal_radius": 0.59, + "ionic_radius": 0.45 + } + }, + "IV": { + "": { + "crystal_radius": 0.66, + "ionic_radius": 0.52 + } + }, + "VI": { + "": { + "crystal_radius": 0.87, + "ionic_radius": 0.73 + } + }, + "VII": { + "": { + "crystal_radius": 0.95, + "ionic_radius": 0.81 + } + }, + "VIII": { + "": { + "crystal_radius": 1.0, + "ionic_radius": 0.86 + } + } + } + }, + "Superconduction temperature": "0.2 K", + "Thermal conductivity": "27 W m-1 K-1", + "Van der waals radius": 1.86, + "Velocity of sound": "3155 m s-1", + "Vickers hardness": "1960 MN m-2", + "X": 1.38, + "Youngs modulus": "208 GPa" + }, + "V": { + "Atomic mass": 50.9415, + "Atomic no": 23, + "Atomic orbitals": { + "1s": -195.224014, + "2p": -18.435189, + "2s": -21.815346, + "3d": -0.204634, + "3p": -1.610516, + "3s": -2.526904, + "4s": -0.175968 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.71, + "Boiling point": "3680 K", + "Brinell hardness": "628 MN m-2", + "Bulk modulus": "160 GPa", + "Coefficient of linear thermal expansion": "8.4 x10-6K-1", + "Common oxidation states": [ + 5 + ], + "Critical temperature": "no data K", + "Density of solid": "6110 kg m-3", + "Electrical resistivity": "20 10-8 Ω m", + "Electronic structure": "[Ar].3d3.4s2", + "ICSD oxidation states": [ + 2, + 3, + 4, + 5 + ], + "Ionic radii": { + "2": 0.93, + "3": 0.78, + "4": 0.72, + "5": 0.68 + }, + "Liquid range": "1497 K", + "Melting point": "2183 K", + "Mendeleev no": 54, + "Mineral hardness": "7.0", + "Molar volume": "8.32 cm3", + "Name": "Vanadium", + "Oxidation states": [ + -1, + 1, + 2, + 3, + 4, + 5 + ], + "Poissons ratio": "0.37", + "Reflectivity": "61 %", + "Refractive index": "no data", + "Rigidity modulus": "47 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 0.93, + "ionic_radius": 0.79 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 0.78, + "ionic_radius": 0.64 + } + } + }, + "4": { + "V": { + "": { + "crystal_radius": 0.67, + "ionic_radius": 0.53 + } + }, + "VI": { + "": { + "crystal_radius": 0.72, + "ionic_radius": 0.58 + } + }, + "VIII": { + "": { + "crystal_radius": 0.86, + "ionic_radius": 0.72 + } + } + }, + "5": { + "IV": { + "": { + "crystal_radius": 0.495, + "ionic_radius": 0.355 + } + }, + "V": { + "": { + "crystal_radius": 0.6, + "ionic_radius": 0.46 + } + }, + "VI": { + "": { + "crystal_radius": 0.68, + "ionic_radius": 0.54 + } + } + } + }, + "Superconduction temperature": "5.40 K", + "Thermal conductivity": "31 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "4560 m s-1", + "Vickers hardness": "628 MN m-2", + "X": 1.63, + "Youngs modulus": "128 GPa", + "NMR Quadrupole Moment": { + "V-50": 210.4, + "V-51": -52.1 + } + }, + "W": { + "Atomic mass": 183.84, + "Atomic no": 74, + "Atomic orbitals": { + "1s": -2341.042887, + "2p": -369.013973, + "2s": -384.856157, + "3d": -66.724787, + "3p": -80.502102, + "3s": -87.867792, + "4d": -8.879693, + "4f": -1.550835, + "4p": -14.495102, + "4s": -17.570797, + "5d": -0.220603, + "5p": -1.504457, + "5s": -2.396018, + "6s": -0.181413 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.93, + "Boiling point": "5828 K", + "Brinell hardness": "2570 MN m-2", + "Bulk modulus": "310 GPa", + "Coefficient of linear thermal expansion": "4.5 x10-6K-1", + "Common oxidation states": [ + 4, + 6 + ], + "Critical temperature": "no data K", + "Density of solid": "19250 kg m-3", + "Electrical resistivity": "5.4 10-8 Ω m", + "Electronic structure": "[Xe].4f14.5d4.6s2", + "ICSD oxidation states": [ + 2, + 3, + 4, + 5, + 6 + ], + "Ionic radii": { + "4": 0.8, + "5": 0.76, + "6": 0.74 + }, + "Liquid range": "2133 K", + "Melting point": "3695 K", + "Mendeleev no": 55, + "Mineral hardness": "7.5", + "Molar volume": "9.47 cm3", + "Name": "Tungsten", + "Oxidation states": [ + -2, + -1, + 1, + 2, + 3, + 4, + 5, + 6 + ], + "Poissons ratio": "0.28", + "Reflectivity": "62 %", + "Refractive index": "no data", + "Rigidity modulus": "161 GPa", + "Shannon radii": { + "4": { + "VI": { + "": { + "crystal_radius": 0.8, + "ionic_radius": 0.66 + } + } + }, + "5": { + "VI": { + "": { + "crystal_radius": 0.76, + "ionic_radius": 0.62 + } + } + }, + "6": { + "IV": { + "": { + "crystal_radius": 0.56, + "ionic_radius": 0.42 + } + }, + "V": { + "": { + "crystal_radius": 0.65, + "ionic_radius": 0.51 + } + }, + "VI": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + } + } + }, + "Superconduction temperature": "0.015 K", + "Thermal conductivity": "170 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "5174 m s-1", + "Vickers hardness": "3430 MN m-2", + "X": 2.36, + "Youngs modulus": "411 GPa" + }, + "Xe": { + "Atomic mass": 131.293, + "Atomic no": 54, + "Atomic orbitals": { + "1s": -1208.688993, + "2p": -172.599583, + "2s": -183.327495, + "3d": -24.37823, + "3p": -32.867042, + "3s": -37.415454, + "4d": -2.286666, + "4p": -5.063802, + "4s": -6.67834, + "5p": -0.309835, + "5s": -0.672086 + }, + "Atomic radius": "no data", + "Atomic radius calculated": 1.08, + "Boiling point": "165.1 K", + "Brinell hardness": "no data MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "no data x10-6K-1", + "Critical temperature": "289.7 K", + "Density of solid": "no data kg m-3", + "Electrical resistivity": "no data 10-8 Ω m", + "Electronic structure": "[Kr].4d10.5s2.5p6", + "Ionic radii": { + "8": 0.62 + }, + "Liquid range": "3.7 K", + "Max oxidation state": 8.0, + "Melting point": "161.4 K", + "Mendeleev no": 5, + "Min oxidation state": 2.0, + "Mineral hardness": "no data", + "Molar volume": "35.92 cm3", + "Name": "Xenon", + "Poissons ratio": "no data", + "Reflectivity": "no data %", + "Refractive index": "1.000702", + "Rigidity modulus": "no data GPa", + "Shannon radii": { + "8": { + "IV": { + "": { + "crystal_radius": 0.54, + "ionic_radius": 0.4 + } + }, + "VI": { + "": { + "crystal_radius": 0.62, + "ionic_radius": 0.48 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "0.00565 W m-1 K-1", + "Van der waals radius": 2.16, + "Velocity of sound": "1090 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 2.6, + "Youngs modulus": "no data GPa" + }, + "Y": { + "Atomic mass": 88.90585, + "Atomic no": 39, + "Atomic orbitals": { + "1s": -605.631981, + "2p": -74.803201, + "2s": -81.789102, + "3d": -5.671499, + "3p": -10.399926, + "3s": -12.992217, + "4d": -0.108691, + "4p": -1.02449, + "4s": -1.697124, + "5s": -0.150727 + }, + "Atomic radius": 1.8, + "Atomic radius calculated": 2.12, + "Boiling point": "3609 K", + "Brinell hardness": "589 MN m-2", + "Bulk modulus": "41 GPa", + "Coefficient of linear thermal expansion": "10.6 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "4472 kg m-3", + "Electrical resistivity": "about 60 10-8 Ω m", + "Electronic structure": "[Kr].4d1.5s2", + "ICSD oxidation states": [ + 3 + ], + "Ionic radii": { + "3": 1.04 + }, + "Liquid range": "1810 K", + "Melting point": "1799 K", + "Mendeleev no": 25, + "Mineral hardness": "no data", + "Molar volume": "19.88 cm3", + "Name": "Yttrium", + "Oxidation states": [ + 1, + 2, + 3 + ], + "Poissons ratio": "0.24", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "26 GPa", + "Shannon radii": { + "3": { + "VI": { + "": { + "crystal_radius": 1.04, + "ionic_radius": 0.9 + } + }, + "VII": { + "": { + "crystal_radius": 1.1, + "ionic_radius": 0.96 + } + }, + "VIII": { + "": { + "crystal_radius": 1.159, + "ionic_radius": 1.019 + } + }, + "IX": { + "": { + "crystal_radius": 1.215, + "ionic_radius": 1.075 + } + } + } + }, + "Superconduction temperature": "1.3 (under pressure)K", + "Thermal conductivity": "17 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "3300 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.22, + "Youngs modulus": "64 GPa" + }, + "Yb": { + "Atomic mass": 173.04, + "Atomic no": 70, + "Atomic orbitals": { + "1s": -2084.069389, + "2p": -323.178219, + "2s": -337.978976, + "3d": -56.026315, + "3p": -68.698655, + "3s": -75.47663, + "4d": -6.574963, + "4f": -0.286408, + "4p": -11.558246, + "4s": -14.312076, + "5p": -0.966137, + "5s": -1.683886, + "6s": -0.136989 + }, + "Atomic radius": 1.75, + "Atomic radius calculated": 2.22, + "Boiling point": "1469 K", + "Brinell hardness": "343 MN m-2", + "Bulk modulus": "31 GPa", + "Coefficient of linear thermal expansion": "26.3 x10-6K-1", + "Common oxidation states": [ + 3 + ], + "Critical temperature": "no data K", + "Density of solid": "6570 kg m-3", + "Electrical resistivity": "25.0 10-8 Ω m", + "Electronic structure": "[Xe].4f14.6s2", + "ICSD oxidation states": [ + 2, + 3 + ], + "Ionic radii": { + "2": 1.16, + "3": 1.008 + }, + "Liquid range": "372 K", + "Melting point": "1097 K", + "Mendeleev no": 17, + "Mineral hardness": "no data", + "Molar volume": "24.84 cm3", + "Name": "Ytterbium", + "Oxidation states": [ + 2, + 3 + ], + "Poissons ratio": "0.21", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "9.9 GPa", + "Shannon radii": { + "2": { + "VI": { + "": { + "crystal_radius": 1.16, + "ionic_radius": 1.02 + } + }, + "VII": { + "": { + "crystal_radius": 1.22, + "ionic_radius": 1.08 + } + }, + "VIII": { + "": { + "crystal_radius": 1.28, + "ionic_radius": 1.14 + } + } + }, + "3": { + "VI": { + "": { + "crystal_radius": 1.008, + "ionic_radius": 0.868 + } + }, + "VII": { + "": { + "crystal_radius": 1.065, + "ionic_radius": 0.925 + } + }, + "VIII": { + "": { + "crystal_radius": 1.125, + "ionic_radius": 0.985 + } + }, + "IX": { + "": { + "crystal_radius": 1.182, + "ionic_radius": 1.042 + } + } + } + }, + "Superconduction temperature": "no data K", + "Thermal conductivity": "39 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "1590 m s-1", + "Vickers hardness": "206 MN m-2", + "X": 1.1, + "Youngs modulus": "24 GPa" + }, + "Zn": { + "Atomic mass": 65.409, + "Atomic no": 30, + "Atomic orbitals": { + "1s": -344.969756, + "2p": -36.648765, + "2s": -41.531323, + "3d": -0.398944, + "3p": -3.022363, + "3s": -4.573041, + "4s": -0.222725 + }, + "Atomic radius": 1.35, + "Atomic radius calculated": 1.42, + "Boiling point": "1180 K", + "Brinell hardness": "412 MN m-2", + "Bulk modulus": "70 GPa", + "Coefficient of linear thermal expansion": "30.2 x10-6K-1", + "Common oxidation states": [ + 2 + ], + "Critical temperature": "no data K", + "Density of solid": "7140 kg m-3", + "Electrical resistivity": "6.0 10-8 Ω m", + "Electronic structure": "[Ar].3d10.4s2", + "ICSD oxidation states": [ + 2 + ], + "Ionic radii": { + "2": 0.88 + }, + "Liquid range": "487.32 K", + "Melting point": "692.68 K", + "Mendeleev no": 76, + "Mineral hardness": "2.5", + "Molar volume": "9.16 cm3", + "Name": "Zinc", + "Oxidation states": [ + 1, + 2 + ], + "Poissons ratio": "0.25", + "Reflectivity": "80 %", + "Refractive index": "1.002050", + "Rigidity modulus": "43 GPa", + "Shannon radii": { + "2": { + "IV": { + "": { + "crystal_radius": 0.74, + "ionic_radius": 0.6 + } + }, + "V": { + "": { + "crystal_radius": 0.82, + "ionic_radius": 0.68 + } + }, + "VI": { + "": { + "crystal_radius": 0.88, + "ionic_radius": 0.74 + } + }, + "VIII": { + "": { + "crystal_radius": 1.04, + "ionic_radius": 0.9 + } + } + } + }, + "Superconduction temperature": "0.85 K", + "Thermal conductivity": "120 W m-1 K-1", + "Van der waals radius": 1.39, + "Velocity of sound": "3700 m s-1", + "Vickers hardness": "no data MN m-2", + "X": 1.65, + "Youngs modulus": "108 GPa", + "NMR Quadrupole Moment": { + "Zn-67": 150.15 + } + }, + "Zr": { + "Atomic mass": 91.224, + "Atomic no": 40, + "Atomic orbitals": { + "1s": -639.292236, + "2p": -80.010043, + "2s": -87.237062, + "3d": -6.544643, + "3p": -11.514415, + "3s": -14.230432, + "4d": -0.150673, + "4p": -1.186597, + "4s": -1.918971, + "5s": -0.162391 + }, + "Atomic radius": 1.55, + "Atomic radius calculated": 2.06, + "Boiling point": "4682 K", + "Brinell hardness": "650 MN m-2", + "Bulk modulus": "no data GPa", + "Coefficient of linear thermal expansion": "5.7 x10-6K-1", + "Common oxidation states": [ + 4 + ], + "Critical temperature": "no data K", + "Density of solid": "6511 kg m-3", + "Electrical resistivity": "43.3 10-8 Ω m", + "Electronic structure": "[Kr].4d2.5s2", + "ICSD oxidation states": [ + 2, + 3, + 4 + ], + "Ionic radii": { + "4": 0.86 + }, + "Liquid range": "2554 K", + "Melting point": "2128 K", + "Mendeleev no": 49, + "Mineral hardness": "5.0", + "Molar volume": "14.02 cm3", + "Name": "Zirconium", + "Oxidation states": [ + 1, + 2, + 3, + 4 + ], + "Poissons ratio": "0.34", + "Reflectivity": "no data %", + "Refractive index": "no data", + "Rigidity modulus": "33 GPa", + "Shannon radii": { + "4": { + "IV": { + "": { + "crystal_radius": 0.73, + "ionic_radius": 0.59 + } + }, + "V": { + "": { + "crystal_radius": 0.8, + "ionic_radius": 0.66 + } + }, + "VI": { + "": { + "crystal_radius": 0.86, + "ionic_radius": 0.72 + } + }, + "VII": { + "": { + "crystal_radius": 0.92, + "ionic_radius": 0.78 + } + }, + "VIII": { + "": { + "crystal_radius": 0.98, + "ionic_radius": 0.84 + } + }, + "IX": { + "": { + "crystal_radius": 1.03, + "ionic_radius": 0.89 + } + } + } + }, + "Superconduction temperature": "0.61 K", + "Thermal conductivity": "23 W m-1 K-1", + "Van der waals radius": "no data", + "Velocity of sound": "3800 m s-1", + "Vickers hardness": "903 MN m-2", + "X": 1.33, + "Youngs modulus": "68 GPa" + } } \ No newline at end of file diff --git a/plotting/my_plotly.py b/plotting/my_plotly.py index 480ff6d..5593c78 100644 --- a/plotting/my_plotly.py +++ b/plotting/my_plotly.py @@ -1,251 +1,258 @@ -#!/usr/bin/env python - -"""My plot settings and methods. - -Author: Raul A. Flores -""" - -#| - Import Modules -import plotly - -import os -# import plotly.plotly as py -import chart_studio.plotly as py -import plotly.graph_objs as go - -from plotly import io as pyio -#__| - - -#| - Plotly -def reapply_colors(data): - """Redefines the line colors of a plotly data series. - - Groups by legend grouping, fix this it's not general enough - - Args: - plotly data series (list of graph objects to be plotted) - """ - #| - reapply_colors - from colors.colors import generate_color_palette - - dat_lst_master = data - - groups_list = [] - for series_i in dat_lst_master: - groups_list.append(series_i.legendgroup) - - groups_list = list(set(groups_list)) - # print(groups_list) - - num_series = len(groups_list) - colors = generate_color_palette(bins=num_series) - - new_list = [] - for color in colors: - color_new = tuple([int(255 * x) for x in color]) - color_new = "rgb" + str(color_new) - new_list.append(color_new.replace(" ", "")) - colors = new_list - - colors_dict = dict(zip(groups_list, colors)) - - for series_i in dat_lst_master: - tmp = colors_dict[series_i.legendgroup] - - series_i.marker["color"] = tmp - series_i.line["color"] = tmp - - return(dat_lst_master) - #__| - -def plot_layout( - # xax_labels = - ): - """ - """ - #| - plot_layout - - #| - Plot Settings - plot_title_size = 18 - tick_lab_size = 16 - axes_lab_size = 18 - legend_size = 18 - #__| - - #| - Plot Layout - xax_labels = ["O2", "OOH", "O", "OH", "H2O"] - layout = { - - "title": "FED of ORR Mechanism For Iron-Supported-Graphene", - - "font": { - "family": "Courier New, monospace", - "size": plot_title_size, - "color": "black", - }, - - #| - Axes -------------------------------------------------------------- - "yaxis": { - "title": "Free Energy [eV]", - "zeroline": True, - "titlefont": dict(size=axes_lab_size), - "showgrid": False, - "tickfont": dict( - size=tick_lab_size, - ), - }, - - "xaxis": { - "title": "Reaction Coordinate", - "zeroline": True, - "titlefont": dict(size=axes_lab_size), - "showgrid": False, - - # "showticklabels": False, - - "ticktext": xax_labels, - "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], - - "tickfont": dict( - size=tick_lab_size, - ), - }, - #__| ------------------------------------------------------------------- - - #| - Legend ------------------------------------------------------------ - "legend": { - "traceorder": "normal", - "font": dict(size=legend_size) - }, - #__| ------------------------------------------------------------------- - - #| - Plot Size - "width": 200 * 4., - "height": 200 * 3., - #__| - - } - #__| - - fig = Figure(data=dat_lst, layout=layout) - # plotly.plotly.image.save_as(fig, filename="pl_hab_opda_raman.png") - - plotly.offline.plot( - { - "data": dat_lst, - "layout": layout, - }, - filename="plots/pl_fed_supp_graph_02.html" - ) - - # tmp = plotly.plotly.image.plot(data, filename="pl_fed_180314.png") - - return(layout) - - #__| - -#__| - - - -def my_plotly_plot( - layout=None, - layout_override=None, - plot_name=None, - save_dir=None, - data=None, - upload_plot=True, - ): - """ - TODO: - Remove layout override functionality, this should be done before calling - the method - - Args: - --------------------------------------------------------------------------- - layout: - plotly layout - layout_override: - Dictionary to override layout - plot_name: - Plot name (used both for plot upload and local save) - save_dir: - Plot.ly folder to save figure into (Not used for local save) - data: - plotly data object - upload_plot: - Upload plot to plotly servers - - """ - #| - plot_proto - if layout is None: - layout = go.Layout() - - layout.update(layout_override) - - fig = go.Figure(data=data, layout=layout) - - #| - Upload to plot.ly website - # ######################################################################### - if upload_plot: - plotly_filename = os.path.join( - save_dir, - # "02_oer_analysis", - # "oer_2d_volcano_plot", - plot_name) - tmp = py.iplot(fig, filename=plotly_filename) - print(plotly_filename) - #__| - - #| - Local write to HTML - # ######################################################################### - plot_dir = "out_plot" - if not os.path.exists(plot_dir): - os.makedirs(plot_dir) - - local_filename = os.path.join( - plot_dir, - plot_name + ".html" - ) - - pyio.write_html( - { - "data": data, - "layout": layout, - - }, - local_filename, - ) - #__| - - #| - Write pdf and svg (if ORCA is installed and working) - import socket - hostname = socket.gethostbyaddr(socket.gethostname())[0] - - # Requires ORCA installation - if os.environ["USER"] == "raul-ubuntu-desktop" or hostname == "raul-ubuntu-vb": - print("Writing pdf with ORCA") - - # pyio.write_json( - # { - # "data": data, - # "layout": layout, - # }, - # os.path.join(plot_dir, plot_name + ".pdf")) - - # This seems to be the preferred syntax now - fig.write_image( - os.path.join(plot_dir, plot_name + ".pdf") - # "out_plot/test_fig.pdf" - ) - - # This seems to be the preferred syntax now - fig.write_image( - os.path.join(plot_dir, plot_name + ".svg") - # "out_plot/test_fig.pdf" - ) - #__| - - return(fig) - #__| +#!/usr/bin/env python + +"""My plot settings and methods. + +Author: Raul A. Flores +""" + +#| - Import Modules +import plotly + +import os +# import plotly.plotly as py +import chart_studio.plotly as py +import plotly.graph_objs as go + +from plotly import io as pyio +#__| + + +#| - Plotly +def reapply_colors(data): + """Redefines the line colors of a plotly data series. + + Groups by legend grouping, fix this it's not general enough + + Args: + plotly data series (list of graph objects to be plotted) + """ + #| - reapply_colors + from colors.colors import generate_color_palette + + dat_lst_master = data + + groups_list = [] + for series_i in dat_lst_master: + groups_list.append(series_i.legendgroup) + + groups_list = list(set(groups_list)) + # print(groups_list) + + num_series = len(groups_list) + colors = generate_color_palette(bins=num_series) + + new_list = [] + for color in colors: + color_new = tuple([int(255 * x) for x in color]) + color_new = "rgb" + str(color_new) + new_list.append(color_new.replace(" ", "")) + colors = new_list + + colors_dict = dict(zip(groups_list, colors)) + + for series_i in dat_lst_master: + tmp = colors_dict[series_i.legendgroup] + + series_i.marker["color"] = tmp + series_i.line["color"] = tmp + + return(dat_lst_master) + #__| + +def plot_layout( + # xax_labels = + ): + """ + """ + #| - plot_layout + + #| - Plot Settings + plot_title_size = 18 + tick_lab_size = 16 + axes_lab_size = 18 + legend_size = 18 + #__| + + #| - Plot Layout + xax_labels = ["O2", "OOH", "O", "OH", "H2O"] + layout = { + + "title": "FED of ORR Mechanism For Iron-Supported-Graphene", + + "font": { + "family": "Courier New, monospace", + "size": plot_title_size, + "color": "black", + }, + + #| - Axes -------------------------------------------------------------- + "yaxis": { + "title": "Free Energy [eV]", + "zeroline": True, + "titlefont": dict(size=axes_lab_size), + "showgrid": False, + "tickfont": dict( + size=tick_lab_size, + ), + }, + + "xaxis": { + "title": "Reaction Coordinate", + "zeroline": True, + "titlefont": dict(size=axes_lab_size), + "showgrid": False, + + # "showticklabels": False, + + "ticktext": xax_labels, + "tickvals": [1.5 * i + 0.5 for i in range(len(xax_labels))], + + "tickfont": dict( + size=tick_lab_size, + ), + }, + #__| ------------------------------------------------------------------- + + #| - Legend ------------------------------------------------------------ + "legend": { + "traceorder": "normal", + "font": dict(size=legend_size) + }, + #__| ------------------------------------------------------------------- + + #| - Plot Size + "width": 200 * 4., + "height": 200 * 3., + #__| + + } + #__| + + fig = Figure(data=dat_lst, layout=layout) + # plotly.plotly.image.save_as(fig, filename="pl_hab_opda_raman.png") + + plotly.offline.plot( + { + "data": dat_lst, + "layout": layout, + }, + filename="plots/pl_fed_supp_graph_02.html" + ) + + # tmp = plotly.plotly.image.plot(data, filename="pl_fed_180314.png") + + return(layout) + + #__| + +#__| + + + +def my_plotly_plot( + figure=None, + layout=None, + layout_override=None, + plot_name=None, + save_dir=None, + data=None, + upload_plot=True, + ): + """ + TODO: + Remove layout override functionality, this should be done before calling + the method + + Returns: Plotly figure object + + Args: + --------------------------------------------------------------------------- + layout: + plotly layout + layout_override: + Dictionary to override layout + plot_name: + Plot name (used both for plot upload and local save) + save_dir: + Plot.ly folder to save figure into (Not used for local save) + data: + plotly data object + upload_plot: + Upload plot to plotly servers + + """ + #| - plot_proto + if layout is None: + layout = go.Layout() + + if figure is not None: + fig = figure + else: + fig = go.Figure(data=data, layout=layout) + + + fig.layout.update(layout_override) + + + #| - Upload to plot.ly website + # ######################################################################### + if upload_plot: + plotly_filename = os.path.join( + save_dir, + # "02_oer_analysis", + # "oer_2d_volcano_plot", + plot_name) + tmp = py.iplot(fig, filename=plotly_filename) + print(plotly_filename) + #__| + + + # ######################################################################### + plot_dir = "out_plot" + if not os.path.exists(plot_dir): + os.makedirs(plot_dir) + + + #| - Local write to HTML + pyio.write_html( + fig, + os.path.join(plot_dir, plot_name + ".html"), + # config=None, + # auto_play=True, + # include_plotlyjs=True, + # include_mathjax=False, + # post_script=None, + # full_html=True, + # animation_opts=None, + # validate=True, + # default_width='100%', + # default_height='100%', + # auto_open=False, + ) + #__| + + + #| - Write pdf and svg (if ORCA is installed and working) + import socket + hostname = socket.gethostbyaddr(socket.gethostname())[0] + + # Requires ORCA installation + if os.environ["USER"] == "raul-ubuntu-desktop" or hostname == "raul-ubuntu-vb": + print("Writing pdf with ORCA") + + # This seems to be the preferred syntax now + fig.write_image( + os.path.join(plot_dir, plot_name + ".pdf") + # "out_plot/test_fig.pdf" + ) + + # This seems to be the preferred syntax now + fig.write_image( + os.path.join(plot_dir, plot_name + ".svg") + # "out_plot/test_fig.pdf" + ) + #__| + + + return(fig) + #__| diff --git a/plotting/plotly_layout_template.py b/plotting/plotly_layout_template.py new file mode 100644 index 0000000..cc560d6 --- /dev/null +++ b/plotting/plotly_layout_template.py @@ -0,0 +1,190 @@ +""" +""" + +#| - Import Modules +import plotly.graph_objs as go +#__| + +# ############################################################################# + + +#| - Main layout object +layout = go.Layout( + angularaxis=None, + annotations=None, + annotationdefaults=None, + autosize=None, + bargap=None, + bargroupgap=None, + barmode=None, + barnorm=None, + boxgap=None, + boxgroupgap=None, + boxmode=None, + calendar=None, + clickmode=None, + coloraxis=None, + colorscale=None, + colorway=None, + datarevision=None, + direction=None, + dragmode=None, + editrevision=None, + extendfunnelareacolors=None, + extendpiecolors=None, + extendsunburstcolors=None, + font=None, + funnelareacolorway=None, + funnelgap=None, + funnelgroupgap=None, + funnelmode=None, + geo=None, + grid=None, + height=None, + hiddenlabels=None, + hiddenlabelssrc=None, + hidesources=None, + hoverdistance=None, + hoverlabel=None, + hovermode=None, + images=None, + imagedefaults=None, + legend=None, + mapbox=None, + margin=None, + meta=None, + metasrc=None, + modebar=None, + orientation=None, + paper_bgcolor=None, + piecolorway=None, + plot_bgcolor=None, + polar=None, + radialaxis=None, + scene=None, + selectdirection=None, + selectionrevision=None, + separators=None, + shapes=None, + shapedefaults=None, + showlegend=None, + sliders=None, + sliderdefaults=None, + spikedistance=None, + sunburstcolorway=None, + template=None, + ternary=None, + title=None, + titlefont=None, + transition=None, + uirevision=None, + updatemenus=None, + updatemenudefaults=None, + violingap=None, + violingroupgap=None, + violinmode=None, + waterfallgap=None, + waterfallgroupgap=None, + waterfallmode=None, + width=None, + xaxis=None, + yaxis=None, + ) +#__| + + +#| - Axis Layout options + +#| - shared axis dict +shared_axis_dict = dict( + anchor=None, + automargin=None, + autorange=None, + calendar=None, + categoryarray=None, + categoryarraysrc=None, + categoryorder=None, + color=None, + constrain=None, + constraintoward=None, + dividercolor=None, + dividerwidth=None, + domain=None, + dtick=None, + exponentformat=None, + fixedrange=None, + gridcolor=None, + gridwidth=None, + hoverformat=None, + layer=None, + linecolor=None, + linewidth=None, + matches=None, + mirror=None, + nticks=None, + overlaying=None, + position=None, + range=None, + rangemode=None, + scaleanchor=None, + scaleratio=None, + separatethousands=None, + showdividers=None, + showexponent=None, + showgrid=None, + showline=None, + showspikes=None, + showticklabels=None, + showtickprefix=None, + showticksuffix=None, + side=None, + spikecolor=None, + spikedash=None, + spikemode=None, + spikesnap=None, + spikethickness=None, + tick0=None, + tickangle=None, + tickcolor=None, + tickfont=None, + tickformat=None, + tickformatstops=None, + tickformatstopdefaults=None, + ticklen=None, + tickmode=None, + tickprefix=None, + ticks=None, + tickson=None, + ticksuffix=None, + ticktext=None, + ticktextsrc=None, + tickvals=None, + tickvalssrc=None, + tickwidth=None, + title=None, + titlefont=None, + type=None, + uirevision=None, + visible=None, + zeroline=None, + zerolinecolor=None, + zerolinewidth=None, + ) +#__| + +xaxis_layout = go.layout.XAxis(shared_axis_dict) +xaxis_layout.update(go.layout.XAxis( + title="ISJFIDJSF", + rangeselector=None, + rangeslider=None, + )) + +yaxis_layout = go.layout.YAxis(shared_axis_dict) +yaxis_layout.update(go.layout.YAxis( + title="ISJFIDJSF", + )) +#__| + + +layout.xaxis = xaxis_layout +layout.yaxis = yaxis_layout diff --git a/pourbaix_pymatgen/LICENSE b/pourbaix_pymatgen/LICENSE index fe05c81..53a365c 100644 --- a/pourbaix_pymatgen/LICENSE +++ b/pourbaix_pymatgen/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2017 Raul Flores - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2017 Raul Flores + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pourbaix_pymatgen/README.md b/pourbaix_pymatgen/README.md index 8557a42..24146ec 100644 --- a/pourbaix_pymatgen/README.md +++ b/pourbaix_pymatgen/README.md @@ -1,2 +1,2 @@ -# pourbaix_pymatgen -Pourbaix construction and analysis using Materials Project database +# pourbaix_pymatgen +Pourbaix construction and analysis using Materials Project database diff --git a/pourbaix_pymatgen/data_exp_form_e.py b/pourbaix_pymatgen/data_exp_form_e.py index 8b03294..e4493b2 100644 --- a/pourbaix_pymatgen/data_exp_form_e.py +++ b/pourbaix_pymatgen/data_exp_form_e.py @@ -1,122 +1,122 @@ -"""TEMP TEMP - 180317""" - -def formation_e_data_dict(): - """ - Dictionary of formation energies for transition metal species. - - All energies are in [eV] - """ - #| - - formation_e_data_dict - import ast - direct_0 = '/home/flores12/01_ORR-MatStabScreen/01_virenv-pymatgen/01_data/03_formation_e/' - List = open(direct_0+'data.py').read().splitlines() - # Returns python list of entries_lst from read data file - entries_lst = [] - line_cnt = 1 - for i in List: - # print str(line_cnt)+' :'+str(i) - if not i=="": - if i[0]=='#': - line_cnt=line_cnt+1 - continue - else: - try: - entries_lst.append(ast.literal_eval(i)) - except: - print 'data_exp_form_e.formation_e_data_dict - error with line: '+str(line_cnt) - line_cnt=line_cnt+1 - ## Turns entry lists into dictionaries - cf_k = "chem_formula" # Chemical formula list key - fe_k = "form_e" # Formation energy key - r_k = "reference" # Literature reference key - c_k = "comments" # Comments key - - entries = [] - for i in entries_lst: - entry_dict = {} - entry_dict[cf_k] = i[0] - entry_dict[fe_k] = i[1] - entry_dict[r_k] = i[2] - entry_dict[c_k] = i[3] - entries.append(entry_dict) - - chem_form_lst = [] - for entry in entries: - # chem_form = entry[0] - chem_form_lst.append(frozenset(entry[cf_k])) - unique_entries_lst = list(list(i) for i in list(set(chem_form_lst))) - - dict = {} - for i in unique_entries_lst: - dict[frozenset(i)]=[] - for j in entries: - if set(j[cf_k])==set(i): - dict[frozenset(i)].append(j) - return dict - - #__| - -def get_entry(chemical_formula_list, data_dict): - """ - - Args: - chemical_formula_list: - data_dict: - """ - #| - - get_entry - # print chemical_formula_list - key = frozenset(chemical_formula_list) - - try: - entry = data_dict[key] - except KeyError: - entry = None - # print 'data_exp_form_e.get_entry - no experimental data available' - - return entry - - #__| - -# form_e_data = formation_e_data_dict() -# temp = get_entry(['Pt1','O2'],form_e_data) - -def oxygen_stoich(exp_entry): - """ - - Args: - exp_entry - """ - #| - - oxygen_stoich - formula = exp_entry['chem_formula'] - for i in formula: - if i[0]=='O' and i[1].isdigit()==True: - num_of_digits = len(i)-1 - if num_of_digits==1: - oxy_num = int(i[1]) - elif num_of_digits>1: - oxy_num = int(i[1:]) - break - return oxy_num - - #__| - - -#| - - Possible code to take "Pt2O3 and extract out the elements and stoicheometric numbers" -# import re -# -# chem_form_lst = [] -# for entry in entries_lst: -# -# chem_form = entry[0] -# form_e = entry[1] -# ref = entry[2] -# comments = entry[3] -# -# chem_form_lst.append(set(chem_form)) -# -# ## Separating the element name from the stoicheometric factor -# for element in chem_form: -# elem_stoich = re.match(r"([a-z]+)([0-9]+)", element, re.I).groups() -# elem = elem_stoich[0] -# stoich = elem_stoich[1] -#__| +"""TEMP TEMP - 180317""" + +def formation_e_data_dict(): + """ + Dictionary of formation energies for transition metal species. + + All energies are in [eV] + """ + #| - - formation_e_data_dict + import ast + direct_0 = '/home/flores12/01_ORR-MatStabScreen/01_virenv-pymatgen/01_data/03_formation_e/' + List = open(direct_0+'data.py').read().splitlines() + # Returns python list of entries_lst from read data file + entries_lst = [] + line_cnt = 1 + for i in List: + # print str(line_cnt)+' :'+str(i) + if not i=="": + if i[0]=='#': + line_cnt=line_cnt+1 + continue + else: + try: + entries_lst.append(ast.literal_eval(i)) + except: + print 'data_exp_form_e.formation_e_data_dict - error with line: '+str(line_cnt) + line_cnt=line_cnt+1 + ## Turns entry lists into dictionaries + cf_k = "chem_formula" # Chemical formula list key + fe_k = "form_e" # Formation energy key + r_k = "reference" # Literature reference key + c_k = "comments" # Comments key + + entries = [] + for i in entries_lst: + entry_dict = {} + entry_dict[cf_k] = i[0] + entry_dict[fe_k] = i[1] + entry_dict[r_k] = i[2] + entry_dict[c_k] = i[3] + entries.append(entry_dict) + + chem_form_lst = [] + for entry in entries: + # chem_form = entry[0] + chem_form_lst.append(frozenset(entry[cf_k])) + unique_entries_lst = list(list(i) for i in list(set(chem_form_lst))) + + dict = {} + for i in unique_entries_lst: + dict[frozenset(i)]=[] + for j in entries: + if set(j[cf_k])==set(i): + dict[frozenset(i)].append(j) + return dict + + #__| + +def get_entry(chemical_formula_list, data_dict): + """ + + Args: + chemical_formula_list: + data_dict: + """ + #| - - get_entry + # print chemical_formula_list + key = frozenset(chemical_formula_list) + + try: + entry = data_dict[key] + except KeyError: + entry = None + # print 'data_exp_form_e.get_entry - no experimental data available' + + return entry + + #__| + +# form_e_data = formation_e_data_dict() +# temp = get_entry(['Pt1','O2'],form_e_data) + +def oxygen_stoich(exp_entry): + """ + + Args: + exp_entry + """ + #| - - oxygen_stoich + formula = exp_entry['chem_formula'] + for i in formula: + if i[0]=='O' and i[1].isdigit()==True: + num_of_digits = len(i)-1 + if num_of_digits==1: + oxy_num = int(i[1]) + elif num_of_digits>1: + oxy_num = int(i[1:]) + break + return oxy_num + + #__| + + +#| - - Possible code to take "Pt2O3 and extract out the elements and stoicheometric numbers" +# import re +# +# chem_form_lst = [] +# for entry in entries_lst: +# +# chem_form = entry[0] +# form_e = entry[1] +# ref = entry[2] +# comments = entry[3] +# +# chem_form_lst.append(set(chem_form)) +# +# ## Separating the element name from the stoicheometric factor +# for element in chem_form: +# elem_stoich = re.match(r"([a-z]+)([0-9]+)", element, re.I).groups() +# elem = elem_stoich[0] +# stoich = elem_stoich[1] +#__| diff --git a/pourbaix_pymatgen/element_list.py b/pourbaix_pymatgen/element_list.py index 8572ad7..9509caf 100644 --- a/pourbaix_pymatgen/element_list.py +++ b/pourbaix_pymatgen/element_list.py @@ -1,125 +1,125 @@ -from pymatgen.core.periodic_table import Element # Call elements by atomic # -class ElementList(object): - """ - Class for creating element lists and ranges - By default the first list created is in order of atomic number - Args: - N/A - """ - #| - - ElementList - def __init__(self, atom_num_lst=[[]]): - self.atom_num_lst = atom_num_lst - if not atom_num_lst==[[]]: - self.list = self.mk_lst_atnum() - self.trans_met = self.mk_lst_trans_met() - - def mk_lst_atnum(self): - """ - Makes list of elements from the atom_num_lst input - """ - elem_rnge=[] - for i in self.atom_num_lst: - el_strt=i[0] - el_end=i[1] - rnge_sect=range(el_strt,el_end+1) - elem_rnge.extend(rnge_sect) - elements=[] - for i in elem_rnge: - element=Element.from_Z(i) # Indice -> pymatgen element object - elements.append(element) - return elements - print elements - - def mk_lst_trans_met(self): - """ - Produces list of transition metals in order of atomic number - """ - elem_rnge_I = [[21,30],[39,44],[46,48],[74,76],[78,80]] - elem_rnge=[] - for i in elem_rnge_I: - el_strt=i[0] - el_end=i[1] - rnge_sect=range(el_strt,el_end+1) - elem_rnge.extend(rnge_sect) - elements=[] - for i in elem_rnge: - element=Element.from_Z(i) # Indice -> pymatgen element object - elements.append(element) - return elements - - #__| - -class ElemList_mod(object): - """ - """ - #| - - ElemList_mod - def __init__(self,elem_lst): - self.elem_lst = elem_lst - @property - def sort(self,srt_type='group_num'): - """ - Sorts element entries - Args: - srt_type - DEFAULT: group_num, sorts by group number with lowest group number first, and - lowest period first - """ - if srt_type == 'group_num': - elem_lst = self.elem_lst - elem_lst_sorted = elem_lst[:] # Maintains the original unaffected - elem_lst_sorted.sort(key=lambda x: x.group) - return elem_lst_sorted - - #| - - d-band filling - if srt_type == 'd-band': #COMBAK - tmp = 7 - - - - - #__| - - def remove(self,element): - """ - Removes element from element list - Args: - List of element objects - If only 1 element just 1 element number or chemical symbol - name "or" atomic number of the element to be removed - """ - elem_lst_0 = self.elem_lst - if type(element)==type([]): - for elem in element: - if type(elem)==type('string'): - # Find the occurance of input 'elem' in the list and returns it - elem_0 = next((x for x in elem_lst_0 if x.name == elem), None) - elem_lst_0 = [x for x in elem_lst_0 if not x.name == elem] - elif type(elem)==type(2): - elem_0 = next((x for x in elem_lst_0 if x.number == elem), None) - elem_lst_0 = [x for x in elem_lst_0 if not x.number == elem] - return elem_lst_0 - if type(element)==type('string'): - # Find the occurance of input 'elem' in the list and returns it - elem_0 = next((x for x in self.elem_lst if x.name == element), None) - elem_lst_new = [x for x in self.elem_lst if not x.name == element] - return elem_lst_new - - elif type(element)==type(2): - elem_0 = next((x for x in self.elem_lst if x.number == element), None) - elem_lst_new = [x for x in self.elem_lst if not x.number == element] - return elem_lst_new - #__| - -def elem_str_mke(elem_lst): - """ - - Args: - elem_lst: - """ - #| - - elem_str_mke - elem_str=[] - for i in elem_lst: - elem_str.append(i.symbol) - return elem_str - - #__| +from pymatgen.core.periodic_table import Element # Call elements by atomic # +class ElementList(object): + """ + Class for creating element lists and ranges + By default the first list created is in order of atomic number + Args: + N/A + """ + #| - - ElementList + def __init__(self, atom_num_lst=[[]]): + self.atom_num_lst = atom_num_lst + if not atom_num_lst==[[]]: + self.list = self.mk_lst_atnum() + self.trans_met = self.mk_lst_trans_met() + + def mk_lst_atnum(self): + """ + Makes list of elements from the atom_num_lst input + """ + elem_rnge=[] + for i in self.atom_num_lst: + el_strt=i[0] + el_end=i[1] + rnge_sect=range(el_strt,el_end+1) + elem_rnge.extend(rnge_sect) + elements=[] + for i in elem_rnge: + element=Element.from_Z(i) # Indice -> pymatgen element object + elements.append(element) + return elements + print elements + + def mk_lst_trans_met(self): + """ + Produces list of transition metals in order of atomic number + """ + elem_rnge_I = [[21,30],[39,44],[46,48],[74,76],[78,80]] + elem_rnge=[] + for i in elem_rnge_I: + el_strt=i[0] + el_end=i[1] + rnge_sect=range(el_strt,el_end+1) + elem_rnge.extend(rnge_sect) + elements=[] + for i in elem_rnge: + element=Element.from_Z(i) # Indice -> pymatgen element object + elements.append(element) + return elements + + #__| + +class ElemList_mod(object): + """ + """ + #| - - ElemList_mod + def __init__(self,elem_lst): + self.elem_lst = elem_lst + @property + def sort(self,srt_type='group_num'): + """ + Sorts element entries + Args: + srt_type + DEFAULT: group_num, sorts by group number with lowest group number first, and + lowest period first + """ + if srt_type == 'group_num': + elem_lst = self.elem_lst + elem_lst_sorted = elem_lst[:] # Maintains the original unaffected + elem_lst_sorted.sort(key=lambda x: x.group) + return elem_lst_sorted + + #| - - d-band filling + if srt_type == 'd-band': #COMBAK + tmp = 7 + + + + + #__| + + def remove(self,element): + """ + Removes element from element list + Args: + List of element objects + If only 1 element just 1 element number or chemical symbol + name "or" atomic number of the element to be removed + """ + elem_lst_0 = self.elem_lst + if type(element)==type([]): + for elem in element: + if type(elem)==type('string'): + # Find the occurance of input 'elem' in the list and returns it + elem_0 = next((x for x in elem_lst_0 if x.name == elem), None) + elem_lst_0 = [x for x in elem_lst_0 if not x.name == elem] + elif type(elem)==type(2): + elem_0 = next((x for x in elem_lst_0 if x.number == elem), None) + elem_lst_0 = [x for x in elem_lst_0 if not x.number == elem] + return elem_lst_0 + if type(element)==type('string'): + # Find the occurance of input 'elem' in the list and returns it + elem_0 = next((x for x in self.elem_lst if x.name == element), None) + elem_lst_new = [x for x in self.elem_lst if not x.name == element] + return elem_lst_new + + elif type(element)==type(2): + elem_0 = next((x for x in self.elem_lst if x.number == element), None) + elem_lst_new = [x for x in self.elem_lst if not x.number == element] + return elem_lst_new + #__| + +def elem_str_mke(elem_lst): + """ + + Args: + elem_lst: + """ + #| - - elem_str_mke + elem_str=[] + for i in elem_lst: + elem_str.append(i.symbol) + return elem_str + + #__| diff --git a/pourbaix_pymatgen/energy_scheme.py b/pourbaix_pymatgen/energy_scheme.py index aed8246..b63be25 100644 --- a/pourbaix_pymatgen/energy_scheme.py +++ b/pourbaix_pymatgen/energy_scheme.py @@ -1,162 +1,162 @@ -def ref_atoms_dict(): - """ - Contains dictionary of reference atom energies and entropic corrections to - form Gibbs free energies - - Args: - - """ - #| - - ref_atoms_dict - - # e_o = -4.93552791875 # mp-12957, half of O2 - No entropy term - # e_h = -3.2397 # mp-754417, half of H2 - No entropy term - - # e_o = -5.25225891875 # mp-12957, half of O2 - With entropy @300K - # e_h = -3.6018845 # mp-754417, half of H2 - With entropy @300K - - # e_o = -5.11 # Optimzed for 1st row transitino metals - # e_h = -3.6018845 # mp-754417, half of H2 - With entropy @300K - - e_o = -5.21 - e_h = -3.6018845 - - #| - - H2O, H2 Reference State - # From Michal Badjich - o2=-9.88557216 - h2o=-14.23091949 - h2=-6.77149190 - h2ozpe=0.5584 - h2ocp=0.10 - h2zpe=0.27283 - h2cp=0.09 - o2zpe=0.098 - o2cp=0.090 - - # o_ref1=o2/2 - o_ref2=(h2o-h2 + 2.506)+(h2ozpe-h2zpe-0.5*o2zpe)+(h2ocp-h2cp-0.5*o2cp) - - # e_o = o_ref2 - # e_h = h2/2. - #__| - - - #| - - Entropic Corrections - entr_o = -0.3167 - entr_h = -0.36218 - - - ref_dict = {} - ref_dict['e_o'] = e_o - ref_dict['e_h'] = e_h - - return ref_dict - - #__| - - #__| - -def h2o_energy(): - """ - Enthalpy and Gibbs free energy of formation for liquid water - """ - e_h2o = -2.96211 - g_h2o = -2.4583 - - h2o_dict = {} - h2o_dict['h2o_enth'] = e_h2o - h2o_dict['h2o_gibb'] = g_h2o - - return h2o_dict - -def form_e_all_oxides(element, only_pd_entries=False): - # e_o = oxy_energy - """ - OUTLINE: - 1. Get all entries in the chemical ensemble for 1 element and oxygen - 2. Extract all of the oxide species - 3. Extract the pure metallic references - 4. Apply correction scheme to entries - 5. Calculate the formation energy for the oxides per oxygen molecule - """ - #| - - form_e_all_oxides - - #| - - Imported Modules - from pd_make import entry_data, aq_correction, stable_entr, form_e - from entry_methods import entry_remove, pure_atoms_return,contains_element, norm_e - from energy_scheme import ref_atoms_dict - #__| - - #| - - Script parameters - mprester_key = 'ZJhfHmMTTwbW29Sr' # Input your materials project id - direct_0 = '/home/flores12/01_ORR-MatStabScreen/01_virenv-pymatgen/01_data/01-1_local_MP_entry/' - correction_=True - #__| - - all_entries = entry_data(element,element,direct_0,mprester_key)['entries'] - oxygen_entries = contains_element(all_entries,'O') - hydrogen_entries = contains_element(all_entries,'H') - - entries_no_h = [entry for entry in oxygen_entries if entry not in hydrogen_entries ] - - oxides = entry_remove(entries_no_h, 'O2') - - #| - - Finding the Entries Used in the Pourbaix Diagram - entry_ion_data = entry_data(element, element, direct_0, mprester_key) - entries = entry_ion_data["entries"] - - entries_aqcorr = aq_correction(entries) - stable_solids_minus_h2o = stable_entr(entries_aqcorr) - pbx_solid_entries = form_e(stable_solids_minus_h2o, entries_aqcorr) - - entry_id_lst = [] - for i in pbx_solid_entries: - entry_id_lst.append(i.entry_id) - #__| - - - #| - - Deleting Entries in Oxides Which Aren't in Pourbaix Entry List - if only_pd_entries==True: - oxides_temp = [] - for i in oxides: - if i.entry_id in entry_id_lst: - oxides_temp.append(i) - oxides = oxides_temp - #__| - - #| - - Metallic References - elem_ref = pure_atoms_return(all_entries)[0] - elem_ref_e = norm_e(elem_ref) - - if not elem_ref.name==element: - print 'calc_form_e - The reference atom is not the same as the element' - #__| - - #| - - Formation Energy - ref_atom_energies = ref_atoms_dict() - e_o = ref_atom_energies['e_o'] - e_h = ref_atom_energies['e_h'] - - form_e_lst = [] - for oxide in oxides: - oxide_e = norm_e(oxide,correction=correction_) - - elem_coef = oxide.composition.get_el_amt_dict()[element]/oxide.composition.get_integer_formula_and_factor()[1] - oxygen_coef = oxide.composition.get_el_amt_dict()['O']/oxide.composition.get_integer_formula_and_factor()[1] - - form_e = (oxide_e - elem_coef*elem_ref_e - oxygen_coef*e_o)/(oxygen_coef/2.) - - elem_comp_lst = [] - elem_comp_lst.append(str(element)+str(elem_coef)[:1]) - elem_comp_lst.append('O'+str(oxygen_coef)[:1]) - - entry_dict = {} - entry_dict['form_e'] = form_e - entry_dict['entry'] = oxide.name - entry_dict['entry_elements'] = elem_comp_lst - - form_e_lst.append(entry_dict) - - #__| - return form_e_lst - - #__| +def ref_atoms_dict(): + """ + Contains dictionary of reference atom energies and entropic corrections to + form Gibbs free energies + + Args: + + """ + #| - - ref_atoms_dict + + # e_o = -4.93552791875 # mp-12957, half of O2 - No entropy term + # e_h = -3.2397 # mp-754417, half of H2 - No entropy term + + # e_o = -5.25225891875 # mp-12957, half of O2 - With entropy @300K + # e_h = -3.6018845 # mp-754417, half of H2 - With entropy @300K + + # e_o = -5.11 # Optimzed for 1st row transitino metals + # e_h = -3.6018845 # mp-754417, half of H2 - With entropy @300K + + e_o = -5.21 + e_h = -3.6018845 + + #| - - H2O, H2 Reference State + # From Michal Badjich + o2=-9.88557216 + h2o=-14.23091949 + h2=-6.77149190 + h2ozpe=0.5584 + h2ocp=0.10 + h2zpe=0.27283 + h2cp=0.09 + o2zpe=0.098 + o2cp=0.090 + + # o_ref1=o2/2 + o_ref2=(h2o-h2 + 2.506)+(h2ozpe-h2zpe-0.5*o2zpe)+(h2ocp-h2cp-0.5*o2cp) + + # e_o = o_ref2 + # e_h = h2/2. + #__| + + + #| - - Entropic Corrections + entr_o = -0.3167 + entr_h = -0.36218 + + + ref_dict = {} + ref_dict['e_o'] = e_o + ref_dict['e_h'] = e_h + + return ref_dict + + #__| + + #__| + +def h2o_energy(): + """ + Enthalpy and Gibbs free energy of formation for liquid water + """ + e_h2o = -2.96211 + g_h2o = -2.4583 + + h2o_dict = {} + h2o_dict['h2o_enth'] = e_h2o + h2o_dict['h2o_gibb'] = g_h2o + + return h2o_dict + +def form_e_all_oxides(element, only_pd_entries=False): + # e_o = oxy_energy + """ + OUTLINE: + 1. Get all entries in the chemical ensemble for 1 element and oxygen + 2. Extract all of the oxide species + 3. Extract the pure metallic references + 4. Apply correction scheme to entries + 5. Calculate the formation energy for the oxides per oxygen molecule + """ + #| - - form_e_all_oxides + + #| - - Imported Modules + from pd_make import entry_data, aq_correction, stable_entr, form_e + from entry_methods import entry_remove, pure_atoms_return,contains_element, norm_e + from energy_scheme import ref_atoms_dict + #__| + + #| - - Script parameters + mprester_key = 'ZJhfHmMTTwbW29Sr' # Input your materials project id + direct_0 = '/home/flores12/01_ORR-MatStabScreen/01_virenv-pymatgen/01_data/01-1_local_MP_entry/' + correction_=True + #__| + + all_entries = entry_data(element,element,direct_0,mprester_key)['entries'] + oxygen_entries = contains_element(all_entries,'O') + hydrogen_entries = contains_element(all_entries,'H') + + entries_no_h = [entry for entry in oxygen_entries if entry not in hydrogen_entries ] + + oxides = entry_remove(entries_no_h, 'O2') + + #| - - Finding the Entries Used in the Pourbaix Diagram + entry_ion_data = entry_data(element, element, direct_0, mprester_key) + entries = entry_ion_data["entries"] + + entries_aqcorr = aq_correction(entries) + stable_solids_minus_h2o = stable_entr(entries_aqcorr) + pbx_solid_entries = form_e(stable_solids_minus_h2o, entries_aqcorr) + + entry_id_lst = [] + for i in pbx_solid_entries: + entry_id_lst.append(i.entry_id) + #__| + + + #| - - Deleting Entries in Oxides Which Aren't in Pourbaix Entry List + if only_pd_entries==True: + oxides_temp = [] + for i in oxides: + if i.entry_id in entry_id_lst: + oxides_temp.append(i) + oxides = oxides_temp + #__| + + #| - - Metallic References + elem_ref = pure_atoms_return(all_entries)[0] + elem_ref_e = norm_e(elem_ref) + + if not elem_ref.name==element: + print 'calc_form_e - The reference atom is not the same as the element' + #__| + + #| - - Formation Energy + ref_atom_energies = ref_atoms_dict() + e_o = ref_atom_energies['e_o'] + e_h = ref_atom_energies['e_h'] + + form_e_lst = [] + for oxide in oxides: + oxide_e = norm_e(oxide,correction=correction_) + + elem_coef = oxide.composition.get_el_amt_dict()[element]/oxide.composition.get_integer_formula_and_factor()[1] + oxygen_coef = oxide.composition.get_el_amt_dict()['O']/oxide.composition.get_integer_formula_and_factor()[1] + + form_e = (oxide_e - elem_coef*elem_ref_e - oxygen_coef*e_o)/(oxygen_coef/2.) + + elem_comp_lst = [] + elem_comp_lst.append(str(element)+str(elem_coef)[:1]) + elem_comp_lst.append('O'+str(oxygen_coef)[:1]) + + entry_dict = {} + entry_dict['form_e'] = form_e + entry_dict['entry'] = oxide.name + entry_dict['entry_elements'] = elem_comp_lst + + form_e_lst.append(entry_dict) + + #__| + return form_e_lst + + #__| diff --git a/pourbaix_pymatgen/entry_methods.py b/pourbaix_pymatgen/entry_methods.py index 77bf65d..19aaa37 100644 --- a/pourbaix_pymatgen/entry_methods.py +++ b/pourbaix_pymatgen/entry_methods.py @@ -1,304 +1,304 @@ -# -*- coding: utf-8 -*- - -# ███ ███ ██████ ██████ █████ ████████ ██████ ███████ ███████ -# ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -# ██ ████ ██ ██████ ██ ██ ███████ ██ ██████ ███████ █████ -# ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -# ██ ██ ██ ██████ ██ ██ ██ ██████ ███████ ███████ - - -def get_entries_MP(material_name): - """ - Args: - material_name: Material's formula unit - """ - #| - - get_entries_MP - from pymatgen.matproj.rest import MPRester # MP API key to access species in MP - import warnings - warnings.filterwarnings('ignore') - mpr = MPRester('ZJhfHmMTTwbW29Sr') - - # entries = mpr.get_entries - #__| - -def get_entry_MP(entry_s): - """ - Returns a specific entry from the Materials Project database - Args: - ent: - """ - #| - - get_entry_MP - from pymatgen.matproj.rest import MPRester # MP API key to access species in MP - import warnings - warnings.filterwarnings('ignore') - mpr = MPRester('ZJhfHmMTTwbW29Sr') - - # entry = mpr.get_entries(entry_s)[0] - - - entryid_prefix = entry_s[:3] - if entryid_prefix=='mp-': - out = mpr.get_entries(entry_s)[0] - - else: - out = mpr.get_entries(entry_s) - return out - #__| - -def norm_e(entry, correction=True): - """ - - Args: - entry: - correction: Apply default MP corrections - """ - #| - - norm_e - if correction==True: - e_raw = entry.energy - elif correction==False: - e_raw = entry.uncorrected_energy - - stoich_fact = entry.composition.get_integer_formula_and_factor()[1] - - e_norm = e_raw/stoich_fact - - return e_norm - #__| - -def return_entry(entry_list, entryid): - """ - Returns the desired entry from a list of pymatgen entries if entryid given - Returns a list of entries matching the given entry name - Args: - entry_list: List of pymatgen entries - entryid: Materials Project id (ex. mp-715572) or entry name - """ - #| - - return_entry - entryid_prefix = entryid[:3] - if entryid_prefix=='mp-': - for ent in entry_list: - if ent.entry_id == entryid: - return ent - else: - out_lst = [] - for ent in entry_list: - if ent.name == entryid: - out_lst.append(ent) - return out_lst - - #__| - - -def entry_remove(entries, entry_to_remove): - """ - Removes the entries in a list which match the name of entry_to_remove - - Args: - entries: List of entries to be processed - entry_to_remove: Name of entry to be removed from the entries list - """ - #| - - entry_remove - import numpy as np - - index_lst = [] - entries_copy = entries[:] - cnt = 0 - for entry in entries_copy: - if entry.name == entry_to_remove: - index_lst.append(cnt) - # entries.remove(entry) - cnt=cnt+1 - - entries_copy = np.delete(entries_copy, index_lst).tolist() - - return entries_copy - #__| - -def base_atom(entries): - """ - Returns the base metal(s) from a list of entries as a list of strings in - order of their atomic number - - Args: - entries: List of entries - """ - #| - - base_atom - from pymatgen import Element - - elem_lst = [] - # Adds elements from every element to a list (losts of duplicates) - for entry in entries: - elem_lst.extend(entry.composition.elements) - elem_lst_duplrem = list(set(elem_lst)) # Remove duplicate elements - elem_lst_duplrem.sort(key=lambda x: x.number) # Order by atomic number - - # Converts list of element objects to atomic symbol strings - elem_lst_nme = [] - for elem in elem_lst_duplrem: - elem_lst_nme.append(elem.name) - - try: # Attempts to remove oxygen from list - elem_lst_nme.remove('O') # if no oxygen is present do nothing - except: - pass - try: # Attempts to remove hydrogen from list - elem_lst_nme.remove('H') # if no hydrogen is present do nothing - except: - pass - - elem_lst = elem_lst_nme - - return elem_lst - #__| - -def pure_atoms_remove(entries): - """ - Removes entries corresponding to pure atoms, defined as entries with one - species, and that species has to be the base element (or one of the base - elements if binary) - - Args: - entries: List of entries - """ - #| - - pure_atoms_remove - from pymatgen import Element - from entry_methods import base_atom - - base_atoms = base_atom(entries) - pure_met_lst=[] - # Selects single atom entries of either elem_0 or elem_1 (not ion species) - for entry in entries: - entr_elem_lst = entry.composition.elements - - if len(entr_elem_lst)==1 and entry.phase_type!='Ion' \ - and entr_elem_lst[0].name in base_atoms: - pure_met_lst.append(entry) - # Removes the entries from entry list - for entry in pure_met_lst: - entries.remove(entry) - return entries - #__| - -def pure_atoms_return(entries): - """ - """ - #| - - pure_atoms_return - from pymatgen import Element - from entry_methods import base_atom - - base_atoms = base_atom(entries) - pure_met_lst=[] - - for entry in entries: - entr_elem_lst = entry.composition.elements - - - if len(entr_elem_lst)==1 and entr_elem_lst[0].name in base_atoms: - pure_met_lst.append(entry) - - #| - - If there are more pure atomic species than there are base atoms return an error - if len(pure_met_lst)>len(base_atoms): - tmp = 4 - # print 'entry_methods.pure_atoms_return - There is more than one option for the reference metallic atom' - #__| - - # for i in pure_met_lst: - # print norm_e(i) - # print '' - - return pure_met_lst - #__| - - - # ████████ ███████ ███ ███ ██████ - # ██ ██ ████ ████ ██ ██ - # ██ █████ ██ ████ ██ ██████ - # ██ ██ ██ ██ ██ ██ - # ██ ███████ ██ ██ ██ - - -def alloy_entries(entries): - """ - Returns the alloy species in entries in a list - Args: - entries: List of entries - """ - #| - - alloy_entries - from pymatgen import Element - from entry_methods import base_atom - - base_atoms = base_atom(entries) - if len(base_atoms)==1: - alloy_lst=[] - return alloy_lst - elem_0 = base_atoms[0] - elem_1 = base_atoms[1] - - alloy_lst = [] - for entry in entries: - entr_elem_lst = entry.composition.elements # Elements in current entry - entr_elem_lst_str = [] - for i in entr_elem_lst: - entr_elem_lst_str.append(i.name) - if len(entr_elem_lst_str)==2 and \ - (elem_0 in entr_elem_lst_str and elem_1 in entr_elem_lst_str): - alloy_lst.append(entry) - - # Orders alloys from lowest to highest composition of elem_0 - alloy_lst.sort(key=lambda x: \ - x.composition.fractional_composition.get_atomic_fraction(elem_0)) - - return alloy_lst - #__| - - -def contains_element(entries,element_symbol): - """ - Returns the entries in a list of entries which contain element_symbol - - Args: - entries: List of pymatgen objects - """ - #| - - contains_element - - from pymatgen import Element - - - #| - - Get rid of entries without oxygen - element = Element(element_symbol) - - lst = [entry for entry in entries if element in entry.composition.elements] - # for i in entries: - return lst - #__| - - #__| - - -def number_of_elem_in_entry(entry,element): - """ - Returns the number of a certain element in an entry, where the entry has been - normalized to a reduced formula unit - - Args: - entry: entry/species to be processes - element: element to be counted in the target entry - """ - #| - - number_of_elem_in_entry - #__| - - -def element_formula_list(entry): - """ - Returns the reduced formula list for an entry - - Args: - entry: entry to be proccessed - """ - #| - - element_formula_list - formula_list = [] - for element in entry.composition.get_el_amt_dict(): - elem_coef = entry.composition.get_el_amt_dict()[element]/entry.composition.get_integer_formula_and_factor()[1] - formula_list.append(str(element)+str(elem_coef)[:1]) - return formula_list - #__| +# -*- coding: utf-8 -*- + +# ███ ███ ██████ ██████ █████ ████████ ██████ ███████ ███████ +# ████ ████ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +# ██ ████ ██ ██████ ██ ██ ███████ ██ ██████ ███████ █████ +# ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +# ██ ██ ██ ██████ ██ ██ ██ ██████ ███████ ███████ + + +def get_entries_MP(material_name): + """ + Args: + material_name: Material's formula unit + """ + #| - - get_entries_MP + from pymatgen.matproj.rest import MPRester # MP API key to access species in MP + import warnings + warnings.filterwarnings('ignore') + mpr = MPRester('ZJhfHmMTTwbW29Sr') + + # entries = mpr.get_entries + #__| + +def get_entry_MP(entry_s): + """ + Returns a specific entry from the Materials Project database + Args: + ent: + """ + #| - - get_entry_MP + from pymatgen.matproj.rest import MPRester # MP API key to access species in MP + import warnings + warnings.filterwarnings('ignore') + mpr = MPRester('ZJhfHmMTTwbW29Sr') + + # entry = mpr.get_entries(entry_s)[0] + + + entryid_prefix = entry_s[:3] + if entryid_prefix=='mp-': + out = mpr.get_entries(entry_s)[0] + + else: + out = mpr.get_entries(entry_s) + return out + #__| + +def norm_e(entry, correction=True): + """ + + Args: + entry: + correction: Apply default MP corrections + """ + #| - - norm_e + if correction==True: + e_raw = entry.energy + elif correction==False: + e_raw = entry.uncorrected_energy + + stoich_fact = entry.composition.get_integer_formula_and_factor()[1] + + e_norm = e_raw/stoich_fact + + return e_norm + #__| + +def return_entry(entry_list, entryid): + """ + Returns the desired entry from a list of pymatgen entries if entryid given + Returns a list of entries matching the given entry name + Args: + entry_list: List of pymatgen entries + entryid: Materials Project id (ex. mp-715572) or entry name + """ + #| - - return_entry + entryid_prefix = entryid[:3] + if entryid_prefix=='mp-': + for ent in entry_list: + if ent.entry_id == entryid: + return ent + else: + out_lst = [] + for ent in entry_list: + if ent.name == entryid: + out_lst.append(ent) + return out_lst + + #__| + + +def entry_remove(entries, entry_to_remove): + """ + Removes the entries in a list which match the name of entry_to_remove + + Args: + entries: List of entries to be processed + entry_to_remove: Name of entry to be removed from the entries list + """ + #| - - entry_remove + import numpy as np + + index_lst = [] + entries_copy = entries[:] + cnt = 0 + for entry in entries_copy: + if entry.name == entry_to_remove: + index_lst.append(cnt) + # entries.remove(entry) + cnt=cnt+1 + + entries_copy = np.delete(entries_copy, index_lst).tolist() + + return entries_copy + #__| + +def base_atom(entries): + """ + Returns the base metal(s) from a list of entries as a list of strings in + order of their atomic number + + Args: + entries: List of entries + """ + #| - - base_atom + from pymatgen import Element + + elem_lst = [] + # Adds elements from every element to a list (losts of duplicates) + for entry in entries: + elem_lst.extend(entry.composition.elements) + elem_lst_duplrem = list(set(elem_lst)) # Remove duplicate elements + elem_lst_duplrem.sort(key=lambda x: x.number) # Order by atomic number + + # Converts list of element objects to atomic symbol strings + elem_lst_nme = [] + for elem in elem_lst_duplrem: + elem_lst_nme.append(elem.name) + + try: # Attempts to remove oxygen from list + elem_lst_nme.remove('O') # if no oxygen is present do nothing + except: + pass + try: # Attempts to remove hydrogen from list + elem_lst_nme.remove('H') # if no hydrogen is present do nothing + except: + pass + + elem_lst = elem_lst_nme + + return elem_lst + #__| + +def pure_atoms_remove(entries): + """ + Removes entries corresponding to pure atoms, defined as entries with one + species, and that species has to be the base element (or one of the base + elements if binary) + + Args: + entries: List of entries + """ + #| - - pure_atoms_remove + from pymatgen import Element + from entry_methods import base_atom + + base_atoms = base_atom(entries) + pure_met_lst=[] + # Selects single atom entries of either elem_0 or elem_1 (not ion species) + for entry in entries: + entr_elem_lst = entry.composition.elements + + if len(entr_elem_lst)==1 and entry.phase_type!='Ion' \ + and entr_elem_lst[0].name in base_atoms: + pure_met_lst.append(entry) + # Removes the entries from entry list + for entry in pure_met_lst: + entries.remove(entry) + return entries + #__| + +def pure_atoms_return(entries): + """ + """ + #| - - pure_atoms_return + from pymatgen import Element + from entry_methods import base_atom + + base_atoms = base_atom(entries) + pure_met_lst=[] + + for entry in entries: + entr_elem_lst = entry.composition.elements + + + if len(entr_elem_lst)==1 and entr_elem_lst[0].name in base_atoms: + pure_met_lst.append(entry) + + #| - - If there are more pure atomic species than there are base atoms return an error + if len(pure_met_lst)>len(base_atoms): + tmp = 4 + # print 'entry_methods.pure_atoms_return - There is more than one option for the reference metallic atom' + #__| + + # for i in pure_met_lst: + # print norm_e(i) + # print '' + + return pure_met_lst + #__| + + + # ████████ ███████ ███ ███ ██████ + # ██ ██ ████ ████ ██ ██ + # ██ █████ ██ ████ ██ ██████ + # ██ ██ ██ ██ ██ ██ + # ██ ███████ ██ ██ ██ + + +def alloy_entries(entries): + """ + Returns the alloy species in entries in a list + Args: + entries: List of entries + """ + #| - - alloy_entries + from pymatgen import Element + from entry_methods import base_atom + + base_atoms = base_atom(entries) + if len(base_atoms)==1: + alloy_lst=[] + return alloy_lst + elem_0 = base_atoms[0] + elem_1 = base_atoms[1] + + alloy_lst = [] + for entry in entries: + entr_elem_lst = entry.composition.elements # Elements in current entry + entr_elem_lst_str = [] + for i in entr_elem_lst: + entr_elem_lst_str.append(i.name) + if len(entr_elem_lst_str)==2 and \ + (elem_0 in entr_elem_lst_str and elem_1 in entr_elem_lst_str): + alloy_lst.append(entry) + + # Orders alloys from lowest to highest composition of elem_0 + alloy_lst.sort(key=lambda x: \ + x.composition.fractional_composition.get_atomic_fraction(elem_0)) + + return alloy_lst + #__| + + +def contains_element(entries,element_symbol): + """ + Returns the entries in a list of entries which contain element_symbol + + Args: + entries: List of pymatgen objects + """ + #| - - contains_element + + from pymatgen import Element + + + #| - - Get rid of entries without oxygen + element = Element(element_symbol) + + lst = [entry for entry in entries if element in entry.composition.elements] + # for i in entries: + return lst + #__| + + #__| + + +def number_of_elem_in_entry(entry,element): + """ + Returns the number of a certain element in an entry, where the entry has been + normalized to a reduced formula unit + + Args: + entry: entry/species to be processes + element: element to be counted in the target entry + """ + #| - - number_of_elem_in_entry + #__| + + +def element_formula_list(entry): + """ + Returns the reduced formula list for an entry + + Args: + entry: entry to be proccessed + """ + #| - - element_formula_list + formula_list = [] + for element in entry.composition.get_el_amt_dict(): + elem_coef = entry.composition.get_el_amt_dict()[element]/entry.composition.get_integer_formula_and_factor()[1] + formula_list.append(str(element)+str(elem_coef)[:1]) + return formula_list + #__| diff --git a/pourbaix_pymatgen/find_closest_point_pd.py b/pourbaix_pymatgen/find_closest_point_pd.py index c1bea9d..53441e4 100644 --- a/pourbaix_pymatgen/find_closest_point_pd.py +++ b/pourbaix_pymatgen/find_closest_point_pd.py @@ -1,130 +1,130 @@ -def find_closest_point_pd(pourbaix_diagram_object): - from pymatgen.analysis.pourbaix.plotter import PourbaixPlotter - import matplotlib.pyplot as plt - import numpy as np - from pymatgen.util.coord_utils import in_coord_list - from pymatgen.analysis.pourbaix.maker import PREFAC - - lw = 1 - limits = [[-2, 16],[-3, 3]] - - fig1 = plt.figure() - ax = fig1.gca() - - plotter = PourbaixPlotter(pourbaix_diagram_object) - (stable, unstable) = plotter.pourbaix_plot_data(limits) - -#| - - Ambar's Region Filter Check Function - def screening_check_desirable(entry,criteria='only-solid'): - is_desired = False - if criteria not in ['only-solid']: - print "Not implemented" - sys.exit() - if criteria == 'only-solid': - if entry.nH2O == 0.0 and entry.npH == 0.0 and entry.nPhi == 0.0: - is_desired = True - print "Desired entry", entry.name - if not criteria: - print "Not desired entry", entry.name - return is_desired -#__| - -#| - - Ambar's Function for Water and Hydrogen Lines - def get_water_stability_lines(limits): - from pymatgen.analysis.pourbaix.maker import PREFAC - xlim = limits[0] - ylim = limits[1] - h_line = np.transpose([[xlim[0], -xlim[0] * PREFAC], - [xlim[1], -xlim[1] * PREFAC]]) - o_line = np.transpose([[xlim[0], -xlim[0] * PREFAC + 1.23], - [xlim[1], -xlim[1] * PREFAC + 1.23]]) - return (h_line, o_line) -#__| - -#| - - Returns the Desirable Regions of PD in "vertices" - vertices = [] - import time - for entry, lines in stable.items(): - print entry.name - is_desired = screening_check_desirable(entry,criteria='only-solid') - if is_desired: - desired_entry = entry - for line in lines: - (x, y) = line - #print "points", x, y - plt.plot(x, y, "k-", linewidth=lw) - point1 = [x[0],y[0]] - point2 = [x[1],y[1]] - if point1 not in vertices and is_desired: - vertices.append(point1) - if point2 not in vertices and is_desired: - vertices.append(point2) -#__| - -#| - - Placing the desired phase's name in the diagram - center_x=0 - center_y=0 - count = 0 - for point in vertices: - x,y = point - count = count + 1 - center_x = center_x + x - center_y = center_y + y - plt.plot(x,y,'ro') - center_x = center_x /count - center_y = center_y /count - plt.annotate(str(desired_entry.name), xy=(center_x, center_y)) -#__| - -#| - - Plotting Water and Hydrogen Equilibrium Lines - # Get water line - h_line, o_line = get_water_stability_lines(limits) - plt.plot(h_line[0], h_line[1], "r--", linewidth=lw) - plt.plot(o_line[0], o_line[1], "r--", linewidth=lw) -#__| - - # Getting distances - print "Getting distances of vertices" - reference_line = o_line - p1 = np.array([reference_line[0][0], reference_line[1][0]]) - p2 = np.array([reference_line[0][1], reference_line[1][1]]) - - min_d = 1000.0 - min_vertex = [] - d_and_vert_lst =[] - for p3 in vertices: - np.array(p3) - d = np.linalg.norm(np.cross(p2-p1, p1-p3))/np.linalg.norm(p2-p1) - d_and_vert = [d, p3] - d_and_vert_lst.append(d_and_vert) - - #https://stackoverflow.com/questions/39840030/distance-between-point-and-a-line-from-two-points - #http://www.fundza.com/vectors/point2line/index.html - print "Vertex: ", p3, "Distance: ", d - - if d <= min_d: - min_d = d - min_vertex = p3 - - fin_lst = [] - for i in d_and_vert_lst: - if round(i[0], 4) == round(min_d, 4): - fin_lst.append(i) - - # Plotting the star on highest stability vertices - for i in fin_lst: - plt.plot(i[1][0],i[1][1],'*b',ms=16) - - ########################################### - V_RHE = 1.23 - min_d - - pH_0 = fin_lst[0][1][0] - V_SHE = V_RHE - PREFAC*pH_0 - ########################################### - - # plt.annotate('d = '+ str(round(min_d,2)),xy=(center_x, center_y-0.3)) - plt.annotate('V_crit = ' + str(round(V_RHE,2))+' VvsRHE',xy=(center_x, center_y-0.3)) - plt.annotate('V_crit = ' + str(round(V_SHE,2))+' VvsSHE',xy=(center_x, center_y-0.6)) - plt.xlabel("pH") - plt.ylabel("E (V)") - plt.show() +def find_closest_point_pd(pourbaix_diagram_object): + from pymatgen.analysis.pourbaix.plotter import PourbaixPlotter + import matplotlib.pyplot as plt + import numpy as np + from pymatgen.util.coord_utils import in_coord_list + from pymatgen.analysis.pourbaix.maker import PREFAC + + lw = 1 + limits = [[-2, 16],[-3, 3]] + + fig1 = plt.figure() + ax = fig1.gca() + + plotter = PourbaixPlotter(pourbaix_diagram_object) + (stable, unstable) = plotter.pourbaix_plot_data(limits) + +#| - - Ambar's Region Filter Check Function + def screening_check_desirable(entry,criteria='only-solid'): + is_desired = False + if criteria not in ['only-solid']: + print "Not implemented" + sys.exit() + if criteria == 'only-solid': + if entry.nH2O == 0.0 and entry.npH == 0.0 and entry.nPhi == 0.0: + is_desired = True + print "Desired entry", entry.name + if not criteria: + print "Not desired entry", entry.name + return is_desired +#__| + +#| - - Ambar's Function for Water and Hydrogen Lines + def get_water_stability_lines(limits): + from pymatgen.analysis.pourbaix.maker import PREFAC + xlim = limits[0] + ylim = limits[1] + h_line = np.transpose([[xlim[0], -xlim[0] * PREFAC], + [xlim[1], -xlim[1] * PREFAC]]) + o_line = np.transpose([[xlim[0], -xlim[0] * PREFAC + 1.23], + [xlim[1], -xlim[1] * PREFAC + 1.23]]) + return (h_line, o_line) +#__| + +#| - - Returns the Desirable Regions of PD in "vertices" + vertices = [] + import time + for entry, lines in stable.items(): + print entry.name + is_desired = screening_check_desirable(entry,criteria='only-solid') + if is_desired: + desired_entry = entry + for line in lines: + (x, y) = line + #print "points", x, y + plt.plot(x, y, "k-", linewidth=lw) + point1 = [x[0],y[0]] + point2 = [x[1],y[1]] + if point1 not in vertices and is_desired: + vertices.append(point1) + if point2 not in vertices and is_desired: + vertices.append(point2) +#__| + +#| - - Placing the desired phase's name in the diagram + center_x=0 + center_y=0 + count = 0 + for point in vertices: + x,y = point + count = count + 1 + center_x = center_x + x + center_y = center_y + y + plt.plot(x,y,'ro') + center_x = center_x /count + center_y = center_y /count + plt.annotate(str(desired_entry.name), xy=(center_x, center_y)) +#__| + +#| - - Plotting Water and Hydrogen Equilibrium Lines + # Get water line + h_line, o_line = get_water_stability_lines(limits) + plt.plot(h_line[0], h_line[1], "r--", linewidth=lw) + plt.plot(o_line[0], o_line[1], "r--", linewidth=lw) +#__| + + # Getting distances + print "Getting distances of vertices" + reference_line = o_line + p1 = np.array([reference_line[0][0], reference_line[1][0]]) + p2 = np.array([reference_line[0][1], reference_line[1][1]]) + + min_d = 1000.0 + min_vertex = [] + d_and_vert_lst =[] + for p3 in vertices: + np.array(p3) + d = np.linalg.norm(np.cross(p2-p1, p1-p3))/np.linalg.norm(p2-p1) + d_and_vert = [d, p3] + d_and_vert_lst.append(d_and_vert) + + #https://stackoverflow.com/questions/39840030/distance-between-point-and-a-line-from-two-points + #http://www.fundza.com/vectors/point2line/index.html + print "Vertex: ", p3, "Distance: ", d + + if d <= min_d: + min_d = d + min_vertex = p3 + + fin_lst = [] + for i in d_and_vert_lst: + if round(i[0], 4) == round(min_d, 4): + fin_lst.append(i) + + # Plotting the star on highest stability vertices + for i in fin_lst: + plt.plot(i[1][0],i[1][1],'*b',ms=16) + + ########################################### + V_RHE = 1.23 - min_d + + pH_0 = fin_lst[0][1][0] + V_SHE = V_RHE - PREFAC*pH_0 + ########################################### + + # plt.annotate('d = '+ str(round(min_d,2)),xy=(center_x, center_y-0.3)) + plt.annotate('V_crit = ' + str(round(V_RHE,2))+' VvsRHE',xy=(center_x, center_y-0.3)) + plt.annotate('V_crit = ' + str(round(V_SHE,2))+' VvsSHE',xy=(center_x, center_y-0.6)) + plt.xlabel("pH") + plt.ylabel("E (V)") + plt.show() diff --git a/pourbaix_pymatgen/heat_map.py b/pourbaix_pymatgen/heat_map.py index 9ac0d9f..8810b4e 100644 --- a/pourbaix_pymatgen/heat_map.py +++ b/pourbaix_pymatgen/heat_map.py @@ -1,471 +1,471 @@ -#| - - Import Modules -# -*- coding: utf-8 -*- -from pourdiag import pd_entries -from entry_methods import pure_atoms_remove, alloy_entries, base_atom -from pd_screen_tools import phase_coord, phase_filter -from stability_crit import most_stable_phase -from element_list import ElementList, ElemList_mod - -import numpy as np -import matplotlib.colors as colors -#__| - -def process(i,j,comp=0.5, heat_map_scale='Pt_ref', pt_oxid_V=0.6470339): - """ - Creates and analyzes a Pourbaix Diagram from two elements (they can be the - same ex. Pt,Pt). Finds relevant entries, creates Pourbaix diagram, - identifies stable phases, and calculates the stability of the phase - - Args: - i: First element in the system - j: Second element in the system - comp: Composition loading of the two elements (default is 0.5) - """ - #| - - process - entries = pd_entries(i.symbol,j.symbol) - coord = phase_coord(entries, comp, prim_elem=i.symbol) - filt1 = phase_filter(coord,'metallic') - filt2 = phase_filter(coord,'metallic_metallic') - filt = filt1 + filt2 - - # msp = most_stable_phase(filt,Pt_ref=True) - if not filt: - print 'heat_map.process - no phase present - '+i.symbol+'-'+j.symbol - msp = [-1.5,'Pourbaix Entry placeholder'] # TEMP - else: - msp = most_stable_phase(filt, scale=heat_map_scale, pt_oxid_V=pt_oxid_V) - # msp = most_stable_phase(filt,pH=10.5,scale=heat_map_scale) - return msp - #__| - -def process_alloy(i,j): # Deprecated ******************************************* - """ - Creates and analyzes a Pourbaix Diagram from two elements (they can be the - same ex. Pt,Pt). Finds relevant entries, removes the pure element entries, - for each alloy removes all other alloys and analyzes stability of all - forced alloy phases. Returns the the most highest performing forced alloy - phase. - - Args: - i: First element in the system - j: Second element in the system - """ - #| - - process_alloy - entries = pd_entries(i.symbol,j.symbol) -# entries = pure_atoms_remove(entries) - alloy_entr = alloy_entries(entries) - if not alloy_entr: - print 'heat map - no alloy entries' - non_alloy = process(i,j) - return non_alloy - - base_atoms = base_atom(entries) - alloy_performance_lst = [] - for alloy in alloy_entr: - entries_0 = entries[:] - comp = alloy.composition \ - .fractional_composition.get_atomic_fraction(base_atoms[0]) - for alloy_0 in alloy_entr: - if not alloy_0 == alloy: entries_0.remove(alloy_0) - - coord = phase_coord(entries_0,comp) - filt1 = phase_filter(coord,'metallic') - filt2 = phase_filter(coord,'metallic_metallic') - filt = filt1 + filt2 - try: - alloy_performance_lst.append(most_stable_phase(filt, scale='Pt_ref')) - except: - pass - - alloy_performance_lst.sort(key=lambda x: x[0], reverse=True) - # NOTE This sort will not work when the performance criteria is distance - # from the ORR line (which needs to be as small as possible) - try: - best_alloy = alloy_performance_lst[0] - except: - best_alloy = [-1,'placeholder'] #NOTE Make this better - return best_alloy - #__| - -def construct_output_matrix(elem): - """ - Constructs the skeleton of the output matrix from the element sweep. Matrix - is square with dimensions of n, where n is the number of elements in elem - - Args: - elem: List of elements to be screened over - """ - #| - - construct_output_matrix - - o_lst = [] - i_cnt = 0 - for i in elem: - o_lst.append([]) - for j in elem: - o_lst[i_cnt].append([]) - i_cnt = i_cnt+1 - return o_lst - #__| - -def finish_symmetric_matrix(elem, output_lst): - """ - Fills in the the opposite diagonal of a symmetric matrix - - Args: - elem: Element list being screened over - output_lst: Half filled matrix to be filled in - """ - #| - - finish_symmetric_matrix - i_cnt = 0 - for i in elem[:-1]: - j_cnt = 1 - for j in elem[1:]: - output_lst[i_cnt][j_cnt] = output_lst[j_cnt][i_cnt] - j_cnt = j_cnt+1 - i_cnt=i_cnt+1 - return output_lst - #__| - - -################################################################################ -# ██ ██████ ██████ ██████ ██ ███ ██ ██████ -# ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ -# ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ ██ ███ -# ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ -# ███████ ██████ ██████ ██ ██ ██ ████ ██████ -################################################################################ - -def run_all_binary_combinations(elements, loop_funct, scale, pt_oxid_V=0.6470339): - """ - """ - #| - - run_all_binary_combinations - o_lst = construct_output_matrix(elements) - - print 'constructing output V_crit matrix from scratch' - - i_cnt = 0 - for j in elements: - # for j in elements[1:]: #TEMP - # for i in elements[i_cnt:1]: #TEMP - for i in elements[i_cnt:]: - print '##_'+j.symbol + i.symbol+'_##' - output = loop_funct(i, j, heat_map_scale=scale, pt_oxid_V=pt_oxid_V) - o_lst[elements.index(i)][elements.index(j)] = output - - #TEMP_PRINT - if i.name=='Ru' or j.name=='Ru': - print 'heat_map.run_all_binary_combinations - TEMP_PRINT' - print output - # - - print '_' - print '_________________________________________' - i_cnt=i_cnt+1 - print '#########################################' - - o_lst = finish_symmetric_matrix(elements,o_lst) - - return o_lst - #__| - -def oxidation_dissolution_product_0(i, j, scale): - """ - Creates Pourbaix Diagrams for single or binary systems - """ - #| - - oxidation_dissolution_product_0 - # from pourdiag import pd_entries - - from pymatgen.analysis.pourbaix.maker import PourbaixDiagram - from pymatgen.analysis.pourbaix.plotter import PourbaixPlotter - from pd_screen_tools import phase_coord, phase_filter - from stability_crit import most_stable_phase, oxidation_dissolution_product - - elem0 = i.symbol; elem1 = j.symbol - - mat_co_0 = 0.50 # Composition of 1st entry in elem_sys - - entr = pd_entries(elem0,elem1) - pourbaix = PourbaixDiagram(entr,{elem0: mat_co_0,elem1: 1-mat_co_0}) - plotter = PourbaixPlotter(pourbaix) - - coord = phase_coord(entr,mat_co_0) - filt1 = phase_filter(coord,'metallic') - filt2 = phase_filter(coord,'metallic_metallic') - filt = filt1 + filt2 - msp = most_stable_phase(filt,scale='RHE') - - tmp = oxidation_dissolution_product(coord,msp) - - if 'Ion' in tmp: - entry_lst = 'dis' - else: - entry_lst = 'oxi' - - """ - entry_lst = '' - i_cnt = 0 - for i in tmp: - entry_lst = str(entry_lst)+'\n'+str(i) - if i_cnt==0: - entry_lst = entry_lst[1:] - i_cnt=i_cnt+1 - - """ - return entry_lst - #__| - -# TEMP -def ref_atoms(i,j, scale): - """ - TEMP - """ - #| - - ref_atoms - ref_atoms = pd_entries(i.symbol,j.symbol) - print ref_atoms #TEMP_PRINT - return ref_atoms - print ref_atoms # TEMP_PRINT - #__| - -################################################################################ -# ██████ ██ ██████ ████████ -# ██ ██ ██ ██ ██ ██ -# ██████ ██ ██ ██ ██ -# ██ ██ ██ ██ ██ -# ██ ███████ ██████ ██ -################################################################################ - -class MidpointNormalize(colors.Normalize): - """ - Used with diverging color schemes to set the white color to 0 - """ - #| - - MidpointNormalize - def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False): - self.midpoint = midpoint - colors.Normalize.__init__(self, vmin, vmax, clip) - - def __call__(self, value, clip=None): - # I'm ignoring masked values and all kinds of edge cases to make a - # simple example... - x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1] - return np.ma.masked_array(np.interp(value, x, y)) - #__| - -def extract_data_from_matrix(output_lst): - """ - Extracts numerical data from screen output matrix (because the output - matrix entries contain numerical stability and PD entry data) and makes a - completley numerical matrix for plotting - - Args: - output_lst: Matrix containing numerical data paired with entry data - """ - #| - - extract_data_from_matrix - data_matrix=[] - cnt=0 - for i in output_lst: - data_matrix.append([]) - for j in i: - try: - data_matrix[cnt].append(j[0]) - except: - data_matrix[cnt].append(0) - cnt=cnt+1 - return data_matrix - #__| - -def plot_heat_map(data_matrix, elem, text_overlay=None, composition=False, - show_plot=False, save_file=True, file_type='.pdf', - heat_map_scale='Pt_ref', transparency=False, plot_title=None, - colorbar_title=None, lock_cbar_rnge=None): - """ - Constructs heat map plot from a matrix. If another matrix is passed to - text_overlay it will be overlayed as text on top of the heatmap squares - - Args: - data_matrix: - elem: - text_overlay: Matrix of data which will be overlayed on the heatmap, if - ='data_value' it will overlay the numerical value for each grid point - """ - #| - - plot_heat_map - - #| - - Import modules - from heat_map import MidpointNormalize - import matplotlib.pyplot as plt; import numpy as np - from element_list import elem_str_mke - #__| - - #| - - Setting colorbar range - if lock_cbar_rnge == None: - vmin_=None - vmax_=None - elif lock_cbar_rnge != None: - vmin_=lock_cbar_rnge[0] - vmax_=lock_cbar_rnge[1] - #__| - - #| - - Main, create heatmap, set labels, colorbar, scale plot - font_color = 'White' - - fig, ax1 = plt.subplots(1,1) - - if heat_map_scale=='Pt_ref': - cmap_ = 'seismic' - norm_ = MidpointNormalize(midpoint=0.) - elif heat_map_scale=='RHE': - cmap_ = 'hot' - norm_ = None - - img = ax1.imshow( data_matrix, cmap=cmap_, interpolation='nearest', - norm=norm_, vmin=vmin_, vmax=vmax_) - - #| - - TEMP - Plotting heat map with either Pt_ref or RHE scaling - # if heat_map_scale=='Pt_ref': - # cmap_='seismic' - # img = ax1.imshow( data_matrix, cmap=cmap_, interpolation='nearest', - # norm=MidpointNormalize(midpoint=0.), vmin=vmin_, vmax=vmax_) - # - # elif heat_map_scale=='RHE': - # cmap_='seismic' - # # cmap_='hot' - # - # img = ax1.imshow( data_matrix, cmap=cmap_, interpolation='nearest', - # norm=MidpointNormalize(midpoint=0.), vmin=vmin_, vmax=vmax_) - - # img = ax1.imshow( data_matrix, cmap=cmap_, interpolation='nearest', - # norm=MidpointNormalize(midpoint=0.)) #TEMP - # img = ax1.imshow(data_matrix, cmap=cmap_, interpolation='nearest') - #cmap='hot'; cmap='seismic'; cmap='Reds' - #__| - - - elem_str = elem_str_mke(elem) - ax1.tick_params(labelbottom='off',labeltop='on') - # plt.setp(ax1.get_xticklabels(), fontdict=font) - plt.setp(ax1.get_xticklabels(), fontsize=32, color=font_color) - plt.setp(ax1.get_yticklabels(), fontsize=32, color=font_color) - tcks = range(0,len(elem_str)) - plt.xticks(tcks,elem_str) - plt.yticks(tcks,elem_str) - - if plot_title != None: - plt.title(plot_title, y=1.06, fontsize=25./23*len(elem)+13, - color=font_color) - - # fig_note = 'Note: Text box numbers indicate the number of alloys - # available in the Materials\nProject data base for a given binary - # element pair. Black boxes indicate no alloy.' - - # plt.figtext(0.08,0.08, fig_note,fontsize=26) - -############################ COLORBAR ########################################## - cb = plt.colorbar(img, spacing='uniform', fraction=0.046, pad=0.04) - plt.setp(plt.getp(cb.ax.axes, 'yticklabels'), color=font_color) - # cb.ax.tick_params(labelsize=20./23*len(elem)+5) - cb.ax.tick_params(labelsize=20./23*len(elem)+14) - - ## Setting the colorbar label - if colorbar_title != None: - col_bar_lb = colorbar_title - elif heat_map_scale=='Pt_ref': - col_bar_lb = 'V$\mathregular{_{critical}}$ - V$\mathregular{_{Pt}}$ [V vs RHE]' - elif heat_map_scale=='RHE': - col_bar_lb = 'V$\mathregular{_{critical}}$ [V vs RHE]' - - cb.set_label(col_bar_lb, rotation=-90, fontsize=25./23*len(elem)+10, - labelpad=50, color=font_color) -################################################################################ - - scl = 20./23.*len(elem)+2; fig.set_figheight(scl); fig.set_figwidth(scl) - #__| - - if composition != False: - # Adding text to plot - import matplotlib.patheffects as PathEffects - - plt.text(0.1, 0.9,str(composition), fontsize=45, ha='center', - va='center', color=font_color, - transform=ax1.transAxes).set_path_effects([PathEffects.withStroke(linewidth=2, foreground='w')]) - - #| - - Setting text in heatmaps squares - ###################### SETTING TEXT IN EACH SQUARE ######################### - ############################################################################ - if text_overlay == 'data_value': - text_overlay = np.array(data_matrix) - - diff = 1. - min_val = 0. - rows = text_overlay.shape[0] - cols = text_overlay.shape[1] - - col_array = np.arange(min_val, cols, diff) - row_array = np.arange(min_val, rows, diff) - x, y = np.meshgrid(col_array, row_array) - # TEMP - print '_________________________________________' - # - import matplotlib.patheffects as PathEffects - for col_val, row_val in zip(x.flatten(), y.flatten()): - c = np.round(text_overlay[int(row_val), int(col_val)],2) - fontsize_0=17 - - ax1.text(col_val, row_val, c, fontsize=fontsize_0 ,va='center', - ha='center').set_path_effects([PathEffects.withStroke(linewidth=2, - foreground='w')]) - - elif text_overlay != None: - text_overlay = np.array(text_overlay) - - diff = 1. - min_val = 0. - rows = text_overlay.shape[0] - cols = text_overlay.shape[1] - - col_array = np.arange(min_val, cols, diff) - row_array = np.arange(min_val, rows, diff) - x, y = np.meshgrid(col_array, row_array) - - import matplotlib.patheffects as PathEffects - for col_val, row_val in zip(x.flatten(), y.flatten()): - - c = str(text_overlay[row_val.astype(int),col_val.astype(int)]) - fontsize_0=54/2 - - #| - - TEMP - # if row_val.astype(int)==col_val.astype(int): - # c = '' - # fontsize_0=10 - # elif text_overlay[row_val.astype(int),col_val.astype(int)] == 0: - # c = u'\u25A0' - # fontsize_0=20 # 56 covers most of square - # else: - # c = str(text_overlay[row_val.astype(int),col_val.astype(int)]) - # fontsize_0=26/4 - #__| - - ax1.text(col_val, row_val, c, fontsize=fontsize_0, - color=font_color, va='center', - ha='center').set_path_effects([PathEffects.withStroke(linewidth=2, - foreground='black')]) - ############################################################################ - #__| - - #| - - Saving Figure, showing figure - import fnmatch; import sys; import os - num_fle = len(fnmatch.filter(os.listdir('.'),'*'+file_type)) - fle_nme = 'fig_heat_map'+'_'+str(num_fle)+file_type - - if save_file == True: - print 'saving '+fle_nme - - # if file_type=='.svg': - # fig.savefig(fle_nme, format='svg',spi=1200,transparent=transparency) - # else: - # fig.savefig(fle_nme, transparent=transparency) - - fig.savefig(fle_nme, format=file_type[1:],spi=1200,transparent=transparency) - - if show_plot==True: fig.patch.set_facecolor('black'); plt.show() - #__| - - #__| +#| - - Import Modules +# -*- coding: utf-8 -*- +from pourdiag import pd_entries +from entry_methods import pure_atoms_remove, alloy_entries, base_atom +from pd_screen_tools import phase_coord, phase_filter +from stability_crit import most_stable_phase +from element_list import ElementList, ElemList_mod + +import numpy as np +import matplotlib.colors as colors +#__| + +def process(i,j,comp=0.5, heat_map_scale='Pt_ref', pt_oxid_V=0.6470339): + """ + Creates and analyzes a Pourbaix Diagram from two elements (they can be the + same ex. Pt,Pt). Finds relevant entries, creates Pourbaix diagram, + identifies stable phases, and calculates the stability of the phase + + Args: + i: First element in the system + j: Second element in the system + comp: Composition loading of the two elements (default is 0.5) + """ + #| - - process + entries = pd_entries(i.symbol,j.symbol) + coord = phase_coord(entries, comp, prim_elem=i.symbol) + filt1 = phase_filter(coord,'metallic') + filt2 = phase_filter(coord,'metallic_metallic') + filt = filt1 + filt2 + + # msp = most_stable_phase(filt,Pt_ref=True) + if not filt: + print 'heat_map.process - no phase present - '+i.symbol+'-'+j.symbol + msp = [-1.5,'Pourbaix Entry placeholder'] # TEMP + else: + msp = most_stable_phase(filt, scale=heat_map_scale, pt_oxid_V=pt_oxid_V) + # msp = most_stable_phase(filt,pH=10.5,scale=heat_map_scale) + return msp + #__| + +def process_alloy(i,j): # Deprecated ******************************************* + """ + Creates and analyzes a Pourbaix Diagram from two elements (they can be the + same ex. Pt,Pt). Finds relevant entries, removes the pure element entries, + for each alloy removes all other alloys and analyzes stability of all + forced alloy phases. Returns the the most highest performing forced alloy + phase. + + Args: + i: First element in the system + j: Second element in the system + """ + #| - - process_alloy + entries = pd_entries(i.symbol,j.symbol) +# entries = pure_atoms_remove(entries) + alloy_entr = alloy_entries(entries) + if not alloy_entr: + print 'heat map - no alloy entries' + non_alloy = process(i,j) + return non_alloy + + base_atoms = base_atom(entries) + alloy_performance_lst = [] + for alloy in alloy_entr: + entries_0 = entries[:] + comp = alloy.composition \ + .fractional_composition.get_atomic_fraction(base_atoms[0]) + for alloy_0 in alloy_entr: + if not alloy_0 == alloy: entries_0.remove(alloy_0) + + coord = phase_coord(entries_0,comp) + filt1 = phase_filter(coord,'metallic') + filt2 = phase_filter(coord,'metallic_metallic') + filt = filt1 + filt2 + try: + alloy_performance_lst.append(most_stable_phase(filt, scale='Pt_ref')) + except: + pass + + alloy_performance_lst.sort(key=lambda x: x[0], reverse=True) + # NOTE This sort will not work when the performance criteria is distance + # from the ORR line (which needs to be as small as possible) + try: + best_alloy = alloy_performance_lst[0] + except: + best_alloy = [-1,'placeholder'] #NOTE Make this better + return best_alloy + #__| + +def construct_output_matrix(elem): + """ + Constructs the skeleton of the output matrix from the element sweep. Matrix + is square with dimensions of n, where n is the number of elements in elem + + Args: + elem: List of elements to be screened over + """ + #| - - construct_output_matrix + + o_lst = [] + i_cnt = 0 + for i in elem: + o_lst.append([]) + for j in elem: + o_lst[i_cnt].append([]) + i_cnt = i_cnt+1 + return o_lst + #__| + +def finish_symmetric_matrix(elem, output_lst): + """ + Fills in the the opposite diagonal of a symmetric matrix + + Args: + elem: Element list being screened over + output_lst: Half filled matrix to be filled in + """ + #| - - finish_symmetric_matrix + i_cnt = 0 + for i in elem[:-1]: + j_cnt = 1 + for j in elem[1:]: + output_lst[i_cnt][j_cnt] = output_lst[j_cnt][i_cnt] + j_cnt = j_cnt+1 + i_cnt=i_cnt+1 + return output_lst + #__| + + +################################################################################ +# ██ ██████ ██████ ██████ ██ ███ ██ ██████ +# ██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ +# ██ ██ ██ ██ ██ ██████ ██ ██ ██ ██ ██ ███ +# ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ +# ███████ ██████ ██████ ██ ██ ██ ████ ██████ +################################################################################ + +def run_all_binary_combinations(elements, loop_funct, scale, pt_oxid_V=0.6470339): + """ + """ + #| - - run_all_binary_combinations + o_lst = construct_output_matrix(elements) + + print 'constructing output V_crit matrix from scratch' + + i_cnt = 0 + for j in elements: + # for j in elements[1:]: #TEMP + # for i in elements[i_cnt:1]: #TEMP + for i in elements[i_cnt:]: + print '##_'+j.symbol + i.symbol+'_##' + output = loop_funct(i, j, heat_map_scale=scale, pt_oxid_V=pt_oxid_V) + o_lst[elements.index(i)][elements.index(j)] = output + + #TEMP_PRINT + if i.name=='Ru' or j.name=='Ru': + print 'heat_map.run_all_binary_combinations - TEMP_PRINT' + print output + # + + print '_' + print '_________________________________________' + i_cnt=i_cnt+1 + print '#########################################' + + o_lst = finish_symmetric_matrix(elements,o_lst) + + return o_lst + #__| + +def oxidation_dissolution_product_0(i, j, scale): + """ + Creates Pourbaix Diagrams for single or binary systems + """ + #| - - oxidation_dissolution_product_0 + # from pourdiag import pd_entries + + from pymatgen.analysis.pourbaix.maker import PourbaixDiagram + from pymatgen.analysis.pourbaix.plotter import PourbaixPlotter + from pd_screen_tools import phase_coord, phase_filter + from stability_crit import most_stable_phase, oxidation_dissolution_product + + elem0 = i.symbol; elem1 = j.symbol + + mat_co_0 = 0.50 # Composition of 1st entry in elem_sys + + entr = pd_entries(elem0,elem1) + pourbaix = PourbaixDiagram(entr,{elem0: mat_co_0,elem1: 1-mat_co_0}) + plotter = PourbaixPlotter(pourbaix) + + coord = phase_coord(entr,mat_co_0) + filt1 = phase_filter(coord,'metallic') + filt2 = phase_filter(coord,'metallic_metallic') + filt = filt1 + filt2 + msp = most_stable_phase(filt,scale='RHE') + + tmp = oxidation_dissolution_product(coord,msp) + + if 'Ion' in tmp: + entry_lst = 'dis' + else: + entry_lst = 'oxi' + + """ + entry_lst = '' + i_cnt = 0 + for i in tmp: + entry_lst = str(entry_lst)+'\n'+str(i) + if i_cnt==0: + entry_lst = entry_lst[1:] + i_cnt=i_cnt+1 + + """ + return entry_lst + #__| + +# TEMP +def ref_atoms(i,j, scale): + """ + TEMP + """ + #| - - ref_atoms + ref_atoms = pd_entries(i.symbol,j.symbol) + print ref_atoms #TEMP_PRINT + return ref_atoms + print ref_atoms # TEMP_PRINT + #__| + +################################################################################ +# ██████ ██ ██████ ████████ +# ██ ██ ██ ██ ██ ██ +# ██████ ██ ██ ██ ██ +# ██ ██ ██ ██ ██ +# ██ ███████ ██████ ██ +################################################################################ + +class MidpointNormalize(colors.Normalize): + """ + Used with diverging color schemes to set the white color to 0 + """ + #| - - MidpointNormalize + def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False): + self.midpoint = midpoint + colors.Normalize.__init__(self, vmin, vmax, clip) + + def __call__(self, value, clip=None): + # I'm ignoring masked values and all kinds of edge cases to make a + # simple example... + x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1] + return np.ma.masked_array(np.interp(value, x, y)) + #__| + +def extract_data_from_matrix(output_lst): + """ + Extracts numerical data from screen output matrix (because the output + matrix entries contain numerical stability and PD entry data) and makes a + completley numerical matrix for plotting + + Args: + output_lst: Matrix containing numerical data paired with entry data + """ + #| - - extract_data_from_matrix + data_matrix=[] + cnt=0 + for i in output_lst: + data_matrix.append([]) + for j in i: + try: + data_matrix[cnt].append(j[0]) + except: + data_matrix[cnt].append(0) + cnt=cnt+1 + return data_matrix + #__| + +def plot_heat_map(data_matrix, elem, text_overlay=None, composition=False, + show_plot=False, save_file=True, file_type='.pdf', + heat_map_scale='Pt_ref', transparency=False, plot_title=None, + colorbar_title=None, lock_cbar_rnge=None): + """ + Constructs heat map plot from a matrix. If another matrix is passed to + text_overlay it will be overlayed as text on top of the heatmap squares + + Args: + data_matrix: + elem: + text_overlay: Matrix of data which will be overlayed on the heatmap, if + ='data_value' it will overlay the numerical value for each grid point + """ + #| - - plot_heat_map + + #| - - Import modules + from heat_map import MidpointNormalize + import matplotlib.pyplot as plt; import numpy as np + from element_list import elem_str_mke + #__| + + #| - - Setting colorbar range + if lock_cbar_rnge == None: + vmin_=None + vmax_=None + elif lock_cbar_rnge != None: + vmin_=lock_cbar_rnge[0] + vmax_=lock_cbar_rnge[1] + #__| + + #| - - Main, create heatmap, set labels, colorbar, scale plot + font_color = 'White' + + fig, ax1 = plt.subplots(1,1) + + if heat_map_scale=='Pt_ref': + cmap_ = 'seismic' + norm_ = MidpointNormalize(midpoint=0.) + elif heat_map_scale=='RHE': + cmap_ = 'hot' + norm_ = None + + img = ax1.imshow( data_matrix, cmap=cmap_, interpolation='nearest', + norm=norm_, vmin=vmin_, vmax=vmax_) + + #| - - TEMP - Plotting heat map with either Pt_ref or RHE scaling + # if heat_map_scale=='Pt_ref': + # cmap_='seismic' + # img = ax1.imshow( data_matrix, cmap=cmap_, interpolation='nearest', + # norm=MidpointNormalize(midpoint=0.), vmin=vmin_, vmax=vmax_) + # + # elif heat_map_scale=='RHE': + # cmap_='seismic' + # # cmap_='hot' + # + # img = ax1.imshow( data_matrix, cmap=cmap_, interpolation='nearest', + # norm=MidpointNormalize(midpoint=0.), vmin=vmin_, vmax=vmax_) + + # img = ax1.imshow( data_matrix, cmap=cmap_, interpolation='nearest', + # norm=MidpointNormalize(midpoint=0.)) #TEMP + # img = ax1.imshow(data_matrix, cmap=cmap_, interpolation='nearest') + #cmap='hot'; cmap='seismic'; cmap='Reds' + #__| + + + elem_str = elem_str_mke(elem) + ax1.tick_params(labelbottom='off',labeltop='on') + # plt.setp(ax1.get_xticklabels(), fontdict=font) + plt.setp(ax1.get_xticklabels(), fontsize=32, color=font_color) + plt.setp(ax1.get_yticklabels(), fontsize=32, color=font_color) + tcks = range(0,len(elem_str)) + plt.xticks(tcks,elem_str) + plt.yticks(tcks,elem_str) + + if plot_title != None: + plt.title(plot_title, y=1.06, fontsize=25./23*len(elem)+13, + color=font_color) + + # fig_note = 'Note: Text box numbers indicate the number of alloys + # available in the Materials\nProject data base for a given binary + # element pair. Black boxes indicate no alloy.' + + # plt.figtext(0.08,0.08, fig_note,fontsize=26) + +############################ COLORBAR ########################################## + cb = plt.colorbar(img, spacing='uniform', fraction=0.046, pad=0.04) + plt.setp(plt.getp(cb.ax.axes, 'yticklabels'), color=font_color) + # cb.ax.tick_params(labelsize=20./23*len(elem)+5) + cb.ax.tick_params(labelsize=20./23*len(elem)+14) + + ## Setting the colorbar label + if colorbar_title != None: + col_bar_lb = colorbar_title + elif heat_map_scale=='Pt_ref': + col_bar_lb = 'V$\mathregular{_{critical}}$ - V$\mathregular{_{Pt}}$ [V vs RHE]' + elif heat_map_scale=='RHE': + col_bar_lb = 'V$\mathregular{_{critical}}$ [V vs RHE]' + + cb.set_label(col_bar_lb, rotation=-90, fontsize=25./23*len(elem)+10, + labelpad=50, color=font_color) +################################################################################ + + scl = 20./23.*len(elem)+2; fig.set_figheight(scl); fig.set_figwidth(scl) + #__| + + if composition != False: + # Adding text to plot + import matplotlib.patheffects as PathEffects + + plt.text(0.1, 0.9,str(composition), fontsize=45, ha='center', + va='center', color=font_color, + transform=ax1.transAxes).set_path_effects([PathEffects.withStroke(linewidth=2, foreground='w')]) + + #| - - Setting text in heatmaps squares + ###################### SETTING TEXT IN EACH SQUARE ######################### + ############################################################################ + if text_overlay == 'data_value': + text_overlay = np.array(data_matrix) + + diff = 1. + min_val = 0. + rows = text_overlay.shape[0] + cols = text_overlay.shape[1] + + col_array = np.arange(min_val, cols, diff) + row_array = np.arange(min_val, rows, diff) + x, y = np.meshgrid(col_array, row_array) + # TEMP + print '_________________________________________' + # + import matplotlib.patheffects as PathEffects + for col_val, row_val in zip(x.flatten(), y.flatten()): + c = np.round(text_overlay[int(row_val), int(col_val)],2) + fontsize_0=17 + + ax1.text(col_val, row_val, c, fontsize=fontsize_0 ,va='center', + ha='center').set_path_effects([PathEffects.withStroke(linewidth=2, + foreground='w')]) + + elif text_overlay != None: + text_overlay = np.array(text_overlay) + + diff = 1. + min_val = 0. + rows = text_overlay.shape[0] + cols = text_overlay.shape[1] + + col_array = np.arange(min_val, cols, diff) + row_array = np.arange(min_val, rows, diff) + x, y = np.meshgrid(col_array, row_array) + + import matplotlib.patheffects as PathEffects + for col_val, row_val in zip(x.flatten(), y.flatten()): + + c = str(text_overlay[row_val.astype(int),col_val.astype(int)]) + fontsize_0=54/2 + + #| - - TEMP + # if row_val.astype(int)==col_val.astype(int): + # c = '' + # fontsize_0=10 + # elif text_overlay[row_val.astype(int),col_val.astype(int)] == 0: + # c = u'\u25A0' + # fontsize_0=20 # 56 covers most of square + # else: + # c = str(text_overlay[row_val.astype(int),col_val.astype(int)]) + # fontsize_0=26/4 + #__| + + ax1.text(col_val, row_val, c, fontsize=fontsize_0, + color=font_color, va='center', + ha='center').set_path_effects([PathEffects.withStroke(linewidth=2, + foreground='black')]) + ############################################################################ + #__| + + #| - - Saving Figure, showing figure + import fnmatch; import sys; import os + num_fle = len(fnmatch.filter(os.listdir('.'),'*'+file_type)) + fle_nme = 'fig_heat_map'+'_'+str(num_fle)+file_type + + if save_file == True: + print 'saving '+fle_nme + + # if file_type=='.svg': + # fig.savefig(fle_nme, format='svg',spi=1200,transparent=transparency) + # else: + # fig.savefig(fle_nme, transparent=transparency) + + fig.savefig(fle_nme, format=file_type[1:],spi=1200,transparent=transparency) + + if show_plot==True: fig.patch.set_facecolor('black'); plt.show() + #__| + + #__| diff --git a/pourbaix_pymatgen/pd_make.py b/pourbaix_pymatgen/pd_make.py index 7f9d5d8..804922f 100644 --- a/pourbaix_pymatgen/pd_make.py +++ b/pourbaix_pymatgen/pd_make.py @@ -1,313 +1,313 @@ -# -*- coding: utf-8 -*- - -def entry_data(mtnme_1, mtnme_2, direct_0, mprester_key): - """ - Obtaining entry and ion data from local source. If the data cannot be - found, it will do an HTTP request to the Materials Project database. - - Args: - mtnme_1: Material 1 - mtnme_2: Material 2 - direct_0: Directory of entry database for binary systems - """ - #| - entry_data - from pymatgen.matproj.rest import MPRester # Access species in MP - import warnings; import json; from monty.json import MontyDecoder - warnings.filterwarnings('ignore') # Ignore errors related to HTTP request - mpr = MPRester(mprester_key) # REST api adaptor, INPUT - - try: - direct_0 = direct_0 #INPUT# - direct = direct_0+mtnme_1+'_'+mtnme_2+'/' - entries = json.loads(open(direct+'mp_entries.txt','r').read(), cls=MontyDecoder) - ion_dict_1 = json.loads(open(direct+'ion_data_1.txt','r').read()) - - if not mtnme_1==mtnme_2: - ion_dict_2 = json.loads(open(direct+'ion_data_2.txt','r').read()) - except: - pass - -################################################################################ - ## Obtains all entries in MP corresponding to input element, O and H - if mtnme_1==mtnme_2: - try: - entries = entries - except: - print 'pd_make.entry_data - made http request line 64' - entries = mpr.get_entries_in_chemsys([mtnme_1, 'O', 'H']) - - ## Dictionary of reference state:experimental formation energy - try: - ion_dict_1 = ion_dict_1 - except: - print 'pd_make.entry_data - made http request line 69' - ion_dict_1 = mpr._make_request('/pourbaix_diagram/reference_data/'+mtnme_1) - out_dict = {"entries" : entries, "ion_dict_1" : ion_dict_1} - return out_dict - - if not mtnme_1==mtnme_2: - try: - entries = entries - except: - print 'pd_make.entry_data - made http request - line 146' - ## Obtains all entries in MP corresponding to input element, O and H - entries = mpr.get_entries_in_chemsys([mtnme_1, mtnme_2, 'O', 'H']) - ## Dictionary of reference state:experimental formation energy - try: - ion_dict_1 == ion_dict_1 - ion_dict_2 == ion_dict_2 - except: - print 'pd_make.entry_data - made http request - line 154' - ion_dict_1 = mpr._make_request('/pourbaix_diagram/reference_data/'+mtnme_1) - ion_dict_2 = mpr._make_request('/pourbaix_diagram/reference_data/'+mtnme_2) - out_dict = {"entries" : entries, "ion_dict_1" : ion_dict_1, "ion_dict_2" : ion_dict_2} - return out_dict - #__| - -def remove_duplicate_entries(entry_list): - """ - """ - #| - remove_duplicate_entries - def contains_entry(entry_list, ent): - """ - Helpful to filter duplicate entries, if entry - is in entry_list, return True - Args: - entry_list: list of pymatgen entries to consider - entry: entry which will be analyzed - """ - - ent_id = ent.entry_id - ent_E = ent.energy_per_atom - ent_redfor = ent.composition.reduced_formula - for e in entry_list: - if e.entry_id == ent_id or (abs(ent_E - e.energy_per_atom) < 1e-6 - and ent_redfor == e.composition.reduced_formula): - return True - - entry_list_new = list() - for entry in entry_list: - if not contains_entry(entry_list_new, entry): - entry_list_new.append(entry) - - return entry_list_new - #__| - -def aq_correction(entries): - """ - Applies the Materials Project Aqueous Compatibility scheme for mixing GGA - and GGA+U to a list of entries. - Removes entries which aren't compatible with the mixing scheme - - Args: - entries: List of entries on which the correction will be applied - """ - #| - aq_correction - from pymatgen.entries.compatibility import MaterialsProjectAqueousCompatibility - - def contains_entry(entry_list, ent): - """ - Helpful to filter duplicate entries, if entry - is in entry_list, return True - Args: - entry_list: list of pymatgen entries to consider - entry: entry which will be analyzed - """ - - ent_id = ent.entry_id - ent_E = ent.energy_per_atom - ent_redfor = ent.composition.reduced_formula - for e in entry_list: - if e.entry_id == ent_id or (abs(ent_E - e.energy_per_atom) < 1e-6 - and ent_redfor == e.composition.reduced_formula): - return True - - aqcompat = MaterialsProjectAqueousCompatibility() #Implements the GGA/GGA+U mixing scheme, - - entries_aqcorr = list() - for entry in entries: - aq_corrected_entry = aqcompat.process_entry(entry) #Corrections, if none applicable, gets rid of entry - - if not contains_entry(entries_aqcorr, aq_corrected_entry): #If entry already in entries_aqcorr don't add - entries_aqcorr.append(aq_corrected_entry) - - return entries_aqcorr -#__| - -def stable_entr(entries_aqcorr): - """ - Evaluate a entries in list for stability and discard unstable entries - Remove H2, O2, H2O, and H2O2 from the list - Calculate the formation using the species in the chemical ensemble - - Args: - entries_aqcorr: List of entries, usually they have been run through the - aqueous compatibility module - """ - #| - stable_entr - from pymatgen.analysis.pourbaix.entry import PourbaixEntry - from pymatgen.phasediagram.maker import PhaseDiagram - - ## Generate phase diagram to consider only solid entries stable in water - pd = PhaseDiagram(entries_aqcorr) - stable_solids = pd.stable_entries - stable_solids_minus_h2o = [entry for entry in stable_solids if - entry.composition.reduced_formula not in ["H2", "O2", "H2O", "H2O2"]] - - return stable_solids_minus_h2o - #__| - -def form_e(stable_solids_minus_h2o, entries_aqcorr, gas_gibbs=True): - """ - Calculate the formation energy for the entries in stable_solids_minus_h2o - Reduce by stoicheometric factor if applicable (ex. Fe4O4) - - Args: - stable_solids_minus_h2o: list of stable solids without O2, H2O, H2, and - H2O2 (from stable_entr) - entries_aqcorr: entries list before being modified by stable_entr - """ - #| - form_e - - #| - Imported Modules - from pymatgen.analysis.pourbaix.entry import PourbaixEntry - from pymatgen.phasediagram.maker import PhaseDiagram - from entry_methods import base_atom - from energy_scheme import ref_atoms_dict - #__| - - ref_atom_energies = ref_atoms_dict() - e_o = ref_atom_energies['e_o'] - e_h = ref_atom_energies['e_h'] - - pd = PhaseDiagram(entries_aqcorr) - - base_at = base_atom(stable_solids_minus_h2o) - d = {} - for i in stable_solids_minus_h2o: - if i.name in base_at: - d[i.name] = i.energy_per_atom - - def form_energy(entry, solid_ref_energy_dict, gas_gibbs=True): - """ - Calculates the formation energy of an entry relative to the VASP - energies of the reference atoms. Gibbs/entropy corrections for the gas - phase are optionable - - Args: - entry: Entry whose formation energy will be calculated - solid_ref_energy_dict: Dictionary of reference atom energies - gas_gibbs: Whether the gas phase reference atoms will have an - entropic correction - """ - if gas_gibbs==True: - ref_dict = {} - ref_dict['O'] = e_o-0.3167 - ref_dict['H'] = e_h-0.36218 - elif gas_gibbs==False: - ref_dict = {} - ref_dict['O'] = e_o - ref_dict['H'] = e_h - - z = ref_dict.copy() - z.update(solid_ref_energy_dict) - ref_dict = z - - elem_dict = entry.composition.get_el_amt_dict() - entry_e = entry.energy - - for elem in entry.composition.elements: - elem_num = elem_dict[elem.symbol] - entry_e = entry_e - elem_num*ref_dict[elem.symbol] - return entry_e - - pbx_solid_entries = [] - for entry in stable_solids_minus_h2o: - pbx_entry = PourbaixEntry(entry) - pbx_entry.g0_replace(form_energy(entry, d, gas_gibbs=gas_gibbs)) #Replace E with form E relative to ref elements - # pbx_entry.g0_replace(pd.get_form_energy(entry)) #Replace E with form E relative to ref elements - pbx_entry.reduced_entry() #Reduces parameters by stoich factor (ex. Li2O2 -> LiO) - pbx_solid_entries.append(pbx_entry) - - return pbx_solid_entries - #__| - -############################################################################### -# ██ ██████ ███ ██ ███████ -# ██ ██ ██ ████ ██ ██ -# ██ ██ ██ ██ ██ ██ ███████ -# ██ ██ ██ ██ ██ ██ ██ -# ██ ██████ ██ ████ ███████ -############################################################################### - -def ref_entry_find(stable_solids_minus_h2o, ref_state): - """ - Args: - stable_solids_minus_h2o: - ref_state: - """ - #| - ref_entry_find - - # print ref_state+'_______________' # TEMP - #Chk# Ion solid material reference state (defined by the dict 'Reference Solid' entry in ion_dict) - # is in the generated material list (if YES assign to ref_entry var), if NO generate error - for entry in stable_solids_minus_h2o: - # print entry.composition.reduced_formula+'#_#_' # TEMP - if entry.composition.reduced_formula==ref_state: ref_entry=entry; break - else: ref_entry=[] - #if not ref_entry: return '05 - Error with '+ref_state+' solid reference data for:'+mtnme - if not ref_entry: - print '05 - Error with '+ref_state+' solid reference data' - return '05 - Error with '+ref_state+' solid reference data' - - return ref_entry - #__| - -def ref_entry_stoich(ref_entry): - """ - """ - #| - ref_entry_stoich - ref_stoich_fact=ref_entry.composition.get_reduced_composition_and_factor()[1] - return ref_stoich_fact - #__| - -def mke_pour_ion_entr(mtnme, ion_dict, stable_solids_minus_h2o, ref_state, entries_aqcorr, ref_dict): - """ - """ - #| - mke_pour_ion_entr - from pymatgen import Element # Accesses properties of element - from pymatgen.core.ion import Ion - from pymatgen.phasediagram.maker import PhaseDiagram - from pymatgen.analysis.pourbaix.entry import PourbaixEntry, IonEntry - - from pd_make import ref_entry_find, ref_entry_stoich - pd = PhaseDiagram(entries_aqcorr) - - ref_entry = ref_entry_find(stable_solids_minus_h2o, ref_state) - ref_stoich_fact = ref_entry_stoich(ref_entry) - - ## Calculate DFT reference E for ions (Persson et al, PRB (2012)) - dft_for_e=pd.get_form_energy(ref_entry)/ref_stoich_fact # DFT formation E, normalized by composition "factor" - ion_correction_1 = dft_for_e-ref_dict[ref_state] # Difference of DFT form E and exp for E of reference - - el = Element(mtnme) - pbx_ion_entries_1 = [] - for id in ion_dict: - comp = Ion.from_formula(id['Name']) # Ion name-> Ion comp name (ex. Fe[3+] -> Ion: Fe1 +3) - # comp.composition[el] : number of Fe atoms in ion - num_el_ref = (ref_entry.composition[el]) / ref_stoich_fact # number of element atoms in reference - factor = comp.composition[el] / num_el_ref # Stoicheometric factor for ionic correction - # (i.e. Fe2O3 ref but calc E for Fe[2+] ion) - energy = id['Energy'] + ion_correction_1 * factor - - #TEMP_PRINT - if id['Name']=='Pd[2+]': - energy = 123 - # print id['Name'] - - pbx_entry_ion = PourbaixEntry(IonEntry(comp, energy)) - pbx_entry_ion.name = id['Name'] - pbx_ion_entries_1.append(pbx_entry_ion) - - return pbx_ion_entries_1 - #__| +# -*- coding: utf-8 -*- + +def entry_data(mtnme_1, mtnme_2, direct_0, mprester_key): + """ + Obtaining entry and ion data from local source. If the data cannot be + found, it will do an HTTP request to the Materials Project database. + + Args: + mtnme_1: Material 1 + mtnme_2: Material 2 + direct_0: Directory of entry database for binary systems + """ + #| - entry_data + from pymatgen.matproj.rest import MPRester # Access species in MP + import warnings; import json; from monty.json import MontyDecoder + warnings.filterwarnings('ignore') # Ignore errors related to HTTP request + mpr = MPRester(mprester_key) # REST api adaptor, INPUT + + try: + direct_0 = direct_0 #INPUT# + direct = direct_0+mtnme_1+'_'+mtnme_2+'/' + entries = json.loads(open(direct+'mp_entries.txt','r').read(), cls=MontyDecoder) + ion_dict_1 = json.loads(open(direct+'ion_data_1.txt','r').read()) + + if not mtnme_1==mtnme_2: + ion_dict_2 = json.loads(open(direct+'ion_data_2.txt','r').read()) + except: + pass + +################################################################################ + ## Obtains all entries in MP corresponding to input element, O and H + if mtnme_1==mtnme_2: + try: + entries = entries + except: + print 'pd_make.entry_data - made http request line 64' + entries = mpr.get_entries_in_chemsys([mtnme_1, 'O', 'H']) + + ## Dictionary of reference state:experimental formation energy + try: + ion_dict_1 = ion_dict_1 + except: + print 'pd_make.entry_data - made http request line 69' + ion_dict_1 = mpr._make_request('/pourbaix_diagram/reference_data/'+mtnme_1) + out_dict = {"entries" : entries, "ion_dict_1" : ion_dict_1} + return out_dict + + if not mtnme_1==mtnme_2: + try: + entries = entries + except: + print 'pd_make.entry_data - made http request - line 146' + ## Obtains all entries in MP corresponding to input element, O and H + entries = mpr.get_entries_in_chemsys([mtnme_1, mtnme_2, 'O', 'H']) + ## Dictionary of reference state:experimental formation energy + try: + ion_dict_1 == ion_dict_1 + ion_dict_2 == ion_dict_2 + except: + print 'pd_make.entry_data - made http request - line 154' + ion_dict_1 = mpr._make_request('/pourbaix_diagram/reference_data/'+mtnme_1) + ion_dict_2 = mpr._make_request('/pourbaix_diagram/reference_data/'+mtnme_2) + out_dict = {"entries" : entries, "ion_dict_1" : ion_dict_1, "ion_dict_2" : ion_dict_2} + return out_dict + #__| + +def remove_duplicate_entries(entry_list): + """ + """ + #| - remove_duplicate_entries + def contains_entry(entry_list, ent): + """ + Helpful to filter duplicate entries, if entry + is in entry_list, return True + Args: + entry_list: list of pymatgen entries to consider + entry: entry which will be analyzed + """ + + ent_id = ent.entry_id + ent_E = ent.energy_per_atom + ent_redfor = ent.composition.reduced_formula + for e in entry_list: + if e.entry_id == ent_id or (abs(ent_E - e.energy_per_atom) < 1e-6 + and ent_redfor == e.composition.reduced_formula): + return True + + entry_list_new = list() + for entry in entry_list: + if not contains_entry(entry_list_new, entry): + entry_list_new.append(entry) + + return entry_list_new + #__| + +def aq_correction(entries): + """ + Applies the Materials Project Aqueous Compatibility scheme for mixing GGA + and GGA+U to a list of entries. + Removes entries which aren't compatible with the mixing scheme + + Args: + entries: List of entries on which the correction will be applied + """ + #| - aq_correction + from pymatgen.entries.compatibility import MaterialsProjectAqueousCompatibility + + def contains_entry(entry_list, ent): + """ + Helpful to filter duplicate entries, if entry + is in entry_list, return True + Args: + entry_list: list of pymatgen entries to consider + entry: entry which will be analyzed + """ + + ent_id = ent.entry_id + ent_E = ent.energy_per_atom + ent_redfor = ent.composition.reduced_formula + for e in entry_list: + if e.entry_id == ent_id or (abs(ent_E - e.energy_per_atom) < 1e-6 + and ent_redfor == e.composition.reduced_formula): + return True + + aqcompat = MaterialsProjectAqueousCompatibility() #Implements the GGA/GGA+U mixing scheme, + + entries_aqcorr = list() + for entry in entries: + aq_corrected_entry = aqcompat.process_entry(entry) #Corrections, if none applicable, gets rid of entry + + if not contains_entry(entries_aqcorr, aq_corrected_entry): #If entry already in entries_aqcorr don't add + entries_aqcorr.append(aq_corrected_entry) + + return entries_aqcorr +#__| + +def stable_entr(entries_aqcorr): + """ + Evaluate a entries in list for stability and discard unstable entries + Remove H2, O2, H2O, and H2O2 from the list + Calculate the formation using the species in the chemical ensemble + + Args: + entries_aqcorr: List of entries, usually they have been run through the + aqueous compatibility module + """ + #| - stable_entr + from pymatgen.analysis.pourbaix.entry import PourbaixEntry + from pymatgen.phasediagram.maker import PhaseDiagram + + ## Generate phase diagram to consider only solid entries stable in water + pd = PhaseDiagram(entries_aqcorr) + stable_solids = pd.stable_entries + stable_solids_minus_h2o = [entry for entry in stable_solids if + entry.composition.reduced_formula not in ["H2", "O2", "H2O", "H2O2"]] + + return stable_solids_minus_h2o + #__| + +def form_e(stable_solids_minus_h2o, entries_aqcorr, gas_gibbs=True): + """ + Calculate the formation energy for the entries in stable_solids_minus_h2o + Reduce by stoicheometric factor if applicable (ex. Fe4O4) + + Args: + stable_solids_minus_h2o: list of stable solids without O2, H2O, H2, and + H2O2 (from stable_entr) + entries_aqcorr: entries list before being modified by stable_entr + """ + #| - form_e + + #| - Imported Modules + from pymatgen.analysis.pourbaix.entry import PourbaixEntry + from pymatgen.phasediagram.maker import PhaseDiagram + from entry_methods import base_atom + from energy_scheme import ref_atoms_dict + #__| + + ref_atom_energies = ref_atoms_dict() + e_o = ref_atom_energies['e_o'] + e_h = ref_atom_energies['e_h'] + + pd = PhaseDiagram(entries_aqcorr) + + base_at = base_atom(stable_solids_minus_h2o) + d = {} + for i in stable_solids_minus_h2o: + if i.name in base_at: + d[i.name] = i.energy_per_atom + + def form_energy(entry, solid_ref_energy_dict, gas_gibbs=True): + """ + Calculates the formation energy of an entry relative to the VASP + energies of the reference atoms. Gibbs/entropy corrections for the gas + phase are optionable + + Args: + entry: Entry whose formation energy will be calculated + solid_ref_energy_dict: Dictionary of reference atom energies + gas_gibbs: Whether the gas phase reference atoms will have an + entropic correction + """ + if gas_gibbs==True: + ref_dict = {} + ref_dict['O'] = e_o-0.3167 + ref_dict['H'] = e_h-0.36218 + elif gas_gibbs==False: + ref_dict = {} + ref_dict['O'] = e_o + ref_dict['H'] = e_h + + z = ref_dict.copy() + z.update(solid_ref_energy_dict) + ref_dict = z + + elem_dict = entry.composition.get_el_amt_dict() + entry_e = entry.energy + + for elem in entry.composition.elements: + elem_num = elem_dict[elem.symbol] + entry_e = entry_e - elem_num*ref_dict[elem.symbol] + return entry_e + + pbx_solid_entries = [] + for entry in stable_solids_minus_h2o: + pbx_entry = PourbaixEntry(entry) + pbx_entry.g0_replace(form_energy(entry, d, gas_gibbs=gas_gibbs)) #Replace E with form E relative to ref elements + # pbx_entry.g0_replace(pd.get_form_energy(entry)) #Replace E with form E relative to ref elements + pbx_entry.reduced_entry() #Reduces parameters by stoich factor (ex. Li2O2 -> LiO) + pbx_solid_entries.append(pbx_entry) + + return pbx_solid_entries + #__| + +############################################################################### +# ██ ██████ ███ ██ ███████ +# ██ ██ ██ ████ ██ ██ +# ██ ██ ██ ██ ██ ██ ███████ +# ██ ██ ██ ██ ██ ██ ██ +# ██ ██████ ██ ████ ███████ +############################################################################### + +def ref_entry_find(stable_solids_minus_h2o, ref_state): + """ + Args: + stable_solids_minus_h2o: + ref_state: + """ + #| - ref_entry_find + + # print ref_state+'_______________' # TEMP + #Chk# Ion solid material reference state (defined by the dict 'Reference Solid' entry in ion_dict) + # is in the generated material list (if YES assign to ref_entry var), if NO generate error + for entry in stable_solids_minus_h2o: + # print entry.composition.reduced_formula+'#_#_' # TEMP + if entry.composition.reduced_formula==ref_state: ref_entry=entry; break + else: ref_entry=[] + #if not ref_entry: return '05 - Error with '+ref_state+' solid reference data for:'+mtnme + if not ref_entry: + print '05 - Error with '+ref_state+' solid reference data' + return '05 - Error with '+ref_state+' solid reference data' + + return ref_entry + #__| + +def ref_entry_stoich(ref_entry): + """ + """ + #| - ref_entry_stoich + ref_stoich_fact=ref_entry.composition.get_reduced_composition_and_factor()[1] + return ref_stoich_fact + #__| + +def mke_pour_ion_entr(mtnme, ion_dict, stable_solids_minus_h2o, ref_state, entries_aqcorr, ref_dict): + """ + """ + #| - mke_pour_ion_entr + from pymatgen import Element # Accesses properties of element + from pymatgen.core.ion import Ion + from pymatgen.phasediagram.maker import PhaseDiagram + from pymatgen.analysis.pourbaix.entry import PourbaixEntry, IonEntry + + from pd_make import ref_entry_find, ref_entry_stoich + pd = PhaseDiagram(entries_aqcorr) + + ref_entry = ref_entry_find(stable_solids_minus_h2o, ref_state) + ref_stoich_fact = ref_entry_stoich(ref_entry) + + ## Calculate DFT reference E for ions (Persson et al, PRB (2012)) + dft_for_e=pd.get_form_energy(ref_entry)/ref_stoich_fact # DFT formation E, normalized by composition "factor" + ion_correction_1 = dft_for_e-ref_dict[ref_state] # Difference of DFT form E and exp for E of reference + + el = Element(mtnme) + pbx_ion_entries_1 = [] + for id in ion_dict: + comp = Ion.from_formula(id['Name']) # Ion name-> Ion comp name (ex. Fe[3+] -> Ion: Fe1 +3) + # comp.composition[el] : number of Fe atoms in ion + num_el_ref = (ref_entry.composition[el]) / ref_stoich_fact # number of element atoms in reference + factor = comp.composition[el] / num_el_ref # Stoicheometric factor for ionic correction + # (i.e. Fe2O3 ref but calc E for Fe[2+] ion) + energy = id['Energy'] + ion_correction_1 * factor + + #TEMP_PRINT + if id['Name']=='Pd[2+]': + energy = 123 + # print id['Name'] + + pbx_entry_ion = PourbaixEntry(IonEntry(comp, energy)) + pbx_entry_ion.name = id['Name'] + pbx_ion_entries_1.append(pbx_entry_ion) + + return pbx_ion_entries_1 + #__| diff --git a/pourbaix_pymatgen/pd_screen_tools.py b/pourbaix_pymatgen/pd_screen_tools.py index 0dffacb..24d17a2 100644 --- a/pourbaix_pymatgen/pd_screen_tools.py +++ b/pourbaix_pymatgen/pd_screen_tools.py @@ -1,212 +1,212 @@ -def ORR_line(pH): - """ - """ - #| - - ORR_line - intercept = 1.23 - slope = -0.0591 - - V = slope*pH + intercept - return V - #__| - -def stable_mat_one_elem(pH,V,mat): - """ - Returns pymatgen pourbaix entry object corresponding to most stable species - - Args: - pH: pH of system - V: Potential with reference to the Standard Hydrogen Electrode (SHE) - """ - #| - - stable_mat_one_elem - from pourdiag_single import pourdiag_single as pd_sgle - from pymatgen.analysis.pourbaix.maker import PourbaixDiagram - # Access entry Gibbs(pH, V) - from pymatgen.analysis.pourbaix.analyzer import PourbaixAnalyzer - - - pH = 0 - V = 1 - mat = 'Pt' - - all_entries = pd_sgle(mat) - - pourbaix = PourbaixDiagram(all_entries) - PA=PourbaixAnalyzer(pourbaix) - - templist=[] - for i in all_entries: - templist.append(PA.g(i,pH,V)) - minE=min(templist) - - for i in all_entries: - if PA.g(i,pH,V)==minE: - StableSpec=i - return StableSpec # Returns the entries object of the stable species - - #__| - -def plot_reg(coord_data): - """ - Plots the region boundaries for the given region - - Args: - coord_data: Coordinate data of region of interest, must be in the form - of [[[x-points],[y-points]],[], ...] - """ - #| - - plot_reg - import numpy as np - import matplotlib.pyplot as plt - - fig, ax = plt.subplots() - for line in coord_data: - ax.plot(line[0],line[1]) - plt.show() - #__| - -def phase_coord(entries, atom_comp, prim_elem=False): - """ - Produces a list of line segments corresponding to each phase area in a PD - along with the PD entries corresponding to each area. - The produced list is of the following form: - list = [[[coordinate data], [pourbaix entry]], [], [] .... ] - - Args: - entries: List of entries in a PD - atom_comp: Composition of atom if system is binary, given as a fraction - between 0 and 1. Corresponds to the element with lowest atomic number if - prim_elem is left to its default - prim_elem: Primary element to which the atom_comp is assigned - """ - #| - - phase_coord - from pymatgen.analysis.pourbaix.maker import PourbaixDiagram - from pymatgen.analysis.pourbaix.plotter import PourbaixPlotter - from entry_methods import base_atom - - base_atoms = base_atom(entries) - mat0 = base_atoms[0] - if len(base_atoms)==2: mat1 = base_atoms[1] - else: mat1 = mat0 - - # If the primary element is declared then set the given composition to it - if not prim_elem==False: - for atom in base_atoms: - if atom==prim_elem: - mat0 = atom - else: mat1 = atom - - pd = PourbaixDiagram(entries,{mat0: atom_comp,mat1: 1-atom_comp}) - pl = PourbaixPlotter(pd) - ppd = pl.pourbaix_plot_data([[-2, 16],[-3, 3]]) #ppd == Pourbaix_Plot Data - pd_lst = [] - cnt = 0 - - for stable_entry in ppd[0]: - pd_lst.append([]) - pd_lst[cnt].append(ppd[0][stable_entry]) - pd_lst[cnt].append(stable_entry.entrylist) - cnt = cnt+1 - - return pd_lst - - #__| - -def phase_filter(phase_coord,phase_type): - """ - Returns a list of Pourbaix diagrams regions and corresponding species - that match the specified phase_type - - Args: - phase_coord: PD phase coordinate data produced from phase_coord - phase_type: Type of phase that will be filtered for. Samples include the following: - metallic, oxide, metallic_metallic, metallic_oxide, oxide_oxide, - metallic_aqueous oxide_aqueous, aqueous_aqueous - """ - - #| - - phase_filter - ## METALLIC: 1 METALLIC PHASE - # For a binary system this is necessarily an alloy - #TMP - - if phase_type == 'metallic': - met_phase_lst = [] - for region in phase_coord: - is_oxide_phase = False - if len(region[1]) == 1: - if region[1][0].phase_type == 'Solid': - for elem in region[1][0].composition.elements: - if elem.symbol == 'O': is_oxide_phase = True - if is_oxide_phase == False: - met_phase_lst.append(region) - return met_phase_lst - - ## METALLIC_METALLIC: 2 METALLIC SPECIES - # May be 2 single atomic species (ex. Ni(s) + Pt(s)) or two alloys (ex. NiPt2(s) + Ni2Pt(s)) - - if phase_type == 'metallic_metallic': - met_met_phase_lst = [] - - for region in phase_coord: - c1 = len(region[1]) == 2 - - if len(region[1]) == 2: - c2 = region[1][0].phase_type == 'Solid' - c3 = region[1][1].phase_type == 'Solid' - - if c2 and c3: - is_oxide_phase = False - - for elem in region[1][0].composition.elements: - if elem.symbol == 'O': is_oxide_phase = True - for elem in region[1][1].composition.elements: - if elem.symbol == 'O': is_oxide_phase = True - - if is_oxide_phase == False: - met_met_phase_lst.append(region) - return met_met_phase_lst - - #__| - -def is_solid_phase(mat1, mat2, mat1_co=0.5): - """ - Returns TRUE is there exists a all solid phase in the binary Pourbaix Diagram - This means that the phase doesn't have any aqueous species - - Args: - mat1: - mat2: - mat1_co: - """ - - #| - - is_solid_phase - from pourdiag import pourdiag # Returns Pourbaix entries for binary system - from pymatgen.analysis.pourbaix.maker import PourbaixDiagram - from pymatgen.analysis.pourbaix.plotter import PourbaixPlotter - - mat2_co = 1-mat1_co - - pd_b = pourdiag(mat1,mat2) - return pd_b - - pd = PourbaixDiagram(pd_b,{mat1: mat1_co,mat2: mat2_co}) - pl = PourbaixPlotter(pd) - ppd = pl.pourbaix_plot_data([[-2, 16],[-3, 3]]) #ppd == Pourbaix_Plot Data - - pd_lst = [] - cnt = 0 - for stable_entry in ppd[0]: - pd_lst.append([]) - pd_lst[cnt].append(ppd[0][stable_entry]) - pd_lst[cnt].append(stable_entry.entrylist) - cnt = cnt+1 - - solidphase=False - for i in pd_lst: - if len(i[1])==1: - if i[1][0].phase_type == 'Solid': - solidphase=True - if len(i[1])==2: - if i[1][0].phase_type and i[1][1].phase_type == 'Solid': - solidphase=True - return solidphase - - #__| +def ORR_line(pH): + """ + """ + #| - - ORR_line + intercept = 1.23 + slope = -0.0591 + + V = slope*pH + intercept + return V + #__| + +def stable_mat_one_elem(pH,V,mat): + """ + Returns pymatgen pourbaix entry object corresponding to most stable species + + Args: + pH: pH of system + V: Potential with reference to the Standard Hydrogen Electrode (SHE) + """ + #| - - stable_mat_one_elem + from pourdiag_single import pourdiag_single as pd_sgle + from pymatgen.analysis.pourbaix.maker import PourbaixDiagram + # Access entry Gibbs(pH, V) + from pymatgen.analysis.pourbaix.analyzer import PourbaixAnalyzer + + + pH = 0 + V = 1 + mat = 'Pt' + + all_entries = pd_sgle(mat) + + pourbaix = PourbaixDiagram(all_entries) + PA=PourbaixAnalyzer(pourbaix) + + templist=[] + for i in all_entries: + templist.append(PA.g(i,pH,V)) + minE=min(templist) + + for i in all_entries: + if PA.g(i,pH,V)==minE: + StableSpec=i + return StableSpec # Returns the entries object of the stable species + + #__| + +def plot_reg(coord_data): + """ + Plots the region boundaries for the given region + + Args: + coord_data: Coordinate data of region of interest, must be in the form + of [[[x-points],[y-points]],[], ...] + """ + #| - - plot_reg + import numpy as np + import matplotlib.pyplot as plt + + fig, ax = plt.subplots() + for line in coord_data: + ax.plot(line[0],line[1]) + plt.show() + #__| + +def phase_coord(entries, atom_comp, prim_elem=False): + """ + Produces a list of line segments corresponding to each phase area in a PD + along with the PD entries corresponding to each area. + The produced list is of the following form: + list = [[[coordinate data], [pourbaix entry]], [], [] .... ] + + Args: + entries: List of entries in a PD + atom_comp: Composition of atom if system is binary, given as a fraction + between 0 and 1. Corresponds to the element with lowest atomic number if + prim_elem is left to its default + prim_elem: Primary element to which the atom_comp is assigned + """ + #| - - phase_coord + from pymatgen.analysis.pourbaix.maker import PourbaixDiagram + from pymatgen.analysis.pourbaix.plotter import PourbaixPlotter + from entry_methods import base_atom + + base_atoms = base_atom(entries) + mat0 = base_atoms[0] + if len(base_atoms)==2: mat1 = base_atoms[1] + else: mat1 = mat0 + + # If the primary element is declared then set the given composition to it + if not prim_elem==False: + for atom in base_atoms: + if atom==prim_elem: + mat0 = atom + else: mat1 = atom + + pd = PourbaixDiagram(entries,{mat0: atom_comp,mat1: 1-atom_comp}) + pl = PourbaixPlotter(pd) + ppd = pl.pourbaix_plot_data([[-2, 16],[-3, 3]]) #ppd == Pourbaix_Plot Data + pd_lst = [] + cnt = 0 + + for stable_entry in ppd[0]: + pd_lst.append([]) + pd_lst[cnt].append(ppd[0][stable_entry]) + pd_lst[cnt].append(stable_entry.entrylist) + cnt = cnt+1 + + return pd_lst + + #__| + +def phase_filter(phase_coord,phase_type): + """ + Returns a list of Pourbaix diagrams regions and corresponding species + that match the specified phase_type + + Args: + phase_coord: PD phase coordinate data produced from phase_coord + phase_type: Type of phase that will be filtered for. Samples include the following: + metallic, oxide, metallic_metallic, metallic_oxide, oxide_oxide, + metallic_aqueous oxide_aqueous, aqueous_aqueous + """ + + #| - - phase_filter + ## METALLIC: 1 METALLIC PHASE + # For a binary system this is necessarily an alloy + #TMP + + if phase_type == 'metallic': + met_phase_lst = [] + for region in phase_coord: + is_oxide_phase = False + if len(region[1]) == 1: + if region[1][0].phase_type == 'Solid': + for elem in region[1][0].composition.elements: + if elem.symbol == 'O': is_oxide_phase = True + if is_oxide_phase == False: + met_phase_lst.append(region) + return met_phase_lst + + ## METALLIC_METALLIC: 2 METALLIC SPECIES + # May be 2 single atomic species (ex. Ni(s) + Pt(s)) or two alloys (ex. NiPt2(s) + Ni2Pt(s)) + + if phase_type == 'metallic_metallic': + met_met_phase_lst = [] + + for region in phase_coord: + c1 = len(region[1]) == 2 + + if len(region[1]) == 2: + c2 = region[1][0].phase_type == 'Solid' + c3 = region[1][1].phase_type == 'Solid' + + if c2 and c3: + is_oxide_phase = False + + for elem in region[1][0].composition.elements: + if elem.symbol == 'O': is_oxide_phase = True + for elem in region[1][1].composition.elements: + if elem.symbol == 'O': is_oxide_phase = True + + if is_oxide_phase == False: + met_met_phase_lst.append(region) + return met_met_phase_lst + + #__| + +def is_solid_phase(mat1, mat2, mat1_co=0.5): + """ + Returns TRUE is there exists a all solid phase in the binary Pourbaix Diagram + This means that the phase doesn't have any aqueous species + + Args: + mat1: + mat2: + mat1_co: + """ + + #| - - is_solid_phase + from pourdiag import pourdiag # Returns Pourbaix entries for binary system + from pymatgen.analysis.pourbaix.maker import PourbaixDiagram + from pymatgen.analysis.pourbaix.plotter import PourbaixPlotter + + mat2_co = 1-mat1_co + + pd_b = pourdiag(mat1,mat2) + return pd_b + + pd = PourbaixDiagram(pd_b,{mat1: mat1_co,mat2: mat2_co}) + pl = PourbaixPlotter(pd) + ppd = pl.pourbaix_plot_data([[-2, 16],[-3, 3]]) #ppd == Pourbaix_Plot Data + + pd_lst = [] + cnt = 0 + for stable_entry in ppd[0]: + pd_lst.append([]) + pd_lst[cnt].append(ppd[0][stable_entry]) + pd_lst[cnt].append(stable_entry.entrylist) + cnt = cnt+1 + + solidphase=False + for i in pd_lst: + if len(i[1])==1: + if i[1][0].phase_type == 'Solid': + solidphase=True + if len(i[1])==2: + if i[1][0].phase_type and i[1][1].phase_type == 'Solid': + solidphase=True + return solidphase + + #__| diff --git a/pourbaix_pymatgen/pourdiag.py b/pourbaix_pymatgen/pourdiag.py index b8ba579..e39001c 100644 --- a/pourbaix_pymatgen/pourdiag.py +++ b/pourbaix_pymatgen/pourdiag.py @@ -1,75 +1,75 @@ -# -*- coding: utf-8 -*- -from pd_make import entry_data, aq_correction, stable_entr, form_e, mke_pour_ion_entr - -def pd_entries(mtnme_1,mtnme_2): - """ - Creates the entry objects corresponding to a binary or single component - Pourbaix diagram - - Args: - mtnme_1: Name of element 1 - mtnme_2: Name of element 2 - """ - - ################################## INPUTS ####################### - mprester_key = 'ZJhfHmMTTwbW29Sr' # Input your materials project id - # Local directory containing entry data (solid and ion) - direct_0 = '/home/flores12/01_ORR-MatStabScreen/01_virenv-pymatgen/01_data/01-1_local_MP_entry/' - ################################################################# - entry_ion_data = entry_data(mtnme_1, mtnme_2, direct_0, mprester_key) - entries = entry_ion_data["entries"] - ion_dict_1 = entry_ion_data["ion_dict_1"] - if not mtnme_1==mtnme_2: - ion_dict_2 = entry_ion_data["ion_dict_2"] - print ion_dict_1 - ############################## 1 Element ######################## - if mtnme_1 == mtnme_2: - ref_state_1=str(ion_dict_1[0]['Reference Solid']) - ref_dict_1 = {ref_state_1: ion_dict_1[0]['Reference solid energy']} - entries_aqcorr = aq_correction(entries) - - # #TEMP - # for i in entries_aqcorr: - # i.correction=0 - - stable_solids_minus_h2o = stable_entr(entries_aqcorr) - - pbx_solid_entries = form_e(stable_solids_minus_h2o, - entries_aqcorr) - - pbx_ion_entries_1 = mke_pour_ion_entr(mtnme_1, - ion_dict_1, stable_solids_minus_h2o, ref_state_1, - entries_aqcorr, ref_dict_1) - - all_entries = pbx_solid_entries + pbx_ion_entries_1 - - return all_entries - -############################## 2 Elements ####################### - else: - ref_state_1=str(ion_dict_1[0]['Reference Solid']) - ref_state_2=str(ion_dict_2[0]['Reference Solid']) - ref_dict_1 = {ref_state_1: ion_dict_1[0]['Reference solid energy']} - ref_dict_2 = {ref_state_2: ion_dict_2[0]['Reference solid energy']} - entries_aqcorr = aq_correction(entries) - - # # TEMP - # for i in entries_aqcorr: - # i.correction=0 - - stable_solids_minus_h2o = stable_entr(entries_aqcorr) - - pbx_solid_entries = form_e(stable_solids_minus_h2o, - entries_aqcorr) - - pbx_ion_entries_1 = mke_pour_ion_entr(mtnme_1, - ion_dict_1, stable_solids_minus_h2o, ref_state_1, - entries_aqcorr, ref_dict_1) - - pbx_ion_entries_2 = mke_pour_ion_entr(mtnme_2, - ion_dict_2, stable_solids_minus_h2o, ref_state_2, - entries_aqcorr, ref_dict_2) - - all_entries = pbx_solid_entries + pbx_ion_entries_1 + pbx_ion_entries_2 - - return all_entries +# -*- coding: utf-8 -*- +from pd_make import entry_data, aq_correction, stable_entr, form_e, mke_pour_ion_entr + +def pd_entries(mtnme_1,mtnme_2): + """ + Creates the entry objects corresponding to a binary or single component + Pourbaix diagram + + Args: + mtnme_1: Name of element 1 + mtnme_2: Name of element 2 + """ + + ################################## INPUTS ####################### + mprester_key = 'ZJhfHmMTTwbW29Sr' # Input your materials project id + # Local directory containing entry data (solid and ion) + direct_0 = '/home/flores12/01_ORR-MatStabScreen/01_virenv-pymatgen/01_data/01-1_local_MP_entry/' + ################################################################# + entry_ion_data = entry_data(mtnme_1, mtnme_2, direct_0, mprester_key) + entries = entry_ion_data["entries"] + ion_dict_1 = entry_ion_data["ion_dict_1"] + if not mtnme_1==mtnme_2: + ion_dict_2 = entry_ion_data["ion_dict_2"] + print ion_dict_1 + ############################## 1 Element ######################## + if mtnme_1 == mtnme_2: + ref_state_1=str(ion_dict_1[0]['Reference Solid']) + ref_dict_1 = {ref_state_1: ion_dict_1[0]['Reference solid energy']} + entries_aqcorr = aq_correction(entries) + + # #TEMP + # for i in entries_aqcorr: + # i.correction=0 + + stable_solids_minus_h2o = stable_entr(entries_aqcorr) + + pbx_solid_entries = form_e(stable_solids_minus_h2o, + entries_aqcorr) + + pbx_ion_entries_1 = mke_pour_ion_entr(mtnme_1, + ion_dict_1, stable_solids_minus_h2o, ref_state_1, + entries_aqcorr, ref_dict_1) + + all_entries = pbx_solid_entries + pbx_ion_entries_1 + + return all_entries + +############################## 2 Elements ####################### + else: + ref_state_1=str(ion_dict_1[0]['Reference Solid']) + ref_state_2=str(ion_dict_2[0]['Reference Solid']) + ref_dict_1 = {ref_state_1: ion_dict_1[0]['Reference solid energy']} + ref_dict_2 = {ref_state_2: ion_dict_2[0]['Reference solid energy']} + entries_aqcorr = aq_correction(entries) + + # # TEMP + # for i in entries_aqcorr: + # i.correction=0 + + stable_solids_minus_h2o = stable_entr(entries_aqcorr) + + pbx_solid_entries = form_e(stable_solids_minus_h2o, + entries_aqcorr) + + pbx_ion_entries_1 = mke_pour_ion_entr(mtnme_1, + ion_dict_1, stable_solids_minus_h2o, ref_state_1, + entries_aqcorr, ref_dict_1) + + pbx_ion_entries_2 = mke_pour_ion_entr(mtnme_2, + ion_dict_2, stable_solids_minus_h2o, ref_state_2, + entries_aqcorr, ref_dict_2) + + all_entries = pbx_solid_entries + pbx_ion_entries_1 + pbx_ion_entries_2 + + return all_entries diff --git a/pourbaix_pymatgen/read_coord_data.py b/pourbaix_pymatgen/read_coord_data.py index f6d6996..974d1db 100644 --- a/pourbaix_pymatgen/read_coord_data.py +++ b/pourbaix_pymatgen/read_coord_data.py @@ -1,65 +1,65 @@ -def read_coord_data(elem_1,elem_2, mat1_co=0.5): - """ - - Args: - elem_1: - elem_2: - mat1_co: - """ - #| - - read_coord_data - from monty.json import MontyEncoder, MontyDecoder - import json - import os - import fnmatch - - # This script will rebuild the coord object from a locally saved file - coord = [] - - direct = '/home/flores12/01_ORR-MatStabScreen/01_virenv-pymatgen/02_loc_PD_data/02_local_PD_line_data/' -# direct = '/home/flores12/01_ORR-MatStabScreen/01_virenv-pymatgen/88_tmp/08_local_PD_data/02_local_PD_line_data/' -# direct = '/home/flores12/01_ORR-MatStabScreen/01_virenv-pymatgen/88_tmp/08_local_PD_data/01_making_local_data/' - - direct_elem = direct+elem_1+'_'+elem_2+'/' - - reg_lst = os.listdir(direct_elem) - reg_lst.sort(key=int) - - os.chdir(direct_elem) - reg_cnt = 0 - for reg in reg_lst: - coord.append([]) -# coord[reg_cnt].append([]) - coord[reg_cnt].append([]) - - ## Adding Pourbaix Object/Entry Data - os.chdir(reg) - os.chdir('pourb_entry') - - pourb_ent_open_0 = open('pourb_entry_0.txt','r') - pourb_ent_fle_0 = pourb_ent_open_0.read() - pourb_ent_data_0 = json.loads(pourb_ent_fle_0, cls=MontyDecoder) - - if len(os.listdir('.'))==2: - - pourb_ent_open_1 = open('pourb_entry_1.txt','r') - pourb_ent_fle_1 = pourb_ent_open_1.read() - pourb_ent_data_1 = json.loads(pourb_ent_fle_1, cls=MontyDecoder) - - coord[reg_cnt][0].append(pourb_ent_data_0) - coord[reg_cnt][0].append(pourb_ent_data_1) - else: - coord[reg_cnt][0].append(pourb_ent_data_0) - - ## Adding Pourbaix Line Data - os.chdir('..') - os.chdir('pourb_lines') - pourb_lne_open = open('pourb_lines.txt','r') - pourb_lne_data = json.load(pourb_lne_open) - - coord[reg_cnt].insert(0,pourb_lne_data) - os.chdir('../..') - - reg_cnt = reg_cnt+1 - - return coord - #__| +def read_coord_data(elem_1,elem_2, mat1_co=0.5): + """ + + Args: + elem_1: + elem_2: + mat1_co: + """ + #| - - read_coord_data + from monty.json import MontyEncoder, MontyDecoder + import json + import os + import fnmatch + + # This script will rebuild the coord object from a locally saved file + coord = [] + + direct = '/home/flores12/01_ORR-MatStabScreen/01_virenv-pymatgen/02_loc_PD_data/02_local_PD_line_data/' +# direct = '/home/flores12/01_ORR-MatStabScreen/01_virenv-pymatgen/88_tmp/08_local_PD_data/02_local_PD_line_data/' +# direct = '/home/flores12/01_ORR-MatStabScreen/01_virenv-pymatgen/88_tmp/08_local_PD_data/01_making_local_data/' + + direct_elem = direct+elem_1+'_'+elem_2+'/' + + reg_lst = os.listdir(direct_elem) + reg_lst.sort(key=int) + + os.chdir(direct_elem) + reg_cnt = 0 + for reg in reg_lst: + coord.append([]) +# coord[reg_cnt].append([]) + coord[reg_cnt].append([]) + + ## Adding Pourbaix Object/Entry Data + os.chdir(reg) + os.chdir('pourb_entry') + + pourb_ent_open_0 = open('pourb_entry_0.txt','r') + pourb_ent_fle_0 = pourb_ent_open_0.read() + pourb_ent_data_0 = json.loads(pourb_ent_fle_0, cls=MontyDecoder) + + if len(os.listdir('.'))==2: + + pourb_ent_open_1 = open('pourb_entry_1.txt','r') + pourb_ent_fle_1 = pourb_ent_open_1.read() + pourb_ent_data_1 = json.loads(pourb_ent_fle_1, cls=MontyDecoder) + + coord[reg_cnt][0].append(pourb_ent_data_0) + coord[reg_cnt][0].append(pourb_ent_data_1) + else: + coord[reg_cnt][0].append(pourb_ent_data_0) + + ## Adding Pourbaix Line Data + os.chdir('..') + os.chdir('pourb_lines') + pourb_lne_open = open('pourb_lines.txt','r') + pourb_lne_data = json.load(pourb_lne_open) + + coord[reg_cnt].insert(0,pourb_lne_data) + os.chdir('../..') + + reg_cnt = reg_cnt+1 + + return coord + #__| diff --git a/pourbaix_pymatgen/save_data.py b/pourbaix_pymatgen/save_data.py index 024bbc6..654acea 100644 --- a/pourbaix_pymatgen/save_data.py +++ b/pourbaix_pymatgen/save_data.py @@ -1,15 +1,15 @@ -def save_data(data,file_name): - """ - Saves data into a json format - Args: - data: data to be saved - file_name: Desired filename including extension (.json) - """ - #| - - save_data - import json - # Storing and Retrieving Matrix data - json_dumps = json.dumps(data) - f = open(file_name,'w') - f.write(json_dumps); f.close() - print 'Saving file: '+str(file_name) - #__| +def save_data(data,file_name): + """ + Saves data into a json format + Args: + data: data to be saved + file_name: Desired filename including extension (.json) + """ + #| - - save_data + import json + # Storing and Retrieving Matrix data + json_dumps = json.dumps(data) + f = open(file_name,'w') + f.write(json_dumps); f.close() + print 'Saving file: '+str(file_name) + #__| diff --git a/pourbaix_pymatgen/stability_crit.py b/pourbaix_pymatgen/stability_crit.py index be70621..415973d 100644 --- a/pourbaix_pymatgen/stability_crit.py +++ b/pourbaix_pymatgen/stability_crit.py @@ -1,282 +1,282 @@ -# This is a test to see if I can push code from sherlock to github 170926 -# -*- coding: utf-8 -*- - -def most_stable_phase(phase_regions,pH=None, scale='RHE', pt_oxid_V=0.6470339): - """ - Returns a list containing how close the closest phase is to the ORR - equilbrium line and the Pourbaix entry object(s) corrsponding to that phase - - Meant to be used with phase_filter to create the input to this method - - Args: - phase_regions: PD regions which will be analyzed - Pt_ref = True, difference between the Pt V_crit and system's V_crit - RHE = V_crit on an RHE scale - """ - #| - - most_stable_phase - - #| - - Imported Modules - from pd_screen_tools import ORR_line # ORR/OER V_equil, function of pH - #__| - - # print phase_regions[0] - - if pH==None: - #| - - pH==None - Considers Entire pH range - - point_dis_ORR_lst = [] # Smallest distance from ORR paired with - # Pourbaix entry object for each region - cnt = 0 - for region in phase_regions: - dist_ORR_reg_lst = [] # Distance from ORR for all sides of region - for line in region[0]: - dist_ORR_0 = ORR_line(line[0][0])-line[1][0] # Distance from ORR - # for 1st endpoint - dist_ORR_1 = ORR_line(line[0][1])-line[1][1] # Distance from ORR - # for 2nd endpoint - # Grabs closest point from line segment - dist_ORR_reg_lst.append(min(dist_ORR_0,dist_ORR_1)) - # Closest point on closest side to ORR line for phase region - min_dist_ORR = min(dist_ORR_reg_lst) - - point_dis_ORR_lst.append([]) - point_dis_ORR_lst[cnt].append(min_dist_ORR) # Closeness to ORR - point_dis_ORR_lst[cnt].append(region[1]) # Pourbaix entry object - - cnt = cnt+1 - most_stable_reg = min(point_dis_ORR_lst) # Closest point to ORR for - # inputed regions - #__| - - if pH!=None: - #| - - pH is Specified - - point_dis_ORR_lmost = [] - cnt = 0 - V_max_of_regions = [] - for region in phase_regions: - - entry_name_lst = [] - for i in region[1]: - entry_name_lst.append(i.name) - - V_lst = [] - for line in region[0]: - if round(line[0][0],4)==round(line[0][1],4): - # print 'Vertical line removed' - continue - - pH_range = sorted(line[0]) - if pHpH_range[1]: - # print 'pH not in range of line segment' - continue - - m = (line[1][0]-line[1][1])/(line[0][0]-line[0][1]) - b = line[1][0]-m*line[0][0] - # b2 = line[1][1]-m*line[0][1] - - V_at_ph = m*pH+b - V_lst.append(V_at_ph) - - if not V_lst == []: - V_max = max(V_lst) - V_and_entry = [V_max,region[1]] - V_max_of_regions.append(V_and_entry) - else: - pass - - V_max_total = max(V_max_of_regions) - - V_dist_from_ORR = ORR_line(pH) - V_max_total[0] - V_max_total[0] = V_dist_from_ORR - most_stable_reg = V_max_total - #__| - - - # start_fold - Other Voltage References - ## Distance from ORR line - if scale == 'ORR_dist': - most_stable_reg = most_stable_reg - - ## Pt reference: V_diss - V_Pt - elif scale == 'Pt_ref': - # Pt_diss_V = 0.6470339 - # Pt_diss_V = 0.83981341187500214 - pt_crit_V = pt_oxid_V - - most_stable_reg[0] = 1.23 - most_stable_reg[0] - pt_crit_V - ## Returns the maximum achievable V on an RHE scale - elif scale == 'RHE': - most_stable_reg[0] = 1.23 - most_stable_reg[0] - # end_fold - - return most_stable_reg - #__| - -def oxidation_dissolution_product(phase_regions_all, most_stable_phase): - - """ - Returns the Pourbaix Entry of the most likely dissolved or oxidized phase - given a starting stable phase - - Graphically, this is the phase which is above the stable phase (In terms of - voltage), near the pH region at which stable phasae has the highest V_crit - """ - #| - - oxidation_dissolution_product - from pymatgen.analysis.pourbaix.maker import PREFAC - import numpy as np - slope = -0.0591 - - phase_regions_all_copy = phase_regions_all[:] - - ## Obtaining the Region Coordinates of the most_stable_phase ## - for region in phase_regions_all_copy: - if region[1] == most_stable_phase[1]: - stable_region_coord_tmp = region - - stable_region_coord = stable_region_coord_tmp[0] - - ## Converting the coordinates to a RHE scale - for side in stable_region_coord: - side[1][0] = side[1][0] - slope*side[0][0] - side[1][1] = side[1][1] - slope*side[0][1] - - ## Finding the highest Voltage in the stable phase vs RHE - highest_V = -20 - for side in stable_region_coord: - if side[1][0] >= highest_V: - highest_V = side[1][0] - - if side[1][1] >= highest_V: - highest_V = side[1][1] - - ## Returns the coordinate of the most stable side/point - highest_V_points = [] - for side in stable_region_coord: - if round(side[1][0], 4) == round(highest_V, 4): - highest_V_points.append([side[0][0],side[1][0]]) - - if round(side[1][1], 4) == round(highest_V, 4): - highest_V_points.append([side[0][1],side[1][1]]) - - lst_0 = np.round(highest_V_points,6) - set_1 = set(map(tuple,lst_0)) - most_stable_points = map(list,set_1) - - - # print most_stable_points - - ### - for point in most_stable_points: - point[1] = point[1]-PREFAC*point[0] - ### - - ## Reversing the coordinates to a SHE scale - for side in stable_region_coord: - - side[1][0] = side[1][0] + slope*side[0][0] - side[1][1] = side[1][1] + slope*side[0][1] - - ## Returns the Other Regions Which Contain the Most Stable point - # Not Including the Original Stable Phase - neighbor_reg = [] - neighbor_reg_tmp = [] - - - def format_to_point_pairs(line_segment): - - point_0 = [line_segment[0][0],line_segment[1][0]] - point_1 = [line_segment[0][1],line_segment[1][1]] - - - return [point_0,point_1] - - def compare_points(point_0, point_1, rounding): - if round(point_0[0],rounding) == round(point_1[0],rounding) and round(point_0[1],rounding) == round(point_1[1],rounding): - return True - - - adj_reg_lst = [] - for point in most_stable_points: - - for region in phase_regions_all: - # print '######################' #TEMP_PRINT - - if region==stable_region_coord_tmp: - # print 'TEMP_PRINT' - continue - - for segment in region[0]: - - point_0 = format_to_point_pairs(segment)[0] - point_1 = format_to_point_pairs(segment)[1] - - if compare_points(point_0,point,3)==True or compare_points(point_1,point,4)==True: - adj_reg_lst.append(region) - - def make_unique(original_list): - unique_list = [] - [unique_list.append(obj) for obj in original_list if obj not in unique_list] - return unique_list - - def binary_region_entries(region): - # for i in adj_reg_lst: - if len(i[1])==1: - return [i[1][0]] - if len(i[1])==2: - return [i[1][0],i[1][1]] - - uniq_lst = make_unique(adj_reg_lst) - - for i in uniq_lst: - i.append(adj_reg_lst.count(i)) - tmp = max(uniq_lst, key=lambda x: x[2]) - - neighbor_reg_0 = binary_region_entries(tmp) - - name_lst = [] - for i in neighbor_reg_0: - name_lst.append(i.phase_type) - - # print name_lst - - return name_lst - - #__| - - -def is_nonox_phase(phase_regions): - """ - Checks if there exits a non-oxide solid phase - "Position-agnositic" stability criteria on a Pourbaix Diagram - - Args: - phase_regions: PD regions which will be analyzed - """ - #| - - is_nonox_phase - from pymatgen.analysis.pourbaix.entry import PourbaixEntry, IonEntry - - ## CHECKING FOR NON-OXIDE SOLID PHASES ## - non_oxide = False - for region in phase_regions: - if len(region[1]) == 1: # region has one entry - if not region[1][0].phase_type == 'Solid': break # Region solid? - # If no, pass - for elem in region[1][0].composition.elements: - if elem.symbol == 'O': break - - elif len(region[1]) == 2: # region has two entries - reg_phase_type_1 = region[1][0].phase_type - reg_phase_type_2 = region[1][1].phase_type - if not reg_phase_type_1 == 'Solid' and reg_phase_type_2 == 'Solid': - break - elem_lst = [] - elem_comb = region[1][0].composition.elements + \ - region[1][1].composition.elements - for elem in elem_comb: - elem_lst.append(elem.symbol) - if 'O' not in elem_lst: - non_oxide = True - break - return non_oxide - #__| +# This is a test to see if I can push code from sherlock to github 170926 +# -*- coding: utf-8 -*- + +def most_stable_phase(phase_regions,pH=None, scale='RHE', pt_oxid_V=0.6470339): + """ + Returns a list containing how close the closest phase is to the ORR + equilbrium line and the Pourbaix entry object(s) corrsponding to that phase + + Meant to be used with phase_filter to create the input to this method + + Args: + phase_regions: PD regions which will be analyzed + Pt_ref = True, difference between the Pt V_crit and system's V_crit + RHE = V_crit on an RHE scale + """ + #| - - most_stable_phase + + #| - - Imported Modules + from pd_screen_tools import ORR_line # ORR/OER V_equil, function of pH + #__| + + # print phase_regions[0] + + if pH==None: + #| - - pH==None - Considers Entire pH range + + point_dis_ORR_lst = [] # Smallest distance from ORR paired with + # Pourbaix entry object for each region + cnt = 0 + for region in phase_regions: + dist_ORR_reg_lst = [] # Distance from ORR for all sides of region + for line in region[0]: + dist_ORR_0 = ORR_line(line[0][0])-line[1][0] # Distance from ORR + # for 1st endpoint + dist_ORR_1 = ORR_line(line[0][1])-line[1][1] # Distance from ORR + # for 2nd endpoint + # Grabs closest point from line segment + dist_ORR_reg_lst.append(min(dist_ORR_0,dist_ORR_1)) + # Closest point on closest side to ORR line for phase region + min_dist_ORR = min(dist_ORR_reg_lst) + + point_dis_ORR_lst.append([]) + point_dis_ORR_lst[cnt].append(min_dist_ORR) # Closeness to ORR + point_dis_ORR_lst[cnt].append(region[1]) # Pourbaix entry object + + cnt = cnt+1 + most_stable_reg = min(point_dis_ORR_lst) # Closest point to ORR for + # inputed regions + #__| + + if pH!=None: + #| - - pH is Specified + + point_dis_ORR_lmost = [] + cnt = 0 + V_max_of_regions = [] + for region in phase_regions: + + entry_name_lst = [] + for i in region[1]: + entry_name_lst.append(i.name) + + V_lst = [] + for line in region[0]: + if round(line[0][0],4)==round(line[0][1],4): + # print 'Vertical line removed' + continue + + pH_range = sorted(line[0]) + if pHpH_range[1]: + # print 'pH not in range of line segment' + continue + + m = (line[1][0]-line[1][1])/(line[0][0]-line[0][1]) + b = line[1][0]-m*line[0][0] + # b2 = line[1][1]-m*line[0][1] + + V_at_ph = m*pH+b + V_lst.append(V_at_ph) + + if not V_lst == []: + V_max = max(V_lst) + V_and_entry = [V_max,region[1]] + V_max_of_regions.append(V_and_entry) + else: + pass + + V_max_total = max(V_max_of_regions) + + V_dist_from_ORR = ORR_line(pH) - V_max_total[0] + V_max_total[0] = V_dist_from_ORR + most_stable_reg = V_max_total + #__| + + + # start_fold - Other Voltage References + ## Distance from ORR line + if scale == 'ORR_dist': + most_stable_reg = most_stable_reg + + ## Pt reference: V_diss - V_Pt + elif scale == 'Pt_ref': + # Pt_diss_V = 0.6470339 + # Pt_diss_V = 0.83981341187500214 + pt_crit_V = pt_oxid_V + + most_stable_reg[0] = 1.23 - most_stable_reg[0] - pt_crit_V + ## Returns the maximum achievable V on an RHE scale + elif scale == 'RHE': + most_stable_reg[0] = 1.23 - most_stable_reg[0] + # end_fold + + return most_stable_reg + #__| + +def oxidation_dissolution_product(phase_regions_all, most_stable_phase): + + """ + Returns the Pourbaix Entry of the most likely dissolved or oxidized phase + given a starting stable phase + + Graphically, this is the phase which is above the stable phase (In terms of + voltage), near the pH region at which stable phasae has the highest V_crit + """ + #| - - oxidation_dissolution_product + from pymatgen.analysis.pourbaix.maker import PREFAC + import numpy as np + slope = -0.0591 + + phase_regions_all_copy = phase_regions_all[:] + + ## Obtaining the Region Coordinates of the most_stable_phase ## + for region in phase_regions_all_copy: + if region[1] == most_stable_phase[1]: + stable_region_coord_tmp = region + + stable_region_coord = stable_region_coord_tmp[0] + + ## Converting the coordinates to a RHE scale + for side in stable_region_coord: + side[1][0] = side[1][0] - slope*side[0][0] + side[1][1] = side[1][1] - slope*side[0][1] + + ## Finding the highest Voltage in the stable phase vs RHE + highest_V = -20 + for side in stable_region_coord: + if side[1][0] >= highest_V: + highest_V = side[1][0] + + if side[1][1] >= highest_V: + highest_V = side[1][1] + + ## Returns the coordinate of the most stable side/point + highest_V_points = [] + for side in stable_region_coord: + if round(side[1][0], 4) == round(highest_V, 4): + highest_V_points.append([side[0][0],side[1][0]]) + + if round(side[1][1], 4) == round(highest_V, 4): + highest_V_points.append([side[0][1],side[1][1]]) + + lst_0 = np.round(highest_V_points,6) + set_1 = set(map(tuple,lst_0)) + most_stable_points = map(list,set_1) + + + # print most_stable_points + + ### + for point in most_stable_points: + point[1] = point[1]-PREFAC*point[0] + ### + + ## Reversing the coordinates to a SHE scale + for side in stable_region_coord: + + side[1][0] = side[1][0] + slope*side[0][0] + side[1][1] = side[1][1] + slope*side[0][1] + + ## Returns the Other Regions Which Contain the Most Stable point + # Not Including the Original Stable Phase + neighbor_reg = [] + neighbor_reg_tmp = [] + + + def format_to_point_pairs(line_segment): + + point_0 = [line_segment[0][0],line_segment[1][0]] + point_1 = [line_segment[0][1],line_segment[1][1]] + + + return [point_0,point_1] + + def compare_points(point_0, point_1, rounding): + if round(point_0[0],rounding) == round(point_1[0],rounding) and round(point_0[1],rounding) == round(point_1[1],rounding): + return True + + + adj_reg_lst = [] + for point in most_stable_points: + + for region in phase_regions_all: + # print '######################' #TEMP_PRINT + + if region==stable_region_coord_tmp: + # print 'TEMP_PRINT' + continue + + for segment in region[0]: + + point_0 = format_to_point_pairs(segment)[0] + point_1 = format_to_point_pairs(segment)[1] + + if compare_points(point_0,point,3)==True or compare_points(point_1,point,4)==True: + adj_reg_lst.append(region) + + def make_unique(original_list): + unique_list = [] + [unique_list.append(obj) for obj in original_list if obj not in unique_list] + return unique_list + + def binary_region_entries(region): + # for i in adj_reg_lst: + if len(i[1])==1: + return [i[1][0]] + if len(i[1])==2: + return [i[1][0],i[1][1]] + + uniq_lst = make_unique(adj_reg_lst) + + for i in uniq_lst: + i.append(adj_reg_lst.count(i)) + tmp = max(uniq_lst, key=lambda x: x[2]) + + neighbor_reg_0 = binary_region_entries(tmp) + + name_lst = [] + for i in neighbor_reg_0: + name_lst.append(i.phase_type) + + # print name_lst + + return name_lst + + #__| + + +def is_nonox_phase(phase_regions): + """ + Checks if there exits a non-oxide solid phase + "Position-agnositic" stability criteria on a Pourbaix Diagram + + Args: + phase_regions: PD regions which will be analyzed + """ + #| - - is_nonox_phase + from pymatgen.analysis.pourbaix.entry import PourbaixEntry, IonEntry + + ## CHECKING FOR NON-OXIDE SOLID PHASES ## + non_oxide = False + for region in phase_regions: + if len(region[1]) == 1: # region has one entry + if not region[1][0].phase_type == 'Solid': break # Region solid? + # If no, pass + for elem in region[1][0].composition.elements: + if elem.symbol == 'O': break + + elif len(region[1]) == 2: # region has two entries + reg_phase_type_1 = region[1][0].phase_type + reg_phase_type_2 = region[1][1].phase_type + if not reg_phase_type_1 == 'Solid' and reg_phase_type_2 == 'Solid': + break + elem_lst = [] + elem_comb = region[1][0].composition.elements + \ + region[1][1].composition.elements + for elem in elem_comb: + elem_lst.append(elem.symbol) + if 'O' not in elem_lst: + non_oxide = True + break + return non_oxide + #__| diff --git a/prototype_ML_proj/lennard_jones_regress/lj_regression.py b/prototype_ML_proj/lennard_jones_regress/lj_regression.py index e8c427d..6fd82b2 100644 --- a/prototype_ML_proj/lennard_jones_regress/lj_regression.py +++ b/prototype_ML_proj/lennard_jones_regress/lj_regression.py @@ -1,672 +1,672 @@ -#!/usr/bin/env python - -"""Methods for the regression of Lennard Jones parameters to DFT energies. - -Author: Raul A. Flores -""" - -#| - Import Modules -import gc -import pickle - -import math - -import itertools - -import numpy as np -import pandas as pd -from scipy.optimize import minimize - -#My Modules -from energetics.formation_energy import calc_formation_energy -from classical_methods.lennard_jones import lennard_jones_sp - -from IPython.display import display, clear_output - -#| - __old__ -# import os -# import copy -# from scipy import stats -# from scipy.optimize import fmin -# import collections -# import plotly.plotly as py -# import plotly.graph_objs as go -# from ase.visualize import view -# from ase import io -# from asap3 import LennardJones -# import math -# from an_data_processing import load_df -# from ase_modules.ase_methods import create_species_element_dict -#__| - -#__| - -def calc_lennard_jones_form_e( - atoms_i=None, - - atoms_H2=None, - atoms_Ir=None, - atoms_O2=None, - - epsilon=None, - sigma=None, - - ): - """Calculate the Lennard Jones formation energy of atoms object. - - Args: - atoms_i: - atoms_H2: - atoms_Ir: - atoms_O2: - epsilon: - sigma: - """ - #| - calc_lennard_jones_form_e - E_H = lennard_jones_sp(epsilon, sigma, atoms_H2) - E_O = lennard_jones_sp(epsilon, sigma, atoms_O2) - E_Ir = lennard_jones_sp(epsilon, sigma, atoms_Ir) - - reference_states = [ - { - "elec_e": E_H, - "element_dict": {"H": 1}, - }, - - { - "elec_e": E_O, - "element_dict": {"O": 1}, - }, - - { - "elec_e": E_Ir, - "element_dict": {"Ir": 1}, - }, - - ] - - E_form_i = calc_formation_energy( - atoms_i, - - lennard_jones_sp( - epsilon, - sigma, - atoms_i, - normalize_per_atom=False, - # return_quantity=return_quantity, - ), - - reference_states, - normalize_per_atom=False, - ) - - E_form_per_atom_i = E_form_i / atoms_i.get_number_of_atoms() - - E_out = E_form_per_atom_i - - return(E_out) - #__| - -def calc_lennard_jones_all_atoms( - pars, - atoms_list, - reference_atoms, - return_quantity="energies" # 'energies' or 'forces' - ): - """Calculate the Lennard Jones formation energies of list of atoms. - - Now can also return list of force arrays for all structures. - - Args: - pars: - atoms_list: - reference_atoms: - return_quantity: - """ - #| - calc_lennard_jones_all_atoms - - epsilon = pars[0] - sigma = pars[1] - - atoms_H2 = reference_atoms[0] - atoms_O2 = reference_atoms[1] - atoms_Ir = reference_atoms[2] - - predicted_energies = [] - predicted_forces = [] - - - if return_quantity == "energies": - for atoms_i in atoms_list: - - #| - Energy - lj_energy_i = calc_lennard_jones_form_e( - atoms_i=atoms_i, - atoms_H2=atoms_H2, - atoms_Ir=atoms_Ir, - atoms_O2=atoms_O2, - epsilon=epsilon, - sigma=sigma, - ) - - predicted_energies.append(lj_energy_i) - #__| - - predicted_energies = np.array(predicted_energies) - return(predicted_energies) - - if return_quantity == "forces": - for atoms_i in atoms_list: - - #| - Forces - lj_forces_i = lennard_jones_sp( - epsilon, - sigma, - atoms_i, - modified_lj=True, - normalize_per_atom=True, - return_quantity="forces", # 'energy', 'forces', 'both', 'energy&forces' - ) - - predicted_forces.append(lj_forces_i) - #__| - - predicted_forces = np.array(predicted_forces) - - return(predicted_forces) - #__| - -def objective( - pars, - known_energies, - - known_forces, - - atoms_list, - eps_shape, - sig_shape, - elem_list, - reference_atoms, - info, - ): - """Objective function to be minimized for LJ parameter fitting. - - Args: - pars: - known_energies: - atoms_list: - eps_shape: - sig_shape: - reference_atoms: - """ - #| - objective - epsilon, sigma = unflatten_eps_sig_array( - pars, - eps_shape, - sig_shape, - elem_list, - ) - - #| - Energy Term - err = known_energies - \ - calc_lennard_jones_all_atoms( - (epsilon, sigma), - atoms_list, - reference_atoms, - ) - - denominator_i = math.sqrt(np.sum(known_energies ** 2)) - numerator_i = math.sqrt(np.sum(err ** 2)) - - energy_term = numerator_i / denominator_i - - MSE = np.mean(err ** 2) - #__| - - #| - Force Term - def calc_sum_of_normals_of_forces(forces): - """Calculate sum of normals of forces on each atom. - - Args: - forces: - List of 3 components of force for each atom - """ - #| - calc_sum_of_normals_of_forces - sum_of_normals = 0. - for atom_forces_i in forces: - sum_of_normals += np.linalg.norm(atom_forces_i) - - return(sum_of_normals) - #__| - - - sum_of_structures_forces_known = 0. - for atoms_i in known_forces: - sum_of_normals_i = calc_sum_of_normals_of_forces(atoms_i) - sum_of_structures_forces_known += sum_of_normals_i - - lj_forces = calc_lennard_jones_all_atoms( - (epsilon, sigma), - atoms_list, - reference_atoms, - return_quantity="forces", # 'energies' or 'forces' - ) - - sum_of_structures_forces = 0. - for atoms_i in lj_forces: - sum_of_normals_i = calc_sum_of_normals_of_forces(atoms_i) - sum_of_structures_forces += sum_of_normals_i - - - force_term = sum_of_structures_forces / sum_of_structures_forces_known - #__| - - #| - Score Function - w_energy = 1. - w_force = 0.0001 - - score_function = w_energy * energy_term + w_force * force_term - - print(score_function) - #__| - - #| - Display Real-time Info - clear_output(wait=True) - - display("Iter: " + str(info["Nfeval"])) - display("MSE: " + str(MSE)) - - display("Energy Term: " + str(energy_term)) - display("Force Term: " + str(force_term)) - - display("Energy Term (weighted): " + str(w_energy * energy_term)) - display("Force Term (weighted): " + str(w_force * force_term)) - - - display("Score Function: " + str(score_function)) - display("Epsilon Matrix: ") - display(epsilon) - display("Sigma Matrix: ") - display(sigma) - display("__________________________") - - display(epsilon.values) - display(sigma.values) - - info["Nfeval"] += 1 - #__| - - return(score_function) - - # return(MSE) - #__| - -def flatten_eps_sig_triangular_matrices( - epsilon, - sigma, - mode="traingular", # 'triangular' or 'diagonal' - ): - """Flatten triangular epsilon and sigma matrices into a 1D array. - - Args: - epsilon: - sigma: - """ - #| - flatten_eps_sig_triangular_matrices - epsilon = epsilon.values - sigma = sigma.values - - if mode == "triangular": - flat_eps_sig = np.hstack([ - epsilon.flatten(), - sigma.flatten(), - ]) - - # Remove 0s - flat_eps_sig_no_0s = flat_eps_sig[flat_eps_sig != 0.] - - return(flat_eps_sig_no_0s) - - elif mode == "diagonal": - flat_eps_sig_diag = np.hstack( - [ - epsilon.diagonal(), - sigma.diagonal(), - ] - ) - - return(flat_eps_sig_diag) - #__| - -def unflatten_eps_sig_array( - flat_eps_sig, - eps_shape, - sig_shape, - elem_list, - ): - """Unflatten a 1D array into 2 triangular epsilon and sigma matrices. - - Args: - flat_eps_sig: - eps_shape: - sig_shape: - """ - #| - unflatten_eps_sig_array - - #| - Array Dimension Check - assert eps_shape[0] == eps_shape[1] - assert sig_shape[0] == sig_shape[1] - - N_eps = eps_shape[0] - N_sig = sig_shape[0] - - assert N_eps == N_sig - - N = N_eps - #__| - - len_pars = len(flat_eps_sig) - half_way = int(len_pars / 2) - - epsilon_short = flat_eps_sig[:half_way] - sigma_short = flat_eps_sig[half_way:] - - if len(epsilon_short) == N and len(sigma_short) == N: - pars_mode = "diagonal" - else: - pars_mode = "triangular" - - #| - Methods - def unflatten_tri_matrix_with_defined_cross_terms( - flat_array, - N, - cross_terms_mode="geo" # "geo" or "ave" - ): - """Convert array into a diagonal matrix with defined lower cross-terms. - - The lower-half cross terms are calculated from the diagonal terms. - - Args: - flat_array: - N: - cross_terms_mode: - "geo" or "ave" - """ - #| - unflatten_tri_matrix_with_defined_cross_terms - matrix = np.diag(flat_array) - - # Return list of i, j indices corresponding to the off diagonal - # cross-terms in the lower section of a triangular matrix - all_comb_indices = list(itertools.product( - np.array(range(N)), - np.array(range(N)), - )) - - unique_ij_list = [] - for i_j_pair in all_comb_indices: - i_ind = i_j_pair[0] - j_ind = i_j_pair[1] - if i_ind == j_ind: - continue - unique_ij_list.append(set(i_j_pair)) - - unique_ij_list = list(set([frozenset(item) for item in unique_ij_list])) - unique_ij_list = [list(item) for item in unique_ij_list] - - for i in unique_ij_list: - i.sort(reverse=True) - - for ij_ind in unique_ij_list: - i_ind = ij_ind[0] - j_ind = ij_ind[1] - - i_term = matrix[i_ind][i_ind] - j_term = matrix[j_ind][j_ind] - - average_ij = (i_term + j_term) / 2. - geo_ave_ij = (i_term * j_term) ** (1. / 2.) - - if cross_terms_mode == "geo": - matrix[i_ind][j_ind] = geo_ave_ij - elif cross_terms_mode == "ave": - matrix[i_ind][j_ind] = average_ij - - return(matrix) - #__| - - def unflatten_single_triangular_matrix(flat_array, N): - """Unflatten a single triangular matrix. - - Args: - flat_array: - N: - """ - #| - unflatten_single_traingular_matrix - start_index_list = [] - stop_index_list = [] - j_cnt = 0 - for i in range(N): - start_index_list.append(j_cnt) - increment = (i + 1) - j_cnt += increment - stop_index_list.append(j_cnt) - - rebuilt_matrix = [] - for i_ind, (start_i, stop_i) in enumerate(zip( - start_index_list, - stop_index_list)): - - num_of_0_to_add = N - i_ind - 1 - - final_row = np.append( - flat_array[start_i:stop_i], - num_of_0_to_add * [0.], - ) - - rebuilt_matrix.append(final_row) - - rebuilt_matrix = np.array(rebuilt_matrix) - - return(rebuilt_matrix) - #__| - - #__| - - if pars_mode == "triangular": - epsilon = unflatten_single_triangular_matrix(epsilon_short, N) - sigma = unflatten_single_triangular_matrix(sigma_short, N) - - elif pars_mode == "diagonal": - - epsilon = unflatten_tri_matrix_with_defined_cross_terms( - epsilon_short, - N, - cross_terms_mode="geo", - ) - - sigma = unflatten_tri_matrix_with_defined_cross_terms( - sigma_short, - N, - cross_terms_mode="ave", - ) - - epsilon = pd.DataFrame( - epsilon, - index=elem_list, - columns=elem_list, - ) - - sigma = pd.DataFrame( - sigma, - index=elem_list, - columns=elem_list, - ) - - return(epsilon, sigma) - - #__| - -def fit_LJ_to_DFT( - objective=None, - known_energies=None, - known_forces=None, - atoms_list=None, - elem_list=None, - reference_atoms=None, - epsilon_0=None, - sigma_0=None, - tol=1e-4, - maxiter=50, - maxfun=20, - params_mode="triangular", # "triangular" or "diagonal" - ): - """Fit LJ parameters to DFT energies. - - Args: - objective: - known_energies: - atoms_list: - reference_atoms: - epsilon_0: - sigma_0: - tol: - maxiter: - maxfun: - """ - #| - fit_LJ_to_DFT - atoms_H2 = reference_atoms[0] - atoms_O2 = reference_atoms[1] - atoms_Ir = reference_atoms[2] - - epsilon = epsilon_0 - sigma = sigma_0 - - eps_shape = epsilon.shape - sig_shape = sigma.shape - - # if params_mode == "triangular": - pars = flatten_eps_sig_triangular_matrices( - epsilon, - sigma, - mode=params_mode, # 'triangular' or 'diagonal' - ) - - #| - Minimize Method - opt_out = minimize( - objective, - pars, - - args=( - known_energies, - known_forces, - atoms_list, - eps_shape, - sig_shape, - elem_list, - [ - atoms_H2, - atoms_O2, - atoms_Ir, - ], - - {'Nfeval': 0}, - ), - - # method=None, - method='L-BFGS-B', - - jac=None, - hess=None, - hessp=None, - - # I'm adding a bit to the lower bound to avoid 0. values - # bounds=[(0, None) for i in pars], - bounds=[(0.0001, None) for i in pars], - - constraints=(), - tol=tol, - callback=None, - options={ - "maxiter": maxiter, - "maxfun": maxfun, - - "disp": True, - }, - ) - #__| - - LJ_pars = opt_out.x - - epsilon_out, sigma_out = unflatten_eps_sig_array( - LJ_pars, - eps_shape, - sig_shape, - elem_list, - ) - - with open("opt_params.pickle", "wb") as fle: - pickle.dump((epsilon_out, sigma_out), fle) - - return(epsilon_out, sigma_out) - #__| - -def calc_MSE( - pars, - df_i, - DFT_energies_col, - ref_atoms_list, - ): - """Calculate the mean-squared-error of model on dataset. - - Args: - pars: - df_i: - DFT_energies_col: - ref_atoms_list: - """ - #| - calc_MSE - # df_i = df_orig.iloc[cv_folds_indices[0]["testing"]] - epsilon = pars[0] - sigma = pars[1] - - known_energies = np.array(df_i[DFT_energies_col].tolist()) - atoms_list = df_i["final_atoms"].tolist() - - new_energies_test = calc_lennard_jones_all_atoms( - (epsilon, sigma), - atoms_list, - ref_atoms_list, - # [atoms_H2, atoms_O2, atoms_Ir], - ) - - err = known_energies - new_energies_test - MSE = np.mean(err ** 2) - - return(MSE) - #__| - -def k_fold_cross_validation(data, k=5): - """k-fold cross-validation indices list. - - Args: - data: - k: - """ - #| - k_fold_cross_validation - folds = np.array_split(data, k) - - cv_data = [] - for i_cnt in range(k): - - training_data_i = [] - for j_cnt in np.delete(np.arange(k), i_cnt): - training_data_i = np.concatenate((training_data_i, folds[j_cnt])) - testing_data_i = folds[i_cnt] - - cv_data.append({ - "training": training_data_i, - "testing": testing_data_i, - }) - - return(cv_data) - #__| +#!/usr/bin/env python + +"""Methods for the regression of Lennard Jones parameters to DFT energies. + +Author: Raul A. Flores +""" + +#| - Import Modules +import gc +import pickle + +import math + +import itertools + +import numpy as np +import pandas as pd +from scipy.optimize import minimize + +#My Modules +from energetics.formation_energy import calc_formation_energy +from classical_methods.lennard_jones import lennard_jones_sp + +from IPython.display import display, clear_output + +#| - __old__ +# import os +# import copy +# from scipy import stats +# from scipy.optimize import fmin +# import collections +# import plotly.plotly as py +# import plotly.graph_objs as go +# from ase.visualize import view +# from ase import io +# from asap3 import LennardJones +# import math +# from an_data_processing import load_df +# from ase_modules.ase_methods import create_species_element_dict +#__| + +#__| + +def calc_lennard_jones_form_e( + atoms_i=None, + + atoms_H2=None, + atoms_Ir=None, + atoms_O2=None, + + epsilon=None, + sigma=None, + + ): + """Calculate the Lennard Jones formation energy of atoms object. + + Args: + atoms_i: + atoms_H2: + atoms_Ir: + atoms_O2: + epsilon: + sigma: + """ + #| - calc_lennard_jones_form_e + E_H = lennard_jones_sp(epsilon, sigma, atoms_H2) + E_O = lennard_jones_sp(epsilon, sigma, atoms_O2) + E_Ir = lennard_jones_sp(epsilon, sigma, atoms_Ir) + + reference_states = [ + { + "elec_e": E_H, + "element_dict": {"H": 1}, + }, + + { + "elec_e": E_O, + "element_dict": {"O": 1}, + }, + + { + "elec_e": E_Ir, + "element_dict": {"Ir": 1}, + }, + + ] + + E_form_i = calc_formation_energy( + atoms_i, + + lennard_jones_sp( + epsilon, + sigma, + atoms_i, + normalize_per_atom=False, + # return_quantity=return_quantity, + ), + + reference_states, + normalize_per_atom=False, + ) + + E_form_per_atom_i = E_form_i / atoms_i.get_number_of_atoms() + + E_out = E_form_per_atom_i + + return(E_out) + #__| + +def calc_lennard_jones_all_atoms( + pars, + atoms_list, + reference_atoms, + return_quantity="energies" # 'energies' or 'forces' + ): + """Calculate the Lennard Jones formation energies of list of atoms. + + Now can also return list of force arrays for all structures. + + Args: + pars: + atoms_list: + reference_atoms: + return_quantity: + """ + #| - calc_lennard_jones_all_atoms + + epsilon = pars[0] + sigma = pars[1] + + atoms_H2 = reference_atoms[0] + atoms_O2 = reference_atoms[1] + atoms_Ir = reference_atoms[2] + + predicted_energies = [] + predicted_forces = [] + + + if return_quantity == "energies": + for atoms_i in atoms_list: + + #| - Energy + lj_energy_i = calc_lennard_jones_form_e( + atoms_i=atoms_i, + atoms_H2=atoms_H2, + atoms_Ir=atoms_Ir, + atoms_O2=atoms_O2, + epsilon=epsilon, + sigma=sigma, + ) + + predicted_energies.append(lj_energy_i) + #__| + + predicted_energies = np.array(predicted_energies) + return(predicted_energies) + + if return_quantity == "forces": + for atoms_i in atoms_list: + + #| - Forces + lj_forces_i = lennard_jones_sp( + epsilon, + sigma, + atoms_i, + modified_lj=True, + normalize_per_atom=True, + return_quantity="forces", # 'energy', 'forces', 'both', 'energy&forces' + ) + + predicted_forces.append(lj_forces_i) + #__| + + predicted_forces = np.array(predicted_forces) + + return(predicted_forces) + #__| + +def objective( + pars, + known_energies, + + known_forces, + + atoms_list, + eps_shape, + sig_shape, + elem_list, + reference_atoms, + info, + ): + """Objective function to be minimized for LJ parameter fitting. + + Args: + pars: + known_energies: + atoms_list: + eps_shape: + sig_shape: + reference_atoms: + """ + #| - objective + epsilon, sigma = unflatten_eps_sig_array( + pars, + eps_shape, + sig_shape, + elem_list, + ) + + #| - Energy Term + err = known_energies - \ + calc_lennard_jones_all_atoms( + (epsilon, sigma), + atoms_list, + reference_atoms, + ) + + denominator_i = math.sqrt(np.sum(known_energies ** 2)) + numerator_i = math.sqrt(np.sum(err ** 2)) + + energy_term = numerator_i / denominator_i + + MSE = np.mean(err ** 2) + #__| + + #| - Force Term + def calc_sum_of_normals_of_forces(forces): + """Calculate sum of normals of forces on each atom. + + Args: + forces: + List of 3 components of force for each atom + """ + #| - calc_sum_of_normals_of_forces + sum_of_normals = 0. + for atom_forces_i in forces: + sum_of_normals += np.linalg.norm(atom_forces_i) + + return(sum_of_normals) + #__| + + + sum_of_structures_forces_known = 0. + for atoms_i in known_forces: + sum_of_normals_i = calc_sum_of_normals_of_forces(atoms_i) + sum_of_structures_forces_known += sum_of_normals_i + + lj_forces = calc_lennard_jones_all_atoms( + (epsilon, sigma), + atoms_list, + reference_atoms, + return_quantity="forces", # 'energies' or 'forces' + ) + + sum_of_structures_forces = 0. + for atoms_i in lj_forces: + sum_of_normals_i = calc_sum_of_normals_of_forces(atoms_i) + sum_of_structures_forces += sum_of_normals_i + + + force_term = sum_of_structures_forces / sum_of_structures_forces_known + #__| + + #| - Score Function + w_energy = 1. + w_force = 0.0001 + + score_function = w_energy * energy_term + w_force * force_term + + print(score_function) + #__| + + #| - Display Real-time Info + clear_output(wait=True) + + display("Iter: " + str(info["Nfeval"])) + display("MSE: " + str(MSE)) + + display("Energy Term: " + str(energy_term)) + display("Force Term: " + str(force_term)) + + display("Energy Term (weighted): " + str(w_energy * energy_term)) + display("Force Term (weighted): " + str(w_force * force_term)) + + + display("Score Function: " + str(score_function)) + display("Epsilon Matrix: ") + display(epsilon) + display("Sigma Matrix: ") + display(sigma) + display("__________________________") + + display(epsilon.values) + display(sigma.values) + + info["Nfeval"] += 1 + #__| + + return(score_function) + + # return(MSE) + #__| + +def flatten_eps_sig_triangular_matrices( + epsilon, + sigma, + mode="traingular", # 'triangular' or 'diagonal' + ): + """Flatten triangular epsilon and sigma matrices into a 1D array. + + Args: + epsilon: + sigma: + """ + #| - flatten_eps_sig_triangular_matrices + epsilon = epsilon.values + sigma = sigma.values + + if mode == "triangular": + flat_eps_sig = np.hstack([ + epsilon.flatten(), + sigma.flatten(), + ]) + + # Remove 0s + flat_eps_sig_no_0s = flat_eps_sig[flat_eps_sig != 0.] + + return(flat_eps_sig_no_0s) + + elif mode == "diagonal": + flat_eps_sig_diag = np.hstack( + [ + epsilon.diagonal(), + sigma.diagonal(), + ] + ) + + return(flat_eps_sig_diag) + #__| + +def unflatten_eps_sig_array( + flat_eps_sig, + eps_shape, + sig_shape, + elem_list, + ): + """Unflatten a 1D array into 2 triangular epsilon and sigma matrices. + + Args: + flat_eps_sig: + eps_shape: + sig_shape: + """ + #| - unflatten_eps_sig_array + + #| - Array Dimension Check + assert eps_shape[0] == eps_shape[1] + assert sig_shape[0] == sig_shape[1] + + N_eps = eps_shape[0] + N_sig = sig_shape[0] + + assert N_eps == N_sig + + N = N_eps + #__| + + len_pars = len(flat_eps_sig) + half_way = int(len_pars / 2) + + epsilon_short = flat_eps_sig[:half_way] + sigma_short = flat_eps_sig[half_way:] + + if len(epsilon_short) == N and len(sigma_short) == N: + pars_mode = "diagonal" + else: + pars_mode = "triangular" + + #| - Methods + def unflatten_tri_matrix_with_defined_cross_terms( + flat_array, + N, + cross_terms_mode="geo" # "geo" or "ave" + ): + """Convert array into a diagonal matrix with defined lower cross-terms. + + The lower-half cross terms are calculated from the diagonal terms. + + Args: + flat_array: + N: + cross_terms_mode: + "geo" or "ave" + """ + #| - unflatten_tri_matrix_with_defined_cross_terms + matrix = np.diag(flat_array) + + # Return list of i, j indices corresponding to the off diagonal + # cross-terms in the lower section of a triangular matrix + all_comb_indices = list(itertools.product( + np.array(range(N)), + np.array(range(N)), + )) + + unique_ij_list = [] + for i_j_pair in all_comb_indices: + i_ind = i_j_pair[0] + j_ind = i_j_pair[1] + if i_ind == j_ind: + continue + unique_ij_list.append(set(i_j_pair)) + + unique_ij_list = list(set([frozenset(item) for item in unique_ij_list])) + unique_ij_list = [list(item) for item in unique_ij_list] + + for i in unique_ij_list: + i.sort(reverse=True) + + for ij_ind in unique_ij_list: + i_ind = ij_ind[0] + j_ind = ij_ind[1] + + i_term = matrix[i_ind][i_ind] + j_term = matrix[j_ind][j_ind] + + average_ij = (i_term + j_term) / 2. + geo_ave_ij = (i_term * j_term) ** (1. / 2.) + + if cross_terms_mode == "geo": + matrix[i_ind][j_ind] = geo_ave_ij + elif cross_terms_mode == "ave": + matrix[i_ind][j_ind] = average_ij + + return(matrix) + #__| + + def unflatten_single_triangular_matrix(flat_array, N): + """Unflatten a single triangular matrix. + + Args: + flat_array: + N: + """ + #| - unflatten_single_traingular_matrix + start_index_list = [] + stop_index_list = [] + j_cnt = 0 + for i in range(N): + start_index_list.append(j_cnt) + increment = (i + 1) + j_cnt += increment + stop_index_list.append(j_cnt) + + rebuilt_matrix = [] + for i_ind, (start_i, stop_i) in enumerate(zip( + start_index_list, + stop_index_list)): + + num_of_0_to_add = N - i_ind - 1 + + final_row = np.append( + flat_array[start_i:stop_i], + num_of_0_to_add * [0.], + ) + + rebuilt_matrix.append(final_row) + + rebuilt_matrix = np.array(rebuilt_matrix) + + return(rebuilt_matrix) + #__| + + #__| + + if pars_mode == "triangular": + epsilon = unflatten_single_triangular_matrix(epsilon_short, N) + sigma = unflatten_single_triangular_matrix(sigma_short, N) + + elif pars_mode == "diagonal": + + epsilon = unflatten_tri_matrix_with_defined_cross_terms( + epsilon_short, + N, + cross_terms_mode="geo", + ) + + sigma = unflatten_tri_matrix_with_defined_cross_terms( + sigma_short, + N, + cross_terms_mode="ave", + ) + + epsilon = pd.DataFrame( + epsilon, + index=elem_list, + columns=elem_list, + ) + + sigma = pd.DataFrame( + sigma, + index=elem_list, + columns=elem_list, + ) + + return(epsilon, sigma) + + #__| + +def fit_LJ_to_DFT( + objective=None, + known_energies=None, + known_forces=None, + atoms_list=None, + elem_list=None, + reference_atoms=None, + epsilon_0=None, + sigma_0=None, + tol=1e-4, + maxiter=50, + maxfun=20, + params_mode="triangular", # "triangular" or "diagonal" + ): + """Fit LJ parameters to DFT energies. + + Args: + objective: + known_energies: + atoms_list: + reference_atoms: + epsilon_0: + sigma_0: + tol: + maxiter: + maxfun: + """ + #| - fit_LJ_to_DFT + atoms_H2 = reference_atoms[0] + atoms_O2 = reference_atoms[1] + atoms_Ir = reference_atoms[2] + + epsilon = epsilon_0 + sigma = sigma_0 + + eps_shape = epsilon.shape + sig_shape = sigma.shape + + # if params_mode == "triangular": + pars = flatten_eps_sig_triangular_matrices( + epsilon, + sigma, + mode=params_mode, # 'triangular' or 'diagonal' + ) + + #| - Minimize Method + opt_out = minimize( + objective, + pars, + + args=( + known_energies, + known_forces, + atoms_list, + eps_shape, + sig_shape, + elem_list, + [ + atoms_H2, + atoms_O2, + atoms_Ir, + ], + + {'Nfeval': 0}, + ), + + # method=None, + method='L-BFGS-B', + + jac=None, + hess=None, + hessp=None, + + # I'm adding a bit to the lower bound to avoid 0. values + # bounds=[(0, None) for i in pars], + bounds=[(0.0001, None) for i in pars], + + constraints=(), + tol=tol, + callback=None, + options={ + "maxiter": maxiter, + "maxfun": maxfun, + + "disp": True, + }, + ) + #__| + + LJ_pars = opt_out.x + + epsilon_out, sigma_out = unflatten_eps_sig_array( + LJ_pars, + eps_shape, + sig_shape, + elem_list, + ) + + with open("opt_params.pickle", "wb") as fle: + pickle.dump((epsilon_out, sigma_out), fle) + + return(epsilon_out, sigma_out) + #__| + +def calc_MSE( + pars, + df_i, + DFT_energies_col, + ref_atoms_list, + ): + """Calculate the mean-squared-error of model on dataset. + + Args: + pars: + df_i: + DFT_energies_col: + ref_atoms_list: + """ + #| - calc_MSE + # df_i = df_orig.iloc[cv_folds_indices[0]["testing"]] + epsilon = pars[0] + sigma = pars[1] + + known_energies = np.array(df_i[DFT_energies_col].tolist()) + atoms_list = df_i["final_atoms"].tolist() + + new_energies_test = calc_lennard_jones_all_atoms( + (epsilon, sigma), + atoms_list, + ref_atoms_list, + # [atoms_H2, atoms_O2, atoms_Ir], + ) + + err = known_energies - new_energies_test + MSE = np.mean(err ** 2) + + return(MSE) + #__| + +def k_fold_cross_validation(data, k=5): + """k-fold cross-validation indices list. + + Args: + data: + k: + """ + #| - k_fold_cross_validation + folds = np.array_split(data, k) + + cv_data = [] + for i_cnt in range(k): + + training_data_i = [] + for j_cnt in np.delete(np.arange(k), i_cnt): + training_data_i = np.concatenate((training_data_i, folds[j_cnt])) + testing_data_i = folds[i_cnt] + + cv_data.append({ + "training": training_data_i, + "testing": testing_data_i, + }) + + return(cv_data) + #__| diff --git a/prototype_ML_proj/lennard_jones_regress/old.lj_regression_180724.py b/prototype_ML_proj/lennard_jones_regress/old.lj_regression_180724.py index 5b110ce..34babd0 100644 --- a/prototype_ML_proj/lennard_jones_regress/old.lj_regression_180724.py +++ b/prototype_ML_proj/lennard_jones_regress/old.lj_regression_180724.py @@ -1,653 +1,653 @@ -#!/usr/bin/env python - -"""Methods for the regression of Lennard Jones parameters to DFT energies. - -Author: Raul A. Flores -""" - -#| - Import Modules -import gc -import pickle - -import itertools - -import numpy as np -import pandas as pd -from scipy.optimize import minimize - -#My Modules -from energetics.formation_energy import calc_formation_energy -from classical_methods.lennard_jones import lennard_jones_sp - -from IPython.display import display, clear_output - -#| - __old__ -# import os -# import copy -# from scipy import stats -# from scipy.optimize import fmin -# import collections -# import plotly.plotly as py -# import plotly.graph_objs as go -# from ase.visualize import view -# from ase import io -# from asap3 import LennardJones -# import math -# from an_data_processing import load_df -# from ase_modules.ase_methods import create_species_element_dict -#__| - -#__| - -def calc_lennard_jones_form_e( - atoms_i=None, - - atoms_H2=None, - atoms_Ir=None, - atoms_O2=None, - - epsilon=None, - sigma=None, - - ): - """Calculate the Lennard Jones formation energy of atoms object. - - Args: - atoms_i: - atoms_H2: - atoms_Ir: - atoms_O2: - epsilon: - sigma: - """ - #| - calc_lennard_jones_form_e - E_H = lennard_jones_sp(epsilon, sigma, atoms_H2) - E_O = lennard_jones_sp(epsilon, sigma, atoms_O2) - E_Ir = lennard_jones_sp(epsilon, sigma, atoms_Ir) - - reference_states = [ - { - "elec_e": E_H, - "element_dict": {"H": 1}, - }, - - { - "elec_e": E_O, - "element_dict": {"O": 1}, - }, - - { - "elec_e": E_Ir, - "element_dict": {"Ir": 1}, - }, - - ] - - E_form_i = calc_formation_energy( - atoms_i, - - lennard_jones_sp( - epsilon, - sigma, - atoms_i, - normalize_per_atom=False, - # return_quantity=return_quantity, - ), - - reference_states, - normalize_per_atom=False, - ) - - E_form_per_atom_i = E_form_i / atoms_i.get_number_of_atoms() - - E_out = E_form_per_atom_i - - return(E_out) - #__| - -def calc_lennard_jones_all_atoms( - pars, - atoms_list, - reference_atoms, - return_quantity="energies" # 'energies' or 'forces' - ): - """Calculate the Lennard Jones formation energies of list of atoms. - - Now can also return list of force arrays for all structures. - - Args: - pars: - atoms_list: - reference_atoms: - return_quantity: - """ - #| - calc_lennard_jones_all_atoms - - epsilon = pars[0] - sigma = pars[1] - - atoms_H2 = reference_atoms[0] - atoms_O2 = reference_atoms[1] - atoms_Ir = reference_atoms[2] - - predicted_energies = [] - predicted_forces = [] - - - if return_quantity == "energies": - for atoms_i in atoms_list: - - #| - Energy - lj_energy_i = calc_lennard_jones_form_e( - atoms_i=atoms_i, - atoms_H2=atoms_H2, - atoms_Ir=atoms_Ir, - atoms_O2=atoms_O2, - epsilon=epsilon, - sigma=sigma, - ) - - predicted_energies.append(lj_energy_i) - #__| - - predicted_energies = np.array(predicted_energies) - return(predicted_energies) - - if return_quantity == "forces": - for atoms_i in atoms_list: - - #| - Forces - lj_forces_i = lennard_jones_sp( - epsilon, - sigma, - atoms_i, - modified_lj=True, - normalize_per_atom=True, - return_quantity="forces", # 'energy', 'forces', 'both', 'energy&forces' - ) - - predicted_forces.append(lj_forces_i) - #__| - - predicted_forces = np.array(predicted_energies) - - return(predicted_forces) - - # predicted_energies = np.array(predicted_energies) - # return(predicted_energies) - #__| - -def objective( - pars, - known_energies, - - known_forces, - - atoms_list, - eps_shape, - sig_shape, - elem_list, - reference_atoms, - info, - ): - """Objective function to be minimized for LJ parameter fitting. - - Args: - pars: - known_energies: - atoms_list: - eps_shape: - sig_shape: - reference_atoms: - """ - #| - objective - epsilon, sigma = unflatten_eps_sig_array( - pars, - eps_shape, - sig_shape, - elem_list, - ) - - #| - Energy Term - err = known_energies - \ - calc_lennard_jones_all_atoms( - (epsilon, sigma), - atoms_list, - reference_atoms, - ) - - MSE = np.mean(err ** 2) - #__| - - #| - Force Term - def calc_sum_of_normals_of_forces(forces): - """Calculate sum of normals of forces on each atom. - - Args: - forces: - List of 3 components of force for each atom - """ - #| - calc_sum_of_normals_of_forces - sum_of_normals = 0. - for atom_forces_i in forces: - sum_of_normals += np.linalg.norm(atom_forces_i) - - return(sum_of_normals) - #__| - - known_sum_of_normals = calc_sum_of_normals_of_forces(known_forces) - - lj_forces = calc_lennard_jones_all_atoms( - (epsilon, sigma), - atoms_list, - reference_atoms, - return_quantity="forces", # 'energies' or 'forces' - ) - - sum_of_structures_forces = 0. - for atom_i in lj_forces: - sum_of_normals_i = calc_sum_of_normals_of_forces(atom_i) - sum_of_structures_forces += sum_of_normals_i - - - print(sum_of_structures_forces / known_sum_of_normals) - - # print(tmp) - - print(30 * "&") - #__| - - - # clear_output(wait=True) - # - # - # display(tmp) - # display(20 * "*") - # - # - # - # display("Iter: " + str(info["Nfeval"])) - # display("MSE: " + str(MSE)) - # display("Epsilon Matrix: ") - # display(epsilon) - # display("Sigma Matrix: ") - # display(sigma) - # display("__________________________") - # - # display(epsilon.values) - # display(sigma.values) - - info["Nfeval"] += 1 - - return(MSE) - #__| - -def flatten_eps_sig_triangular_matrices( - epsilon, - sigma, - mode="traingular", # 'triangular' or 'diagonal' - ): - """Flatten triangular epsilon and sigma matrices into a 1D array. - - Args: - epsilon: - sigma: - """ - #| - flatten_eps_sig_triangular_matrices - epsilon = epsilon.values - sigma = sigma.values - - if mode == "triangular": - flat_eps_sig = np.hstack([ - epsilon.flatten(), - sigma.flatten(), - ]) - - # Remove 0s - flat_eps_sig_no_0s = flat_eps_sig[flat_eps_sig != 0.] - - return(flat_eps_sig_no_0s) - - elif mode == "diagonal": - flat_eps_sig_diag = np.hstack( - [ - epsilon.diagonal(), - sigma.diagonal(), - ] - ) - - return(flat_eps_sig_diag) - #__| - -def unflatten_eps_sig_array( - flat_eps_sig, - eps_shape, - sig_shape, - elem_list, - ): - """Unflatten a 1D array into 2 triangular epsilon and sigma matrices. - - Args: - flat_eps_sig: - eps_shape: - sig_shape: - """ - #| - unflatten_eps_sig_array - - #| - Array Dimension Check - assert eps_shape[0] == eps_shape[1] - assert sig_shape[0] == sig_shape[1] - - N_eps = eps_shape[0] - N_sig = sig_shape[0] - - assert N_eps == N_sig - - N = N_eps - #__| - - len_pars = len(flat_eps_sig) - half_way = int(len_pars / 2) - - epsilon_short = flat_eps_sig[:half_way] - sigma_short = flat_eps_sig[half_way:] - - if len(epsilon_short) == N and len(sigma_short) == N: - pars_mode = "diagonal" - else: - pars_mode = "triangular" - - #| - Methods - def unflatten_tri_matrix_with_defined_cross_terms( - flat_array, - N, - cross_terms_mode="geo" # "geo" or "ave" - ): - """Convert array into a diagonal matrix with defined lower cross-terms. - - The lower-half cross terms are calculated from the diagonal terms. - - Args: - flat_array: - N: - cross_terms_mode: - "geo" or "ave" - """ - #| - unflatten_tri_matrix_with_defined_cross_terms - matrix = np.diag(flat_array) - - # Return list of i, j indices corresponding to the off diagonal - # cross-terms in the lower section of a triangular matrix - all_comb_indices = list(itertools.product( - np.array(range(N)), - np.array(range(N)), - )) - - unique_ij_list = [] - for i_j_pair in all_comb_indices: - i_ind = i_j_pair[0] - j_ind = i_j_pair[1] - if i_ind == j_ind: - continue - unique_ij_list.append(set(i_j_pair)) - - unique_ij_list = list(set([frozenset(item) for item in unique_ij_list])) - unique_ij_list = [list(item) for item in unique_ij_list] - - for i in unique_ij_list: - i.sort(reverse=True) - - for ij_ind in unique_ij_list: - i_ind = ij_ind[0] - j_ind = ij_ind[1] - - i_term = matrix[i_ind][i_ind] - j_term = matrix[j_ind][j_ind] - - average_ij = (i_term + j_term) / 2. - geo_ave_ij = (i_term * j_term) ** (1. / 2.) - - if cross_terms_mode == "geo": - matrix[i_ind][j_ind] = geo_ave_ij - elif cross_terms_mode == "ave": - matrix[i_ind][j_ind] = average_ij - - return(matrix) - #__| - - def unflatten_single_triangular_matrix(flat_array, N): - """Unflatten a single triangular matrix. - - Args: - flat_array: - N: - """ - #| - unflatten_single_traingular_matrix - start_index_list = [] - stop_index_list = [] - j_cnt = 0 - for i in range(N): - start_index_list.append(j_cnt) - increment = (i + 1) - j_cnt += increment - stop_index_list.append(j_cnt) - - rebuilt_matrix = [] - for i_ind, (start_i, stop_i) in enumerate(zip( - start_index_list, - stop_index_list)): - - num_of_0_to_add = N - i_ind - 1 - - final_row = np.append( - flat_array[start_i:stop_i], - num_of_0_to_add * [0.], - ) - - rebuilt_matrix.append(final_row) - - rebuilt_matrix = np.array(rebuilt_matrix) - - return(rebuilt_matrix) - #__| - - #__| - - if pars_mode == "triangular": - epsilon = unflatten_single_triangular_matrix(epsilon_short, N) - sigma = unflatten_single_triangular_matrix(sigma_short, N) - - elif pars_mode == "diagonal": - - epsilon = unflatten_tri_matrix_with_defined_cross_terms( - epsilon_short, - N, - cross_terms_mode="ave", - ) - - sigma = unflatten_tri_matrix_with_defined_cross_terms( - sigma_short, - N, - cross_terms_mode="geo", - ) - - epsilon = pd.DataFrame( - epsilon, - index=elem_list, - columns=elem_list, - ) - - sigma = pd.DataFrame( - sigma, - index=elem_list, - columns=elem_list, - ) - - return(epsilon, sigma) - - #__| - -def fit_LJ_to_DFT( - objective=None, - known_energies=None, - known_forces=None, - atoms_list=None, - elem_list=None, - reference_atoms=None, - epsilon_0=None, - sigma_0=None, - tol=1e-4, - maxiter=50, - maxfun=20, - params_mode="triangular", # "triangular" or "diagonal" - ): - """Fit LJ parameters to DFT energies. - - Args: - objective: - known_energies: - atoms_list: - reference_atoms: - epsilon_0: - sigma_0: - tol: - maxiter: - maxfun: - """ - #| - fit_LJ_to_DFT - atoms_H2 = reference_atoms[0] - atoms_O2 = reference_atoms[1] - atoms_Ir = reference_atoms[2] - - epsilon = epsilon_0 - sigma = sigma_0 - - eps_shape = epsilon.shape - sig_shape = sigma.shape - - # if params_mode == "triangular": - pars = flatten_eps_sig_triangular_matrices( - epsilon, - sigma, - mode=params_mode, # 'triangular' or 'diagonal' - ) - - #| - Minimize Method - opt_out = minimize( - objective, - pars, - - args=( - known_energies, - known_forces, - atoms_list, - eps_shape, - sig_shape, - elem_list, - [ - atoms_H2, - atoms_O2, - atoms_Ir, - ], - - {'Nfeval': 0}, - ), - - # method=None, - method='L-BFGS-B', - - jac=None, - hess=None, - hessp=None, - - # I'm adding a bit to the lower bound to avoid 0. values - # bounds=[(0, None) for i in pars], - bounds=[(0.0001, None) for i in pars], - - constraints=(), - tol=tol, - callback=None, - options={ - "maxiter": maxiter, - "maxfun": maxfun, - - "disp": True, - }, - ) - #__| - - LJ_pars = opt_out.x - - epsilon_out, sigma_out = unflatten_eps_sig_array( - LJ_pars, - eps_shape, - sig_shape, - elem_list, - ) - - with open("opt_params.pickle", "wb") as fle: - pickle.dump((epsilon_out, sigma_out), fle) - - return(epsilon_out, sigma_out) - #__| - -def calc_MSE( - pars, - df_i, - DFT_energies_col, - ref_atoms_list, - ): - """Calculate the mean-squared-error of model on dataset. - - Args: - pars: - df_i: - DFT_energies_col: - ref_atoms_list: - """ - #| - calc_MSE - # df_i = df_orig.iloc[cv_folds_indices[0]["testing"]] - epsilon = pars[0] - sigma = pars[1] - - known_energies = np.array(df_i[DFT_energies_col].tolist()) - atoms_list = df_i["final_atoms"].tolist() - - new_energies_test = calc_lennard_jones_all_atoms( - (epsilon, sigma), - atoms_list, - ref_atoms_list, - # [atoms_H2, atoms_O2, atoms_Ir], - ) - - err = known_energies - new_energies_test - MSE = np.mean(err ** 2) - - return(MSE) - #__| - -def k_fold_cross_validation(data, k=5): - """k-fold cross-validation indices list. - - Args: - data: - k: - """ - #| - k_fold_cross_validation - folds = np.array_split(data, k) - - cv_data = [] - for i_cnt in range(k): - - training_data_i = [] - for j_cnt in np.delete(np.arange(k), i_cnt): - training_data_i = np.concatenate((training_data_i, folds[j_cnt])) - testing_data_i = folds[i_cnt] - - cv_data.append({ - "training": training_data_i, - "testing": testing_data_i, - }) - - return(cv_data) - #__| +#!/usr/bin/env python + +"""Methods for the regression of Lennard Jones parameters to DFT energies. + +Author: Raul A. Flores +""" + +#| - Import Modules +import gc +import pickle + +import itertools + +import numpy as np +import pandas as pd +from scipy.optimize import minimize + +#My Modules +from energetics.formation_energy import calc_formation_energy +from classical_methods.lennard_jones import lennard_jones_sp + +from IPython.display import display, clear_output + +#| - __old__ +# import os +# import copy +# from scipy import stats +# from scipy.optimize import fmin +# import collections +# import plotly.plotly as py +# import plotly.graph_objs as go +# from ase.visualize import view +# from ase import io +# from asap3 import LennardJones +# import math +# from an_data_processing import load_df +# from ase_modules.ase_methods import create_species_element_dict +#__| + +#__| + +def calc_lennard_jones_form_e( + atoms_i=None, + + atoms_H2=None, + atoms_Ir=None, + atoms_O2=None, + + epsilon=None, + sigma=None, + + ): + """Calculate the Lennard Jones formation energy of atoms object. + + Args: + atoms_i: + atoms_H2: + atoms_Ir: + atoms_O2: + epsilon: + sigma: + """ + #| - calc_lennard_jones_form_e + E_H = lennard_jones_sp(epsilon, sigma, atoms_H2) + E_O = lennard_jones_sp(epsilon, sigma, atoms_O2) + E_Ir = lennard_jones_sp(epsilon, sigma, atoms_Ir) + + reference_states = [ + { + "elec_e": E_H, + "element_dict": {"H": 1}, + }, + + { + "elec_e": E_O, + "element_dict": {"O": 1}, + }, + + { + "elec_e": E_Ir, + "element_dict": {"Ir": 1}, + }, + + ] + + E_form_i = calc_formation_energy( + atoms_i, + + lennard_jones_sp( + epsilon, + sigma, + atoms_i, + normalize_per_atom=False, + # return_quantity=return_quantity, + ), + + reference_states, + normalize_per_atom=False, + ) + + E_form_per_atom_i = E_form_i / atoms_i.get_number_of_atoms() + + E_out = E_form_per_atom_i + + return(E_out) + #__| + +def calc_lennard_jones_all_atoms( + pars, + atoms_list, + reference_atoms, + return_quantity="energies" # 'energies' or 'forces' + ): + """Calculate the Lennard Jones formation energies of list of atoms. + + Now can also return list of force arrays for all structures. + + Args: + pars: + atoms_list: + reference_atoms: + return_quantity: + """ + #| - calc_lennard_jones_all_atoms + + epsilon = pars[0] + sigma = pars[1] + + atoms_H2 = reference_atoms[0] + atoms_O2 = reference_atoms[1] + atoms_Ir = reference_atoms[2] + + predicted_energies = [] + predicted_forces = [] + + + if return_quantity == "energies": + for atoms_i in atoms_list: + + #| - Energy + lj_energy_i = calc_lennard_jones_form_e( + atoms_i=atoms_i, + atoms_H2=atoms_H2, + atoms_Ir=atoms_Ir, + atoms_O2=atoms_O2, + epsilon=epsilon, + sigma=sigma, + ) + + predicted_energies.append(lj_energy_i) + #__| + + predicted_energies = np.array(predicted_energies) + return(predicted_energies) + + if return_quantity == "forces": + for atoms_i in atoms_list: + + #| - Forces + lj_forces_i = lennard_jones_sp( + epsilon, + sigma, + atoms_i, + modified_lj=True, + normalize_per_atom=True, + return_quantity="forces", # 'energy', 'forces', 'both', 'energy&forces' + ) + + predicted_forces.append(lj_forces_i) + #__| + + predicted_forces = np.array(predicted_energies) + + return(predicted_forces) + + # predicted_energies = np.array(predicted_energies) + # return(predicted_energies) + #__| + +def objective( + pars, + known_energies, + + known_forces, + + atoms_list, + eps_shape, + sig_shape, + elem_list, + reference_atoms, + info, + ): + """Objective function to be minimized for LJ parameter fitting. + + Args: + pars: + known_energies: + atoms_list: + eps_shape: + sig_shape: + reference_atoms: + """ + #| - objective + epsilon, sigma = unflatten_eps_sig_array( + pars, + eps_shape, + sig_shape, + elem_list, + ) + + #| - Energy Term + err = known_energies - \ + calc_lennard_jones_all_atoms( + (epsilon, sigma), + atoms_list, + reference_atoms, + ) + + MSE = np.mean(err ** 2) + #__| + + #| - Force Term + def calc_sum_of_normals_of_forces(forces): + """Calculate sum of normals of forces on each atom. + + Args: + forces: + List of 3 components of force for each atom + """ + #| - calc_sum_of_normals_of_forces + sum_of_normals = 0. + for atom_forces_i in forces: + sum_of_normals += np.linalg.norm(atom_forces_i) + + return(sum_of_normals) + #__| + + known_sum_of_normals = calc_sum_of_normals_of_forces(known_forces) + + lj_forces = calc_lennard_jones_all_atoms( + (epsilon, sigma), + atoms_list, + reference_atoms, + return_quantity="forces", # 'energies' or 'forces' + ) + + sum_of_structures_forces = 0. + for atom_i in lj_forces: + sum_of_normals_i = calc_sum_of_normals_of_forces(atom_i) + sum_of_structures_forces += sum_of_normals_i + + + print(sum_of_structures_forces / known_sum_of_normals) + + # print(tmp) + + print(30 * "&") + #__| + + + # clear_output(wait=True) + # + # + # display(tmp) + # display(20 * "*") + # + # + # + # display("Iter: " + str(info["Nfeval"])) + # display("MSE: " + str(MSE)) + # display("Epsilon Matrix: ") + # display(epsilon) + # display("Sigma Matrix: ") + # display(sigma) + # display("__________________________") + # + # display(epsilon.values) + # display(sigma.values) + + info["Nfeval"] += 1 + + return(MSE) + #__| + +def flatten_eps_sig_triangular_matrices( + epsilon, + sigma, + mode="traingular", # 'triangular' or 'diagonal' + ): + """Flatten triangular epsilon and sigma matrices into a 1D array. + + Args: + epsilon: + sigma: + """ + #| - flatten_eps_sig_triangular_matrices + epsilon = epsilon.values + sigma = sigma.values + + if mode == "triangular": + flat_eps_sig = np.hstack([ + epsilon.flatten(), + sigma.flatten(), + ]) + + # Remove 0s + flat_eps_sig_no_0s = flat_eps_sig[flat_eps_sig != 0.] + + return(flat_eps_sig_no_0s) + + elif mode == "diagonal": + flat_eps_sig_diag = np.hstack( + [ + epsilon.diagonal(), + sigma.diagonal(), + ] + ) + + return(flat_eps_sig_diag) + #__| + +def unflatten_eps_sig_array( + flat_eps_sig, + eps_shape, + sig_shape, + elem_list, + ): + """Unflatten a 1D array into 2 triangular epsilon and sigma matrices. + + Args: + flat_eps_sig: + eps_shape: + sig_shape: + """ + #| - unflatten_eps_sig_array + + #| - Array Dimension Check + assert eps_shape[0] == eps_shape[1] + assert sig_shape[0] == sig_shape[1] + + N_eps = eps_shape[0] + N_sig = sig_shape[0] + + assert N_eps == N_sig + + N = N_eps + #__| + + len_pars = len(flat_eps_sig) + half_way = int(len_pars / 2) + + epsilon_short = flat_eps_sig[:half_way] + sigma_short = flat_eps_sig[half_way:] + + if len(epsilon_short) == N and len(sigma_short) == N: + pars_mode = "diagonal" + else: + pars_mode = "triangular" + + #| - Methods + def unflatten_tri_matrix_with_defined_cross_terms( + flat_array, + N, + cross_terms_mode="geo" # "geo" or "ave" + ): + """Convert array into a diagonal matrix with defined lower cross-terms. + + The lower-half cross terms are calculated from the diagonal terms. + + Args: + flat_array: + N: + cross_terms_mode: + "geo" or "ave" + """ + #| - unflatten_tri_matrix_with_defined_cross_terms + matrix = np.diag(flat_array) + + # Return list of i, j indices corresponding to the off diagonal + # cross-terms in the lower section of a triangular matrix + all_comb_indices = list(itertools.product( + np.array(range(N)), + np.array(range(N)), + )) + + unique_ij_list = [] + for i_j_pair in all_comb_indices: + i_ind = i_j_pair[0] + j_ind = i_j_pair[1] + if i_ind == j_ind: + continue + unique_ij_list.append(set(i_j_pair)) + + unique_ij_list = list(set([frozenset(item) for item in unique_ij_list])) + unique_ij_list = [list(item) for item in unique_ij_list] + + for i in unique_ij_list: + i.sort(reverse=True) + + for ij_ind in unique_ij_list: + i_ind = ij_ind[0] + j_ind = ij_ind[1] + + i_term = matrix[i_ind][i_ind] + j_term = matrix[j_ind][j_ind] + + average_ij = (i_term + j_term) / 2. + geo_ave_ij = (i_term * j_term) ** (1. / 2.) + + if cross_terms_mode == "geo": + matrix[i_ind][j_ind] = geo_ave_ij + elif cross_terms_mode == "ave": + matrix[i_ind][j_ind] = average_ij + + return(matrix) + #__| + + def unflatten_single_triangular_matrix(flat_array, N): + """Unflatten a single triangular matrix. + + Args: + flat_array: + N: + """ + #| - unflatten_single_traingular_matrix + start_index_list = [] + stop_index_list = [] + j_cnt = 0 + for i in range(N): + start_index_list.append(j_cnt) + increment = (i + 1) + j_cnt += increment + stop_index_list.append(j_cnt) + + rebuilt_matrix = [] + for i_ind, (start_i, stop_i) in enumerate(zip( + start_index_list, + stop_index_list)): + + num_of_0_to_add = N - i_ind - 1 + + final_row = np.append( + flat_array[start_i:stop_i], + num_of_0_to_add * [0.], + ) + + rebuilt_matrix.append(final_row) + + rebuilt_matrix = np.array(rebuilt_matrix) + + return(rebuilt_matrix) + #__| + + #__| + + if pars_mode == "triangular": + epsilon = unflatten_single_triangular_matrix(epsilon_short, N) + sigma = unflatten_single_triangular_matrix(sigma_short, N) + + elif pars_mode == "diagonal": + + epsilon = unflatten_tri_matrix_with_defined_cross_terms( + epsilon_short, + N, + cross_terms_mode="ave", + ) + + sigma = unflatten_tri_matrix_with_defined_cross_terms( + sigma_short, + N, + cross_terms_mode="geo", + ) + + epsilon = pd.DataFrame( + epsilon, + index=elem_list, + columns=elem_list, + ) + + sigma = pd.DataFrame( + sigma, + index=elem_list, + columns=elem_list, + ) + + return(epsilon, sigma) + + #__| + +def fit_LJ_to_DFT( + objective=None, + known_energies=None, + known_forces=None, + atoms_list=None, + elem_list=None, + reference_atoms=None, + epsilon_0=None, + sigma_0=None, + tol=1e-4, + maxiter=50, + maxfun=20, + params_mode="triangular", # "triangular" or "diagonal" + ): + """Fit LJ parameters to DFT energies. + + Args: + objective: + known_energies: + atoms_list: + reference_atoms: + epsilon_0: + sigma_0: + tol: + maxiter: + maxfun: + """ + #| - fit_LJ_to_DFT + atoms_H2 = reference_atoms[0] + atoms_O2 = reference_atoms[1] + atoms_Ir = reference_atoms[2] + + epsilon = epsilon_0 + sigma = sigma_0 + + eps_shape = epsilon.shape + sig_shape = sigma.shape + + # if params_mode == "triangular": + pars = flatten_eps_sig_triangular_matrices( + epsilon, + sigma, + mode=params_mode, # 'triangular' or 'diagonal' + ) + + #| - Minimize Method + opt_out = minimize( + objective, + pars, + + args=( + known_energies, + known_forces, + atoms_list, + eps_shape, + sig_shape, + elem_list, + [ + atoms_H2, + atoms_O2, + atoms_Ir, + ], + + {'Nfeval': 0}, + ), + + # method=None, + method='L-BFGS-B', + + jac=None, + hess=None, + hessp=None, + + # I'm adding a bit to the lower bound to avoid 0. values + # bounds=[(0, None) for i in pars], + bounds=[(0.0001, None) for i in pars], + + constraints=(), + tol=tol, + callback=None, + options={ + "maxiter": maxiter, + "maxfun": maxfun, + + "disp": True, + }, + ) + #__| + + LJ_pars = opt_out.x + + epsilon_out, sigma_out = unflatten_eps_sig_array( + LJ_pars, + eps_shape, + sig_shape, + elem_list, + ) + + with open("opt_params.pickle", "wb") as fle: + pickle.dump((epsilon_out, sigma_out), fle) + + return(epsilon_out, sigma_out) + #__| + +def calc_MSE( + pars, + df_i, + DFT_energies_col, + ref_atoms_list, + ): + """Calculate the mean-squared-error of model on dataset. + + Args: + pars: + df_i: + DFT_energies_col: + ref_atoms_list: + """ + #| - calc_MSE + # df_i = df_orig.iloc[cv_folds_indices[0]["testing"]] + epsilon = pars[0] + sigma = pars[1] + + known_energies = np.array(df_i[DFT_energies_col].tolist()) + atoms_list = df_i["final_atoms"].tolist() + + new_energies_test = calc_lennard_jones_all_atoms( + (epsilon, sigma), + atoms_list, + ref_atoms_list, + # [atoms_H2, atoms_O2, atoms_Ir], + ) + + err = known_energies - new_energies_test + MSE = np.mean(err ** 2) + + return(MSE) + #__| + +def k_fold_cross_validation(data, k=5): + """k-fold cross-validation indices list. + + Args: + data: + k: + """ + #| - k_fold_cross_validation + folds = np.array_split(data, k) + + cv_data = [] + for i_cnt in range(k): + + training_data_i = [] + for j_cnt in np.delete(np.arange(k), i_cnt): + training_data_i = np.concatenate((training_data_i, folds[j_cnt])) + testing_data_i = folds[i_cnt] + + cv_data.append({ + "training": training_data_i, + "testing": testing_data_i, + }) + + return(cv_data) + #__| diff --git a/quantum_espresso/qe_methods.py b/quantum_espresso/qe_methods.py index eae525c..b09bfcf 100644 --- a/quantum_espresso/qe_methods.py +++ b/quantum_espresso/qe_methods.py @@ -1,379 +1,379 @@ -#!/usr/bin/env python - -"""Quantum Espresso methods and code. - -Author: Raul A. Flores -""" - -#| - Import Modules -import os -import pandas as pd - -import numpy as np -#__| - -#| - Log File Methods - -def number_of_atoms(path_i=".", log="log"): - """Return number of atoms from QE log file. - - Args: - path_i: - log: - """ - #| - number_of_atoms - file_name = path_i + "/" + log - with open(file_name, "r") as fle: - fle.seek(0) # just in case - - while True: - line = fle.readline() - - if "Cartesian axes" in line: - fle.readline().strip() # Blank line - fle.readline() # Column headers - - atom_list = [] - while True: - data_line_i = fle.readline().strip() - - if data_line_i == "": - break - - atom_list.append(data_line_i) - - if not line: - break - - num_atoms = len(atom_list) - - return(num_atoms) - #__| - -def tot_abs_magnetization(path_i=".", log="log"): - """Return total and absolute magnetization vs SCF iteration. - - Abs: - path_i - log - """ - #| - tot_abs_magnetization - fle = open(log, "r") - fle.seek(0) # just in case - - tot_mag_list = [] - abs_mag_list = [] - while True: - line = fle.readline() - - # Break out of loop - if not line: - break - - #| - Searching for Atomic Magmoms - if "total magnetization" in line: - line_list = line.strip().split(" ") - line = [i for i in line_list if i != ""] - tot_mag = float(line[3]) - tot_mag_list.append(tot_mag) - - if "absolute magnetization" in line: - line_list = line.strip().split(" ") - line = [i for i in line_list if i != ""] - abs_mag = float(line[3]) - abs_mag_list.append(abs_mag) - - #__| - - df_tot = pd.DataFrame(tot_mag_list, columns=["tot_mag"]) - df_abs = pd.DataFrame(abs_mag_list, columns=["abs_mag"]) - - df = pd.concat([df_tot, df_abs], axis=1) - - return(df) - #__| - -def element_index_dict(path_i=".", log="log"): - """Return index: element dictionary. - - Format: {0: 'Fe', 1: 'Fe', 2: 'Fe'} - - Args: - path_i - log - """ - #| - element_index_dict - elem_ind_dict = {} - file_name = path_i + "/" + log - with open(file_name, "r") as fle: - - fle.seek(0) # just in case - while True: - line = fle.readline() - - # Break out of loop - if not line: - break - - #| - Atom Index <---> Atom Type - if "Cartesian axes" in line: - fle.readline() # Blank line - fle.readline() # Column header line - - # elem_ind_dict = {} - while True: - line_i = fle.readline() - if "tau(" in line_i: - - line_list = line_i.strip().split(" ") - line_list = [i_ct for i_ct in line_list if i_ct != ""] - - ind_i = int(line_list[0]) - 1 # "0" indexed - - elem_i = line_list[1] - elem_i = ''.join([i for i in elem_i if not i.isdigit()]) - - elem_ind_dict[ind_i] = elem_i - - else: - break - - #__| - - return(elem_ind_dict) - #__| - -def magmom_charge_data(path_i=".", log="log"): - """Return charge and magmom data per atom for all SCF iterations. - - Args: - path_i - log - """ - #| - magmom_charge_data - - #| - Reading Log File - file_name = path_i + "/" + log - - fle = open(file_name, "r") - fle.seek(0) # just in case - - master_list = [] - while True: - line = fle.readline() - - # Break out of loop - if not line: - break - - #| - Searching for Atomic Magmoms - if "Magnetic moment per site" in line: - - list_i = [] - while True: - # print("ksjfksjfks - 3") - line_i = fle.readline() - if "atom:" in line_i: - - line_list = line_i.strip().split(" ") - line_list = [i_cnt for i_cnt in line_list if i_cnt != ""] - - atom_num = int(line_list[1]) - 1 # "0" indexed - charge = float(line_list[3]) - magmom = float(line_list[5]) - - entry_dict = { - "atom_num": atom_num, - "charge": charge, - "magmom": magmom, - } - - list_i.append(entry_dict) - else: - break - - master_list.append(list_i) - #__| - - #__| - - #| - Creating Pandas DataFrame - if master_list == []: - print("Magmom/charge data not found, ", - "calculation probably not spin-polarized" - ) - return(None) - - elem_ind_dict = element_index_dict(path_i=path_i, log=log) - - df_list = [] - for i_cnt, iter_i in enumerate(master_list): - df_i = pd.DataFrame(iter_i) - - df_list.append(df_i) - df_i["iteration"] = i_cnt - - # Combining data frames - df = pd.concat(df_list) - - # Creating element type column (mapping index <--> element) - df["element"] = df["atom_num"].map(elem_ind_dict) - - # Resetting index - df.reset_index() - #__| - - return(df) - #__| - -def estimate_magmom( - path_i=".", - atoms=None, - log="log", - ): - """Estimage magnetic moments from QE log file. - - TODO Also read charges data for last iteration - TODO Modify to not need atoms object to function - - Author: Colin Dickens - - Estimate magmom from log file (based on charge spheres centered on atoms) - and assign to atoms object to assist with calculation restart upon - unexpected interruption. - """ - #| - estimate_magmom - num_atoms = number_of_atoms(path_i=path_i, log=log) - # print(num_atoms) - - file_name = path_i + "/" + log - - with open(file_name, "r") as fle: - lines = fle.readlines() - - i = len(lines) - 1 - while True: - - #| - If magmom/charge data is not found in log file - # The calculation is probably not spin-polarized - if i == 0: - print("estimate_magmom - Could not find magmom/charge data \n", - "Calculation is probably not spin polarized" - ) - return(None) - break - # raise IOError("Could not identify espresso magmoms") - - #__| - - line = lines[i].split() - if len(line) > 3: - if line[0] == "absolute": - abs_magmom = float(line[3]) - if len(line) > 6: - if line[4] == "magn:": - i -= num_atoms - 1 - break - i -= 1 - - magmom_list = [] - charge_list = [] - - if abs_magmom < 1e-3: - print("estimate_magmom | Absolute magnetism is near 0, setting " - "initial atomic magmoms to 0" - ) - - # for atom in atoms: - # atom.magmom = 0 - - for atom in range(num_atoms): - magmom_list.append(0.) - - else: - total_esp_magmom = 0 - # for j in range(len(atoms)): - for j in range(num_atoms): - total_esp_magmom += np.abs(float(lines[i + j].split()[5])) - - magmom_list = [] - charge_list = [] - # for j in range(len(atoms)): - for j in range(num_atoms): - charge_i = float(lines[i + j].split()[3]) - magmom_i = float(lines[i + j].split()[5]) - new_magmom_i = magmom_i * abs_magmom / total_esp_magmom - # atoms[j].magmom = new_magmom_i - magmom_list.append(new_magmom_i) - charge_list.append(charge_i) - - magmom_list = np.array(magmom_list) - charge_list = np.array(charge_list) - - if atoms is not None: - atoms.info.update({"qe_log_magmoms": magmom_list}) - atoms.info.update({"qe_log_charges": charge_list}) - - return(magmom_list, charge_list) - #__| - -def scf_convergence(path_i=".", log="log"): - """Return SCF convergence vs iteration. - - Author: ??? - I didn't write this. - - TODO: Not working well with python3.6, probably best to rewrite this - - Args: - log - """ - #| - scf_convergence - rydberg = 13.6057 # rydberg to eV conversion - - filename = os.path.join( - os.environ["HOME"], - "scf_temp.txt", - ) - - os.system("grep scf %s > %s" % (log, filename)) - - file = open(filename) - file.seek(0) # just in case - - lines = file.read().split("\n") - lines = filter(None, lines) - - scf = [] - iter = [] - n = 0 - for line in lines: - items = filter(None, line.split(" ")) - try: - scf.append(float(items[4]) * rydberg) - n += 1 - iter.append(n) - except: - continue - - os.system("grep cpu log > %s" % filename) - file = open(filename) - lines = file.read().split("\n") - lines = filter(None, lines) - #time = float(lines[-1][40:50])/3600/48 - file.close() - - os.system('grep "kinetic-energy cutoff" %s > %s' % (log, filename)) - file = open(filename) - - # FIXME This is breaking in python3.6 - # items = filter(None, file.read().split(" ")) - items = list(filter(None, file.read().split(" "))) - - pw = float(items[3]) * 13.606 - os.system("rm %s" % filename) - - return(scf, iter, pw) - #__| - -#__| +#!/usr/bin/env python + +"""Quantum Espresso methods and code. + +Author: Raul A. Flores +""" + +#| - Import Modules +import os +import pandas as pd + +import numpy as np +#__| + +#| - Log File Methods + +def number_of_atoms(path_i=".", log="log"): + """Return number of atoms from QE log file. + + Args: + path_i: + log: + """ + #| - number_of_atoms + file_name = path_i + "/" + log + with open(file_name, "r") as fle: + fle.seek(0) # just in case + + while True: + line = fle.readline() + + if "Cartesian axes" in line: + fle.readline().strip() # Blank line + fle.readline() # Column headers + + atom_list = [] + while True: + data_line_i = fle.readline().strip() + + if data_line_i == "": + break + + atom_list.append(data_line_i) + + if not line: + break + + num_atoms = len(atom_list) + + return(num_atoms) + #__| + +def tot_abs_magnetization(path_i=".", log="log"): + """Return total and absolute magnetization vs SCF iteration. + + Abs: + path_i + log + """ + #| - tot_abs_magnetization + fle = open(log, "r") + fle.seek(0) # just in case + + tot_mag_list = [] + abs_mag_list = [] + while True: + line = fle.readline() + + # Break out of loop + if not line: + break + + #| - Searching for Atomic Magmoms + if "total magnetization" in line: + line_list = line.strip().split(" ") + line = [i for i in line_list if i != ""] + tot_mag = float(line[3]) + tot_mag_list.append(tot_mag) + + if "absolute magnetization" in line: + line_list = line.strip().split(" ") + line = [i for i in line_list if i != ""] + abs_mag = float(line[3]) + abs_mag_list.append(abs_mag) + + #__| + + df_tot = pd.DataFrame(tot_mag_list, columns=["tot_mag"]) + df_abs = pd.DataFrame(abs_mag_list, columns=["abs_mag"]) + + df = pd.concat([df_tot, df_abs], axis=1) + + return(df) + #__| + +def element_index_dict(path_i=".", log="log"): + """Return index: element dictionary. + + Format: {0: 'Fe', 1: 'Fe', 2: 'Fe'} + + Args: + path_i + log + """ + #| - element_index_dict + elem_ind_dict = {} + file_name = path_i + "/" + log + with open(file_name, "r") as fle: + + fle.seek(0) # just in case + while True: + line = fle.readline() + + # Break out of loop + if not line: + break + + #| - Atom Index <---> Atom Type + if "Cartesian axes" in line: + fle.readline() # Blank line + fle.readline() # Column header line + + # elem_ind_dict = {} + while True: + line_i = fle.readline() + if "tau(" in line_i: + + line_list = line_i.strip().split(" ") + line_list = [i_ct for i_ct in line_list if i_ct != ""] + + ind_i = int(line_list[0]) - 1 # "0" indexed + + elem_i = line_list[1] + elem_i = ''.join([i for i in elem_i if not i.isdigit()]) + + elem_ind_dict[ind_i] = elem_i + + else: + break + + #__| + + return(elem_ind_dict) + #__| + +def magmom_charge_data(path_i=".", log="log"): + """Return charge and magmom data per atom for all SCF iterations. + + Args: + path_i + log + """ + #| - magmom_charge_data + + #| - Reading Log File + file_name = path_i + "/" + log + + fle = open(file_name, "r") + fle.seek(0) # just in case + + master_list = [] + while True: + line = fle.readline() + + # Break out of loop + if not line: + break + + #| - Searching for Atomic Magmoms + if "Magnetic moment per site" in line: + + list_i = [] + while True: + # print("ksjfksjfks - 3") + line_i = fle.readline() + if "atom:" in line_i: + + line_list = line_i.strip().split(" ") + line_list = [i_cnt for i_cnt in line_list if i_cnt != ""] + + atom_num = int(line_list[1]) - 1 # "0" indexed + charge = float(line_list[3]) + magmom = float(line_list[5]) + + entry_dict = { + "atom_num": atom_num, + "charge": charge, + "magmom": magmom, + } + + list_i.append(entry_dict) + else: + break + + master_list.append(list_i) + #__| + + #__| + + #| - Creating Pandas DataFrame + if master_list == []: + print("Magmom/charge data not found, ", + "calculation probably not spin-polarized" + ) + return(None) + + elem_ind_dict = element_index_dict(path_i=path_i, log=log) + + df_list = [] + for i_cnt, iter_i in enumerate(master_list): + df_i = pd.DataFrame(iter_i) + + df_list.append(df_i) + df_i["iteration"] = i_cnt + + # Combining data frames + df = pd.concat(df_list) + + # Creating element type column (mapping index <--> element) + df["element"] = df["atom_num"].map(elem_ind_dict) + + # Resetting index + df.reset_index() + #__| + + return(df) + #__| + +def estimate_magmom( + path_i=".", + atoms=None, + log="log", + ): + """Estimage magnetic moments from QE log file. + + TODO Also read charges data for last iteration + TODO Modify to not need atoms object to function + + Author: Colin Dickens + + Estimate magmom from log file (based on charge spheres centered on atoms) + and assign to atoms object to assist with calculation restart upon + unexpected interruption. + """ + #| - estimate_magmom + num_atoms = number_of_atoms(path_i=path_i, log=log) + # print(num_atoms) + + file_name = path_i + "/" + log + + with open(file_name, "r") as fle: + lines = fle.readlines() + + i = len(lines) - 1 + while True: + + #| - If magmom/charge data is not found in log file + # The calculation is probably not spin-polarized + if i == 0: + print("estimate_magmom - Could not find magmom/charge data \n", + "Calculation is probably not spin polarized" + ) + return(None) + break + # raise IOError("Could not identify espresso magmoms") + + #__| + + line = lines[i].split() + if len(line) > 3: + if line[0] == "absolute": + abs_magmom = float(line[3]) + if len(line) > 6: + if line[4] == "magn:": + i -= num_atoms - 1 + break + i -= 1 + + magmom_list = [] + charge_list = [] + + if abs_magmom < 1e-3: + print("estimate_magmom | Absolute magnetism is near 0, setting " + "initial atomic magmoms to 0" + ) + + # for atom in atoms: + # atom.magmom = 0 + + for atom in range(num_atoms): + magmom_list.append(0.) + + else: + total_esp_magmom = 0 + # for j in range(len(atoms)): + for j in range(num_atoms): + total_esp_magmom += np.abs(float(lines[i + j].split()[5])) + + magmom_list = [] + charge_list = [] + # for j in range(len(atoms)): + for j in range(num_atoms): + charge_i = float(lines[i + j].split()[3]) + magmom_i = float(lines[i + j].split()[5]) + new_magmom_i = magmom_i * abs_magmom / total_esp_magmom + # atoms[j].magmom = new_magmom_i + magmom_list.append(new_magmom_i) + charge_list.append(charge_i) + + magmom_list = np.array(magmom_list) + charge_list = np.array(charge_list) + + if atoms is not None: + atoms.info.update({"qe_log_magmoms": magmom_list}) + atoms.info.update({"qe_log_charges": charge_list}) + + return(magmom_list, charge_list) + #__| + +def scf_convergence(path_i=".", log="log"): + """Return SCF convergence vs iteration. + + Author: ??? + I didn't write this. + + TODO: Not working well with python3.6, probably best to rewrite this + + Args: + log + """ + #| - scf_convergence + rydberg = 13.6057 # rydberg to eV conversion + + filename = os.path.join( + os.environ["HOME"], + "scf_temp.txt", + ) + + os.system("grep scf %s > %s" % (log, filename)) + + file = open(filename) + file.seek(0) # just in case + + lines = file.read().split("\n") + lines = filter(None, lines) + + scf = [] + iter = [] + n = 0 + for line in lines: + items = filter(None, line.split(" ")) + try: + scf.append(float(items[4]) * rydberg) + n += 1 + iter.append(n) + except: + continue + + os.system("grep cpu log > %s" % filename) + file = open(filename) + lines = file.read().split("\n") + lines = filter(None, lines) + #time = float(lines[-1][40:50])/3600/48 + file.close() + + os.system('grep "kinetic-energy cutoff" %s > %s' % (log, filename)) + file = open(filename) + + # FIXME This is breaking in python3.6 + # items = filter(None, file.read().split(" ")) + items = list(filter(None, file.read().split(" "))) + + pw = float(items[3]) * 13.606 + os.system("rm %s" % filename) + + return(scf, iter, pw) + #__| + +#__| diff --git a/raman_dft/vasp_raman_job_methods.py b/raman_dft/vasp_raman_job_methods.py index 06c1309..2bcc0e5 100644 --- a/raman_dft/vasp_raman_job_methods.py +++ b/raman_dft/vasp_raman_job_methods.py @@ -1,401 +1,401 @@ -"""Methods to run VASP-Raman jobs.""" - -#| - IMPORT MODULES -import os -import sys -from math import sqrt - -from ase import io -import numpy as np - -from plotly.graph_objs import Scatter -import re -#__| - -#| - Methods from vasp_raman script (Github) - -def get_modes_from_OUTCAR(outcar_fh, nat=None, free_nat=None, path_i="."): - #| - get_modes_from_OUTCAR - if nat == None: - - name = "OUTCAR.phon" - if os.path.isfile(path_i + "/" + name): - file_name = name - elif os.path.isfile(path_i + "/" + "OUTCAR"): - file_name = "OUTCAR" - else: - file_name = None - - atoms = io.read(path_i + "/" + file_name) - nat = atoms.get_number_of_atoms() - - # nat = vp.num_of_atoms_OUTCAR(outcar_fh) - - if free_nat == None: - free_nat = nat - - eigvals = [ 0.0 for i in range(nat*3) ] - eigvecs = [ 0.0 for i in range(nat*3) ] - norms = [ 0.0 for i in range(nat*3) ] - - outcar_fh.seek(0) # just in case - while True: - line = outcar_fh.readline() - - if not line: - break - - if "Eigenvectors after division by SQRT(mass)" in line: - outcar_fh.readline() # empty line - outcar_fh.readline() # Eigenvectors and eigenvalues of the dynamical matrix - outcar_fh.readline() # ---------------------------------------------------- - outcar_fh.readline() # empty line - - for i in range(free_nat*3): # all frequencies should be supplied, regardless of those requested to calculate - - outcar_fh.readline() # empty line - line_i = outcar_fh.readline() - p = re.search(r"^\s*(\d+).+?([\.\d]+) cm-1", line_i) - - eigvals[i] = float(p.group(2)) - - outcar_fh.readline() # X Y Z dx dy dz - eigvec = [] - - for j in range(nat): - tmp = outcar_fh.readline().split() - - eigvec.append([ float(tmp[x]) for x in range(3,6) ]) - - eigvecs[i] = eigvec - norms[i] = sqrt( sum( [abs(x)**2 for sublist in eigvec for x in sublist] ) ) - - return eigvals, eigvecs, norms - - print("[get_modes_from_OUTCAR]: ERROR Couldn't find 'Eigenvectors after", - " division by SQRT(mass)'' in OUTCAR.", - " Use 'NWRITE=3' in INCAR. Exiting...") - sys.exit(1) - #__| - -def parse_env_params(params): - #| - parse_env_params - tmp = params.strip().split("_") - if len(tmp) != 4: - print("[parse_env_params]: ERROR there should be exactly four parameters") - sys.exit(1) - - [first, last, nderiv, step_size] = [int(tmp[0]), int(tmp[1]), int(tmp[2]), float(tmp[3])] - - return first, last, nderiv, step_size - #__| - -def parse_poscar(poscar_fh, cons_atoms=0): - #| - parse_poscar - # modified subroutine from phonopy 1.8.3 (New BSD license) - - poscar_fh.seek(0) # just in case - lines = poscar_fh.readlines() - - scale = float(lines[1]) - if scale < 0.0: - print("[parse_poscar]: ERROR negative scale not implemented.") - sys.exit(1) - - b = [] - for i in range(2, 5): - b.append([float(x)*scale for x in lines[i].split()[:3]]) - - vol = b[0][0]*b[1][1]*b[2][2] + b[1][0]*b[2][1]*b[0][2] + b[2][0]*b[0][1]*b[1][2] - \ - b[0][2]*b[1][1]*b[2][0] - b[2][1]*b[1][2]*b[0][0] - b[2][2]*b[0][1]*b[1][0] - - try: - num_atoms = [int(x) for x in lines[5].split()] - line_at = 6 - except ValueError: - symbols = [x for x in lines[5].split()] - num_atoms = [int(x) for x in lines[6].split()] - line_at = 7 - - nat = sum(num_atoms) # TEMP - free_nat = sum(num_atoms) - cons_atoms # TEMP - - if lines[line_at][0].lower() == "s": - line_at += 1 - - if (lines[line_at][0].lower() == "c" or lines[line_at][0].lower() == "k"): - is_scaled = False - else: - is_scaled = True - - line_at += 1 - - positions = [] - for i in range(line_at, line_at + nat): - pos = [float(x) for x in lines[i].split()[:3]] - - if is_scaled: - pos = MAT_m_VEC(T(b), pos) - - positions.append(pos) - - poscar_header = "".join(lines[1:line_at-1]) # will add title and "Cartesian" later - return nat, free_nat, vol, b, positions, poscar_header - #__| - -def MAT_m_VEC(m, v): - #| - MAT_m_VEC - p = [ 0.0 for i in range(len(v)) ] - for i in range(len(m)): - assert len(v) == len(m[i]), "Length of the matrix row is not equal to the length of the vector" - p[i] = sum( [ m[i][j]*v[j] for j in range(len(v)) ] ) - return p - #__| - -def T(m): - #| - T - p = [[ m[i][j] for i in range(len( m[j] )) ] for j in range(len( m )) ] - return p - #__| - -def get_epsilon_from_OUTCAR(outcar_fh): - #| - get_epsilon_from_OUTCAR - epsilon = [] - - outcar_fh.seek(0) # just in case - while True: - line = outcar_fh.readline() - if not line: - break - - if "MACROSCOPIC STATIC DIELECTRIC TENSOR" in line: - print(line) - outcar_fh.readline() - epsilon.append([float(x) for x in outcar_fh.readline().split()]) - epsilon.append([float(x) for x in outcar_fh.readline().split()]) - epsilon.append([float(x) for x in outcar_fh.readline().split()]) - return epsilon - - raise RuntimeError("[get_epsilon_from_OUTCAR]: ERROR Couldn't find dielectric tensor in OUTCAR") - return 1 - #__| - - -#| - Substitute Functions for VTST - -def parse_freqdat(freqdat_fh, nat): - #| - parse_freqdat - freqdat_fh.seek(0) # just in case - # - eigvals = [ 0.0 for i in range(nat*3) ] - # - for i in range(nat*3): # all frequencies should be supplied, regardless of requested to calculate - tmp = freqdat_fh.readline().split() - eigvals[i] = float(tmp[0]) - # - return eigvals - #__| - -def parse_modesdat(modesdat_fh, nat): - #| - parse_modesdat - # from math import sqrt - modesdat_fh.seek(0) # just in case - # - eigvecs = [ 0.0 for i in range(nat*3) ] - norms = [ 0.0 for i in range(nat*3) ] - # - for i in range(nat*3): # all frequencies should be supplied, regardless of requested to calculate - eigvec = [] - for j in range(nat): - tmp = modesdat_fh.readline().split() - eigvec.append([ float(tmp[x]) for x in range(3) ]) - # - modesdat_fh.readline().split() # empty line - eigvecs[i] = eigvec - norms[i] = sqrt( sum( [abs(x)**2 for sublist in eigvec for x in sublist] ) ) - # - return eigvecs, norms - #__| - -#__| - -#__| - -def modes_list(num_modes, step, mode_0=1, modes_to_run="All"): - """Returns list of strings representing number of modes to run per job - - Args: - atoms: - modes_to_run: - """ - #| - modes_list - - - # atoms = io.read("POSCAR.phon") - # num_atoms = atoms.get_number_of_atoms() - # max_modes = 3 * num_atoms - - - if modes_to_run == "All": - high_bound = mode_0 + num_modes - 1 - else: - high_bound = mode_0 + modes_to_run - 1 - - mode_range = [mode_0, high_bound] - - modes_list = [] - num_1 = mode_range[0] - num_2 = 0 - - while num_2 < mode_range[1] - step: - num_2 = num_1 + step - - modes = str(num_1).zfill(2) + "-" + str(num_2).zfill(2) - modes_list.append(modes) - num_1 = num_2 + 1 - - if num_2 != mode_range[1]: - modes_rem = mode_range[1] - num_2 - last_modes = str(num_2 + 1).zfill(2) + "-" + str(num_2 + modes_rem) - - modes_list.append(last_modes) - - # for ind, modes in enumerate(modes_list): - # rev_entry = "Modes_" + modes + "_2_0.01" - # modes_list[ind] = rev_entry - - - return(modes_list) - #__| - -def vasp_raman_input_file(modes, dir="."): - """ - - Args: - modes: - dir: - Directory to write the vasp_raman input file to - """ - #| - vasp_raman_input_file - VASP_RAMAN_RUN = "python 3_vasp_raman_run_ibrion_n1.py" - - #| Changing "-" character in mode to "_" - modes = modes.replace("-", "_") - - # Create VASP_RAMAN_RUN and VASP_RAMAN_PARAMS file - VASP_RAMAN_PARAMS = modes + "_2_0.01" - - filename = "param_vasp_raman" - - with open(dir + "/" + filename, "w") as file: - file.write(VASP_RAMAN_PARAMS + "\n" + VASP_RAMAN_RUN + "\n") - #__| - -def concatenate_mode_files(): - """ - """ - #| - concatenate_mode_filess - tmp = 7 - - #__| - -def to_plot(hw, ab, gam=0.05, type="Gaussian", scaling=1.): - """ - - Args: - hw: - ab: - gam: - type: - scaling: - """ - #| - to_plot - ab /= np.max(np.abs(ab), axis=0) - - ab = ab * scaling - - fmin = min(hw) - fmax = max(hw) - erange = np.arange(fmin - 40. * gam, fmax + 40. * gam, gam / 10.) #np.arange(fmin-40*gam,fmax+40*gam,gam/10) - spectrum = 0.0 * erange - for i in range(len(hw)): - if type=="Gaussian": - - term_1 = ab[i] * (2 * np.pi) ** (-0.5) / gam - term_2 = np.exp(np.clip(-1.0 * (hw[i] - erange) ** 2/(2 * gam ** 2), -300, 300)) - spectrum += term_1 * term_2 - - # spectrum += (2 * np.pi) ** (-0.5) / gam * np.exp(np.clip(-1.0 * (hw[i] - erange) ** 2/(2 * gam ** 2), -300, 300)) - - elif type=="Lorentzian": - spectrum += ab[i]*1/np.pi*gam/((hw[i]-erange)**2+gam**2) - - return erange, spectrum - #__| - -def proc_data( - data, - add_to_label="", - scaling=1., - freq_shift=0.0, - gauss_gamma=8.0, - color_palette=None, - ): - """Process data. - - Args: - data: - add_to_label="": - scaling=1.: - freq_shift=0.0: - gauss_gamma=8.0: - color_palette=None: - """ - #| - proc_data - data_sets = data - - plot_data_list = [] - - ind = 0 - for data_series in data_sets: - ind += 1 - data_i_labels = add_to_label + data_series["label"] - x_dat = data_series["data"]["frequency"].tolist() - y_dat = data_series["data"]["activity"].tolist() - - x_dat = np.array(x_dat) + freq_shift - - #| - Creating Gaussian Curves From Frequencies and Activities - x_dat, y_dat = to_plot( - x_dat, - y_dat, - gam=gauss_gamma, - scaling=scaling - ) - #__| - - if color_palette is None: - data_i = Scatter( - x=x_dat, - y=y_dat, - fill="tozeroy", - name=data_i_labels, - mode="lines", - ) - - else: - data_i = Scatter( - x=x_dat, - y=y_dat, - fill="tozeroy", - name=data_i_labels, - mode="lines", - marker={ - "color": color_palette[ind - 1], - }, - ) - - plot_data_list.append(data_i) - - return(plot_data_list) - #__| +"""Methods to run VASP-Raman jobs.""" + +#| - IMPORT MODULES +import os +import sys +from math import sqrt + +from ase import io +import numpy as np + +from plotly.graph_objs import Scatter +import re +#__| + +#| - Methods from vasp_raman script (Github) + +def get_modes_from_OUTCAR(outcar_fh, nat=None, free_nat=None, path_i="."): + #| - get_modes_from_OUTCAR + if nat == None: + + name = "OUTCAR.phon" + if os.path.isfile(path_i + "/" + name): + file_name = name + elif os.path.isfile(path_i + "/" + "OUTCAR"): + file_name = "OUTCAR" + else: + file_name = None + + atoms = io.read(path_i + "/" + file_name) + nat = atoms.get_number_of_atoms() + + # nat = vp.num_of_atoms_OUTCAR(outcar_fh) + + if free_nat == None: + free_nat = nat + + eigvals = [ 0.0 for i in range(nat*3) ] + eigvecs = [ 0.0 for i in range(nat*3) ] + norms = [ 0.0 for i in range(nat*3) ] + + outcar_fh.seek(0) # just in case + while True: + line = outcar_fh.readline() + + if not line: + break + + if "Eigenvectors after division by SQRT(mass)" in line: + outcar_fh.readline() # empty line + outcar_fh.readline() # Eigenvectors and eigenvalues of the dynamical matrix + outcar_fh.readline() # ---------------------------------------------------- + outcar_fh.readline() # empty line + + for i in range(free_nat*3): # all frequencies should be supplied, regardless of those requested to calculate + + outcar_fh.readline() # empty line + line_i = outcar_fh.readline() + p = re.search(r"^\s*(\d+).+?([\.\d]+) cm-1", line_i) + + eigvals[i] = float(p.group(2)) + + outcar_fh.readline() # X Y Z dx dy dz + eigvec = [] + + for j in range(nat): + tmp = outcar_fh.readline().split() + + eigvec.append([ float(tmp[x]) for x in range(3,6) ]) + + eigvecs[i] = eigvec + norms[i] = sqrt( sum( [abs(x)**2 for sublist in eigvec for x in sublist] ) ) + + return eigvals, eigvecs, norms + + print("[get_modes_from_OUTCAR]: ERROR Couldn't find 'Eigenvectors after", + " division by SQRT(mass)'' in OUTCAR.", + " Use 'NWRITE=3' in INCAR. Exiting...") + sys.exit(1) + #__| + +def parse_env_params(params): + #| - parse_env_params + tmp = params.strip().split("_") + if len(tmp) != 4: + print("[parse_env_params]: ERROR there should be exactly four parameters") + sys.exit(1) + + [first, last, nderiv, step_size] = [int(tmp[0]), int(tmp[1]), int(tmp[2]), float(tmp[3])] + + return first, last, nderiv, step_size + #__| + +def parse_poscar(poscar_fh, cons_atoms=0): + #| - parse_poscar + # modified subroutine from phonopy 1.8.3 (New BSD license) + + poscar_fh.seek(0) # just in case + lines = poscar_fh.readlines() + + scale = float(lines[1]) + if scale < 0.0: + print("[parse_poscar]: ERROR negative scale not implemented.") + sys.exit(1) + + b = [] + for i in range(2, 5): + b.append([float(x)*scale for x in lines[i].split()[:3]]) + + vol = b[0][0]*b[1][1]*b[2][2] + b[1][0]*b[2][1]*b[0][2] + b[2][0]*b[0][1]*b[1][2] - \ + b[0][2]*b[1][1]*b[2][0] - b[2][1]*b[1][2]*b[0][0] - b[2][2]*b[0][1]*b[1][0] + + try: + num_atoms = [int(x) for x in lines[5].split()] + line_at = 6 + except ValueError: + symbols = [x for x in lines[5].split()] + num_atoms = [int(x) for x in lines[6].split()] + line_at = 7 + + nat = sum(num_atoms) # TEMP + free_nat = sum(num_atoms) - cons_atoms # TEMP + + if lines[line_at][0].lower() == "s": + line_at += 1 + + if (lines[line_at][0].lower() == "c" or lines[line_at][0].lower() == "k"): + is_scaled = False + else: + is_scaled = True + + line_at += 1 + + positions = [] + for i in range(line_at, line_at + nat): + pos = [float(x) for x in lines[i].split()[:3]] + + if is_scaled: + pos = MAT_m_VEC(T(b), pos) + + positions.append(pos) + + poscar_header = "".join(lines[1:line_at-1]) # will add title and "Cartesian" later + return nat, free_nat, vol, b, positions, poscar_header + #__| + +def MAT_m_VEC(m, v): + #| - MAT_m_VEC + p = [ 0.0 for i in range(len(v)) ] + for i in range(len(m)): + assert len(v) == len(m[i]), "Length of the matrix row is not equal to the length of the vector" + p[i] = sum( [ m[i][j]*v[j] for j in range(len(v)) ] ) + return p + #__| + +def T(m): + #| - T + p = [[ m[i][j] for i in range(len( m[j] )) ] for j in range(len( m )) ] + return p + #__| + +def get_epsilon_from_OUTCAR(outcar_fh): + #| - get_epsilon_from_OUTCAR + epsilon = [] + + outcar_fh.seek(0) # just in case + while True: + line = outcar_fh.readline() + if not line: + break + + if "MACROSCOPIC STATIC DIELECTRIC TENSOR" in line: + print(line) + outcar_fh.readline() + epsilon.append([float(x) for x in outcar_fh.readline().split()]) + epsilon.append([float(x) for x in outcar_fh.readline().split()]) + epsilon.append([float(x) for x in outcar_fh.readline().split()]) + return epsilon + + raise RuntimeError("[get_epsilon_from_OUTCAR]: ERROR Couldn't find dielectric tensor in OUTCAR") + return 1 + #__| + + +#| - Substitute Functions for VTST + +def parse_freqdat(freqdat_fh, nat): + #| - parse_freqdat + freqdat_fh.seek(0) # just in case + # + eigvals = [ 0.0 for i in range(nat*3) ] + # + for i in range(nat*3): # all frequencies should be supplied, regardless of requested to calculate + tmp = freqdat_fh.readline().split() + eigvals[i] = float(tmp[0]) + # + return eigvals + #__| + +def parse_modesdat(modesdat_fh, nat): + #| - parse_modesdat + # from math import sqrt + modesdat_fh.seek(0) # just in case + # + eigvecs = [ 0.0 for i in range(nat*3) ] + norms = [ 0.0 for i in range(nat*3) ] + # + for i in range(nat*3): # all frequencies should be supplied, regardless of requested to calculate + eigvec = [] + for j in range(nat): + tmp = modesdat_fh.readline().split() + eigvec.append([ float(tmp[x]) for x in range(3) ]) + # + modesdat_fh.readline().split() # empty line + eigvecs[i] = eigvec + norms[i] = sqrt( sum( [abs(x)**2 for sublist in eigvec for x in sublist] ) ) + # + return eigvecs, norms + #__| + +#__| + +#__| + +def modes_list(num_modes, step, mode_0=1, modes_to_run="All"): + """Returns list of strings representing number of modes to run per job + + Args: + atoms: + modes_to_run: + """ + #| - modes_list + + + # atoms = io.read("POSCAR.phon") + # num_atoms = atoms.get_number_of_atoms() + # max_modes = 3 * num_atoms + + + if modes_to_run == "All": + high_bound = mode_0 + num_modes - 1 + else: + high_bound = mode_0 + modes_to_run - 1 + + mode_range = [mode_0, high_bound] + + modes_list = [] + num_1 = mode_range[0] + num_2 = 0 + + while num_2 < mode_range[1] - step: + num_2 = num_1 + step + + modes = str(num_1).zfill(2) + "-" + str(num_2).zfill(2) + modes_list.append(modes) + num_1 = num_2 + 1 + + if num_2 != mode_range[1]: + modes_rem = mode_range[1] - num_2 + last_modes = str(num_2 + 1).zfill(2) + "-" + str(num_2 + modes_rem) + + modes_list.append(last_modes) + + # for ind, modes in enumerate(modes_list): + # rev_entry = "Modes_" + modes + "_2_0.01" + # modes_list[ind] = rev_entry + + + return(modes_list) + #__| + +def vasp_raman_input_file(modes, dir="."): + """ + + Args: + modes: + dir: + Directory to write the vasp_raman input file to + """ + #| - vasp_raman_input_file + VASP_RAMAN_RUN = "python 3_vasp_raman_run_ibrion_n1.py" + + #| Changing "-" character in mode to "_" + modes = modes.replace("-", "_") + + # Create VASP_RAMAN_RUN and VASP_RAMAN_PARAMS file + VASP_RAMAN_PARAMS = modes + "_2_0.01" + + filename = "param_vasp_raman" + + with open(dir + "/" + filename, "w") as file: + file.write(VASP_RAMAN_PARAMS + "\n" + VASP_RAMAN_RUN + "\n") + #__| + +def concatenate_mode_files(): + """ + """ + #| - concatenate_mode_filess + tmp = 7 + + #__| + +def to_plot(hw, ab, gam=0.05, type="Gaussian", scaling=1.): + """ + + Args: + hw: + ab: + gam: + type: + scaling: + """ + #| - to_plot + ab /= np.max(np.abs(ab), axis=0) + + ab = ab * scaling + + fmin = min(hw) + fmax = max(hw) + erange = np.arange(fmin - 40. * gam, fmax + 40. * gam, gam / 10.) #np.arange(fmin-40*gam,fmax+40*gam,gam/10) + spectrum = 0.0 * erange + for i in range(len(hw)): + if type=="Gaussian": + + term_1 = ab[i] * (2 * np.pi) ** (-0.5) / gam + term_2 = np.exp(np.clip(-1.0 * (hw[i] - erange) ** 2/(2 * gam ** 2), -300, 300)) + spectrum += term_1 * term_2 + + # spectrum += (2 * np.pi) ** (-0.5) / gam * np.exp(np.clip(-1.0 * (hw[i] - erange) ** 2/(2 * gam ** 2), -300, 300)) + + elif type=="Lorentzian": + spectrum += ab[i]*1/np.pi*gam/((hw[i]-erange)**2+gam**2) + + return erange, spectrum + #__| + +def proc_data( + data, + add_to_label="", + scaling=1., + freq_shift=0.0, + gauss_gamma=8.0, + color_palette=None, + ): + """Process data. + + Args: + data: + add_to_label="": + scaling=1.: + freq_shift=0.0: + gauss_gamma=8.0: + color_palette=None: + """ + #| - proc_data + data_sets = data + + plot_data_list = [] + + ind = 0 + for data_series in data_sets: + ind += 1 + data_i_labels = add_to_label + data_series["label"] + x_dat = data_series["data"]["frequency"].tolist() + y_dat = data_series["data"]["activity"].tolist() + + x_dat = np.array(x_dat) + freq_shift + + #| - Creating Gaussian Curves From Frequencies and Activities + x_dat, y_dat = to_plot( + x_dat, + y_dat, + gam=gauss_gamma, + scaling=scaling + ) + #__| + + if color_palette is None: + data_i = Scatter( + x=x_dat, + y=y_dat, + fill="tozeroy", + name=data_i_labels, + mode="lines", + ) + + else: + data_i = Scatter( + x=x_dat, + y=y_dat, + fill="tozeroy", + name=data_i_labels, + mode="lines", + marker={ + "color": color_palette[ind - 1], + }, + ) + + plot_data_list.append(data_i) + + return(plot_data_list) + #__| diff --git a/readthedocs.py b/readthedocs.py index 9eced43..84f3c2d 100644 --- a/readthedocs.py +++ b/readthedocs.py @@ -1,15 +1,15 @@ -"""Temporary file to test readthedocs functionality.""" - - - -def tmp_method(var): - """Does something really usefull and cool. - - Args: - var: - """ - #| - tmp_method - - var + 2 - return("hello world") - #__| +"""Temporary file to test readthedocs functionality.""" + + + +def tmp_method(var): + """Does something really usefull and cool. + + Args: + var: + """ + #| - tmp_method + + var + 2 + return("hello world") + #__| diff --git a/vasp/vasp_methods.py b/vasp/vasp_methods.py index 3190814..eb3609f 100644 --- a/vasp/vasp_methods.py +++ b/vasp/vasp_methods.py @@ -1,330 +1,330 @@ -#| - IMPORT MODULES -from raman_dft.vasp_raman_job_methods import get_modes_from_OUTCAR -# from raman_dft.vasp_raman_job_methods import parse_poscar - -from ase_modules.ase_methods import create_gif_from_atoms_movies - -from ase import io -import copy -import numpy as np -import os -import itertools -#__| - -def num_of_atoms_OUTCAR_tmp(outcar_fh): - """Parses OUTCAR for number of atoms in atoms object - """ - #| - num_of_atoms_OUTCAR - outcar_fh.seek(0) - num_atoms = 0 - while True: - line = outcar_fh.readline() - if not line: - break - - if "ion position" in line: - while True: - next_line = outcar_fh.readline() - - if next_line == "\n": - break - - # ion_entry = next_line.split()[0].isdigit() - num_atoms += 1 - return(num_atoms) - #__| - -def create_vib_modes_atoms( - path_i=".", - file_name="OUTCAR", - modes_to_run="all", - create_gifs=True, - step_size=0.8, - number_images=21, - ): - """Creates atoms movie for each vibrational mode. - - Args: - path_i: - file_name: - modes_to_run: - create_gifs: - step_size: - number_images: - """ - #| - create_vib_modes_atoms - - #| - SCRIPT INPUTS - # step_size = 1.2 - # number_images = 31 - vis_dir = "/mode_movies" - # path_i = "/mnt/c/Users/raul_desktop/Dropbox/01_acad_folder - # /01_grad_school/01_norskov/04_comp_clusters/00_scripts/ - # 09_raman_dft/view_modes" - #__| - - #| - Reading in OUTCAR - file_name = "OUTCAR" - with open(path_i + "/" + file_name, "r") as fle: - atoms = io.read(path_i + "/" + file_name) - N_atoms = atoms.get_number_of_atoms() - pos = atoms.positions - - eigvals, eigvecs, norms = get_modes_from_OUTCAR(fle, path_i=path_i) - #__| - - #| - Creating Visualization Directory - if not os.path.isdir(path_i + vis_dir): - os.makedirs(path_i + vis_dir) - #__| - - iterator = enumerate(itertools.izip(eigvals, eigvecs, norms)) - for index, (eigval_i, eigvec_i, norm_i) in iterator: - - # if not modes_to_run == "all": - # eigval_in_list = False - # for mode_to_run in modes_to_run: - # if eigval_i - # # if not eigval_i not in - - disps = np.linspace(-1, 1, num=number_images / 2) - disps = np.append(disps, np.flip(disps, 0)) - - master_pos_lst = [] - for disp_step in disps: - pos_lst = [] - for k in range(N_atoms): - - p_k = pos[k] - e_ik = eigvec_i[k] - ss = step_size - ds = disp_step - l_lst = range(3) - - pos_disp = [p_k[l] + e_ik[l] * ss * ds / norm_i for l in l_lst] - # pos_disp = [ pos[k][l] + eigvec_i[k][l] * step_size - # * disp_step / norm_i for l in range(3)] - pos_lst.append(pos_disp) - - atoms_i = copy.deepcopy(atoms) - atoms_i.set_positions(pos_lst) - - master_pos_lst.append(atoms_i) - - eig_str = str(round(eigval_i, 3)).zfill(3) - - eig_str_lst = str(round(eigval_i, 3)).split(".") - eig_str = eig_str_lst[0].zfill(4) + "." + eig_str_lst[1].ljust(3, "0") - - lead_num = str(index).zfill(2) - folder_i = path_i + vis_dir + "/" + lead_num + "_" + eig_str + "_cm-1/" - - if not os.path.isdir(folder_i): - os.makedirs(folder_i) - - - out_traj_file = folder_i + "out-" + eig_str + ".traj" - if os.path.isfile(out_traj_file): - continue - - print("#####################################################") - print("Creating: " + folder_i + "out-" + eig_str + ".traj") - print("#####################################################") - - - io.write(out_traj_file, master_pos_lst) - - if create_gifs: - create_gif_from_atoms_movies( - atoms_file="Default", - path_i=folder_i, - delay=10, - ) - - with open(".FINISHED", "w") as fle: - fle.write("") - #__| - -def create_vdw_kernel_symlink(): - """ - If on the SLAC cluster, symlinks the vdw vasp kernel into the job directory, - otherwise does nothing - """ - #| - create_vdw_kernel_symlink - if os.getenv("COMPENV") == "slac": - print("TEMP - 180313 !@#") - if not (os.path.exists("vdw_kernel.bindat")): - os.symlink( - "/nfs/slac/g/suncatfs/sw/vasp/vdw_kernel.bindat", - "vdw_kernel.bindat", - ) - - - # target = "/nfs/slac/g/suncatfs/sw/vasp/vdw_kernel.bindat" - # tmpLink = "temp_vdw_kernel" - # linkName = "vdw_kernel.bindat" - # os.symlink(target, tmpLink) - # os.rename(tmpLink, linkName) - - elif os.getenv("COMPENV") == "sherlock": - pass - - if os.getenv("AWS_BATCH_JOB_ID") is None: - pass - - #__| - - -def parse_incar(incar_list): - """Manipulate INCAR data into python dictionary with correct data types. - - Args: - incar_list: - INCAR file in python list where each line represents a line from - the file. - """ - #| - parse_incar - incar_1 = [line for line in incar_list if " = " in line] - - incar_dict = {} - for line in incar_1: - line_i = line.split("=") - mess = "Each incar row should have 1 equals sign which " - mess += "will be parsed into the LHS (key) and RHS (value)" - assert len(line_i) == 2, mess - incar_dict.update({line_i[0].strip(): line_i[1].strip()}) - - #| - Incar keys list - # incar_keys = [ - # "ENCUT", - # "AMIX_MAG", - # "BMIX_MAG", - # "BMIX", - # "SIGMA", - # "AMIX", - # "EDIFF", - # "EDIFFG", - # "PREC", - # "GGA", - # "ALGO", - # "ISMEAR", - # "NPAR", - # "LDAUPRINT", - # "NELM", - # "IBRION", - # "IDIPOL", - # "ISIF", - # "ISPIN", - # "INIMIX", - # "NSW", - # "LORBIT", - # "LMAXMIX", - # "KPAR", - # "LDAUTYPE", - # "DIPOL", - # "LDAU", - # "LVTOT", - # "LDIPOL", - # "LASPH", - # "LREAL", - # "LDAUL", - # "LDAUU", - # "LDAUJ", - # ] - #__| - - #| - Incar Types Dict - - incar_types_dict = { - "ENCUT": "float", - "AMIX_MAG": "float", - "BMIX_MAG": "float", - "BMIX": "float", - "SIGMA": "float", - "AMIX": "float", - "EDIFF": "float", - "EDIFFG": "float", - - # string - "PREC": "string", - "GGA": "string", - "ALGO": "string", - - # float - "ISMEAR": "integer", - "NPAR": "integer", - "LDAUPRINT": "integer", - "NELM": "integer", - "IBRION": "integer", - "IDIPOL": "integer", - "ISIF": "integer", - "ISPIN": "integer", - "INIMIX": "integer", - "NSW": "integer", - "LORBIT": "integer", - "LMAXMIX": "integer", - "KPAR": "integer", - "LDAUTYPE": "integer", - - # [a, b, c] - "DIPOL": "list", - - # True/False - "LDAU": "boolean", - "LVTOT": "boolean", - "LDIPOL": "boolean", - "LASPH": "boolean", - - # string - "LREAL": "string", - - # [a, b] - "LDAUL": "list", - "LDAUU": "list", - "LDAUJ": "list", - } - #__| - - #| - Formatting Dict to Proper Data Types - formatted_incar_dict = {} - for key, value in incar_dict.items(): - - # if key == "LDIPOL": - # print(key) - # print(value) - # print("___;_-___--__") - - if key in incar_types_dict: - - data_type = incar_types_dict[key] - - if data_type == "float": - value_new = float(value) - elif data_type == "string": - # Basically leave it alone - value_new = value - elif data_type == "integer": - value_new = int(value) - elif data_type == "list": - # Figure this out later - value_new = value - elif data_type == "boolean": - if value == ".FALSE.": - value_new = False - elif value == ".TRUE.": - value_new = True - else: - value_new = "ERROR 0847589347" - - else: - value_new = value - else: - value_new = value - - formatted_incar_dict.update({key: value_new}) - #__| - - return(formatted_incar_dict) - - # return(incar_dict) - #__| +#| - IMPORT MODULES +from raman_dft.vasp_raman_job_methods import get_modes_from_OUTCAR +# from raman_dft.vasp_raman_job_methods import parse_poscar + +from ase_modules.ase_methods import create_gif_from_atoms_movies + +from ase import io +import copy +import numpy as np +import os +import itertools +#__| + +def num_of_atoms_OUTCAR_tmp(outcar_fh): + """Parses OUTCAR for number of atoms in atoms object + """ + #| - num_of_atoms_OUTCAR + outcar_fh.seek(0) + num_atoms = 0 + while True: + line = outcar_fh.readline() + if not line: + break + + if "ion position" in line: + while True: + next_line = outcar_fh.readline() + + if next_line == "\n": + break + + # ion_entry = next_line.split()[0].isdigit() + num_atoms += 1 + return(num_atoms) + #__| + +def create_vib_modes_atoms( + path_i=".", + file_name="OUTCAR", + modes_to_run="all", + create_gifs=True, + step_size=0.8, + number_images=21, + ): + """Creates atoms movie for each vibrational mode. + + Args: + path_i: + file_name: + modes_to_run: + create_gifs: + step_size: + number_images: + """ + #| - create_vib_modes_atoms + + #| - SCRIPT INPUTS + # step_size = 1.2 + # number_images = 31 + vis_dir = "/mode_movies" + # path_i = "/mnt/c/Users/raul_desktop/Dropbox/01_acad_folder + # /01_grad_school/01_norskov/04_comp_clusters/00_scripts/ + # 09_raman_dft/view_modes" + #__| + + #| - Reading in OUTCAR + file_name = "OUTCAR" + with open(path_i + "/" + file_name, "r") as fle: + atoms = io.read(path_i + "/" + file_name) + N_atoms = atoms.get_number_of_atoms() + pos = atoms.positions + + eigvals, eigvecs, norms = get_modes_from_OUTCAR(fle, path_i=path_i) + #__| + + #| - Creating Visualization Directory + if not os.path.isdir(path_i + vis_dir): + os.makedirs(path_i + vis_dir) + #__| + + iterator = enumerate(itertools.izip(eigvals, eigvecs, norms)) + for index, (eigval_i, eigvec_i, norm_i) in iterator: + + # if not modes_to_run == "all": + # eigval_in_list = False + # for mode_to_run in modes_to_run: + # if eigval_i + # # if not eigval_i not in + + disps = np.linspace(-1, 1, num=number_images / 2) + disps = np.append(disps, np.flip(disps, 0)) + + master_pos_lst = [] + for disp_step in disps: + pos_lst = [] + for k in range(N_atoms): + + p_k = pos[k] + e_ik = eigvec_i[k] + ss = step_size + ds = disp_step + l_lst = range(3) + + pos_disp = [p_k[l] + e_ik[l] * ss * ds / norm_i for l in l_lst] + # pos_disp = [ pos[k][l] + eigvec_i[k][l] * step_size + # * disp_step / norm_i for l in range(3)] + pos_lst.append(pos_disp) + + atoms_i = copy.deepcopy(atoms) + atoms_i.set_positions(pos_lst) + + master_pos_lst.append(atoms_i) + + eig_str = str(round(eigval_i, 3)).zfill(3) + + eig_str_lst = str(round(eigval_i, 3)).split(".") + eig_str = eig_str_lst[0].zfill(4) + "." + eig_str_lst[1].ljust(3, "0") + + lead_num = str(index).zfill(2) + folder_i = path_i + vis_dir + "/" + lead_num + "_" + eig_str + "_cm-1/" + + if not os.path.isdir(folder_i): + os.makedirs(folder_i) + + + out_traj_file = folder_i + "out-" + eig_str + ".traj" + if os.path.isfile(out_traj_file): + continue + + print("#####################################################") + print("Creating: " + folder_i + "out-" + eig_str + ".traj") + print("#####################################################") + + + io.write(out_traj_file, master_pos_lst) + + if create_gifs: + create_gif_from_atoms_movies( + atoms_file="Default", + path_i=folder_i, + delay=10, + ) + + with open(".FINISHED", "w") as fle: + fle.write("") + #__| + +def create_vdw_kernel_symlink(): + """ + If on the SLAC cluster, symlinks the vdw vasp kernel into the job directory, + otherwise does nothing + """ + #| - create_vdw_kernel_symlink + if os.getenv("COMPENV") == "slac": + print("TEMP - 180313 !@#") + if not (os.path.exists("vdw_kernel.bindat")): + os.symlink( + "/nfs/slac/g/suncatfs/sw/vasp/vdw_kernel.bindat", + "vdw_kernel.bindat", + ) + + + # target = "/nfs/slac/g/suncatfs/sw/vasp/vdw_kernel.bindat" + # tmpLink = "temp_vdw_kernel" + # linkName = "vdw_kernel.bindat" + # os.symlink(target, tmpLink) + # os.rename(tmpLink, linkName) + + elif os.getenv("COMPENV") == "sherlock": + pass + + if os.getenv("AWS_BATCH_JOB_ID") is None: + pass + + #__| + + +def parse_incar(incar_list): + """Manipulate INCAR data into python dictionary with correct data types. + + Args: + incar_list: + INCAR file in python list where each line represents a line from + the file. + """ + #| - parse_incar + incar_1 = [line for line in incar_list if " = " in line] + + incar_dict = {} + for line in incar_1: + line_i = line.split("=") + mess = "Each incar row should have 1 equals sign which " + mess += "will be parsed into the LHS (key) and RHS (value)" + assert len(line_i) == 2, mess + incar_dict.update({line_i[0].strip(): line_i[1].strip()}) + + #| - Incar keys list + # incar_keys = [ + # "ENCUT", + # "AMIX_MAG", + # "BMIX_MAG", + # "BMIX", + # "SIGMA", + # "AMIX", + # "EDIFF", + # "EDIFFG", + # "PREC", + # "GGA", + # "ALGO", + # "ISMEAR", + # "NPAR", + # "LDAUPRINT", + # "NELM", + # "IBRION", + # "IDIPOL", + # "ISIF", + # "ISPIN", + # "INIMIX", + # "NSW", + # "LORBIT", + # "LMAXMIX", + # "KPAR", + # "LDAUTYPE", + # "DIPOL", + # "LDAU", + # "LVTOT", + # "LDIPOL", + # "LASPH", + # "LREAL", + # "LDAUL", + # "LDAUU", + # "LDAUJ", + # ] + #__| + + #| - Incar Types Dict + + incar_types_dict = { + "ENCUT": "float", + "AMIX_MAG": "float", + "BMIX_MAG": "float", + "BMIX": "float", + "SIGMA": "float", + "AMIX": "float", + "EDIFF": "float", + "EDIFFG": "float", + + # string + "PREC": "string", + "GGA": "string", + "ALGO": "string", + + # float + "ISMEAR": "integer", + "NPAR": "integer", + "LDAUPRINT": "integer", + "NELM": "integer", + "IBRION": "integer", + "IDIPOL": "integer", + "ISIF": "integer", + "ISPIN": "integer", + "INIMIX": "integer", + "NSW": "integer", + "LORBIT": "integer", + "LMAXMIX": "integer", + "KPAR": "integer", + "LDAUTYPE": "integer", + + # [a, b, c] + "DIPOL": "list", + + # True/False + "LDAU": "boolean", + "LVTOT": "boolean", + "LDIPOL": "boolean", + "LASPH": "boolean", + + # string + "LREAL": "string", + + # [a, b] + "LDAUL": "list", + "LDAUU": "list", + "LDAUJ": "list", + } + #__| + + #| - Formatting Dict to Proper Data Types + formatted_incar_dict = {} + for key, value in incar_dict.items(): + + # if key == "LDIPOL": + # print(key) + # print(value) + # print("___;_-___--__") + + if key in incar_types_dict: + + data_type = incar_types_dict[key] + + if data_type == "float": + value_new = float(value) + elif data_type == "string": + # Basically leave it alone + value_new = value + elif data_type == "integer": + value_new = int(value) + elif data_type == "list": + # Figure this out later + value_new = value + elif data_type == "boolean": + if value == ".FALSE.": + value_new = False + elif value == ".TRUE.": + value_new = True + else: + value_new = "ERROR 0847589347" + + else: + value_new = value + else: + value_new = value + + formatted_incar_dict.update({key: value_new}) + #__| + + return(formatted_incar_dict) + + # return(incar_dict) + #__| From 3741e35d85176c5624b8e89bc8f4e7f4c9249257 Mon Sep 17 00:00:00 2001 From: Raul Flores Date: Tue, 3 Dec 2019 13:36:30 -0800 Subject: [PATCH 16/16] Mass update all --- ase_modules/ase_methods.py | 72 +- ase_modules/dft_params.py | 12 +- compute_envs/__init__.py | 0 compute_envs/nersc.py | 637 ++++++++++++++++++ compute_envs/nersc_sub/submit_cori.pbs | 5 + compute_envs/nersc_sub/submit_knl.pbs | 9 + dft_job_automat/__old__.py | 28 + dft_job_automat/compute_env.py | 152 +++-- dft_post_analysis/rapiDOS/README | 26 + dft_post_analysis/rapiDOS/rapiDOS.py | 376 +++++++++++ .../rapiDOS/rapiDOS_analysis.ipynb | 460 +++++++++++++ .../rapiDOS/rapiDOS_original_jose.py | 333 +++++++++ energetics/dft_energy.py | 15 +- misc_modules/image_processing.py | 53 ++ misc_modules/misc_methods.py | 59 +- .../oxr_plot_2d_volcano.py | 48 +- plotting/my_plotly.py | 94 +-- plotting/plotly_layout_template.py | 64 +- quantum_espresso/qe_methods.py | 2 +- surface_energy/surface_energy.py | 243 ++++++- .../surface_energy_pourbaix_plot.py | 39 ++ 21 files changed, 2593 insertions(+), 134 deletions(-) create mode 100644 compute_envs/__init__.py create mode 100644 compute_envs/nersc.py create mode 100644 compute_envs/nersc_sub/submit_cori.pbs create mode 100644 compute_envs/nersc_sub/submit_knl.pbs create mode 100644 dft_post_analysis/rapiDOS/README create mode 100644 dft_post_analysis/rapiDOS/rapiDOS.py create mode 100644 dft_post_analysis/rapiDOS/rapiDOS_analysis.ipynb create mode 100644 dft_post_analysis/rapiDOS/rapiDOS_original_jose.py create mode 100644 misc_modules/image_processing.py create mode 100644 surface_energy/surface_energy_pourbaix_plot.py diff --git a/ase_modules/ase_methods.py b/ase_modules/ase_methods.py index 7a9eb6c..527c913 100644 --- a/ase_modules/ase_methods.py +++ b/ase_modules/ase_methods.py @@ -30,6 +30,7 @@ from ase.io import read, write, Trajectory from ase import io +from ase.visualize import view from ase.dft.kpoints import ibz_points, get_bandpath from ase.vibrations import Vibrations from ase.thermochemistry import HarmonicThermo @@ -44,6 +45,11 @@ from quantum_espresso.qe_methods import estimate_magmom from bader_charge.bader import bader + +import tempfile +import shutil +import random +import string #__| #| - METHODS @@ -2217,6 +2223,70 @@ def create_species_element_dict( #__| ************************************************************************** #| - Visualization ************************************************************ + + +def view_in_vesta( + atoms, + ase_gui=False, + name_list=None, + ): + """ + + Args: + atoms: atoms object or list of atoms objects + ase_gui: Boolean + Whether to also show atoms with ase-gui + name_list: list or None + Optional list of names for cif files, easier to id structures when + opened in VESTA + """ + #| - view_in_vesta + def randomString(stringLength=10): + """Generate a random string of fixed length """ + letters = string.ascii_lowercase + return ''.join(random.choice(letters) for i in range(stringLength)) + + dirpath = tempfile.mkdtemp( + suffix=None, + prefix="RAUL_TEMP_DIR_", + ) + # dirpath = "/tmp/RAUL_TEMP_DIR_i5jjf29c" + + if type(atoms) == list: + atoms_list = atoms + else: + atoms_list = [atoms] + + bash_comm = "VESTA " + for i_cnt, atoms_i in enumerate(atoms_list): + if ase_gui: + view(atoms_i) + + file_i = randomString(stringLength=10) + + if name_list is not None: + mess_i = "name_list must be the same len as atoms_list" + assert len(name_list) == len(atoms_list), mess_i + filename_prepend = name_list[i_cnt] + file_i = str(i_cnt).zfill(3) + "_" + filename_prepend + "_" + file_i + + full_path_i = os.path.join( + dirpath, + file_i + ".cif") + atoms_i.write(full_path_i) + bash_comm += full_path_i + " " + bash_comm += "&" + print(bash_comm) + + os.system(bash_comm) + + + + # shutil.rmtree(dirpath) + #__| + + + def create_gif_from_traj( traj_name="qn.traj", path_i=".", @@ -2437,6 +2507,4 @@ def max_force(atoms): return(largest, sum) #__| - - #__| diff --git a/ase_modules/dft_params.py b/ase_modules/dft_params.py index c0f36c3..c1f7e7b 100644 --- a/ase_modules/dft_params.py +++ b/ase_modules/dft_params.py @@ -43,17 +43,19 @@ def load_submission_params(self, filename=".submission_params_2.json"): filename: Name of file containing submission parameters in a json file format. The file is created automatically from my - comp_env module when used in conjuction witht he job + comp_env module when used in conjuction with the job submission script. """ #| - load_submission_params + bkp_filename = ".submission_params.json" + submission_params = None if os.path.isfile(filename): with open(filename, "r") as fle: submission_params = json.load(fle) - elif os.path.isfile(".submission_params.json"): - with open(filename, "r") as fle: + elif os.path.isfile(bkp_filename): + with open(bkp_filename, "r") as fle: submission_params = json.load(fle) else: print("Couldn't read submission_params file") @@ -70,7 +72,7 @@ def load_params(self, dir=".", update_params=True): """ #| - load_params try: - data = open(dir + "/dft-params.json").read() + data = open(os.path.join(dir, "dft-params.json")).read() data = json.loads(data) if update_params is True: @@ -79,6 +81,8 @@ def load_params(self, dir=".", update_params=True): self.params = data except: + print("ase_modules/dft_params.py") + print(" Couldn't read dft-params.json file") pass #__| diff --git a/compute_envs/__init__.py b/compute_envs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/compute_envs/nersc.py b/compute_envs/nersc.py new file mode 100644 index 0000000..c34c1c6 --- /dev/null +++ b/compute_envs/nersc.py @@ -0,0 +1,637 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Class for computer cluster operations, mainly batch. + +""" + +#| - Import Modules +import os +import sys +import subprocess +import datetime +import copy +import time + +from shutil import copyfile + +# My Modules +from misc_modules.misc_methods import merge_two_dicts + +from dft_job_automat.compute_env import ComputerCluster +from dft_job_automat.compute_env import slurm_squeue_parse +#__| + + + +class NERSC_Cluster(ComputerCluster): + """NERSC computing cluster. + + Two main architectures, knl and haswell + """ + + #| - NERSC_Cluster ******************************************************** + def __init__(self, + root_dir=".", + ): + """Initialize Sherlock cluster instance. + + Args: + root_dir: + """ + #| - __init__ + # print(80 * "#") + # print(4 * "jfsd78yf7823w78yhs81") + # print(80 * "#") + + # nersc_host = os.environ["NERSC_HOST"] + + self.cores_per_node = 32 # <-- Cori Haswell + + self.default_sub_params = self.default_submission_parameters() + + + self.job_data_dir = "" + self.root_dir = root_dir + self.queues = self.__queue_types__() + self.job_state_keys = self.job_state_dict() + self.job_queue_state_key = "STAT" # COMBAK + self.error_file = "job.err" + self.out_file = "job.out" + #__| + + def submit_job_clust(self, **kwargs): + """Submit job to sherlck. + + Args: + **kwargs: + """ + #| - submit_job + time.sleep(1.5) + + #| - Merging Submission Parameters + params = merge_two_dicts(self.default_sub_params, kwargs) + + path = params["path_i"] + + # Fixing debug flag specification + if params["priority"] == "debug": + params["queue"] = "debug" + + if params["queue"] == "debug": + params["priority"] = "debug" + + if params["priority"] == "scavenger": + params["queue"] = "regular" + params["qos"] = "scavenger" + # params["queue"] = "regular" + + + if params["wall_time"] < 180: + + params["min_time"] = params["wall_time"] - 30 + else: + params["min_time"] = 180 + # --time-min=01:30:00 + + #__| + + self.__import_arch_class__(params) + + self.arch_inst.__make_run_vasp_script__(params) + + params = merge_two_dicts(params, self.arch_inst.sbatch_params) + + #| - Write submission script + + knl_sub_script = """#!/bin/bash +# KNL submission bash script + +module load vasp-tpc/5.4.4-knl + +# cd $SLURM_SUBMIT_DIR +# export TMPDIR=$SLURM_SUBMIT_DIR + +export OMP_NUM_THREADS=1 +export OMP_PLACES=threads +export OMP_PROC_BIND=spread + +export VASP_SCRIPT=./run_vasp.py +export VASP_PP_PATH=/project/projectdirs/m2997/vasp-psp/pseudo52 + +python ./model.py""" + + + + + cori_sub_script = """#!/bin/bash +# Cori submission bash script + +module load vasp-tpc/5.4.4-hsw + +# cd $SLURM_SUBMIT_DIR +# export TMPDIR=$SLURM_SUBMIT_DIR + +export VASP_SCRIPT=./run_vasp.py +export VASP_PP_PATH=/project/projectdirs/m2997/vasp-psp/pseudo52 + +python ./model.py""" + + if params["architecture"] == "knl": + sub_script = knl_sub_script + elif params["architecture"] == "haswell": + sub_script = cori_sub_script + else: + # TEMP + print("IJDIFJIJDSIFJs8df8sdd") + sub_script = None + + with open(os.path.join(path, 'submit_job.pbs'), 'w') as the_file: + the_file.write(sub_script) + #__| + + + #| - Submit Job + os.chdir(path) + if params["job_name"] == "Default": + params["job_name"] = os.getcwd() + + print("submitting job") + os.system("chmod 777 *") + # bash_command = "/u/if/flores12/bin/qv model.py" + #__| **** TEMP + + #| - Bash Submisssion Command + # The -q flag is being used in place of the -p flag + # Only the -q needs to be defined + + sbatch_to_param_key_dict = { + "constraints": "-C", + "out_file": "--output", + "err_file": "--error", + "wall_time": "--time", + "nodes": "--nodes", + "queue": "-q", + "tasks-per-node": "--tasks-per-node", + "account": "-A", + "qos": "--qos", + "min_time": "--time-min", + } + + + bash_command = "/usr/bin/sbatch " + for key, value in params.items(): + if key in sbatch_to_param_key_dict: + sbatch_key = sbatch_to_param_key_dict[key] + bash_command += sbatch_key + " " + bash_command += str(value) + " " + else: + tmp = 42 + + # print("kjfs8usd9fusd09") + # print(key, value) + + # bash_command += params["job_script"] + bash_command += "submit_job.pbs" + + print("Bash Submission Command:") + print(bash_command) + #__| + + try: + output = subprocess.Popen( + bash_command, + stdout=subprocess.PIPE, + shell=True, + ) + sub_time = datetime.datetime.now().isoformat() + # except subprocess.CalledProcessError, e: + except subprocess.CalledProcessError as e: + print("Ping stdout output:\n", e.output) + + os.chdir(self.root_dir) + print("JOB SKIPPED: ") + return(None) + + #| - Parsing Output + out, err = output.communicate() + out_copy = copy.deepcopy(out) + + try: + out = out.strip() + out_list = out.decode().split(" ") + job_id = int(out_list[-1]) + + except: + print("Couldn't parse for jobid") + job_id = None + #__| + + #| - Writing Files + with open(".SUBMITTED", "w") as fle: + fle.write("\n") + + with open(".bash_comm", "w") as fle: + fle.write(str(bash_command) + str("\n")) + + with open(".jobid", "w") as fle: + fle.write(str(job_id) + str("\n")) + + if sys.version_info >= (3, 0): + with open(".sub_out", "wb") as fle: + fle.write(out_copy) + + else: + with open(".sub_out", "w") as fle: + fle.write(out_copy) + #__| + + os.chdir(self.root_dir) + #__| + + + + def default_submission_parameters(self): + """Defaul SLURM parameters for Sherlock cluster.""" + #| - default_submission_parameters + + def_params = { + "queue": "regular", # -p flag | regular, debug + ##SBATCH -p regular + #SBATCH -p debug + "nodes": "10", + # 24 cpus per node on edison, 32 per node on cori haswell + #SBATCH -N 10 + + "account": "m2997", # -A flag + #SBATCH -A m2997 + + "wall_time": "180", + #SBATCH -t 00:30:00 + + + "priority": "regular", # --qos -q flag + # "priority": "scavenger", # --qos -q flag + + ##SBATCH --qos=scavenger + ##SBATCH --qos=premium + ##SBATCH --qos=debug + ##SBATCH --qos=regular + + "constraints": "haswell", + + ##SBATCH -C haswell #this is for cori haswell (old) + ##SBATCH -C knl #new cori + #SBATCH -e job.err#SBATCH -o job.out + + "architecture": "knl", + } + + return(def_params) + #__| + + + def __import_arch_class__(self, params): + """ + """ + #| - __import_arch_class__ + arch = params["architecture"] + + if arch == "knl": + arch_inst = KNL_Arch() + elif arch == "haswell": + arch_inst = Haswell_Arch() + + + self.arch_inst = arch_inst + #__| + + + #| - out of sight + + def job_state_dict(self): + """ + """ + #| - job_state_dict + job_state_dict = { + "PD": "PENDING", + "R": "RUNNING", + "CF": "CONFIGURING", + "SUCCEEDED": "SUCCEEDED", + + # "FAILED": "FAILED", + # "STARTING": "STARTING", + # "RUNNABLE": "PENDING", + # "SUBMITTED": "SUBMITTED", + } + + return(job_state_dict) + #__| + + + def __queue_types__(self): + """Queue types for Edison cluster + """ + #| - __queue_types__ + queue_list = [ + "regular", + "debug", + "premium", + ] + + return(queue_list) + #__| + + def job_info_batch(self, job_id, path_i=None): + """ + """ + #| - job_info_batch + data_dict = slurm_squeue_parse( + job_id, + path_i=path_i, + queue_state_key=self.job_queue_state_key, + job_state_dict=self.job_state_keys, + ) + + return(data_dict) + + #| - __old__ + # bash_comm = "squeue -j " + str(job_id) + # + # try: + # out = subprocess.check_output( + # bash_comm, + # shell=True, + # stderr=subprocess.STDOUT, + # ) + # + # # 'JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)' + # out = out.splitlines() + # out = out[1].split(" ") + # out = [i for i in out if i != ''] + # + # data_dict = { + # "PARTITION": out[1], + # "STAT": out[4], + # # "CF": + # } + # + # if path_i is not None: + # key = self.job_queue_state_key + # with open(path_i + "/.QUEUESTATE", "w") as fle: + # fle.write(self.job_state_keys[data_dict[key]]) + # fle.write("\n") + # + # except subprocess.CalledProcessError: + # data_dict = None + # pass + # + # except: + # data_dict = None + # pass + # + # + # return(data_dict) + # + # bash_comm = "squeue -j " + str(job_id) + # + # try: + # out = subprocess.check_output( + # bash_comm, + # shell=True, + # stderr=subprocess.STDOUT, + # ) + # + # # 'JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)' + # out = out.splitlines() + # out = out[1].split(" ") + # out = [i for i in out if i != ''] + # + # data_dict = { + # "PARTITION": out[1], + # "STAT": out[4], + # # "CF": + # } + # + # if path_i is not None: + # key = self.job_queue_state_key + # with open(path_i + "/.QUEUESTATE", "w") as fle: + # fle.write(self.job_state_keys[data_dict[key]]) + # fle.write("\n") + # + # except subprocess.CalledProcessError: + # data_dict = None + # pass + # + # except: + # print("tmp except final") + # data_dict = None + # pass + # + # # TEMP_PRINT + # print(data_dict) + # + # return(data_dict) + #__| + + #__| + + def completed_file(self, path_i="."): + """Check whether ".FINISHED" file exists. + + Indicates that the job has gone to completion + + Args: + path_i: + """ + #| - completed_file + completed_fle = False + if os.path.exists(path_i + "/.FINISHED"): + completed_fle = True + + return(completed_fle) + #__| + + def job_state(self, path_i="."): + """Return job state of path_i --> job_i. + + Args: + path_i + """ + #| - job_state + job_id = self.get_jobid(path_i=path_i) + + job_state_out = None + if job_id is not None: + job_info = self.job_info_batch(job_id, path_i=path_i) + + if job_info is not None: + key = self.job_queue_state_key + if key in job_info: + job_state_out = job_info[key] + job_state_out = self.job_state_keys[job_state_out] + + #| - Checking for "completed" file indicating success + completed_fle = self.completed_file(path_i=path_i) + if completed_fle: + job_state_out = self.job_state_keys["SUCCEEDED"] + #__| + + return(job_state_out) + #__| + + def get_jobid(self, path_i="."): + """Return job ID of job_i. + + Args: + path_i: + """ + #| - get_jobid + fileid_path = path_i + "/.jobid" + if os.path.isfile(fileid_path): + with open(path_i + "/.jobid") as fle: + jobid = fle.read().strip() + else: + jobid = None + + return(jobid) + #__| + + #__| + + #__| ********************************************************************** + + + + + +class KNL_Arch(): + """ + """ + + #| - KNL_Arch ************************************************************* + def __init__(self): + """Initialize Sherlock cluster instance. + + Args: + root_dir: + """ + #| - __init__ + self.vasp_module = "vasp-tpc/5.4.4-knl" + + # Actually 68 + self.cores_per_node = 66 + + self.__module_load_vasp__() + + self.sbatch_params = self.__self_sbatch_settings__() + + os.putenv("OMP_NUM_THREADS", "1") + os.putenv("OMP_PLACES", "threads") + os.putenv("OMP_PROC_BIND", "spread") + + os.putenv("TMPDIR", "$SLURM_SUBMIT_DIR") + os.putenv("VASP_SCRIPT", "./run_vasp.py") + #__| + + def __make_run_vasp_script__(self, params): + """ + """ + #| - __make_run_vasp_script__ + os.system("echo import os > run_vasp.py") + exitcode_line = "exitcode = os.system('srun -n" + " " + \ + str(int(self.cores_per_node * int(params["nodes"]))) + " " + \ + "-c 4 --cpu_bind=cores" + " " + \ + "vasp_std')" + line_2 = 'echo ' + '"' + exitcode_line + '" >> run_vasp.py' + os.system(line_2) # on edison + + + if params["path_i"] == ".": + pass + + else: + copyfile( + "run_vasp.py", + os.path.join(params["path_i"], "run_vasp.py"), + ) + + #__| + + def __self_sbatch_settings__(self): + """ + """ + #| - __self_sbatch_settings__ + def_params = { + "constraints": "knl", + "tasks-per-node": 66, + } + + return(def_params) + #__| + + def __module_load_vasp__(self): + """ + THIS DOESN'T WORK + """ + #| - __module_load_vasp__ + bash_comm = "module load " + self.vasp_module + + # TEMP + print("fjjisdjfjisdfu8h3w8whgiafd6gwgundssoijgg") + print(bash_comm) + os.system(bash_comm) + #__| + + #__| ********************************************************************** + + + + +class Haswell_Arch(): + """ + """ + + #| - Haswell_Arch ********************************************************* + def __init__(self): + """Initialize Sherlock cluster instance. + + Args: + root_dir: + """ + #| - __init__ + self.vasp_module = "vasp-tpc/5.4.4-hsw" + + # Actually 68 + self.cores_per_node = 32 + + self.sbatch_params = self.__self_sbatch_settings__() + #__| + + def __self_sbatch_settings__(self): + """ + """ + #| - __self_sbatch_settings__ + def_params = { + "constraints": "haswell", + # "tasks-per-node": 66, + } + + return(def_params) + #__| + + def __make_run_vasp_script__(self, params): + """ + """ + #| - __make_run_vasp_script__ + os.system("echo import os > run_vasp.py") + exitcode_line = "exitcode = os.system('srun -n" + " " + \ + str(int(self.cores_per_node * int(params["nodes"]))) + " " + \ + "vasp_std')" + line_2 = 'echo ' + '"' + exitcode_line + '" >> run_vasp.py' + os.system(line_2) # on edison + + + #__| + + #__| ********************************************************************** diff --git a/compute_envs/nersc_sub/submit_cori.pbs b/compute_envs/nersc_sub/submit_cori.pbs new file mode 100644 index 0000000..9f8f5aa --- /dev/null +++ b/compute_envs/nersc_sub/submit_cori.pbs @@ -0,0 +1,5 @@ +#!/bin/bash + +module load vasp-tpc/5.4.4-hsw + +python ./model.py diff --git a/compute_envs/nersc_sub/submit_knl.pbs b/compute_envs/nersc_sub/submit_knl.pbs new file mode 100644 index 0000000..7084003 --- /dev/null +++ b/compute_envs/nersc_sub/submit_knl.pbs @@ -0,0 +1,9 @@ +#!/bin/bash + +module load vasp-tpc/5.4.4-knl + +export OMP_NUM_THREADS=1 +export OMP_PLACES=threads +export OMP_PROC_BIND=spread + +python ./model.py diff --git a/dft_job_automat/__old__.py b/dft_job_automat/__old__.py index ffe6ee7..7c1c711 100644 --- a/dft_job_automat/__old__.py +++ b/dft_job_automat/__old__.py @@ -1,3 +1,31 @@ + + #| - __old__ + # def __parse_username__(self): + # """ + # """ + # #| - __parse_username__ + # username = os.environ.get("USER") + # + # cond_1 = False + # if type(username) == str: + # cond_1 = True + # + # cond_2 = False + # if username is not None: + # cond_2 = True + # + # print(cond_1) + # print(cond_2) + # + # print(username) + # print("*******") + # return(username) + # #__| + #__| + + + + #| - job_analysis #| - DEPRECATED METHODS diff --git a/dft_job_automat/compute_env.py b/dft_job_automat/compute_env.py index e428630..def0211 100644 --- a/dft_job_automat/compute_env.py +++ b/dft_job_automat/compute_env.py @@ -26,6 +26,7 @@ import time import pandas as pd +from shutil import copyfile import json @@ -66,7 +67,7 @@ def slurm_squeue_parse( # 'JOBID PARTITION NAME USER ST TIME NODES NODELIST(REASON)' out = out.splitlines() - out = out[1].split(" ") + out = out[1].decode().split(" ") out = [i for i in out if i != ''] data_dict = { @@ -115,30 +116,6 @@ def __init__(self, self.__parse_cluster_type__() #__| - #| - __old__ - # def __parse_username__(self): - # """ - # """ - # #| - __parse_username__ - # username = os.environ.get("USER") - # - # cond_1 = False - # if type(username) == str: - # cond_1 = True - # - # cond_2 = False - # if username is not None: - # cond_2 = True - # - # print(cond_1) - # print(cond_2) - # - # print(username) - # print("*******") - # return(username) - # #__| - #__| - def __parse_cluster_type__(self): """Parse for the current cluster system.""" #| - __parse_cluster_type__ @@ -153,7 +130,16 @@ def __parse_cluster_type__(self): if cluster_sys in clusters_dict: package = "dft_job_automat.compute_env" + + name = clusters_dict[cluster_sys] + + # TEMP Writing new NERSC module ################################### + if cluster_sys == "nersc": + package = "compute_envs.nersc" + name = "NERSC_Cluster" + # ################################################################# + cluster = getattr(__import__(package, fromlist=[name]), name) self.cluster_sys = cluster_sys @@ -292,7 +278,8 @@ def submit_job(self, **kwargs): #__| #| - Writing Job Submission Parameters - with open(".submission_params.json", "w") as fle: + sub_params_name = ".submission_params.json" + with open(os.path.join(path_i, sub_params_name), "w") as fle: json.dump(kwargs, fle, indent=2, skipkeys=True) #__| @@ -302,7 +289,7 @@ def submit_job(self, **kwargs): if "path_i" in kwargs: path_i = kwargs["path_i"] - with open(".cluster_sys", "w") as fle: + with open(os.path.join(path_i, ".cluster_sys"), "w") as fle: # fle.write(self.cluster_sys) fle.write(self.cluster_sys + "\n") #__| @@ -316,9 +303,7 @@ def submit_job(self, **kwargs): class EdisonCluster(ComputerCluster): """NERSC Edison computing cluster. - - - I'll try to get this to work with Cori as well + DEPRECATED """ #| - EdisonCluster ******************************************************** @@ -329,6 +314,20 @@ def __init__(self, root_dir="."): root_dir: """ #| - __init__ + print("THIS MODULE IS DEPRECATED") + print("USE THE ONE IN COMPUTE_ENVS") + print("THIS MODULE IS DEPRECATED") + print("USE THE ONE IN COMPUTE_ENVS") + print("THIS MODULE IS DEPRECATED") + print("USE THE ONE IN COMPUTE_ENVS") + print("THIS MODULE IS DEPRECATED") + print("USE THE ONE IN COMPUTE_ENVS") + print("THIS MODULE IS DEPRECATED") + print("USE THE ONE IN COMPUTE_ENVS") + print("THIS MODULE IS DEPRECATED") + print("USE THE ONE IN COMPUTE_ENVS") + print("THIS MODULE IS DEPRECATED") + print("USE THE ONE IN COMPUTE_ENVS") # 24 cores (edison) 32 cpus (cori) nersc_host = os.environ["NERSC_HOST"] @@ -434,6 +433,7 @@ def submit_job_clust(self, **kwargs): os.system("cd $SLURM_SUBMIT_DIR") os.system("export TMPDIR=$SLURM_SUBMIT_DIR") os.system("export VASP_SCRIPT=./run_vasp.py") + os.system("echo import os > run_vasp.py") exitcode_line = "exitcode = os.system('srun -n " + \ @@ -447,7 +447,6 @@ def submit_job_clust(self, **kwargs): #| - Bash Submisssion Command bash_command = "/usr/bin/sbatch " - # The -q flag is being used in place of the -p flag # Only the -q needs to be defined bash_command += "-q " + str(params["queue"]) + " " @@ -814,7 +813,9 @@ def default_submission_parameters(self): #| - default_submission_parameters def_params = { "queue": "suncat", - "cpus": "8", + "cpus": "10", + "nodes": "1", + "wall_time": "3000", # "memory": "6000", # "job_name": "Default", @@ -858,9 +859,15 @@ def submit_job_clust(self, **kwargs): # bash_command = "/u/if/flores12/bin/qv model.py" - bash_command = "/afs/slac/g/suncat/bin/dobsub " + # bash_command = "/afs/slac/g/suncat/bin/dobsub " + bash_command = "dobsub " bash_command += "-q " + str(params["queue"]) + " " + + # Not sure why, but the -n flag is used to specify the numer of cores bash_command += "-n " + str(params["cpus"]) + " " + # bash_command += "-n " + str(params["nodes"]) + " " + # bash_command += "-c " + str(params["cpus"]) + " " + bash_command += "-W " + str(params["wall_time"]) + " " bash_command += "-o " + str(params["out_file"]) + " " bash_command += "-e " + str(params["err_file"]) + " " @@ -933,7 +940,8 @@ def submit_job_clust(self, **kwargs): #__| #| - Parsing Output - out = output.communicate()[0] + # out = output.communicate()[0] + out = output.communicate()[0].decode() ind = out.find("Job <") out1 = out[ind:] @@ -976,6 +984,9 @@ def get_jobid(self, path_i="."): if os.path.isfile(path_i + "/.jobid"): with open(path_i + "/.jobid") as fle: jobid = fle.read().strip() + + if jobid == "None": + jobid = None else: jobid = None @@ -998,7 +1009,7 @@ def job_info_batch(self, path_i="."): bash_comm, shell=True, stderr=subprocess.STDOUT, - ) + ).decode() #| - Checking if Job Id Still in Batch System if "is not found" in out: @@ -1039,7 +1050,17 @@ def job_info_batch(self, path_i="."): #| - write_job_queue_state_file key = self.job_queue_state_key with open(path_i + "/.QUEUESTATE", "w") as fle: - fle.write(self.job_state_keys[data_dict[key]]) + + # fle.write(self.job_state_keys[data_dict[key]]) + + fle.write( + self.job_state_keys.get( + data_dict[key], + data_dict[key], + ), + ) + + fle.write("\n") #__| @@ -1061,7 +1082,11 @@ def job_state(self, path_i="."): key = self.job_queue_state_key if key in job_info: job_state_out = job_info[key] - job_state_out = self.job_state_keys[job_state_out] + job_state_out = self.job_state_keys.get( + job_state_out, + job_state_out, + ) + else: job_state_out = None @@ -1101,6 +1126,8 @@ def __init__(self, root_dir="."): self.error_file = "job.err" self.out_file = "job.out" + self.cores_per_node = 16 + # self.aws_dir = os.environ["aws_sc"] # self.job_queue_dir = self.aws_dir + "/jobs_bin" @@ -1126,6 +1153,29 @@ def __parse_username__(self): #__| + def __make_run_vasp_script__(self, params): + """ + """ + #| - __make_run_vasp_script__ + os.system("echo import os > run_vasp.py") + exitcode_line = "exitcode = os.system('srun -n" + " " + \ + str(int(self.cores_per_node * int(params["nodes"]))) + " " + \ + "vasp_std_544_161018')" + # "-c 4 --cpu_bind=cores" + " " + \ + line_2 = 'echo ' + '"' + exitcode_line + '" >> run_vasp.py' + os.system(line_2) # on edison + + + if params["path_i"] == ".": + pass + + else: + copyfile( + "run_vasp.py", + os.path.join(params["path_i"], "run_vasp.py"), + ) + #__| + def default_submission_parameters(self): """Defaul SLURM parameters for Sherlock cluster.""" #| - default_submission_parameters @@ -1138,9 +1188,11 @@ def default_submission_parameters(self): "wall_time": "720", # --time (720min -> 12hrs) "job_name": "Default", # --job-name "priority": "normal", # --qos - # "email": "flores12@stanford.edu", # --mail-user "email": self.username + "@stanford.edu", # --mail-user - "email_mess": "FAIL", # --mail-type + + # NONE, BEGIN, END, FAIL, REQUEUE, ALL + # "email_mess": "FAIL", # --mail-type + "email_mess": "END", # --mail-type } return(def_params) @@ -1161,6 +1213,9 @@ def submit_job_clust(self, **kwargs): path = params["path_i"] #__| + self.__make_run_vasp_script__(params) + + #| - Submit Job os.chdir(path) @@ -1172,6 +1227,7 @@ def submit_job_clust(self, **kwargs): # bash_command = "/u/if/flores12/bin/qv model.py" #__| **** TEMP + #| - Bash Submisssion Command bash_command = "/usr/bin/sbatch " @@ -1869,4 +1925,22 @@ def submit_job_clust(self, **kwargs): print("Nothing happens!!") #__| + def job_state(self, path_i="."): + """ + """ + #| - job_state + return("TEMP") + + # job_info = self.job_info_batch(path_i=path_i) + # if job_info is not None: + # key = self.job_queue_state_key + # if key in job_info: + # job_state_out = job_info[key] + # job_state_out = self.job_state_keys[job_state_out] + # else: + # job_state_out = None + # return(job_state_out) + #__| + + #__| diff --git a/dft_post_analysis/rapiDOS/README b/dft_post_analysis/rapiDOS/README new file mode 100644 index 0000000..028908c --- /dev/null +++ b/dft_post_analysis/rapiDOS/README @@ -0,0 +1,26 @@ + +----------------------------------------------- +rapiDOS v.0.6.1 +-- Aug. - 20 - 2019 -- +Jose A. Garrido Torres & Michal Bajdich. +jagt@stanford.edu & bajdich@slac.stanford.edu +----------------------------------------------- + +# (1) Requirements: + +python -m pip install jupyter --user +python -m pip install pandas --user +python -m pip install ase --user +python -m pip install seaborn --user + +# (2) Then you will have to copy the source files to your working directory +(The working directory must contain the output files from the VASP run): + +cp rapiDOS.py rapiDOS_analysis.ipynb ../calculation_dir +cd ../calculation_dir + +# (3) Execute the code: +python rapiDOS.py + +# (4) The code will create the dataframes and will automatically open +the jupyter notebook in your default browser. diff --git a/dft_post_analysis/rapiDOS/rapiDOS.py b/dft_post_analysis/rapiDOS/rapiDOS.py new file mode 100644 index 0000000..9117ff7 --- /dev/null +++ b/dft_post_analysis/rapiDOS/rapiDOS.py @@ -0,0 +1,376 @@ +""" + rapiDOS v.0.5.1 + -- Feb. - 19 - 2018 -- + Jose A. Garrido Torres & Michal Bajdich. + jagt@stanford.edu & bajdich@slac.stanford.edu +""" + +#| - Import Modules +import numpy as np +from ase import io +import re +import pandas as pd +import os +# __| + + +#| - Script Inputs +# data_folder = "/home/raulf2012/__temp__/irox_bulk_systems/IrO2/_1" +# +# out_folder = "out_data" +# __| + + +############################################################################## +# Code adapted from split_dos.py which belongs to Jonsson and Henkelman groups. +# URL: http://theory.cm.utexas.edu/vtsttools/scripts.html +############################################################################## + +#| - Methods +# ### READ DOSCAR ### +def read_dosfile(data_folder): + #| - read_dosfile + f = open(os.path.join(data_folder, "DOSCAR"), 'r') + lines = f.readlines() + f.close() + index = 0 + natoms = int(lines[index].strip().split()[0]) + index = 5 + nedos = int(lines[index].strip().split()[2]) + efermi = float(lines[index].strip().split()[3]) + print(natoms, nedos, efermi) + + return lines, index, natoms, nedos, efermi + #__| + +# ### READ POSCAR or CONTCAR and save pos +def read_posfile(data_folder): + #| - read_posfile + from ase.io import read + + try: + atoms = read(os.path.join(data_folder, 'POSCAR')) + except IOError: + print("[__main__]: Couldn't open input file POSCAR, atomic positions will not be written...\n") + atoms = [] + + return atoms + #__| + +# ### WRITE DOS0 CONTAINING TOTAL DOS ### +def write_dos0(lines, index, nedos, efermi, out_folder): + #| - write_dos0 + fdos = open(os.path.join(out_folder, "DOS0"), 'w') + line = lines[index + 1].strip().split() + ncols = int(len(line)) + # fdos.write('# %d \n' % (ncols)) #GH not sure why this is here + + for n in range(nedos): + index += 1 + e = float(lines[index].strip().split()[0]) + e_f = e - efermi + fdos.write('%15.8f ' % (e_f)) + + for col in range(1, ncols): + dos = float(lines[index].strip().split()[col]) + fdos.write('%15.8f ' % (dos)) + fdos.write('\n') + return index + #__| + +# ### LOOP OVER SETS OF DOS, NATOMS ### +def write_nospin(lines, index, nedos, natoms, ncols, efermi, data_folder, out_folder): + #| - write_nospin + atoms = read_posfile(data_folder) + if len(atoms) < natoms: + pos = np.zeros((natoms, 3)) + else: + pos = atoms.get_positions() + + for i in range(1, natoms + 1): + si = str(i) + + # ## OPEN DOSi FOR WRITING ## + fdos = open(os.path.join(out_folder, "DOS" + si), 'w') + index += 1 + ia = i - 1 + # fdos.write('# %d \n' % (ncols)) + fdos.write('# %15.8f %15.8f %15.8f \n' % (pos[ia, 0], pos[ia, 1], pos[ia, 2])) + + # ### LOOP OVER NEDOS ### + for n in range(nedos): + index += 1 + e = float(lines[index].strip().split()[0]) + e_f = e - efermi + fdos.write('%15.8f ' % (e_f)) + + for col in range(1, ncols): + dos = float(lines[index].strip().split()[col]) + fdos.write('%15.8f ' % (dos)) + fdos.write('\n') + fdos.close() + #__| + +def write_spin(lines, index, nedos, natoms, ncols, efermi, data_folder, out_folder): + #| - write_spin + #pos=[] + atoms = read_posfile(data_folder) + if len(atoms) < natoms: + pos = np.zeros((natoms, 3)) + else: + pos = atoms.get_positions() + + nsites = (ncols - 1) / 2 + + for i in range(1, natoms + 1): + si = str(i) + # ## OPEN DOSi FOR WRITING ## + fdos = open(os.path.join(out_folder, "DOS" + si), 'w') + index += 1 + ia = i - 1 + fdos.write('# %d \n' % (ncols)) + fdos.write('# %15.8f %15.8f %15.8f \n' % (pos[ia, 0], pos[ia, 1], pos[ia, 2])) + + # ### LOOP OVER NEDOS ### + for n in range(nedos): + index += 1 + e = float(lines[index].strip().split()[0]) + e_f = e - efermi + fdos.write('%15.8f ' % (e_f)) + + for site in range(int(nsites)): + dos_up = float(lines[index].strip().split()[site * 2 + 1]) + dos_down = float(lines[index].strip().split()[site * 2 + 2]) * -1 + fdos.write('%15.8f %15.8f ' % (dos_up, dos_down)) + fdos.write('\n') + fdos.close() + #__| + + +def get_bandgap(total_dos): + #| - get_bandgap + arg_fermi = np.where(total_dos[:, 0] > 0)[0][0] + arg_fermi_upper = arg_fermi + arg_fermi_lower = arg_fermi + band_tolerance = 5e-2 + + converged = False + while not converged: + occup_lower = total_dos[:, 1][arg_fermi_lower] + occup_upper = total_dos[:, 1][arg_fermi_upper] + + if occup_lower > band_tolerance: + arg_fermi_lower = arg_fermi_lower + 1 + if occup_upper > band_tolerance: + arg_fermi_upper = arg_fermi_upper - 1 + + if occup_lower > band_tolerance and occup_upper > band_tolerance: + converged = True + e_lower = total_dos[arg_fermi_lower][0] + e_upper = total_dos[arg_fermi_upper][0] + band_gap = e_lower - e_upper + arg_fermi_lower = arg_fermi_lower - 1 + arg_fermi_upper = arg_fermi_upper + 1 + + print("Approx. band gap: ", np.abs(band_gap), "eVv") + return [e_lower, e_upper, band_gap] + #__| + +# __| + +# if __name__ == '__main__': + +def rapiDOS( + data_folder=None, + out_folder=None, + ): + """ + """ + #| - __main__ ************************************************************* + if data_folder is None: + data_folder = "." + + if out_folder is None: + out_folder = "." + + if not os.path.exists(out_folder): + os.makedirs(out_folder) + + ########################################################################### + # Get general information of the system: + ########################################################################### + + # atoms = io.read('CONTCAR') # Open CONTCAR file + atoms = io.read(os.path.join(data_folder, 'CONTCAR')) # Open CONTCAR file + range_of_atoms = range(len(atoms)) # Number of atoms. + atomic_numbers = atoms.get_atomic_numbers() # Atomic number of the atoms. + atomic_symbols = atoms.get_chemical_symbols() # Chemical symbol of the atoms. + # outcar_file = io.read('OUTCAR', format='vasp-out') + outcar_file = io.read(os.path.join(data_folder, 'OUTCAR'), format='vasp-out') + + ########################################################################### + + + ########################################################################### + # Check spin: + ########################################################################### + + incar_file = open(os.path.join(data_folder, "INCAR"), "r") + ispin = 1 # Non spin polarised calculations. + for line in incar_file: + if re.match("(.*)ISPIN(.*)2", line): + ispin = 2 # For spin polarised calculations. + + ########################################################################### + + + ########################################################################### + # Check scale: + ########################################################################### + + # KBLOCK scales DOSCAR (See VASP Manual). + for line in open(os.path.join(data_folder, 'OUTCAR')): + if line.find('KBLOCK') != -1: + ckblock = line.split() + for i in range(0, len(ckblock)): + if ckblock[i] == 'KBLOCK': kblock = float(ckblock[i + 2]) + + ########################################################################### + + + # import sys + # import os + # import datetime + # import time + # import optparse + + lines, index, natoms, nedos, efermi = read_dosfile(data_folder) + index = write_dos0(lines, index, nedos, efermi, out_folder) + # ## Test if a spin polarized calculation was performed ## + line = lines[index + 2].strip().split() + ncols = int(len(line)) + if ncols == 7 or ncols == 19 or ncols == 9 or ncols == 33: + write_spin(lines, index, nedos, natoms, ncols, efermi, data_folder, out_folder) + is_spin = True + else: + write_nospin(lines, index, nedos, natoms, ncols, efermi, data_folder, out_folder) + is_spin = False + print("Spin unrestricted calculation: ", is_spin) + print(ncols) + + + ########################################################################### + + + ########################################################################### + # Define the columns of the database for the PDOS: + ########################################################################### + + if ispin == 2: + if ncols < 19: + pdos_columns = ['Energy (E-Ef)', 's_up', 's_down', 'py_up', 'py_down', + 'pz_up', 'pz_down', 'px_up', 'px_down', 'Element', 'Atom Number', + 'Atom Label'] + if ncols == 19: + pdos_columns = ['Energy (E-Ef)', 's_up', 's_down', 'py_up', + 'py_down', 'pz_up', 'pz_down', 'px_up', 'px_down', 'dxy_up', + 'dxy_down', 'dyz_up', 'dyz_down', 'dz2_up', 'dz2_down', 'dxz_up', + 'dxz_down', 'dx2_up', 'dx2_down', 'Element', 'Atom Number', + 'Atom Label'] + if ncols > 19: + pdos_columns = ['Energy (E-Ef)', 's_up', 's_down', 'py_up', 'py_down', + 'pz_up', 'pz_down', 'px_up', 'px_down', 'dxy_up', 'dxy_down', + 'dyz_up', 'dyz_down', 'dz2_up', 'dz2_down', 'dxz_up', 'dxz_down', + 'dx2_up', 'dx2_down', 'f1_up', 'f1_down', 'f2_up', 'f2_down', 'f3_up', + 'f3_down', 'f4_up', 'f4_down', 'f5_up', 'f5_down', 'f6_up', + 'f6_down', 'Element', 'Atom Number', 'Atom Label'] + + if ispin != 2: + if ncols < 10: + pdos_columns = ['Energy (E-Ef)', 's_up', 'py_up', 'pz_up', 'px_up', 'Atom Label'] + if ncols == 10: + pdos_columns = ['Energy (E-Ef)', 's_up', 'py_up', 'pz_up', 'px_up', 'dxy_up', 'dyz_up', + 'dz2_up', 'dxz_up', 'dx2_up', 'Element', 'Atom Number', 'Atom Label'] + if ncols > 10: + pdos_columns = ['Energy (E-Ef)', 's_up', 'py_up', 'pz_up', 'px_up', 'dxy_up', 'dyz_up', + 'dz2_up', 'dxz_up', 'dx2_up', 'f1_up', 'f2_up', 'f3_up', 'f4_up', 'f5_up', 'f6_up', 'Element', + 'Atom Number', 'Atom Label'] + + ########################################################################### + + + ########################################################################### + # Build pandas dataframe for total DOS: + ########################################################################### + + total_dos = np.loadtxt(os.path.join(out_folder, 'DOS0'), skiprows=0) # Load file total DOS from DOS0. + total_dos[:, 1:] = total_dos[:, 1:] * kblock # Scale (See kblock VASP). + + + if ispin == 2: + total_dos_columns = ['Energy (E-Ef)', 'Total DOS Spin Up', 'Total DOS ' + 'Spin ' + 'Down', 'Integrated DOS Spin Up', 'Integrated DOS Spin Down'] + if ispin != 2: + total_dos_columns = ['Energy (E-Ef)', 'Total DOS Spin Up', 'Integrated DOS'] + + total_dos_df = pd.DataFrame(total_dos, columns=total_dos_columns) + + ########################################################################### + + + ########################################################################### + # Build pandas dataframe for PDOS: + ########################################################################### + + pdos_df = pd.DataFrame([], columns=pdos_columns) + + for i in range_of_atoms: + dos_atom_i = np.loadtxt(os.path.join(out_folder, 'DOS' + str(i + 1)), skiprows=0) # Load the DOSxx files. + dos_atom_i[:, 1:] = dos_atom_i[:, 1:] # Do NOT scale PDOS (See KBLOCK VASP). + index_i = str(atomic_symbols[i]) # Element + index_i2 = str(i + 1) # Atom Number. + index_i3 = str(atomic_symbols[i] + str(i + 1)) # Element index. + column_index_i = np.repeat(index_i, len(dos_atom_i)) + column_index_i2 = np.repeat(index_i2, len(dos_atom_i)) + column_index_i3 = np.repeat(index_i3, len(dos_atom_i)) + column_index_i = np.reshape(column_index_i, (len(column_index_i), 1)) + column_index_i2 = np.reshape(column_index_i2, (len(column_index_i2), 1)) + column_index_i3 = np.reshape(column_index_i3, (len(column_index_i3), 1)) + dos_atom_i = np.append(dos_atom_i, column_index_i, axis=1) # Append Element. + dos_atom_i = np.append(dos_atom_i, column_index_i2, axis=1) # Append Atom N. + dos_atom_i = np.append(dos_atom_i, column_index_i3, axis=1) # Append Label. + pdos_df_i = pd.DataFrame(dos_atom_i, columns=pdos_columns) + pdos_df = pd.DataFrame.append(pdos_df_i, pdos_df, ignore_index=True) + + ########################################################################### + + + ########################################################################### + # Get band gap: + ########################################################################### + + band_gap = get_bandgap(total_dos) + band_gap_columns = ['Lower Band Gap', 'Upper Band Gap', 'Band Gap'] + band_gap_df = pd.DataFrame([band_gap], columns=band_gap_columns) + + ########################################################################### + + + ########################################################################### + # Save files for Jupyter notebook + ########################################################################### + + total_dos_df.to_csv(os.path.join(out_folder, 'TotalDOS.csv')) + pdos_df.to_csv(os.path.join(out_folder, 'PDOS.csv')) + band_gap_df.to_csv(os.path.join(out_folder, 'BandGap.csv')) + + ########################################################################### + + # Open example file (rapiDOS_analysis.ipynb) using Jupyter Notebook. + + # os.system('jupyter notebook rapiDOS_analysis.ipynb') + #use the second to run it without a browser + #os.system('jupyter nbconvert --to notebook --execute rapiDOS_analysis.ipynb') + + #__| diff --git a/dft_post_analysis/rapiDOS/rapiDOS_analysis.ipynb b/dft_post_analysis/rapiDOS/rapiDOS_analysis.ipynb new file mode 100644 index 0000000..9ab40d2 --- /dev/null +++ b/dft_post_analysis/rapiDOS/rapiDOS_analysis.ipynb @@ -0,0 +1,460 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### rapiDOS v.0.5.1 -- (build Feb. - 19 - 2018) -- \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Set environment" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "import os\n", + "import re\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "pd.set_option('display.max_rows', 20) # Set maximum number of col. df display.\n", + "\n", + "# Check spin polarized calculations:\n", + "incar_file = open(\"INCAR\", \"r\")\n", + "ispin = 1 # Non spin polarised calculations.\n", + "for line in incar_file:\n", + " if re.match(\"(.*)ISPIN(.*)2\", line):\n", + " ispin = 2 # For spin polarised calculations." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load data .csv files" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "total_dos_df = pd.read_csv('TotalDOS.csv')\n", + "pdos_df = pd.read_csv('PDOS.csv')\n", + "band_gap_df = pd.read_csv('BandGap.csv')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Approximate band gap:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Approx. Band Gap: 2.537 eV\n" + ] + } + ], + "source": [ + "band_gap = band_gap_df\n", + "band_gap_lower = band_gap['Lower Band Gap'][0]\n", + "band_gap_upper = band_gap['Upper Band Gap'][0]\n", + "print('Approx. Band Gap:',np.round(np.abs(band_gap['Band Gap'][0]),3), \"eV\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 1. Plot total DOS." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAm0AAAF3CAYAAAD3rnzeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJzs3Xd4VFX+x/H3uXdaGi2E0JvSW+hC\nAJdlRcCuoKioC4LKWlBcUVfErthZUGy4Cvb6UxfRtawKiI0mVVB6EkhCSM8k087vjwSWnjYzd5J8\nX8/DI8y9c84nQPA7556itNYIIYQQQojIZlgdQAghhBBClE+KNiGEEEKIGkCKNiGEEEKIGkCKNiGE\nEEKIGkCKNiGEEEKIGkCKNiGEEEKIGkCKNiGEEEKIGkCKNiGEEEKIGkCKNiGEEEKIGkCKNiGEEEKI\nGsBmdYBQaNy4sW7btq3VMYQQolbwFhcTCATC3m8g4Gd/1gEaxzfCMMyw91/bGYaB3eWyOoYAVq1a\ntV9rnVDefbWyaGvbti0rV660OoYQQtQKO9asJLp+g7D3uy89naTBQ/jik49ompgY9v5ru6LcHNr1\n7md1DAEopXZV5D55PCqEECIiNY6P54evv6JxfLzVUYSICLVypE0IIUTNZ7PZaNe2jdUxhIgYMtIm\nhBAiIqVnZNChV2/SMzKsjiJERJCRNiGEEBFJa01+QQFaa6ujHJc/ECCvxIPPgkUawaANG5s3b7Y6\nRp3icrlo2bIldru9Su+Xok0IIYSogrwSDw0axdOoYQOUUlbHqbSA348zOsbqGHWG1pqsrCxSUlJo\n165dldqQx6NCCCFEFfgCgRpbsInwU0oRHx9PcXFxlduQok0IIUREio2J4dabbiQ2JnJHg6RgE5VR\n3b8vUrQJIYSISLGxsdw27SZiY2OtjhJxsrKy6DdgIP0GDKRVm7a0bd/+0K89Hs8x9x84cIAXX3qp\n3HZ9Ph8NGhy7J5/P58M0TZKSkujatStJSUnMmTPniE2Xly5dSv/+/encuTOdO3fm5ZdfPnRt8+bN\nnH766SQlJdGlSxemTp16TB9+v5/rr7+e7t2706NHDwYMGMCuXSffvuyuu+7im2++KffrOmjBggXc\nfPPNR7w2ZMgQ1q5dW+E2rCRz2oQQQkSk3Lw8Zj/1NHdMv4X69epZHSeixMfHs/LnnwC4/4EHiY2N\nYfott5zw/gPZ2bz40gKumTKlyn3GxcUdKm7S09MZP348+fn53H333aSlpTFhwgQ++eQTkpKSyMzM\nZOTIkbRo0YJRo0Zxww03MGPGDM466yy01mzYsOGY9t98802ysrJYt24dhmGwe/du6pXz5/7QQw9V\n+eupiWSkTQghRERyu9288trruN1uq6PUKE88+SRJffqS1Kcvz86fD8BdM2eydetW+g0YyD9mziQv\nL48zR4+hT58+9OzZk8WLF1eqj8TERF544QXmzZsHwLx585g8eTJJSUkAJCQkMHv2bB599FEA9u7d\nS8uWLYHSR4Q9evQ4ps29e/fSrFkzDKO0NGndujUNGjQ4NPp300030a1bN8444wyysrIAmDBhAh99\n9BEALVu25N5776V379707NmTrVu3VuprOlk/kUJG2oQQQohqynzscUq2bAlqm85OnUiYcVul3vPz\nzz/z1tvv8MP3y/H5fAweMpRhw4bx0IMPsm3b9kOjc16vl/feeZuEps3IyMggOTmZs88+u1J9dezY\nEbfbTVZWFhs3buTaa6894nq/fv3YuHEjANOnT2fYsGEkJyczcuRIJk6cSP369Y+4f/z48QwdOpRv\nv/2WESNGMGHChENFYG5uLsnJycydO5dZs2bxwAMPMGfOnGMyJSYmsmbNGubOnctTTz3F888/X6mv\nqaL9WEVG2oQ4Ca01xVu24C8otDqKEEKU6/sVK7jg/POJiooiLi6Oc885h++///6Y+7TWzJw1i549\nezJy5Ej27NnD/v37K91fRffQmzx5Mps2bWLs2LF8/fXXDBo06Ji5d61bt2bLli2HHnkOHz6cb7/9\nFig9HWPcuHFA6eja8uXLj9vPhRdeCEDfvn3ZuXPnMddPtBDg4OsV7ccqMtImxAn4Dhwgdfp0in78\nCSM2lqb33EP9cyr3SVQIUXWmadK2dWtM07Q6SrkqOyJmtddff4Pc3DxWr16NzWajZcuWld6KYuvW\nrURHRxMfH0/Xrl1ZtWoVZ5111qHrq1atolu3bod+3aJFCyZNmsSkSZPo3LkzmzdvplevXke06XK5\nGDNmDGPGjKFx48Z8/PHHDBky5Ji+T1R8OZ1OoPTvjs/nO+Z6fHw82dnZR7x24MABGjdufNz2Im11\nsIy0CXEC6Q89TNGq1biumYJq3Zq9d99NybZtVscSos5IaNyYH7/5moQT/A9VHGtIcjIff/IJbreb\n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\nQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = plt.figure(figsize=(10.0,6.0)) # Create figure.\n", + "plt.axvline(x=[0.0], color='k', linestyle='--',linewidth=1.2) # Plot vertical line in Fermi.\n", + "plt.plot(total_dos_df['Energy (E-Ef)'],total_dos_df['Total DOS Spin Up'],color='C3') # Plot DOS spin up.\n", + "plt.fill_between(total_dos_df['Energy (E-Ef)'], \n", + " 0, total_dos_df['Total DOS Spin Up'],\n", + " facecolor='C7', alpha=0.2, interpolate=True) # Fill between spin up and down.\n", + "plt.axvspan(band_gap_lower, band_gap_upper, alpha=0.2, color='C5')\n", + "\n", + "if ispin == 2:\n", + " plt.plot(total_dos_df['Energy (E-Ef)'],-total_dos_df['Total DOS Spin Down'],color='C4') # Plot DOS spin down.\n", + " plt.fill_between(total_dos_df['Energy (E-Ef)'], \n", + " 0, -total_dos_df['Total DOS Spin Up'],\n", + " facecolor='C7', alpha=0.2, interpolate=True) # Fill between spin up and down.\n", + " \n", + "plt.legend() # Add legend to the plot.\n", + "plt.xlabel('E - Ef (eV)') # x axis label.\n", + "plt.ylabel('DOS (states/eV)') # x axis label.\n", + "plt.xlim([-8.0,4.0]) # Plot limits.\n", + "\n", + "fig.savefig(\"Fig1.pdf\") # Save figure EPS." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Double check that the maximum DOS value of the total DOS is consistent with p4vasp:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Max DOS (using this script) = 8.312999999999999 states/eV\n" + ] + } + ], + "source": [ + "max_dos = total_dos_df['Total DOS Spin Up'].max() \n", + "print('Max DOS (using this script) = ', max_dos, 'states/eV')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Example 2. PDOS: Plot total p$_z$ and d$_{z^2}$ states." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAmMAAAF3CAYAAADpZ0xtAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJzs3Xd8VfX9+PHXuSN3Zg8gEAiy9zCg\niCCKWJzfWkVqXYjiwqq1oNXagq1batWKo6hYtVbqLPpz42BUhbD3UELI3uvu8fn9ERKlMjJucm6S\n9/NhHoR7z/mc940Jed/3+XzeH00phRBCCCGE0IdB7wCEEEIIIboyScaEEEIIIXQkyZgQQgghhI4k\nGRNCCCGE0JEkY0IIIYQQOpJkTAghhBBCR5KMCSGEEELoSJIxIYQQQggdSTImhBBCCKEjScaEEEII\nIXRk0juA5khJSVGZmZl6hyGEEKIVwuEwRUVFdO/eHYNBagKi81q/fn2ZUir1eMd1qGQsMzOT7Oxs\nvcMQQgjRCgUFBfTs2ZPs7GzS09P1DkeINqNp2oGmHCdvSYQQQrSrtLQ09u7dS1pamt6hCBEVOlRl\nTAghRMdnMpno37+/3mEIETWkMiaEEKJdFRYWEh8fT2Fhod6hCBEVpDImhBCiXSmlqKmpQSmldyhd\nUiAQIC8vD6/Xq3conYbVaqVXr16YzeYWnS/JmBBCCNGF5OXlERsbS2ZmJpqm6R1Oh6eUory8nLy8\nPPr27duiMeQ2pRBCCNGFeL1ekpOTJRGLEE3TSE5OblWlUZIxIYQQ7So2NpYFCxYQGxurdyhdliRi\nkdXar6fcphRCCNGuYmNjWbhwod5hCBE1pDImhBCiXVVVVXHzzTdTVVWldyhCRAVJxoQQQrQrt9vN\n4sWLcbvdeociRFSQ25RCCCFEF1X0wAP4du6K6JiWIYPpfvfdxzwmJyeH6dOnc+KJJ7JhwwaGDRvG\nLbfcwi233AJAKBRi27ZtR21/MmXKFBYtWkRWVhZlZWVkZWWRk5PDSy+9xDvvvEN1dTX5+flcfvnl\nLFiwIKKvry1IZUyILiQcDlJVlU1l5bcoFdI7HCFEF7Z7925uuukmdu7cSVxcHGvXrmXTpk1s2rSJ\n6dOnM2/evBaNu3btWt566y22bNnCG2+80SH2tJbKmBBdRCBQw9Ztc6ms/C8AcXGjGT7sSWy2njpH\nJroao9FIv379MBqNeofS5R2vgtWWMjIymDhxIgCXX345Tz75JPPmzWPZsmVs2LCBTz75pEXjTps2\njeTkZAB+8YtfsHr1arKysiIWd1uQZEyILmLnrruoqlrHwAF/xGi0s3ff/Wzecg1ZJ76BySQtBkT7\n6datG/v27dM7DKGz/20HoWka27ZtY+HChaxcufKYybrJZCIcDgP8pL/XkcaNdnKbUoguoLZ2O6Wl\nH5HZ5wYyMq4iPX0GI0Y8g9u9n127/6B3eKKL8fv9fPPNN/j9fr1DETrKzc3l66+/BuC1117j1FNP\n5dJLL+Xll18mNTX1mOdmZmayfv16AN58883Dnvv000+pqKjA4/Hw7rvvNlbfopluyZimaRmapn2h\nadoOTdO2a5p2q16xCNHZ7c95GpMpjoyM2Y2PJSVOoE+f6ykufo/qms06Rie6mrKyMiZMmEBZWZne\noQgdDRo0iMWLFzNkyBAqKytJSUnhwIEDzJkzh9GjRzN69Oijnjtv3jyeeeYZxowZ85Pvo/Hjx3PR\nRRcxcuRILrrooqi/RQn63qYMAr9VSm3QNC0WWK9p2qdKqR06xiREpxMMuigv/5z09Esxm+MOe65P\n7+vIz3+dffse5sSxr+kUoRCiKzKZTLz66quHPXbVVVc16dzBgwezZcuWxr/fd999jZ/36tWLd999\nNzJBthPdKmNKqUKl1IZDn9cCOwGZSSxEhFVUrCYc9pOWetZPnjOZnGT2uYGqqm+pqdlyhLOFEEK0\ntaiYM6ZpWiYwBvhW30iE6HxKyz7BZEogPv7Ipfr09BkYjU4O5D7fzpEJIbqqzMxMtm3bdtzj5s6d\n23jLsuFj6dKlRz1+1qxZPPXUU5EMtV3ovppS0zQn8BZwm1Kq5gjPXwdcB9C7d+92jk6Ijk2pMOXl\nX5GSMgWD4cg/7iZTLD17/pKDB5fi85dhiUlp5yhFV5OSksLXX39NSop8r4ljW7x4sd4htAtdK2Oa\nppmpT8T+qZR6+0jHKKX+rpTKUkplHW91hRDicG73fgKBShITJhzzuB7df4FSIUpLPmqnyERXFhMT\nw8knn0xMTIzeoQgRFfRcTakBLwA7lVKP6RWHEJ1ZdfUGAOLjxxzzOKdzEA7HAIpL/l97hCW6uOLi\nYvr3709xcbHeoQgRFfSsjE0ErgDO0DRt06GPc3SMR4hOp7p6AyZTAnZ73+Me2y3tXKqq1uHzyS9I\n0bZCoRDfffcdoZBsySUE6LuacrVSSlNKjVRKjT708YFe8QjRGVXXbCQ+fjSadvwf9ZTUaYCivGJV\n2wcmhBCiUVSsphRCRF4gUIPLtZf4+LFNOt7pGITZnExFxZo2jkwIIQ63cOFCFi1adMTnHnvsMYYO\nHcrIkSOZOnUqBw4caOfo2p4kY0J0UnV1uwCIix3epOM1TSMpaSIVFWtQSrVlaKKLs9vtzJ07F7vd\nrncoogMYM2YM2dnZbNmyhYsvvpg77rhD75AiTvfWFkKItuFy7QXA4RjQ5HOSEidSXLwcl2sPTueg\ntgpNdHEJCQkdshdUZ7Rnz5+prdsZ0TFjnUMYOPD4e97ef//9/OMf/yAtLY2MjAyGDBly2BZIW7du\n5fvvv+f0009vfOzkk0/+Sdf+H/vyyy9ZtGgR77//PgA333wzWVlZzJo1i8zMTC655BI+/PBDbDYb\nr732Gv3792/FK40cqYwJ0Um5XHsxGp1YLD2afE5S0ikAVFZ+01ZhCUFtbS0LFy6ktrZW71CETtav\nX8/rr7/Opk2b+OCDD1i3bh12u51NmzaxadMm5syZw0UXXUSfPn0OO++FF17g7LPPbvF14+Pj2bp1\nKzfffDO33XZba19GxEhlTIhOqs61B4djAPVdZJrGYumBJaYb1TUbyaBpe8QJ0Vy1tbXce++9XHfd\ndcTGxuodTpfWlApWW1i1ahUXXnhh463qCy64oPG5NWvWsGTJElavXn3YOa+++irZ2dl89dVXLb7u\npZde2vjnb37zmxaPE2mSjAnRSblce0lNObNZ52iaRnz8WKqrN7ZRVEIIcXSFhYVcc801LF++HKfT\n2fj4Z599xv33389XX32FxWI56vkmk4lwONz4d6/Xe9jzP35z2pw3qm1NblMK0Qn5/eUEAhXNmi/W\nID5+DF5vHj5faRtEJoQQMHnyZN599108Hg+1tbW89957KKWYMWMGDz/8MAMHDmw8duPGjVx//fUs\nX76ctLS0Y47bp08fduzYgc/no6qqihUrVhz2/LJlyxr/nDDh2DuTtCepjAnRCf0web/5k1MbuvVX\n12wgLfVnEY1LCKivSMTFxUVVZUK0r7FjxzJz5kxGjRpFWloa48aNw+12k52dzYIFC1iwYAEAH3zw\nAfPnz6euro4ZM2YA9ftUL1++/IjjZmRkcMkllzB8+HD69u3LmDGH7z5SWVnJyJEjsVgs/Otf/2rb\nF9kMWkdawp6VlaWys7P1DkOIqJef/zq7dv+eUyZ8hc3Wq1nnhsM+vvxqNL0zZtG//51tFKEQQi87\nd+5kyJAheofR7jIzM8nOzm6zDeqP9HXVNG29UirreOfKbUohOiGPJxdNM2O1Nn0lZQODwYLD0a+x\nT5kQkRYMBtm3bx/BYFDvUISICnKbUohOyOPJxWbrhaYZW3S+0zGIyippbyHaRklJCQMGDCA/P5/0\n9HS9wxEd0NatW7niiisOe8xisfDtt98e9ZycnJw2jqrlJBkTohNyew5gs/Vu8flO5yCKit8lEKjG\nbI6PYGRCCNF6I0aMYNOmTXqHETFym1KITkYpdagy1rpkDKCubnekwhJCCHEUkowJ0ckEAhWEQnXY\nbH2Of/BROBqSMZckY0II0dYkGROik/F4cgFaVRmzxHTDZIrHJZUx0QaSkpJYvnw5SUlJeociRFSQ\nZEyITiYSyZimaTgcA6g71K9MiEiyWq2cf/75WK1WvUMRnUBOTg7Dhw/XO4xWkWRMiE6mMRmzZrRq\nHIf9BNzu/ZEISYjDlJaWcvLJJ1NaKrs8CAGSjAnR6Xi8+cTEpGI0tq7qYLdnEgiUEwjURCgyIeoF\nAgG+/fZbAoGA3qEIneTk5DB48GAuu+wyhgwZwsUXX8zKlSsZPXo0o0ePZsSIEcfcoWH9+vWMGjWK\nUaNGsXjx4sbHvV4vV199NSNGjGDMmDF88cUXAJx77rls2bIFgDFjxvCnP/0JgD/+8Y8sWbKEL7/8\nkilTpnDxxRc3xtWeTfGltYUQnYzXm4/V2ryu+0dit58AgMeTg9k8stXjCSGiT9EDD+DbGdkGz5Yh\ng+l+993HPW737t288MILTJw4kdmzZ7N27drGdhXz589n+vTpRz336quv5qmnnmLy5MnMnz+/8fHF\nixejaRpbt25l165dnHXWWezZs4dJkyaxatUq+vTpg8lkYs2aNQCsWrWKZ599lsLCQjZu3Mj27dtJ\nT09n4sSJrFmzhlNPPbWVX42mkcqYEJ2M15uHzdqz1ePY7X0B5FalEKJNZGRkMHHiRAAuv/xyVq9e\nDdRv4r1hwwYeeuihI55XVVVFVVUVkydPBjis+evq1au5/PLLARg8eDB9+vRpTMZWrlzJmjVrOPfc\nc6mrq8PtdrN//34GDapfPT5+/Hh69eqFwWBg9OjR7dokVipjQnQiSoXxegtJSz271WPZbBmAQZIx\nEXFWq5VLLrlEJvBHgaZUsNrK/96G1DSNbdu2sXDhQlauXInR2LIdRI5k3LhxZGdnc8IJJzBt2jTK\nyspYsmQJJ554YuMxFoul8XOj0diu23VJZUyITsTnL0GpANZmbg5+JAaDBZu1Fy739xGITIgfJCUl\nsWzZMmlt0cXl5uby9ddfA/Daa69x6qmncumll/Lyyy+Tmpp61PMSEhJISEhorKT985//bHxu0qRJ\njX/fs2cPubm5DBo0iJiYGDIyMnjjjTeYMGECkyZNYtGiRY3VNb1JMiZEJ+L15AFE5DYlgN3RVypj\nIuJcLhdPPfUULpdL71CEjgYNGsTixYsZMmQIlZWVpKSkcODAAebMmdM4kf9oli5dyty5cxk9evRh\nE+1vuukmwuEwI0aMYObMmbz00kuNFa9JkyaRlpaGzWZj0qRJ5OXlMWnSpDZ/nU2htedqgdbKyspS\n2dnZeochRNQqKlrO9h2/4eSTPsHh6Nfq8XbvuZfCwrc5bfKmY65sEqI5CgoK6Nmzp2wUrpOdO3cy\nZMgQXWPIycnhvPPOY9u2bbrGEUlH+rpqmrZeKZV1vHOlMiZEJ+L11lfGrNbI/IKz2XoTCtURCFRE\nZDwhhBA/JRP4hehEPN48zOZkjEZbRMazH9rf0uPJJSYmOSJjCiFEZmZmk6pic+fObWxD0eDWW2/l\n6quvbqvQdCHJmBCdiM9bGLGqGIDVVt/F3+PJJT5+TMTGFUKIpvhxQ9fOTJIxIToRn6+4MYGKhIYt\nlRq2WBIiEnr06IHf78dkkl9BQoDMGROiU/H6irFYukdsPKPRisXSXZIxEVFKKdxud7tuNyNENJNk\nTIhOIhTyEgxWYbGkRXRcm603bknGRAQVFRWRkJBAUVGR3qEIERUkGROik/D7SwCwWLpFdFybrbdU\nxoQQog1JMiZEJ+H1FQNE9DYl1M8b8/tLCIU8ER1XCCEaLFy4kEWLFh3xuccee4yhQ4cycuRIpk6d\nyoEDB5o87qxZs3jzzTcjFWabkWRMiE7C56u/5RP5ylj9JH6vtyCi4wohRFOMGTOG7OxstmzZwsUX\nX8wdd9yhd0gRJ8mYEJ2E71BlzBrhypjlUKsMScZEpCQkJPDiiy+SkJCgdyhCR/fffz8DBw7k1FNP\nZffu3bjd7sZtkEaPHo3RaOTAgQOcfvrp2O12AE4++WTy8vKOOqZSiptvvplBgwZx5plnUlJS0vjc\nihUrGDNmDCNGjGD27Nn4fD7WrVvHL37xCwD+85//YLPZ8Pv9eL1eTjjhBACmTJnCnXfeyfjx4xk4\ncCCrVq2K+NdC1hUL0Un4fMUYDDaMRmdEx7VaDiVjPknGRGTY7fZO17Szo9qz58/U1u2M6JixziEM\nHPiHYx6zfv16Xn/9dTZt2kQwGGTs2LGceOKJbNq0CajvL/bVV1/Rp0+fw8574YUXOPvss4867jvv\nvMPu3bvZsWMHxcXFDB06lNmzZ+P1epk1axYrVqxg4MCBXHnllTzzzDPcfPPNjddctWoVw4cPZ926\ndQSDQU466aTGcYPBIGvXruWDDz7g3nvv5bPPPmvpl+eIpDImRCfh8xVhsXSL+B6S9aszDVIZExFT\nXl7O+eefT3l5ud6hCJ2sWrWKCy+8ELvdTlxcHBdccEHjc2vWrGHJkiW8+OKLh53z6quvkp2dzfz5\n84867sqVK7n00ksxGo2kp6dzxhlnALB792769u3LwIEDAbjqqqtYuXIlJpOJfv36sXPnTtauXcvt\nt9/OypUrWbVq1WGbiDdUz0488URycnIi9WVoJJUxIToJn68k4vPFAAwGMxZLGj5JxkSE+Hw+3n//\nfXw+n96hdHnHq2C1t8LCQq655hqWL1+O0/lDlf+zzz7j/vvv56uvvsJisUT0mpMnT+bDDz/EbDZz\n5plnMmvWLEKhEI8++mjjMQ3XNBqNBIPBiF4fpDImRKfh8xVHfL5YA6s1XSpjQoiImTx5Mu+++y4e\nj4fa2lree+89lFLMmDGDhx9+uLGCBbBx40auv/56li9fTlrasfsoTp48mWXLlhEKhSgsLOSLL74A\nYNCgQeTk5LBv3z4AXnnlFU477TQAJk2axOOPP86ECRNITU2lvLyc3bt3M3z48DZ69T8llTEhOgGl\nFH5/cZtUxqB+3lhN7ZY2GVsI0fWMHTuWmTNnMmrUKNLS0hg3bhxut5vs7GwWLFjAggULAPjggw+Y\nP38+dXV1zJgxA4DevXuzfPnyI4574YUX8vnnnzN06FB69+7NhAkTALBarSxdupQZM2YQDAYZN24c\nN9xwAwAnnXQSxcXFTJ48GYCRI0dSVFQU8Skfx6J1pO0osrKyVHZ2tt5hCBF1/P4KVq0ex4AB99A7\nI/ITo/fte5jcgy9x+pTtaJoU1EXrlJWVMXPmTJYtW0ZKSore4XQ5O3fuZMiQIXqH0ekc6euqadp6\npVTW8c6VypgQnYCvjRq+NrBY01HKj99fjsWS2ibXEF1HSkoKK1as0DsMIaKGJGNCdAI+f0OPsTa6\nTWn9ob2FJGOitTweD8uXL+eCCy7AZrPpHY7ogLZu3coVV1xx2GMWi4Vvv/1Wp4haR5IxITqBtq6M\nNfYa8xYQHzeqTa4huo7Kykp++ctfkp+fL8mYaJERI0Y09gfrDGTyhxCdQH0yphET0zZVK6u1Z/11\nZEWlEJ1CR5ov3hG09uspyZgQnYDPV0RMTDIGg7lNxjeZYjEandLeQohOwGq1Ul5eLglZhCilKC8v\nx2q1tngMuU0pRCfg8xVjiWmb+WIAmqZhtfbA681vs2sIIdpHr169yMvLo7S0VO9QOg2r1UqvXr1a\nfL4kY0J0Aj5fSZs1fG1gtabL/pQiIrp160Z+fj7durXdGwhxdGazmb59++odhvgRuU0pRCfQsC9l\nW7Ja0vF6C9v0GqJraNg30Gg06h2KEFFBkjEhOrhw2EcgUNH2yZg1nUCgglDI06bXEZ1fQUEBZrOZ\nggKptAoBkowJ0eH5fPXzPtqqrUUDS0OvMamOiQhoi82WheioJBkTooPz+YoAsFiOvYFuazX2GpN5\nY0IIEVGSjAnRwfn8JUDbV8YauvBLrzEhhIgsScaE6OB+6L7ftnPG6sfXpNeYaLW4uDgefvhh4uLi\n9A5FiKggrS2E6OB8viIMBgsmU3ybXsdgMBMTk9KY/AnRUk6nkzvuuEPvMISIGlIZE6KD8/mKsVi6\noWlam1/LaumB1ycT+EXrVFZWcvXVV1NZWal3KEJEBUnGhOjg2rr7/o9ZrN0bFwwI0VIej4eXXnoJ\nj0fapAgBkowJ0eG1R8PXBhZLd2ltIYQQESbJmBAdmFIKn6+k3ZIxq6U7oVAdwWBtu1xPCCG6AknG\nhOjAgsEawmFvm7e1aGCx9ACQSfyiVUwmEyNGjMBkkjVkQoCsphSiQ/uh4Wv73aYE8PqKcDj6t8s1\nReeTlpbGli1b9A5DiKghlTEhOrD26jHWwGo9VBmTeWOiFXw+HytWrMDn8+kdihBRQZIxITqw9k7G\nGrZc8sqKStEK5eXlnHnmmZSXl+sdihBRQddkTNO0FzVNK9E0bZuecQjRUf2QjLXtvpQNDAYLZnMy\nPuk1JoQQEaN3ZewlYLrOMQjRYfn8xZjNSRgMlna7plV6jQkhRETpmowppVYCFXrGIERH1tB9vz1Z\nLD3weSUZE0KISNG7MiaEaIX2bPjawGLpLnPGRKukpqayefNmUlNT9Q5FiKgQ9cmYpmnXaZqWrWla\ndmlpqd7hCBFV6rdCap/5Yg2slh4Eg9WEQu52va7oPMxmMyNHjsRsNusdihBRIeqTMaXU35VSWUqp\nLHkXJcQPwuEAfn95uzV8bWCxHuo1JrcqRQsVFRWRnp5OUZF8DwkBHSAZE0Icmd9fCqh2v01pPZT8\nyYpK0VLhcJjCwkLC4bDeoQgRFfRubfEv4GtgkKZpeZqmXaNnPEJ0JO3dY6yBpTEZk6qGEEJEgq7b\nISmlLtXz+kJ0ZD8kY+18m/JHWyIJIYRoPblNKUQH5T10m9Bqbd9kzGi0YjYnSmVMtJjD4WD+/Pk4\nHA69QxEiKshG4UJ0UD5vIQaDDZMpod2vbbH0wCv7U4oWio+P55FHHtE7DCGihlTGhOigvN4CrNZ0\nNE1r92tbLd3xeQva/bqic6iuruaOO+6gurpa71CEiAqSjAnRQXl99cmYHqy2nni8+SildLm+6Nhc\nLhePPvooLpdL71CEiAqSjAnRQXm9BVgtPXS5ttXai1CojmCwRpfrCyFEZyLJmBAdUDjsw+8v1a0y\nZrP2AsDrzdPl+kII0ZlIMiZEB9TQ/V6325TWnofiyNfl+qJjMxgM9OjRA4NBfgUJAbKaUogOyeur\nnzxv0asyZquvjHkkGRMt0L17dwoKZAGIEA3kbYkQHVDDSka95oyZTAkYjQ68HrlNKZovEAiwZcsW\nAoGA3qEIERUkGROiA/IeSsYsOiVjmqZhtabjkTljogVKS0sZNWoUpaWleociRFSQZEyIDsjrLSAm\nJgWj0aJbDFZrL5kzJoQQESDJmBAdkNdXiNWiz3yxBjZrL1lNKYQQESDJmBAdkNdbqNvk/QZWW0+C\nwVoCAek1JoQQrSHJmBAdjFIKn47d9xtYpdeYaKHk5GQ+++wzkpOT9Q5FiKggrS2EiJBQVRWVry/D\ns3EjxoQEkq+9BsuAARG/TjBYTSjk1j0Zs/2o11hs7FBdYxEdi8ViYerUqXqHIUTUkMqYEBHg2bKF\n7//v55Q+/jiBggJqP/+c7y/8BTWffhrxa3kb21pER2VMVlSK5iopKWHkyJGUlJToHYoQUUGSMdEp\nqWCQUHU1qh36GLk3bOTArKvRTCYy33iDE95bTr+PP8I6bCgFd/4O3759Eb1eYzJm1aetRQOzORGj\n0S4rKkWzBYNBtm7dSjAY1DsUIaKC3KYUnUbY66X6nXeoevddvNt3QDAIBgMxffpgP2k8CT//OdZR\no9A0LWLX9GzbzsHrrsOcmkqfV1/BlJoKgCkpiV5PPsn+n19I0b1/ovfL/4jYdfXuvt+gvtdYT2n8\nKoQQrSTJmOgUPFu2UHDHnfhzcrAMHULyrKswpqQQqq7Gt2s31f9ZTtXry4jp14+U668j7txz0YzG\nVl3Tu3s3B6+5BmN8PL1fWtqYiDUwd+tGyty5FN93H66VK3Gedlqrrtd4XW8BBkMMMeakiIzXGlZr\nT9kSSQghWkmSMdHh1Xz4IQV3/g5jSjIZS5bgOHXiT6pQobo6aj/+mIpX/0nBHXdSvuR5Un9zG87T\nT29Rxcr33XfkXj0bzWql90tLMfc48i3DxEtmUPHyy5QufjqiyZjF0gNN03+WgdXai+rqDXqHIToY\nm83GrFmzsNlseociRFTQ/19zIVqh5qOPyf/tPKwjR9D3rbdwTjr1iMmV0ekk4aKL6PvWm/R87C8o\nv5+8m+Zy4NJf4V63rlnX9O3fT+6sq8FgoPdLS4nJyDjqsVpMDEmX/Qrvli14d+9u9us7Eq83H+uh\nlYx6s1l7EgzWSK8x0SyJiYksXbqUxMREvUMRIipIMiY6LPeGjRTMn49t1Ch6L1mCqQn/sGsGA3Hn\nnMMJ779H9z/dS6CwkANXXMnB62/Au3vP8a+Znc2BX12GCgbps/RFLH37HvecuAsuQDObqfr3G016\nXcfj8eRis/WOyFitZbXVJ6Je70GdIxEdSV1dHY888gh1dXV6hyJEVJBkTHRIgeJi8m65BVOPHmQ8\n8zSGZt7u0MxmEi+5hH4ff0TavN/i3riR/T//ObnXzqHm408I+/2HHe8/eJDCBQs5cMWVGOPiyPzX\na03uIWZKTCR22jRq3n8f1crVY/Ud7yuwR0kyZrf1AcDtOaBzJKIjqamp4c4776SmRiqqQoDMGRMd\nkAoEyL/tN4Tdbvq8tBRjQkKLxzJYrSRfey0JM2ZQ8cqrVL35Jvm33opmNhPTrx8Gp4NQaRn+AwfA\nZCLx8stJvfVWjE5Hs64Te/Z0aj74AHf2ehwnn9TieD2eXACsUZKM2Q4lYx53jr6BCCFEBybJmOhw\nShb9Bc/GjfR87C9Y+vePyJjG+HhSb55Lyo034Prvf3F9/Q3+778n7HJhGTiQhEtmEHfeeZi7dWvR\n+M6JE9EsFmpXrGhVMuY+lIxFS2XMZHIQE5OGW5IxIYRoMUnGRIdS89FHVPzjHyRefjlx55wT8fE1\noxHnpEk4J02K6LgGux3HxInUrviMbnff1eKeYw2VsWiZMwZgt2fi9uToHYboYEwm+fUjRAOZMyY6\nDO+OHRTcdTe20aPpdsd8vcOpYKfaAAAgAElEQVRpttipUwkWFOLdsaPFY3g8BzCbkzCZYiMYWevY\nbZlSGRPNkp6eTiAQID1d38bFQkQLScZEhxAoKeHgTXMxJiTQ629PosXE6B1SszlPnwIGA3UrVrR4\njGhaSdnAZs8kECgnGKzVOxTRQYRCIQoKCgiFQnqHIkRUOG4ypmmaVdO0izVNe0LTtDc0TXtZ07Q7\nNE0b1h4BChGqc5F3868JVVeT8fTin3S67yhMSUnYx46l9rPOlYzZbZkAUh0TTVZcXEzPnj0pLi7W\nOxQhosIxkzFN0+4F/gtMAL4FngP+DQSBhzRN+1TTtJFtHqXoskK1teTdcAPe7dvpuehRrEOG6B1S\nqzjPnIpvzx78ubnNPjcUcuP15uOwn9AGkbWc3Z4JgNu9X99AhBCigzreDMq1SqkFR3nuMU3T0oDo\nepsuOg3f99+T9+tb8B84QPojDxM7dareIf1EKOSltnYb1TWb8LhzCIXcmMxxxMWNJi11Okaj9bDj\nY08/nZKHHqZu1SqSLrusWddyufYB4HAMjFj8kWC390XTzNS5IrPDgBBCdDXHS8bsmqZZlFK+Iz2p\nlCoBSiIflujKVCBAxav/pPSJJzDYbPR+4QUcJ43XO6xGPl8xJSUfUlb2BZVVa1GqvkGs2ZyEyejE\nH6ggL+8V9sU8yOBBfyY19azGc2P69MGckYFr9ZoWJGN7AXA4mtZstr0YDDE47CdQV7dL71CEEKJD\nOl4y9itgsaZpHwP/Aj5WSsmMS9Emwj4f1e+8S/nzzxPIy8N52ml0//OfMKel6R0aABWVX5OX9zJl\nZStQKoTd3o+MXleQkDCOuPgxWGJSAFAqTFXVWvbue5AtW29kQP/f07v37MZxHBNPoWb5eyi/v1kL\nEepce9G0mKibMwbgdA6msmqt3mGIDiIxMZHXX39d9qYU4pBjJmNKqQs1TYsDLgR+Dbygadp/gH8p\npb5qjwBF5xd2uahc9m8qli4lWFqKdeRIuv/hHhyTJ7e4H1ckeX1F7Np1N+XlX2E2J9E74xrS0y/B\nbj/yvpSaZiAx8WROHPtvtu+4nb377sdsTqBHj18A4Jg4karXl+HZvBn7uHFNjsPl2ovDcQIGQ/T1\nZ3I4B1FU/B8CgWrM5ni9wxFRzmazMXPmTL3DECJqHHc1pVKqRin1D6XU2cBwYCPwpKZpsjOwaJVQ\nVRWlTy1m7xlTKXnkEWL696P30hfJXPY6ztNOi4pErKzsC9auPY+qqnX0738XE09ZTf/+dx41Efsx\no9HC8GF/JTFxArt2/6Fxgrvj5JPBaKRu9ZpmxeJy7cVhj8yOA5HmdA4CoM51/M3WhSgrK2Pq1KmU\nlZXpHYoQUaHJfcY0TUsEfgHMBJKAN9sqKNG5BUpKKH7kUfadMZWyp57CnpVF5rLX6bN0KY4JE6Ii\nCQPIyXmWzVuuxWLpxris/9Cn97UYjZZmjWEwxDBs6F8wGCzs2Pk7lFIYY2OxjRqFa03Tk7Fg0FW/\nkjLK5os1cDoOJWMyb0w0gd/v5/PPP8fv9+sdihBR4Zj3OzRNc1J/i/JSYAywHPgz8KVSSrV9eKKz\nUErh3bqVildfpebDjyAUIu6cc0ieMwfroOhaHQiQk/MM332/iG7dzmfI4IebnYT9mMXSjf7972TX\nrrspLfuEtNSf4Zh4CmVPLSZYWYmpCfNm6up2AvVzs6KRxdIdszmRutqW7y7Q2QXLyghWVGBKTW3S\n/3MhRNdxvMknOcBHwNPUT94PtHlEotMI1dbi3b4d1+rV1Hz6KYEDuRgcDhJnziTpisuJ6dNH7xCP\n6MCB5/ju+0V07/Z/DB36KJpmbPWYPbpfRG7uC3z33V9ISZ6K89RTKfvbU7i//rpJe2zW1m4DIDZu\neKtjaQuaphEXO4Ka2i16hxJVlFLUffElZc8+i3fLD18b67BhJF93HbFnTYuaSrAQQj/HS8YylFIe\nAE3TbJqmnaCUkmZC4ifCfj++3bvxbNmCd8tWPFu34v/++/onTSYcJ51E8uxriDv3HIxOp77BHkNp\n6afs++4RuqWdF7FEDMBgMNG/3zy2bL2RwqK3SB9+MYa4OOpWr2liMradmJgULDHdIhJPW4iNG0l5\nztOEQm6MRrve4egu7HZTeM8fqPngA2IyM0m9/XZiMnrhP5hH9TvvkH/rrTjPOIP0Bx/AGN+1Fj1Y\nLBbOO+88LJaWV5yF6EyOt5qyIRE7H1gExAB9NU0bDfxJKXVB24co9BSqqiJUU0PY5SLs8aL8flTA\nT9jlJpCfhz/3IN6dO/Ht3IkK1BdOjcnJ2EaOJP7887AOH4Ft1EiMcXE6v5Ljc7v3s33HPGJjRzBk\nyCMRS8QapKRMIz5uDPu/f4Lu3S7AMWECrjVrUEodtzpSU7uN2NjhUV1FiYsbCYSprd1BQkKW3uHo\nKlRTQ+6cOXi3bCX1tttIvmY2mtnc+HzyNbOpePkVSh97jJxLf0Xv55dg7kKbZicnJ/Pee+/pHYYQ\nUaOpa+QXAuOBLwGUUps0TTv+cjLRIfn27aPytdeo/fwLgkVFxzzWGB+PZeBAEq+8AtuIkdhGjsDU\no0dUJw1HEgy62LL1RgyGGEaOeLpVc8SORtM0+vW7gw0bL6WgYBnOiadQ+/HH+L/7Dkv/o6+SDIU8\nuFz7SE2dFvGYIikutn5ntJqazV06GQvVuci95lq8u3bR88kniJv20/9vmtFI8tWzsA4bSt7cmzkw\n62r6vPIK5m7R0VOvrbndbpYtW8bMmTOx26WKKkRTk7GAUqr6f37BygT+TibsdlP84ENUvfkmWkwM\nztNOw3bFFRiTkzA4HBisNrSYGDSzGYPNirlnzw5R8ToepRQ7d/0Ol+s7xox+Cau17SoUiYnjSUgY\nz4HcJYw75Z8AuNasOWYyVj95P0xcbHTOF2tgsaRisfSgumZTxMYMu1zUrlhB3Vcr8e3ZQ8hVh9EZ\ni3XIEOwnn4zjlFOiKoEJ+3zk3Xwz3h076PW3vxF7xunHPN4xfjy9l/yd3NnXkHv11fR55WVMycnt\nFK1+qqqqmD17Nj/72c8kGROCpidj2zVN+xVg1DRtAHAL9RuIi04iUFLCwWuuxbdvH0lXXknyDdd3\nmRVfuQefp6TkA/r3u5OkpIltfr3MPjewafNsyg3riOnbl7rVa0i66qqjHl9ZWd/ZPi5+bJvH1lqJ\nCeMpr1iFUmE0rcmdc34i7PdT9a9/UfbMs4SqqjCmpmAbPgJrfDyhqirqVq6k+j//AU3DPn48ceed\nS9xZZx137pVSCpRCM7Q8tqOOHQxSMG8e7m++qd9L9TiJWAPb6NFk/P05cudcR+61c+jzyisYnY6I\nxyeEiF5NTcZ+Dfwe8AGvAR8D97VVUKJ9BYqKyL1qFoHSUjKeX4JzYtsnJNGiouK/7Nv3CGmpZ9O7\n95x2uWZS0mRincPIOfAsfSdOofrNtwn7fBiOMpm5svJrHI6BjdstRbOkpIkUFf+HurrdxMYOadEY\n7nXrKLj79wQOHsQ+4WRSb7oJ24knHpZAqXAY35491H62gpr336foD3+k6E9/xj5qFNZhwzAmJoIK\nE/b5CBYVEygqIlhURKCoCOX1otntxGT2wX5iFvEXnI9txIhWvW6lFIULF1L76Wd0u/tu4i9o3nRa\ne1YWvZ58goM33Ej+b28nY/FiNFP07bQghGgbx+szdhfwkVJqI/XJ2O/bJSrRbgIlJRy44kpCFRX0\nfn4J9rHRX32JFK+3gG3bb8VuP4EhQx5qt3lumqbRJ/NGtm27Gd9EK+pVL54NG3BMmPCTY8NhP1XV\n2aSnt8/WMYH8fDybNxN2uzH37Ilt9GgMNluTz09MPAWAiso1zU7GlN9P6VOLKV+yBHNGBhnPP4/z\n1CO/MdAMBqyDB2MdPJiUuTfh3b6D2o8+xPXNt1QuW4byeusPNBgwpaVh7tYNy+DBOKdMweB0Eqqp\nxr9vH1VvvEHlK69gHT6cpKuuJO7ss5udBKlQiMIFC6h+8y1SbrqJpCuvaNb5DZyTJtH9j3+kaMEC\niu6/n+5//GOHm3sphGiZ4/2r8z1wq6Zpo4DNwIfAJ0qpyjaPTLQ5FQiQf9tvCJaV0eelpdhGjdI7\npHYTCvnYunUu4bCfkSOewWRq33YbaalnYbf3pZgviDWbcK1Zc8RkrLpmM+Gwl6TEnz4XSZ7Nmyl9\n4glc//36sMcN8fEkXXYZyXOubVJSZrX2wG7vR0XFavr0vrbJ1/d9v5+C+fPxbt9O/MUX0f2uuzA4\nmnarTtM0bMOHYRs+DKivmhEMgqaB0XjMW5Khujqqly+n8rXXKJh/B2VPLSb5hhuIP/+8JiVlYb+f\ngvl3UPvxx6TcdCMpv765aS/4KBJnXkLgYC7lz79ATEZvkmdf3arxolX37t2pqqoiNjZW71CEiArH\nnDihlFqmlJqllBoDPAGcALytadpKTdP+qGna+HaJUrSJ4kcfxbNhAz3u+3OXSsQA9uxZSE3tFoYN\nfRSH44R2v76mGenT+wbq3LvhvMyj7lNZVvopmmYiIaFtftSU30/RAw+Q88tL8e7dS+ptt9H3nbfp\n99lnZDz3LI7x4yl7+mm+/7+f493TtH0nU5KnUFn5DYHA8d+zKaWofH0Z+y+6iEBeHj2ffIL0++5r\nciJ2JJrB0LjQ5Hhzw4xOJ0m/+hUnLF9Oz789iWa3U3jXXXx3zrlUvfV2Y7uWI/Hn5pJ75VXUfvwx\nab+7k9RbbolIJSv19tuJnT6dkkcfpebjT1o9XjTSNA273S6VPyEO0Vqyq5GmaXHANOBnSqnrIh7V\nUWRlZans7Oz2ulynVv3+/6Ng3jySrrqSbnfdpXc47So//3V27f49mX1uol+/3+oWRzjs579fn4Gx\n2kD87SX0//RTYjIyfvR8gDX/PZX4uDGMHPlsxK8fqqkh76a5uLOzSbzsMlJ/85sjThx3fbuWgnnz\nCLvd9Hz8cZyTTj3muLW1O1m77jwGDlxIRq+j37ILVlRQeM8fqPv8cxynTKDHgw9i7qZvU1ulFHWf\nf07Z4qfx7tiBuVcvEi65BMfEU7BkZqIU+Pbuoeb9/0fVv/+NZrXS496FTWrc2xxhr5fcWVfj3bmT\nPi//o9O9WSooKKBnz57k5+eT3oX6q4muR9O09Uqp4/b6aVIypmnaDOrnjtVqmnYPMBa4Tym1ofWh\nNp0kY5Hh3bOHnJm/xDp0KH1eWnpYM8rOrqoqmw0bryAx8SRGj3oh4o1dmyu/YBm7dt1N4hITvaf8\nlpTrf3hvU1q2gi1brmPkiOdITT0zotcNlJRwcM51+L7/nvQHHiD+/POOfXxhIQdvvAnf3r30+NO9\nJFx00TGP/3bteRg0M+PGvXPE5+tWrqTg7t8Trq4m9be3k3TllW2ywrGllFLUffkl5c/9Hc+mI7Tq\nMJuJv+B8Um+5pc0SyGBFBTkzf0nY5SJz2euHJeodnSRjoquIdDK2RSk1UtO0U6lfRfko8Eel1Emt\nD7XpJBlrvVBtLTkXzyDkdtH3rbcwp0VPj6a25nYfIHv9RZhM8YzLeguzOUHvkFAqxNq15+Mt2k/6\nq/0Z8MZ7hx5XbNx4OS73PiaeshqDIXIJcyA/nwOzriZYXk7GU3/DccopTTovVOci/9Zbca1ZQ7d7\n7iHp8suOemzuwaXs3XsfWSe+RXz86MbHwx4PJY8uovK117AM6E/6okVYBw1q9WtqS4GiIjybNhHI\nywPA3CsDx4ST22ULI9/+/Rz45aUYk5LI/NdrGBP0/56NBEnGRFfR1GSsqW9FQ4f+PBf4u1Lq/1G/\nNZLoQFQ4TMHv7sKfl0evv/61SyVigUA1m7dci1KK0aOej4pEDOrnjg0efB9BZ5CSCTvx7q3f+rWk\n9CMqq76hb+avI5uIFZdw4OrZhKqr6fPS0iYnYgBGp4NezzyNc+pUiu+7j7Jnn+Vob+bSe1yC2ZzI\n/pwnGx/zbNvO/otnUPnaayRddRWZb74Z9YkYgLl7d+KmTyf52mtJvvZa4qb/rN32krT07UuvxU8R\nyMsj79e3EPb72+W6Qoj21dRkLF/TtOeAmcAHmqZZmnGuiBLlz79A3YoVdLtjPvasrrNdTTDoYvPm\na/B4DjJyxDPY7dG1k1d8/Fj6pd+Cd7Ri844bycl5mp0778TpHELPnpdG7DrBigpyZ88mVFZG7yV/\nxzZyZLPHMMTE0OvxvxJ3/vmUPv4E+bfcSqiu7ifHmUwOeveeQ3n5V5TmfULxgw+Sc8klhGtr6f3i\nC3S763dH7asmDmfPyqLHAw/gXreOwnvuOWoC3JHEx8fzt7/9jfgutkG6EEfT1NuUdmA6sFUptVfT\ntB7ACKVUuy71GTtsmNqwfXt7XrLTcH39NbnX1L+rT//LX7rMKqZQyMvmzddQWbWWEcP/RlradL1D\nOiKlFFsfnE5p1ndgUiQkjGfY0MewWntEZPxQdTUHrpqFPyeHjL8/h2N861ZnKqWoeOkflCxaRExG\nBt3uuQfHxFMO+77yV5ey7pv/wx8oJeVBEynTZpJ2++2dYgstPZQ9+yyljz9Byk03kXrLr/UORwjR\nBBGdM3ZowFOBAUqppZqmpQJOpdT+VsbZLMOtNvXxLb8mbd68LnWLrbUCBQXsv+hijMlJ9F22rFVt\nAzqSUMjN1q1zKa9YxdAhj9Kjx4V6h3RMlW+8QeGf/kD6K88RP2pyxBLm+o2rZ+PbsZNeTz993NWQ\nzeFau5bCu+4mkJ9PTJ8+2MaOxWCz4c/Nxb1+PYFYN2V3hTFa4xk19jniO8CWTtFKKUXhPfdQ/dbb\ndPv970m64nK9Q2qxiooKbrzxRp555hmSkpL0DkfoSAUCeHfvwbd7F/6cHPwH8whVVRGqroZgQ2uZ\n+p6BBrv9hw+H44fPY2MxJSdjSk3BlJJSv29ylFRdIz2BfwGQBQxSSg3UNC0deEMp1a775ozOyFCv\nJyahWSykzZtHwoyLo2oFVjQK1dZy4FeXESgsJPPf/8ZyQnTdomsrfn85m7fMoaZmK4MH30fPdupg\n3xqh6mr2njaFuPPOJf2+yOw2Fna5OHj9Dbg3bqTXk08QO3VqRMY97Bp+PzXLl1Pz0cf4du9G+f2Y\n0tKwj8si/oILCPa3snnzNfh8RSQmnExS8mSSEifgdA7CYJBblc2hAgHyb7+d2k8/o/vCBST+8pd6\nh9QiMoG/61LBIJ6NG6lbswbPho14tm5FeTz1T5rNxKSnY0xOxhgXhxYTA4dyFBUKEfa4CbvchN0u\nwu5Dn7tc9U2e/4cpNRXLgP5YBgzEduJY7OPG6bLfcqSTsU3AGGDDoQawjSssWx1pM2RlZan/vvkm\nhQsW4v72W+xZWXT/071YTmj/pp0dgQoEOHj9DbjWrqX3359r1mTtjqymZgvbtt+Gz1fE8GGPk5p6\nlt4hNVnhgoVUv/su/b/8otX/cITq6jh43fV4Nm+m56OPRLwXVnMEg3UcPLiU4pIPcLnqm8dqmgmH\nYwCxzqHEx48lKWkSNltP3WLsKJTfT96tt1H3xRcdtkImyVjXEna7qV3xObWfr8C1eg3h2lowGrEO\nGYJtzBjsY0ZjHTYMc8+eLdqTNezxECyvIFRWSqC0lEBuLr69+/Dtq/9QXi9oWv2WaKdOJHbaNKwj\nRrTLdJ1IJ2NrlVLjNU3boJQaq2maA/haj2QsOzsbpRTVb79N8SOPotxukq+7jqSrZ2F0tu+WNtFM\nhcMU3vMHqt9+mx7333fcvlCdQSjkY3/O38jN/Tsx5hSGD3+ShISOtVDBt3cv359/ASlz55Laiq11\nQjU1HJxzHZ7t2+m56FHipkfPXDmfr5Sq6nXU1u6grnY7NbXbCQTKAbDb+5KUdCrJSZNJSDgJk6lr\n3FJvrrDfT/5vbqduxQqSrrqKtDvmoxn17ZnXHJKMdX4qHMb136+peW85NZ9+hnK7Maam4Jw8Gedp\np+E45ZR2+Z2t/H4827bh+uYb3N98i3vDBggGMaX3IG7aNGLPOgvbmDFtdpct0snYPGAA9V33HwRm\nA/9SSj15zBMj7H/7jAXLyih+4AFqPvgQQ1wcSZdfTsKMizH3iMyk545KKUXRvfdS9fqyVv9Sby9K\nKQKBCoLBGkIhL5pmwGxOwGxOxGA4dhcVn6+YouL3OHhwKT5fET26X8SAAb/HbI6OOQPNlXfrbdSt\nWkW/jz5s0dzIUFUVudfOwbt7N73++hixZ0a2YWykKaVwu7+jvGIVFRWrqKz8lnDYi6aZiY8fS3LS\nZJKSTsHpHBLRNh8dnQqFKH7oYSpfeYXYaWeS/sgjzdrUXU+lpaWcf/75vPfee6SmpuodjoigUF0d\n1W+/TcWr/ySQm4shLo646dOJv+B8bGPH6j61KFRVRe0XX1L7ySe41qypn1aRmkrstDOJPess7FlZ\nLarOHU1bTOCfBpwFaMDHSqlPWxdi8x2t6atn6zbK//4ctZ9+BoBt1CicU07DOmIk1mFDMSYkHLMc\nqZRCud2EXC6U10vY40X5/RicDoxxcRgTE3X/BmoqFQ5T/MCDVL76KslzriX19tujcuWkUmFqa7dT\nVv4lVZXfUOfaQyBQccRjzeZEYmJSsVi6YYlJxWhyEg55CYbqcLn24nLtBSAhfhx9+95CUlLHvh3r\nz83lu3PPI/6cc0h/+KFmnev7/nsO3ngjwYJCej75BLGnn95GUbadUMhHdXV2Y3JWV7cLAIPBQmzs\ncOLjRhMXP4a42GFYrb3QtI7xs9lWKl5+meIHH8I6fDg9//oYMb166R2S6IJCtbVUvvoq5S/9g3B1\nNbYxY0i64nKcU6dGbRubUF0ddV9+Re0nn1C3ciXK68WYmIhz6hk4TjoJ+9ixmNLTW/U7NNKVsYeV\nUnce77G2drwO/P7cXGo+/Iiajz/Ct2Nn4+Oa1YopLQ2D1QomI5rRBKEQobo6wjU1hGprIRQ66ria\n3Y5lQH9sw4bhOPVUHCedFJUrEsNuNwV3/o7aTz+tv3XxuzujKhELhdxUVKyhrOxzysq/xO8vATRi\nY4cR6xyKwzmQGHMSBqMVpUIEAlUE/OX4/KX4fSX4/CX4fMWEQm4MBitGox27vS8J8Vmkpk7D4ein\n90uMmJLHH6f82efotfipJk+6r/3ySwrmzUezWOj1tyexj+0cKxd9vhKqqtZSXbOZmuqN1NZtJxyu\nb35qNNpxOAbgcAzE6RiA1doTiyUNoykWg2ZC00yNW14pFQYUoFAqjKYZMZsTMBqdUfVz0hK1K1ZQ\ncOfvAOi+cCHx552rc0TH5vV6+fTTT5k2bRpWq1XvcEQrhGprqXjlFSpe+gfhmhqcZ5xByo03YBsx\nQu/QmiXsdlO3clV9YvbVV/ULAwBjQgKW/v2J6dsXU1pa/UdqKganA4PFgma1ohmNhL0+lMdNoKiY\nQH4+3p078WzaxMCVX0U0GduglBr7P4/pMoG/qdshhWpq8G7fjnf3boLFJQRLSgj7vBAKo0JB0DSM\nsXEY42IxNPxpt6PZbBisNrQYM2GXi1BVNf7cXHy7d+PZtg3ldqOZzTgmTiTunLNxnnFGVMxV8+fl\nk3fLr/Ht2k3aHfNJuuqqFv2CUSqE11uE319MKOQhrAIYDXZMplhMpjjM5rgm//IKhdzU1u6gumYT\nlZXfUFn5X8JhH0ajk+TkyaQkTyE5+TRiYlJa8pI7NeX3s/+XvyRwMI/eL76IbcTwox4bqq6m+KGH\nqX7nHSxDhpCx+CnMnXgeTjjsp65uF7V1O3HV7aHOtQeXaw9+f1mLxtM0M1ZrOnb7CTjsJ2C398Xp\nHIzTOQij0R7h6NuOPy+fgvnz8WzcSOy0M+l2111R+30gc8Y6vmBFBRWvvELlP1/7IQm76SZsw4fp\nHVqrqWAQ3549uNdvwLdnD759+/Dn5hKqqGhc3Xk85vR0bKNH0+uvj7U+GdM07UbgJuAE4LsfPRUL\nrFFKtesyHr33pgz7/Xg2bKDuiy+p+fhjgkVFaDExOCZPIu7ss4mdMqXdK2YqFKLqjTcoeXQRAOl/\nWUTslClNPt/rLaSqah1V1euoqsrG7d6PUoFjnqNpMcSYEzHHJB2qZNkwaGYUilDIRTBYg8eT1zgp\nG8Bm601K8hmkpJxBQsK4484DE/X94Q5ceRWhqiq637uQuHPOOSwJDrtcVL37LmXPPEuospLka64h\nZe5NUXtLoK0FApV4vUX4/MWEgi6UCqFUgLAKomEAtEP/1X+u+KH66vEcxO3Zj9u9n3DYd2hEDZut\nN07nEJzOwcQ6B+N0Dj50azQ6K2kqGKT8xaWUPf00aBrJc64l6YorMMbG6h3aYSQZ67j8ublUvPQS\nVW+9jfL7cU49g5Qbb8Q2rOMnYcejAgGC5eUES0sJu9won5ew1wehIJrVisFqxdStG+YePTDY69/I\nReQ2paZp8UAi9ZP2f/ejp2qVUkee4NMMmqZNB54AjMDzSqljTpDROxn7MRUO49m0mZoPP6T2o48I\nlpaiWa04TzuNuLPPxnna5DadTKuUwv3tWooffhjfzp3YTzqJHvffT0yvY7cG8Hjyqar6pr5SVbUW\nr7d+82Oj0Ul8/BhiY4dhs2ZgsXbHaLBhMMQQCrkJBmsJBmsJBKsI+CvxByoIBCrw+ysIh70oFTw0\njgOT0YnVmo7NloHDMYC4+DFYpPrVIoGCAvJ/czuezZuJ6d8P+4lZGKwWfDk5uNeuQ3k82E48kW53\n39Ul/jFsa0qF8XrzqKvbTW3dLurqdlFXtxOPJ5f6W5z1PytO5yBstgwslu5YLN2IiUnBaLBhNNoa\n35xomvFHH6b/+bvx0K32tvk3IpCfT/FDD1H76WeHFjddRsIll2Du3r1Nrtdckox1LMHycuq++ILq\nd/+DOzsbzGbi/+8CkmfPltZSxxHxCfyHBk0DGm/wK6VyWxYeaPUTOfZQv0IzD1gHXKqU2nG0c6Ip\nGfsxFQ7jWb+emg8/pObjTwiVl6PZ7cROmULsmVOxDh+OOSMjIu+mA/n51H7+BVX/XoZv7z5MPXrQ\n7Y75xE6f/pPxA4Ea6mnTGA8AACAASURBVFy762/p1G6jsvJbvN6DQP2k+ISEcSQkjCchYRxOx2AM\nhsitIBGRo4JBqv+znOp33sG7d2/9suwe3bGPG0f8+efXL8uO0kpNZxEMunC59hxKzup/przefHz+\nksY3Ii1hNDqxWFKJiUklJiYFi6U7Vkv3+iTP2h2rpQcxMWkt/tn0bN9O+bPP1i9uMhhwTJxI7LQz\ncZwy8bhv3NqSJGPRK+x218952rUL77btuLOz8R7ahjAmM5P4n/+c+AsvxNyt5bvghMOB+qp0oJJA\nsJpgoJJAoLr+zX6gmkCgkuChv4dCbsJhX/1HyEfo0OdK+VGqYa639pM/69/wxGAwWBo/jAbL/2fv\nrsPkrK4Hjn/vuK37xkNCIMQJ7g4tUKBCoEBxK+4U2qKlhSItoVhxWuwHhWKlTaAUAoEEAgkSI8TW\nXcbl/v6Y2egmazP7zsyez/Psszsz79z37GQzc94r52K2uLFa8rBY8+Mr9i352GyFWK2F2GxF2GxF\nWK1FmM2upLyvJnsC/zHAPUAlUA+MAr7VWvf7UlwptRdwk9b6iMTt6wG01nds6zlTp+6g337794nV\nU6bEFaYJlAmFOf7CKTMKU+J+Myrxj7LxH4ktfgY2ecHVlo/16jiViEFBVBP49lu8H3yE96OPibW3\ng1aYnG7sY8dirajAWlSCuagES1EhJqcLs8OFcrhQJjPEdPwrHCHS3k60rYVQzTpC69biX/4N4foa\nMGusE3bAdfi+2GdOJKr8hCPthMPNBALVBAI1BAJViQnycV3JV0H+HhQU7IXbPX7Ir0ITYqC0jhEK\nNxMKNRKLBojFAkSjfrSOJIZJI2gd6/Z2NOonFGqIL1AJNRAMxheoxGL+Lc5iwm4rwe4ox24rxWLN\ni3+YWHI3+dmzyYeObbPvymQjvL6K9rfeov3tfxGtqQMN5tJSbOPHYR89BmtpCaaiQiwFRZjzclE2\nO8pmRVnjX5jNG+fKaAAFWrP1Z5UGpej2U0XHH1NANBJh7br1jBwxHPNmZQQ0oLaelqM2f3wb/xjE\nP4S7u7/r9Gqbc340euvHNru9xeNbHLvVZ+lmN2Pbabdrcck2HtebN7Z1+HrzxyMRdDBILBCvCqAD\ngfhwWjCIDobi9wcDRDu9aK+XaGdHfH50Wwvh+jqiHe10jerjsGLbcTyuGdNwTJ+GbezoxO8SS/wd\nx/+mo7FAPGmK+olGfUQ3fPfFk65IC+FQC+FwK6FwM9Fo55a/xAZKWbBY8hKljfIwm92bJVObJlfx\nz3a9xcuduB0LE9MhYtEgsViIWCy4Ic6NyV7LhsVAWzKZHNishVhtRVgsOVv9vzKZbPEeb0wbP/+V\naavb43a4IqnJ2JfAwcAcrfV0pdRBwCla67N6fPK22/wJcKTW+uzE7VOBPbTW2yyKNWGCXf/lwQxc\ntq3p+vvd7D+o0qAVmyf1XV9deVLX89jk/m3mi/HaXDZbKU7ncHJyJpGbOxmPZyfstjLpPREizWmt\niUTaCQZrCQRrCPhr8PlX4/evJhCoJhRq2vBhB/3vkRP9FOv5kG3q/SBUap7fZcuPge5uJ+mjQikr\nZnPXArA8bLZCbLYSHPZybLZSbLYCrNaCxEVFwYbkazA/q6JRP+FwC6FQI6FQE+FwM8FgHf5ANcFg\nLaFgA9GYL5HQhePzUGPhRI94LJGEd63S3jQxjv986CGrepWM9bbvO6y1blJKmZRSJq31e0qp+/r1\nm/eRUupc4FyAceNduFxjN2Se8augru/xTCWejcb/mlRXRqN6/uvqrkdMb/b4tmkSV1x0nRdinQFi\nNU3EGtrQbX4IR+MXjZr4VabdirKawWSKx2dSGx+PEb/8iWiIxNCBIDoWQZsBm0IV52AaUYQq8RAj\nlLgK6Ux078bncnm9S2lsnIvTOWrD5OP8/N3Jy5sm+wEKkQai0SChUH2iV6yBYKieULCOQLA2nowF\naggGa4nFAt0824TVko/Z4kn0HMSv0k3Kkni/i48UbHwPBO0PE1vdgK5uJVbXDtEYSifeL51WlM2C\ntpnBrOIXfSa19Qdzd2+Em9ynt3nQ5odGY1FaWlopKMjHbNp054BkZRxbn1mnrO0Np0hd+D2ee5Me\nQx0fXVEx0Bu+x+IjLtHE90gMItH4bUB3XeR3XfA7rKg8J6rAjSrwYCrKRVnNidewq6cx8XOipzem\nwxuGE6Mbeol9RCJtRCJtxGcjbRKysiZ6v+JDhVZrfmLoMA+rJT+eoFnzsWzSM7Zl729X2Zqte8eI\nxxQNbhzi3BCbNzFE2ko40pb4uZlQqCmRjDURiXT09R8ApbpG6xK5iNpuz8lWepuMtSqlPMD/gL8p\npeoBbx+j3VIVMGKT28MT921Ga/0I8AjE54ztteeg15rtteD339Pxr3/R/tbbBFesAKVwTp2KY9Ik\nHJN3xjFxZ6wjRmL29G3FpdaaaEsL/i+/xDd/Ph2v/Jfw2rWY8/Mp/MVpFJ55Jia7PT5kEmoiEKwm\nEKjC6/1uwwTkhoZ3AI3JZCcvdzoFBXuSX7AnuTlTMJslOUt3sVAI7//+R2D58sScsQpcM2diHzM0\nNn5PF1rH8PvX0Nm5nEBgPcFE8hQONyc+gPy9Hqbs7pNbKTN2Wxl2Rzk5ORMpKT5kk/lj8d6EeO9B\n72ujeT/9lOYnn6Lz/fchGsU2bgfcex+Pa9eZOCbsGJ/POshbKVVXV7O3zBkzXCwY3FBrM9rURLim\nhnB1NaH16wkuWkZw2TJ0uAHMZpzTp5H3w6PJPeoozPn5vWpf6xiRSHt8blh44zDlhvlioebEFJsW\n/IF1hDuWEA63dTNUnxpKWbFYcuNzxayF5OTskvi5KF4tIPHztocprWzsDNrmWXoXSy+HKd2An3jO\n/HMgD3h2ICsqlVIW4hP4DyGehC0ATtZaf72t56TjBP7QunXxQrNvv03w23ihWeeuu8ZLXRx+WL+2\ns+mJjsXwzZ9P8zPP0vnee1iHDaPshl+Rc/DB23xOONxGa+sCWlrn09LyCZ2d3xJPzmzk5kwlP38m\n+fm748mZiM1atM0/rvjEy8RqylAT4XAL0WggUQ5DYba4sVhycNgrcDpHZFSdpnTV9vob1N1xR7zG\nDcR7MhL/bx2TJlF0zjnkHH6YDEMnWSTSsdmKyvjE/WWbfVCYTHbs9vL4akqzKzGvxbGhpwpl6mYl\npQWlTJhNjvjEfXsJdltpYhJ/4SZX+wPjW7CAhj/9Gd/ChZiLisg/4Xjyjj8B+1jjE3iZwJ8ZdCiE\nf8kSOj/4gM657xJcsQJltZJz5JEUnX0WjgkTUnLeaDRIJBLvvdpsAn9s4wT+WCyUuKiJv+9tHN1K\n3FYmTCYHJvPmvWoWsys+NGrJS9ok/e3JiAr8SqkfAPcRL23xuNb69u0dny7JWLi6mvZ/vUP7228T\nWLIEAMfUKeQedRS5Rx45qMvHvfPnU3f77QRXrCTvRz+i/Le/2VDfZHvC4RZaWxfGa4y1LqCj8+sN\nK1NMJicORzmmzUpbtBOJdG534mV3HI4R5OVOJS9/V4qLDsTpHNmv33Mo0lpTf9cfaX78cZzTplF8\n0UW4dp2BstsJr11L5/vv0/Lc84RWr8a1155U3HILthEjem5YbBCLReJX5f41+Hyr8flW4fV9l1gt\nuXFYxWLJSxSC3Ykcz86J0hYjsVjy0i4JjjQ0UHfnXbS//jqWsjKKzj6b/J/+JL4DSZqQZCzzaK0J\nLl1K68uv0PrKK2ifD/f++1F8zjm4dtvN6PDSVrKTsYyrwN9FRyJEGhvjFfgDAYhG0ZEomBTmnBzM\nubmYcnMxezwo29aFSLXWhKuq4hX4Fy2i838fEFy+HADHLruQe9SR5Bx5lKHLxHU4TOODD9L44EM4\ndt6Z4X95oM8JYSTipb39C7y+7/D71yZWdcWvPjZOwExMwrQWYrUVxL9bC+NXFyYL6NiGxM0fqMLv\nX0tnx7e0tS8iGKwFwO0eT3HxIRQXHURe3vSk9QJko4YHHqDx/tkUnHwSZb/6Vbeb1+polNYXX6T+\nj3ejYzHKrruOghN/ZkC0gy9eE6w6UXJiOV7vCgLBGkKheiIRb2JIMJK4yOi6Wt50FUx0q7khSlkT\n8ywnJJKueAJmt5enXdLVnbY336T2ppvRgQBF55xN0bnnplUS1qWjo4O7776bK6+8kpw0K0grehZt\nbaXluedofuZZos3NuHbbjeKLLsK9x+5Gh5ZUOhwmtHp1ogL/OiL19UQaGuJFX32++F7WwSA6GsFk\ns2NyObGUlGIdNgz7uB1wTp+Oa+rUpFbg3wFYuclDaVuBP9reTud77+H95FMCS5YQ/O47iPVuCYyy\n2eLbIdntKJstvty3owMiiVVLViuuGTPw7L8fOYceim3UqIH+SknV8d57VF95FSa3mxEPP4Rj4kSj\nQ9rA51tDY9O7NDbMobVtAVpHsVoLKCrcn8Ki/cnxTMTlGoPJZN3wHK3jFf3jE5zr4kv/Q/VEo754\nvRizG5drDLm5U7FYjN+SKpl8n3/OmlNOJffoH1L5hz/0mAiEa2qoufHXeOfNI3/WiZTfcEO8JEGW\n0FoTDNbQ1raI9vYvaWtfRGfnMqLRjVNX7faKDXtTWiw5ieHAjXtTomMbJyAnyixYrfGLCodjGC7X\nWByOYRlZby/m9VJ76220vfoqzunTqbzjd9hGjzY6LJHlYoEArS++RNOjjxJpaMA1c2a8B3+P3TPi\n4mVLWmsCixfT8d57+Bd+hn/JEnQwuOFxU07O5ntT2jbZmzIYIObzEamrJ7x+PdGWFgAmLlua/hX4\n+2p7yZhvwQKanniSzg8+gHAYc0EBjsmTcOw8EWtFRXyjcJczPlHVbIFYlGhHB7GOjvj39nZiPh8x\nf4BYwI8OhjB53Jg9OViHD8ex0wTs48f3agjQSIHly1l3/vlor4+RTz+VsjH9gQiH22lu/oDGpndp\navof4XD8TyleXyYXs8mBJkY43LzNGjCbUspCYcHeVFbOoqTksIyvn6bDYVYdcyw6HGbMa6/2eu9T\nHY3ScO+9NP31MVx77MHwB2anxb6p/RUI1tLc/CHNTR/Q0vrphrp5JpOdnJxJ5OTsgsc9AY9nR9zu\n8VgsQ7OHJVxby7rzLyC4fDnFF1xA8QXnd9uLmk5aW1u58cYbue2228jv5WRwkb5iwSCtL/0fTY88\nQqS+Huf06RT+4jRyDj007f8WdTSKf9Ei2v/9bzr+/R8itbVgNuOYOBHXjOk4dtklvlH46NF9+vwP\n19XhX/QFeUcdmdRhyh2A9VrroFLqQGAK8LTWurXXkSVBd8mYb9Ei6v94N/7PPsNcVETesceSe+QR\nOKZMycjMPBlC69ax5tTT0MEgo55+Cvv48UaHtE1aR+n0rsDbGd/sORxpJxYNgErUTLMWYLOXYbeV\nYreXYreXYTa7icUCRCIddHpX0NI8j7q6NwgEq/F4JrLzTr8jN3ey0b9avzU/8yx1t9/O8Af/Qs5B\nB/X5+W2vvUb1DTfi3GUXRjz6CObc3BREmXzRaIDW1gU0N39AU/MHeL3x6QA2WwkFBXuRlzeDvNxp\neDw7bdaDOpQFli5l3XnnE+vsZNh99+HZb1+jQ+oVmTOWnbqSsuYnnyS8fj2WsjLyjj2WvGOPSavP\nIR2J4FuwIJ6A/WcO0cbG+D7T++5L7hGH4znooKS9byZ7ztgXwExgNPAW8Bqwi9b6BwOMs082Tcai\nnZ003HMPLc89j6W0lKJzziH/Jz9Oy/kRRgitXs2aU08DpRj94gtpsyddqmgdpa7uTVau/D2hcCOj\nRp7LmDGXZNyG5DGfj5UHH4J9p50Y+cTj/b6g6Jgzh/WXX4FjwgRG/vXRXi9FH0zBUCOdHd/Q0fE1\nLa2f0Nr6KbFYEKVsFOTvRmHhvhQW7Y/HPWHIXlhtT+cHH1J16aWYcnPj0xLSsBd8WyQZy246Go0v\nMHr+ebzzPoJoFPvOOyf2bT4A+47jB/3/dLS9Hd/ChXS8+y6dc+YSbW2N7ye9//7kHHE4ngMO7HPZ\nqd5IyQR+pdQ1gF9rfb9SapHWenoygu2trmSsY+5cam+5lUhDA4WnnkLJJZdgcif/Rcx0geXLWXPy\nz7EOH86oZ59NyR9augmH21ix4nZqal+msGAfJk9+IKOGr1qef4Ham25i1N+exbXrrgNqq+O//6Xq\n4kuwjRvHyMcfw1JQkKQo+ycYaqSp8V2am+fR2rqAYKhuw2Mu1ziKivajqHA/8vN3T9kG2tmiY+5c\n1l96Gfbx4xnx0INYy8qMDqlPJBkbOiKNjbS/9TZtr7++ofqApaICz3774dptJs7p07EOG5bU5CwW\nCBBatYrgypUEvl2K79NPCXz7LcRimNxuPAceGE/A9tsPkzO17zXJTsY+IV6C4gbgGK3190qpr7TW\nkwYeau/tOmWqfu3AA+n497+xT5hAxW234pycucNRg6Hzw3msO+883HvvzYgH/5L24/fJUlPzMt8u\nvR63ewLTpj6G3Z78em/JprVm1THHYLLZGf3y/yXlzanzgw9Zf9FF2MaOZdSTT2DOy0tCpFuLhUL4\n5s8nuHw5sVAIa1kZrl13xTZ6NFrH+H71bNaseZhYLIDNVkpBwZ7k5kwmJ2ciHs9ErNbMGEpNBx3v\nvcf6Sy7FMXFnRj72WEbOC6yrq2OfffZh3rx5lGVYIin6L1xXh/eDD+h8//343s3e+AIcc0kxzom7\nYBs9GuuokVgKCzHn58cXIXXtLRqJEvP7iHl9xHze+Bxvb+J7RyeRpiYijfGVjpHaug0L95TVinPq\nVFx77IFrj91xTpuGqZvKCamS7GRsInA+8LHW+jml1BjgZ1rrPww81N6b5HLp/9txAsUXXkjRGadn\n1WqxVGp58UVqf/Nbis45m9IrrzQ6nEHT1PQ+S766CLu9jBkznsduKzY6pO3yLVzImlNOpeKOO8g/\n/riktdv5wYesv/BC7BN3ZuRjjye1h1SHQjQ/8wxNjzxKtK1tq8ft0ybTeramxfQ5paU/ZMzoX+J2\n7yjDjv3knT+fdeeci33CBEY+/ljGzAcUYks6GiW4YgX+RYvwfb6I4LJlhNauRQe62/5r25Tdjsnj\nwVJcvOHLOmwY9vHjsI8fj23UKENzhaQmY+lianmFXvjFoqyf/5QKNTfdROvzLzDsz38i9/DDjQ5n\n0LS2LmTRF6fjco5kxoy/Y7Wm39ypLut/9yvWh/6B67gDKa88jtLSI5LWdsfcuay/5FJcM2Yw4pGH\nk9I1H66ro+rSy/B/8QXu/fej4OSTce26Kyank9DadXS+/z7fV8+mba8WiuaPYKcfP4Jjwo5J+G2G\npuDKlaw+6WSs5WWMeuaZtJwH2FuhUIjPP/+cGTNmYBvEXgqR3nQsRqSxkWhLK9HWVogmykopBcqE\nye3G5HZhcrniPzudaT/ak5RkTCn1OvF9If+l4/vdbPrYWOB0YLXW+vGBhds76VKBPxPFQiHWnHIq\noe++Y/RLL6XFliiDpbl5Hl98eTY5np2YMeNvablFk7d9BQvm/IBYDticJQRDdYwZcyljx1yStHO0\nvfEm1VdfjXvvvRn+4F8G1FXvW7iQ9ZdeRszvp/K2W8n9wdZreVpaF/D557MoDu6B8+bviXZ2UnT2\nWZRceGG3BZbFtkUaGlh94ixi4RBjXngBa4bPs5I5Y2Ko6G0y1lNBpnOA/YClSqkFSqm3lFLvKqVW\nAQ8Dnw1WIiYGxmSzMfxP96FsNtZfcvGGsfqhoLBwHyZPup/2jq/46uvLN2z7lC4iES9ffnYW2hxj\norqevfd+n7KyY1m9ejadncuSdp68o39IxW234p03j6rLr0CHwz0/qRud77/P2jPPwpyTw5gXX+g2\nEQNYtepebLZSJh3+OGPffou8o4+m6aGHWT3rJIKrVg3kVxlSYj4f6y64kEhLCyMefCjjEzEhxNa2\nm4xprWu11tdorXcAfgrcClwBTNJaH6a1fm0wghTJYa2oYNg9dxNa9T01v/41mTREPVAlJYey4/gb\naWycw8rv7jQ6nM18991d+GNVFD6XQ+l+P8dksjJhx99gNuewYsXvknqu/B//mLIbb6Rz7lzWXXQR\nMb+/5ydtov2df7PuoouxjxvHqOf+jn3cuG6Pa2ldQGvrJ4wadS5mswNLQQGVv7+DYff/mXB1Nd+f\n8GOa//a3jPob1KEQsVDPRYiTes5olKqrryHwzTcMu/tunJN2GdTzCyEGR69LlWutV2utP9Zaf6G1\n9qUyKJE67r32ouSyy2h/621annnG6HAG1YgRv2D48FNZu/avVFe/ZHQ4AHi9K6mq+jvuj+2UjD4K\nk90OgNVawKiRZ9Pc8iE+3+qknrPwlJ9TftNNeP/3AWvPOrvbiffdaX7mWaouvxznLrsw8skntlsq\no2r9s1gseQyrPGmz+3MPO4wx/3wN18yZ1N16G+vOP59IY+OAfp9U0dEo7W+/zfpLLmXFfvuzdMpU\nlk2ZyooDDqTm178msHRpymOov/NOOufOpez668k5uO8FgIUQmSGz940R/VJ0ztl4Dj2EujvvwjfE\n5uCNH3cjhQX7sGz5b2hvX2x0OKz87i5M2orn1Ri5P/zhZo9VVJwAmKipeTnp5y2YdSLD7r0H/5Il\nrD5xFsEVK7Z5rI5EqL31Nupuvx3PgQf2uIovEumgofE/lJUdg9m8dRFma2kpIx59hLIbbsD38XxW\nHfsjOt57Lym/VzLoSITWV19l1Q+PpuryK/AvWoR7770ovuRiii++COeM6bS/+RbfH38CNb/+DdHO\n1Az5Nz/zLM1PPU3hL06j8NRB3QY45YqLi/n4448pLk7vFc5CDJaMWk0pE/iTJ9rRweqf/JSoz8uY\nl1/GWpr+dbiSJRRqZsGCH6HR7L7ba9hsRYbE0dm5jE8+/QHF303E+dcGxn/4wVZLsL/48kw6O5ex\nz97/27jhdRL5Fixg/eVXEGtro/CsMyk6/fQNq/S01vg/+4y6O35P4OuvKTzjDEqvujK+v+t2VFU9\nz9JlNzBz5ivk5U7d7rHBFSuouupqgsuWkT/rRMquvTblRRi3RYfDtL3+Bo0PP0R4zVrsO+1E8YUX\nxPfXM21+3Rpta6PxoYdpfuopbCNHMvKxv2IdNixpsXS8+y7rL7oYz0EHMfzPf+rxNRdCpKdkTeDf\nslGrUmq6UmrofHJnKXNODsPu/zOxTm98Mvcgz4Uxks1WyOTJfyEcbuKrry8jFosYEsfqNQ9hNruw\nv9SCe5+9u62FU1Z2LMFgLR2d36YkBtduuzH2H6+Qc8QRND30MCv2P4A1p57GuosuYtVRP2DNKacS\nrq9j2H33UnbtNb1KCuob/oXTOZrcnCk9HmsfP57RL71I4Rln0Pr8C3x/wo/xf/V1Mn61Xov5fLQ8\n/wLf/eCH1PzqV5jcboY/MJsx/3iF3MMP3yoRAzDn5VF27TWMfPIJIk1NrP75KUlblOD/6muqrrwK\nxy67MOyuO7MyEaurq2PcuHHU1dX1fLAQQ0BPpS0eAu7XWn+tlMoDPgaiQCFwldb6ucEJM056xpKv\n7Y03qb7qKjwHHcSwP903qJWJjVZd8398++21jBp5LuPGXTuo5/b51vDx/EOp9BwPp71Oxe23kf/j\nH291XDBYz4fz9mLcuOsYNfKclMYUWL6ctpdfwf/FF8R8PqzDh+PZfz/yfvQjTK7elQOJRoP874MZ\nVFaeyIQdf9On83s//pjq664n0tREySWXUHTWmX1KRMJ19fg+/YTg8hVEOztQSqGsNixlZVjLy7CU\nV2CtKMeUk0OsrY3AihV4P/iQtn/+k1hHB45Jkyi+8EI8Bx3Yp6K0gaVLWXv2ORCNMvKpJ3Hs2P9a\nauGqKr6fNQuT1cboF1/AkqXDeFLaQgwVve0Z66la2n5a6/MTP58BLNdaH6eUKgfeBgY1GRPJl3f0\nD4l1tFN78y2s/+VFDL//z0Nms/XKip/Q3r6YNWsfISd3MmWlg7fv/dq1j6KUhYJvh9MCuPfZp9vj\n7PZSXK5xtLR8nPJkzLHjjjiuv25AbbS1f04sFqCwsPvfZ3vce+3F2Ndepea3N9Fwzz20v/46JVde\ngeeAA7aZHEVaWuj4179oe+NN/J99Fr/TasWckwNaEwsG0b5trzdSVis5RxxBwckn4Zw+vV87Azh2\n2onRzz7DmtN+wbqzzmbUc3/HNnx4n9uJdnSw7vzz0YEgI554ImsTMSHE1npKxjYduzoMeAniJS9k\nO5PsUXDSSSirlZpf/4Y1p57GsD/ehW3UKKPDGhQ7jr+Rjo5v+Pbba3G7x+Nxj0/5OYPBOqprXqay\n4seEnl2MbdwO291VoqBgT2prXyEWC2MypfcWYM3N81DKTEH+Hv16vjk/n2H33UvHO/+m/t57WH/+\nBTgmTiTnqCNxTp6MOS+PaGsr/i++wDv/E3yffQaRCLZxO1By2aV4DjgA+/jxm1XljnZ0EK6pIVJb\nS7imlpjPh8ntwjZ6NM4pU5Jy8WEbPZoRf32UNaeextozz2L0357FUlLS6+fHAgHWX3Qxwe9XM/Kv\nj26zZIgQIjv1lIy1KqWOBqqAfYCzAJRSFsCYWbYiJfJ/8hNMeXnU3HAj3x19DPnHH0/ej47FMXly\nVg9dmkw2Jk+ezaefHsuSJRew28x/YLHkpPSca9c+htYRRpT/gnULf0rBrBO3e3xhwV5UVT1LR8cS\n8vJmpDS2gWpp+Yjc3KlYLP3fvFopRe6RR5BzyMG0vvwyrS++RMPd92x1nH3nnSk643Ryjz4a+47b\n3u/SnJMT7ykbwPBhbzh23JGRDz/EmjPOZO055zLq6ad6tXdkLBRi/cWX4Pv0Uyrv/APuPfdMaZzp\nwOVy8ctf/hJXL4e/hch2PSVj5wF/BiqAy7TWtYn7DwHeTGVgYvDlHnYYzilTaPzLg7S9+iqtL74I\nJhOmnJz4fmAOJ8pmQ1mtmJxOrJWVWEeOwDFhAo5Jk7GWZea6Doe9nMmTZrPoi1P4+purmDL5QZRK\nTdWXcLiFqurn1q9/oQAAIABJREFUKC87Bv1VPToY3OYQZZfcxIrE9vb0TsZisSAdHd8wcsQZSWlP\nWa0UzJpFwaxZRJqaCC5fTrSjA3NuLvYJE7Zb58wozmnTGH7//ay74ALWnXMuI/76aDwR3IZYKETV\n5Vfg/eADym+9hbxjjhnEaI2Tn5/P7NmzjQ5DiLSx3WRMa70cOLKb+98B3klVUMI41rIyKm6+idKr\nr8I77yOCy5YSbWsn1tkZn38TCsUrkft8eD/6iMir9RueaykrwzllMo7JU+Lfd9llux9E6aSgYHfG\njbueFStuY82ahxg9+sKUnGf1moeIRv2MGnU+3jdeRVmtuGZuf26n3V6O1VpER8fgrjLsq87OZWgd\nJie351WUfWUpKsKy115JbzcVPPvuw7B77qbqiitZ84tfMGL27G63MIo0NlJ1+RX4Fiyg7MYbKfjp\nTw2I1hgdHR3cfffdXHnlleRkyHuEEKnU43bnSqmjgOuArn04vgb+oLV+K5WBCWOZPR5yjzgcjjh8\nu8fF/H4CS5cSWLIE/+Il+JcspuM/c+IPKoVtzBhcu+5KzmGH4tpzz7Qe8hwx/HTa2xfz3ap78ORM\npLjowKS2HwhUs37905SXH4fHsyP18+bhnLlrjysVlVLk5uxCR8dXSY0n2dravwTosbbYUJB72GGY\nHphN1RVX8v3xJ1D8y1+Sd8LxmD0eYl4vra+9RuOf7yfm81F5113kHXO00SEPqo6ODm6++WbOPfdc\nScaEoIdkTCl1DvGhymuArpoSM4HfK6WGa60fSXF8Is2ZnE5c06fjmj59w32RlhYCX31N4Ksl+L9c\nTPtbb9H60kuYcnLIP+F4Ck4+OS0XCCil2Hmn2/F6V7BkyS+ZOuVRCgv3Tlr7q77/M1rD2DGXE66r\nJ7h8OaVXXdmr5+bkTKK5ZR7RaKDbqvbpoKN9MVZrEXZ7hdGhpAXP/vsz+qUXqb3pZup+9zvq7roL\nS34+keZmiEZx7rorFTffJJP1hRA99oxdDuyrtW7e5L53E71lHwKSjImtWAoK8Oy3L5799gXi82J8\nH39M2z9fp/nvz9H89DN4DjmY4vPOwzl5ssHRbs5sdjF92pN8vugUvlx8DlOn/pXCgoEPj3V6V1BT\n8zIjRpyO0zmM1n+9Cmy7pMWWcnInoXWUzs6l5OVNG3A8qdDesYS83Kn9Kg+RrexjxjDyySfwf/EF\nne/9l0hzE9bSUtz77INzxgx5rYQQQM/JmNoiEQNAa90kbyKit0w2G54DDsBzwAGU1tfT+vzzNP/t\n76yeMxf33ntRdO55uPbYPW0+mGy2YmZMfzaekH15JuPH/5phlSf1Oz6tYyxffgtms4vRoy4AwDtv\nHuaiIuwTJvSqjRzPJAA6Or5Oy2QsGvXj9a6ktOQoo0NJO0qprXqPhzqlFLm5uWnzf14Io/W0ZKxd\nKbXVBJDEfR2pCUlkM2tpKSWXXMK4uXMpvfoqAstXsPb001lz0sl0vPce6bJXajwh+xv5+XuwbNmv\n+errSwiHW/rV1vqqv9HS8hHjx12HzVaIjsXwfvRRfAukbrba6Y7DUYnZ7MHr3faG3kaKx6Xx5Oxk\ndCgiA1RUVNDW1kZFhQxpCwE9J2NXAv9USt2klDom8XUz8BpwRerDE9nK7HFTdNZZjJs7h/Lf/oZI\nfT3rL7iQ7487nrY330RHo0aHiM1WxLSpj7PDDtfQ0PAOH318MN+tupdAoLrXbTQ2vseKFbdRVHQA\nlZWzAAh8+y3R5mY8vRyihHhPgts9jk7v8j7/HoOhs3MpAB5373r6xNAWiURYuXIlkYgx+8IKkW62\nm4xprT8E9kgcd3riywTsmXhMiAEx2e0UnHQSO7zzLyp+fwc6EqH6yqtYdcyxdM6bZ3R4KGVi9Kjz\n2H23N8jP353Vqx9g3kcH8MWXZ7K+6u8EAjXdPk9rTXX1iyz56kI8nglM2uVPG4ZkvPM+AsDVx1IN\nbvf4tO0Z6+xchsnkxOkcaXQoIgPU19czfvx46uvrez5YiCGgx9IWiUKvv1FKlSRuN6Q8KjHkKKuV\n/OOOI+/YY+mYM4f6u+9m3VlnU3DyyZRed63hJTE8nh2ZOuVh/P51VFW/QF3dGzQ1/ZplgMMxnLy8\n6bjd47GYPYRCjTQ2/ZfOzm8oLNiHSZP+tFlVf++8edgnTMBa2rciuR73eGpqXiIUasJmK0rybzgw\nnZ1L8Xh2TFmxXCGEyGY9lbZQwG+BXwLmxH1R4H6t9S2pD08MNcpkIvfww/EceCAN99xL85NPEli6\nlOEPzE6LiutO5wjG7XAVO4y9Ep/vO5qa3qetbRGtrQuoq3sdAKXMeDw7s/NOv6e8/HhMpo3/zWJe\nL77PP6fwtFP7fG53Yt9Mr3dlWiVjWms6vcsoKT7M6FCEECIj9aa0xT7A7lrr7wGUUmOBB5VSl2ut\n7011gGJoMtlslF13Lc6pU6i+7nrWnnEmo558AnN+vtGhARvncLndG2tERaMBolEfZrMbs9ne7fO8\nn3wC4XCf5ot12ZiMraCgoH8bcadCKNRAONyCxyPzxYQQoj96GlM4FTipKxED0FqvAk4BTktlYEIA\n5B51FMNnzyb03Xesv+hidChkdEjbZDY7sNkKt5mIAXTMmYspJ6fHLZC6Y7eXYzZ76EyzeWNe70pg\nY7IoRE8KCwv55z//SWFhodGhCJEWekrGrFrrxi3vTMwbs6YmJCE259lvXyp+9zt8CxdSc8staVP+\noq90JELnu+/iOeAAVD/mwCmlcLlG4/evSUF0/efzrwbA5RpjbCAiYzgcDo455hgcjvTcTUKIwdZT\nMra9boj07aIQWSfvmKMpOv882v7vZZqfesrocPrFv2gR0dZWcg49pN9tOJ0j0y4Z8/tWYzLZsdvL\njQ5FZIiGhgb23HNPGhpkPZgQ0POcsalKqfZu7leAXNKIQVVyySWEvltF/Z134dh5Iu49djc6pD7p\nmDMXZbPh3ne/frfhdI6ioeHfxGKRzRYGGMnnX4PTOVJWUopeC4fDfPLJJ4TDYaNDESIt9FRnzKy1\nzu3mK0drLcOUYlApk4mKO+7ANmoUVVdeSTiFNYrCdXV4P/6Yjjlz8C1cSMznG1B7Wms65s7Fvdde\nmD3ufrfjco5E6wjBYPf1zYzg863G5RxtdBhCCJGx0uPSWoheMnvcDP/zn/j+ZydSdcUVjHriCZQ1\nOdcFkaYm2v7xD1pffoXQ999v/qDVSu4RR1B84QXYx47tc9vB5csJr19P0XnnDijGrqKqfv9anM4R\nA2orGbSO4vevpbj4IKNDEUKIjCXJmMg49vHjqbjlZqqvvoa6O++i/IZfDai9SHMzjQ8+ROvzz6PD\nYZy77krZrBOx77QzJo+baGMjnR/Oo+2VV2h/5x1KLr6YonPO7tMmxx3/mQNKkXPQwJKWrmTM519D\nIX0vj5FsgUANWoekZ0z0icPh4Gc/+5lM4BciQZIxkZHyjjmGwFdf0fzU09h3GEvBrFl9biPm9dL0\n1FM0P/Y4Mb+f/B+fQOHpp2PfYYetjvUccADF559H7S230nDPPYRWraLi9ttQZnOP59GxGG2vvopr\n992xFBf3Oc5N2e1lKGXD7187oHaSpWslpdM1ythAREYpLCzkhRdeMDoMIdKGJGMiY5VefTWh1Wuo\nvfkWlMNB/nHH9ep5sVCI1udfoPHhh4k2NZFz2GGUXH5Zj8OPlqIiht13L42zH6DxgQdAqXhCZtr+\nxHXf/PmE16+n5NJLe/27bYtSZpzO4WmTjHXF4XJKMiZ6z+v18sQTT3DGGWfgdvd/DqUQ2UKSMZGx\nlMXCsPvuZd35F1Bz3fWE1qyh5MILtzmHLBYK0f7GmzTOnk24uhrXHntQ+sBsnNOm9f6cSlFy8UWg\nFI2zZ6NsNspv+u12hyxbXngRc14eOYcnZ7sgp3MEfv+6pLQ1UIFAFUpZsNvLjA5FZJC2tjYuvvhi\nTjjhBEnGhECSMZHhTE4nIx59hNqbbqbpwYfonPsuhWeegXvvvbEUFxNtayO4dCkdc+bS/sYbRNva\ncOyyC+W33oJ77737NO9rU8W/vBAdCtH0yCOYHHZKr7uu27YC33xDxzvvUHTuuZjs267M3xcOxzDa\n2xcnpa2BCvjX47BXolTPw7VCCCG6J8mYyHgmm43K392O58ADaLj3Pmquu36rY5TNRs6hh5B3/Am4\n992n30nYhvaUouTyy9DBAM1PPY1yOCm9/LLNjtFaU//HP2LOy6Po7LMGdL5NOeyVhMMtRKN+zGZn\n0trtD3+gCodzmKExCCFEppNkTGSN3MMPJ+fQQwksXox/8RKira2YcnOwjx2Lc/p0zDk5ST2fUorS\n664jFgjS9PDDoDUll126YQ5Z8+OP4/3oY8puvBFzbm7SzutwVALxlYxud9/LbCRTIFBFUdEBhsYg\nhBCZTpIxkVWUyYRz2rQ+zQMb0PmUovy3v4FYjKZHHsH3+WfkH3ccgW++peW558g58kgKfn5yUs9p\n70rGgtWGJmPRaJBQqB6nQ3rGRN9UVFQQCoWwWOQjSAiQZEyIAVMmE+W33Ixj8iQaZz9AzY2/BqUo\nOOkkSq+6csBDolty2CsACAaqk9puXwWD8fM7HMMNjUNkHq01Pp+PnJycpP//ECITSTImRBIopSj4\n2c/IP/54wtXVmHJzsRQUpORc8ZWLioDByZjfvx6ILygQoi9qa2sZNmwYVVVVVFZWGh2OEIaTZEyI\nJFJWK7ZRqa25ZTJZsdvLDE/GAoF4MuZ0Ss+YEEIMxParVQoh0pLDXkEgaHDPWKLGmM1WamgcQgiR\n6SQZEyID2R2VadEzZrdXYDJJB7sQQgyEJGNCZCCHo5JgsAattWExBPzrZSWl6Jf8/Hwef/xx8vPz\njQ5FiLQgyZgQGcjhqCQWCxEONxkWQyBQjUPmi4l+cLlcnHHGGbhcLqNDESItSDImRAZy2LsKvxoz\nVBmLBQmG6qSsheiXpqYmjjnmGJqajLuYECKdSDImRAbatAq/EbqSQKdDyhKIvgsGg7zxxhsEg0Gj\nQxEiLUgyJkQGcmxShd8I/kBVIg7pGRNCiIGSZEyIDGSx5GE2uwwbpgxsKPgqyZgQQgyUJGNCZCCl\nFHa7ceUtAoH1KGVO7AYgRN/YbDYOPvhgbDab0aEIkRakQJAQGcrhqDBsf0p/oEpqjIl+Ky4uZu7c\nuUaHIUTakJ4xITKUw1Fp2JyxQKB6w7w1IfrK7/fzwgsv4Pf7jQ5FiLQgyZgQGcphryAUaiQWG/wV\nacFgLQ57xaCfV2SHlpYWZs2aRUtLi9GhCJEWJBkTIkMZVd5C6xjBYB12e/mgnlcIIbKVIcmYUuqn\nSqmvlVIxpdRMI2IQItN1JUPBYP2gnjcUakLrMHaHJGNCCJEMRvWMfQWcAPzPoPMLkfG6VjIGg7WD\net5gMN4TJ8OUQgiRHIYshdJafwvx5flCiP7ZkIyF6gb1vF3JnwxTiv4qKyujqqqKsjIpjSIESGkL\nITKWxZKD2ewmGBzcZCzQlYw5pGdM9I/ZbKayUlbjCtElZcOUSqk5Sqmvuvn6UR/bOVcptVAptbCh\noSFV4QqRkez20kFPxoKBWpSyYrMWDup5Rfaorq7GarVSXW1MaRYh0k3Kesa01ocmqZ1HgEcAZs6c\nqZPRphDZwm4rG/xkLFiL3V6GUrIYW/RfJBIxOgQh0oa8mwqRwez2cgOGKWtkvpgQQiSRUaUtjldK\nrQf2At5USr1jRBxCZDq7vYxgsB6tB6/TOBioxSHzxYQQImkMSca01v/QWg/XWtu11mVa6yOMiEOI\nTGe3l6F1iHC4eVDOp7UmEKyVnjExILm5ufzhD38gNzfX6FCESAuymlKIDLax1lgdNltRys8XDjej\ndQiHJGNiADweD9dcc43RYQiRNmTOmBAZbNNkbDBsrDEmw5Si/1paWjjjjDNkb0ohEiQZEyKDDXYy\ntrHGmPSMif7z+/08+eST+P1+o0MRIi1IMiZEBrPZSgA1eD1jAdkKSQghkk2SMSEymMlkxWYrHrT9\nKQPBWpSyDMr8NCGEGCokGRMiw9ntZYO2P2UwWIPdVopS5kE5n8hOFouFyZMnY7HIGjIhQFZTCpHx\n7PYyAoGqQTlXMFAr88XEgJWWlrJ48WKjwxAibUjPmBAZrqvw62CQGmMiGYLBIHPnziUYDBodihBp\nQZIxITKc3VZGONxMLJbaDzatNcFgrUzeFwPW1NTEoYceSlNTk9GhCJEWJBkTIsN19VSluncsEmkl\nFgtIz5gQQiSZJGNCZLjBqjUWCFQD4HAMS+l5hBBiqJFkTIgMZ7eXAqS8vMXGZEyGKYUQIpkkGRMi\nww3WMOXGZKwypecR2a+kpIQvv/ySkpISo0MRIi1IaQshMpzFkovJ5Eh9z1iwGpPJhtUqBV/FwFit\nVqZMmWJ0GEKkDekZEyLDKaUS5S1SP2fMbq9EKZXS84jsV1tbS2VlJbW1g7NzhBDpTpIxIbKA3V4+\nCMlYjQxRiqSIxWLU1NQQi8WMDkWItCDJmBBZwG4vTXkyFgxUSzImhBApIMmYEFkgvj9lLVrrlLQf\ni4UIhupx2CUZE0KIZJNkTIgsYLeXE4uFiETaUtJ+vNdNS8+YSAq3283VV1+N2+02OhQh0oKsphQi\nC2xa+NVqzU96+1LWQiRTXl4ed955p9FhCJE2pGdMiCywMRlLzeo0ScZEMrW1tXHNNdfQ1paanlwh\nMo0kY0JkAbsttVsiBYLxZMwum4SLJPB6vdx11114vV6jQxEiLUgyJkQW6NoSKZCqZCxQhdVahNns\nSEn7QggxlEkyJkQWiFfGLySUsmRMyloIIUSqSDImRJZIZeFXKfgqkslkMlFRUYHJJB9BQoCsphQi\na6RqSyStNcFgNUVF+yW9bTE0lZeXU11dbXQYQqQNuSwRIkvY7aUEUrCaMhJpIxr1ScFXkTThcJjF\nixcTDoeNDkWItCDJmBBZwm4vJxxuIhYLJbVdKWshkq2hoYGpU6fS0NBgdChCpAVJxoTIEl21xkKh\nxqS2K8mYEEKkliRjQmSJVBV+DQSq4u1LMiaEECkhyZgQWcJuLweSX2vMH1iH2ezCZi1KartCCCHi\nJBkTIks4UtQz5vevxekYgVIqqe2KoauoqIg5c+ZQVCQJvhAgpS2EyBoWSz4mky3p5S38/rW4nKOT\n2qYY2ux2O4cccojRYQiRNqRnTIgsoZTCZkturTGtY/GeMefIpLUpRH19PVOmTKG+vt7oUIRIC5KM\nCZFFkl34NRRqIBYLSjImkioSibBkyRIikYjRoQiRFiQZEyKLOOzlBIM1SWvP518LIMmYEEKkkCRj\nQmQRh2MYgUANWseS0p7fvwaQZEwIIVJJkjEhsojDORytwwRDyZmL4/evBUxS8FUkldPp5PTTT8fp\ndBodihBpQVZTCpFFupKmQKAKR6Lu2ED4/WtxOCoxmWwDbkuILgUFBTzxxBNGhyFE2pCeMSGyiNMx\nHICAvyop7fl83+NyjUlKW0J06ezs5M4776Szs9PoUIRIC5KMCZFFHI5hAAQC6wfcltYan2+1JGMi\n6drb27n22mtpb283OhQh0oIkY0JkEbPZidVaiD8w8J6xUKiRaLRTkjEhhEgxScaEyDJOx/ANm3sP\nhM+3CgCXU5IxIYRIJUnGhMgyDufwpAxT+nzfA0jPmEgJi0XWjwnRRf43CJFlHI5KGhvnoHUMpfp/\nveXzf4/JZMPhqEhidEJAZWUl4XDY6DCESBvSMyZElnE6RhCLhQiFGgbUjs+3GqdzNEqZkxSZEHHR\naJTq6mqi0ajRoQiRFiQZEyLLdFXL79rKqL+83pW4XGOTEZIQm6mrq2PYsGHU1SVvH1UhMpkkY0Jk\nma5krGsro/6IRn34/WvweCYkKywhhBDbIMmYEFnG4RiGUmb8vv4nY17vSkDjcUsyJoQQqSbJmBBZ\nxmSyYrdXJvaV7J/OzmUAeDw7JissIYQQ2yDJmBBZyOUcObBkzLsMk8mxYchTiGQqKCjg+eefp6Cg\nwOhQhEgLkowJkYWczpEDmsDf2bkMt3u8rKQUKeF0OjnxxBNxOp1GhyJEWpBkTIgs5HSOJBJpJRzu\n+95/Wms6O5fJ5H2RMo2NjRxyyCE0NjYaHYoQaUGSMSGykNM1CgC/f3WfnxsIVBEON5GbMznJUQkR\nFwqFePfddwmFQkaHIkRakGRMiCzkdo0DulZF9k1b2+cA5OVNT2pMQgghuifJmBBZyOkchVI2vN4V\nfX5uW/sizGYXbilrIYQQg0KSMSGykMlkwe0aQ2d/krG2ReTkTMZkkq1rRWrY7XaOPvpo7Ha70aEI\nkRYkGRMiS7nd4/vcMxaN+uns/Ja8vBkpikoIKCoq4vXXX6eoqMjoUIRIC5KMCZGl3O7xBALriUS8\nvX5OW9sitI6Qn7drCiMTQ53P5+OJJ57A5/MZHYoQaUGSMSGylNszHgCf77teP6e5ZR5KWcjP3y1V\nYQlBa2srZ555Jq2trUaHIkRakGRMiCzlcce3MursXNrr5zQ3zyM3dxoWiydVYQkhhNiCJGNCZCmn\ncxQWSx5tbYt6dXw43EJHx1cUFu6b4siEEEJsypBkTCl1l1JqqVJqsVLqH0qpfCPiECKbKWUiL286\nbe29S8aamj8ENIWFe6c2MCGEEJsxqmfsP8AkrfUUYDlwvUFxCJHV8vJm4PWu6NW2SPX1b2GzlZKX\nO20QIhNDWXl5Oa2trZSXlxsdihBpwZBkTGv9b611JHFzPjDciDiEyHZ5ufEq+u099I5FIh00Nf2X\n0tKjZHNwkXJKKVwuF0opo0MRIi2kw5yxM4G3jQ5CiGyUmzsVMNHa9tl2j2to+A+xWIjysqMHJzAx\npNXU1GCz2aipqTE6FCHSQsqSMaXUHKXUV918/WiTY24AIsDfttPOuUqphUqphQ0NDakKV4isZLG4\nycubRlPTf7d5jNaadeufxuUaQ26u7EcphBCDLWX7nWitD93e40qp04GjgUO01no77TwCPAIwc+bM\nbR4nhOheSfFhrPzuDwQC1TgclVs93tq6gI6OJUyYcKsMGwkhhAGMWk15JHANcKzWWkowC5FCJSWH\nAfGhyO6sXvMXrNZCKspPGMywhBBCJBg1Z2w2kAP8Ryn1hVLqIYPiECLruVxjcLnGUVv3T7bshG5u\nnkdz8weMGnUeZrPDoAjFUJOXl8f9999PXl6e0aEIkRZSNky5PVrrcUacV4ihasSIX7Bs2a9pbv6A\noqL9AYhEOlm+4lYcjuGMGH6qwRGKocTtdnPRRRcZHYYQaSMdVlMKIVKssuInOOyVrFz5e0KhZiIR\nL199fRk+3yp23ul3mEx2o0MUQ0hzczMnnngizc3NRociRFqQZEyIIcBksjFhwi34/N8z/5Mj+Xj+\noTQ1/Zcdx/+WwsJ9jA5PDDGBQIAXX3yRQCBgdChCpAVDhimFEIOvuPggZkz/O2vW/hV0lBEjz6Ig\nfzejwxJCiCFPkjEhhpC8vOlMmfyA0WEIIYTYhAxTCiGEGFRWq5U99tgDq9VqdChCpAXpGRNCCDGo\nSkpKmD9/vtFhCJE2pGdMCCHEoAoEArz++usygV+IBEnGhBBCDKrm5maOPfZYKW0hRIIkY0IIIYQQ\nBpJkTAghhBDCQJKMCSGEEEIYSJIxIYQQg6q0tJQVK1ZQWlpqdChCpAUpbSGEEGJQWSwWxo0bZ3QY\nQqQN6RkTQggxqGpqasjLy6OmpsboUIRIC5KMCSGEGFRaa9rb29FaGx2KEGlBkjEhhBBCCANJMiaE\nEEIIYSCVSd3ESqkOYJnRcQwxxUCj0UEMMfKaDz55zQefvOaDT17zwTdBa53T00GZtppymdZ6ptFB\nDCVKqYXymg8uec0Hn7zmg09e88Enr/ngU0ot7M1xMkwphBBCCGEgScaEEEIIIQyUacnYI0YHMATJ\naz745DUffPKaDz55zQefvOaDr1eveUZN4BdCCCGEyDaZ1jMmhBBCCJFVMi4ZU0pNU0rNV0p9oZRa\nqJTa3eiYhgKl1MVKqaVKqa+VUncaHc9QoZS6UimllVLFRseS7ZRSdyX+xhcrpf6hlMo3OqZspJQ6\nUim1TCm1Uil1ndHxDAVKqRFKqfeUUt8k3sMvNTqmoUApZVZKLVJKvdHTsRmXjAF3AjdrracBv0nc\nFimklDoI+BEwVWu9C/BHg0MaEpRSI4DDgbVGxzJE/AeYpLWeAiwHrjc4nqyjlDIDDwBHAROBk5RS\nE42NakiIAFdqrScCewK/lNd9UFwKfNubAzMxGdNAbuLnPKDawFiGiguA32utgwBa63qD4xkq7gWu\nIf43L1JMa/1vrXUkcXM+MNzIeLLU7sBKrfUqrXUIeJ74hZ5IIa11jdb688TPHcQThGHGRpXdlFLD\ngR8Cf+3N8ZmYjF0G3KWUWke8h0auXlNvR2A/pdQnSqn3lVK7GR1QtlNK/Qio0lp/aXQsQ9SZwNtG\nB5GFhgHrNrm9HkkKBpVSajQwHfjE2Eiy3n3EL6ZjvTk4LSvwK6XmAOXdPHQDcAhwudb6ZaXUz4DH\ngEMHM75s1MNrbgEKiXdv7wa8qJQaq2Up7oD08Jr/ivgQpUii7b3mWuvXEsfcQHxY52+DGZsQqaaU\n8gAvA5dprduNjidbKaWOBuq11p8ppQ7s1XMy7fNUKdUG5GuttVJKAW1a69yenif6Tyn1L+APWuv3\nEre/A/bUWjcYG1l2UkpNBuYCvsRdw4kPx++uta41LLAhQCl1OnAecIjW2tfD4aKPlFJ7ATdprY9I\n3L4eQGt9h6GBDQFKKSvwBvCO1voeo+PJZkqpO4BTiV/UOYhPrXpFa33Ktp6TicOU1cABiZ8PBlYY\nGMtQ8SpwEIBSakfAhmw2mzJa6yVa61Kt9Wit9WjiQzkzJBFLLaXUkcSHFY6VRCxlFgDjlVJjlFI2\nYBbwT4NjynqJjovHgG8lEUs9rfX1WuvhiffvWcC720vEIE2HKXtwDvAnpZQFCADnGhzPUPA48LhS\n6isgBPyzzOBeAAAC30lEQVRChihFFpoN2IH/xD+7mK+1Pt/YkLKL1jqilLoIeAcwA49rrb82OKyh\nYB/iPTVLlFJfJO77ldb6LQNjEpvIuGFKIYQQQohskonDlEIIIYQQWUOSMSGEEEIIA0kyJoQQQghh\nIEnGhBBCCCEMJMmYEEIIIYSBJBkTQqQ9pVRUKfXFJl/X9fH5q5VSSzZ5/p8T9++UuL1IKbXDFs9R\nSql3lVLbLCqtlHpCKXXeFvcdp5R6WyllU0r9L1GGRwghtkneJIQQmcCvtZ42wDYO0lpvWaz4OOD/\ntNa3dXP8D4Ave9g25jni++M+vMl9s4DntNYhpdRc4ERkayUhxHZIz5gQYkhSSv0AuAy4QCn1XjeH\n/Bx4bZPjT1FKfZroSXtYKWUmvm3VTkqpisQxbuJ75b6aeNqriXaEEGKbJBkTQmQC5xbDlCf2o433\nNnn+5Ynq4w8B92qtD+rm+H2AzwCUUjsT7+HaJ9FDFwV+rrWOEt94+WeJ5xwD/HeT3rSvgN36EasQ\nYgiRYUohRCZI1TDl9hRqrTsSPx8C7AosSGyV5ATqE489B/wR+BPxIcpnuhrQWkeVUiGlVM4mbQkh\nxGYkGRNCZDyl1Ajg9cTNh7TWDyWh2YhSyqS1jgEKeEprfX03x30EVCilpgJ7E0/INmUnvo+uEEJ0\nS4YphRAZT2u9Tms9LfGVjEQMYBkwNvHzXOAnSqlSAKVUoVJqVOLcGngBeAp4W2u9IfFSShUBjVrr\ncJJiEkJkIUnGhBCZYMs5Y7/vRxubzhl7uhfHvwkcCKC1/ga4Efi3Umox8B+gYpNjnwOmJr5v6qBE\nO0IIsU0qflEnhBBiU4kVkk9rrQ8bQBuvANdprZcnLzIhRLaRnjEhhOiG1roGeHR7RV+3RyllA16V\nREwI0RPpGRNCCCGEMJD0jAkhhBBCGEiSMSHE/7dbxwIAAAAAg/yth7GnKAJgJGMAACMZAwAYyRgA\nwEjGAABGAWycCMDMYZxTAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = plt.figure(figsize=(10.0,6.0)) # Create figure.\n", + "pdos_energy_index_df = pdos_df.set_index(['Energy (E-Ef)']) # Set index.\n", + "# Sum same orbitals for all atoms:\n", + "sum_orbitals_df = pdos_energy_index_df.groupby(pdos_energy_index_df.index).sum()\n", + "\n", + "plt.axvline(x=[0.0], color='k', linestyle='--',linewidth=1.2) # Plot vertical line in Fermi.\n", + "\n", + "# Spin up.\n", + "plt.plot(sum_orbitals_df['pz_up'],color='C3')\n", + "plt.plot(sum_orbitals_df['dz2_up'],color='C8')\n", + "\n", + "# Spin down.\n", + "if ispin == 2:\n", + " plt.plot(sum_orbitals_df['pz_down'],color='C3')\n", + " plt.plot(sum_orbitals_df['dz2_down'],color='C8')\n", + "\n", + "plt.legend() # Add legend to the plot.\n", + "plt.xlabel('E - Ef (eV)') # x axis label.\n", + "plt.ylabel('DOS (states/eV)') # x axis label.\n", + "plt.xlim([-8.0,4.0]) # Plot limits.\n", + "\n", + "fig.savefig(\"Fig2.pdf\") # Save figure EPS." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 3. PDOS: Plot $s$ states, $p$ states ($p$$_x$, $p$$_y$, $p$$_z$) and $d$ states ($d$$_{xy}$, $d$$_{yz}$, $d$$_{xz}$, $d$$_{z^2}$, $d$$_{x^2}$)." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\nWbHim5/jlZWVXH/99WRmZnLxxReza9cuAEaMGEF9fT0+n4/w8HDeeOMNAG677TY+++wzFi1axC23\n3MKkSZNISUnh8ccf7+7bdBqpMyYCWm1dHl5vQ6fWi31bXNwUDhyYR0PDAazWzo2o9aZvqu/7PxmD\nlqnKior/oKqqbIskRB9W+txzuPb6dxTblDac+CeeOOvzNm7cyNKlS9m8eTMej4ecnBwuvfRS5s+f\nT35+Pnl5eQA0NzezfPlyQkNDKS8vZ/z48UyZ0v6+wHv27OHVV19l3Lhx3HHHHfz1r3/lwQcfPK2d\nw+Hgvvvu4/PPP+f888/nlltuaT325JNPcuGFF/LBBx/wn//8hzvvvJMtW7Zw8cUX8+WXXxIXF0dK\nSgrr1q3jtttuY+PGjbz66qscOnSI7du3s3XrVoxGI6mpqcyaNYvExMSzfo/OREbGRECz2z9HUfRE\nRo4/q/NiY64BFMrL/9UzgXWT23Wi4Ksfq+9/m9U6nObmatzu8h7pXwgReNavX8/NN9+MxWLBZrMx\nbdo01q1bd1o7VVWZM2cOmZmZXH311RQUFFBZWdlu34MHD2bcuHEAzJgxg/Xr17fZbs+ePaSmpjJk\nyBAUReF//ud/Tonv9ttvB+Dqq6+muLiYxsZGcnNzWbt2LWvXruUnP/kJeXl5HD16lLi4uNaixFde\neSWhoaFYLBaGDx/O8ePHu/QenYmMjImAVlW1lrDQ0RgMtrM6z2SKITw8h7Lyjxk8+Kd9bnToZJLU\nEwv4oWWPSoD6hr2YTPLEm/Cv0NBQnn/+eUJD2y81IzrWlREsrS1ZsoTa2lq2bduGwWAgOTkZp9PZ\n7jnf/Rnsz5/JEydO5NVXXyUuLo7f/e53vPXWWyxfvpzc3NzWNiaTqfXver3e79PsMjImApbHU099\n/R4iIi7q0vlxsZNxOPL7ZIkH18mRsZ6apgyRJypFz7FarcyePRur1ap1KMKPcnNzWbZsGU1NTTQ0\nNLBixQpyc3Ox2WzU19e3tqutrSU2NhaDwcCqVasoKur4yfUjR46wefNmAN544w0mTJjQZrsRI0Zw\n8OBBjhw5gqqqvPnmm6fEt3TpUqDlKcukpCRCQkIYPHgwxcXFHDt2jIEDBzJhwgR+97vfMXFix0/g\n+4skYyJg1dRuBVTCw7O7dH5M7CRAR1kfLADrcpej11vR64N7pH+jMRSzKZEG2RZJ9IDq6mruuusu\n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\nzc3NrF27lubmZqejiBQFFWNStmpDO+eNTW+oMhJ5mmSyl5bmv89lrJwY3RIpjLXpvLSfyaQYHHyF\n6ur98tK+zG7xeJzVq1cTj8edjiJSFFSMSdmqrFyE19tAJPLMtM7fvuMPuN2VNDQcneNkM+f3NQMZ\nEonevLQ/PLyZTCZBdfX+eWlfZrdwOMwJJ5xAOBx2OopIUVAxJmXLGEN9/ZGEe/+EtZkpnZvJpOju\nfpDGxuNxuyvylHD6fNlV+PM1iT8W2wignjERkQJQMSZlraH+KJLJ8K4nAyerL/IUyWRf0awt9l7+\n7Cr88Xh+irFobCPGeKiqWpyX9kVE5B0qxqSs1Tf8DQDh3iemdN6O7b/H7a6ivv6ofMSasXc2C8/P\nE5Wx2EaqKvfC5fLnpX0REXmHijEpa35fI8HgAYTDj0/6nHQ6zo7uB2hqPLEohyjhnf0p8/VEZSy2\nUUOUkjdNTU2sWbOGpqYmp6OIFAUVY1L2GuqPor//BZLJ/kkdHw4/SioVpbX1Y3lONn1utx+PpyYv\nWyIlkxHi8U4VY5I3Xq+X5cuX4/V6nY4iUhRUjEnZG30aMkNv35OTOr6r6258vibq6z+Y32Az5PM1\n52VLpNFtkDR5X/Knq6uL9vZ2urq6nI4iUhRUjEnZq6lZiccTnNRQZTIZoSf8GK0tp2KMuwDpps/v\nb8rL05R6klLyLZPJ0NnZSSYztaecRcqVijEpey6Xh/q6D9EbfmLCrZG27/gD1iZpbf1ogdJNn9/X\nTDwPw5Sx2Ea83vpd89JERCS/VIzJrNDYeDzxxHb6+58b97iurnuoqtqb6uqlBUo2fT7f6GbhM9l7\ncyw7J+9rGyQRkcJQMSazQlPT3+J2V9LZ+T97PGZw8HX6+5+lteVjJVGI+PzNZDJx0ulYztq0Nk1M\n2yBJnlVVVfGtb32Lqqoqp6OIFAUVYzIreDxVNDV9mO07/kA6PTLmMW9v/TUul4/29k8VON30+LNr\njeVy4dehobfIZEYIqhiTPAqFQlx22WWEQiGno4gUBRVjMmu0t32SdDpGV9fd73svmeynq+t3tDSf\ngs/X4EC6qdu5JVIu1xqLDWryvuRff38/F110Ef39k1tuRqTcqRiTWaO29nCCwQN5a8t1ZDKpd733\n5uarSaeHmTf/8w6lm7qdPWOJHPaMxWIbMcZNZeWSnLUp8l6Dg4NcfvnlDA4OOh1FpCioGJNZwxjD\n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\n8TL4ln8AAAAASUVORK5CYII=\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pdos_energy_index_df = pdos_df.set_index(['Energy (E-Ef)']) # Set index.\n", + "# Sum same orbitals for all atoms:\n", + "sum_orbitals_df = pdos_energy_index_df.groupby(pdos_energy_index_df.index).sum()\n", + "# Sum of orbitals for spin up:\n", + "sum_orbitals_df['Total p_up'] = sum_orbitals_df.apply(lambda row: row.px_up + row.py_up + row.pz_up, axis=1)\n", + "sum_orbitals_df['Total d_up'] = sum_orbitals_df.apply(lambda row: row.dxy_up + row.dyz_up + row.dxz_up + row.dz2_up + row.dx2_up, axis=1)\n", + "\n", + "\n", + "# Sum of orbitals for spin up:\n", + "if ispin == 2:\n", + " sum_orbitals_df['Total p_down'] = sum_orbitals_df.apply(lambda row: row.px_down + row.py_down + row.pz_down, axis=1)\n", + " sum_orbitals_df['Total d_down'] = sum_orbitals_df.apply(lambda row: row.dxy_down + row.dyz_down + row.dxz_down + row.dz2_down + row.dx2_down, axis=1)\n", + "\n", + "# Plots:\n", + "fig = plt.figure(figsize=(10.0,6.0)) # Create figure.\n", + "plt.axvline(x=[0.0], color='k', linestyle='--',linewidth=1.2) # Plot vertical line in Fermi.\n", + "\n", + "# Spin up:\n", + "plt.plot(sum_orbitals_df['s_up'],color='C1')\n", + "plt.plot(sum_orbitals_df['Total p_up'],color='C3')\n", + "plt.plot(sum_orbitals_df['Total d_up'],color='C8')\n", + "\n", + "# Spin down:\n", + "if ispin == 2:\n", + " plt.plot(sum_orbitals_df['s_down'],color='C1')\n", + " plt.plot(sum_orbitals_df['Total p_down'],color='C3')\n", + " plt.plot(sum_orbitals_df['Total d_down'],color='C8')\n", + "\n", + "plt.legend() # Add legend to the plot.\n", + "plt.xlabel('E - Ef (eV)') # x axis label.\n", + "plt.ylabel('DOS (states/eV)') # x axis label.\n", + "plt.xlim([-8.0,4.0]) # Plot limits.\n", + "fig.savefig(\"Fig3.pdf\") # Save figure EPS." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 4. PDOS: Plot states of a single atom (e.g. Cu$_2$)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Print list of atoms that one can select:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "List of atoms: ['Cu1', 'Cu2', 'Ga3', 'Ga4', 'S5', 'S6', 'S7', 'S8']\n" + ] + } + ], + "source": [ + "list_of_atoms = list(reversed(pdos_df['Atom Label'].unique()))\n", + "print('List of atoms: ', list_of_atoms)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAmMAAAF3CAYAAADpZ0xtAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAIABJREFUeJzs3Xd4VFX6wPHvmZLeSIEkBAhNUEpA\nQOmiiA0b4k9Yyy7Ydm27upbddYviNru7K+xaVsUGurBrA7uAAiJKky41QCoppJGeOb8/TgIBQhKS\nmbkzk/fzPPPczJ07974hIfedU96jtNYIIYQQQghr2KwOQAghhBCiI5NkTAghhBDCQpKMCSGEEEJY\nSJIxIYQQQggLSTImhBBCCGEhScaEEEIIISwkyZgQQgghhIUkGRNCCCGEsJAkY0IIIYQQFrIsGVNK\nhSilvlVKfa+U2qKUmmVVLEIIIYQQVlFWLYeklFJAuNa6TCnlBFYAv9Baf3Oy98THx+vU1FRvhSiE\nEMIDXC4XOTk5JCYmYrNJB40IXGvXrs3XWie0dJzDG8E0RZsssKz+qbP+0WxmmJqaypo1azwdmhBC\nCA/Kysqia9eurFmzhuTkZKvDEcJjlFL7WnOcpR9JlFJ2pdQG4CDwmdZ6tZXxCCGE8LzOnTuzc+dO\nOnfubHUoQvgES5MxrXWd1noIkAKcpZQaePwxSqlblVJrlFJr8vLyvB+kEEIIt3I4HPTp0weHw7LO\nGSF8ik901muti4ClwEVNvPaC1nq41np4QkKL3a5CCCF8XHZ2NtHR0WRnZ1sdihA+wbKPJUqpBKBG\na12klAoFJgGPWRWPEEII79BaU1JSglUTyHxFTU0NGRkZVFZWWh2KaKeQkBBSUlJwOp1ter+VbcRJ\nwKtKKTumhe4/WutFFsYjhBBCeE1GRgaRkZGkpqZiCgwIf6S1pqCggIyMDHr27Nmmc1g5m3IjMNSq\n6wshhBBWqqyslEQsACiliIuLoz3j2n1izJgQQoiOIzIykoceeojIyEirQ7GcJGKBob0/R0nGhBBC\neFVkZCQPP/ywJGM+4t1330Upxfbt24/sS09PZ968eRZGddTo0aOtDsHjJBkTQgjhVUVFRdx5550U\nFRVZHYoA5s+fz9ixY5k/f/6Rfb6UjH399ddWh+BxkowJIYTwqvLycubMmUN5ebnVoXR4ZWVlrFix\ngpdeeom33nrryP5f//rXLF++nCFDhvDMM89QWVnJzJkzGTRoEEOHDmXp0qUAzJ07lyuvvJJJkyaR\nmprK7Nmzefrppxk6dCgjR46ksLDwhGsuWLCAgQMHkpaWxvjx44+c54orrmDChAn07duXWbOOLlcd\nEREBwLJly5gwYQJXX301/fv357rrrmtyRu6ECROOrNaTn59PwzKKzV3DalJxTwghhLDaR7+GnE3u\nPWfiILj40WYPee+997jooos47bTTiIuLY+3atQwbNoxHH32UJ598kkWLTJGDp556CqUUmzZtYvv2\n7VxwwQXs2LEDgM2bN7N+/XoqKyvp06cPjz32GOvXr+eee+7htdde4+677z7mmo888giffPIJXbt2\nPaZ19Ntvv2Xz5s2EhYUxYsQIJk+ezPDhw4957/r169myZQvJycmMGTOGlStXMnbs2Fb/k7TmGlaQ\nljEhAlnWBiiTlSuEEE2bP38+06dPB2D69OnHdFU2tmLFCq6//noA+vfvT48ePY4kY+eeey6RkZEk\nJCQQHR3NZZddBsCgQYNIT08/4VxjxoxhxowZvPjii9TV1R3ZP2nSJOLi4ggNDeWqq65ixYoVJ7z3\nrLPOIiUlBZvNxpAhQ5o8f3Nacw0rSMuYEIFq63vwnx+bryc+BON+aW08QtSz2+307t0bu91udSi+\no4UWLE8oLCxkyZIlbNq0CaUUdXV1KKV44oknTuk8wcHBR7622WxHnttsNmpra084/rnnnmP16tUs\nXryYYcOGsXbtWuDEGYlNzVBsfC273d7k+R0OBy6XC+CEgrqtuYYVpGVMiEBUdhA++AUkDYG+F8Ky\nv0LBbqujEgKALl26sGvXLrp06WJ1KB3awoULueGGG9i3bx/p6ekcOHCAnj17snz5ciIjIyktLT1y\n7Lhx43jzzTcB2LFjB/v376dfv35tuu7u3bs5++yzeeSRR0hISODAgQMAfPbZZxQWFlJRUcG7777L\nmDFj2nT+1NTUIwnewoULj3nNXddwN0nGhAhEG9+GikMw5Tm4/B9gD4IvHrE6KiEAqK6u5ptvvqG6\nutrqUDq0+fPnM2XKlGP2TZ06lfnz5zN48GDsdjtpaWk888wz3H777bhcLgYNGsS0adOYO3fuMa1U\np+L+++9n0KBBDBw4kNGjR5OWlgaYLsipU6cyePBgpk6d2uaxXPfddx//+te/GDp0KPn5+ce85q5r\nuJvyp7XBhg8frhtmSAghmvHyRVBdBj+rHw/x8W/gu3/DfTsgtJO1sYkOLysri65du5KZmUlycrLV\n4Vhm27ZtnH766VaH4RPmzp3LmjVrmD17tt9eo6mfp1Jqrda6xYxPWsaECDRlebD/G+h/6dF9g/4P\n6qph2wfWxSWEEKJJkowJEWh2fAxo6D/56L7koRDbGzYtsCwsIYQ4mRkzZni0Vcxb12grScaECDQH\nvoHQWOgy8Og+pWDAlZC+EiqLrYtNCCHECSQZEyLQZG2ArmeaBKyx3hNB18Her6yJS4h68fHxrFq1\nivj4eKtDEcInSDImRCCpLoeD20y35PG6nQVBEbB7iffjEqKRoKAgRo4cSVBQkNWhCOETJBkTIpDk\nbDKtX8lnnvia3Qk9x8OuL8CPZlGLwJObm0ufPn3Izc21OhQhfIIkY0IEkqz1ZttUyxhA7/OgaJ95\nCGGRuro6du/efcxSOMI67777Lkoptm/ffmRfeno68+bNszCqo0aPHt3m96anpzNw4MCWD7SYJGNC\nBJLsDRCRCFFJTb/e7SyzzZB6fUIIY/78+YwdO/aYdSl9KRn7+uuvrQ7B4yQZEyKQ5P0AnZspItl5\nADhCJRkTQgBQVlbGihUreOmll3jrrbeO7P/1r3/N8uXLGTJkCM888wyVlZXMnDmTQYMGMXToUJYu\nXQqYQqpXXnklkyZNIjU1ldmzZ/P0008zdOhQRo4cSWFh4QnXXLBgAQMHDiQtLY3x48cfOc8VV1zB\nhAkT6Nu3L7NmzTpyfEREBADLli1jwoQJXH311fTv35/rrruOpgrXr127lrS0NNLS0pgzZ86R/Sf7\nHiZPnszGjRsBGDp0KI88YlYr+cMf/sCLL77Y6uu2hywULkSg0BoKd5sCrydjd5guzExJxoR1wsLC\nuOOOOwgLC7M6FJ+R85e/ULVte8sHnoLg0/uT+OCDzR7z3nvvcdFFF3HaaacRFxfH2rVrGTZsGI8+\n+ihPPvkkixYtAuCpp55CKcWmTZvYvn07F1xwATt27ABg8+bNrF+/nsrKSvr06cNjjz3G+vXrueee\ne3jttde4++67j7nmI488wieffELXrl0pKio6sv/bb79l8+bNhIWFMWLECCZPnnzCckXr169ny5Yt\nJCcnM2bMGFauXMnYsWOPOWbmzJnMnj2b8ePHc//99x/ZP2fOnCa/h3HjxrF8+XJ69OiBw+Fg5cqV\nACxfvpznnnuO7OzsVl23PaRlTIhAUV5gaojF9Wn+uJRhkP091FZ5Jy4hjhMTE8Ps2bOJiYmxOpQO\nb/78+UyfPh2A6dOnH9NV2diKFSu4/vrrAejfvz89evQ4koyde+65REZGkpCQQHR0NJdddhkAgwYN\nIj09/YRzjRkzhhkzZvDiiy8eM25w0qRJxMXFERoaylVXXcWKFStOeO9ZZ51FSkoKNpuNIUOGnHD+\noqIiioqKjrS43XDDDS1+D+PGjeOrr75i5cqVTJ48mbKyMsrLy9m7d++RxdBbum57ScuYEIGiYJfZ\ntpiMjYCvn4WczSYxE8LLSktLeeqpp7j33nuJjIy0Ohyf0FILlicUFhayZMkSNm3ahFKKuro6lFI8\n8cQTp3SexguG22y2I89tNhu1tbUnHP/cc8+xevVqFi9ezLBhw1i7di0A6rjaiMc/P/5adru9yfOf\nqhEjRrBmzRp69erFpEmTyM/P58UXX2TYsKN/Hz1x3cakZUyIQHEkGevd/HFd65v9patSWKS0tJRZ\ns2ZRWlpqdSgd2sKFC7nhhhvYt28f6enpHDhwgJ49e7J8+XIiIyOP+fmMGzeON998E4AdO3awf//+\nI61Gp2r37t2cffbZPPLIIyQkJHDgwAEAPvvsMwoLC6moqODdd99lzJgxp3zumJgYYmJijrSqNcTc\n3PcQFBREt27dWLBgAaNGjWLcuHE8+eSTR1rXvEGSMSECRcEusDkhunvzx0V3hcgkyPjOO3EJIXzS\n/PnzmTJlyjH7pk6dyvz58xk8eDB2u520tDSeeeYZbr/9dlwuF4MGDWLatGnMnTv3mNaiU3H//fcz\naNAgBg4cyOjRo0lLSwNMV+DUqVMZPHgwU6dOPWG8WGu98sor3HHHHQwZMuSYgfbNfQ/jxo2jc+fO\nhIaGMm7cODIyMhg3blybrt8Wyt0zAjxp+PDhes0a+TQvRJPevsFU37+rFf9H3roOcrfALzZ4Pi4h\njpOVlUXXrl3JzMwkOTnZ6nAss23bNk4/vZnZzx3I3LlzWbNmjc8u5N0aTf08lVJrtdYtZpXSMiZE\noCjc03IXZYOUEXBoLxwu8GxMQjRBKUVUVFSTY4KE6IgkGRMiEGgNh/ZBp9TWHZ8i48aEdZKSkigu\nLiYp6STFiUWHM2PGDL9uFWsvScaECAQVh6C6FGJaGC/WIHkoKBtkrvNsXEI0oba2ll27drl9RpoQ\n/kqSMSECQbGZjdTqZCwoHOJPM/XGhPCygwcP0rdvXw4ePGh1KJbzp3Hb4uTa+3OUZEyIQFC032yj\nu7X+PUlpZi1LIYQlQkJCKCgokITMz2mtKSgoICQkpM3nkKKvQgSChmSstS1jAElDYOPbUJoLkV08\nE5cQ4qRSUlLIyMggLy/P6lBEO4WEhJCSktLm90syJkQgKDoAQZEQ2qn170kytX3I/h4iL/BMXEKI\nk3I6nfTs2dPqMIQPkG5KIQJB0X6I6QanUiogabDZSlel8LLY2Fjef/99YmNjrQ5FCJ8gLWNCBIKi\n/afWRQkQHGnWsZRB/MLLQkJCjiwmLYSQljEhAkNbkjEw48aypGVMeFdeXh4jR46UsVJC1JNkTAh/\nV1kCVcUQ3YbBo0lpUJIBh/PdH5cQJ1FTU8Pq1aupqamxOhQhfIIkY0L4u9Ics41swxp/yUPMVsaN\nCSGEZSQZE8LflTUkY20oT5FYP4hfuiqFEMIykowJ4e+OtIy1YZ2/0Bjo1FMG8QuvCgkJ4ZprrmlX\nkUwhAonMphTC3zUkYxFtLNyalAZZskal8J7Y2Fjefvttq8MQwmdIy5gQ/q40B5zhplRFWySlmdmY\nFYfcG5cQJ3H48GFmz57N4cOHrQ5FCJ8gyZgQ/q4sx4wXO5WCr401FH/N2eS+mIRoRnFxMXfddRfF\nxcVWhyKET5BkTAh/V5rTtvFiDRIblkXa6J54hBBCnBJJxoTwd6U5bR8vBhCRYJK5HEnGhBDCCpYl\nY0qpbkqppUqprUqpLUqpX1gVixB+rb0tY2BKXEjLmBBCWMLK2ZS1wL1a63VKqUhgrVLqM631Vgtj\nEsK/VJVCzeG21RhrLCkNdn0G1eUQFOae2IQ4iaSkJKqrq3E4ZEK/EGBhy5jWOltrva7+61JgG9DV\nqniE8EvtqTHWWNJg0C44KJ+FhOdprSkvL0drbXUoQvgEnxgzppRKBYYCq62NRAg/094aYw0aKvFL\n8VfhBTk5OcTExJCTk2N1KEL4BMuTMaVUBPBf4G6tdUkTr9+qlFqjlFqTl5fn/QBF4HLVgb9/MndX\ny1hMdwiJkUH8QghhAUuTMaWUE5OIvam1/l9Tx2itX9BaD9daD09ISPBugCIw1dXCB3fDY6nw9zTY\nvcTqiNquPetSNqYUJA6SQfxCCGEBK2dTKuAlYJvW+mmr4hAd0OcPwdpXoN/F4AiGN6+BnM1WR9U2\npTngDIPgqPafKykNcrdAXU37zyWEEKLVrGwZGwPcAJynlNpQ/7jEwnhER5C5FlbNhhE3w1UvwMyP\nzWLZ7/7MtJj5m4YaY22tvt9YUhrUVUH+jvafS4hmxMTE8PLLLxMTE2N1KEL4BCtnU67QWiut9WCt\n9ZD6x4dWxSM6iBXPQEg0THzIPA+Pg4sfN0sBbX3X2tjawh01xhocGcQvXZXCs8LCwpg5cyZhYVJG\nRQjwgQH8QnhN/i7YtgjOuhVCGnXrnXElxPcziZq/DehvWJfSHeL7giNUBvELjysoKOCyyy6joKDA\n6lCE8AmSjImO4/t5pjtvxC3H7rfZYOzdkLsZ9iy1Jra2cmfLmM0OXQZIy5jwuKqqKhYtWkRVVZXV\noQjhEyQZEx2DywWbFkDv85puSRo41XRffv+W92Nrq6pSqC5rf42xxpLSTMuYy+W+cwohhGiWJGOi\nYziwGor2w6Brmn7dEQwDpsC2D6CqzLuxtVVprtm6q2UMTCX+qhIoSnffOYUQQjRLkjHRMWz7AOzB\n0H/yyY8ZPA1qymH7Yu/F1R7uqjHWmAziF14QFBTEeeedR1BQkNWhCOETJBkTHcOeZdBjFARHnPyY\nbiNNK9O2970WVrscWQop0X3n7HwGKLsM4hceFR8fzxdffEF8fLzVoQjhEyQZE4GvNBcOboFeE5o/\nzmaDfpeYivw1Fd6IrH1KPdAy5gyBhP7SMiY8qqKigrfffpuKCj/4fyaEF0gyJgLfnmVm2+vclo/t\nf4npqtzzpUdDcouyXNP1GuLmwplJabJguPCoQ4cOMX36dA4dOmR1KEL4BEnGRODbsxTC4o6Oh2pO\n6niztND2RZ6Pq73Kct1Xfb+xpMFw+ODRljchhBAeJcmYCGxaw+6l0PMc0w3ZEkcQ9DkfdnwMrjrP\nx9ceZbnu7aJsIIP4hRDCqyQZE4Etb7uZddhrQuvf038yHM6DjDWeiso9SnPdW2OsQeIgs82Rrkoh\nhPAGScZEYGsYL9a7FePFGvSdBDYn/ODjJS7KPJSMhURBbC9pGRMe06VLFzIzM+nSxQO/v0L4IUnG\nRGDbvRRie0NM99a/JyQaUsfCdh9et762GioKIdKNZS0ak0H8woPsdjvJycnY7XarQxHCJ0gyJgKX\nywX7V0HP8af+3n6XQMFOs7i4Lyqrr74f0dkz509Kg6J9UCGz3YT7ZWVl4XQ6ycrKsjoUIXyCJGMi\ncOVtN0v7dDv71N/b7yKz3fGRe2Nyl7KDZuvOgq+NJaWZrXRVCg+pra21OgQhfIYkYyJwHVhttt3O\nOvX3xnSHzgPgh4/dG5O7NCyF5KmWscSGZEy6KoUQwtMkGROB68C3EBZvBqO3Rb+LTDenL3bVNXRT\nemrMWHgcRKXIskhCCOEFkoyJwJXxrWkVa2tR1NMuBl0HOz93b1zuUJoLKAhP8Nw1ZBC/8JCoqCge\ne+wxoqKirA5FCJ8gyZgITIcLoGBX27ooG3QdZpIdXxw3VpZrVhWwOz13jaQ0yN8JVWWeu4bokCIi\nInjggQeIiIiwOhQhfIIkYyIwZXxrtm0ZvN/AZoO+F5qWsboa98TlLmW5nuuibJCUBmjI3ezZ64gO\n59ChQ8ycOVPWphSiniRjIjAd+BZsDkge2r7z9LsIqoohfYV74nKX0hzPDd5vkCSD+IVnVFRUMHfu\nXCoqKqwORQifIMmYCEwHvjVrLDpD23ee3hPBGQ5b33VPXO5SdtBzZS0aRCZCeGdJxoQQwsMkGROB\np64GMte2r4uyQVAY9LsYtr4PdT5SF0lrzy0S3phSkDRYao0JIYSHSTImAk/uZqitgG4j3HO+AVPM\n0kPpX7nnfO1VcQhcNZ5Zl/J4SWmQtw1qKj1/LdFhOBwOBg0ahMPhsDoUIXyCJGMi8Bxww+D9xvqc\nD0ERsPl/7jlfe5U2FHz1UjLmqoWDWz1/LdFhdO7cmY0bN9K5s4fHPQrhJyQZE4HnwGqI6grRKe45\nnzPErFW57QPfmFVZ5uVkDGTcmHCrqqoqvvjiC6qqqqwORQifIMmYCDwHvoMUN3VRNhgwBSqLYM+X\n7j1vWzSsS+np0hYAMT0gJFqSMeFWBQUFnH/++RQUFFgdihA+QZIxEVhKsqB4v/u6KBv0mWiSku/n\nufe8bVHq4XUpG1PKtI7JskhCCOExkoyJwOLu8WINHMEw5DrY+t7RZMgqZQdNuY3gSO9cL3Ew5Gz2\njS5aIYQIQJKMicCS8R04QiBxkPvPPeJmM5h97avuP/epKMvxfFmLxpKHQl0V5P3gvWsKIUQHIsmY\nCCwHVpvkwRHk/nPH9TYzK797EWosrBxedtA7g/cbNKxikLXOe9cUAS0hIYHvv/+ehAQPLnQvhB+R\nZEwEjppKyNrQvsXBWzLmbjicB+vf8Nw1WlKa491krFNPCI6GrPXeu6YIaE6nk8GDB+N0enCheyH8\niCRjInBkf2+Kobp7vFhjqWPNTM2V/4Bai6bll+V6Nxmz2SB5iCRjwm1ycnJITk4mJ8fi8ZdC+AhJ\nxkTgOLDabFM82DKmFJz7WzNjc/XznrvOyVSXQ1WJd8eMgemqzNlsXQIqAorL5SI7OxuXy2V1KEL4\nBEnGRODY/w3E9oIID49D6X0u9JkEXz0JJdmevdbxynLN1pstY2CSMVeNWWpKCCGEW0kyJgKDywX7\nv4buo71zvYseNcnJu7eZa3tLQ8HXCC8UfG2soYhuQ+kQIYQQbiPJmAgM+T+YBbR7jPLO9eL7wIV/\nhj1LYfVz3rkmHF0KydvdlNFdIbo77F/l3euKgBQeHs79999PeHi41aEI4RMkGROBYd/XZtvDSy1j\nAMNmmjUrP3/IjKfyhiMtY15OxgC6jzRdwVp7/9oioERHR/P4448THR1tdShC+ARJxkRg2L/KdN11\n6um9ayoFlz8LoZ3gPz+GyhLPX7M0B5QdwuI8f63jdR9pxqwdSvf+tUVAKS4u5oEHHqC4uNjqUITw\nCZKMCf+ntWkZ6zHKJEjeFB4PV79iEpT37vB8q1FZDoQngM3u2es0pftIs93/jfevLQLK4cOHeeKJ\nJzh8+LDVoQjhEyQZE/6vaD+UZHpv8P7xUsfA+Q/Dtvfhm3969lplB70/XqxBwumm+KuMGxNCCLeS\nZEz4v4bkwFuD95sy+i7oNxk+fxjydnjuOt6uvt+YzQbdz5aWMSGEcDNJxoT/2/e1abHpfIZ1MSgF\nl/0NnGHw/l2eK3fh7er7x+s+0sxcLS+0Lgbh92w2G0lJSdhscgsSAiQZE4Fg39cmSbBiHFVjEZ3h\ngj/BgW9g80L3n7+22nRTRnV1/7lbq1v9uLGG1Q6EaIPExESysrJITPRyvTwhfJQkY8K/lWRDwU4z\nbssXDLnOVKv/7CGodvPg5NIsQJuaX1bpeibYnEdLiQjRBjU1NWzcuJGamhqrQxHCJ1iajCmlXlZK\nHVRKyRorom32fmW2Pc+xNo4GNhtc+BeTOK1/w73nLs40Wytbxpyhphr/3i+ti0H4vby8PNLS0sjL\ny7M6FCF8gtUtY3OBiyyOQfizvV9BSAwkDrY6kqN6jIZuZ8Oq2VBX677zltQnY9Ep7jtnW/Q+D7K/\nhzI33UgPF0DRAbMIuhBCdECWJmNa668AGQks2kZr00LTc5xpkfIlo39uSm5sX+S+cxZnmK2VLWMA\nfc4z2z3L2n6OymL44o/w9AB4ohf8bSD8tSv8awwsexTyd7olVCGE8Ac+dgcT4hQc2gvFB3yni7Kx\nfhdDVAqse8195yzJgpBoCI5w3znbImkIhMbC7i/a9v7MtfDP0bDiaegywHTrXv4sjH/AfH/LHoXZ\nw2HupbDjE+8uxC6EEBZwWB1AS5RStwK3AnTv3t3iaIRP2VM/bskXkzGbHYZeD18+ZlrIYtzwu1uS\naRI8q9ns0Od82PGxmeHpCGr9e/cuh3nTzMoFN30GKcOPO+A3ZlLGpv/A6hdg3jXQZZBZlL2XD/6c\nRZvExcXx+eefExdnwbJeQvggn28Z01q/oLUerrUenpCQYHU4wpfs/QoikyC+r9WRNG3odWa7Yb57\nzlecYe1MysYGXgUVh2DP0ta/J2sDzP8RxHSDmz5tIhGrF5UEY34Bv9gAU543XZqvXW7e27BQuvBr\nwcHBTJw4keDgYKtDEcIn+HwyJkSTXC6TjPU8x/vrUbZWTHdIHQubFrhnzcqSTOvHizXoPdFMnNjU\nynpqZXkwfzqExsAN70BkK+pL2Z2QNh3u/A4mPgS7l8Bz4yB9ZftiF5Y7ePAggwcP5uBBSa6FAOtL\nW8wHVgH9lFIZSqmbrIxH+JGDW6E8H3qOtzqS5g262tRBy/6+feepqYDyAt9pGXMEwRlXwPbFUFnS\n/LGuOvjvTaYlbfo8iEo+tWs5Q2DcL+HmL8x4uVcvhTWvtD12Ybna2lo2bdpEba0bZxsL4cesnk35\nI611ktbaqbVO0Vq/ZGU8wo/s+Mhs+0y0No6WnH65KZK6aUH7ztNQYyy6W/tjcpdhP4Gaw/B9C92w\nS/9sZr1e8iQktaMESeJAuHWZGa+26G5JyIQQAUO6KYV/2r4Yug5vXXeXlcJiofe5psRFe7oqi/aZ\nrTsmArhL12GmAOzq508+4/GHj2D5U3Dmj+HMG9p/zeBImPYG9L3AJGTunK0qhBAWkWRM+J/iTMha\nD/0nWx1J6/S9AA6lQ8Hutp/DF5MxgJG3Q+Fu2NDEagP5u+B/P4WkNLj4Cfdd0xEM17xuxq198AuT\n8Am/EhoayowZMwgNDbU6FCF8giRjwv/88KHZ+k0yNslsd37a9nMU7TfdnZFJ7onJXQZMge6j4dPf\nmzpoDYoz4PUpZhD+Na+ZcV/u5AyBaa+blRcW3giZ69x7fuFRnTp14pVXXqFTp05WhyKET5BkTPif\nHz6E2N4Qf5rVkbROp1SI7wc7P2n7OYr2m2WQbHa3heUWSsGlz0BdDbx0IWx5B7590cx6rDgE1y80\n378nBIXDtf+BsHhTj+xQumeuI9yurKyMxx9/nLKyMqtDEcInSDIm/EtlsSkc2n+y75a0aMppF5iS\nDFVtvPm4q3CsJ3TuDzMXg6vR7p/wAAAgAElEQVQGFsyAD++DTj3MYPvkoZ69dmQXk/DVVcOb/wfl\nsrqaPygpKeFXv/oVJSUtzMQVooOQZEz4l52fmZu+v3RRNuh7gYl775dte78vJ2Ngkq67N8FNn8Pt\n38AtSyG+j3eundAPps83LWNvXGUSdiGE8COSjAn/svU9CE8ws/j8SbeREBTZtnFjNRVQlgsxPdwf\nlzvZndBtBHQ+3futlqljzNi0nE0wd/Kx49eEEMLHSTIm/Ed5oVkPceDVvjd2qiWOIOg9wbTsnWqJ\ni6IDZuvLLWO+oN/FcO3bULgX/jUa1r8BdVJU1Fc5HD6/NLIQXiP/G4T/2PKOGRuUNt3qSNqm7wWw\n7QOzekCXAa1/X8PAdEnGWtbnfLhlCbx3J7x3Byx71Py7d0qFiC6m7ltwpGld7ZTqf0l9gEhOTqam\npsbqMITwGZKMCf+xYR50PsPUrfJHfc43252fnloyVrDTbH11QXRfk9APbvzErNKw9lXY+DZUNzFx\nwhkOvSbA8BvNSg7+NCHEz9XV1ZGbm0uXLl2w2yUhFqLFZEwpFQJcCowDkoEKYDOwWGu9xbPhCVEv\neyNkroEL/+q/N82oZOgyCHZ+DmPvaf378neaRbnD4jwXW6Cx2cwkj/6TTbdwVakZd1dRBFUlUJpt\napNtXww/LIYeY+Gyv3tv0kEHl5ubS9euXcnMzCQ5+RTXKhUiADWbjCmlZgGXAUuB1cBBIAQ4DXi0\nPlG7V2u90dOBig5uzUvgCIUhP7I6kvbpez58/ayZ8RcS3br3FOwyrWL+moRaTSkIiTKPxoZeDxc9\nCutfhy9mwfPj4fJ/mMXdhRDCi1oawP+t1vpMrfW9Wut5WuvPtdaLtNZPa60vA64DgrwQp+jIygth\n4wIYOBVC/bxid59J4KqFPcta/578nRAnXZQe4QiCETeZchxJafDfm2DVP62OSgjRwbSUjIUppYJP\n9qLW+qDWeo2bYxLiWKufg5rDMPpOqyNpv25nQXC0mVXZGpUlUJYj3WeeFpUMP34PTr8cPvmNGfjf\nnoXdhRDiFLSUjF0LHFBKva6UukQpJSMthXdVFJlk7PTLTP0qf2d3mhIXuz5v3c2+YJfZSsuY5zmC\n4OpXYMh1sOyv8PnDkpB5SKdOnXjrrbdkbUoh6jU7ZkxrPUUpFQVMAe4CXlJKvQfM11q3sZS4EKdg\nyZ/M4OtzfmV1JO7TZ5IpXpu7GRIHNX9sQzImMym9w+6Ay2eDIwRW/s2suXnhn9s2Xq8014xH2/ul\naeGMP82UZel9Xocf/xcaGsq0adOsDkMIn9Fi0VetdYnW+lWt9cXAQGA98A+l1AGPRyc6toy18N2/\nYcQtLSct/uRIiYtWdFXmbgabE2J7eTYmcZTNBpOfgrN/Bt/MgY8eOLUWMpcLVv4D/jEUlvzRTNYI\ni4XdS8xyTW9eDWV5novfD+Tn5zNx4kTy8/OtDkUIn9DqOmNKqU7AVcA0IBZY6KmghKCyxAymjuoK\n5/3W6mjcKyrJJJe7Podxv2z+2Mx1kDgQHCcduik8QSkz09LmgFWzTQvZ5KdNotac0hx456dmgka/\nS2DSH4+O96utgjUvm+7PF8+DmR9CTDdPfyc+qbq6miVLllBdXW11KEL4hGb/siilIpRSNyilPgS2\nAsOBPwLdtdanUChJiFNQVwP/vRmK9sHUf7e+BIQ/6TMJ9n/T/KLWLhdkfw/JZ3ovLnGUUnDBn2Ds\nL2HtK6aif03lyY/f8YlZhmn/arj8WZg+79iJF45gGHkbzPzI/Nxfu9wkb0KIDq+lbsp04ELgn5gE\n7Kda66Vay6hW4SHVh2HBDNj5iekq6jHK6og8o+8k0HWwe+nJjynYZQqUdpVkzDJKwcQ/wLm/he/n\nwUvnQ/rKY48p3Av/vQXmXQORSfDTL+HMH598XFjXM+H6hWZM2WtXQMUhz38fQgif1lI3ZTetdQWA\nUipUKdVLa/2DF+ISHVHuFtMilrcdLnrMLFMTqFLOMi1+Oz+FAVc2fUzWOrOVljFrKQXnPGC6lhfd\nA3MvMbNb408zlfyz1oM9CMbdB+PvB2dIy+fsdhZc+xa8fhX876fwo7da7gINIMHBwVx66aUEB0v3\nuxDQQstYo0TsMmAD8HH98yFKqfc9H57oECpL4NPfw/PnwOE8uG4BjPyZ1VF5lt0Bp11sluOpPcm4\nmcx1Zv3EhH7ejU00rd/FcNc602LbqYdZwD0o3Mz0/cUGmPj71iViDXqOhwv/YlqBVzzlsbB9UVxc\nHB988AFxcbLElxDQ+gH8DwNnAcsAtNYblFI9PRST6Ci0ho3/gU9/Z5KwodfB+bMgPN7qyLxjwBTY\n+JYpfdB30omv71lmWlBsUt7PZwSFwYibzcMdzroFMr6FJX+GrsNM2YsOoLy8nLfffptp06YRFhZm\ndThCWK617eI1WuvjRxrLuDHRdoV74PUp8M6tENMdblkCV8zpOIkYQO9zITgKNv/vxNeK9kP+D00n\naSJwKGUWKE/oDwtvgqKOUTGoqKiIG2+8kaKiIqtDEcIntDYZ26KUuhawK6X6KqWeBb72YFwiUNVW\nw/Kn4J+jIHMtXPIk3PRpxxyk7giGMy6Hre+alQYaa6hB1keSsYAXFA7T3jCziBf85OTd1kKIgNXa\nZOwuYABQBcwDioG7PRWUCFD7V8ML58AXj0DfC+COb003TUfuhhtxC9SUw4Y3j92/81PTYiiV9zuG\n+D5w5T/NB5RPf2d1NEIIL2upzthvlFJDtdblWuvfaq1H1D9+p7VupuCOEI1UFJlZaC9faAbr/+gt\nmPa6KX7a0SUPgW5nw+rnoabC7Mv7wdSsGji1wy+b06GccTmMuhO+fR42SU1tITqSllrG9gC/UEqt\nV0rNVUpNq6/EL0TLtDY3lTlnwdq5MPJ2uGO1mZUmjprwa1PgdsmfzL/Zsr+CMwxG3WV1ZMLbzn/Y\nJOfv/9wk5QEqMTGRoqIiEhMTrQ5FCJ+gWlu/VSk1FLgIuACwA58DH2utv/VceMcaPny4XrNmjbcu\nJ9ojZzN89CvYtwKS0swg5eShVkfluxb9Eta8BF0GmvUox98P50l3VYdUkgXPjTOTWW7+AoIjrI7I\n7bTW1NbW4nA4UNL6KwKYUmqt1np4S8e1usqg1nq91vqvWutzgUuBLYCb5neLgHG4ABbfB8+Pg4Nb\n4dJn4Jalkoi15MK/wPgHzPqF5/0eJvzG6oiEVaKS4eqXIH8HvHf7qS1S7ieys7MJCgoiOzvb6lCE\n8AmtqjOmlPo/TCtYqVLqd8CZwJ+01rd6NDrhP6rLYfW/YMXfoLoMht8E5z4IYbFWR+YfnCFmQfRA\nWxRdtE2vCTDpETOY/6snzAoAQoiA1dqir7/XWi9QSo0FzgeeAP4FnO2xyIR/cNXBhnmw9C9QmmWq\nyp//MHTub3VkQvi3UXdCziZY+mfoMgD6T7Y6IiGEh7S2m7KufjsZeEFrvRgI8kxIwi/UVsH6N0y9\nsPfvNDMjZ3xo1tuTREyI9msoCJt8JvzvVsjdanVEQggPaW0ylqmUeh6YBnyolAo+hfeKQJK/09QJ\n+9tgeO8OsDvh/141A41Tx1gdnRCBxRkK0980hWHnT4eyPKsjcovo6GieffZZoqOjrQ5FCJ/QqtmU\nSqkwzEzKTVrrnUqpJGCQ1vpTTwfYmMymtEBVGez72qyTuGcZHNwCymbW0Bt5G/SeKLWwhPC0jLUw\ndzJ0OQN+ssiskSmE8HmtnU3ZqjFjWutypdRBYCywE6it34pAVLjHFB3d8TGkrwRXDdiDoccoGPJn\nGHQ1REp9ICG8JmUYTP03vH09/O8WuOY1v165orCwkNtuu41//etfxMbKJB8hWtsy9hAwHOintT5N\nKZUMLNBae7VfSlrGPKimErb8z1SCz95g9sX3g9MuMK1f3UeaLhMhhHW+eQ4+/hUMm2nKxvhpq3RW\nVhZdu3YlMzOT5ORkq8MRwmPc2jIGTAGGAusAtNZZSqnIdsQnfIXLZdZFXPJHKMuFhP5w4V+h30UQ\n28vq6IQQjY38GZTlwIpnILQTnP+Q1REJIdygtclYtdZaK6U0gFIq3IMxCW/Z/42pkp+9wSzBMuV5\nU9/ITz9tC9EhTHwIKg7BiqfN2LFx98n/WSH8XGuTsf/Uz6aMUUrdAtwI/NtzYQmPKs6Azx6CzQsh\nMhmmviSLUgvhL5SCyU+bheWX/AkqS0yBWD/6/+t0Ojn77LNxOp1WhyKET2jtAP4nlVKTgBKgH/AH\nrfVnHo1MuF91OXz9rOniQJvld8bebabNCyH8h80OVz4HQRHw9T+gohAmPwMO/yj/mJCQwDfffGN1\nGEL4jNYuh/SY1vpXwGdN7BO+TmvY8g589gcoPgBnXGk+SXfqYXVkQoi2stlg8lNmybGvnoC8H8ws\nyyjfHxBfWVnJZ599xqRJkwgJCbE6HCEs19rCrZOa2HexOwMRHqA17F4K/54IC2dCSAzMWAzXvCqJ\nmBCBQCk473em8PLBbfD8eNj2gdVRtaiwsJDLL7+cwsJCq0MRwic02zKmlLoNuB3opZTa2OilSGCl\nJwPzKq3hcB4c2geH0qEo3XxdfMCUfNB1YA8yyUx4HMT2hoR+EH8adEr1vXo/WsP+VWa9yPTlEJUC\nlz8LQ67zvViFEO034ErofDosvNHUIus3GS5+FGK6Wx2ZEKIVWuqmnAd8BPwV+HWj/aVa63Z/pFFK\nXQT8HbAD/9ZaP9reczap+rAp21Caa7YlmSbpOrQPivZB0X6oKT/2PeGdzR+yoDBQdqirNu/J+NYk\nbg2c4ZA0GJKHHn3E9jZdCN5WcQi2vgff/htyN0F4Alz8OAybAY5g78cjhPCehH5w6zJYNQeWPQr/\nOBOGXGvGhUqZGuFtWkNlUf19N8dsy/Ohosjsrygy96zKIjOeua4KaquhttLcb9FmtReUaQE+6dd2\n08hgd4LNCXZH/dYJNoe59wVHQnAUhERDSJRpWAmJrn/EQGjM0a1F98pWFX09crBSnYEjHfxa6/1t\nvrBSdmAHpgs0A/gO+JHW+qSr4Q7vHafX/HGSqQhfVwOu2vptDdTVNtrf6HlNBVSXnXiyoEjTqtWp\nB8T0aLRNPZqEnUzFIbNGY94PkLsZstZD9kaorTh67uQhkJTWKEHr5f7ZTlqbGNKXm4r5e5aZ77nL\nQBhxMwy+RgbnC9ERFWfAir/BulfNja3bSLNyRq9zIa635TMvpeirH3PVweF8k2CVHYTSnKPJ1vHb\nuqomTqBMEtQ4AQqKMEmQPdhMQrEHmePQoF3mXtfk15ieqyO5QOOcoP55bRVUlUJlMVSVmGSvOY5Q\nE5/NYZI8m90kfMpmrnnk2vWxaH3c/kav11WjHsxoVdHX1lbgvwx4GkgGDgI9gG1a6wEtvvnk5xwF\nPKy1vrD++W8AtNZ/Pdl7hneP0GseHNIo620iCz5+vyMEIjpDRBeI7AIRiWaAa2gn9/5BqquF/B9M\nYpa1HrI2QM6mo7+MwdH1CV93iO5mYjmSmUeb1x3B5gd+5KFMi131YfMoL4TSbPOHNm87HNxqEkMw\nieQZV5juiuQzLf9jK4TwASVZsGEebFpg/maAafVPHgJxfSG2p5kAEBprts6w+r+jQWB3opUdM7T4\nZC39je8fx/7NafLeUv93qbamhvR9+0nt0R2Ho5kOGq2P+Vt2zJ81rY+9ptLHvtb44Gb+HJ7wp7K5\ne+Ixr+lmXjvu9ba+dkrXPP41l2lpamhxqqsyiUltVev2NU5gKkvM15XFpnVLuzhBSLS5vzbcZ49s\nE+vvv4kQHm/udVb0HDWorWr0/RQ1aqk7dPR5VYlJOl31iZ6uM99z4/sz6th7tVIn7rMHoS553K3J\n2PfAecDnWuuhSqlzgeu11je19d9DKXU1cJHW+ub65zcAZ2ut7zzZe/xuOaS6Gji4DZ2xjpot31C9\nP52a7IPU5BdRd7iWuhobrmpltjU28/PW5i9Dw4/FZtfYHPWPIBfO0DocUU6CuycR3Pc0goaeg+o1\n3rToSQImhGiK1pC/E71nOZXffk7VDzupzs6nphTqqmzUVivqqmzoOoV2qfoP+ApcHf1vSqP746n8\nU7QuDzzuxWbuxarZpye/tk2j7BplM/cS87zx/uNf0yi7Qjns2EKDsIeFYAsPwx4ZgS0qCntUNPYu\nydi7dEdFNkq0IjrLcnkn4e7lkGq01gVKKZtSyqa1XqqU+ls7Y2wVpdStwK0AvRMSKPrfOyinA+Vw\ngMNslcN5ZJ/ZX//c6cQWHIw9Lg6bl6ZPa5eLmv37qdi8hcrNm81j61Zc5Y3GpNlCscd2wh4ZgT0q\nBHtYMEEhDpTTVt8NrupbaDW6FlzVtbiqaqkrq6Ayv4i6vYWwoQBYhS1iE2HDvyF89CgiL7gAZ6Is\n4C2EOKquuJiSTz+l9JNPqVi37ujfIkckzqQuOOLDcYaHEBLmRDlt5kO9veEDvgKbbv5znlInb006\ntinryFc5ZeWMfuF9vr71ChIjwo475vj31D9vuIZq/FwdPYwTDz1B60flNDqnOq6VTx0bS7Mtaa28\nVHPHHd8CeNLXjj1Oa20+4Ne60HXabGtduGrr0DV19dta86iqwVVTg66uQdfUoKuqzFJ5VNc/io69\nrtOJIz7ePBISmn50TsARF2fuyX5Aa42uqKCupARXaSm6rg5da1rHdG0dZgybMvdn29HWL/N/5Gjr\nmDrytQ0V1Pq6f61tGfscuBIzkD8e01U5Qms9um3fdtu6KQeGhOoFqaltup4tMvLoL0mXzgSlpODs\nmoIzJYWgbik4unRB2U9tpqHWmpoDB6jcsoWKzZup3LyFyi1bcJWZMWoqOJjg/v0IHTCQkAFnENS9\nO87kZHOtdvyCuiorqd6zh6qdOylfu47y1aup3rcPgNChQ4m5+mqiJl/itQRUCOF7qvbsIf+55yj5\n6GOoqSGoRw/Cx4wmdNgwQgcMwJmSYtmNUsaM+TatNbqykrrSUlz1j7rSMupKiqkrKKA2L5/avLxj\nHnWHDp14IqWwx8YevffGxmKLrm9hi4rCHhONLSoKW1gYtqAgVHAwKijoaBKjNbhcJhlueBx5juk6\ndLnQtbXmUVOLrq2Bxs9rqnGVlVFXWoartKT+eyqjrrQEV3EJdSVHH9TUuP3f8owftru1mzIcqMAM\nHLgOiAbeaM+MSqWUAzOAfyKQiRnAf63WesvJ3jMsLU2vWrwYXdPoH7upH0Cjfbqy8oRfnJqcHGpz\nco79OOJ04kxKIiil65Ekzdm1K7awULDZ0DU1uIqLqS0oNInQnj1U79mD6/Bh8/04nQT370/IgDMI\nHTiQkIEDCe7dG+Wl5T6q9u6l9JNPKV70AdW7dmOPjqbTddcSO2MG9qgor8QghLBebV4euU88QckH\ni1AhIcRcfTXRV15ByBlnmE/1PkCSscCjq6upLShodK9tImErLDQtT2VNTKrzBqcTe2QktsgI7BGR\n2KOjsDUkhtFRR7tiIyPA6TQNNDYbyu442gpaP0hfu44O4NcuF7iODuZveK6rq+h09dVuTcZOqLbv\njgr8SqlLgL9hSlu8rLX+c3PHu3PMmK6upiY7m+qMDGoyMqnJyKAmM4Pq+q/rmilG6OjcmaDevQju\n1Zvg004jZOAAQvr2PaUmSU/RWlP+7XcceuN1Sj/7HFt0NHE33UTs9ddhC2tmhqgQwq9prSlauJCD\nTzyJrqgg9ic/JvbGG3HExlod2gkkGevYdG2taaEqLqauuBhXRQW6uhpdXY2rqgpdbVqolK1RKYuG\nLkHVeB+mW7BhuJLDcdwwJifK6TRj3iIjTcublz+QtHbMWGuTsXVa6zOP27dRaz24HTGeMm8O4Hcd\nPkxNdjauikozo8LhwBETgz0mBlu4f5SLqNy6lby//4OyL7/EHh9P53vuJnrKFPPLK4QIGHVlh8l+\n8EFKP/2UsBEjSJw1i+BePa0O66RKS0t56qmnuPfee4mMjLQ6HCE8xi3JWKMK/L2BXY1eigRWaq2v\nb2+gp8LvZlP6iPJ16zn4+ONUbNhAyIABdPntg4SdeWbLbxRC+LyqPXvJuPNOqvfto/Mvf0nsjTN9\npjtSiI6utclYS00k84DLgPfqtw2PYd5OxETbhZ05lB7z55H8xBPU5uez79rryLz3Pmqys60OTQjR\nDhWbNrPv2mupKyqi+0svEXfTjX6RiBUVFXHnnXdSVFTU8sFCdADNJmNa62KtdTrwOyBHa70P6Alc\nr5SK8UJ8wk2UUkRfdim9P/qQ+Ntvo/Tzz9l98SXkzZmDq6LC6vCEEKfo8Opv2T9jBrbwcFLnzyN8\n5NlWh9Rq5eXlzJkzh/Ly8pYPFqIDaO3gof8CdUqpPsALQDdMq5nwM7awMBJ+/nN6f7iYiHMnkP/s\nbHZPnkzJRx81XTFbCOFzyteu5cBPf4ojMZEe894kqEcPq0MSQrRDa5Mxl9a6FrgKeFZrfT+Q5Lmw\nhKc5u3Yl5Zln6PH6a9ijY8i855fsvfxyDr39n2ML1AohfErl9u0c+NltOBMT6fHaqzi7dLE6JCFE\nO7U2GatRSv0I+DGwqH6fdwpoCY8KGzGCngsXkPToX8HhJOehh9gxegwHfnYbh956m5rcXKtDFELU\nq96/n/0334ItPJzuL7+EIy7O6pDaxG6307t3b+ynWGhbiEDV2tIWZwA/A1ZprecrpXoC12itH/N0\ngI3JbErP0lpTsXYtJR9/QtmyZdRkZAAQ3LcPYaNGET5qFOFnneU3pT2ECCS1hw6xb/qPqCsqose8\nNwnu3dvqkIQQLXBrnTFfIcmY92itqd69m7Ivv+Tw16soX7MGXVWFCgkh8vzzib7ySsJHj5KaZUJ4\ngauqiv033kTlpk10f+VlwoYNszqkdqmurmbdunWceeaZBPlAsWwhPMVddcY+wAzY/1hrXXPca72A\nGUC61vrl9oXbOpKMWcdVVUXFunWUfPopJR9+hKu4mKDevYm78UaiL7vUJ1YfECIQaa3Juv8BShYt\nouvTTxF1ySVWh9RuUoFfdBTuqjN2CzAO2K6U+k4p9aFSaolSag/wPLDWW4mYsJYtOJjwUaNIeugh\n+i7/iuQnHkc5nWT/9rfsvmQyxYsWm/W4hBBuVfjSS5QsWkTC3XcHRCImhDhRq7splVKpmBmUFcAO\nrbXXp9xJy5hv0VpzePlyDj79DFXbtxMyYACd77+P8JEjrQ5NiIBQ9uWXHPjZbURdfBHJTz3lFwVd\nW0NaxkRH4a6WsSO01ula61Va6w1WJGLC9yiliBg/np7/+y/Jjz1KbWEh+2fMZP+tt1K1e7fV4Qnh\n16r27CXz3vsIPr0/SX/+c8AkYkKIE8noa9FuymYj+oor6P3xR3S+/34q1m9gzxVXkvvXR6krLbU6\nPL9Rk5vLobfeknIigrrSUjLuuAMVFES32bOxhYZaHZJbxcfHs2rVKuLj460ORQifILMphdvVFhaS\n98zfKFq4EHtsLJ3vvZfoKVfKJ/tmlK1YScbtt6Orq7FFR9PtX/+Uxdw7KK01mT//OaVLl9HjlZcJ\nGzHC6pCEEG3k9m7K+pM6lVJDlVKd2x6aCHSO2FiS/vgIqQsWENStG9kPPsj+n8ygas9eq0PzSbWH\nDpH9m98Q1KM73efOxR4eTs6f/iTLU3VQha/MpfSzz+l8370Bm4jl5ubSp08fcqUVWAighWRMKfWc\nUmpA/dfRwPfAa8D6+or8QpxU6MAB9Jj3JomzZlG5bRt7r7jCLExeXW11aD4lf/Ycag8dIvnxxwkf\neTbxd91F1dZtlH3xhdWhCS8rX7uWg089ReSkScT+5CdWh+MxdXV17N69m7q6OqtDEcIntNQyNk5r\nvaX+65mYWZSDgGHAAx6NTAQEZbPRado19P5wMZGTzif/2dnsvXIK5d99Z3VoPqGutJSid94h+tJL\nCTn9dACiL7sUZ/fuFL7+hsXRCW+qzc8n8+57cKZ0JekvMmBfiI6kpWSscRPGJOBdAK11jsciEgHJ\nkZBA16efptsLz6MrK9l3w4/J+t3vqCsqsjo0SxW/8w66vJxO1113ZJ9yOIi68ALK166lrqzMwuiE\nt+jaWjLvu5+6khJS/v537JGRVockhPCilpKxIqXUpUqpocAY4GMApZQDCKzpPcIrIsaPp9eiD4i9\n6UaK33mX3ZMvpfiDDzrs+Kii//6PkMGDCR008Jj94ePGQW0th1etsigy4U15f/8H5d98Q+JDDxHS\nv7/V4XhcWFgYd9xxB2FhYVaHIoRPaCkZ+ylwJzAXuLtRi9hEYLEH4xIBzBYWRpf776fnwgU4k5PJ\nuv8B9t1wA5Vbt1odmldV7dlL1Q8/EH3p5BNeCxs6FFtEBIe/Wm5BZMKbSr/4goIXXyTmmmuIuWqK\n1eF4RUxMDLNnzyYmJsbqUITwCc0mY1rrHVrri7TWaVrruY32f6K1vtfj0YmAFnL66aS+NZ/EWbOo\n3r2HvVOvJvfRx3BVVVkdmleUfvIxAJEXXnjCa8rpJHzUSA5//bW3wxItcFVVUbZiJUX//S+lS5ZQ\nW1DQ5nNVp6eT9atfEzJgAF1++6Abo/RtpaWlPPzww5RKHUIhgFaUtlBKXayU+lIplV//+FIpJQuk\nCbdQdrsZ4P/Jx8RMu4bCuXPZd+111OQE/rDEko8/IfTMM3F26dLk66FDhlKTmUltYaGXIxNNcVVU\nkDdnDjvHjOXAzTeT/dvfkXH7Hew8ZwJZv/oVNVlZp3a+8nIyfv4LlN1Oyj/+ji042EOR+57S0lJm\nzZolyZgQ9VoqbXEL8EdgFtCr/jELeFgpdavnwxMdhT0qiqSHHyZlzmyq9+4l/UfXUpOdbXVYHlOT\nnU3VDz8QOXHiSY8JqR9HVrl5s7fCEidRnZ5O+jXTyH92NuGjRtLtxRfo/fln9Jg3j07X/oiSTz5l\n9yWTOfTWW60a/+iqqiLjzruo2rWL5CefwNm1qxe+CyGEr2qpZewe4AKt9RKtdUn9Ywlwcf1rQrhV\n5MSJdH/9NVylpey/+QnsDh0AACAASURBVBbqyg5bHZJHlC03Y8Eixo876TEhZwwApajYtMlbYYkm\nVO3cSfr1N1Cbn0+3F18k5dlniRg3jqCUFMLOHErigw/S+8PFhA0fTs7Ds8j8+S+anSWsa2rIvPse\nDn/9NUl/+hMR407+OyCE6BhaSsaU1vqEPhKtddsHSQjRgtABA0iZbVrIcv/4R6vD8Yiyr77CkZxE\nUJ8+Jz3GHhFOUK9eVG6SljGrVG7fzr4f/wSlFD3efIOIcWObPM6ZnEy3F56n8wMPULpsGXumXMXh\nb1afcFztoUMcuOMOypYupcsfft9hBuwfTylFVFSU1FITop6jhddLlFJpWuvvG+9USqUB0tkvPCZ8\n5NnE33Yb+XPmEHnhBUSed57VIbmNrq6m/OtVRF12WYs3o9CBAylbuRKttdy4vKxiyxYO3HgTKjSU\nHnNfISg1tdnjlc1G3I0zCRsxgsz77mX/jBlEnHMOUZMvwd6pExUbvufQm2/iOnyYxIcfptP0ad75\nRnxQUlISxcXFVochhM9oKRm7F3hfKfUKsLZ+33DgJ8D1ngxMiPif/ZTSTz8h909/JnzUKGyhgVHa\nrnzdelzl5c12UTYIGTiQ4vfeozYvD2dnWRLWWyo2bmT/zbdgj4ig+2uvEpSS0ur3hg4aSK9336Vw\n7lwK35xH2ZdfHnktfNw4Ot/7yw5RS6w5tbW1pKenk5qaisPR0m1IiMDX7P8CrfUKpdTZwO3AjPrd\nW4GRUoVfeJpyOuny+9+z/8c/ofCNN4i/5RarQ3KLsq++AqeT8JEjWzw2qFdPAKr3pksy5iXl69Zx\n4NafYu/UiR5zX2nT4HpbaCjxt91G3K23UrVrN67SEoJ69cIRG+uBiP3PwYMH6du3L5mZmSQnJ1sd\njhCWa/EjSX3S9QelVEL98zyPRyVEvfCzziJ87FgK575K7PXXB0Tr2OHlXxE2fBi28PAWjw3u2ZCM\n7SH87LM8HVqHV7ZiJRl33okzMZHuc1/BmZjYrvMpu52Qfqe5KTohRKBqqbSFUko9rJTKA34AflBK\n5Sml/uCd8ISA+Nt+Rl1BAUUL/2t1KO1Wk5VF1c5dRIwb36rjHYmJqJAQqvfu9XBkonjxYjJuu42g\n1FR6vPlGuxMxIYRordaUthgDnKW1jtVaxwJnA2OUUlLaQnhF2LBhhKalcWjePL9fw7KsfnmjiHNa\nl4wpm42g1FSqJBnzmLrSUrL/8BBZ995HyKBB9Hh1Lo64OKvDEkJ0IC0lYzcAP9JaH7kTaK33YAbv\n/397dx4mVXXnDfz7q716pZfqFRERFYFmkUZQssgSBRXMZKKYN5kZJdEkMyZqVKLRNzOZiYlL8moS\nExWNJE4SxSxGUVDD4oaiEZGG7kYUBEIv9r7XXuf9owrS0Ybe6ta5dfv7eR4e6ap7z/1yHyl+dc65\n5/yrkcGI+hv3hcsR+uAD9L3xpu4oo9LzyitwlpXBNWnSkM9xnTIRoQ8OGpZpLFJKIXjgA7Tcfz/2\nX7AUHX/4A/JXrcLJv1oLe26u7niWl5+fj6effhr5nENHBGDwOWNOpVTLR19USjWLiNOgTEQfk7N0\nKZp+eAfa1z2OzPnzdMcZkVgohL7XX0fOisGXtOjPfcop6H7+BcRCIdhcLgMTWouKRND317+i9803\nEfmwCZGWZkQ7OxHr6UWkqQmxxFY8mZ/8JHzf/Ca8iR0PyHgejwfLly/XHYPINAYrxkIjfI8oqWwe\nD3KWL0fHE08g2tmZlr0X/h07EktafHpY57lOOQWIxRA6eBCe0zkZfDBKKXRv3Iime3+C8OHDgN0O\nh88HR0EB7OPGwVlSisx5Z8N9xhRkLlgA13huRZRqzc3NWL58OdavXw+fz6c7DpF2gxVjM0Wka4DX\nBYDHgDxEx5V7ySVo/81v0LXxubRcMLPn5VcgTuewn4p0nXwyACB85AiLsUHE/H7U33wLup9/Hu6p\nZ6L83nuQ9alPwZaRoTsa9RMOh/HGG28gHA7rjkJkCoOtM2ZPVRCiwXimT4Nr8qnofOqpNC3GXkbG\n3LlDWtKiv6PrXIWP1BkRyzKi3d3421eugr+qCr4bvoWCVasgdn6EEZH5DTaBn8g0RAS5F18M/86d\nCH/YpDvOsISOHEFo/35knTe8IUoAsOfnQ7xehOtYjB1PrK8Pf7vqavirq1H+05+g8KqrWIgRUdpg\nMUZpJXvxYgBAz9YtmpMMz9EtcbI+NbQlLfoTETjLyxCuN28xpiIRtDy4BgdXXo7Dq1ahc/36lC1D\noqJR1N1wI/xVVSj/8Y+R85nPpOS6NHIejweXXXYZPB7OdiECWIxRmnFNngznhAno3pxmxdjLL8N5\n8oRBN5s+Hmd5OUIm7RlToRCOXPMNNN9zDyCCcH0D6m9ajfobboQKGfucj1IKH95+O3q2bkXxrd9B\nzgXnG3o9So78/HysW7eOS1sQJbAYo7QiIshetAh927cj2tOrO86QxAIB9G1/Y9hPUfbnKi9HuK4+\niamSp+Xhh9Hz4oso/r+3YeLjj2HShmfhu+46dG3YgPqbb4aKxQy7dtsja9H+u8eQv2oV8r/4RcOu\nQ8nV29uL++67D7296fF3mMhoLMYo7WQvWQwVDqP31Vd0RxmSvjffhAoGRzREeZSzvByxzk5EE2tj\nmUXo8GG0PvAgspctPVYMic2Gwq99Fb4bvoWuDRvRcv/9hly7a8MGNN19N7KXLkXRjTcYcg0yRmdn\nJ77xjW+gs7NTdxQiU2AxRmnHO3s27Hl56N60WXeUIel58SWI14uMs+eOuI1jT1SabKiyde1aAEDx\nzbd87L2Cr3wFOSuWo+W+n6PnlVeTet2uF15A3U2r4a2cg7I774DY+FFGROmLn2CUdsRuR9bCheh5\n+WUok69TpGIxdG/ZgsxzzoHN7R5xO87y8QDMVYxFu7rQ+eenkHPxxXAWF33sfRFB6fe+B/dpp6H+\nxhuTlr170ybUfesGeCsqcNIDD47qvhIRmQGLMUpL2YsXIdbVhb4db+uOckL+HTsQaWxEzoUXjqod\nZ3kZAJhq3ljnk09C+f3I/9Lx52rZvF6M/+lPoKJRHLnuesRGMaFfxWJoffhhHLn2OninTcNJDz8E\ne9bw1mwjIjIjLcWYiFwqItUiEhORSh0ZKL1lzJsP2O3off113VFOqPPZZyFeL7IXLRxVO/a8PIjb\njXBjY5KSjV7n0+vhmT4dnqlTT3ica+JElP7gdgR278aH//P9ES15EWltxZH/uAZNP/oxspcswUm/\nfBj2rKyRRifNSktLEQqFUFpaqjsKkSno6hnbA+BzAF7WdH1Kc/asTHgrKtC73bzFmAqF0P3c88he\ntGjU2/GICBwlxYg0NiQp3eiEDh5EoLoaORddNKTjc84/HwVXXYWO3/8eLT//xZCvEwsG0fLQQ9h/\n/gXoefVVFN96K8rvvYeFWJpTSqGvry9la9ERmd1ge1MaQilVC8T/gSEaqYxz5qP1wTWIdnfDnp2t\nO87HdG/ZimhHB3I/e0lS2nOWlCLcYI6esc5nnwVEkHPhsiGf47v+OkSam9Fy331QwSB811933In3\n0a4utK9bh/b//Q0iTU3IWrgQRTfdCPekScn6I5BGjY2NKC8vR11dHcrKynTHIdJOSzFGlAyZ889B\n6/0PoO+vb416GNAIHX/4Axylpcg899yktOcsKUHvm28mpa3R6t60Gd6zzoKzuHjI54jNhtLbvw9x\nu9H60EPo2/k2fP/+78iorIS4XIh2dqL3zTfRvXEjure+COX3I/Pcc1B2153InD/fwD8NEZFehhVj\nIrIJQMkAb92qlHpqGO1cDeBqAJgwYUKS0pEVeGfNhLjd6N3+uumKsdCROvRu24bCr389aXskOkpL\nEGlqgopGte67GGlpQbC2Fr7rrx/2uWK3o+S//hPeWbPQdMcdOLzqy4DDAZvLhVhfH4D4/LjcFSuQ\nd/lKeM48M9nxiYhMx7BiTCm1JEntrAGwBgAqKys5wYCOsbndyJhzFvq2v6E7yse0/frXgN2OcZdd\nmrQ2nSWlQDSKSHMznCUDfc9Jjd5t2wAAmQsWjOh8EcG4f/osci5chp4XX0KgpgYqEIC9sADeiop4\nT5mDnfZENHbwE4/SWsa8+Wi+5x5EWlvhKCjQHQcAEO3oQMcf/4jciy5KatHkLI23FW5o0FqM9Wzb\nBnteHjxTR9drZXO7kXPB+dxPcgwaN24cHnnkEYwbN053FCJT0LW0xT+JyBEA5wB4VkSe15GD0l/m\nOfG5RH1vmKd3rOXBNfH1t768KqntOkriywBENC5voZRC7+uvI/Occ7jqPY1YRkYGrrzySmSM8ilj\nIqvQ8mmqlHpSKTVeKeVWShUrpS7QkYPSn2fqVNiystBrkqHK0MGDaPvNb5D7z5+D5/TTk9q2syQ+\nWV7nE5Xhw4cRbW4Z1dZORK2trVi+fDlaW1t1RyEyBX61pbQmDge8c85C31tv6Y4CpRQa//u/YXO5\nUHTttUlv35aTA8nIQFjjWmN9b+8EAHjPOktbBkp/wWAQzzzzDILBoO4oRKbAYozSXsacSoQOHECk\nrU1rjs4/PYne115H0Y03wOHzJb19EYGzqAiRpuaktz1U/rd3wJaTA/fkydoyEBFZDYsxSnsZlXMA\nAH07dmjLEHz/fTTefjsy5s7FuJUrDbuOw+dDpEVfMda3421kzJ7N+WJEREnET1RKe57p0yEuF/xv\n6SnGoj29OPLNa2HzelH2ox8ZWqg4fD5EmvUUY5H2doQOHOAQJY2ay+XCokWL4HK5dEchMgUubUFp\nz+ZywTtzppZ5Y0opNH73uwgdPIgJjzwCZ3GRoddz+AoRaW4x9BrH498Zny+WMYfFGI1OYWEhNm/e\nrDsGkWmwZ4wswVs5B4HaWkR7elN63c4//QldGzbA981vInP+PMOv5/D5oPr6EOtN7Z8TiA8Di9MJ\nT0VFyq9N1uL3+7Fu3Tr4/X7dUYhMgcUYWULGnEogFoP/nXdSds3QoUNovP0HyJg3DwVXX5WSa9oL\nCwFAy1Cl/+2d8EyfDpvbnfJrk7W0t7fj8ssvR3t7u+4oRKbAYowswTtrFmCzoW9HaoYqVTiMutWr\nIQ4Hyu74YcomtB99SjPSktqhylggAP+ePRyiJCIyAOeMkSXYszLhmTo1ZZP42x59FIFdVSi/9x44\nS0tTck0AcBQmirEU94wFqquBcJiT94mIDMCeMbKMjDlz4K+qggqFDL1OpK0NLfc/gKzzzkPO0qWG\nXuujHEVHi7HU9oz5d+8GAHg5X4yIKOlYjJFleGfPhgoGEdi719DrtDzwAGJ+P4puutHQ6wzEnpsL\nOJ2p7xnbUw1HSYkhi9nS2FNcXIy6ujoUFxfrjkJkCizGyDK8s2cD+PsSDEaItLWh44nfI3f5crhP\nPdWw6xyP2GxwFBSkvhjbvRveiukpvSZZl91uR1lZGex2u+4oRKbAYowsw1lcBGdZGfp2GvdEZduj\nj0IFgyl7enIg8VX4UzdMGe3qQujQIXimsRij5Kivr4fT6UR9fb3uKESmwGKMLMU7a5Zhy1vEAgF0\nPL4OWYsXwT1pkiHXGApHYWFKe8YCNTUA4jsdECVLJBLRHYHINFiMkaV4Z89GpLER4YaGpLfdtWEj\noh0dyP/SvyS97eFIdc9YYM8eAIBn2tSUXZOIaCxhMUaWYuS8sfbf/Q6uyaciY97ZSW97OBw+H6Jt\nbVAp6lkI1NTCWV4OR15eSq5HRDTWsBgjS/GccTrE40Ffkocqg/v3I7BnD/IuvRQiktS2h8vhKwSU\nQqS1LSXXC9TUwDP1zJRci8aGnJwc3HnnncjJydEdhcgUWIyRpYjTCW9FBfxJnsTf9dxzgAiyU7yu\n2ECOrcKfgnlj0Z4ehA4ehGcqhygpebKysrB69WpkZWXpjkJkCizGyHK8s2cjUFuLWCCQtDa7n3sO\n3jlnwWmCdZEcx/anbDL8WsHEmm0sxiiZ2tvbceWVV3JvSqIEFmNkOd5Zs4BI5NjE89EKvvcegu+9\nj5xly5LS3milcn/KY09SshijJPL7/fjVr34Fv9+vOwqRKbAYI8vxzp4FAOhL0iT+rueeB0SQc/75\nSWlvtOzHesaMH6YMVNfA4fNx5X0iIgOxGCPLceTlwTVxYlLmjSml0LVxIzLmzjVNQWJzuWDPzUU0\nFT1jtbVwc/I+EZGhWIyRJR1d/FUpNap2gvveQ+jAAeQs0z9xvz9Hkc/wnrFYIIDg/v0coqSkczgc\nqKiogMPh0B2FyBRYjJEleWfPRrStDeHDh0fVTs+WzQCA7CVLkhEraeyFhYg0G9szFty3D4hGWYxR\n0hUVFaGqqgpFRUW6oxCZAosxsqRkzRvr3voiPDNmmGaI8iiHz/iesaOT970sxijJgsEgNm/ejGAw\nqDsKkSmwGCNLck+eDFtW1qj2qYw0NyNQVYXsheclL1iSOArjxdhoh2FPJFBdA3tuLhxlZYZdg8am\n1tZWLFmyBK2trbqjEJkCizGyJLHZ4J05c1ST+HteegkAkLVwYbJiJY3D54MKhRDr7jbsGoGaGnim\nTdW+4wARkdWxGCPL8s6ejeC+fYj29Izo/O6tL8JRWgr3GWckOdnoOQxe3kKFwwju2wf3mXySkojI\naCzGyLK8s2YBSiFQVTXsc2PBIHpfew3ZCxeasmfo71siGTOJP7h/P1Q4zMn7REQpwGKMLMs7cwYg\nMqJJ/H3bt0P5/aYcogTiS1sAxvWMBaq58j4Zx+fzYdeuXfCZ7MEYIl24yAtZlj07G+7TT0ffW28N\n+9zuLVthy8hAxryzDUg2eseGKQ1a+DVQUwNbRgZcJ59sSPs0tjmdTsyYMUN3DCLTYM8YWVrm/Pnw\n73h7WJuGq1gMPVu3InPBAthcLgPTjZwtOxvidhvXM1ZTA/fUMyE2fkRQ8jU2NqKsrAyNjY26oxCZ\nAj9pydIyF5wLFQqhb8eOIZ8T2LMHkaYmZC9ZbGCy0REROAoLDSnGVDSKwN698JzJIUoyRiwWQ0ND\nA2KxmO4oRKbAYowsLaOyEuJ0ove114Z8TvfmLYDdjqxPf9rAZKPn8PkQaUl+MRY6dAjK74eHT1IS\nEaUEizGyNFtGBryzZ6P3tdeHfE735k3IqKyEfdw4A5ONnlGr8AdqagEAnmnsGSMiSgUWY2R5meee\ni2BtLSJDWO07dOgQQu/vR/biRSlINjoOXyGiBixtEaipgbhccE+alPS2iQAgMzMTN910EzIzM3VH\nITIFFmNkeZkLzgUA9G7fPuix3Zu3AACyFpl3vthRDp8P0c5OxEKhpLYbqK2B+7TTIE5nUtslOio3\nNxd33XUXcnNzdUchMgUWY2R5nqlTYcvNHdK8se7Nm+GeMgWu8eUpSDY69sTyFtEkDlUqpRCsqYVn\nKueLkXE6OzuxevVqdHZ26o5CZAosxsjyxG5H5rx56H3t9RNurB1uaoJ/505kLzL/ECUAOIuKACR3\n4ddIQwOinZ3cBokM1dvbi7vvvhu9vb26oxCZAosxGhOyPv0pRBoajq0sP5CuDRuAWAw5F12YwmQj\nd3RLpHASi7FAbXzyvpcr7xMRpQyLMRoTsj/zGYjTia71Tx/3mK6n18MzbRrcp56awmQj5zjaM9bU\nlLQ2A9U1gM1mys3RiYisisUYjQn2nBxknXceOp/dABWJfOz9wLv7EKipQc7yizWkGxl7fj5gtyd1\nmDJQWwvXKafA5vUmrU2ij7LZbCgtLYWNOzwQAWAxRmNIzorliLa0oOellz72Xtsjv4RkZCD3kks0\nJBsZsdniq/A3JbcY42KvZLSSkhLU19ejpKREdxQiU2AxRmNG9sKFcJaXo3XNQ/8wkT9cV4fOZ55F\n3qWXwpGXpzHh8CVz4ddIezsijY0sxshw4XAYVVVVCIfDuqMQmYKWYkxE7haRvSJSJSJPioi5lzon\nSxCHA/lfXgX/rl3ofXUbgPhSDo0/+CHEbkf+Ff+mOeHwOYqKkjZnLFATf7iBK++T0ZqbmzFz5kw0\nG7TRPVG60dUz9hcA05VSMwDsA3CLphw0xoz73OfgmjgR9d/+NvzV1Wh9cA16Nm+G79pr4Swt1R1v\n2JLZM3asGJsyJSntERHR0GgpxpRSLyiljs6i3g5gvI4cNPbYPB6M/8UvoMJhHPznz6P53nuRtWRx\nWvaKAYCjyIdoWxtUElbhD9bWwllWZvo9OYmIrMahOwCAVQDW6Q5BY4d70imY9Owz6H35Zdjz8pC1\naBFERHesETm61liktXXUPXuBmlq4ufI+EVHKGVaMicgmAAM9KnOrUuqpxDG3AogA+O0J2rkawNUA\nMGHCBAOS0ljkLCrCuM9/XneMUeu/1thoirFoTy9Chw6l1dIelL4KCgqwadMmFBQU6I5CZAqGFWNK\nqSUnel9ErgBwMYDF6gR71Cil1gBYAwCVlZXH38uGaAw61jM2ynljwXf3AkrBw5X3KQXcbjcWL16s\nOwaRaeh6mnIpgNUAViil+nRkILKCo/tThkf5RGWgJr4NEosxSoWmpibMmDEDTUncPYIonel6mvI+\nANkA/iIi74jIA5pyEKU1e34+YLONumcsUFsLe37+sWFPIiNFIhHs3r0bkQF2wyAai7RM4FdKTdZx\nXSKrEbs9sQr/KHvGEivvp+uDDERE6Ywr8BOludGuNRYLhRB8/314+CQlEZEWLMaI0lx8Ff6RF2PB\n994DwmHOF6OU8Xq9uOKKK+DlhvREAFiMEaW90faMBWsTk/e5JyWlSF5eHtauXYu8NNsLlsgoLMaI\n0pyjqAjR1laoEW66HKiphS0zE06u40cp0tPTg7vuugs9PT26oxCZAosxojTXfxX+kQjU1MA9ZQrE\nxo8DSo2uri58+9vfRldXl+4oRKbAT1+iNOcoShRjI3iiUkWjCOzdC880zhcjItKFxRhRmnP4Elsi\njWDeWOjAAahAAN5p05Idi4iIhojFGFGaG03PWKCmBgBX3qfUczi0LHNJZEr820CU5hwFBYDDgXDj\nh8M+119dDfF44Jo0yYBkRAMrKytDeIQPnBBZEXvGiNKc2O1wlpQgXFc37HMDNTXwTJkCsdsNSEY0\nsGg0ivr6ekSjUd1RiEyBxRiRBTjLy4ddjKlYDMGaWng4X4xS7MMPP0R5eTk+/HD4vblEVsRijMgC\nnOXlCNfXD+uc0MGDiPX1cb4YEZFmLMaILMBZVoZIUxNiodCQzwlUJybvT2fPGBGRTizGiCzAWV4O\nKIVIQ8OQzwlUV0PcbrhPPdXAZERENBgWY0QW4CwvA4BhDVUGamrgPuMMCJcYoBTLy8vD448/zr0p\niRJYjBFZgLOsHACGPIlfxWLxJym58j5p4PV6sXLlSni9Xt1RiEyBxRiRBThLigG7HaEhFmOhg4cQ\n6+nhyvukRUtLCxYvXoyWlhbdUYhMgcUYkQWIwwFncTHCR4ZWjPmrdgEAPDNmGBmLaEChUAhbtmxB\naBgPnBBZGYsxIotwTpiA8OHDQzo2UFUFW2YmJ+8TEZkAizEii3BNPBmhgweHdKz/nV3wVFRw5X0i\nIhNgMUZkEa6JExHt7ESkvf2Ex8UCAQT27YOXQ5SkidvtxsUXXwy32607CpEp8Jl2IotwnXwyACB8\n6BAcJ1gyIFBTA0Qi8M6amapoRP+goKAA69ev1x2DyDTYM0ZkEa6JEwEAwUGGKv27qgCAPWOkTV9f\nH9auXYu+vj7dUYhMgcUYkUW4xo+PL28xaDG2C86yMjgKC1MTjOgjOjo6sGrVKnR0dOiOQmQKLMaI\nLEKcTrjGj0fo4KETHuev2sUhSiIiE2ExRmQhrokTEfrgg+O+H25qQqS+geuLERGZCIsxIgtxT5mC\n4P79iAWDA74fqDo6X4w9Y0REZsFijMhCPNOnAZEIgnv3Dvh+7/Y3IB4P96QkrUpKStDR0YGSkhLd\nUYhMgcUYkYV4KyoAAP7dewZ8v3fbNmScPRc2ru9EGokIMjIyICK6oxCZAosxIgtxFBfDXliIwJ6P\nF2PhujqEPvgAWQsWaEhG9HcNDQ1wuVxoaGjQHYXIFFiMEVmIiMA7bRr8e3Z/7L2ebdsAAJmf+ESq\nYxER0QmwGCOyGE9FBUL7DyDa2fkPr/ds2QpHWSlckyZpSkZERANhMUZkMVmf/ASgFHpeeunYa5H2\ndvS8+ipyli3jPB0iIpNhMUZkMZ6KCjh8PnRv2nzste7nXwAiEeRedJHGZERxubm5+NnPfobc3Fzd\nUYhMgcUYkcWIzYasJYvR88oriAUCULEYOn7/e7gmTYL7zDN1xyNCZmYmrrnmGmRmZuqOQmQKLMaI\nLChn2TIovx+tax5C51NPI1BdjYKrr+IQJZlCW1sbVq5ciba2Nt1RiEyBxRiRBWWefTZyL1mBlvvv\nR8Ntt8EzcwZyV6zQHYsIABAIBPDEE08gEAjojkJkCg7dAYjIGMW33QYAcJSWIu8L/wdi43cvIiIz\nYjFGZFH27GyU3Xmn7hhERDQIflUmIqKUcjqdmDdvHpxOp+4oRKbAnjEiIkopn8+H7du3645BZBrs\nGSMiopQKBAJYv349J/ATJbAYIyKilGpra8OKFSu4tAVRAosxIiIiIo20FGMi8j8iUiUi74jICyJS\npiMHERERkW66esbuVkrNUErNAvAMgO9qykFERESklZZiTCnV1e/HTABKRw4iIkq9oqIivPfeeygq\nKtIdhcgUtC1tISK3A/hXAJ0AFurKQUREqeVwODB58mTdMYhMw7CeMRHZJCJ7Bvh1CQAopW5VSp0E\n4LcArjlBO1eLyFsi8lZzc7NRcYmIKEUaGhqQm5uLhoYG3VGITMGwnjGl1JIhHvpbABsA/Odx2lkD\nYA0AVFZWcjiTiCjNKaXQ1dUFpfiRTgToe5rytH4/XgJgr44cRERERLrpmjN2h4icASAG4BCAr2nK\nQURERKSVpFM3sYh0A3hXd44xphBAi+4QYwzveerxnqce73nq8Z6n3hlKqezBDkq3jcLfVUpV6g4x\nlojIW7znqcV7cmynHAAABhRJREFUnnq856nHe556vOepJyJvDeU4bodEREREpBGLMSIiIiKN0q0Y\nW6M7wBjEe556vOepx3ueerznqcd7nnpDuudpNYGfiIiIyGrSrWeMiIiIyFLSrhgTkVkisl1E3kls\nk3S27kxjgYh8Q0T2iki1iNylO89YISI3iIgSkULdWaxORO5O/D9eJSJPisg43ZmsSESWisi7IvK+\niNysO89YICInichWEalJfIZfqzvTWCAidhHZKSLPDHZs2hVjAO4C8D2l1CwA3038TAYSkYWI75Qw\nUyk1DcCPNEcaE0TkJADnAzisO8sY8RcA05VSMwDsA3CL5jyWIyJ2AD8HsAzAVABfEJGpelONCREA\nNyilpgKYD+A/eN9T4loAtUM5MB2LMQUgJ/H7XAD1GrOMFV8HcIdSKggASqkmzXnGinsArEb8/3ky\nmFLqBaVUJPHjdgDjdeaxqLMBvK+UOqCUCgF4HPEvemQgpVSDUurtxO+7ES8QyvWmsjYRGQ/gIgAP\nD+X4dCzGrgNwt4j8DfEeGn57Nd7pAD4pIm+IyEsiMld3IKsTkUsA1CmldunOMkatArBRdwgLKgfw\nt34/HwGLgpQSkYkAZgN4Q28Sy7sX8S/TsaEcbMoV+EVkE4CSAd66FcBiANcrpf4oIpcB+CWAJanM\nZ0WD3HMHgHzEu7fnAnhCRCYpPoo7KoPc8+8gPkRJSXSie66UeipxzK2ID+v8NpXZiIwmIlkA/gjg\nOqVUl+48ViUiFwNoUkrtEJHzhnROuv17KiKdAMYppZSICIBOpVTOYOfRyInIcwDuVEptTfy8H8B8\npVSz3mTWJCIVADYD6Eu8NB7x4fizlVKN2oKNASJyBYCvAlislOob5HAaJhE5B8B/KaUuSPx8CwAo\npX6oNdgYICJOAM8AeF4p9f9057EyEfkhgH9B/EudB/GpVX9SSn3peOek4zBlPYBPJ36/CMB7GrOM\nFX8GsBAAROR0AC5ws1nDKKV2K6WKlFITlVITER/KOYuFmLFEZCniwworWIgZ5q8AThORU0TEBeBy\nAE9rzmR5iY6LXwKoZSFmPKXULUqp8YnP78sBbDlRIQaYdJhyEFcB+ImIOAAEAFytOc9Y8AiAR0Rk\nD4AQgH/jECVZ0H0A3AD+Ev+3C9uVUl/TG8lalFIREbkGwPMA7AAeUUpVa441FixAvKdmt4i8k3jt\nO0qpDRozUT9pN0xJREREZCXpOExJREREZBksxoiIiIg0YjFGREREpBGLMSIiIiKNWIwRERERacRi\njIhMT0SiIvJOv183D/P8gyKyu9/5P028PiXx804ROfUj54iIbBGR4y4qLSJrReSrH3ntsyKyUURc\nIvJyYhkeIqLj4ocEEaUDv1Jq1ijbWKiU+uhixZ8F8Ael1PcHOP5CALsG2TbmMcT3x32w32uXA3hM\nKRUSkc0AVoJbKxHRCbBnjIjGJBG5EMB1AL4uIlsHOOSLAJ7qd/yXROTNRE/agyJiR3zbqikiUpo4\nJhPxvXL/nDjtz4l2iIiOi8UYEaUD70eGKVeOoI2t/c6/PrH6+AMA7lFKLRzg+AUAdgCAiJyJeA/X\ngkQPXRTAF5VSUcQ3Xr4scc5yAC/2603bA2DuCLIS0RjCYUoiSgdGDVOeSL5Sqjvx+8UA5gD4a2Kr\nJC+ApsR7jwH4EYCfID5E+b9HG1BKRUUkJCLZ/doiIvoHLMaIKO2JyEkA1id+fEAp9UASmo2IiE0p\nFQMgAH6tlLplgONeA1AqIjMBnIt4QdafG/F9dImIBsRhSiJKe0qpvymlZiV+JaMQA4B3AUxK/H4z\ngM+LSBEAiEi+iJycuLYCsA7ArwFsVEodK7xEpABAi1IqnKRMRGRBLMaIKB18dM7YHSNoo/+csUeH\ncPyzAM4DAKVUDYDbALwgIlUA/gKgtN+xjwGYmfhvfwsT7RARHZfEv9QREVF/iSckH1VKfWYUbfwJ\nwM1KqX3JS0ZEVsOeMSKiASilGgA8dKJFX09ERFwA/sxCjIgGw54xIiIiIo3YM0ZERESkEYsxIiIi\nIo1YjBERERFpxGKMiIiISCMWY0REREQasRgjIiIi0uj/A8MxrgAVdSEuAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "\"\"\" Select one atom from the previous list. Remember list_of_atoms[0] corresponds to Atom #1, \n", + "list_of_atoms[1] to #2 ...\"\"\"\n", + "\n", + "atom_selected = list_of_atoms[1] # This is equivalent to atom_selected = 'Cu2' in this example.\n", + "\n", + "pdos_energy_index_df = pdos_df.set_index(['Energy (E-Ef)']) # Set index.\n", + "only_atom_df = pdos_energy_index_df[pdos_energy_index_df['Atom Label']==atom_selected] # Select only one atom (e.g Cu2).\n", + "atom_spin_up_df = only_atom_df.filter(regex=\"up\").sum(axis=1) # Filter, get all bands with spin up. Then, sum all orbitals.\n", + "\n", + "if ispin == 2:\n", + " atom_spin_down_df = only_atom_df.filter(regex=\"down\").sum(axis=1) # Filter, get all bands with spin down. Then, sum all orbitals.\n", + "\n", + "# Plots:\n", + "fig = plt.figure(figsize=(10.0,6.0)) # Create figure.\n", + "\n", + "plt.plot(atom_spin_up_df,color='C1') # Atom spin up.\n", + "\n", + "if ispin == 2:\n", + " plt.plot(atom_spin_down_df,color='C3') # Atom spin down.\n", + "\n", + "plt.axvline(x=[0.0], color='k', linestyle='--',linewidth=1.2) # Plot vertical line in Fermi.\n", + "plt.legend(['Atom spin up']) # Add manually legend to the plot.\n", + "if ispin == 2: plt.legend(['Atom spin up','Atom spin down']) # Add manually legend to the plot.\n", + "plt.xlabel('E - Ef (eV)') # x axis label.\n", + "plt.ylabel('DOS (states/eV)') # x axis label.\n", + "plt.xlim([-8.0,4.0]) # Plot limits.\n", + "fig.savefig(\"Fig4.pdf\") # Save figure EPS." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "## Example 5. PDOS: Plot states for a individual elements and total DOS." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "List of elements: ['Cu', 'Ga', 'S']\n" + ] + } + ], + "source": [ + "list_of_elements = list(reversed(pdos_df['Element'].unique()))\n", + "print('List of elements: ', list_of_elements)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\nAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = plt.figure(figsize=(10.0,6.0)) # Create figure.\n", + "\n", + "plt.plot(total_dos_df['Energy (E-Ef)'],total_dos_df['Total DOS Spin Up'],color='black') # Plot DOS spin up.\n", + "plt.fill_between(total_dos_df['Energy (E-Ef)'], \n", + " 0, total_dos_df['Total DOS Spin Up'],\n", + " facecolor='black', alpha=0.05, interpolate=True) # Fill between spin up and down.\n", + "plt.axvspan(band_gap_lower, band_gap_upper, alpha=0.2, color='C5')\n", + "\n", + "if ispin == 2:\n", + " plt.plot(total_dos_df['Energy (E-Ef)'],-total_dos_df['Total DOS Spin Down'],color='black') # Plot DOS spin down.\n", + " plt.fill_between(total_dos_df['Energy (E-Ef)'], \n", + " 0, -total_dos_df['Total DOS Spin Down'],\n", + " facecolor='black', alpha=0.05, interpolate=True) # Fill between spin up and down.\n", + " \n", + "for element_selected in list_of_elements:\n", + " pdos_energy_index_df = pdos_df.set_index(['Energy (E-Ef)']) # Set index.\n", + " only_element_df = pdos_energy_index_df[pdos_energy_index_df['Element']==element_selected] # Select only states for a given element.\n", + " sum_element_df = only_element_df.groupby(only_element_df.index).sum() # Sum all the states for a given element.\n", + "\n", + " element_spin_up_df = sum_element_df.filter(regex=\"up\").sum(axis=1) # Filter, get all bands with spin up. Then, sum all orbitals.\n", + "\n", + " if ispin == 2:\n", + " element_spin_down_df = sum_element_df.filter(regex=\"down\").sum(axis=1) # Filter, get all bands with spin down. Then, sum all orbitals.\n", + "\n", + " # Plots:\n", + " plt.plot(element_spin_up_df, label=element_selected) # Atom spin up.\n", + "\n", + " if ispin == 2:\n", + " plt.plot(element_spin_down_df, label=element_selected) # Atom spin down.\n", + "\n", + " plt.axvline(x=[0.0], color='k', linestyle='--',linewidth=1.2) # Plot vertical line in Fermi.\n", + "\n", + "plt.xlabel('E - Ef (eV)') # x axis label.\n", + "plt.ylabel('DOS (states/eV)') # x axis label.\n", + "plt.xlim([-8.0, 4.0]) # Plot limits.\n", + "plt.legend() # Add manually legend to the plot.\n", + "fig.savefig(\"Fig5.pdf\") # Save figure EPS." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/dft_post_analysis/rapiDOS/rapiDOS_original_jose.py b/dft_post_analysis/rapiDOS/rapiDOS_original_jose.py new file mode 100644 index 0000000..3d4b5a6 --- /dev/null +++ b/dft_post_analysis/rapiDOS/rapiDOS_original_jose.py @@ -0,0 +1,333 @@ +import numpy as np +from ase import io +import re +import pandas as pd +import os + + +""" + rapiDOS v.0.5.1 + -- Feb. - 19 - 2018 -- + Jose A. Garrido Torres & Michal Bajdich. + jagt@stanford.edu & bajdich@slac.stanford.edu +""" + +############################################################################## +# Get general information of the system: +############################################################################## + +atoms = io.read('CONTCAR') # Open CONTCAR file +range_of_atoms = range(len(atoms)) # Number of atoms. +atomic_numbers = atoms.get_atomic_numbers() # Atomic number of the atoms. +atomic_symbols = atoms.get_chemical_symbols() # Chemical symbol of the atoms. +outcar_file = io.read('OUTCAR', format='vasp-out') + +############################################################################## + + +############################################################################## +# Check spin: +############################################################################## + +incar_file = open("INCAR", "r") +ispin = 1 # Non spin polarised calculations. +for line in incar_file: + if re.match("(.*)ISPIN(.*)2", line): + ispin = 2 # For spin polarised calculations. + +############################################################################## + + +############################################################################## +# Check scale: +############################################################################## + +# KBLOCK scales DOSCAR (See VASP Manual). +for line in open('OUTCAR'): + if line.find('KBLOCK') != -1: + ckblock = line.split() + for i in range(0, len(ckblock)): + if ckblock[i] == 'KBLOCK': kblock = float(ckblock[i+2]) + +############################################################################## + + +############################################################################## +# Code adapted from split_dos.py which belongs to Jonsson and Henkelman groups. +# URL: http://theory.cm.utexas.edu/vtsttools/scripts.html +############################################################################## + +### READ DOSCAR ### +def read_dosfile(): + f = open("DOSCAR", 'r') + lines = f.readlines() + f.close() + index = 0 + natoms = int(lines[index].strip().split()[0]) + index = 5 + nedos = int(lines[index].strip().split()[2]) + efermi = float(lines[index].strip().split()[3]) + print(natoms, nedos, efermi) + + return lines, index, natoms, nedos, efermi + +### READ POSCAR or CONTCAR and save pos +def read_posfile(): + from ase.io import read + + try: + atoms = read('POSCAR') + except IOError: + print("[__main__]: Couldn't open input file POSCAR, atomic positions will not be written...\n") + atoms = [] + + return atoms + +### WRITE DOS0 CONTAINING TOTAL DOS ### +def write_dos0(lines, index, nedos, efermi): + + fdos = open("DOS0", 'w') + line = lines[index+1].strip().split() + ncols = int(len(line)) + # fdos.write('# %d \n' % (ncols)) #GH not sure why this is here + + for n in range(nedos): + index +=1 + e = float(lines[index].strip().split()[0]) + e_f = e-efermi + fdos.write('%15.8f ' % (e_f)) + + for col in range(1, ncols): + dos = float(lines[index].strip().split()[col]) + fdos.write('%15.8f ' % (dos)) + fdos.write('\n') + return index + +### LOOP OVER SETS OF DOS, NATOMS ### +def write_nospin(lines, index, nedos, natoms, ncols, efermi): + + atoms = read_posfile() + if len(atoms) < natoms: + pos = np.zeros((natoms, 3)) + else: + pos = atoms.get_positions() + + for i in range(1,natoms+1): + si = str(i) + + ## OPEN DOSi FOR WRITING ## + fdos = open("DOS"+si, 'w') + index += 1 + ia = i-1 + # fdos.write('# %d \n' % (ncols)) + fdos.write('# %15.8f %15.8f %15.8f \n' % (pos[ia,0], pos[ia,1], pos[ia,2])) + + ### LOOP OVER NEDOS ### + for n in range(nedos): + index += 1 + e = float(lines[index].strip().split()[0]) + e_f = e-efermi + fdos.write('%15.8f ' % (e_f)) + + for col in range(1, ncols): + dos = float(lines[index].strip().split()[col]) + fdos.write('%15.8f ' % (dos)) + fdos.write('\n') + fdos.close() + +def write_spin(lines, index, nedos, natoms, ncols, efermi): + #pos=[] + atoms = read_posfile() + if len(atoms) < natoms: + pos = np.zeros((natoms, 3)) + else: + pos = atoms.get_positions() + + nsites = (ncols -1)/2 + + for i in range(1,natoms+1): + si = str(i) + ## OPEN DOSi FOR WRITING ## + fdos = open("DOS"+si, 'w') + index += 1 + ia = i-1 + fdos.write('# %d \n' % (ncols)) + fdos.write('# %15.8f %15.8f %15.8f \n' % (pos[ia,0], pos[ia,1], pos[ia,2])) + + ### LOOP OVER NEDOS ### + for n in range(nedos): + index +=1 + e = float(lines[index].strip().split()[0]) + e_f = e-efermi + fdos.write('%15.8f ' % (e_f)) + + for site in range(int(nsites)): + dos_up = float(lines[index].strip().split()[site*2+1]) + dos_down = float(lines[index].strip().split()[site*2+2])*-1 + fdos.write('%15.8f %15.8f ' % (dos_up, dos_down)) + fdos.write('\n') + fdos.close() + +# +if __name__ == '__main__': + import sys + import os + import datetime + import time + import optparse + + lines, index, natoms, nedos, efermi = read_dosfile() + index = write_dos0(lines, index, nedos, efermi) + ## Test if a spin polarized calculation was performed ## + line = lines[index+2].strip().split() + ncols = int(len(line)) + if ncols==7 or ncols==19 or ncols==9 or ncols==33: + write_spin(lines, index, nedos, natoms, ncols, efermi) + is_spin=True + else: + write_nospin(lines, index, nedos, natoms, ncols, efermi) + is_spin=False + print("Spin unrestricted calculation: ", is_spin) + print(ncols) + + +############################################################################## + + +############################################################################## +# Define the columns of the database for the PDOS: +############################################################################## + +if ispin == 2: + if ncols < 19: + pdos_columns = ['Energy (E-Ef)', 's_up','s_down', 'py_up','py_down', + 'pz_up', 'pz_down', 'px_up', 'px_down', 'Element', 'Atom Number', + 'Atom Label'] + if ncols == 19: + pdos_columns = ['Energy (E-Ef)', 's_up', 's_down', 'py_up', + 'py_down', 'pz_up', 'pz_down', 'px_up', 'px_down', 'dxy_up', + 'dxy_down', 'dyz_up', 'dyz_down', 'dz2_up', 'dz2_down', 'dxz_up', + 'dxz_down', 'dx2_up', 'dx2_down', 'Element', 'Atom Number', + 'Atom Label'] + if ncols > 19: + pdos_columns = ['Energy (E-Ef)', 's_up', 's_down', 'py_up', 'py_down', + 'pz_up', 'pz_down', 'px_up', 'px_down', 'dxy_up', 'dxy_down', + 'dyz_up', 'dyz_down', 'dz2_up', 'dz2_down', 'dxz_up', 'dxz_down', + 'dx2_up', 'dx2_down', 'f1_up', 'f1_down', 'f2_up', 'f2_down', 'f3_up', + 'f3_down', 'f4_up', 'f4_down', 'f5_up', 'f5_down', 'f6_up', + 'f6_down', 'Element', 'Atom Number', 'Atom Label'] + +if ispin != 2: + if ncols < 10 : + pdos_columns = ['Energy (E-Ef)', 's_up', 'py_up', 'pz_up', 'px_up', 'Atom Label'] + if ncols == 10: + pdos_columns = ['Energy (E-Ef)', 's_up', 'py_up', 'pz_up', 'px_up', 'dxy_up', 'dyz_up', + 'dz2_up', 'dxz_up', 'dx2_up', 'Element', 'Atom Number', 'Atom Label'] + if ncols > 10: + pdos_columns = ['Energy (E-Ef)', 's_up', 'py_up', 'pz_up', 'px_up', 'dxy_up', 'dyz_up', + 'dz2_up', 'dxz_up', 'dx2_up', 'f1_up', 'f2_up', 'f3_up', 'f4_up', 'f5_up', 'f6_up', 'Element', + 'Atom Number', 'Atom Label'] + +############################################################################## + + +############################################################################## +# Build pandas dataframe for total DOS: +############################################################################## + +total_dos = np.loadtxt('DOS0', skiprows=0) # Load file total DOS from DOS0. +total_dos[:,1:] = total_dos[:,1:]* kblock # Scale (See kblock VASP). + + +if ispin == 2: + total_dos_columns = ['Energy (E-Ef)', 'Total DOS Spin Up', 'Total DOS ' + 'Spin ' + 'Down', 'Integrated DOS Spin Up', 'Integrated DOS Spin Down'] +if ispin != 2: + total_dos_columns = ['Energy (E-Ef)', 'Total DOS Spin Up', 'Integrated DOS'] + +total_dos_df = pd.DataFrame(total_dos, columns=total_dos_columns) + +############################################################################## + + +############################################################################## +# Build pandas dataframe for PDOS: +############################################################################## + +pdos_df = pd.DataFrame([], columns=pdos_columns) + +for i in range_of_atoms: + dos_atom_i = np.loadtxt('DOS'+str(i+1), skiprows=0) # Load the DOSxx files. + dos_atom_i[:,1:] = dos_atom_i[:,1:] # Do NOT scale PDOS (See KBLOCK VASP). + index_i = str(atomic_symbols[i]) # Element + index_i2 = str(i+1) # Atom Number. + index_i3 = str(atomic_symbols[i]+str(i+1)) # Element index. + column_index_i = np.repeat(index_i, len(dos_atom_i)) + column_index_i2 = np.repeat(index_i2, len(dos_atom_i)) + column_index_i3 = np.repeat(index_i3, len(dos_atom_i)) + column_index_i = np.reshape(column_index_i, (len(column_index_i),1)) + column_index_i2 = np.reshape(column_index_i2, (len(column_index_i2),1)) + column_index_i3 = np.reshape(column_index_i3, (len(column_index_i3),1)) + dos_atom_i = np.append(dos_atom_i, column_index_i,axis=1) # Append Element. + dos_atom_i = np.append(dos_atom_i, column_index_i2,axis=1) # Append Atom N. + dos_atom_i = np.append(dos_atom_i, column_index_i3,axis=1) # Append Label. + pdos_df_i = pd.DataFrame(dos_atom_i, columns=pdos_columns) + pdos_df = pd.DataFrame.append(pdos_df_i, pdos_df, ignore_index=True) + +############################################################################## + + +############################################################################## +# Get band gap: +############################################################################## + +def get_bandgap(): + arg_fermi = np.where(total_dos[:, 0] > 0)[0][0] + arg_fermi_upper = arg_fermi + arg_fermi_lower = arg_fermi + band_tolerance = 5e-2 + + converged = False + while not converged: + occup_lower = total_dos[:, 1][arg_fermi_lower] + occup_upper = total_dos[:, 1][arg_fermi_upper] + + if occup_lower > band_tolerance: + arg_fermi_lower = arg_fermi_lower + 1 + if occup_upper > band_tolerance: + arg_fermi_upper = arg_fermi_upper - 1 + + if occup_lower > band_tolerance and occup_upper > band_tolerance: + converged = True + e_lower = total_dos[arg_fermi_lower][0] + e_upper = total_dos[arg_fermi_upper][0] + band_gap = e_lower - e_upper + arg_fermi_lower = arg_fermi_lower - 1 + arg_fermi_upper = arg_fermi_upper + 1 + + print("Approx. band gap: ", np.abs(band_gap), "eVv") + return [e_lower, e_upper, band_gap] + +band_gap = get_bandgap() +band_gap_columns = ['Lower Band Gap', 'Upper Band Gap', 'Band Gap'] +band_gap_df = pd.DataFrame([band_gap], columns=band_gap_columns) + +############################################################################## + + +############################################################################## +# Save files for Jupyter notebook +############################################################################## + +total_dos_df.to_csv('TotalDOS.csv') +pdos_df.to_csv('PDOS.csv') +band_gap_df.to_csv('BandGap.csv') + +############################################################################## + +# Open example file (rapiDOS_analysis.ipynb) using Jupyter Notebook. + +os.system('jupyter notebook rapiDOS_analysis.ipynb') +#use the second to run it without a browser +#os.system('jupyter nbconvert --to notebook --execute rapiDOS_analysis.ipynb') diff --git a/energetics/dft_energy.py b/energetics/dft_energy.py index 3bdceb5..2b01002 100644 --- a/energetics/dft_energy.py +++ b/energetics/dft_energy.py @@ -337,10 +337,21 @@ def __init__(self, }, + # * Water formation energy: + # G_Liq: | -237.14 kJ/mol --> -2.457784 eV (-4.915567) + # G_Gas: | -228.61 kJ/mol --> -2.369376 eV (-4.738753) + # -------------------------------------------------------- + # H_Liq: | −285.8 kJ/mol --> -2.96211 eV (-5.92422) + # H_Gas: | −241.818 kJ/mol --> -2.506268 eV (-5.012535) + # + # H2O Formation Energy from H2 and O2 ********************************* H2O_form_e_dict={ - "gibbs_e": -2.4583, - "enthalpy_e": -2.96211, + # "gibbs_e": -2.4583, + # "enthalpy_e": -2.96211, + + "gibbs_e": -2.4583, # Liquid phase Gibbs + "enthalpy_e": -2.506268, # Gas phase enthalpy }, # H2O_form_gibbs=-2.4583, diff --git a/misc_modules/image_processing.py b/misc_modules/image_processing.py new file mode 100644 index 0000000..42380a9 --- /dev/null +++ b/misc_modules/image_processing.py @@ -0,0 +1,53 @@ +""" + +""" + +#| - IMPORT MODULES +import os +#__| + + +def convert_pdf_to_svg(figure_path, out_dir, converter="inkscape"): + """ + + Args: + converter: 'inkscape' or 'cairo' + """ + #| - convert_pdf_to_svg + extension = figure_path[-3:] + + # assert extension == "pdf", "Must give a pdf" + if extension == "svg": + output_path = figure_path + + if extension == "pdf": + output_name = figure_path.split("/")[-1][:-3] + "svg" + output_path = os.path.join(out_dir, output_name) + + bash_comm__cairo = \ + "pdftocairo -svg " + \ + figure_path + \ + " " + \ + output_path + + bash_comm__inkscape = \ + "inkscape --without-gui --file " + \ + figure_path + \ + " --export-text-to-path --export-plain-svg=" + \ + output_path + + if converter == "inkscape": + print("Using inkscape converter") + bash_comm = bash_comm__inkscape + elif converter == "cairo": + print("Using cairo converter") + bash_comm = bash_comm__cairo + + print("bash command: ", bash_comm) + os.system(bash_comm) + + else: + print("Can only handle svg or pdfs now") + + return(output_path) + #__| diff --git a/misc_modules/misc_methods.py b/misc_modules/misc_methods.py index 400163a..493b8fb 100644 --- a/misc_modules/misc_methods.py +++ b/misc_modules/misc_methods.py @@ -36,7 +36,6 @@ def even_spaced_range(start_finish, spacing): return(out_list) #__| - def merge_two_dicts(x, y): """ """ @@ -72,6 +71,7 @@ def dict_merge(dct, merge_dct): dct[k] = merge_dct[k] #__| + #| - File and Directory Management def remove_file_from_all_folders( @@ -103,10 +103,13 @@ def remove_file_from_all_folders( ) if show_file_size: - file_size_i = os.stat(file_path_i).st_size * 1E-6 - print("File size: ", str(file_size_i), " MB") + try: + file_size_i = os.stat(file_path_i).st_size * 1E-6 + print("File size: ", str(file_size_i), " MB") - total_disk_usage += file_size_i + total_disk_usage += file_size_i + except: + pass print("_________") @@ -131,3 +134,51 @@ def remove_file_from_all_folders( #__| + + +#| - Generating unique IDs +import random +from random import choice + +def GetFriendlyID(append_random_num=False): + """ + Create an ID string we can recognise. + (Think Italian or Japanese or Native American.) + """ + #| - GetFriendlyID + v = 'aeiou' + c = 'bdfghklmnprstvw' + + id_i = ''.join([choice(v if i % 2 else c) for i in range(8)]) + + if append_random_num: + id_i += "_" + \ + str(random.randint(0, 9)) + \ + str(random.randint(0, 9)) + + return(id_i) + #__| + +def GetUniqueFriendlyID(used_ids): + """Return an ID that is not in our list of already used IDs. + + used_ids = set() + for i in range(50): + id = GetUniqueFriendlyID(used_ids) + used_ids.add(id) + """ + #| - GetUniqueFriendlyID + # trying infinitely is a bad idea + LIMIT = 1000 + + count = 0 + while count < LIMIT: + id = GetFriendlyID(append_random_num=True) + if id not in used_ids: + break + count += 1 + id = '' + return id + #__| + +#__| diff --git a/oxr_reaction/oxr_plotting_classes/oxr_plot_2d_volcano.py b/oxr_reaction/oxr_plotting_classes/oxr_plot_2d_volcano.py index 9fbcf96..f44e96e 100644 --- a/oxr_reaction/oxr_plotting_classes/oxr_plot_2d_volcano.py +++ b/oxr_reaction/oxr_plotting_classes/oxr_plot_2d_volcano.py @@ -73,17 +73,26 @@ def __create_contour_trace__(self): x_range_bounds = self.plot_range["x"] y_range_bounds = self.plot_range["y"] - x_range = np.arange( - x_range_bounds[0] - 1., - x_range_bounds[1] + 1., + x_range_bounds[0], + x_range_bounds[1], 0.01) y_range = np.arange( - y_range_bounds[0] - 1., - y_range_bounds[1] + 1., + y_range_bounds[0], + y_range_bounds[1], 0.01) + # x_range = np.arange( + # x_range_bounds[0] - 1., + # x_range_bounds[1] + 1., + # 0.01) + # + # y_range = np.arange( + # y_range_bounds[0] - 1., + # y_range_bounds[1] + 1., + # 0.01) + # x_range = np.arange(0.9, 2, 0.01) # y_range = np.arange(-0.5, 2., 0.01) @@ -115,11 +124,26 @@ def __create_contour_trace__(self): #| - Colorbar colorbar=go.contour.ColorBar( - x=None, - xanchor=None, - xpad=None, - y=None, - yanchor=None, + # x=None, + # xanchor=None, + # xpad=None, + # y=None, + # yanchor=None, + + title=go.contour.colorbar.Title( + # font=None, + side="top", # ['right', 'top', 'bottom'] + text="η (V)", + ), + + + dtick=0.2, + lenmode="fraction", + len=1., + xpad=0., + ypad=0., + outlinecolor="black", + outlinewidth=1., ), #__| @@ -128,7 +152,8 @@ def __create_contour_trace__(self): color="white", # dash="dot", smoothing=1., - width=0.5, + # width=0.5, + width=0., ) ) #__| @@ -166,6 +191,7 @@ def __create_scatter_trace_i__(self, name=sys_i.series_name, #
+ hoverinfo="name", marker=dict( size=20, diff --git a/plotting/my_plotly.py b/plotting/my_plotly.py index 5593c78..c795b0a 100644 --- a/plotting/my_plotly.py +++ b/plotting/my_plotly.py @@ -151,12 +151,19 @@ def plot_layout( def my_plotly_plot( figure=None, - layout=None, - layout_override=None, - plot_name=None, - save_dir=None, - data=None, - upload_plot=True, + plot_name="TEMP_PLOT_NAME", + online_save_dir=None, + write_html=False, + write_png=False, + png_scale=6., + write_pdf=False, + write_svg=False, + upload_plot=False, + + # layout=None, + # layout_override=None, + # data=None, + # write_pdf_svg=True, ): """ TODO: @@ -173,7 +180,7 @@ def my_plotly_plot( Dictionary to override layout plot_name: Plot name (used both for plot upload and local save) - save_dir: + online_save_dir: Plot.ly folder to save figure into (Not used for local save) data: plotly data object @@ -181,24 +188,25 @@ def my_plotly_plot( Upload plot to plotly servers """ - #| - plot_proto - if layout is None: - layout = go.Layout() + #| - my_plotly_plot + # if layout is None: + # layout = go.Layout() if figure is not None: fig = figure else: - fig = go.Figure(data=data, layout=layout) + print("NOOOOOOOOOOOOOOOOOOO!!!") + # fig = go.Figure(data=data, layout=layout) - fig.layout.update(layout_override) + # fig.layout.update(layout_override) #| - Upload to plot.ly website # ######################################################################### if upload_plot: plotly_filename = os.path.join( - save_dir, + online_save_dir, # "02_oer_analysis", # "oer_2d_volcano_plot", plot_name) @@ -214,21 +222,22 @@ def my_plotly_plot( #| - Local write to HTML - pyio.write_html( - fig, - os.path.join(plot_dir, plot_name + ".html"), - # config=None, - # auto_play=True, - # include_plotlyjs=True, - # include_mathjax=False, - # post_script=None, - # full_html=True, - # animation_opts=None, - # validate=True, - # default_width='100%', - # default_height='100%', - # auto_open=False, - ) + if write_html: + pyio.write_html( + fig, + os.path.join(plot_dir, plot_name + ".html"), + # config=None, + # auto_play=True, + # include_plotlyjs=True, + # include_mathjax=False, + # post_script=None, + # full_html=True, + # animation_opts=None, + # validate=True, + # default_width='100%', + # default_height='100%', + # auto_open=False, + ) #__| @@ -237,20 +246,27 @@ def my_plotly_plot( hostname = socket.gethostbyaddr(socket.gethostname())[0] # Requires ORCA installation - if os.environ["USER"] == "raul-ubuntu-desktop" or hostname == "raul-ubuntu-vb": + if ( + os.environ["USER"] == "raul-ubuntu-desktop" or + hostname == "raul-ubuntu-vb" or + hostname == "DESKTOP-37GUFJ5" or + hostname == "raul-dell-latitude" + # write_pdf_svg is True + ): print("Writing pdf with ORCA") - # This seems to be the preferred syntax now - fig.write_image( - os.path.join(plot_dir, plot_name + ".pdf") - # "out_plot/test_fig.pdf" - ) + if write_pdf: + fig.write_image( + os.path.join(plot_dir, plot_name + ".pdf")) + if write_svg: + fig.write_image( + os.path.join(plot_dir, plot_name + ".svg")) + if write_png: + fig.write_image( + os.path.join(plot_dir, plot_name + ".png"), + scale=png_scale, + ) - # This seems to be the preferred syntax now - fig.write_image( - os.path.join(plot_dir, plot_name + ".svg") - # "out_plot/test_fig.pdf" - ) #__| diff --git a/plotting/plotly_layout_template.py b/plotting/plotly_layout_template.py index cc560d6..1c5bfe4 100644 --- a/plotting/plotly_layout_template.py +++ b/plotting/plotly_layout_template.py @@ -33,7 +33,11 @@ extendfunnelareacolors=None, extendpiecolors=None, extendsunburstcolors=None, - font=None, + font=go.layout.Font( + color=None, + family=None, + size=None, + ), funnelareacolorway=None, funnelgap=None, funnelgroupgap=None, @@ -51,7 +55,14 @@ imagedefaults=None, legend=None, mapbox=None, - margin=None, + margin=go.layout.Margin( + autoexpand=None, + b=None, + l=None, + pad=None, + r=None, + t=None, + ), meta=None, metasrc=None, modebar=None, @@ -146,7 +157,11 @@ tick0=None, tickangle=None, tickcolor=None, - tickfont=None, + tickfont=dict( + color=None, + family=None, + size=None, + ), tickformat=None, tickformatstops=None, tickformatstopdefaults=None, @@ -183,8 +198,47 @@ yaxis_layout.update(go.layout.YAxis( title="ISJFIDJSF", )) -#__| - layout.xaxis = xaxis_layout layout.yaxis = yaxis_layout +#__| + + +#| - Plot Annotations +annotations = [ + + #| - Axis Titles + { + # 'font': {'size': axis_label_font_size}, + 'font': {'size': 12}, + 'showarrow': False, + 'text': 'Voltage (V vs RHE)', + 'x': 0.5, + 'xanchor': 'center', + 'xref': 'paper', + 'y': 0, + 'yanchor': 'top', + 'yref': 'paper', + 'yshift': -30, + }, + + { + # 'font': {'size': axis_label_font_size}, + 'font': {'size': 12}, + 'showarrow': False, + 'text': 'Surface Free Energy (eV / A2)', + 'textangle': -90, + 'x': 0, + 'xanchor': 'right', + 'xref': 'paper', + 'xshift': -40, + 'y': 0.5, + 'yanchor': 'middle', + 'yref': 'paper' + }, + #__| + + ] + +layout.annotations = annotations +#__| diff --git a/quantum_espresso/qe_methods.py b/quantum_espresso/qe_methods.py index b09bfcf..199d547 100644 --- a/quantum_espresso/qe_methods.py +++ b/quantum_espresso/qe_methods.py @@ -48,7 +48,7 @@ def number_of_atoms(path_i=".", log="log"): num_atoms = len(atom_list) return(num_atoms) - #__| + # __| def tot_abs_magnetization(path_i=".", log="log"): """Return total and absolute magnetization vs SCF iteration. diff --git a/surface_energy/surface_energy.py b/surface_energy/surface_energy.py index 39c80a7..e0f67bc 100644 --- a/surface_energy/surface_energy.py +++ b/surface_energy/surface_energy.py @@ -39,6 +39,8 @@ def __init__(self, H_ref_electronic_energy=None, O_ref_electronic_energy=None, + special_surface_species_corrections=None, + apply_special_species_corrections=False, num_surface_atoms=None, bias=0., @@ -60,6 +62,10 @@ def __init__(self, self.H_ref_electronic_energy = H_ref_electronic_energy self.O_ref_electronic_energy = O_ref_electronic_energy + self.special_surface_species_corrections = \ + special_surface_species_corrections + self.apply_special_species_corrections = \ + apply_special_species_corrections self.num_surface_atoms = num_surface_atoms @@ -77,8 +83,9 @@ def __init__(self, self.slab_thickness = None self.__bulk_energy_per_atom__ = None - #__| + self.non_stoich_comp_new = dict() + #__| self.surface_area = self.__calc_surface_area__() @@ -98,9 +105,15 @@ def __init__(self, self.__bulk_energy_per_formula_unit__ = \ self.__calc_bulk_energy_per_formula_unit__() - self.surface_e_per_side = self.calc_std_surface_energy() + self.special_surface_species = \ + self.__count_special_surface_species__() + + self.std_surface_e_per_side = self.calc_std_surface_energy() + + self.std_surface_e_per_area = \ + self.__calc_surface_energy_per_area__( + unnorm_surface_e=self.std_surface_e_per_side) - self.surface_e_per_area = self.__calc_std_surface_energy_per_area__() if self.num_surface_atoms is not None: self.surface_e_per_surface_atom = \ @@ -109,17 +122,80 @@ def __init__(self, self.slab_thickness = self.__calc_slab_thickness__() #__| + def calc_surface_energy(self, bias, pH, norm_type="area"): + """ + + Args: + norm_type: 'area', 'surface_atom', None + """ + #| - calc_surface_energy + surface_e_per_side = self.std_surface_e_per_side + non_stoich_comp = self.non_stoich_comp + + # print(surface_e_per_side) + + nonstoich_O = non_stoich_comp.get("O", 0) + nonstoich_H = non_stoich_comp.get("H", 0) + + slope = 2 * nonstoich_O - nonstoich_H + + surf_e_V_ph = 0. + \ + +surface_e_per_side + \ + +(slope * 0.0591 * pH) + \ + -(slope * bias) + \ + +0. + + # print(surf_e_V_ph) + + + if norm_type == "area": + surf_e_V_ph__norm = self.__calc_surface_energy_per_area__( + unnorm_surface_e=surf_e_V_ph) + elif norm_type == "surface_atom": + print("NOT SUPPORTEE") + assert False + surf_e_V_ph__norm = "TEMP" + elif norm_type is None: + surf_e_V_ph__norm = surf_e_V_ph + else: + assert False + surf_e_V_ph__norm = "TEMP" + + + return(surf_e_V_ph__norm) + #__| + def calc_std_surface_energy(self): """ """ #| - calc_std_surface_energy + electronic_energy = self.electronic_energy bulk_formula_units_in_slab = self.__bulk_formula_units_in_slab__ bulk_energy_per_formula_unit = self.__bulk_energy_per_formula_unit__ H_ref_electronic_energy = self.H_ref_electronic_energy O_ref_electronic_energy = self.O_ref_electronic_energy + non_stoich_comp = self.non_stoich_comp + # non_stoich_comp_new = self.non_stoich_comp_new + special_surface_species = self.special_surface_species + + + # TODO add this as class input + apply_special_species_corrections = \ + self.apply_special_species_corrections + + special_surface_species_corrections = \ + self.special_surface_species_corrections + # special_surface_species_corrections = { + # "*OH": 0.2945, "*O": 0.044, "*OOH": 0.3765} + sssc = special_surface_species_corrections + + + # TEMP + print(non_stoich_comp) + print(H_ref_electronic_energy) # TODO Make the referencing more robust, take arbitary dict of # referencec atoms @@ -130,24 +206,99 @@ def calc_std_surface_energy(self): -non_stoich_comp.get("H", 0.) * (H_ref_electronic_energy) + \ +0. + if apply_special_species_corrections: + special_surface_species + for spec_i, num_spec_i in special_surface_species.items(): + corr_i = num_spec_i * sssc[spec_i] + print(corr_i) + surf_e_0 += corr_i + + print(surf_e_0) + # Divide surface energy across two sides of slab surf_e_0 /= 2 return(surf_e_0) + #__| + + + def __count_special_surface_species__(self): + """Count the number of *OH and *O surface species. + + Taks the non-stoich dict and pairs the max number of O and H pairs into + *OH and the remaining O's into *O + """ + #| - __count_special_surface_species__ + import copy - # if norm_mode == "area": - # surf_e_0 = surf_e_0 / (2 * row_i["slab_area"]) - # elif norm_mode == "atoms": - # if num_atoms is not None: - # surf_e_0 = surf_e_0 / (2 * num_atoms) + non_stoich_comp = self.non_stoich_comp + + non_stoich_comp_new = copy.copy(non_stoich_comp) + + print(non_stoich_comp) + + special_species_dict = dict() + if "O" in non_stoich_comp.keys(): + + num_Os = non_stoich_comp.get("O") + + if "H" in non_stoich_comp.keys(): + num_Hs = non_stoich_comp.get("H") + + min_num = min([num_Os, num_Hs]) + + num_OHs = min_num + + left_over_Hs = num_Hs - min_num + left_over_Os = num_Os - min_num + + special_species_dict["*OH"] = num_OHs + special_species_dict["*O"] = left_over_Os + + # All nonstoich Os will be *O species + non_stoich_comp_new["O"] = 0 + non_stoich_comp_new["H"] = left_over_Hs + else: + num_OHs = 0 + special_species_dict["*OH"] = num_OHs + + left_over_Hs = 0 + left_over_Os = num_Os + + special_species_dict["*O"] = left_over_Os + special_species_dict["*OH"] = 0 + + # All nonstoich Os will be *O species + non_stoich_comp_new["O"] = 0 + non_stoich_comp_new["H"] = left_over_Hs + + else: + num_OHs = 0 + left_over_Os = num_Os + left_over_Hs = 0 + + if "H" in non_stoich_comp.keys(): + if non_stoich_comp.get("H") > 0: + raise ValueError( + "NOT GOOD HERE, THERE IS AN *H WITHOUT and *OH") + + + # print("----") + # print(non_stoich_comp_new) + # print(special_species_dict) + + + self.non_stoich_comp_new = non_stoich_comp_new + + return(special_species_dict) #__| - def __calc_std_surface_energy_per_area__(self): + def __calc_surface_energy_per_area__(self, unnorm_surface_e=None): """Normalize the surface energy to surface area (A^2).""" - #| - calc_std_surface_energy_per_area + #| - __calc_surface_energy_per_area__ surface_area = self.surface_area - surface_e_per_side = self.surface_e_per_side - + # surface_e_per_side = self.std_surface_e_per_side + surface_e_per_side = unnorm_surface_e surface_e_per_area = surface_e_per_side / surface_area @@ -159,7 +310,7 @@ def __calc_std_surface_energy_per_surface_atom__(self): """Normalize the surface area to a per surface atom basis.""" #| - calc_std_surface_energy_per_area num_surface_atoms = self.num_surface_atoms - surface_e_per_side = self.surface_e_per_side + surface_e_per_side = self.std_surface_e_per_side surface_e_per_surface_atoms = surface_e_per_side / num_surface_atoms @@ -216,6 +367,12 @@ def __calc_units_of_bulk_in_slab__(self): """ """ #| - __calc_units_of_bulk_in_slab__ + # TODO + main_atom = "Ir" # Make this a class attribute + + # 'main_atom' or 'gcm' (greatest common multiple) + find_bulk_form_units_method = "main_atom" + bulk_atoms = self.bulk_atoms atoms = self.atoms @@ -234,12 +391,21 @@ def __calc_units_of_bulk_in_slab__(self): # Removingg columns with 0 df = df.loc[:, (df != 0).any(axis=0)] - slab_comp_array = np.array(list(df.loc["slab"])) - bulk_comp_array = np.array(list(df.loc["bulk"])) + # slab_comp_array = np.array(list(df.loc["slab"])) + # bulk_comp_array = np.array(list(df.loc["bulk"])) + # df.loc["slab"].to_numpy() + # df.loc["bulk"].to_numpy() # Number of unit of the bulk's reduced formula that fit into the slab - bulk_formula_units_in_slab = min(slab_comp_array / bulk_comp_array) - bulk_formula_units_in_slab = int(bulk_formula_units_in_slab) + if find_bulk_form_units_method == "main_atom": + bulk_formula_units_in_slab = int( + df.loc["slab"][main_atom] / df.loc["bulk"][main_atom] + ) + + elif find_bulk_form_units_method == "gcm": + bulk_formula_units_in_slab = int(min( + df.loc["slab"].to_numpy() / df.loc["bulk"].to_numpy() + )) bfuis = bulk_formula_units_in_slab # ##################################################################### @@ -248,7 +414,8 @@ def __calc_units_of_bulk_in_slab__(self): non_stoich_comp = df.loc["nonstoich"].to_dict() self.non_stoich_comp = non_stoich_comp - + # print(bulk_formula_units_in_slab) + # print(non_stoich_comp) return(bulk_formula_units_in_slab) #__| @@ -558,7 +725,7 @@ def __calc_ave_surface_energy__(self, SurfaceEnergy_instances): y_surface_e = [] x_slab_thickness = [] for SE_inst_i in SurfaceEnergy_instances: - y_surface_e.append(SE_inst_i.surface_e_per_area) + y_surface_e.append(SE_inst_i.std_surface_e_per_area) x_slab_thickness.append(SE_inst_i.slab_thickness) df = pd.DataFrame() @@ -623,7 +790,7 @@ def plot_surface_energy(self, #| - Surface Energy (DFT Bulk) ######################################## y_surface_e = []; x_slab_thickness = [] for SE_inst_i in self.SurfaceEnergy_instances: - y_surface_e.append(SE_inst_i.surface_e_per_area) + y_surface_e.append(SE_inst_i.std_surface_e_per_area) x_slab_thickness.append(SE_inst_i.slab_thickness) trace_i = go.Scatter( @@ -655,7 +822,7 @@ def plot_surface_energy(self, #| - Surface Energy (Fitted Bulk) ##################################### y_surface_e = []; x_slab_thickness = [] for SE_inst_i in self.new_SurfaceEnergy_instances: - y_surface_e.append(SE_inst_i.surface_e_per_area) + y_surface_e.append(SE_inst_i.std_surface_e_per_area) x_slab_thickness.append(SE_inst_i.slab_thickness) trace_i = go.Scatter( @@ -802,8 +969,11 @@ def surf_e_4( get_e0_from_row=False, norm_mode="area", # 'area' or 'atoms' num_atoms=None, + units="eV/A^2", # 'eV/A^2' or 'J/m^2' ): """ + DEPRECATED SWITCH TO USING CLASS + Calculate surface energy assuming a water reference state and using the computational hydrogen electrode. """ @@ -841,11 +1011,13 @@ def surf_e_4( +0. # -nonstoich_Hs * (G_H2) + \ + if norm_mode == "area": - surf_e_0 = surf_e_0 / (2 * row_i["slab_area"]) - elif norm_mode == "atoms": - if num_atoms is not None: - surf_e_0 = surf_e_0 / (2 * num_atoms) + norm_term = 2 * row_i["slab_area"] + surf_e_0 = surf_e_0 / norm_term + elif norm_mode == "atoms" and num_atoms is not None: + norm_term = 2 * num_atoms + surf_e_0 = surf_e_0 / norm_term #__| #| - Calculate V, pH Dependant Surface Energy @@ -853,13 +1025,30 @@ def surf_e_4( surf_e = 0. + \ +surf_e_0 + \ - +(slope * 0.0591 * pH) / (2 * row_i["slab_area"]) + \ - -(slope * bias) / (2 * row_i["slab_area"]) + \ + +(slope * 0.0591 * pH) / norm_term + \ + -(slope * bias) / norm_term + \ +0. + # +(slope * 0.0591 * pH) / (2 * row_i["slab_area"]) + \ + # -(slope * bias) / (2 * row_i["slab_area"]) + \ + # surf_e = surf_e / (2 * row_i["slab_area"]) #__| + + #| - Unit conversion + units="eV/A^2", # 'eV/A^2' or 'J/m^2' + + if norm_mode == "area": + if units == "eV/A^2": + pass + elif units == "J/m^2": + # Convert eV/A^2 to J/m^2 + # (1E10 A/m) ^ 2 * (1.6022E-19 J/eV) = 16.022 + ev_A2__to__J_m2 = 16.022 + surf_e = surf_e * ev_A2__to__J_m2 + # __| + return(surf_e) #__| diff --git a/surface_energy/surface_energy_pourbaix_plot.py b/surface_energy/surface_energy_pourbaix_plot.py new file mode 100644 index 0000000..15953c8 --- /dev/null +++ b/surface_energy/surface_energy_pourbaix_plot.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +""" +""" + +#| - IMPORT MODULES +#__| + + +class SurfaceEnergyPourbaixPlot: + """ + """ + + #| - TEMP ******************************************************** + _TEMP = "TEMP" + + def __init__(self, + ): + """ + """ + #| - __init__ + + #| - Setting Argument Instance Attributes + #__| + + #| - Initializing Internal Instance Attributes + #__| + + #__| + + def method_0(): + """ + """ + #| - TEMP + + #__| + + + #__| **********************************************************************