Skip to content

Commit 1e95421

Browse files
authored
Merge pull request #76 from WardLT/multiple_outcars
Added ability to filter which files a parser can read
2 parents 82f3f6c + 0a2a2ef commit 1e95421

File tree

10 files changed

+162
-128
lines changed

10 files changed

+162
-128
lines changed

dfttopif/drivers.py

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,17 @@
99
import json
1010

1111

12-
def _add_quality_report(directory, pif, inline=True):
12+
def _add_quality_report(parser, pif, inline=True):
1313
import tarfile
1414

15-
# Use VaspParser to identify OUTCAR and POSCAR files
16-
parser = VaspParser(directory)
17-
18-
# If we do not have an INCAR, we cannot run the quality report
15+
# if the parser lacks an INCAR, return None
1916
if parser.incar is None:
20-
print("Unable to generate quality report; directory lacks an INCAR file")
21-
return
17+
return None
2218

2319
# Create the tar file
2420
tar = tarfile.open("tmp.tar", "w")
25-
tar.add(os.path.join(directory, "OUTCAR"))
26-
tar.add(os.path.join(directory, "INCAR"))
21+
tar.add(parser.outcar, arcname="OUTCAR")
22+
tar.add(parser.incar, arcname="INCAR")
2723
tar.close()
2824

2925
import requests
@@ -44,7 +40,7 @@ def _add_quality_report(directory, pif, inline=True):
4440
if inline:
4541
setattr(pif, "quality_report", report)
4642
else:
47-
report_file = os.path.join(directory, "quality_report.txt")
43+
report_file = os.path.join(os.path.dirname(parser.outcar), "quality_report.txt")
4844
with open(report_file, "w") as f:
4945
f.write(report)
5046
if report_file[0:2] == "./":
@@ -59,6 +55,7 @@ def _add_quality_report(directory, pif, inline=True):
5955

6056
return pif
6157

58+
6259
def tarfile_to_pif(filename, temp_root_dir='', verbose=0):
6360
"""
6461
Process a tar file that contains DFT data.
@@ -81,8 +78,8 @@ def tarfile_to_pif(filename, temp_root_dir='', verbose=0):
8178
for i in os.listdir(temp_dir):
8279
cur_dir = temp_dir + '/' + i
8380
if os.path.isdir(cur_dir):
84-
return directory_to_pif(cur_dir, verbose)
85-
return directory_to_pif(temp_dir, verbose)
81+
return directory_to_pif(cur_dir, verbose=verbose)
82+
return directory_to_pif(temp_dir, verbose=verbose)
8683
finally:
8784
shutil.rmtree(temp_dir)
8885

@@ -104,14 +101,13 @@ def archive_to_pif(filename, verbose=0):
104101
raise Exception('Cannot process file type')
105102

106103

107-
def directory_to_pif(directory, verbose=0, quality_report=True, inline=True):
104+
def files_to_pif(files, verbose=0, quality_report=True, inline=True):
108105
'''Given a directory that contains output from
109106
a DFT calculation, parse the data and return
110107
a pif object
111108
112109
Input:
113-
directory - String, path to directory containing
114-
DFT results
110+
files - [str] list of files from which the parser is allowed to read.
115111
verbose - int, How much status messages to print
116112
117113
Output:
@@ -123,7 +119,7 @@ def directory_to_pif(directory, verbose=0, quality_report=True, inline=True):
123119
found_parser = False
124120
for possible_parser in [PwscfParser, VaspParser]:
125121
try:
126-
parser = possible_parser(directory)
122+
parser = possible_parser(files)
127123
found_parser = True
128124
break
129125
except InvalidIngesterException:
@@ -195,12 +191,29 @@ def directory_to_pif(directory, verbose=0, quality_report=True, inline=True):
195191
chem.properties.append(prop)
196192

197193
# Check to see if we should add the quality report
198-
if quality_report and isinstance(parser, VaspParser) :
199-
_add_quality_report(directory, chem)
194+
if quality_report and isinstance(parser, VaspParser):
195+
_add_quality_report(parser, chem)
200196

201197
return chem
202198

203-
def convert(files=[], **kwargs):
199+
200+
def directory_to_pif(directory, **kwargs):
201+
"""
202+
Convert a directory to a pif
203+
:param directory: Directory to convert to a pif
204+
:param kwargs: any additional keyword arguments. (See `files_to_pif`)
205+
:return: the created pif
206+
"""
207+
208+
# Get the files
209+
files = [os.path.join(directory, f) for f in os.listdir(directory)
210+
if os.path.isfile(os.path.join(directory, f))]
211+
212+
# Run the pif
213+
return files_to_pif(files, **kwargs)
214+
215+
216+
def convert(files, **kwargs):
204217
"""
205218
Wrap directory to pif as a dice extension
206219
:param files: a list of files, which must be non-empty
@@ -213,10 +226,8 @@ def convert(files=[], **kwargs):
213226

214227
if len(files) == 1:
215228
if os.path.isfile(files[0]):
216-
return directory_to_pif(os.path.dirname(files[0]), **kwargs)
229+
return files_to_pif(files, **kwargs)
217230
else:
218231
return directory_to_pif(files[0], **kwargs)
219232
else:
220-
prefix = os.path.join(".", os.path.commonprefix(files))
221-
print("Trying to use prefix {} from {}".format(prefix, os.getcwd()))
222-
return directory_to_pif(prefix, **kwargs)
233+
return files_to_pif(files, **kwargs)

dfttopif/parsers/abinit.py

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,12 @@ class AbinitParser(DFTParser):
1111
'''
1212
_label = None
1313

14-
def __init__(self, directory):
14+
def __init__(self, files):
1515
# Check whether any file has as name ABINIT in the file in the first two lines
16-
super(AbinitParser, self).__init__(directory)
17-
files = [f for f in os.listdir(directory) if os.path.isfile(os.path.join(directory, f))]
18-
is_abinit = False
16+
super(AbinitParser, self).__init__(files)
1917
for f in files:
2018
try:
21-
with open(os.path.join(directory, f), 'r') as fp:
19+
with open(f, 'r') as fp:
2220
for line in [fp.readline(), fp.readline()]:
2321
if "ABINIT" in line:
2422
is_abinit = True
@@ -34,31 +32,29 @@ def _get_label(self):
3432
for this calculation
3533
'''
3634
if self._label is None:
37-
files = [f for f in os.listdir(self._directory) if os.path.isfile(os.path.join(self._directory, f))]
3835
foundfiles = False
39-
print(files)
40-
for f in files:
36+
for f in self._files:
4137
if ".files" in f:
4238
foundfiles = True
4339
self._label = f.split(".")[0]
44-
fp = open(os.path.join(self._directory, self._label + '.files'), 'r')
45-
line = fp.readline().split()[0]
46-
if line != self._label + ".in":
47-
fp.close()
48-
raise Exception('first line must be label.in')
49-
line = fp.readline().split()[0]
50-
if line != self._label + ".txt":
51-
fp.close()
52-
raise Exception('second line must be label.txt')
53-
line = fp.readline().split()[0]
54-
if line != self._label + "i":
55-
fp.close()
56-
raise Exception('third line must be labeli')
57-
line = fp.readline().split()[0]
58-
if line != self._label + "o":
59-
fp.close()
60-
raise Exception('fourth line must be labelo')
61-
fp.close()
40+
with open(self._label + '.files', 'r') as fp:
41+
line = fp.readline().split()[0]
42+
if line != self._label + ".in":
43+
fp.close()
44+
raise Exception('first line must be label.in')
45+
line = fp.readline().split()[0]
46+
if line != self._label + ".txt":
47+
fp.close()
48+
raise Exception('second line must be label.txt')
49+
line = fp.readline().split()[0]
50+
if line != self._label + "i":
51+
fp.close()
52+
raise Exception('third line must be labeli')
53+
line = fp.readline().split()[0]
54+
if line != self._label + "o":
55+
fp.close()
56+
raise Exception('fourth line must be labelo')
57+
fp.close()
6258
if foundfiles:
6359
return self._label
6460
else:

dfttopif/parsers/base.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,30 @@ class DFTParser(object):
4040
have the same name in the pif.
4141
'''
4242

43-
_directory = None
44-
'''Path to directory containing calculation files'''
45-
4643
_converged = None
4744
''' Whether this calculation has converged '''
4845

49-
def __init__(self, directory):
50-
'''Initialize a parser.
46+
def __init__(self, files):
47+
'''Initialize a parser by defining the list of files that the parser can read from.
5148
5249
Input:
53-
directory - String, path to a directory of output files
50+
files - [str], list of files usable by this parser.
5451
Raises:
55-
Par - If parser cannot find needed files
52+
InvalidIngesterException - If parser cannot find needed files
5653
'''
54+
self._files = files
55+
56+
@classmethod
57+
def generate_from_directory(cls, directory):
58+
"""Create a parser by defining which input files it will read from.
5759
58-
self._directory = directory
60+
Input:
61+
directory - str, directory to read from
62+
files - str, list of files from which to search.
63+
"""
64+
files = [os.path.join(directory, f) for f in os.listdir(directory)
65+
if os.path.isfile(os.path.join(directory, f))]
66+
return cls(files)
5967

6068
def get_setting_functions(self):
6169
'''Get a dictionary containing the names of methods
@@ -101,16 +109,19 @@ def get_result_functions(self):
101109
'Stresses': 'get_stresses'
102110
}
103111

104-
def _call_ase(self, func):
112+
def _call_ase(self, func, directory):
105113
'''Make a call to an ASE function.
114+
115+
Note: I'm about to kill this function, once I'm done with the overhaul
116+
ASE assumes filenames, which we do not want
106117
107118
Handles changing directories
108119
109120
Returns: Result of ASE function
110121
'''
111122
# Change directories
112123
old_path = os.getcwd()
113-
os.chdir(self._directory)
124+
os.chdir(directory)
114125

115126
# Call function
116127
try:

0 commit comments

Comments
 (0)