-
Notifications
You must be signed in to change notification settings - Fork 111
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
Changes from 6 commits
d034852
81a5326
4f225f8
0e3fae8
9965138
42fd9c5
36232c2
0496b86
9e3bdcb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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. | ||
""" | ||
|
||
__author__ = "Janine George, Guido Petretto" | ||
__version__ = "0.1" | ||
__maintainer__ = "Janine George, Guido Petretto" | ||
__email__ = "[email protected]" | ||
__status__ = "Production" | ||
__date__ = "30/3/20" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import os | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There needs to be a module doc. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import logging | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Module doc. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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") |
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() |
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() |
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 |
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 |
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... | ||
|
||
|
||
|
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
okay