Coverage for gpaw/setup_data.py: 94%
490 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-19 00:19 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-19 00:19 +0000
1from __future__ import annotations
3import hashlib
4import os
5import re
6import xml.sax
7from glob import glob
8from math import pi, sqrt
9from pathlib import Path
10from typing import IO, Tuple
12import numpy as np
13from ase.data import atomic_names, atomic_numbers
14from ase.units import Bohr, Ha
16from gpaw import setup_paths
17from gpaw.atom.radialgd import (AbinitRadialGridDescriptor,
18 AERadialGridDescriptor)
19from gpaw.atom.shapefunc import shape_functions
20from gpaw.mpi import broadcast
21from gpaw.xc.pawcorrection import PAWXCCorrection
24class SetupData:
25 """Container class for persistent setup attributes and XML I/O."""
26 def __init__(self, symbol, xcsetupname,
27 name='paw', readxml=True,
28 zero_reference=False, world=None,
29 generator_version=None):
30 self.symbol = symbol
31 self.setupname = xcsetupname
32 self.name = name
33 self.zero_reference = zero_reference
34 self.generator_version = generator_version
36 self.filename = None # full path if this setup was loaded from file
37 self.fingerprint = None # hash value of file data if applicable
39 self.Z = None
40 self.Nc = None
41 self.Nv = None
43 # Quantum numbers, energies
44 self.n_j = []
45 self.l_j = []
46 self.l_orb_J = self.l_j # pointer to same list!
47 self.f_j = []
48 self.eps_j = []
49 self.e_kin_jj = None # <phi | T | phi> - <phit | T | phit>
51 self.rgd = None
53 # Parameters for compensation charge expansion functions:
54 self.shape_function = {'type': 'undefined', 'rc': np.nan}
56 # State identifier, like "X-2s" or "X-p1", where X is chemical symbol,
57 # for bound and unbound states
58 self.id_j = []
60 # Partial waves, projectors
61 self.phi_jg = []
62 self.phit_jg = []
63 self.pt_jg = []
64 self.rcut_j = []
66 # Densities, potentials
67 self.nc_g = None
68 self.nct_g = None
69 self.nvt_g = None
70 self.vbar_g = None
71 self.vt_g = None
73 # Kinetic energy densities of core electrons
74 self.tauc_g = None
75 self.tauct_g = None
77 # Reference energies
78 self.e_kinetic = 0.0
79 self.e_xc = 0.0
80 self.e_electrostatic = 0.0
81 self.e_total = 0.0
82 self.e_kinetic_core = 0.0
84 # Generator may store description of setup in these
85 self.type = None
86 self.generatorattrs = []
87 self.generatordata = ''
89 # Optional quantities, normally not used
90 self.X_p = None
91 self.X_wp = {}
92 self.X_pg = None
93 self.ExxC = None
94 self.ExxC_w = {}
95 self.X_gamma = None
96 self.extra_xc_data = {}
97 self.phicorehole_g = None
98 self.fcorehole = 0.0
99 self.lcorehole = None
100 self.ncorehole = None
101 self.core_hole_e = None
102 self.core_hole_e_kin = None
103 self.has_corehole = False
105 # Parameters for zero-potential:
106 self.l0 = None
107 self.e0 = None
108 self.r0 = None
109 self.nderiv0 = None
111 self.orbital_free = False # orbital-free DFT
113 self.version = None
115 if readxml:
116 self.read_xml(world=world)
118 @classmethod
119 def find_and_read_path(cls, symbol, xctype,
120 setuptype='paw', world=None):
122 setupdata = SetupData(symbol, xctype,
123 name=setuptype,
124 readxml=False,
125 world=world)
127 setupdata.filename, source = search_for_file(setupdata.stdfilename,
128 world=world)
129 PAWXMLParser(setupdata).parse(source=source, world=world)
131 nj = len(setupdata.l_j)
132 setupdata.e_kin_jj.shape = (nj, nj)
134 return setupdata
136 @property
137 def stdfilename(self):
138 """Default filename if this setup is written."""
139 assert self.symbol is not None
140 assert self.setupname is not None
141 if self.name is None or self.name == 'paw':
142 return f'{self.symbol}.{self.setupname}'
143 else:
144 return f'{self.symbol}.{self.name}.{self.setupname}'
146 def __repr__(self):
147 return ('{0}({symbol!r}, {setupname!r}, name={name!r}, '
148 'generator_version={generator_version!r}, ...)'
149 .format(self.__class__.__name__, **vars(self)))
151 def append(self, n, l, f, e, rcut, phi_g, phit_g, pt_g):
152 self.n_j.append(n)
153 self.l_j.append(l)
154 self.f_j.append(f)
155 self.eps_j.append(e)
156 self.rcut_j.append(rcut)
157 self.phi_jg.append(phi_g)
158 self.phit_jg.append(phit_g)
159 self.pt_jg.append(pt_g)
161 # XXX delete me
162 def read_xml(self, source=None, world=None):
163 PAWXMLParser(self).parse(source=source, world=world)
164 nj = len(self.l_j)
165 self.e_kin_jj.shape = (nj, nj)
167 def is_compatible(self, xc):
168 return xc.get_setup_name() == self.setupname
170 def print_info(self, text, setup):
171 if self.phicorehole_g is None:
172 text(self.symbol + ':')
173 else:
174 text(f'{self.symbol}: # ({self.fcorehole:.1f} core hole)')
175 text(' name:', atomic_names[atomic_numbers[self.symbol]])
176 text(' id:', self.fingerprint)
177 text(' Z:', self.Z)
178 text(' valence:', self.Nv)
179 if self.phicorehole_g is None:
180 text(' core: %d' % self.Nc)
181 else:
182 text(f' core: {self.Nc:.1f}')
183 text(' charge:', self.Z - self.Nv - self.Nc)
184 if setup.hubbard_u is not None:
185 description = ''.join([f' {line}' for line
186 in setup.hubbard_u.descriptions()])
187 text(description)
188 text(' file:', self.filename)
189 sf = self.shape_function
190 text(f' compensation charges: {{type: {sf["type"]},\n'
191 f' rc: {sf["rc"] * Bohr:.2f},\n'
192 f' lmax: {setup.lmax}}}')
193 text(f' cutoffs: {{filter: {setup.rcutfilter * Bohr:.2f},\n'
194 f' core: {setup.rcore * Bohr:.2f}}}')
195 text(' projectors:')
196 text(' # energy rcut')
197 j = 0
198 for n, l, f, eps in zip(self.n_j, self.l_j, self.f_j, self.eps_j):
199 if n > 0:
200 f = f'({f:.2f})'
201 text(' - %d%s%-5s %9.3f %5.3f' % (
202 n, 'spdf'[l], f, eps * Ha, self.rcut_j[j] * Bohr))
203 else:
204 text(' - {} {:9.3f} {:5.3f}'.format(
205 'spdf'[l], eps * Ha, self.rcut_j[j] * Bohr))
206 j += 1
207 text()
209 def create_compensation_charge_functions(self, lmax):
210 """Create shape functions used to expand compensation charges."""
211 g_lg = shape_functions(self.rgd, **self.shape_function, lmax=lmax)
212 return g_lg
214 def get_smooth_core_density_integral(self, Delta0):
215 return -Delta0 * sqrt(4 * pi) - self.Z + self.Nc
217 def get_overlap_correction(self, Delta0_ii):
218 return sqrt(4.0 * pi) * Delta0_ii
220 def get_linear_kinetic_correction(self, T0_qp):
221 e_kin_jj = self.e_kin_jj
222 nj = len(e_kin_jj)
223 K_q = []
224 for j1 in range(nj):
225 for j2 in range(j1, nj):
226 K_q.append(e_kin_jj[j1, j2])
227 K_p = sqrt(4 * pi) * np.dot(K_q, T0_qp)
228 return K_p
230 def find_core_density_cutoff(self, nc_g):
231 if self.Nc == 0:
232 return 1.0
233 else:
234 rgd = self.rgd
235 N = 0.0
236 g = self.rgd.N - 1
237 while N < 1e-7:
238 N += sqrt(4 * pi) * nc_g[g] * rgd.r_g[g]**2 * rgd.dr_g[g]
239 g -= 1
240 return rgd.r_g[g]
242 def get_xc_correction(self, rgd, xc, gcut2, lcut):
243 phicorehole_g = self.phicorehole_g
244 if phicorehole_g is not None:
245 phicorehole_g = phicorehole_g[:gcut2].copy()
247 xc_correction = PAWXCCorrection(
248 [phi_g[:gcut2] for phi_g in self.phi_jg],
249 [phit_g[:gcut2] for phit_g in self.phit_jg],
250 self.nc_g[:gcut2] / sqrt(4 * pi),
251 self.nct_g[:gcut2] / sqrt(4 * pi),
252 rgd,
253 list(enumerate(self.l_j)),
254 min(2 * lcut, 4),
255 self.e_xc,
256 phicorehole_g,
257 self.fcorehole,
258 None if self.tauc_g is None else self.tauc_g[:gcut2].copy(),
259 None if self.tauct_g is None else self.tauct_g[:gcut2].copy())
261 return xc_correction
263 def write_xml(self, path=None) -> None:
264 if path is None:
265 path = self.stdfilename
267 with open(path, 'w') as fd:
268 self._write_xml(fd)
270 def _write_xml(self, xml: IO[str]) -> None:
271 l_j = self.l_j
273 print('<?xml version="1.0"?>', file=xml)
274 print(f'<paw_dataset version="{self.version}">',
275 file=xml)
276 name = atomic_names[atomic_numbers[self.symbol]].title()
277 comment1 = name + ' setup for the Projector Augmented Wave method.'
278 comment2 = 'Units: Hartree and Bohr radii.'
279 comment2 += ' ' * (len(comment1) - len(comment2))
280 print(' <!--', comment1, '-->', file=xml)
281 print(' <!--', comment2, '-->', file=xml)
283 print((' <atom symbol="%s" Z="%r" core="%s" valence="%s"/>' %
284 (self.symbol, self.Z, self.Nc, self.Nv)), file=xml)
285 if self.orbital_free:
286 type = 'OFDFT'
287 name = self.setupname
288 elif self.setupname == 'LDA':
289 type = 'LDA'
290 name = 'PW'
291 else:
292 type = 'GGA'
293 name = self.setupname
294 print(f' <xc_functional type="{type}" name="{name}"/>',
295 file=xml)
296 gen_attrs = ' '.join([f'{key}="{value}"' for key, value
297 in self.generatorattrs])
298 print(f' <generator {gen_attrs}>', file=xml)
299 print(f' {self.generatordata}', file=xml)
300 print(' </generator>', file=xml)
301 print(f' <ae_energy kinetic="{self.e_kinetic}" xc="{self.e_xc}"',
302 file=xml)
303 print(' electrostatic="%s" total="%s"/>' %
304 (self.e_electrostatic, self.e_total), file=xml)
306 print(f' <core_energy kinetic="{self.e_kinetic_core}"/>', file=xml)
307 print(' <valence_states>', file=xml)
308 line1 = ' <state n="%d" l="%d" f="%s" rc="%s" e="%s" id="%s"/>'
309 line2 = ' <state l="%d" rc="%s" e="%s" id="%s"/>'
311 for id, l, n, f, e, rc in zip(self.id_j, l_j, self.n_j, self.f_j,
312 self.eps_j, self.rcut_j):
313 if n > 0:
314 print(line1 % (n, l, f, rc, e, id), file=xml)
315 else:
316 print(line2 % (l, rc, e, id), file=xml)
317 print(' </valence_states>', file=xml)
319 print(self.rgd.xml('g1'), file=xml)
321 print(' <shape_function type="{type}" rc="{rc}"/>'
322 .format(**self.shape_function), file=xml)
324 if self.r0 is None:
325 # Old setups:
326 xml.write(' <zero_potential grid="g1">\n')
327 elif self.l0 is None:
328 xml.write(' <zero_potential type="polynomial" ' +
329 'nderiv="%d" r0="%r" grid="g1">\n' %
330 (self.nderiv0, self.r0))
331 else:
332 xml.write((' <zero_potential type="%s" ' +
333 'e0="%r" nderiv="%d" r0="%r" grid="g1">\n') %
334 ('spdfg'[self.l0], self.e0, self.nderiv0, self.r0))
336 for x in self.vbar_g:
337 print(x, end=' ', file=xml)
338 print('\n </zero_potential>', file=xml)
340 if self.has_corehole:
341 print(((' <core_hole_state state="%d%s" ' +
342 'removed="%s" eig="%s" ekin="%s">') %
343 (self.ncorehole, 'spdf'[self.lcorehole],
344 self.fcorehole,
345 self.core_hole_e, self.core_hole_e_kin)), file=xml)
346 for x in self.phicorehole_g:
347 print(x, end=' ', file=xml)
348 print('\n </core_hole_state>', file=xml)
350 for name, a in [('ae_core_density', self.nc_g),
351 ('pseudo_core_density', self.nct_g),
352 ('ae_core_kinetic_energy_density', self.tauc_g),
353 ('pseudo_core_kinetic_energy_density', self.tauct_g)]:
354 print(f' <{name} grid="g1">\n ', end=' ', file=xml)
355 for x in a:
356 print(x, end=' ', file=xml)
357 print(f'\n </{name}>', file=xml)
359 # Print xc-specific data to setup file (used so for KLI and GLLB)
360 for name, a in self.extra_xc_data.items():
361 newname = 'GLLB_' + name
362 print(f' <{newname} grid="g1">\n ', end=' ', file=xml)
363 for x in a:
364 print(x, end=' ', file=xml)
365 print(f'\n </{newname}>', file=xml)
367 for id, l, u, s, q, in zip(self.id_j, l_j, self.phi_jg, self.phit_jg,
368 self.pt_jg):
369 for name, a in [('ae_partial_wave', u),
370 ('pseudo_partial_wave', s),
371 ('projector_function', q)]:
372 print(f' <{name} state="{id}" grid="g1">\n ',
373 end=' ', file=xml)
374 for x in a:
375 print(x, end=' ', file=xml)
376 print(f'\n </{name}>', file=xml)
378 if self.vt_g is not None:
379 xml.write(' <pseudo_potential grid="g1">\n')
380 for x in self.vt_g:
381 print(x, end=' ', file=xml)
382 print('\n </pseudo_potential>', file=xml)
384 print(' <kinetic_energy_differences>', end=' ', file=xml)
385 nj = len(self.e_kin_jj)
386 for j1 in range(nj):
387 print('\n ', end=' ', file=xml)
388 for j2 in range(nj):
389 print(self.e_kin_jj[j1, j2], end=' ', file=xml)
390 print('\n </kinetic_energy_differences>', file=xml)
392 if self.X_p is not None:
393 print(' <exact_exchange_X_matrix>\n ', end=' ', file=xml)
394 for x in self.X_p:
395 print(x, end=' ', file=xml)
396 print('\n </exact_exchange_X_matrix>', file=xml)
398 print(f' <exact_exchange core-core="{self.ExxC}"/>', file=xml)
399 for omega, Ecc in self.ExxC_w.items():
400 print(f' <erfc_exchange omega="{omega}" core-core="{Ecc}"/>',
401 file=xml)
402 print(f' <erfc_exchange_X_matrix omega="{omega}" X_p="',
403 end=' ', file=xml)
404 for x in self.X_wp[omega]:
405 print(x, end=' ', file=xml)
406 print('"/>', file=xml)
408 if self.X_pg is not None:
409 print(' <yukawa_exchange_X_matrix>\n ', end=' ', file=xml)
410 for x in self.X_pg:
411 print(x, end=' ', file=xml)
412 print('\n </yukawa_exchange_X_matrix>', file=xml)
413 print(f' <yukawa_exchange gamma="{self.X_gamma}"/>', file=xml)
414 print('</paw_dataset>', file=xml)
416 def build(self, xcfunc, lmax, basis, filter=None,
417 backwards_compatible=True):
418 from gpaw.setup import Setup
419 setup = Setup(self, xcfunc, lmax, basis, filter,
420 backwards_compatible=backwards_compatible)
421 return setup
424def read_maybe_unzipping(path: Path | str) -> bytes:
425 import gzip
426 if Path(path).suffix == '.gz':
427 with gzip.open(path) as fd:
428 return fd.read()
430 with open(path, 'rb') as fd:
431 return fd.read()
434def search_for_file(name: str, world=None) -> Tuple[str, bytes]:
435 """Traverse gpaw setup paths to find file.
437 Returns the file path and file contents. If the file is not
438 found, raises RuntimeError."""
440 if world is None or world.rank == 0:
441 source = b''
442 filename = None
443 for path in setup_paths:
444 pattern = os.path.join(path, name)
445 filenames = glob(pattern) + glob(f'{pattern}.gz')
446 if filenames:
447 # The globbing is a hack to grab the 'newest' version if
448 # the files are somehow version numbered; then we want the
449 # last/newest of the results (used with SG15). (User must
450 # instantiate (UPF)SetupData directly to override.)
451 filename = max(filenames)
452 source = read_maybe_unzipping(filename)
453 break
455 if world is not None:
456 if world.rank == 0:
457 broadcast((filename, source), 0, world)
458 else:
459 filename, source = broadcast(None, 0, world)
461 if filename is None:
462 if name.endswith('basis'):
463 _type = 'basis set'
464 else:
465 _type = 'PAW dataset'
466 err = f'Could not find required {_type} file "{name}".'
467 helpful_message = """
468You need to set the GPAW_SETUP_PATH environment variable to point to
469the directories where PAW dataset and basis files are stored. See
470https://gpaw.readthedocs.io/install.html#install-paw-datasets
471for details."""
472 raise FileNotFoundError(f'{err}\n{helpful_message}\n')
474 return filename, source
477class PAWXMLParser(xml.sax.handler.ContentHandler):
478 def __init__(self, setup):
479 xml.sax.handler.ContentHandler.__init__(self)
480 self.setup = setup
481 self.id = None
482 self.data = None
484 def parse(self, source=None, world=None):
485 setup = self.setup
486 if source is None:
487 setup.filename, source = search_for_file(setup.stdfilename, world)
489 setup.fingerprint = hashlib.md5(source).hexdigest()
491 # XXXX There must be a better way!
492 # We don't want to look at the dtd now. Remove it:
493 source = re.compile(b'<!DOCTYPE .*?>', re.DOTALL).sub(b'', source, 1)
494 xml.sax.parseString(source, self)
496 if setup.zero_reference:
497 setup.e_total = 0.0
498 setup.e_kinetic = 0.0
499 setup.e_electrostatic = 0.0
500 setup.e_xc = 0.0
502 def startElement(self, name, attrs):
503 setup = self.setup
504 if name == 'paw_setup' or name == 'paw_dataset':
505 setup.version = attrs['version']
506 assert [int(v) for v in setup.version.split('.')] >= [0, 4]
507 if name == 'atom':
508 Z = float(attrs['Z'])
509 setup.Z = Z
510 assert setup.symbol is None or setup.symbol == attrs['symbol']
511 setup.symbol = attrs['symbol']
512 assert setup.Z == Z
513 setup.Nc = float(attrs['core'])
514 Nv = float(attrs['valence'])
515 setup.Nv = int(Nv)
516 assert setup.Nv == Nv
517 elif name == 'xc_functional':
518 if attrs['type'] == 'LDA':
519 setup.xcname = 'LDA'
520 else:
521 setup.xcname = attrs['name']
522 if attrs['type'] == 'OFDFT':
523 setup.orbital_free = True
524 else:
525 assert attrs['type'] == 'GGA'
526 assert setup.setupname is None or setup.setupname == setup.xcname
527 setup.setupname = setup.xcname
528 elif name == 'ae_energy':
529 setup.e_total = float(attrs['total'])
530 setup.e_kinetic = float(attrs['kinetic'])
531 setup.e_electrostatic = float(attrs['electrostatic'])
532 setup.e_xc = float(attrs['xc'])
533 elif name == 'core_energy':
534 setup.e_kinetic_core = float(attrs['kinetic'])
535 elif name == 'state':
536 setup.n_j.append(int(attrs.get('n', -1)))
537 setup.l_j.append(int(attrs['l']))
538 setup.f_j.append(float(attrs.get('f', 0)))
539 setup.eps_j.append(float(attrs['e']))
540 setup.rcut_j.append(float(attrs.get('rc', -1)))
541 setup.id_j.append(attrs['id'])
542 # Compatibility with old setups:
543 version = [int(v) for v in setup.version.split('.')]
544 if version < [0, 6] and setup.f_j[-1] == 0:
545 setup.n_j[-1] = -1
546 elif name == 'radial_grid':
547 if attrs['eq'] == 'r=a*i/(n-i)':
548 beta = float(attrs['a'])
549 ng = int(attrs['n'])
550 setup.rgd = AERadialGridDescriptor(beta / ng, 1.0 / ng, ng)
551 elif attrs['eq'] == 'r=a*i/(1-b*i)':
552 a = float(attrs['a'])
553 b = float(attrs['b'])
554 N = int(attrs['n'])
555 setup.rgd = AERadialGridDescriptor(a, b, N)
556 elif attrs['eq'] == 'r=a*(exp(d*i)-1)':
557 a = float(attrs['a'])
558 d = float(attrs['d'])
559 istart = int(attrs['istart'])
560 iend = int(attrs['iend'])
561 assert istart == 0
562 setup.rgd = AbinitRadialGridDescriptor(a, d, iend + 1)
563 else:
564 raise ValueError('Unknown grid:' + attrs['eq'])
565 elif name == 'shape_function':
566 assert attrs['type'] in {'gauss', 'sinc', 'bessel'}
567 setup.shape_function = {'type': attrs['type'],
568 'rc': float(attrs['rc'])}
569 elif name in ['ae_core_density', 'pseudo_core_density',
570 'localized_potential', 'yukawa_exchange_X_matrix',
571 'kinetic_energy_differences', 'exact_exchange_X_matrix',
572 'ae_core_kinetic_energy_density',
573 'pseudo_core_kinetic_energy_density',
574 'pseudo_potential']:
575 self.data = []
576 elif name.startswith('GLLB_'):
577 self.data = []
578 elif name in ['ae_partial_wave', 'pseudo_partial_wave']:
579 self.data = []
580 self.id = attrs['state']
581 elif name == 'projector_function':
582 self.id = attrs['state']
583 self.data = []
584 elif name == 'erfc_exchange':
585 setup.ExxC_w[float(attrs['omega'])] = float(attrs['core-core'])
586 elif name == 'exact_exchange':
587 setup.ExxC = float(attrs['core-core'])
588 elif name == 'erfc_exchange_X_matrix':
589 X_p = np.array([float(x) for x in ''.join(attrs['X_p']).split()])
590 setup.X_wp[float(attrs['omega'])] = X_p
591 elif name == 'yukawa_exchange':
592 setup.X_gamma = float(attrs['gamma'])
593 elif name == 'core_hole_state':
594 setup.has_corehole = True
595 setup.fcorehole = float(attrs['removed'])
596 full_state = attrs['state']
597 state_l = full_state.lstrip('0123456789')
598 assert state_l
599 state_n = full_state[:-len(state_l)]
600 assert state_n
601 setup.ncorehole = int(state_n)
602 setup.lcorehole = 'spdf'.find(state_l)
603 setup.core_hole_e = float(attrs['eig'])
604 setup.core_hole_e_kin = float(attrs['ekin'])
605 self.data = []
606 elif name == 'zero_potential':
607 if 'type' in attrs:
608 setup.r0 = float(attrs['r0'])
609 setup.nderiv0 = int(attrs['nderiv'])
610 if attrs['type'] == 'polynomial':
611 setup.e0 = None
612 setup.l0 = None
613 else:
614 setup.e0 = float(attrs['e0'])
615 setup.l0 = 'spdfg'.find(attrs['type'])
616 self.data = []
617 elif name == 'generator':
618 setup.type = attrs['type']
619 setup.generator_version = int(attrs.get('version', '1'))
620 else:
621 self.data = None
623 def characters(self, data):
624 if self.data is not None:
625 self.data.append(data)
627 def endElement(self, name):
628 setup = self.setup
629 if self.data is None:
630 return
631 x_g = np.array([float(x) for x in ''.join(self.data).split()])
632 if name == 'ae_core_density':
633 setup.nc_g = x_g
634 elif name == 'pseudo_core_density':
635 setup.nct_g = x_g
636 elif name == 'kinetic_energy_differences':
637 setup.e_kin_jj = x_g
638 elif name == 'ae_core_kinetic_energy_density':
639 setup.tauc_g = x_g
640 elif name == 'pseudo_valence_density':
641 setup.nvt_g = x_g
642 elif name == 'pseudo_core_kinetic_energy_density':
643 setup.tauct_g = x_g
644 elif name in ['localized_potential', 'zero_potential']: # XXX
645 setup.vbar_g = x_g
646 elif name in ['pseudo_potential']:
647 setup.vt_g = x_g
648 elif name.startswith('GLLB_'):
649 # Add setup tags starting with GLLB_ to extra_xc_data. Remove
650 # GLLB_ from front of string:
651 if name == 'GLLB_w_j':
652 v1, v2 = (int(x) for x in self.setup.version.split('.'))
653 if (v1, v2) < (0, 8):
654 # Order was wrong in old generator:
655 w_j = {}
656 j_old = 0
657 for l in range(4):
658 for j_new, (n1, l1) in enumerate(zip(setup.n_j,
659 setup.l_j)):
660 if l == l1:
661 w_j[j_new] = x_g[j_old]
662 j_old += 1
663 x_g = [w_j[j] for j in range(len(w_j))]
664 setup.extra_xc_data[name[5:]] = x_g
666 elif name == 'ae_partial_wave':
667 j = len(setup.phi_jg)
668 assert self.id == setup.id_j[j]
669 setup.phi_jg.append(x_g)
670 elif name == 'pseudo_partial_wave':
671 j = len(setup.phit_jg)
672 assert self.id == setup.id_j[j]
673 setup.phit_jg.append(x_g)
674 elif name == 'projector_function':
675 j = len(setup.pt_jg)
676 assert self.id == setup.id_j[j]
677 setup.pt_jg.append(x_g)
678 elif name == 'exact_exchange_X_matrix':
679 setup.X_p = x_g
680 elif name == 'yukawa_exchange_X_matrix':
681 setup.X_pg = x_g
682 elif name == 'core_hole_state':
683 setup.phicorehole_g = x_g