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

Validators and Jobs for Lobster #152

Merged
merged 9 commits into from
Apr 27, 2020
Merged
Show file tree
Hide file tree
Changes from 6 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
12 changes: 12 additions & 0 deletions custodian/lobster/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from __future__ import unicode_literals

"""
This package implements various VASP Jobs and Error Handlers.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change this doc to say lobster?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay

"""

__author__ = "Janine George, Guido Petretto"
__version__ = "0.1"
__maintainer__ = "Janine George, Guido Petretto"
__email__ = "[email protected]"
__status__ = "Production"
__date__ = "30/3/20"
82 changes: 82 additions & 0 deletions custodian/lobster/handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import os
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There needs to be a module doc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay


from custodian.custodian import Validator
from pymatgen.io.lobster import Lobsterout


class EnoughBandsValidator(Validator):
"""
validates if enough bands for COHP calculation are available
"""

def __init__(self, output_filename: str = "lobsterout"):
"""

Args:
output_filename: filename of output file, usually lobsterout
"""
self.output_filename = output_filename

def check(self) -> bool:
"""
checks if the VASP calculation had enough bands
Returns:
(bool) if True, too few bands have been applied
"""
# checks if correct number of bands is available
try:
with open(self.output_filename) as f:
data = f.read()
return 'You are employing too few bands in your PAW calculation.' in data
except OSError:
return False


class LobsterFilesValidator(Validator):
"""
Check for existence of some of the files that lobster
normally create upon running.
Check if lobster terminated normally by looking for finished
"""

def __init__(self):
pass

def check(self) -> bool:
for vfile in ["lobsterout"]:
if not os.path.exists(vfile):
return True
with open("lobsterout") as f:
data = f.read()
return ('finished' not in data)


class ChargeSpillingValidator(Validator):
"""
Check if spilling is below certain threshold!
"""

def __init__(self, output_filename: str = 'lobsterout', charge_spilling_limit: float = 0.05):
"""

Args:
output_filename: filename of the output file of lobter, usually lobsterout
charge_spilling_limit: limit of the charge spilling that will be considered okay
"""

self.output_filename = output_filename
self.charge_spilling_limit = charge_spilling_limit

def check(self) -> bool:
# open lobsterout and find charge spilling

if os.path.exists(self.output_filename):
lobsterout = Lobsterout(self.output_filename)
if lobsterout.chargespilling[0] > self.charge_spilling_limit:
return True
if len(lobsterout.chargespilling) > 1:
if lobsterout.chargespilling[1] > self.charge_spilling_limit:
return True
return False
else:
return False
81 changes: 81 additions & 0 deletions custodian/lobster/jobs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import logging
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Module doc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay

import os
import shutil
import subprocess

from monty.io import zopen
from monty.shutil import compress_file

from custodian.custodian import Job

LOBSTERINPUT_FILES = ["lobsterin"]
LOBSTEROUTPUT_FILES = ["lobsterout", "CHARGE.lobster", "COHPCAR.lobster", "COOPCAR.lobster", "DOSCAR.lobster",
"GROSSPOP.lobster", "ICOHPLIST.lobster", "ICOOPLIST.lobster", "lobster.out",
"projectionData.lobster"]

logger = logging.getLogger(__name__)


class LobsterJob(Job):
"""
Runs the Lobster Job
"""

def __init__(self, lobster_cmd: str, output_file: str = "lobsterout", stderr_file: str = "std_err_lobster.txt",
gzipped: bool = True, add_files_to_gzip=[], backup: bool = True):
"""

Args:
lobster_cmd: command to run lobster
output_file: usually lobsterout
stderr_file: standard output
gzipped: if True, Lobster files and add_files_to_gzip will be gzipped
add_files_to_gzip: list of files that should be gzipped
backup: if True, lobsterin will be copied to lobsterin.orig
"""
self.lobster_cmd = lobster_cmd
self.output_file = output_file
self.stderr_file = stderr_file
self.gzipped = gzipped
self.add_files_to_gzip = add_files_to_gzip
self.backup = backup

def setup(self):
"""
will backup lobster input files
"""
if self.backup:
for f in LOBSTERINPUT_FILES:
shutil.copy(f, "{}.orig".format(f))

def run(self):
"""
runs the job
"""
cmd = self.lobster_cmd

logger.info("Running {}".format(" ".join(cmd)))

with zopen(self.output_file, 'w') as f_std, \
zopen(self.stderr_file, "w", buffering=1) as f_err:
# use line buffering for stderr
p = subprocess.Popen(cmd, stdout=f_std, stderr=f_err)

return p

def postprocess(self):
"""
will gzip relevant files (won't gzip custodian.json and other output files from the cluster)
"""
if self.gzipped:
for file in LOBSTEROUTPUT_FILES:
if os.path.exists(file):
compress_file(file, compression="gz")
for file in LOBSTERINPUT_FILES:
if os.path.exists(file):
compress_file(file, compression="gz")
if self.backup:
if os.path.exists("lobsterin.orig"):
compress_file("lobsterin.orig", compression="gz")
for file in self.add_files_to_gzip:
compress_file(file, compression="gz")
Empty file.
83 changes: 83 additions & 0 deletions custodian/lobster/tests/test_handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import os
import unittest

from custodian.lobster.handlers import ChargeSpillingValidator, EnoughBandsValidator, LobsterFilesValidator

# get location of module
TEST_DIR = os.path.dirname(os.path.abspath(__file__))
test_files_lobster = os.path.join(TEST_DIR, '../../../test_files/lobster/lobsterouts')


class TestChargeSpillingValidator(unittest.TestCase):

def test_check_and_correct(self):
v = ChargeSpillingValidator(output_filename=os.path.join(test_files_lobster, "lobsterout.normal"))
self.assertFalse(v.check())

v2 = ChargeSpillingValidator(output_filename=os.path.join(test_files_lobster, "lobsterout.largespilling"))
self.assertTrue(v2.check())

v2b = ChargeSpillingValidator(output_filename=os.path.join(test_files_lobster, "lobsterout.largespilling_2"))
self.assertTrue(v2b.check())

v3 = ChargeSpillingValidator(output_filename=os.path.join(test_files_lobster, "nolobsterout", "lobsterout"))
self.assertFalse(v3.check())

v4 = ChargeSpillingValidator(output_filename=os.path.join(test_files_lobster, "no_spin", "lobsterout"))
self.assertFalse(v4.check())

def test_as_dict(self):
v = ChargeSpillingValidator(output_filename=os.path.join(test_files_lobster, "lobsterout.normal"))
d = v.as_dict()
v2 = ChargeSpillingValidator.from_dict(d)
self.assertIsInstance(v2, ChargeSpillingValidator)


class TestLobsterFilesValidator(unittest.TestCase):

def test_check_and_correct_1(self):
os.chdir(test_files_lobster)
v = LobsterFilesValidator()
self.assertFalse(v.check())

def test_check_and_correct_2(self):
os.chdir(os.path.join(test_files_lobster, "nolobsterout"))
v2 = LobsterFilesValidator()
self.assertTrue(v2.check())

def test_check_and_correct_3(self):
os.chdir(os.path.join(test_files_lobster, "crash"))
v3 = LobsterFilesValidator()
self.assertTrue(v3.check())

def test_as_dict(self):
os.chdir(test_files_lobster)
v = LobsterFilesValidator()
d = v.as_dict()
v2 = LobsterFilesValidator.from_dict(d)
self.assertIsInstance(v2, LobsterFilesValidator)


class TestEnoughBandsValidator(unittest.TestCase):

def test_check_and_correct(self):
v = EnoughBandsValidator(output_filename=os.path.join(test_files_lobster, "lobsterout.normal"))
self.assertFalse(v.check())

def test_check_and_correct2(self):
v2 = EnoughBandsValidator(output_filename=os.path.join(test_files_lobster, "lobsterout.nocohp"))
self.assertTrue(v2.check())

def test_check_and_correct3(self):
v3 = EnoughBandsValidator(output_filename=os.path.join(test_files_lobster, "nolobsterout/lobsterout"))
self.assertFalse(v3.check())

def test_as_dict(self):
v = EnoughBandsValidator(output_filename=os.path.join(test_files_lobster, "lobsterout.normal"))
d = v.as_dict()
v2 = EnoughBandsValidator.from_dict(d)
self.assertIsInstance(v2, EnoughBandsValidator)


if __name__ == '__main__':
unittest.main()
67 changes: 67 additions & 0 deletions custodian/lobster/tests/test_jobs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import os
import shutil
import unittest

from custodian.lobster.jobs import LobsterJob
from monty.os import cd
from monty.tempfile import ScratchDir

MODULE_DIR = os.path.dirname(os.path.abspath(__file__))
test_files_lobster2 = os.path.join(MODULE_DIR, '../../../test_files/lobster/lobsterins')
test_files_lobster3 = os.path.join(MODULE_DIR, '../../../test_files/lobster/vasp_lobster_output')

VASP_OUTPUT_FILES = ["OUTCAR", "vasprun.xml", "CHG", "CHGCAR", "CONTCAR", "INCAR", "KPOINTS", "POSCAR", "POTCAR",
"DOSCAR", "EIGENVAL", "IBZKPT", "OSZICAR", "PCDAT", "PROCAR", "REPORT", "WAVECAR", "XDATCAR"]


class LobsterJobTest(unittest.TestCase):
"""
similar to VaspJobTest
ommit test of run
"""

def test_to_from_dict(self):
v = LobsterJob(lobster_cmd="hello")
v2 = LobsterJob.from_dict(v.as_dict())
self.assertEqual(type(v2), type(v))
self.assertEqual(v2.lobster_cmd, "hello")

def test_setup(self):
with cd(test_files_lobster2):
with ScratchDir('.', copy_from_current_on_enter=True) as d:
# check if backup is done correctly
v = LobsterJob("hello", backup=True)
v.setup()
self.assertTrue(os.path.exists("lobsterin.orig"))
# check if backup id done correctly
with ScratchDir('.', copy_from_current_on_enter=True) as d:
v = LobsterJob("hello", backup=False)
v.setup()
self.assertFalse(os.path.exists("lobsterin.orig"))

def test_postprocess(self):
# test gzipped and zipping of additional files
with cd(os.path.join(test_files_lobster3)):
with ScratchDir('.', copy_from_current_on_enter=True) as d:
shutil.copy('lobsterin', 'lobsterin.orig')
v = LobsterJob("hello", gzipped=True, add_files_to_gzip=VASP_OUTPUT_FILES)
v.postprocess()
self.assertTrue(os.path.exists("WAVECAR.gz"))
self.assertTrue(os.path.exists("lobsterin.gz"))
self.assertTrue(os.path.exists("lobsterout.gz"))
self.assertTrue(os.path.exists("INCAR.gz"))
self.assertTrue(os.path.exists("lobsterin.orig.gz"))

with ScratchDir('.', copy_from_current_on_enter=True) as d:
shutil.copy('lobsterin', 'lobsterin.orig')
v = LobsterJob("hello", gzipped=False, add_files_to_gzip=VASP_OUTPUT_FILES)
v.postprocess()
self.assertTrue(os.path.exists("WAVECAR"))
self.assertTrue(os.path.exists("lobsterin"))
self.assertTrue(os.path.exists("lobsterout"))
self.assertTrue(os.path.exists("INCAR"))
self.assertTrue(os.path.exists("lobsterin.orig"))


if __name__ == '__main__':
unittest.main()
9 changes: 9 additions & 0 deletions test_files/lobster/lobsterins/lobsterin
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
COHPstartEnergy -15.0
COHPendEnergy 5.0
basisSet pbeVaspFit2015
cohpGenerator from 0.1 to 6.0 orbitalwise
gaussianSmearingWidth 0.05
saveProjectionToFile
basisfunctions K 3p 3s 4s
basisfunctions Sn 4d 5p 5s
basisfunctions O 2p 2s
9 changes: 9 additions & 0 deletions test_files/lobster/lobsterins/lobsterin2
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
COHPstartEnergy -15.0
COHPendEnergy 10.0
basisSet pbeVaspFit2015
cohpGenerator from 0.1 to 6.0 orbitalwise
gaussianSmearingWidth 0.05
saveProjectionToFile
basisfunctions K 3p 3s 4s
basisfunctions Sn 4d 5p 5s
basisfunctions O 2p 2s
42 changes: 42 additions & 0 deletions test_files/lobster/lobsterouts/crash/lobsterout
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
LOBSTER v3.2.0 (g++ 5.4.0)
Copyright (C) 2019 by Chair of Solid-State and Quantum Chemistry, RWTH Aachen.
All rights reserved. Contributions by S. Maintz, V. L. Deringer, M. Esser, R. Nelson, C. Ertural, A. L. Tchougreeff and R. Dronskowski
starting on host mb-ivy205.cism.ucl.ac.be on 2019-10-08 at 20:25:15 CEST using 8 threads
detecting used PAW program... VASP
initializing PW system...
initializing Augmentations...
recommended basis functions:
K 3p 3s 4s
O 2p 2s
Sn 4d 5p 5s
initializing LCAO system...
setting up local basis functions...
K (pbeVaspFit2015) 3s 4s 3p_y 3p_z 3p_x
O (pbeVaspFit2015) 2s 2p_y 2p_z 2p_x
Sn (pbeVaspFit2015) 5s 5p_y 5p_z 5p_x 4d_xy 4d_yz 4d_z^2 4d_xz 4d_x^2-y^2
setting up CO interactions... found 520 interactions.
projecting...
WARNING: Cannot use the tetrahedron method for k-space integration and must fall
WARNING: back to Gaussian smearing which can take significantly longer. Make
WARNING: sure to use the tetrahedron method whenever applicable.

calculating overlaps...
post-processing projection...
saving projection to projectionData.lobster...
spillings for spin channel 1
abs. total spilling: 6.31%
abs. charge spilling: 0.80%

spillings for spin channel 2
abs. total spilling: 6.33%
abs. charge spilling: 0.80%

calculating pDOS... using Gaussian smearing integration (sigma=0.05eV)
writing DOSCAR.lobster...
writing COOPCAR.lobster and ICOOPLIST.lobster...
calculating pCOHPs... using Gaussian smearing integration (sigma=0.05eV)
writing COHPCAR.lobster and ICOHPLIST.lobster...
writing CHARGE.lobster and GROSSPOP.lobster...



Loading