Coverage for /builds/kinetik161/ase/ase/calculators/siesta/import_ion_xml.py: 92.63%
95 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
1import re
2from xml.dom import minidom
4import numpy as np
7def get_ion(fname):
8 """
9 Read the ion.xml file of a specie
10 Input parameters:
11 -----------------
12 fname (str): name of the ion file
13 Output Parameters:
14 ------------------
15 ion (dict): The ion dictionary contains all the data
16 from the ion file. Each field of the xml file give
17 one key.
18 The different keys are:
19 'lmax_basis': int
20 'self_energy': float
21 'z': int
22 'symbol': str
23 'label': str
24 'mass': flaot
25 'lmax_projs': int
26 'basis_specs': str
27 'norbs_nl': int
28 'valence': float
29 'nprojs_nl: int
31 The following keys give the pao field,
32 'npts': list of int
33 'delta':list of float
34 'cutoff': list of float
35 'data':list of np.arrayof shape (npts[i], 2)
36 'orbital': list of dictionary
37 'projector': list of dictionary
39 """
40 doc = minidom.parse(fname)
42 # the elements from the header
43 elements_headers = [['symbol', str], ['label', str], ['z', int],
44 ['valence', float], ['mass', float],
45 ['self_energy', float], ['lmax_basis', int],
46 ['norbs_nl', int], ['lmax_projs', int],
47 ['nprojs_nl', int]]
49 ion = {}
50 for i, elname in enumerate(elements_headers):
51 name = doc.getElementsByTagName(elname[0])
52 ion[elname[0]] = get_data_elements(name[0], elname[1])
54 # extract the basis_specs
55 name = doc.getElementsByTagName("basis_specs")
56 ion["basis_specs"] = getNodeText(name[0])
58 extract_pao_elements(ion, doc)
59 return ion
62def getNodeText(node):
63 nodelist = node.childNodes
64 result = []
65 for node in nodelist:
66 if node.nodeType == node.TEXT_NODE:
67 result.append(node.data)
68 return ''.join(result)
71def get_data_elements(name, dtype):
72 """
73 return the right type of the element value
74 """
75 if dtype is int:
76 data = str2int(getNodeText(name))
77 if len(data) > 1:
78 return np.array(data)
79 elif len(data) == 1:
80 return data[0]
81 else:
82 raise ValueError("len(data)<1 ??")
83 elif dtype is float:
84 data = str2float(getNodeText(name))
85 if len(data) > 1:
86 return np.array(data)
87 elif len(data) == 1:
88 return data[0]
89 else:
90 raise ValueError("len(data)<1 ??")
91 elif dtype is str:
92 return getNodeText(name)
93 else:
94 raise ValueError('not implemented')
97def extract_pao_elements(ion, doc):
98 """
99 extract the different pao element of the xml file
100 Input Parameters:
101 -----------------
102 ion (dict)
103 doc (minidom.parse)
104 Output Parameters:
105 ------------------
106 ion (dict): the following keys are added to the ion dict:
107 npts
108 delta
109 cutoff
110 data
111 orbital
112 projector
113 """
115 name_npts = doc.getElementsByTagName("npts")
116 name_delta = doc.getElementsByTagName("delta")
117 name_cutoff = doc.getElementsByTagName("cutoff")
118 name_data = doc.getElementsByTagName("data")
120 name_orbital = doc.getElementsByTagName("orbital")
121 name_projector = doc.getElementsByTagName("projector")
123 ion["orbital"] = []
124 ion["projector"] = []
125 for i in range(len(name_orbital)):
126 ion["orbital"].append(extract_orbital(name_orbital[i]))
127 for i in range(len(name_projector)):
128 ion["projector"].append(extract_projector(name_projector[i]))
130 if len(name_data) != len(name_npts):
131 raise ValueError("len(name_data) != len(name_npts): {0} != {1}".
132 format(len(name_data), len(name_npts)))
133 if len(name_data) != len(name_cutoff):
134 raise ValueError("len(name_data) != len(name_cutoff): {0} != {1}".
135 format(len(name_data), len(name_cutoff)))
136 if len(name_data) != len(name_delta):
137 raise ValueError("len(name_data) != len(name_delta): {0} != {1}".
138 format(len(name_data), len(name_delta)))
140 ion["npts"] = np.zeros((len(name_npts)), dtype=int)
141 ion["delta"] = np.zeros((len(name_delta)), dtype=float)
142 ion["cutoff"] = np.zeros((len(name_cutoff)), dtype=float)
143 ion["data"] = []
145 for i in range(len(name_data)):
146 ion["npts"][i] = get_data_elements(name_npts[i], int)
147 ion["cutoff"][i] = get_data_elements(name_cutoff[i], float)
148 ion["delta"][i] = get_data_elements(name_delta[i], float)
149 ion["data"].append(get_data_elements(name_data[i], float).
150 reshape(ion["npts"][i], 2))
153def extract_orbital(orb_xml):
154 """
155 extract the orbital
156 """
157 orb = {}
158 orb['l'] = str2int(orb_xml.attributes['l'].value)[0]
159 orb['n'] = str2int(orb_xml.attributes['n'].value)[0]
160 orb['z'] = str2int(orb_xml.attributes['z'].value)[0]
161 orb['ispol'] = str2int(orb_xml.attributes['ispol'].value)[0]
162 orb['population'] = str2float(orb_xml.attributes['population'].value)[0]
164 return orb
167def extract_projector(pro_xml):
168 """
169 extract the projector
170 """
171 pro = {}
172 pro['l'] = str2int(pro_xml.attributes['l'].value)[0]
173 pro['n'] = str2int(pro_xml.attributes['n'].value)[0]
174 pro['ref_energy'] = str2float(pro_xml.attributes['ref_energy'].value)[0]
176 return pro
179def str2float(string):
180 numeric_const_pattern = r"""
181 [-+]? # optional sign
182 (?:
183 (?: \d* \. \d+ ) # .1 .12 .123 etc 9.1 etc 98.1 etc
184 |
185 (?: \d+ \.? ) # 1. 12. 123. etc 1 12 123 etc
186 )
187 # followed by optional exponent part if desired
188 (?: [Ee] [+-]? \d+ ) ?
189 """
190 rx = re.compile(numeric_const_pattern, re.VERBOSE)
192 nb = rx.findall(string)
193 for i in enumerate(nb):
194 nb[i[0]] = float(i[1])
196 return np.array(nb)
199def str2int(string):
200 numeric_const_pattern = r"""
201 [-+]? # optional sign
202 (?:
203 (?: \d* \. \d+ ) # .1 .12 .123 etc 9.1 etc 98.1 etc
204 |
205 (?: \d+ \.? ) # 1. 12. 123. etc 1 12 123 etc
206 )
207 # followed by optional exponent part if desired
208 (?: [Ee] [+-]? \d+ ) ?
209 """
210 rx = re.compile(numeric_const_pattern, re.VERBOSE)
212 nb = rx.findall(string)
213 for i in enumerate(nb):
214 nb[i[0]] = int(i[1])
216 return np.array(nb)