Skip to content

Commit

Permalink
Merge pull request #35 from molssi-seamm/dev
Browse files Browse the repository at this point in the history
Standard structure handling and cleaned up output
  • Loading branch information
seamm committed Nov 10, 2023
2 parents 4e12526 + 2bf9a09 commit 597d93e
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 104 deletions.
6 changes: 6 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
=======
History
=======
2023.11.10 -- Standard structure handling and cleaned up output
* Switched to standard structure handling and naming, giving consistent options
across SEAMM.
* Corrected issues with the model name in the properties.
* Generally cleaned up the output, mainly indentation.

2023.11.8 -- Bugfix: Fermi level being an array caused problems
* The Fermi level in DFTB+ is a vector with 1 or 2 elements, depending whether the
calculation is spin-polarized. DFTB+ can handle different Fermi levels, but it is
Expand Down
9 changes: 9 additions & 0 deletions dftbplus_step/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,15 @@ def is_runable(self):
"""Indicate whether this not runs or just adds input."""
return True

@property
def model(self):
"""The model (chemistry) used to obtain results."""
return self.parent.model

@model.setter
def model(self, value):
self.parent.model = value

def band_structure(
self, input_path, sym_points, sym_names, Efermi=[0.0, 0.0], DOS=None
):
Expand Down
12 changes: 7 additions & 5 deletions dftbplus_step/choose_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
import seamm_util.printing as printing
from seamm_util.printing import FormattedText as __

from .base import DftbBase

logger = logging.getLogger(__name__)
job = printing.getPrinter()
printer = printing.getPrinter("DFTB+")


class ChooseParameters(seamm.Node):
class ChooseParameters(DftbBase):
def __init__(
self, flowchart=None, title="Choose Parameters", extension=None, logger=logger
):
Expand Down Expand Up @@ -88,7 +90,7 @@ def get_input(self):
PP[key] = "{:~P}".format(PP[key])

self.description = []
self.description.append(__(self.description_text(PP), **PP, indent=self.indent))
self.description.append(__(self.description_text(PP), **PP, indent=4 * " "))

# The parameter data
parameter_set = P["dataset"]
Expand All @@ -113,7 +115,7 @@ def get_input(self):
potentials = metadata[model]["potentials"]
pairs = dataset["potential pairs"]

self.parent._hamiltonian = parameter_set
self.model = parameter_set.replace(" - ", "/")

if P["subset"] == "none" or P["subset"] == "":
subset = None
Expand All @@ -122,7 +124,7 @@ def get_input(self):
if " - " not in subset:
# From a variable
subset = f"{model} - {subset}"
self.parent._hamiltonian += " + " + subset.split(" - ")[1]
self.model += "+" + subset.split(" - ")[1]
subset = datasets[subset]
subpairs = subset["potential pairs"]

Expand Down Expand Up @@ -216,7 +218,7 @@ def get_input(self):
)
elif model == "xTB":
# Broadcast to the parent so that other substeps can use
self.parent._hamiltonian = P["dataset"]
self.model = P["dataset"].replace(" - ", "/")
self.parent._dataset = dataset
self.parent._subset = None

Expand Down
3 changes: 1 addition & 2 deletions dftbplus_step/dftbplus.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,6 @@ def __init__(
# Data to pass between substeps
self._dataset = None # SLAKO dataset used
self._subset = None # SLAKO modifier dataset applied to dataset
self._hamiltonian = None # String name of the Hamiltonian
self._reference_energies = None # Reference energies per element.
self._reference_energy = None # for calculating energy of formation
self._steps = None # The nodes for the steps run so far.
Expand Down Expand Up @@ -363,7 +362,7 @@ def description_text(self, P=None):
text = self.header + "\n\n"
while node is not None:
try:
text += __(node.description_text(), indent=3 * " ").__str__()
text += __(node.description_text(), indent=4 * " ").__str__()
except Exception as e:
print(
"Error describing dftbplus flowchart: {} in {}".format(
Expand Down
18 changes: 9 additions & 9 deletions dftbplus_step/energy.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,14 +195,14 @@ def get_input(self):

# Set up the description.
self.description = []
self.description.append(__(self.description_text(PP), **PP, indent=self.indent))
self.description.append(__(self.description_text(PP), **PP, indent=4 * " "))

# Determine the input and as we do so, replace any default values
# in PP so that we print what is actually done

dataset = self.parent._dataset
parameter_set = self.parent._hamiltonian
model, parameter_set_name = parameter_set.split(" - ", 1)
parameter_set = self.model
model, parameter_set_name = parameter_set.split("/", 1)

if model == "DFTB":
if "defaults" in dataset:
Expand Down Expand Up @@ -407,9 +407,9 @@ def get_input(self):
# First check if we have shell resolved constants or not
spin_constants = hamiltonian["SpinConstants"] = {}
symbols = sorted([*set(atoms.symbols)])
dataset_name = self.parent._hamiltonian
dataset_name = self.model
# e.g. "DFTB - mio"
key = dataset_name.split(" - ")[1]
key = dataset_name.split("/")[1]
if key in spin_constant_data:
constants = spin_constant_data[key]
else:
Expand Down Expand Up @@ -496,7 +496,7 @@ def get_input(self):
__(
f"The mesh for the Brillouin zone integration is {na} x {nb} x {nc}"
f" with offsets of {oa}, {ob}, and {oc}",
indent=self.indent + 4 * " ",
indent=4 * " ",
)
)

Expand Down Expand Up @@ -711,11 +711,11 @@ def analyze(self, indent="", data={}, out=[]):
except Exception as e:
text += f"There was an error making the plots: {str(e)}"
else:
text += f"Orbital plots not supported for {self.parent._hamiltonian}"
text += f"Orbital plots not supported for {self.model}"

text = str(__(text, **data, indent=self.indent + 4 * " "))
text = str(__(text, **data, indent=8 * " "))
text += "\n\n"
text += textwrap.indent("\n".join(text_lines), self.indent + 7 * " ")
text += textwrap.indent("\n".join(text_lines), 12 * " ")

printer.normal(text)

Expand Down
99 changes: 44 additions & 55 deletions dftbplus_step/optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ def description_text(self, P=None):
f" A maximum of {P['MaxSteps']} steps will be used."
)

if self.model is None:
kwargs = {}
else:
kwargs = {"Hamiltonian": self.model}
text += seamm.standard_parameters.structure_handling_description(P, **kwargs)

return (
self.header
+ "\n"
Expand All @@ -85,7 +91,7 @@ def get_input(self):
PP[key] = "{:~P}".format(PP[key])

self.description = []
self.description.append(__(self.description_text(PP), **PP, indent=self.indent))
self.description.append(__(self.description_text(PP), **PP, indent=4 * " "))

_, configuration = self.get_system_configuration(None)

Expand Down Expand Up @@ -136,26 +142,39 @@ def analyze(self, indent="", data={}, out=[]):
context=seamm.flowchart_variables._data
)

# Read the detailed output file to get the number of iterations
directory = Path(self.directory)
path = directory / "detailed.out"
lines = iter(path.read_text().splitlines())
data["nsteps"] = "unknown number of"
data["ediff"] = "unknown"
data["scc error"] = None
for line in lines:
if "Geometry optimization step:" in line:
data["nsteps"] = line.split()[3]
if "Diff electronic" in line:
tmp = next(lines).split()
data["ediff"] = float(tmp[2])

# Print the key results

text += (
"The geometry optimization converged in {nsteps} steps. "
"The last change in energy was {ediff:.6} Eh"
)
if P["SCC"] == "Yes" and data["scc error"] is not None:
text += " and the error in the charges of {scc error:.6}."
else:
text += "."

# Update the structure
if "final structure" in data:
sdata = data["final structure"]

system, starting_configuration = self.get_system_configuration(None)
periodicity = starting_configuration.periodicity
if (
"structure handling" in P
and P["structure handling"] == "Create a new configuration"
):
configuration = system.create_configuration(
periodicity=periodicity,
atomset=starting_configuration.atomset,
bondset=starting_configuration.bondset,
cell_id=starting_configuration.cell_id,
)
else:
configuration = starting_configuration
_, starting_configuration = self.get_system_configuration()
system, configuration = self.get_system_configuration(P)

if periodicity == 3:
if starting_configuration.periodicity == 3:
(
lattice_in,
fractionals_in,
Expand Down Expand Up @@ -190,45 +209,15 @@ def analyze(self, indent="", data={}, out=[]):
)

# And the name of the configuration.
if "configuration name" in P:
if P["configuration name"] == "optimized with <Hamiltonian>":
hamiltonian = self.parent._hamiltonian
configuration.name = f"optimized with {hamiltonian}"
elif P["configuration name"] == "keep current name":
pass
elif P["configuration name"] == "use SMILES string":
configuration.name = configuration.smiles
elif P["configuration name"] == "use Canonical SMILES string":
configuration.name = configuration.canonical_smiles
elif P["configuration name"] == "use configuration number":
configuration.name = str(configuration.n_configurations)

# Read the detailed output file to get the number of iterations
directory = Path(self.directory)
path = directory / "detailed.out"
lines = iter(path.read_text().splitlines())
data["nsteps"] = "unknown number of"
data["ediff"] = "unknown"
data["scc error"] = None
for line in lines:
if "Geometry optimization step:" in line:
data["nsteps"] = line.split()[3]
if "Diff electronic" in line:
tmp = next(lines).split()
data["ediff"] = float(tmp[2])

# Print the key results

text += (
"The geometry optimization converged in {nsteps} steps. "
"The last change in energy was {ediff:.6} Eh"
)
if P["SCC"] == "Yes" and data["scc error"] is not None:
text += " and the error in the charges of {scc error:.6}."
else:
text += "."

printer.normal(__(text, **data, indent=self.indent + 4 * " "))
text += seamm.standard_parameters.set_names(
system,
configuration,
P,
_first=True,
Hamiltonian=self.model,
)

printer.normal(__(text, **data, indent=8 * " "))

printer.normal("\n")

Expand Down
57 changes: 24 additions & 33 deletions dftbplus_step/optimization_parameters.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*-
"""Global control parameters for DFTB+
"""
import logging

import dftbplus_step
import logging
import seamm

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -159,47 +160,33 @@ class OptimizationParameters(dftbplus_step.EnergyParameters):
"description": "Alpha update on reset:",
"help_text": "The factor for the update the alpha parameter on reset.",
},
# Put in the configuration handling options needed
"structure handling": {
"default": "Create a new configuration",
"kind": "enum",
"default_units": "",
"enumeration": (
"Overwrite the current configuration",
"Create a new configuration",
),
"format_string": "s",
"description": "Configuration handling:",
"help_text": (
"Whether to overwrite the current configuration, or create a new "
"configuration or system and configuration for the new structure"
),
},
"configuration name": {
"default": "optimized with <Hamiltonian>",
"kind": "string",
"default_units": "",
"enumeration": (
"optimized with <Hamiltonian>",
"keep current name",
"use SMILES string",
"use Canonical SMILES string",
"use configuration number",
),
"format_string": "s",
"description": "Configuration name:",
"help_text": "The name for the new configuration",
},
}

def __init__(self, defaults={}, data=None):
"""Initialize the instance, by default from the default
parameters given in the class"""

super().__init__(
defaults={**OptimizationParameters.parameters, **defaults}, data=data
defaults={
**OptimizationParameters.parameters,
**seamm.standard_parameters.structure_handling_parameters,
**defaults,
},
data=data,
)

# Do any local editing of defaults
tmp = self["structure handling"]
tmp.description = "Structure handling:"

tmp = self["system name"]
tmp._data["enumeration"] = (*tmp.enumeration, "optimized with {Hamiltonian}")
tmp.default = "keep current name"

tmp = self["configuration name"]
tmp._data["enumeration"] = ["optimized with {Hamiltonian}", *tmp.enumeration]
tmp.default = "optimized with {Hamiltonian}"

def update(self, data):
"""Update values from a dict
Expand All @@ -220,4 +207,8 @@ def update(self, data):
if key in data:
del data[key]

for key in ("system name", "configuration name"):
if key in data and data[key] == "optimized with <Hamiltonian>":
data[key] = "optimized with {Hamiltonian}"

super().update(data)

0 comments on commit 597d93e

Please sign in to comment.