Coverage for gpaw/xc/libxc.py: 92%
65 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 warnings
3import gpaw.cgpaw as cgpaw
4from gpaw import debug
5from gpaw.xc.kernel import XCKernel
8class FunctionalNeedsLaplacianError(Exception):
9 """(MGGA) Functional needs laplacian.
11 """
14short_names = {
15 'LDA': 'LDA_X+LDA_C_PW',
16 'PW91': 'GGA_X_PW91+GGA_C_PW91',
17 'PBE': 'GGA_X_PBE+GGA_C_PBE',
18 'PBEsol': 'GGA_X_PBE_SOL+GGA_C_PBE_SOL',
19 'revPBE': 'GGA_X_PBE_R+GGA_C_PBE',
20 'RPBE': 'GGA_X_RPBE+GGA_C_PBE',
21 'BLYP': 'GGA_X_B88+GGA_C_LYP',
22 'HCTH407': 'GGA_XC_HCTH_407',
23 'WC': 'GGA_X_WC+GGA_C_PBE',
24 'AM05': 'GGA_X_AM05+GGA_C_AM05',
25 'M06-L': 'MGGA_X_M06_L+MGGA_C_M06_L',
26 'TPSS': 'MGGA_X_TPSS+MGGA_C_TPSS',
27 'revTPSS': 'MGGA_X_REVTPSS+MGGA_C_REVTPSS',
28 'mBEEF': 'MGGA_X_MBEEF+GGA_C_PBE_SOL',
29 'SCAN': 'MGGA_X_SCAN+MGGA_C_SCAN'}
32class LibXC(XCKernel):
33 """Functionals from libxc."""
34 def __init__(self, name, provides_laplacian=False, disable_fhc=True):
35 if not hasattr(cgpaw, 'lxcXCFuncNum'):
36 raise NameError(
37 f'Unable to use {name}: GPAW not compiled with LibXC!')
38 self.name = name
39 self.omega = None
40 self.disable_fhc = disable_fhc
41 self.initialize(nspins=1, provides_laplacian=provides_laplacian)
43 def initialize(self,
44 nspins,
45 provides_laplacian=False):
46 self.nspins = nspins
47 name = short_names.get(self.name, self.name)
48 number = cgpaw.lxcXCFuncNum(name)
49 if number is not None:
50 f = number
51 xc = -1
52 x = -1
53 c = -1
54 if '_XC_' in name:
55 xc = f
56 elif '_C_' in name:
57 c = f
58 else:
59 x = f
60 else:
61 try:
62 x, c = name.split('+')
63 except ValueError:
64 raise NameError(f'Unknown functional: {name}.')
65 xc = -1
66 x = cgpaw.lxcXCFuncNum(x)
67 c = cgpaw.lxcXCFuncNum(c)
68 if x is None or c is None:
69 raise NameError(f'Unknown functional: {name}.')
71 self.xc = cgpaw.lxcXCFunctional(xc, x, c, nspins)
72 self.set_omega()
74 if self.xc.is_mgga():
75 self.type = 'MGGA'
76 if self.disable_fhc:
77 ok = self.xc.disable_fhc()
78 if not ok:
79 warnings.warn(
80 'libxc should be compiled with --disable-fhc' +
81 ' otherwise SCF calculations might not converge.')
82 if self.xc.needs_laplacian() and not provides_laplacian:
83 msg = f'Functional "{name}" needs laplacian'
84 msg += ' (unsupported)'
85 raise FunctionalNeedsLaplacianError(msg, self.xc)
86 elif self.xc.is_gga():
87 self.type = 'GGA'
88 else:
89 self.type = 'LDA'
91 def calculate(self, e_g, n_sg, dedn_sg,
92 sigma_xg=None, dedsigma_xg=None,
93 tau_sg=None, dedtau_sg=None):
94 if debug:
95 self.check_arguments(e_g, n_sg, dedn_sg, sigma_xg, dedsigma_xg,
96 tau_sg, dedtau_sg)
97 nspins = len(n_sg)
98 if self.nspins != nspins:
99 self.initialize(nspins)
101 self.xc.calculate(e_g.ravel(), n_sg, dedn_sg,
102 sigma_xg, dedsigma_xg,
103 tau_sg, dedtau_sg)
105 def set_omega(self, omega=None):
106 """Set the value of gamma/omega in RSF."""
107 if omega is not None:
108 self.omega = omega
109 if self.omega is not None:
110 if not self.xc.set_omega(self.omega):
111 raise ValueError('Tried setting omega on a non RSF hybrid.')