2
2
3
3
from .base import DFTParser , Value_if_true , InvalidIngesterException
4
4
import os
5
- from ase . calculators . vasp import Vasp
6
- from ase .io .vasp import read_vasp , read_vasp_out
5
+ import re
6
+ from ase .io .vasp import read_vasp_out
7
7
from pypif .obj import Value , FileReference
8
8
from dftparse .vasp .outcar_parser import OutcarParser
9
9
from dftparse .vasp .eigenval_parser import EigenvalParser
@@ -26,7 +26,7 @@ def _find_file(name):
26
26
for f in self ._files :
27
27
if os .path .basename (f ).upper ().startswith (name ):
28
28
if my_file is not None :
29
- raise InvalidIngesterException ('Found more than one %s file' .format (name ))
29
+ raise InvalidIngesterException ('Found more than one {} file' .format (name ))
30
30
my_file = f
31
31
return my_file
32
32
self .outcar = _find_file ('OUTCAR' )
@@ -121,7 +121,6 @@ def get_xc_functional(self):
121
121
if "TITEL" in line :
122
122
words = line .split ()
123
123
return Value (scalars = [Scalar (value = words [2 ])])
124
- break
125
124
126
125
def get_pp_name (self ):
127
126
# Open up the OUTCAR
@@ -135,10 +134,7 @@ def get_pp_name(self):
135
134
words = line .split ()
136
135
pp .append (words [3 ])
137
136
return Value (vectors = [[Scalar (value = x ) for x in pp ]])
138
-
139
- # Error handling: TITEL not found
140
- raise Exception ('TITEL not found' )
141
-
137
+
142
138
def get_KPPRA (self ):
143
139
# Open up the OUTCAR
144
140
with open (self .outcar ) as fp :
@@ -167,15 +163,46 @@ def get_KPPRA(self):
167
163
else :
168
164
return Value (scalars = [Scalar (value = NI * NIRK )])
169
165
170
-
171
- # Error handling: NKPTS or NIONS not found
172
- raise Exception ('NIONS, irredicuble or Coordinates not found' )
173
-
174
166
def _is_converged (self ):
175
- return self ._call_ase (Vasp ().read_convergence , os .path .dirname (self .outcar ))
167
+ # Follows the procedure used by qmpy, but without reading the whole file into memory
168
+ # Source: https://github.com/wolverton-research-group/qmpy/blob/master/qmpy/analysis/vasp/calculation.py
169
+
170
+ with open (self .outcar ) as fp :
171
+ # Part 1: Determine the NELM
172
+ nelm = None
173
+ for line in fp :
174
+ if line .startswith (" NELM =" ):
175
+ nelm = int (line .split ()[2 ][:- 1 ])
176
+ break
177
+
178
+ # If we don't find it, tell the user
179
+ if nelm is None :
180
+ raise Exception ('NELM not found. Cannot tell if this result is converged' )
181
+
182
+ # Now, loop through the file. What we want to know is whether the last ionic
183
+ # step of this file terminates because it converges or because we hit NELM
184
+ re_iter = re .compile ('([0-9]+)\( *([0-9]+)\)' )
185
+ converged = False
186
+ for line in fp :
187
+ # Count the ionic steps
188
+ if 'Iteration' in line :
189
+ ionic , electronic = map (int , re_iter .findall (line )[0 ])
190
+
191
+ # If the loop is finished, mark the number of electronic steps
192
+ if 'aborting loop' in line :
193
+ converged = electronic < nelm
194
+
195
+ return converged
176
196
177
197
def get_total_energy (self ):
178
- return Property (scalars = [Scalar (value = self ._call_ase (Vasp ().read_energy , os .path .dirname (self .outcar ))[0 ])], units = 'eV' )
198
+ with open (self .outcar ) as fp :
199
+ last_energy = None
200
+ for line in fp :
201
+ if line .startswith (' free energy TOTEN' ):
202
+ last_energy = float (line .split ()[4 ])
203
+ if last_energy is None :
204
+ return None
205
+ return Property (scalars = [Scalar (value = last_energy )], units = 'eV' )
179
206
180
207
def get_version_number (self ):
181
208
# Open up the OUTCAR
0 commit comments