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

1import sys 

2from optparse import OptionParser 

3 

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 

8 

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. 

15 

16 

17class BasisSpecification: 

18 def __init__(self, setup, jvalues, jextra): 

19 self.setup = setup 

20 self.jvalues = jvalues 

21 self.jextra = jextra 

22 

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}]' 

28 

29 

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.""" 

34 

35 

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() 

46 

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)) 

60 

61 if opts._from: 

62 index = symbols.index(opts._from) 

63 symbols = symbols[index:] 

64 

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 

74 

75 # One could include basis functions also for the ``virtual'' states 

76 # (marked with negative n) 

77 

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)) 

87 

88 # XXX check whether automatic settings coincide with those of official 

89 # setups distribution 

90 

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() 

96 

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 

105 

106 tokens = spec.setup.symbol.split('.') 

107 sym = tokens[0] 

108 

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') 

117 

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() 

124 

125 

126if __name__ == '__main__': 

127 main()