# -*- coding: utf-8 -*-
"""The graphical part of a Energy step"""
import json
from pathlib import Path
import pprint # noqa: F401
import tkinter as tk
import tkinter.ttk as ttk
import vasp_step # noqa: F401, E999
import seamm
from seamm_util import ureg, Q_, units_class, CompactJSONEncoder # noqa: F401, E999
import seamm_widgets as sw
default_potentials = {
"potpaw_PBE.64": {
"H": "H",
"He": "He",
"Li": "Li_sv",
"Be": "Be",
"B": "B",
"C": "C",
"N": "N",
"O": "O",
"F": "F",
"Ne": "Ne",
"Na": "Na_pv",
"Mg": "Mg",
"Al": "Al",
"Si": "Si",
"P": "P",
"S": "S",
"Cl": "Cl",
"Ar": "Ar",
"K": "K_sv",
"Ca": "Ca_sv",
"Sc": "Sc_sv",
"Ti": "Ti_sv",
"V": "V_sv",
"Cr": "Cr_pv",
"Mn": "Mn_pv",
"Fe": "Fe",
"Co": "Co",
"Ni": "Ni",
"Cu": "Cu",
"Zn": "Zn",
"Ga": "Ga_d",
"Ge": "Ge_d",
"As": "As",
"Se": "Se",
"Br": "Br",
"Kr": "Kr",
"Rb": "Rb_sv",
"Sr": "Sr_sv",
"Y": "Y_sv",
"Zr": "Zr_sv",
"Nb": "Nb_sv",
"Mo": "Mo_sv",
"Tc": "Tc_pv",
"Ru": "Ru_pv",
"Rh": "Rh_pv",
"Pd": "Pd",
"Ag": "Ag",
"Cd": "Cd",
"In": "In_d",
"Sn": "Sn_d",
"Sb": "Sb",
"Te": "Te",
"I": "I",
"Xe": "Xe",
"Cs": "Cs_sv",
"Ba": "Ba_sv",
"La": "La",
"Ce": "Ce",
"Pr": "Pr_3",
"Nd": "Nd_3",
"Pm": "Pm_3",
"Sm": "Sm_3",
"Eu": "Eu_2",
"Gd": "Gd_3",
"Tb": "Tb_3",
"Dy": "Dy_3",
"Ho": "Ho_3",
"Er": "Er_3",
"Tm": "Tm_3",
"Yb": "Yb_2",
"Lu": "Lu_3",
"Hf": "Hf_pv",
"Ta": "Ta_pv",
"W": "W_sv",
"Re": "Re",
"Os": "Os",
"Ir": "Ir",
"Pt": "Pt",
"Au": "Au",
"Hg": "Hg",
"Tl": "Tl_d",
"Pb": "Pb_d",
"Bi": "Bi_d",
"Po": "Po_d",
"At": "At",
"Rn": "Rn",
"Fr": "Fr_sv",
"Ra": "Ra_sv",
"Ac": "Ac",
"Th": "Th",
"Pa": "Pa",
"U": "U",
"Np": "Np",
"Pu": "Pu",
"Am": "Am",
"Cm": "Cm",
"Cf": "Cf",
},
"potpaw_LDA.64": {
"H": "H",
"He": "He",
"Li": "Li_sv",
"Be": "Be",
"B": "B",
"C": "C",
"N": "N",
"O": "O",
"F": "F",
"Ne": "Ne",
"Na": "Na_pv",
"Mg": "Mg",
"Al": "Al",
"Si": "Si",
"P": "P",
"S": "S",
"Cl": "Cl",
"Ar": "Ar",
"K": "K_sv",
"Ca": "Ca_sv",
"Sc": "Sc_sv",
"Ti": "Ti_sv",
"V": "V_sv",
"Cr": "Cr_pv",
"Mn": "Mn_pv",
"Fe": "Fe",
"Co": "Co",
"Ni": "Ni",
"Cu": "Cu",
"Zn": "Zn",
"Ga": "Ga_d",
"Ge": "Ge_d",
"As": "As",
"Se": "Se",
"Br": "Br",
"Kr": "Kr",
"Rb": "Rb_sv",
"Sr": "Sr_sv",
"Y": "Y_sv",
"Zr": "Zr_sv",
"Nb": "Nb_sv",
"Mo": "Mo_sv",
"Tc": "Tc_pv",
"Ru": "Ru_pv",
"Rh": "Rh_pv",
"Pd": "Pd",
"Ag": "Ag",
"Cd": "Cd",
"In": "In_d",
"Sn": "Sn_d",
"Sb": "Sb",
"Te": "Te",
"I": "I",
"Xe": "Xe",
"Cs": "Cs_sv",
"Ba": "Ba_sv",
"La": "La",
"Ce": "Ce",
"Pr": "Pr_3",
"Nd": "Nd_3",
"Pm": "Pm_3",
"Sm": "Sm_3",
"Eu": "Eu_2",
"Gd": "Gd_3",
"Tb": "Tb_3",
"Dy": "Dy_3",
"Ho": "Ho_3",
"Er": "Er_3",
"Tm": "Tm_3",
"Yb": "Yb_2",
"Lu": "Lu_3",
"Hf": "Hf_pv",
"Ta": "Ta_pv",
"W": "W_sv",
"Re": "Re",
"Os": "Os",
"Ir": "Ir",
"Pt": "Pt",
"Au": "Au",
"Hg": "Hg",
"Tl": "Tl_d",
"Pb": "Pb_d",
"Bi": "Bi_d",
"Po": "Po_d",
"At": "At",
"Rn": "Rn",
"Fr": "Fr_sv",
"Ra": "Ra_sv",
"Ac": "Ac",
"Th": "Th",
"Pa": "Pa",
"U": "U",
"Np": "Np",
"Pu": "Pu",
"Am": "Am",
"Cm": "Cm",
"Cf": "Cf",
},
"potpaw_PBE.64_GW": {
"H": "H_GW",
"He": "He_GW",
"Li": "Li_sv_GW",
"Be": "Be_sv_GW",
"B": "B_GW",
"C": "C_GW",
"N": "N_GW",
"O": "O_GW",
"F": "F_GW",
"Ne": "Ne_GW",
"Na": "Na_sv_GW",
"Mg": "Mg_sv_GW",
"Al": "Al_GW",
"Si": "Si_GW",
"P": "P_GW",
"S": "S_GW",
"Cl": "Cl_GW",
"Ar": "Ar_GW",
"K": "K_sv_GW",
"Ca": "Ca_sv_GW",
"Sc": "Sc_sv_GW",
"Ti": "Ti_sv_GW",
"V": "V_sv_GW",
"Cr": "Cr_sv_GW",
"Mn": "Mn_sv_GW",
"Fe": "Fe_sv_GW",
"Co": "Co_sv_GW",
"Ni": "Ni_sv_GW",
"Cu": "Cu_sv_GW",
"Zn": "Zn_sv_GW",
"Ga": "Ga_d_GW",
"Ge": "Ge_d_GW",
"As": "As_GW",
"Se": "Se_GW",
"Br": "Br_GW",
"Kr": "Kr_GW",
"Rb": "Rb_sv_GW",
"Sr": "Sr_sv_GW",
"Y": "Y_sv_GW",
"Zr": "Zr_sv_GW",
"Nb": "Nb_sv_GW",
"Mo": "Mo_sv_GW",
"Tc": "Tc_sv_GW",
"Ru": "Ru_sv_GW",
"Rh": "Rh_sv_GW",
"Pd": "Pd_sv_GW",
"Ag": "Ag_sv_GW",
"Cd": "Cd_sv_GW",
"In": "In_d_GW",
"Sn": "Sn_d_GW",
"Sb": "Sb_d_GW",
"Te": "Te_GW",
"I": "I_GW",
"Xe": "Xe_GW",
"Cs": "Cs_sv_GW",
"Ba": "Ba_sv_GW",
"La": "La_GW",
"Ce": "Ce_GW",
"Hf": "Hf_sv_GW",
"Ta": "Ta_sv_GW",
"W": "W_sv_GW",
"Re": "Re_sv_GW",
"Os": "Os_sv_GW",
"Ir": "Ir_sv_GW",
"Pt": "Pt_sv_GW",
"Au": "Au_sv_GW",
"Hg": "Hg_sv_GW",
"Tl": "Tl_d_GW",
"Pb": "Pb_d_GW",
"Bi": "Bi_d_GW",
"Po": "Po_d_GW",
"At": "At_d_GW",
"Rn": "Rn_d_GW",
},
"potpaw_LDA.64_GW": {
"H": "H_GW",
"He": "He_GW",
"Li": "Li_sv_GW",
"Be": "Be_sv_GW",
"B": "B_GW",
"C": "C_GW",
"N": "N_GW",
"O": "O_GW",
"F": "F_GW",
"Ne": "Ne_GW",
"Na": "Na_sv_GW",
"Mg": "Mg_sv_GW",
"Al": "Al_GW",
"Si": "Si_GW",
"P": "P_GW",
"S": "S_GW",
"Cl": "Cl_GW",
"Ar": "Ar_GW",
"K": "K_sv_GW",
"Ca": "Ca_sv_GW",
"Sc": "Sc_sv_GW",
"Ti": "Ti_sv_GW",
"V": "V_sv_GW",
"Cr": "Cr_sv_GW",
"Mn": "Mn_sv_GW",
"Fe": "Fe_sv_GW",
"Co": "Co_sv_GW",
"Ni": "Ni_sv_GW",
"Cu": "Cu_sv_GW",
"Zn": "Zn_sv_GW",
"Ga": "Ga_d_GW",
"Ge": "Ge_d_GW",
"As": "As_GW",
"Se": "Se_GW",
"Br": "Br_GW",
"Kr": "Kr_GW",
"Rb": "Rb_sv_GW",
"Sr": "Sr_sv_GW",
"Y": "Y_sv_GW",
"Zr": "Zr_sv_GW",
"Nb": "Nb_sv_GW",
"Mo": "Mo_sv_GW",
"Tc": "Tc_sv_GW",
"Ru": "Ru_sv_GW",
"Rh": "Rh_sv_GW",
"Pd": "Pd_sv_GW",
"Ag": "Ag_sv_GW",
"Cd": "Cd_sv_GW",
"In": "In_d_GW",
"Sn": "Sn_d_GW",
"Sb": "Sb_d_GW",
"Te": "Te_GW",
"I": "I_GW",
"Xe": "Xe_GW",
"Cs": "Cs_sv_GW",
"Ba": "Ba_sv_GW",
"La": "La_GW",
"Ce": "Ce_GW",
"Hf": "Hf_sv_GW",
"Ta": "Ta_sv_GW",
"W": "W_sv_GW",
"Re": "Re_sv_GW",
"Os": "Os_sv_GW",
"Ir": "Ir_sv_GW",
"Pt": "Pt_sv_GW",
"Au": "Au_sv_GW",
"Hg": "Hg_sv_GW",
"Tl": "Tl_d_GW",
"Pb": "Pb_d_GW",
"Bi": "Bi_d_GW",
"Po": "Po_d_GW",
"At": "At_d_GW",
"Rn": "Rn_d_GW",
},
"potpaw_PBE.54": {
"H": "H",
"He": "He",
"Li": "Li_sv",
"Be": "Be",
"B": "B",
"C": "C",
"N": "N",
"O": "O",
"F": "F",
"Ne": "Ne",
"Na": "Na_pv",
"Mg": "Mg",
"Al": "Al",
"Si": "Si",
"P": "P",
"S": "S",
"Cl": "Cl",
"Ar": "Ar",
"K": "K_sv",
"Ca": "Ca_sv",
"Sc": "Sc_sv",
"Ti": "Ti_sv",
"V": "V_sv",
"Cr": "Cr_pv",
"Mn": "Mn_pv",
"Fe": "Fe",
"Co": "Co",
"Ni": "Ni",
"Cu": "Cu",
"Zn": "Zn",
"Ga": "Ga_d",
"Ge": "Ge_d",
"As": "As",
"Se": "Se",
"Br": "Br",
"Kr": "Kr",
"Rb": "Rb_sv",
"Sr": "Sr_sv",
"Y": "Y_sv",
"Zr": "Zr_sv",
"Nb": "Nb_sv",
"Mo": "Mo_sv",
"Tc": "Tc_pv",
"Ru": "Ru_pv",
"Rh": "Rh_pv",
"Pd": "Pd",
"Ag": "Ag",
"Cd": "Cd",
"In": "In_d",
"Sn": "Sn_d",
"Sb": "Sb",
"Te": "Te",
"I": "I",
"Xe": "Xe",
"Cs": "Cs_sv",
"Ba": "Ba_sv",
"La": "La",
"Ce": "Ce",
"Pr": "Pr_3",
"Nd": "Nd_3",
"Pm": "Pm_3",
"Sm": "Sm_3",
"Eu": "Eu_2",
"Gd": "Gd_3",
"Tb": "Tb_3",
"Dy": "Dy_3",
"Ho": "Ho_3",
"Er": "Er_3",
"Tm": "Tm_3",
"Yb": "Yb_2",
"Lu": "Lu_3",
"Hf": "Hf_pv",
"Ta": "Ta_pv",
"W": "W_sv",
"Re": "Re",
"Os": "Os",
"Ir": "Ir",
"Pt": "Pt",
"Au": "Au",
"Hg": "Hg",
"Tl": "Tl_d",
"Pb": "Pb_d",
"Bi": "Bi_d",
"Po": "Po_d",
"At": "At",
"Rn": "Rn",
"Fr": "Fr_sv",
"Ra": "Ra_sv",
"Ac": "Ac",
"Th": "Th",
"Pa": "Pa",
"U": "U",
"Np": "Np",
"Pu": "Pu",
"Am": "Am",
"Cm": "Cm",
"Cf": "Cf",
},
"potpaw_LDA.54": {
"H": "H",
"He": "He",
"Li": "Li_sv",
"Be": "Be",
"B": "B",
"C": "C",
"N": "N",
"O": "O",
"F": "F",
"Ne": "Ne",
"Na": "Na_pv",
"Mg": "Mg",
"Al": "Al",
"Si": "Si",
"P": "P",
"S": "S",
"Cl": "Cl",
"Ar": "Ar",
"K": "K_sv",
"Ca": "Ca_sv",
"Sc": "Sc_sv",
"Ti": "Ti_sv",
"V": "V_sv",
"Cr": "Cr_pv",
"Mn": "Mn_pv",
"Fe": "Fe",
"Co": "Co",
"Ni": "Ni",
"Cu": "Cu",
"Zn": "Zn",
"Ga": "Ga_d",
"Ge": "Ge_d",
"As": "As",
"Se": "Se",
"Br": "Br",
"Kr": "Kr",
"Rb": "Rb_sv",
"Sr": "Sr_sv",
"Y": "Y_sv",
"Zr": "Zr_sv",
"Nb": "Nb_sv",
"Mo": "Mo_sv",
"Tc": "Tc_pv",
"Ru": "Ru_pv",
"Rh": "Rh_pv",
"Pd": "Pd",
"Ag": "Ag",
"Cd": "Cd",
"In": "In_d",
"Sn": "Sn_d",
"Sb": "Sb",
"Te": "Te",
"I": "I",
"Xe": "Xe",
"Cs": "Cs_sv",
"Ba": "Ba_sv",
"La": "La",
"Ce": "Ce",
"Hf": "Hf_pv",
"Ta": "Ta_pv",
"W": "W_sv",
"Re": "Re",
"Os": "Os",
"Ir": "Ir",
"Pt": "Pt",
"Au": "Au",
"Hg": "Hg",
"Tl": "Tl_d",
"Pb": "Pb_d",
"Bi": "Bi_d",
"Po": "Po_d",
"At": "At",
"Rn": "Rn",
"Fr": "Fr_sv",
"Ra": "Ra_sv",
"Ac": "Ac",
"Th": "Th",
"Pa": "Pa",
"U": "U",
"Np": "Np",
"Pu": "Pu",
"Am": "Am",
"Cm": "Cm",
},
"potpaw_PBE.54_GW": {
"H": "H_GW",
"He": "He_GW",
"Li": "Li_sv_GW",
"Be": "Be_sv_GW",
"B": "B_GW",
"C": "C_GW",
"N": "N_GW",
"O": "O_GW",
"F": "F_GW",
"Ne": "Ne_GW",
"Na": "Na_sv_GW",
"Mg": "Mg_sv_GW",
"Al": "Al_GW",
"Si": "Si_GW",
"P": "P_GW",
"S": "S_GW",
"Cl": "Cl_GW",
"Ar": "Ar_GW",
"K": "K_sv_GW",
"Ca": "Ca_sv_GW",
"Sc": "Sc_sv_GW",
"Ti": "Ti_sv_GW",
"V": "V_sv_GW",
"Cr": "Cr_sv_GW",
"Mn": "Mn_sv_GW",
"Fe": "Fe_sv_GW",
"Co": "Co_sv_GW",
"Ni": "Ni_sv_GW",
"Cu": "Cu_sv_GW",
"Zn": "Zn_sv_GW",
"Ga": "Ga_d_GW",
"Ge": "Ge_d_GW",
"As": "As_GW",
"Se": "Se_GW",
"Br": "Br_GW",
"Kr": "Kr_GW",
"Rb": "Rb_sv_GW",
"Sr": "Sr_sv_GW",
"Y": "Y_sv_GW",
"Zr": "Zr_sv_GW",
"Nb": "Nb_sv_GW",
"Mo": "Mo_sv_GW",
"Tc": "Tc_sv_GW",
"Ru": "Ru_sv_GW",
"Rh": "Rh_sv_GW",
"Pd": "Pd_sv_GW",
"Ag": "Ag_sv_GW",
"Cd": "Cd_sv_GW",
"In": "In_d_GW",
"Sn": "Sn_d_GW",
"Sb": "Sb_d_GW",
"Te": "Te_GW",
"I": "I_GW",
"Xe": "Xe_GW",
"Cs": "Cs_sv_GW",
"Ba": "Ba_sv_GW",
"La": "La_GW",
"Ce": "Ce_GW",
"Hf": "Hf_sv_GW",
"Ta": "Ta_sv_GW",
"W": "W_sv_GW",
"Re": "Re_sv_GW",
"Os": "Os_sv_GW",
"Ir": "Ir_sv_GW",
"Pt": "Pt_sv_GW",
"Au": "Au_sv_GW",
"Hg": "Hg_sv_GW",
"Tl": "Tl_d_GW",
"Pb": "Pb_d_GW",
"Bi": "Bi_d_GW",
"Po": "Po_d_GW",
"At": "At_d_GW",
"Rn": "Rn_d_GW",
},
"potpaw_LDA.54_GW": {
"H": "H_GW",
"He": "He_GW",
"Li": "Li_sv_GW",
"Be": "Be_sv_GW",
"B": "B_GW",
"C": "C_GW",
"N": "N_GW",
"O": "O_GW",
"F": "F_GW",
"Ne": "Ne_GW",
"Na": "Na_sv_GW",
"Mg": "Mg_sv_GW",
"Al": "Al_GW",
"Si": "Si_GW",
"P": "P_GW",
"S": "S_GW",
"Cl": "Cl_GW",
"Ar": "Ar_GW",
"K": "K_sv_GW",
"Ca": "Ca_sv_GW",
"Sc": "Sc_sv_GW",
"Ti": "Ti_sv_GW",
"V": "V_sv_GW",
"Cr": "Cr_sv_GW",
"Mn": "Mn_sv_GW",
"Fe": "Fe_sv_GW",
"Co": "Co_sv_GW",
"Ni": "Ni_sv_GW",
"Cu": "Cu_sv_GW",
"Zn": "Zn_sv_GW",
"Ga": "Ga_d_GW",
"Ge": "Ge_d_GW",
"As": "As_GW",
"Se": "Se_GW",
"Br": "Br_GW",
"Kr": "Kr_GW",
"Rb": "Rb_sv_GW",
"Sr": "Sr_sv_GW",
"Y": "Y_sv_GW",
"Zr": "Zr_sv_GW",
"Nb": "Nb_sv_GW",
"Mo": "Mo_sv_GW",
"Tc": "Tc_sv_GW",
"Ru": "Ru_sv_GW",
"Rh": "Rh_sv_GW",
"Pd": "Pd_sv_GW",
"Ag": "Ag_sv_GW",
"Cd": "Cd_sv_GW",
"In": "In_d_GW",
"Sn": "Sn_d_GW",
"Sb": "Sb_d_GW",
"Te": "Te_GW",
"I": "I_GW",
"Xe": "Xe_GW",
"Cs": "Cs_sv_GW",
"Ba": "Ba_sv_GW",
"La": "La_GW",
"Ce": "Ce_GW",
"Hf": "Hf_sv_GW",
"Ta": "Ta_sv_GW",
"W": "W_sv_GW",
"Re": "Re_sv_GW",
"Os": "Os_sv_GW",
"Ir": "Ir_sv_GW",
"Pt": "Pt_sv_GW",
"Au": "Au_sv_GW",
"Hg": "Hg_sv_GW",
"Tl": "Tl_d_GW",
"Pb": "Pb_d_GW",
"Bi": "Bi_d_GW",
"Po": "Po_d_GW",
"At": "At_d_GW",
"Rn": "Rn_d_GW",
},
}
element_layout = [
[
"H",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"He",
], # noqa: E501, E201
[
"Li",
"Be",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"B",
"C",
"N",
"O",
"F",
"Ne",
], # noqa: E501
[
"Na",
"Mg",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"Al",
"Si",
"P",
"S",
"Cl",
"Ar",
], # noqa: E501
[
"K",
"Ca",
"",
"Sc",
"Ti",
"V",
"Cr",
"Mn",
"Fe",
"Co",
"Ni",
"Cu",
"Zn",
"Ga",
"Ge",
"As",
"Se",
"Br",
"Kr",
], # noqa: E501, E201
[
"Rb",
"Sr",
"",
"Y",
"Zr",
"Nb",
"Mo",
"Tc",
"Ru",
"Rh",
"Pd",
"Ag",
"Cd",
"In",
"Sn",
"Sb",
"Te",
"I",
"Xe",
], # noqa: E501
[
"Cs",
"Ba",
"",
"Lu",
"Hf",
"Ta",
"W",
"Re",
"Os",
"Ir",
"Pt",
"Au",
"Hg",
"Tl",
"Pb",
"Bi",
"Po",
"At",
"Rn",
], # noqa: E501
[
"Fr",
"Ra",
"",
"Lr",
"Rf",
"Db",
"Sg",
"Bh",
"Hs",
"Mt",
"Ds",
"Rg",
"Cn",
"Nh",
"Fl",
"Mc",
"Lv",
"Ts",
"Og",
], # noqa: E501
[],
[
"",
"",
"",
"La",
"Ce",
"Pr",
"Nd",
"Pm",
"Sm",
"Eu",
"Gd",
"Tb",
"Dy",
"Ho",
"Er",
"Tm",
"Yb",
], # noqa: E501, E201
[
"",
"",
"",
"Ac",
"Th",
"Pa",
"U",
"Np",
"Pu",
"Am",
"Cm",
"Bk",
"Cf",
"Es",
"Fm",
"Md",
"No",
], # noqa: E501, E201
] # yapf: disable
[docs]
class TkEnergy(seamm.TkNode):
"""
The graphical part of a Energy step in a flowchart.
Attributes
----------
tk_flowchart : TkFlowchart = None
The flowchart that we belong to.
node : Node = None
The corresponding node of the non-graphical flowchart
canvas: tkCanvas = None
The Tk Canvas to draw on
dialog : Dialog
The Pmw dialog object
x : int = None
The x-coordinate of the center of the picture of the node
y : int = None
The y-coordinate of the center of the picture of the node
w : int = 200
The width in pixels of the picture of the node
h : int = 50
The height in pixels of the picture of the node
self[widget] : dict
A dictionary of tk widgets built using the information
contained in Energy_parameters.py
See Also
--------
Energy, TkEnergy,
EnergyParameters,
"""
def __init__(
self,
tk_flowchart=None,
node=None,
canvas=None,
x=None,
y=None,
w=200,
h=50,
):
"""
Initialize a graphical node.
Parameters
----------
tk_flowchart: Tk_Flowchart
The graphical flowchart that we are in.
node: Node
The non-graphical node for this step.
namespace: str
The stevedore namespace for finding sub-nodes.
canvas: Canvas
The Tk canvas to draw on.
x: float
The x position of the nodes center on the canvas.
y: float
The y position of the nodes cetner on the canvas.
w: float
The nodes graphical width, in pixels.
h: float
The nodes graphical height, in pixels.
Returns
-------
None
"""
self.dialog = None
self.available = {} # The available potentials for the current set
self.current_potential_set = None
self.default_potential = {}
super().__init__(
tk_flowchart=tk_flowchart,
node=node,
canvas=canvas,
x=x,
y=y,
w=w,
h=h,
)
# Make sure we have the information about the PAW potentials
directory = Path("~/SEAMM/Parameters/VASP").expanduser()
index = directory / "index.json"
if index.exists():
with index.open() as fd:
self.potential_metadata = json.load(fd)
else:
self.potential_metadata = self.node.parent.catalog_potentials()
with index.open("w") as fd:
json.dump(
self.potential_metadata,
fd,
indent=4,
sort_keys=True,
cls=CompactJSONEncoder,
)
print(f"Wrote the index to {index}")
[docs]
def create_dialog(self, title="Energy"):
"""
Create the dialog. A set of widgets will be chosen by default
based on what is specified in the Energy_parameters
module.
Parameters
----------
None
Returns
-------
None
See Also
--------
TkEnergy.reset_dialog
"""
# Shortcut for parameters
P = self.node.parameters
frame = super().create_dialog(title=title, default_number_values=1)
# Make scrollable in case contents too large
self["scrolled frame"] = sw.ScrolledFrame(frame)
self["scrolled frame"].grid(row=0, column=0, sticky=tk.NSEW)
frame.rowconfigure(0, weight=1)
frame.columnconfigure(0, weight=1)
main_frame = self["main frame"] = self["scrolled frame"].interior()
# Then create the widgets
for key in (
"input only",
"use hdf5 files",
"calculate stress",
"save gradients",
):
self[key] = P[key].widget(main_frame)
# Frame to isolate widgets for the calculation definition
calculation_frame = self["calculation frame"] = ttk.LabelFrame(
main_frame,
borderwidth=4,
relief="sunken",
text="Single-Point Energy Control",
labelanchor="n",
padding=10,
)
# Then create the widgets and place them
row = 0
widgets = []
for key in ("calculate stress", "save gradients"):
w = self[key] = P[key].widget(calculation_frame)
w.grid(row=row, column=0, sticky="ew")
row += 1
widgets.append(w)
sw.align_labels(widgets, sticky="e")
# Frame to isolate widgets
e_frame = self["model frame"] = ttk.LabelFrame(
main_frame,
borderwidth=4,
relief="sunken",
text="Electronic Structure Definition",
labelanchor="n",
padding=10,
)
# Then create the widgets
for key in ("model", "submodel", "spin polarization", "nonspherical PAW"):
self[key] = P[key].widget(e_frame)
try:
self[key].configure(width=45)
except Exception:
pass
for key in ("model", "submodel"):
self[key].bind("<<ComboboxSelected>>", self.reset_model_frame)
self[key].bind("<Return>", self.reset_model_frame)
self[key].bind("<FocusOut>", self.reset_model_frame)
# Frame for the control of the electronic minimization
scf_frame = self["scf frame"] = ttk.LabelFrame(
main_frame,
borderwidth=4,
relief="sunken",
text="Electronic Minimization",
labelanchor="n",
padding=10,
)
# Then create the widgets and place them
row = 0
widgets = []
for key in (
"electronic method",
"nelm",
"nelmin",
"ediff",
"precision",
"initial wavefunction",
):
w = self[key] = P[key].widget(scf_frame)
w.grid(row=row, column=0, sticky="ew")
row += 1
widgets.append(w)
sw.align_labels(widgets, sticky="e")
for key in ("electronic method",):
self[key].bind("<<ComboboxSelected>>", self.reset_performance_frame)
self[key].bind("<Return>", self.reset_performance_frame)
self[key].bind("<FocusOut>", self.reset_performance_frame)
# The k-space integration
k_frame = self["k-space frame"] = ttk.LabelFrame(
main_frame,
borderwidth=4,
relief="sunken",
text="K-space Integration",
labelanchor="n",
padding=10,
)
for key in vasp_step.EnergyParameters.kspace_parameters:
self[key] = P[key].widget(k_frame)
for key in ("na", "nb", "nc"):
self[key].entry.configure(width=4)
for key in ("k-grid method", "occupation type"):
self[key].bind("<<ComboboxSelected>>", self.reset_kspace_frame)
self[key].bind("<Return>", self.reset_kspace_frame)
self[key].bind("<FocusOut>", self.reset_kspace_frame)
# Frame for the performance parameters
performance_frame = self["performance frame"] = ttk.LabelFrame(
main_frame,
borderwidth=4,
relief="sunken",
text="Performance Parameters",
labelanchor="n",
padding=10,
)
# Then create the widgets
for key in (
"np",
"ncore",
"kpar",
"lplane",
"lreal",
"lscalapack",
"lscalu",
"nsim",
):
self[key] = P[key].widget(performance_frame)
s_frame = self["structure frame"] = ttk.LabelFrame(
main_frame,
borderwidth=4,
relief="sunken",
text="Configuration Handling",
labelanchor="n",
padding=10,
)
row = 0
widgets = []
for key in ("structure handling", "system name", "configuration name"):
self[key] = P[key].widget(s_frame)
self[key].grid(row=row, column=0, sticky=tk.EW)
widgets.append(self[key])
row += 1
sw.align_labels(widgets, sticky=tk.E)
# Top level needs to call reset_dialog to layout the dialog
if self.node.calculation == "energy":
self.reset_dialog()
self.create_potentials_tab()
[docs]
def create_potentials_tab(self):
"""Add a tab with a periodic table for setting the potentials."""
# Shortcut for parameters
P = self.node.parameters
notebook = self["notebook"]
potentials_frame = ttk.Frame(notebook)
self["potentials frame"] = potentials_frame
notebook.insert(
self["results frame"],
potentials_frame,
text="Potentials",
sticky="nsew",
)
row = 0
widgets = []
for key in ("set of potentials", "plane-wave cutoff"):
self[key] = P[key].widget(potentials_frame)
self[key].grid(row=row, column=0, sticky="ew")
row += 1
widgets.append(self[key])
# Align the labels
sw.align_labels(widgets, sticky="e")
for key in ("set of potentials",):
self[key].bind("<<ComboboxSelected>>", self._change_set)
self[key].bind("<Return>", self._change_set)
self[key].bind("<FocusOut>", self._change_set)
# Display the max enmax next to the plane-wave cutoff
for key in ("enmax",):
w = self[key] = P[key].widget(potentials_frame)
w.grid(row=1, column=1, sticky="w")
w.config(state="readonly")
# Put the possible potential sets into the widget
metadata = self.potential_metadata
sets = [*metadata.keys()]
self.current_potential_set = self["set of potentials"].value
self["set of potentials"].config(values=sets)
if "GW" in P["subset"]:
self.default_potential = default_potentials[
self.current_potential_set + "_GW"
]
else:
self.default_potential = default_potentials[self.current_potential_set]
# This is used for the radiobutton to control what subset is show/used
var = self.tk_var["subset"] = tk.StringVar()
var.set(P["subset"])
# And make a scrollable periodic table area for the potentials
self["scrolled periodic table"] = sw.ScrolledFrame(potentials_frame)
self["scrolled periodic table"].grid(
row=row, column=0, columnspan=2, sticky=tk.NSEW
)
potentials_frame.rowconfigure(row, weight=1)
potentials_frame.columnconfigure(1, weight=1)
row += 1
frame = self["potentials"] = self["scrolled periodic table"].interior()
# Create the widgets in the periodic table layout
current = self.node.parameters["potentials"].value
self.find_available_potentials()
for _row, elements in enumerate(element_layout):
for _col, element in enumerate(elements):
if element != "":
if element in self.available:
w = self._widget[element] = ttk.Combobox(
frame,
values=[f"_{element}_", *self.available[element]],
width=6,
)
if element in current:
w.set(current[element])
else:
w.set(self.default_potential[element])
else:
w = self._widget[element] = ttk.Combobox(
frame,
width=5,
)
w.set(f"_{element}_")
w.config(state="disabled")
w.grid(row=_row, column=_col, sticky=tk.EW)
w.bind("<<ComboboxSelected>>", self.update_Emax)
w.bind("<Return>", self.update_Emax)
w.bind("<FocusOut>", self.update_Emax)
self.update_Emax()
# Radio button to allow selecting standard and GW potentials.
for text in (
"Show all potentials",
"Show standard potentials",
"Show GW potentials",
):
w = self._widget[text] = ttk.Radiobutton(
potentials_frame,
text=text,
value=text,
variable=self.tk_var["subset"],
command=self._handle_show_potentials,
)
w.grid(row=row, column=0, sticky="w")
row += 1
w = self._widget["default potentials"] = ttk.Button(
potentials_frame,
text="Reset to default potentials",
command=self._set_to_default_potentials,
)
w.grid(row=row, column=0, sticky="w")
row += 1
w = self._widget["clear all potentials"] = ttk.Button(
potentials_frame,
text="Clear all potentials",
command=self._clear_potentials,
)
w.grid(row=row, column=0, sticky="w")
row += 1
frame.grid_columnconfigure(2, minsize=30)
frame.grid_rowconfigure(7, minsize=30)
def _change_set(self, *args):
"""Handle changing the set of potentials to use."""
self.current_potential_set = self["set of potentials"].get()
self._handle_show_potentials()
def _handle_show_potentials(self, current=None):
"""Show or hide the standard or GW potentials."""
subset = self.tk_var["subset"].get()
self.find_available_potentials()
if "GW" in subset:
self.default_potential = default_potentials[
self.current_potential_set + "_GW"
]
else:
self.default_potential = default_potentials[self.current_potential_set]
if current is None:
current = self.get_current_potentials()
for elements in element_layout:
for element in elements:
if element != "":
if element in self.available:
self._widget[element].config(
values=[f"_{element}_", *self.available[element]],
state="!disabled",
)
if element in current:
if current[element] in self.available[element]:
self._widget[element].set(current[element])
else:
self._widget[element].set(
self.default_potential[element]
)
else:
self._widget[element].set(f"_{element}_")
else:
self._widget[element].config(state="!disabled")
self._widget[element].set(f"_{element}_")
self._widget[element].config(
values=[f"_{element}_"], state="disabled"
)
self.update_Emax()
def _set_to_default_potentials(self):
"""Reset to the default potentials."""
self.find_available_potentials()
subset = self.tk_var["subset"].get()
if "GW" in subset:
self.default_potential = default_potentials[
self.current_potential_set + "_GW"
]
else:
self.default_potential = default_potentials[self.current_potential_set]
for elements in element_layout:
for element in elements:
if element != "":
if element in self.available:
self._widget[element].set(self.default_potential[element])
else:
self._widget[element].config(state="!disabled")
self._widget[element].set(f"_{element}_")
self._widget[element].config(state="disabled")
self.update_Emax()
def _clear_potentials(self):
"""Reset to the no potentials."""
for elements in element_layout:
for element in elements:
if element != "":
self._widget[element].set(f"_{element}_")
self.update_Emax()
[docs]
def find_available_potentials(self):
potential_data = self.potential_metadata[self.current_potential_set]
self.available = {}
subset = self.tk_var["subset"].get()
for potential, data in potential_data.items():
if "GW" in subset:
if "_GW" not in potential:
continue
elif "all" not in subset:
if "_GW" in potential:
continue
el = potential.split("_")[0]
if el in self.available:
self.available[el].append(potential)
else:
self.available[el] = [potential]
for el, tmp in self.available.items():
self.available[el] = sorted(tmp)
[docs]
def get_current_potentials(self):
"""Get the currently selected potentials from the widgets."""
result = {}
for elements in element_layout:
for element in elements:
if element != "":
if element in self.available:
tmp = self._widget[element].get()
if tmp != "" and not tmp.startswith("_"):
result[element] = tmp
return result
[docs]
def get_Emax(self):
"""Get the maximum ENMAX for the currently slsected potentials"""
potential_data = self.potential_metadata[self.current_potential_set]
Emax = 0
for elements in element_layout:
for element in elements:
if element != "":
if element in self.available:
potential = self._widget[element].get()
if potential.startswith("_") or potential == "":
pass
else:
Emax = max(Emax, float(potential_data[potential]["Emax"]))
return Emax
[docs]
def update_Emax(self, event=None):
"""Update the value of Emax in the display."""
self["enmax"].config(state="!readonly")
self["enmax"].set(self.get_Emax(), unit_string="eV")
self["enmax"].config(state="readonly")
[docs]
def reset_dialog(self, widget=None, row=0):
"""Layout the widgets in the dialog.
The widgets are chosen by default from the information in
Energy_parameter.
This function simply lays them out row by row with
aligned labels. You may wish a more complicated layout that
is controlled by values of some of the control parameters.
If so, edit or override this method
Parameters
----------
widget : Tk Widget = None
Returns
-------
None
See Also
--------
TkEnergy.create_dialog
"""
# Remove any widgets previously packed
frame = self["main frame"]
for slave in frame.grid_slaves():
slave.grid_forget()
# Shortcut for parameters
P = self.node.parameters
# Whether to just write input
widgets = []
for key in ("input only", "use hdf5 files"):
self[key].grid(row=row, column=0, sticky=tk.W)
widgets.append(self[key])
row += 1
sw.align_labels(widgets, sticky=tk.E)
# The calculation and handling of the structure
self["calculation frame"].grid(
row=row, column=0, columnspan=2, pady=5, sticky="new"
)
self["structure frame"].grid(
row=row, column=2, columnspan=2, pady=5, sticky="new"
)
row += 1
# The model for the calculation
self["model frame"].grid(row=row, column=0, columnspan=2, pady=5, sticky="new")
self["scf frame"].grid(row=row, column=2, columnspan=2, pady=5, sticky="new")
row += 1
self["k-space frame"].grid(
row=row, column=0, columnspan=2, pady=5, sticky="new"
)
self["performance frame"].grid(
row=row, column=2, columnspan=2, pady=5, sticky="new"
)
row += 1
# Layout the energy widgets
self.reset_calculation_frame()
self.reset_model_frame()
self.reset_kspace_frame()
self.reset_performance_frame()
# Setup the results if there are any
have_results = (
"results" in self.node.metadata and len(self.node.metadata["results"]) > 0
)
if have_results and "results" in P:
self.setup_results()
return row
[docs]
def reset_calculation_frame(self, widget=None):
"""Layout the widgets for the calculation control.
Note
----
The single point energy has nothing that changes, so do nothing.
"""
pass
[docs]
def reset_model_frame(self, widget=None):
"""Layout the widgets in the dialog.
The widgets are chosen by default from the information in
Energy_parameter.
This function simply lays them out row by row with
aligned labels. You may wish a more complicated layout that
is controlled by values of some of the control parameters.
If so, edit or override this method
Parameters
----------
widget : Tk Widget = None
Returns
-------
None
See Also
--------
TkEnergy.create_dialog
"""
# Remove any widgets previously packed
frame = self["model frame"]
for slave in frame.grid_slaves():
slave.grid_forget()
# Shortcut for parameters
P = self.node.parameters
# keep track of the row in a variable, so that the layout is flexible
# if e.g. rows are skipped to control such as "method" here
row = 0
# The model for the calculation
keys = ["model", "submodel", "spin polarization", "nonspherical PAW"]
model = self["model"].get()
# And what models have available sublevels?
model_data = self.node.metadata["computational models"][
"Density Functional Theory (DFT)"
]["models"]
models = []
for tmp in model_data.keys():
models.append(tmp)
w = self["model"]
if w.combobox.cget("values") != models:
w.config(values=models)
if not self.is_expr(model) and model not in models and len(models) > 0:
w.set(models[0])
else:
w.set(model)
# Fill out the possible submodels
submodel = self["submodel"].get()
choices = model_data[model]["parameterizations"]
submodels = [*choices.keys()]
w = self["submodel"]
if w.combobox.cget("values") != submodels:
w.config(values=submodels)
if (
not self.is_expr(submodel)
and submodel not in submodels
and len(submodels) > 0
):
w.set(submodels[0])
else:
w.set(submodel)
# And the basis
widgets = []
for key in keys:
self[key].grid(row=row, column=0, sticky=tk.EW)
widgets.append(self[key])
row += 1
# Align the labels
sw.align_labels(widgets, sticky=tk.E)
frame.columnconfigure(0, weight=1)
# Setup the results if there are any
have_results = (
"results" in self.node.metadata and len(self.node.metadata["results"]) > 0
)
if have_results and "results" in P:
self.setup_results()
[docs]
def reset_kspace_frame(self, widget=None):
"""Layout the widgets in the dialog.
The widgets are chosen by default from the information in
Energy_parameter.
This function simply lays them out row by row with
aligned labels. You may wish a more complicated layout that
is controlled by values of some of the control parameters.
If so, edit or override this method
Parameters
----------
widget : Tk Widget = None
Returns
-------
None
See Also
--------
TkEnergy.create_dialog
"""
# Remove any widgets previously packed
frame = self["k-space frame"]
for slave in frame.grid_slaves():
slave.grid_forget()
# keep track of the row in a variable, so that the layout is flexible
# if e.g. rows are skipped to control such as "method" here
row = 0
widgets = []
widgets1 = []
# The model for the calculation
key = "k-grid method"
method = self[key].get()
self[key].grid(row=row, column=0, columnspan=4, sticky=tk.W)
widgets.append(self[key])
row += 1
if "explicit" in method:
for col, key in enumerate(("na", "nb", "nc"), start=1):
self[key].grid(row=row, column=col, sticky=tk.EW)
row += 1
elif "point" in method:
pass
else:
for key in ("k-spacing", "odd grid", "centering"):
self[key].grid(row=row, column=1, columnspan=3, sticky=tk.EW)
widgets1.append(self[key])
row += 1
key = "occupation type"
smearing = self[key].get()
self[key].grid(row=row, column=0, columnspan=4, sticky=tk.W)
widgets.append(self[key])
row += 1
if "Methfessel-Paxton" in smearing:
key = "Methfessel-Paxton order"
self[key].grid(row=row, column=1, columnspan=3, sticky=tk.EW)
widgets1.append(self[key])
row += 1
if "without smearing" not in smearing:
key = "smearing width"
self[key].grid(row=row, column=1, columnspan=3, sticky=tk.EW)
widgets1.append(self[key])
row += 1
w0 = sw.align_labels(widgets, sticky=tk.E)
w1 = sw.align_labels(widgets1, sticky=tk.E)
minwidth = w0 - w1 + 30
frame.columnconfigure(0, minsize=minwidth)
frame.columnconfigure(1, weight=1)
frame.columnconfigure(2, weight=1)
frame.columnconfigure(3, weight=1)
[docs]
def right_click(self, event):
"""
Handles the right click event on the node.
Parameters
----------
event : Tk Event
Returns
-------
None
See Also
--------
TkEnergy.edit
"""
super().right_click(event)
self.popup_menu.add_command(label="Edit..", command=self.edit)
self.popup_menu.tk_popup(event.x_root, event.y_root, 0)
[docs]
def fit_dialog(self):
"""Make the dialog fill the window."""
screen_w = self.dialog.winfo_screenwidth()
screen_h = self.dialog.winfo_screenheight()
w = int(1.0 * screen_w)
h = int(1.0 * screen_h)
x = 0
y = int(0.0 * screen_h / 2)
self.dialog.geometry(f"{w}x{h}+{x}+{y}")
[docs]
def handle_dialog(self, result):
"""Handle closing the dialog.
Parameters
----------
result : str
The button that was pressed to close the dialog, or None if the x dialog
close button was pressed.
"""
if result is None or result == "Cancel":
# Reset the potentials to their original values
P = self.node.parameters
subset = P["subset"]
self.tk_var["subset"].set(subset)
for key in ("set of potentials", "plane-wave cutoff"):
self[key].set(P[key])
self.current_potential_set = P["set of potentials"].value
if "GW" in subset:
self.default_potential = default_potentials[
self.current_potential_set + "_GW"
]
else:
self.default_potential = default_potentials[self.current_potential_set]
current = self.node.parameters["potentials"].value
self._handle_show_potentials(current)
elif result == "OK":
self.node.parameters["potentials"].value = self.get_current_potentials()
# And let the superclass do the rest
super().handle_dialog(result)