Skip to content
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

Caffeinate #13

Merged
merged 25 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7a0d965
initial commit for caffeinate sub-module
ebanyas Aug 6, 2024
522e8bb
support for gamma-centered, M-P, and line-mode KPOINTS objects
ebanyas Aug 15, 2024
43aa519
resolved KPointsCard import and return blocks
ebanyas Aug 16, 2024
c2b6c89
Renamed module, added (some) error messages and warnings
ebanyas Aug 16, 2024
54eaabd
removed old module file
ebanyas Aug 16, 2024
d1228e4
minor updates; pushing latest version for debugging explicit grid
ebanyas Aug 16, 2024
a6f3ddf
Fixed explicit grid issue
ebanyas Aug 17, 2024
6c173f6
_caffeinate_kpoints is fully functional (famous last words)
ebanyas Aug 17, 2024
5a7c0b7
another module rename
ebanyas Aug 17, 2024
33e9713
fixed bug in gamma-point only explicit grids
ebanyas Aug 17, 2024
8556161
fixed tetrahedra warning error
ebanyas Aug 17, 2024
ca16483
added caffeination support for POSCAR files
ebanyas Aug 20, 2024
3c11dd2
cleaning up Poscar implementation
ebanyas Aug 20, 2024
8d4160c
reverting unintended pwin changes
ebanyas Aug 20, 2024
e45ffae
created sub-functions for k-point caffeination
ebanyas Aug 20, 2024
05bb85c
fixed poscar bug
ebanyas Aug 20, 2024
49fa739
Didn't really fix the ibrav check
ebanyas Aug 20, 2024
73dc5b7
updated ibrav kwarg handling
ebanyas Aug 20, 2024
5f6c996
removed superfluous ibrav type-checking
ebanyas Aug 20, 2024
2061996
added custom warning class for tpiba conversion (for later filtering …
ebanyas Aug 21, 2024
874ce94
changed return logic for k-point converters
ebanyas Aug 21, 2024
50fe91b
removed useless Angstrom comment
ebanyas Aug 21, 2024
5b5f529
fixed species bug
ebanyas Aug 21, 2024
f052358
updated line_mode conversion
ebanyas Aug 21, 2024
89f67f1
Final reformat and lint
oashour Aug 21, 2024
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
275 changes: 275 additions & 0 deletions pymatgen/io/espresso/caffeinator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
"""
Convert VASP inputs to PWSCF inputs.

Supported VASP inputs:
KPOINTS*
POSCAR
Not (yet) supported:
INCAR
KPOINTS: generalized regular grids or
fully automatic (KSPACING) grids
"""

# TODO: imports need linting!
# TODO: Gamma vs. M-P conversion should be tested with an actual VASP/QE comp.
# TODO: Stylistic updates

# TODO: Commented imports reserved for future updates.
#from __future__ import annotations

import warnings

import numpy as np

from pymatgen.core.structure import Structure
#from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
from pymatgen.io.vasp.inputs import (
Kpoints,
Poscar,
)

#from pymatgen.io.espresso import utils
from pymatgen.io.espresso.inputs.pwin import (
KPointsCard,
AtomicSpeciesCard,
AtomicPositionsCard,
CellParametersCard,
SystemNamelist,
PWin,
)


"""
Module-level functions for converting pmg's VASP input file objects
to PWin-compatible cards and namelists.

caffeinate(vasp_in) returns: [relevant namelists], [relevant cards]
"""
def caffeinate(vasp_in, **kwargs):
if isinstance(vasp_in, Kpoints):
return _caffeinate_kpoints(vasp_in)
elif isinstance(vasp_in, Poscar):
return _caffeinate_poscar(vasp_in,
ibrav = kwargs.get("ibrav", False)
)
else:
raise CaffeinationError(
"Input file type not recognized (or not yet supported)"
)

def _caffeinate_kpoints(kpoints):
"""
Convert a Kpoints object to a KPointsCard object.

NOTE: Cartesian coordinates are preserved in their original form, i.e.
in units of 2*pi/a where a is defined in an accompanying Poscar object.
"""
oashour marked this conversation as resolved.
Show resolved Hide resolved
if kpoints.style.name in ["Gamma","Monkhorst"]:
option, grid, shift, k, weights, labels = _convert_grid_k(kpoints)

elif kpoints.style.name == "Line_mode":
option, grid, shift, k, weights, labels = _convert_linemode_k(kpoints)

elif (
kpoints.style.name in ["Reciprocal","Cartesian"] and
kpoints.num_kpts > 0
):
option, grid, shift, k, weights, labels = _convert_explicit_k(kpoints)

else:
raise CaffeinationError(
("\nConversion of generalized regular grids or fully-automatic "
"grids is not currently implemented. "
"Please use one of the following KPOINTS file types:\n"
" - Gamma-centered\n"
" - Monkhorst-Pack\n"
" - Explicit mesh\n"
" - Line-mode")
)

if "tpiba" in str(option):
# TODO: This warning can be ignored if a Poscar object is provided.
# Need to add filtering in the Caffeinator methods.
warnings.warn(
(
"\nWarning: VASP's cartesian coordinates cannot be fully "
"converted to tpiba coordinates without an accompanying "
"POSCAR file! Use the following k-points at your own risk."),
CaffeinationWarning)
#TODO: Make warning pretty

#TODO: Return logic
#come back to this post-Caffeinator
return KPointsCard(
ebanyas marked this conversation as resolved.
Show resolved Hide resolved
option = option,
grid = grid,
shift = shift,
k = k,
weights = weights,
labels = labels)

def _convert_grid_k(kpoints):
if (
all(int(x) == 1 for x in kpoints.kpts[0]) and
all(x == 0.0 for x in kpoints.kpts_shift)
):
opt_str = "gamma"
ebanyas marked this conversation as resolved.
Show resolved Hide resolved
else:
opt_str = "automatic"
option = KPointsCard.opts.from_string(opt_str)
shift = [bool(x) for x in kpoints.kpts_shift]
grid = []
for i, x in enumerate(list(kpoints.kpts[0])):
grid.append(int(x))
if kpoints.style.name == "Gamma" and not x % 2:
shift[i] = not shift[i]
# TODO: Gamma-to-MP conversion needs testing!
k = []
weights = []
labels = []
return option, grid, shift, k, weights, labels

def _convert_linemode_k(kpoints):
if kpoints.coord_type.lower()[0] == "r":
opt_str = "crystal_b"
else:
opt_str = "tpiba_b"
k = [list(kpoints.kpts[0])]
labels = [kpoints.labels[0]]
weights = [kpoints.num_kpts]
for i in range(1,len(kpoints.labels)):
ebanyas marked this conversation as resolved.
Show resolved Hide resolved
if kpoints.labels[i] == kpoints.labels[i - 1]:
pass
ebanyas marked this conversation as resolved.
Show resolved Hide resolved
elif not i % 2:
labels.append(kpoints.labels[i])
weights[-1] = 1
ebanyas marked this conversation as resolved.
Show resolved Hide resolved
weights.append(kpoints.num_kpts)
k.append(list(kpoints.kpts[i]))
else:
labels.append(kpoints.labels[i])
weights.append(kpoints.num_kpts)
k.append(list(kpoints.kpts[i]))
weights[-1] = 1
option = KPointsCard.opts.from_string(opt_str)
grid = []
shift = []
return option, grid, shift, k, weights, labels

def _convert_explicit_k(kpoints):
if kpoints.num_kpts == 1 and all(int(x) == 0 for x in kpoints.kpts[0]):
opt_str = "gamma"
ebanyas marked this conversation as resolved.
Show resolved Hide resolved
elif kpoints.style.name == "Cartesian":
opt_str = "tpiba"
else:
opt_str = "crystal"
option = KPointsCard.opts.from_string(opt_str)
k = []
ebanyas marked this conversation as resolved.
Show resolved Hide resolved
labels = []
for x in kpoints.kpts:
k.append(list(x))
labels.append("")
weights = kpoints.kpts_weights
grid = []
shift = []
if kpoints.tet_number != 0:
warnings.warn(
("\nWarning: explicit tetrahedra are not compatible "
"with PWscf and will not be preserved in the kpoints "
"card."),
CaffeinationWarning)
#TODO: Make warning pretty
#TODO:
# Caffeinator can swap out the occupations tag for something else
# reasonable.
# Define a unique warning category so that the two k-point warnings
# defined in this module can be easily filtered?
return option, grid, shift, k, weights, labels

def _caffeinate_poscar(poscar, **kwargs):
"""
Convert a Poscar object to the following objects:
- AtomicPositionsCard
- AtomicSpeciesCard
- CellParametersCard
- Partially-initialized System namelist

Keyword arguments:
- ibrav: bool | False
If set to True, choose the appropriate ibrav != 0
"""

#TODO: clean this up
# this is even more convoluted than before
if ibrav in [False, "False", "false", "F", "f"]:
ibrav = False
elif ibrav in [True, "True", "true", "T", "t"]:
ibrav = True
else:
warnings.warn(
(
"Warning: keyword 'ibrav' is not parsable as a boolean! "
"The ibrav setting will not be used (i.e. 'ibrav = 0').",
CaffeinationWarning)
)
ibrav = False

struct = poscar.structure

system = SystemNamelist(
{"nat":len(struct.species),
"ntyp":len(struct.species)})
species = set(struct.species)

lattice = struct.lattice
#TODO: Check that lattices are always in Angstrom! (They probably are)
ebanyas marked this conversation as resolved.
Show resolved Hide resolved

if not ibrav:
system["ibrav"] = 0
else:
raise CaffeinationError(
"ibrav != 0 is not yet supported"
)
#TODO: Add lattice_to_ibrav to utils.py!
#NOT YET IMPLEMENTED

atomic_species = AtomicSpeciesCard(
None,
[str(s) for s in species],
[s.atomic_mass for s in species],
[f"{s}.upf" for s in species],
)

atomic_positions = AtomicPositionsCard(
AtomicPositionsCard.opts.crystal,
[str(s) for s in struct.species],
struct.frac_coords,
None,
)

cell_params = CellParametersCard(
CellParametersCard.opts.angstrom,
lattice.matrix[0],
lattice.matrix[1],
lattice.matrix[2],
)

#TODO: Return logic
#come back to this post-Caffeinator
return system, atomic_species, atomic_positions, cell_params


#class Caffeinator:
# """
# Class for converting VASP input sets to pwin objects.
# """
# TODO: All of this

class CaffeinationError(Exception):
"""
Exception class for caffeination
"""

class CaffeinationWarning(Warning):
"""
Warning class for caffeination
"""
2 changes: 1 addition & 1 deletion pymatgen/io/espresso/inputs/pwin.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ def get_body(self, indent):

@classmethod
def from_string(cls, s: str):
"""Parse a string containing an ATOMIC_SPECIES card"""
"""Parse a string containing K_POINTS card"""
option, body = cls.split_card_string(s)
grid, shift, k, weights, labels = [], [], [], [], []
if option == cls.opts.automatic:
Expand Down
Loading