Source code for htesp.write_potcar

#!/usr/bin/env python
# coding: utf-8
# Written by Niraj K. Nepal, Ph.D.
"""
Writing POTCAR file from POSCAR.

FIX(23): every third-party import in this module (``pymatgen``) is a core
dependency of the package, so nothing needs deferring here; the module is
imported by eight other modules and must stay cheap.
"""
import os
from pymatgen.core import structure
from pymatgen.io.vasp.sets import Potcar
from htesp.check_json import config
[docs] def poscar2potcar(poscar="POSCAR", outfile="POTCAR"): """ Function to generate the POTCAR file based on the element potentials provided in config.json file. If config.json file is present in the current directory or its parent directory, the function retrieves the potential dictionary from the 'pseudo' key in the config.json file. If the config.json file is not found, a message indicating the absence of the 'pseudo' keyword is displayed. The function reads the POSCAR file to determine the elements present in the structure and generates the corresponding POTCAR file based on the potential dictionary. """ input_data = config() # check_json.config() always returns a populated dict now, so the guard # that used to leave ``pot1`` unbound (and raise NameError one line later) # is gone; a configuration without a 'pseudo' section is reported instead. try: pot2 = input_data['pseudo']['pot'] except (KeyError, TypeError) as exc: raise KeyError( "config.json has no 'pseudo'.'pot' mapping, so no POTCAR can be " "assembled") from exc struc = structure.Structure.from_file(poscar) element_list = [] for elm in struc.composition.elements: try: element_list.append(pot2[str(elm)]) except KeyError as exc: raise KeyError( "no pseudo.pot entry for element {!r} in config.json".format( str(elm))) from exc potcar = Potcar(element_list) potcar.write_file(outfile)
[docs] def ensure_potcar(directory=".", poscar="POSCAR", outfile="POTCAR"): """Make sure ``directory`` has a POTCAR, building one from its POSCAR. FIX(38): POTCARs are licensed, so ``examples/`` cannot ship them -- the reference ``R<mpid>-<compound>/relax/`` directories contain INCAR, KPOINTS and POSCAR but no POTCAR. Anything that stages those four files into a working directory (``mainprogram convtest`` most visibly) then died with ``FileNotFoundError: 'R<...>/relax/POTCAR'`` even though HTESP can build one itself from the POSCAR and ``pseudo.pot``. Does nothing when a POTCAR is already there. Returns True when one exists afterwards, False when it could not be produced (no POSCAR, or pymatgen has no PMG_VASP_PSP_DIR -- the caller decides whether that is fatal). """ directory = os.fspath(directory) target = os.path.join(directory, outfile) if os.path.isfile(target): return True source = os.path.join(directory, poscar) if not os.path.isfile(source): return False previous = os.getcwd() try: os.chdir(directory) poscar2potcar(poscar=poscar, outfile=outfile) except Exception as exc: # noqa: BLE001 - caller decides print("could not build {} from {}: {}: {}".format( target, source, type(exc).__name__, exc)) return False finally: os.chdir(previous) return os.path.isfile(target)
#: printed once per run when a POTCAR is missing and cannot be built POTCAR_HELP = ( "VASP POTCARs are licensed, so HTESP cannot ship them and the reference\n" " R<mpid>-<compound>/relax/ directories contain INCAR, KPOINTS and POSCAR\n" " only. To have HTESP build them from your own set:\n" " htesp-check --config_vasp_pot /path/to/POT_GGA_PAW_PBE\n" " (a raw VASP distribution needs pymatgen's reorganisation first:\n" " pmg config -p /path/to/POT_GGA_PAW_PBE ~/PBE52\n" " pmg config --add PMG_VASP_PSP_DIR ~/PBE52)\n" " (give either that directory or its parent). Until then the inputs are\n" " written without a POTCAR and VASP will not run on them." ) _POTCAR_HELP_SHOWN = False
[docs] def stage_potcar(relax_dir, work_dir=None): """Put a POTCAR in ``relax_dir`` if one can be had; never fail if not. FIX(40): a missing POTCAR is not an error. It cannot be shipped, it is not always configurable (a machine may simply have no VASP licence), and the rest of the input generation is still useful without it -- so this reports what to do and lets the caller carry on rather than aborting the scan. Returns True when ``relax_dir/POTCAR`` exists afterwards. The explanatory message is printed at most once per process, so a 60-material scan does not repeat it 60 times. """ global _POTCAR_HELP_SHOWN if ensure_potcar(relax_dir): return True print("no POTCAR in {}".format(relax_dir)) if not _POTCAR_HELP_SHOWN: print(" " + POTCAR_HELP) _POTCAR_HELP_SHOWN = True return False