@@ -177,13 +177,16 @@ def parseLines(self, lines):
177177 p_nl = 0
178178 p_auxiliary_re = re .compile (r"^auxiliary\[(\d+)\] =" )
179179 p_auxiliary = {}
180+ stru = Structure ()
181+ # ignore trailing blank lines
182+ stop = len (lines )
183+ for line in reversed (lines ):
184+ if line .strip ():
185+ break
186+ stop -= 1
187+ # iterator over the valid data lines
188+ ilines = iter (lines [:stop ])
180189 try :
181- stru = Structure ()
182- # ignore trailing blank lines
183- stop = len (lines )
184- while stop > 0 and lines [stop - 1 ].strip () == "" :
185- stop -= 1
186- ilines = iter (lines [:stop ])
187190 # read XCFG header
188191 for line in ilines :
189192 p_nl += 1
@@ -222,51 +225,22 @@ def parseLines(self, lines):
222225 for i in range (p_auxnum ):
223226 if not i in p_auxiliary :
224227 p_auxiliary [i ] = "aux%d" % i
225- sorted_aux_keys = p_auxiliary .keys ()
226- sorted_aux_keys .sort ()
228+ sorted_aux_keys = sorted (p_auxiliary .keys ())
227229 if p_auxnum != 0 :
228230 stru .xcfg = {
229231 'auxiliaries' : [ p_auxiliary [k ]
230232 for k in sorted_aux_keys ]
231233 }
232- if 6 - 3 * xcfg_NO_VELOCITY + len (p_auxiliary ) != xcfg_entry_count :
233- emsg = ("%d: auxiliary fields " +
234+ ecnt = len (p_auxiliary ) + (3 if xcfg_NO_VELOCITY else 6 )
235+ if ecnt != xcfg_entry_count :
236+ emsg = ("%d: auxiliary fields are "
234237 "not consistent with entry_count" ) % p_nl
235238 raise StructureFormatError (emsg )
236239 # define proper lattice
237240 stru .lattice .setLatBase (xcfg_H0 )
238- # build p_assign_atom function to assign entries to proper fields
239- p_exprs = [ "a.xyz[0]=fields[0]" ,
240- "a.xyz[1]=fields[1]" ,
241- "a.xyz[2]=fields[2]" ]
242- if not xcfg_NO_VELOCITY :
243- p_exprs += [ "a.v=numpy.zeros(3, dtype=float)" ,
244- "a.v[0]=fields[3]" ,
245- "a.v[1]=fields[4]" ,
246- "a.v[2]=fields[5]" ]
247- for idx in sorted_aux_keys :
248- prop = p_auxiliary [idx ]
249- col = idx + 6 - 3 * xcfg_NO_VELOCITY
250- if prop == "Uiso" :
251- p_exprs .append ("a.Uisoequiv=fields[%d]" % col )
252- elif re .match (r"^U\d\d$" , prop ) \
253- and 1 <= int (prop [1 ])<= 3 and 1 <= int (prop [2 ])<= 3 :
254- p_exprs .append ("a.anisotropy=True" )
255- i , j = int (prop [1 ])- 1 , int (prop [2 ])- 1
256- if i == j :
257- p_exprs .append ("a.U[%i,%i]=fields[%d]" % (i , j , col ) )
258- else :
259- p_exprs .append ("a.U[%i,%i]=a.U[%i,%i]=fields[%d]" % \
260- (i , j , j , i , col ) )
261- else :
262- p_exprs .append ( "a.__dict__[%r]=fields[%d]" % \
263- (prop , col ) )
264- p_assign_expr = "pass; " + "; " .join (p_exprs [3 :])
265- exec "def p_assign_atom(a, fields) : %s" % p_assign_expr
266- # here we are inside data
241+ # here we are inside the data block
267242 p_element = None
268- p_nl -= 1
269- for line in lines [p_nl :stop ]:
243+ for line in ilines :
270244 p_nl += 1
271245 words = line .split ()
272246 # ignore atom mass
@@ -277,11 +251,12 @@ def parseLines(self, lines):
277251 w = line .strip ()
278252 p_element = w [:1 ].upper () + w [1 :].lower ()
279253 elif len (words ) == xcfg_entry_count and p_element is not None :
280- fields = [ float (w ) for w in words ]
281- stru .addNewAtom (p_element , fields [:3 ])
282- a = stru .getLastAtom ()
283- a .xyz *= xcfg_A
284- p_assign_atom (a , fields )
254+ fields = [float (w ) for w in words ]
255+ xyz = [xcfg_A * xi for xi in fields [:3 ]]
256+ stru .addNewAtom (p_element , xyz = xyz )
257+ a = stru [- 1 ]
258+ _assign_auxiliaries (a , fields , auxiliaries = p_auxiliary ,
259+ no_velocity = xcfg_NO_VELOCITY )
285260 else :
286261 emsg = "%d: invalid record" % p_nl
287262 raise StructureFormatError (emsg )
@@ -407,9 +382,48 @@ def toLines(self, stru):
407382
408383# End of class P_xcfg
409384
410- # Routines
385+ # Routines -------------------------------------------------------------------
411386
412387def getParser ():
413388 return P_xcfg ()
414389
390+ # Local Helpers --------------------------------------------------------------
391+
392+ def _assign_auxiliaries (a , fields , auxiliaries , no_velocity ):
393+ """\
394+ Assing auxiliary properties for Atom object when reading CFG format.
395+
396+ Parameters
397+ ----------
398+ a : Atom
399+ The Atom instance for which the auxiliary properties need to be set.
400+ fields : list
401+ Floating point values for the current row of the processed CFG file.
402+ auxiliaries : dict
403+ Dictionary of zero-based indices and names of auxiliary properties
404+ defined in the CFG format.
405+ no_velocity : bool
406+ When `False` set atom velocity `a.v` to `fields[3:6]`.
407+ Use `fields[3:6]` for auxiliary values otherwise.
408+
409+ No return value.
410+ """
411+ if not no_velocity :
412+ a .v = numpy .asarray (fields [3 :6 ], dtype = float )
413+ auxfirst = 3 if no_velocity else 6
414+ for i , prop in auxiliaries .items ():
415+ value = fields [auxfirst + i ]
416+ if prop == "Uiso" :
417+ a .Uisoequiv = value
418+ elif prop == "Biso" :
419+ a .Bisoequiv = value
420+ elif prop [0 ] in 'BU' and all (d in '123' for d in prop [1 :]):
421+ nm = (prop if prop [1 ] <= prop [2 ]
422+ else prop [0 ] + prop [2 ] + prop [1 ])
423+ a .anisotropy = True
424+ setattr (a , nm , value )
425+ else :
426+ setattr (a , prop , value )
427+ return
428+
415429# End of file
0 commit comments