Coverage for gpaw/lcao/generate_extended.py: 16%
77 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-08 00:17 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-08 00:17 +0000
1import sys
2from optparse import OptionParser
4from gpaw.atom.basis import BasisMaker
5from gpaw.atom.configurations import parameters, parameters_extra
6from gpaw.setup_data import SetupData
7from gpaw.mpi import world
9# Module for generating basis sets more suitable for excited states.
10#
11# Generates basis sets that include empty p orbitals as valence states
12# for metals. This improves the description of excited states and is
13# useful for TDDFT, band structures (the part above the Fermi level),
14# and more.
17class BasisSpecification:
18 def __init__(self, setup, jvalues, jextra):
19 self.setup = setup
20 self.jvalues = jvalues
21 self.jextra = jextra
23 def __str__(self):
24 l_j = self.setup.l_j
25 jvtxt = ', '.join([f'{j}(l={l_j[j]})' for j in self.jvalues])
26 jetxt = ', '.join([f'{j}(l={l_j[j]})' for j in self.jextra])
27 return f'{self.setup.symbol}: jvalues=[{jvtxt}], jextra=[{jetxt}]'
30description = """Generate basis sets that include unoccupied p states as
31valence states instead of Gaussian-based polarization functions.
32If SYMBOLs are omitted, generate basis sets for all elements with
33unoccupied p states and default setup."""
36def main():
37 parser = OptionParser(usage='%prog [OPTION...] [SYMBOL...]',
38 description=description)
39 parser.add_option('--xc', metavar='FUNCTIONAL',
40 default='PBE',
41 help='generate basis sets for FUNCTIONAL[=%default]')
42 parser.add_option('--from', metavar='SYMBOL', dest='_from',
43 help='generate starting from SYMBOL if generating '
44 'for all elements')
45 opts, symbols = parser.parse_args()
47 if len(symbols) == 0:
48 symbols = sorted(parameters.keys())
49 othersymbols = []
50 for symbol in parameters_extra:
51 name = parameters_extra[symbol]['name']
52 code = f'{symbol}.{name}'
53 othersymbols.append(code)
54 # Setups that cause trouble
55 # trouble = set(['Os.8', 'Ta.5', 'V.5', 'W.6', 'Ir.9'])
56 trouble = set()
57 othersymbols = [symbol for symbol in othersymbols
58 if symbol not in trouble]
59 symbols.extend(sorted(othersymbols))
61 if opts._from:
62 index = symbols.index(opts._from)
63 symbols = symbols[index:]
65 specifications = []
66 for sym in symbols:
67 try:
68 s = SetupData(sym, opts.xc)
69 except RuntimeError as e:
70 if str(e).startswith('Could not find'):
71 continue
72 else:
73 raise
75 # One could include basis functions also for the ``virtual'' states
76 # (marked with negative n)
78 jvalues = []
79 jextra = []
80 for j in range(len(s.f_j)):
81 if s.eps_j[j] < 0:
82 jvalues.append(j)
83 if s.f_j[j] == 0.0 and s.n_j[j] > 0:
84 jextra.append(j)
85 if len(jextra) > 0:
86 specifications.append(BasisSpecification(s, jvalues, jextra))
88 # XXX check whether automatic settings coincide with those of official
89 # setups distribution
91 if world.rank == 0:
92 print('Generating basis sets for: %s'
93 % ' '.join(spec.setup.symbol for spec in specifications))
94 sys.stdout.flush()
95 world.barrier()
97 for i, spec in enumerate(specifications):
98 if i % world.size != world.rank:
99 continue
100 if world.size > 1:
101 print(world.rank, spec)
102 else:
103 print(spec)
104 gtxt = None
106 tokens = spec.setup.symbol.split('.')
107 sym = tokens[0]
109 if len(tokens) == 1:
110 p = parameters
111 name = 'pvalence'
112 elif len(tokens) == 2:
113 p = parameters_extra
114 name = '%s.pvalence' % tokens[1]
115 else:
116 raise ValueError('Strange setup specification')
118 # This generates only dz setups
119 bm = BasisMaker.from_symbol(
120 sym, name=name, gtxt=gtxt, xc=opts.xc,
121 generator_run_kwargs=dict(write_xml=False, **p[sym]))
122 basis = bm.generate(2, 0, txt=None, jvalues=spec.jvalues)
123 basis.write_xml()
126if __name__ == '__main__':
127 main()