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