Skip to content

Yantao Xia - K-point convergence tracker #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions xyttyxy/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
data/
__pycache__/
10 changes: 10 additions & 0 deletions xyttyxy/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
repos:
- repo: https://github.com/psf/black
rev: 22.3.0 # must be, see https://github.com/psf/black/issues/2964
hooks:
- id: black
# It is recommended to specify the latest version of Python
# supported by your project here, or alternatively use
# pre-commit's default_language_version, see
# https://pre-commit.com/#top_level-default_language_version
language_version: python3.9
37 changes: 37 additions & 0 deletions xyttyxy/Convergence-Tracker.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# K-point convergence tracker (Materials)

> Ideal candidate: scientists skilled in Density Functional Theory and proficient in python.

# Overview

The aim of this task is to create a python package that implements automatic convergence tracking mechanism for a materials simulations engine. The convergence is tracked with respect to the k-point sampling inside a reciprocal cell of a crystalline compound.

# Requirements

1. automatically find the dimensions of a k-point mesh that satisfy a certain criteria for total energy (eg. total energy is converged within dE = 0.01meV)
1. the code shall be written in a way that can facilitate easy addition of convergence wrt other characteristics extracted from simulations (forces, pressures, phonon frequencies etc)
1. the code shall support VASP or Quantum ESPRESSO

# Expectations

- correctly find k-point mesh that satisfies total energy convergence parameters for a set of 10 materials, starting from Si2, as simplest, to a 10-20-atom supercell of your choice
- modular and object-oriented implementation
- commit early and often - at least once per 24 hours

# Timeline

We leave exact timing to the candidate. Must fit Within 5 days total.

# User story

As a user of this software I can start it passing:

- path to input data (eg. pw.in / POSCAR, INCAR, KPOINTS) and
- kinetic energy cutoff

as parameters and get the k-point dimensions (eg. 5 5 5).

# Notes

- create an account at exabyte.io and use it for the calculation purposes
- suggested modeling engine: Quantum ESPRESSO
132 changes: 132 additions & 0 deletions xyttyxy/calculation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
from abc import ABC, abstractmethod
from utils import graceful_exit, ConvergenceProperty, messages
from copy import deepcopy as dcopy
import os
import logging


class Calculation(ABC):
@abstractmethod
def __init__(self, name, convergence_property, atoms, path, **kwargs):
self.convergence_property = convergence_property
self.atoms = atoms.copy()
self.path = path
self.name = name

if "logger" in kwargs.keys():
self.logger = kwargs["logger"]
else:
self.logger = logging.getLogger("Calculation") # level defaults to warning

@property
def raw_value(self):
if self.convergence_property == ConvergenceProperty.etotal:
return self.etotal
elif self.convergence_property == ConvergenceProperty.force:
raise NotImplementedError

@property
@abstractmethod
def etotal(self):
pass

@property
@abstractmethod
def kpoints(self):
pass

@kpoints.setter
@abstractmethod
def kpoints(self, kpts):
pass

@abstractmethod
def run(self):
pass


class VaspCalculation(Calculation):
def __init__(
self, name, convergence_property, atoms, path=None, calculator=None, **kwargs
):
Calculation.__init__(self, name, convergence_property, atoms, path, **kwargs)
from ase.calculators.vasp import Vasp

if path:
_calculator = Vasp()
try:
_calculator.read_incar(filename=os.path.join(self.path, "INCAR"))
except FileNotFoundError:
self.logger.warning(messages("no_incar").format("INCAR", self.path))
try:
files = [
f
for f in os.listdir(self.path)
if ".incar" in f and os.path.isfile(os.path.join(self.path, f))
]
assert isinstance(files, list), "BUG 1"

if len(files) == 0:
self.logger.warning(
messages("no_incar").format(".incar", self.path)
)
raise FileNotFoundError
elif len(files) > 1:
self.logger.warning(messages("multiple_incar").format(".incar"))
fname = files[0]
else:
fname = files[0]

_calculator.read_incar(filename=os.path.join(self.path, fname))

except FileNotFoundError:
self.logger.error(messages("no_incar_final"))
graceful_exit()

elif calculator:
_calculator = dcopy(calculator)
else:
self.logger.error(messages("no_calculation_input"))
graceful_exit()

_calculator.set(directory=name)
self._calculator = _calculator
self.atoms.calc = _calculator
self.calculation_required = True

@property
def kpoints(self):
return self._calculator.kpts

def no_tetrahedron_smearing(self):
ismear = self._calculator.int_params["ismear"]
if ismear == -5:
self._calculator.set(ismear=0, sigma=0.02)

def set_to_singlepoint(self):
ibrion = self._calculator.int_params["ibrion"]
nsw = self._calculator.int_params["nsw"]
if ibrion != -1 and nsw != 0:
self.logger.warning(messages("set_to_singlepoint"))
self._calculator.set(ibrion=-1, nsw=0)

def no_kspacing(self):
kspacing = self._calculator.float_params["kspacing"]
if kspacing:
self.logger.warning(messages("ignore_kspacing"))
self._calculator.set(kspacing=None)

@property
def etotal(self):
# if self._calculator.calculation_required(self.atoms, ["energy"]):
if self.calculation_required:
raise Exception(messages("no_etotal"))
return self.atoms.get_potential_energy()

@kpoints.setter
def kpoints(self, kpts):
self._calculator.set(kpts=kpts)

def run(self):
self.atoms.get_potential_energy()
self.calculation_required = False
93 changes: 93 additions & 0 deletions xyttyxy/classes.plantuml
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
@startuml classes
skinparam dpi 100
set namespaceSeparator none
class "Calculation" as xyttyxy.calculation.Calculation {
atoms
convergence_property
etotal
kpoints
logger : NoneType, RootLogger, Logger
name
path
raw_value
run()
}
class "ConvergenceParameter" as xyttyxy.utils.ConvergenceParameter {
name
}
class "ConvergenceProperty" as xyttyxy.utils.ConvergenceProperty {
name
}
class "ConvergenceTracker" as xyttyxy.convergence_tracker.ConvergenceTracker {
atoms
converged_calc
convergence_property
eps : float
error_metric
logger : RootLogger
package
path
reference_calculation
workdir
read_input()
read_structure()
run_calcs()
setup_calcs()
show_results()
}
class "ErrorMetric" as xyttyxy.error_metric.ErrorMetric {
error
fractional : bool
}
class "ErrorMetricMatrix" as xyttyxy.error_metric.ErrorMetricMatrix {
error(calc_0, calc_1)
}
class "ErrorMetricScalar" as xyttyxy.error_metric.ErrorMetricScalar {
error(calc_0, calc_1)
}
class "ErrorMetricVector" as xyttyxy.error_metric.ErrorMetricVector {
error(calc_0, calc_1)
}
class "KpointConvergenceTracker" as xyttyxy.convergence_tracker.KpointConvergenceTracker {
calculations : list
converged_kpoints : list
kpoint_series : list
max_ka
min_ka
num_ka
find_kpoint_series()
read_input()
run_calcs()
setup_calcs()
show_results()
}
class "PeriodicDftPackages" as xyttyxy.utils.PeriodicDftPackages {
name
}
class "PwCutoffConvergenceTracker" as xyttyxy.convergence_tracker.PwCutoffConvergenceTracker {
}
class "VaspCalculation" as xyttyxy.calculation.VaspCalculation {
calculation_required : bool
etotal
kpoints
no_kspacing()
no_tetrahedron_smearing()
run()
set_to_singlepoint()
}
xyttyxy.calculation.VaspCalculation --|> xyttyxy.calculation.Calculation
xyttyxy.convergence_tracker.KpointConvergenceTracker --|> xyttyxy.convergence_tracker.ConvergenceTracker
xyttyxy.convergence_tracker.PwCutoffConvergenceTracker --|> xyttyxy.convergence_tracker.ConvergenceTracker
xyttyxy.error_metric.ErrorMetricMatrix --|> xyttyxy.error_metric.ErrorMetric
xyttyxy.error_metric.ErrorMetricScalar --|> xyttyxy.error_metric.ErrorMetric
xyttyxy.error_metric.ErrorMetricVector --|> xyttyxy.error_metric.ErrorMetric
' manual edits
class "Enum" as python.enum {
error
}
xyttyxy.utils.ConvergenceParameter --|> python.enum
xyttyxy.utils.ConvergenceProperty --|> python.enum
xyttyxy.utils.PeriodicDftPackages --|> python.enum
xyttyxy.calculation.VaspCalculation --* xyttyxy.convergence_tracker.KpointConvergenceTracker
xyttyxy.error_metric.ErrorMetricScalar --* xyttyxy.convergence_tracker.KpointConvergenceTracker
@enduml
Binary file added xyttyxy/classes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading