Coverage for gpaw/xc/__init__.py: 96%

103 statements  

« prev     ^ index     » next       coverage.py v7.7.1, created at 2025-07-09 00:21 +0000

1from gpaw import get_libraries 

2from gpaw.xc.functional import XCFunctional 

3from gpaw.xc.gga import GGA 

4from gpaw.xc.lda import LDA 

5from gpaw.xc.libxc import LibXC 

6from gpaw.xc.mgga import MGGA 

7from gpaw.xc.noncollinear import NonCollinearLDAKernel 

8 

9 

10libraries = get_libraries() 

11 

12 

13def xc_string_to_dict(string): 

14 """Convert XC specification string to dictionary. 

15 

16 'name:key1=value1:...' -> {'name': <name>, key1: value1, ...}.""" 

17 tokens = string.split(':') 

18 

19 d = {'name': tokens[0]} 

20 for token in tokens[1:]: 

21 kw, val = token.split('=') 

22 # Convert value to int or float if possible 

23 try: 

24 val = int(val) 

25 except ValueError: 

26 try: 

27 val = float(val) 

28 except ValueError: 

29 pass 

30 d[kw] = val 

31 return d 

32 

33 

34def XC(kernel, 

35 parameters=None, 

36 atoms=None, 

37 collinear=True) -> XCFunctional: 

38 """Create XCFunctional object. 

39 

40 kernel: XCKernel object, dict or str 

41 Kernel object or name of functional. 

42 parameters: ndarray 

43 Parameters for BEE functional. 

44 

45 Recognized names are: LDA, PW91, PBE, revPBE, RPBE, BLYP, HCTH407, 

46 TPSS, M06-L, revTPSS, vdW-DF, vdW-DF2, EXX, PBE0, B3LYP, BEE, 

47 GLLBSC. One can also use equivalent libxc names, for example 

48 GGA_X_PBE+GGA_C_PBE is equivalent to PBE, and LDA_X to the LDA exchange. 

49 In this way one has access to all the functionals defined in libxc. 

50 See xc_funcs.h for the complete list. 

51 

52 Warning - if an MGGA from libxc is used, libxc should be compiled 

53 with --disable-fhc. Otherwise the calcualtions won't converge""" 

54 

55 if isinstance(kernel, str): 

56 kernel = xc_string_to_dict(kernel) 

57 

58 kwargs = {} 

59 if isinstance(kernel, dict): 

60 kwargs = kernel.copy() 

61 name = kwargs.pop('name') 

62 backend = kwargs.pop('backend', None) 

63 

64 if backend == 'libvdwxc' or name == 'vdW-DF-cx': 

65 # Must handle libvdwxc before old vdw implementation to override 

66 # behaviour for 'name'. Also, cx is not implemented by the old 

67 # vdW module, so that always refers to libvdwxc. 

68 from gpaw.xc.libvdwxc import get_libvdwxc_functional 

69 return get_libvdwxc_functional(name=name, **kwargs) 

70 elif backend == 'ri': 

71 # Note: It is important that this if is before the next name is 

72 # HSExx, since otherwise PWHybrid would hijack the control flow. 

73 from gpaw.xc.ri import RI 

74 return RI(name, **kwargs) 

75 elif backend == 'pw' or name in ['HSE03', 'HSE06', 'YS-PBE0']: 

76 from gpaw.hybrids import HybridXC 

77 return HybridXC(name, **kwargs) # type: ignore 

78 elif backend: 

79 raise ValueError( 

80 'A special backend for the XC functional was given, ' 

81 'but not understood. Please check if there is a typo.') 

82 

83 if name in ['vdW-DF', 'vdW-DF2', 'optPBE-vdW', 'optB88-vdW', 

84 'C09-vdW', 'mBEEF-vdW', 'BEEF-vdW']: 

85 from gpaw.xc.vdw import VDWFunctional 

86 return VDWFunctional(name, **kwargs) 

87 elif name in ['EXX', 'PBE0', 'B3LYP', 

88 'CAMY-BLYP', 'CAMY-B3LYP', 'LCY-BLYP', 'LCY-PBE']: 

89 from gpaw.xc.hybrid import HybridXC as OldHybridXC 

90 return OldHybridXC(name, **kwargs) # type: ignore 

91 elif name.startswith('LCY-') or name.startswith('CAMY-'): 

92 parts = name.split('(') 

93 from gpaw.xc.hybrid import HybridXC as OldHybridXC 

94 return OldHybridXC(parts[0], 

95 omega=float(parts[1][:-1])) 

96 elif name == 'BEE2': 

97 from gpaw.xc.bee import BEE2 

98 kernel = BEE2(parameters) 

99 elif name.startswith('GLLB'): 

100 from gpaw.xc.gllb.nonlocalfunctionalfactory import \ 

101 get_nonlocal_functional 

102 xc = get_nonlocal_functional(name, **kwargs) 

103 return xc 

104 elif name == 'LB94': 

105 from gpaw.xc.lb94 import LB94 

106 kernel = LB94() 

107 elif name == 'TB09': 

108 from gpaw.xc.tb09 import TB09 

109 return TB09(**kwargs) 

110 elif name.endswith('PZ-SIC'): 

111 from gpaw.xc.sic import SIC 

112 return SIC(xc=name[:-7], **kwargs) 

113 elif name in {'TPSS', 'revTPSS', 'M06-L'}: 

114 assert libraries['libxc'], 'Please compile with libxc' 

115 from gpaw.xc.kernel import XCKernel 

116 kernel = XCKernel(name) 

117 elif name in {'LDA', 'PBE', 'revPBE', 'RPBE', 'PW91'}: 

118 from gpaw.xc.kernel import XCKernel 

119 kernel = XCKernel(name) 

120 elif name.startswith('old'): 

121 from gpaw.xc.kernel import XCKernel 

122 kernel = XCKernel(name[3:]) 

123 elif name == 'PPLDA': 

124 from gpaw.xc.lda import PurePythonLDAKernel 

125 kernel = PurePythonLDAKernel() 

126 elif name in ['pyPBE', 'pyPBEsol', 'pyRPBE', 'pyzvPBEsol']: 

127 from gpaw.xc.gga import PurePythonGGAKernel 

128 kernel = PurePythonGGAKernel(name) 

129 elif name == '2D-MGGA': 

130 from gpaw.xc.mgga import PurePython2DMGGAKernel 

131 kernel = PurePython2DMGGAKernel(name, parameters) 

132 elif name[0].isdigit(): 

133 from gpaw.xc.parametrizedxc import ParametrizedKernel 

134 kernel = ParametrizedKernel(name) 

135 elif name == 'null': 

136 from gpaw.xc.kernel import XCNull 

137 kernel = XCNull() 

138 elif name == 'QNA': 

139 from gpaw.xc.qna import QNA 

140 return QNA(atoms, kernel['parameters'], kernel['setup_name'], 

141 alpha=kernel['alpha'], stencil=kwargs.get('stencil', 2)) 

142 else: 

143 kernel = LibXC(name) 

144 

145 if kernel.type == 'LDA': 

146 if not collinear: 

147 kernel = NonCollinearLDAKernel(kernel) 

148 return LDA(kernel, **kwargs) 

149 

150 elif kernel.type == 'GGA': 

151 return GGA(kernel, **kwargs) 

152 else: 

153 return MGGA(kernel, **kwargs)