Source code for pynao.m_siesta_ion_xml
from __future__ import division, print_function
import numpy as np
from xml.dom import minidom
import sys
import re
[docs]def str2int(string):
numeric_const_pattern = r"""
[-+]? # optional sign
(?:
(?: \d* \. \d+ ) # .1 .12 .123 etc 9.1 etc 98.1 etc
|
(?: \d+ \.? ) # 1. 12. 123. etc 1 12 123 etc
)
# followed by optional exponent part if desired
(?: [Ee] [+-]? \d+ ) ?
"""
rx = re.compile(numeric_const_pattern, re.VERBOSE)
nb = rx.findall(string)
for i in enumerate(nb): nb[i[0]] = int(i[1])
return np.array(nb)
#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1
[docs]def str2float(string):
numeric_const_pattern = r"""
[-+]? # optional sign
(?:
(?: \d* \. \d+ ) # .1 .12 .123 etc 9.1 etc 98.1 etc
|
(?: \d+ \.? ) # 1. 12. 123. etc 1 12 123 etc
)
# followed by optional exponent part if desired
(?: [Ee] [+-]? \d+ ) ?
"""
rx = re.compile(numeric_const_pattern, re.VERBOSE)
nb = rx.findall(string)
for i in enumerate(nb): nb[i[0]] = float(i[1])
return np.array(nb)
[docs]def siesta_ion_xml(fname):
"""
Read the ion.xml file of a specie
Input parameters:
-----------------
fname (str): name of the ion file
Output Parameters:
------------------
ion (dict): The ion dictionnary contains all the data
from the ion file. Each field of the xml file give
one key.
The different keys are:
'lmax_basis': int
'self_energy': float
'z': int
'symbol': str
'label': str
'mass': flaot
'lmax_projs': int
'basis_specs': str
'norbs_nl': int
'valence': float
'nprojs_nl: int
The following keys give the pao field,
'npts': list of int
'delta':list of float
'cutoff': list of float
'data':list of np.arrayof shape (npts[i], 2)
'orbital': list of dictionary
'projector': list of dictionary
"""
doc = minidom.parse(fname)
#the elements from the header
elements_headers = [['symbol', str], ['label', str], ['z', int], ['valence', float],
['mass', float], ['self_energy', float], ['lmax_basis', int], ['norbs_nl', int],
['lmax_projs', int], ['nprojs_nl', int]]
ion = {}
for i, elname in enumerate(elements_headers):
name = doc.getElementsByTagName(elname[0])
ion[elname[0]] = get_data_elements(name[0], elname[1])
#extract the basis_specs
name = doc.getElementsByTagName("basis_specs")
ion["basis_specs"] = getNodeText(name[0])
#for node in doc.getElementsByTagName('paos'): # visit every node <bar />
# #print node.toxml()
# for delt in node.getElementsByTagName('delta'):
# print getNodeText(delt)
#node = doc.getElementsByTagName("pao")
#print('pao: ', node)
field = {'paos': 'orbital', 'kbs': 'projector', 'vna': None,
'chlocal': None, 'reduced_vlocal': None, 'core': None}
for k, v in field.items():
if (len(doc.getElementsByTagName(k))>0):
ion[k] = extract_field_elements(doc.getElementsByTagName(k)[0], field=v)
else:
ion[k] = None
return ion
[docs]def getNodeText(node):
nodelist = node.childNodes
result = []
for node in nodelist:
if node.nodeType == node.TEXT_NODE:
result.append(node.data)
return ''.join(result)
[docs]def get_data_elements(name, dtype):
"""
return the right type of the element value
"""
if dtype is int:
data = str2int(getNodeText(name))
if len(data) > 1:
return np.array(data)
elif len(data) == 1:
return data[0]
else:
raise ValueError("len(data)<1 ??")
elif dtype is float:
data = str2float(getNodeText(name))
if len(data) > 1:
return np.array(data)
elif len(data) == 1:
return data[0]
else:
raise ValueError("len(data)<1 ??")
elif dtype is str:
return getNodeText(name)
else:
raise ValueError('not implemented')
[docs]def extract_field_elements(doc, field=None):
"""
extract the different pao element of the xml file
Input Parameters:
-----------------
field: field name of the node
doc (minidom.parse)
Output Parameters:
------------------
pao (dict): the following keys are added to the ion dict:
npts
delta
cutoff
data
orbital
"""
if len(doc.getElementsByTagName('delta')) <1 :
return None
# checks if some of the values are null
for i, delt in enumerate(doc.getElementsByTagName('delta')):
if get_data_elements(delt, float) == 0.0:
return None
# if all(delta) > 0.0 then fill the dict
pao = {}
pao['npaos'] = len(doc.getElementsByTagName('delta'))
if pao['npaos'] != len(doc.getElementsByTagName('cutoff')) or\
pao['npaos'] != len(doc.getElementsByTagName('npts')):
raise ValueError('Error reqding ion file! npaos is not constant??')
pao['delta'] = np.zeros((pao['npaos']), dtype=float)
pao['cutoff'] = np.zeros((pao['npaos']), dtype=float)
pao['npts'] = np.zeros((pao['npaos']), dtype=int)
pao['data'] = []
for i, delt in enumerate(doc.getElementsByTagName('delta')):
pao['delta'][i] = get_data_elements(delt, float)
for i, delt in enumerate(doc.getElementsByTagName('cutoff')):
pao['cutoff'][i] = get_data_elements(delt, float)
for i, delt in enumerate(doc.getElementsByTagName('npts')):
pao['npts'][i] = get_data_elements(delt, int)
for i, dat in enumerate(doc.getElementsByTagName('data')):
pao['data'].append(get_data_elements(dat, float).reshape(pao["npts"][i], 2))
if len(pao['data']) != pao['npaos']:
raise ValueError('Error reading ion file, len(data) != npaos')
if field is not None:
name_orbital = doc.getElementsByTagName(field)
pao[field] = []
if field == 'orbital':
for i in range(len(name_orbital)):
pao[field].append(extract_orbital(name_orbital[i]))
elif field == 'projector':
for i in range(len(name_orbital)):
pao[field].append(extract_projector(name_orbital[i]))
else:
raise ValueError(field + ' not implemented, onlt orbital or projector!!')
if len(pao[field]) != pao['npaos']:
raise ValueError('Error reading ion file, len(' + field +') != npaos')
return pao
[docs]def extract_orbital(orb_xml):
"""
extract the orbital
"""
orb = {}
#print('key: ', orb_xml.attributes.keys)
#print('l values', orb_xml.attributes['l'].value)
orb['l'] = int(orb_xml.attributes['l'].value)
orb['n'] = int(orb_xml.attributes['n'].value)
orb['z'] = int(orb_xml.attributes['z'].value)
orb['ispol'] = int(orb_xml.attributes['ispol'].value)
orb['population'] = float(orb_xml.attributes['population'].value)
return orb
[docs]def extract_projector(pro_xml):
"""
extract the projector
"""
pro = {}
pro['l'] = int(pro_xml.attributes['l'].value)
pro['n'] = int(pro_xml.attributes['n'].value)
#print('ref_energy', pro_xml.attributes['ref_energy'].value)
pro['ref_energy'] = float(pro_xml.attributes['ref_energy'].value)
return pro
#
# Executable part
#
if __name__=="__main__":
import sys
fname = sys.argv[1] #has an error out of range!!
ionxml = siesta_ion_xml(fname)
print(dir(ionxml))