Source code for dftbplus_step.tk_choose_parameters

# -*- coding: utf-8 -*-

"""The graphical part of a DFTB+ ChooseParameters node"""

try:
    import importlib.metadata as implib
except Exception:
    import importlib_metadata as implib
import json
import logging
import tkinter as tk

import seamm
from seamm_util import element_data
import seamm_widgets as sw

logger = logging.getLogger(__name__)

atno_to_symbol = {d["atomic number"]: symbol for symbol, d in element_data.items()}


[docs] def expand_range_list(x): """Expand a list of integers including ranges into a list. Parameters ---------- x : str A string giving shorthand for a list, like this '1,2, 10-20, 40,50' Returns ------- [int] A python list of integers """ result = [] for part in x.split(","): if "-" in part: a, b = part.split("-") a, b = int(a), int(b) result.extend(range(a, b + 1)) else: a = int(part) result.append(a) return result
[docs] class TkChooseParameters(seamm.TkNode): def __init__( self, tk_flowchart=None, node=None, canvas=None, x=120, y=20, w=200, h=50, my_logger=logger, ): """Initialize the graphical Tk DFTB+ step for choosing Slater-Koster parameters. Keyword arguments: """ self.results_widgets = [] super().__init__( tk_flowchart=tk_flowchart, node=node, canvas=canvas, x=x, y=y, w=w, h=h, my_logger=my_logger, ) # Get the metadata for the Slater-Koster parameters package = self.__module__.split(".")[0] files = [p for p in implib.files(package) if p.name == "metadata.json"] if len(files) != 1: raise RuntimeError("Can't find Slater-Koster metadata.json file") data = files[0].read_text() self._metadata = json.loads(data)
[docs] def right_click(self, event): """Probably need to add our dialog...""" 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 create_dialog(self, title="Edit DFTB+ ChooseParameters Step"): """Create the dialog!""" self.logger.debug("Creating the dialog") frame = super().create_dialog(title=title) # Create all the widgets P = self.node.parameters for key in P: if key not in ("results", "extra keywords", "create tables"): self[key] = P[key].widget(frame) # Show which elements are available available = set() for model, metadata in self._metadata.items(): for dataset, data in metadata["datasets"].items(): if "element sets" in data: for element_set in data["element sets"]: for element in element_set: if element not in available: available.add(element) elif "elements" in data: for atno in expand_range_list(data["elements"]): available.add(atno_to_symbol[atno]) pt = self["elements"] elements = set(pt.elements) not_available = elements - available pt.disable(not_available) # Update the dialog as the user selects elements pt.command = self.reset_dialog for item in ("model", "dataset", "subset"): w = self[item] w.combobox.bind("<<ComboboxSelected>>", self.reset_dialog) w.combobox.bind("<Return>", self.reset_dialog) w.combobox.bind("<FocusOut>", self.reset_dialog) self.logger.debug("Finished creating the dialog")
[docs] def reset_dialog(self, widget=None): frame = self["frame"] for slave in frame.grid_slaves(): slave.grid_forget() model = self["model"].get() pt = self["elements"] ds = self["dataset"] ss = self["subset"] elements = set(pt.get()) dataset = ds.get() subset = ss.get() if self.is_expr(dataset): variable_dataset = True else: variable_dataset = False if self.is_expr(subset): variable_subset = True else: variable_subset = False if not variable_dataset: # Catch older flowcharts with the old names. if "-" not in dataset: dataset = "DFTB - " + dataset # Find the datasets that contain all the requested elements possible_datasets = {} possible_elements = set() for tmp_model, metadata in self._metadata.items(): # See if the model is restricted if model != "any" and tmp_model not in model: continue datasets = self._metadata[tmp_model]["datasets"] if tmp_model == "DFTB": for dset, data in datasets.items(): if data["parent"] is None: for element_set in data["element sets"]: coverage = set(element_set) if elements <= coverage: possible_datasets[dset] = ["none"] possible_elements.update(coverage) # Check with specialized datasets... for sset in data["subsets"]: subdata = datasets[sset] for element_set in subdata["element sets"]: coverage = set(element_set) if elements <= coverage: if dset not in possible_datasets: possible_datasets[dset] = [] if sset not in possible_datasets[dset]: possible_datasets[dset].append(sset) possible_elements.update(coverage) elif tmp_model == "xTB": for dset, data in datasets.items(): coverage = set( atno_to_symbol[atno] for atno in expand_range_list(data["elements"]) ) if elements <= coverage: possible_datasets[dset] = ["none"] possible_elements.update(coverage) # Show which elements are available available = set() for model, metadata in self._metadata.items(): for dset, data in metadata["datasets"].items(): if "element sets" in data: for element_set in data["element sets"]: for element in element_set: if element not in available: available.add(element) elif "elements" in data: for atno in expand_range_list(data["elements"]): available.add(atno_to_symbol[atno]) pt = self["elements"] elements = set(pt.elements) not_available = elements - available pt.disable(not_available) # Enable and disable the elements to reflect possible choices all_elements = set(pt.elements) pt.disable(all_elements - possible_elements) pt.enable(possible_elements) # Sort out the dataset widget tmp = [*possible_datasets.keys()] ds.combobox.config(values=tmp) if len(tmp) == 0: # No parameter set covers all the elements! dataset = "" tk.messagebox.showwarning( title="No Potentials Available for Elements", message=( "There is no dataset available that covers the elements\n\t" + ", ".join(elements) ), ) else: if dataset not in tmp: dataset = tmp[0] ds.set(dataset) # and subset widget if dataset == "": ss.combobox.config(values="") subset = "none" else: tmp = possible_datasets[dataset] ss.combobox.config(values=tmp) if subset not in tmp: subset = tmp[0] ss.set(subset) # Note current elements in the dataset/subset with green labels pt.set_text_color("all", "black") if dataset != "": tmp_model = dataset.split(" - ", 1)[0] datasets = self._metadata[tmp_model]["datasets"] data = datasets[dataset] current = set() if subset == "none": if "element sets" in data: for element_set in data["element sets"]: current.update(element_set) elif "elements" in data: current.update( [ atno_to_symbol[a] for a in expand_range_list(data["elements"]) ] ) else: subdata = datasets[subset] for element_set in subdata["element sets"]: current.update(element_set) pt.set_text_color(current, "green") # and grid the widgets in place widgets = [] row = 0 if not variable_dataset and not variable_subset: self["elements"].grid(row=row, column=0, sticky=tk.EW) row += 1 self["model"].grid(row=row, column=0, sticky=tk.EW) widgets.append(self["model"]) row += 1 self["dataset"].grid(row=row, column=0, sticky=tk.EW) widgets.append(self["dataset"]) row += 1 # only grid the subset if there are choices if variable_dataset or ( dataset != "" and possible_datasets[dataset] != ["none"] ): self["subset"].grid(row=row, column=0, sticky=tk.EW) widgets.append(self["subset"]) row += 1 sw.align_labels(widgets, sticky=tk.W) return row