Coverage for eminus/xc/lda_xc_ksdt.py: 100.00%

284 statements  

« prev     ^ index     » next       coverage.py v7.8.2, created at 2025-06-02 10:16 +0000

1# SPDX-FileCopyrightText: 2024 The eminus developers 

2# SPDX-License-Identifier: Apache-2.0 

3"""KSDT LDA exchange-correlation. 

4 

5Reference: Phys. Rev. Lett. 112, 076403. 

6""" 

7 

8import dataclasses 

9import functools 

10 

11import numpy as np 

12 

13# ### Temperature dependent coefficients ### 

14 

15 

16@dataclasses.dataclass 

17class Coefficients: 

18 """Coefficients class to calculate temperature/theta dependent coefficients. 

19 

20 Reference: Phys. Rev. Lett. 112, 076403. 

21 """ 

22 

23 theta: float #: Reduced temperature. 

24 omega: float 

25 e1: float 

26 e2: float 

27 e3: float 

28 e4: float 

29 e5: float 

30 d1: float 

31 d2: float 

32 d3: float 

33 d4: float 

34 d5: float 

35 c1: float 

36 c2: float 

37 c3: float 

38 b1: float 

39 b2: float 

40 b3: float 

41 b4: float 

42 a1: float = 0.75 

43 a2: float = 3.04363 

44 a3: float = -0.09227 

45 a4: float = 1.7035 

46 a5: float = 8.31051 

47 a6: float = 5.1105 

48 

49 @functools.cached_property 

50 def a0(self): 

51 """Calculate a0.""" 

52 return 1 / (np.pi * (4 / (9 * np.pi)) ** (1 / 3)) 

53 

54 @functools.cached_property 

55 def b5(self): 

56 """Calculate b5.""" 

57 return self.b3 * np.sqrt(3 / 2) * self.omega * (4 / (9 * np.pi)) ** (-1 / 3) 

58 

59 @functools.cached_property 

60 def a(self): 

61 """Calculate a.""" 

62 with np.errstate(divide="ignore"): 

63 u = self.a0 * np.tanh( 

64 1 / self.theta, out=np.ones_like(self.theta), where=self.theta > 0 

65 ) 

66 return u * _pade(self.theta, self.a1, self.a2, self.a3, self.a4, self.a5, self.a6) 

67 

68 @property 

69 def dadtheta(self): 

70 """Calculate da / dtheta.""" 

71 with np.errstate(divide="ignore"): 

72 u = self.a0 * np.tanh( 

73 1 / self.theta, out=np.ones_like(self.theta), where=self.theta > 0 

74 ) 

75 du = np.divide( 

76 u**2 / self.a0 - self.a0, 

77 self.theta**2, 

78 out=np.zeros_like(self.theta), 

79 where=self.theta > 0, 

80 ) 

81 v, dv = _dpade(self.theta, self.a1, self.a2, self.a3, self.a4, self.a5, self.a6) 

82 return du * v + u * dv 

83 

84 @functools.cached_property 

85 def b(self): 

86 """Calculate b.""" 

87 with np.errstate(divide="ignore"): 

88 u = np.tanh(1 / np.sqrt(self.theta), out=np.ones_like(self.theta), where=self.theta > 0) 

89 return u * _pade(self.theta, self.b1, self.b2, 0, self.b3, self.b4, self.b5) 

90 

91 @property 

92 def dbdtheta(self): 

93 """Calculate db / dtheta.""" 

94 with np.errstate(divide="ignore"): 

95 u = np.tanh(1 / np.sqrt(self.theta), out=np.ones_like(self.theta), where=self.theta > 0) 

96 du = np.divide( 

97 u**2 - 1, 

98 2 * self.theta * np.sqrt(self.theta), 

99 out=np.zeros_like(self.theta), 

100 where=self.theta > 0, 

101 ) 

102 v, dv = _dpade(self.theta, self.b1, self.b2, 0, self.b3, self.b4, self.b5) 

103 return du * v + u * dv 

104 

105 @functools.cached_property 

106 def c(self): 

107 """Calculate c.""" 

108 with np.errstate(divide="ignore"): 

109 exp = np.exp(-self.c3 / self.theta, out=np.zeros_like(self.theta), where=self.theta > 0) 

110 return (self.c1 + self.c2 * exp) * self.e 

111 

112 @property 

113 def dcdtheta(self): 

114 """Calculate dc / dtheta.""" 

115 with np.errstate(divide="ignore"): 

116 exp = np.exp(-self.c3 / self.theta, out=np.zeros_like(self.theta), where=self.theta > 0) 

117 u = self.c1 + self.c2 * exp 

118 du = np.divide( 

119 self.c2 * self.c3 * exp, 

120 self.theta**2, 

121 out=np.zeros_like(self.theta), 

122 where=self.theta > 0, 

123 ) 

124 v, dv = self.e, self.dedtheta 

125 return du * v + u * dv 

126 

127 @functools.cached_property 

128 def d(self): 

129 """Calculate d.""" 

130 with np.errstate(divide="ignore"): 

131 u = np.tanh(1 / np.sqrt(self.theta), out=np.ones_like(self.theta), where=self.theta > 0) 

132 return u * _pade(self.theta, self.d1, self.d2, 0, self.d3, self.d4, self.d5) 

133 

134 @property 

135 def dddtheta(self): 

136 """Calculate dd / dtheta.""" 

137 with np.errstate(divide="ignore"): 

138 u = np.tanh(1 / np.sqrt(self.theta), out=np.ones_like(self.theta), where=self.theta > 0) 

139 du = np.divide( 

140 u**2 - 1, 

141 2 * self.theta * np.sqrt(self.theta), 

142 out=np.zeros_like(self.theta), 

143 where=self.theta > 0, 

144 ) 

145 v, dv = _dpade(self.theta, self.d1, self.d2, 0, self.d3, self.d4, self.d5) 

146 return du * v + u * dv 

147 

148 @functools.cached_property 

149 def e(self): 

150 """Calculate e.""" 

151 with np.errstate(divide="ignore"): 

152 u = np.tanh(1 / self.theta, out=np.ones_like(self.theta), where=self.theta > 0) 

153 return u * _pade(self.theta, self.e1, self.e2, 0, self.e3, self.e4, self.e5) 

154 

155 @functools.cached_property 

156 def dedtheta(self): 

157 """Calculate de / dtheta.""" 

158 with np.errstate(divide="ignore"): 

159 u = np.tanh(1 / self.theta, out=np.ones_like(self.theta), where=self.theta > 0) 

160 du = np.divide(u**2 - 1, self.theta**2, out=np.zeros_like(self.theta), where=self.theta > 0) 

161 v, dv = _dpade(self.theta, self.e1, self.e2, 0, self.e3, self.e4, self.e5) 

162 return du * v + u * dv 

163 

164 

165# ### Parameters ### 

166 

167 

168@dataclasses.dataclass 

169class Zeta0Coeffs(Coefficients): 

170 """Coefficient class using the parameters for zeta=0. 

171 

172 Reference: Phys. Rev. Lett. 112, 076403. 

173 """ 

174 

175 omega: float = 1 

176 b1: float = 0.283997 

177 b2: float = 48.932154 

178 b3: float = 0.370919 

179 b4: float = 61.095357 

180 c1: float = 0.870089 

181 c2: float = 0.193077 

182 c3: float = 2.414644 

183 d1: float = 0.579824 

184 d2: float = 94.537454 

185 d3: float = 97.839603 

186 d4: float = 59.939999 

187 d5: float = 24.388037 

188 e1: float = 0.212036 

189 e2: float = 16.731249 

190 e3: float = 28.485792 

191 e4: float = 34.028876 

192 e5: float = 17.235515 

193 

194 

195@dataclasses.dataclass 

196class Zeta1Coeffs(Coefficients): 

197 """Coefficient class using the parameters for zeta=1. 

198 

199 Reference: Phys. Rev. Lett. 112, 076403. 

200 """ 

201 

202 omega: float = 2 ** (1 / 3) 

203 b1: float = 0.329001 

204 b2: float = 111.598308 

205 b3: float = 0.537053 

206 b4: float = 105.086663 

207 c1: float = 0.84893 

208 c2: float = 0.167952 

209 c3: float = 0.08882 

210 d1: float = 0.55133 

211 d2: float = 180.213159 

212 d3: float = 134.486231 

213 d4: float = 103.861695 

214 d5: float = 17.75071 

215 e1: float = 0.153124 

216 e2: float = 19.543945 

217 e3: float = 43.400337 

218 e4: float = 120.255145 

219 e5: float = 15.662836 

220 

221 

222@dataclasses.dataclass 

223class PhiParams: 

224 """Parameter class holding the spin-interpolation function parameters. 

225 

226 Reference: Phys. Rev. Lett. 112, 076403. 

227 """ 

228 

229 g1: float = 2 / 3 

230 g2: float = -0.0139261 

231 g3: float = 0.183208 

232 lambda1: float = 1.064009 

233 lambda2: float = 0.572565 

234 

235 

236# ### Functional implementation ### 

237 

238 

239def lda_xc_ksdt( 

240 n, T=0, zeta0_coeffs=Zeta0Coeffs, zeta1_coeffs=Zeta1Coeffs, phi_params=PhiParams, **kwargs 

241): 

242 """KSDT exchange-correlation functional (spin-polarized). 

243 

244 Similar to the functional with the label LDA_XC_KSDT and ID 259 in Libxc, but the 

245 implementations differ: https://gitlab.com/libxc/libxc/-/issues/525 

246 Exchange and correlation cannot be separated. 

247 

248 Reference: Phys. Rev. Lett. 112, 076403. 

249 

250 Args: 

251 n: Real-space electronic density. 

252 

253 Keyword Args: 

254 T: Temperature in Hartree. 

255 zeta0_coeffs: Coefficient class using the parameters for zeta=0. 

256 zeta1_coeffs: Coefficient class using the parameters for zeta=1. 

257 phi_params: Parameter class holding the spin-interpolation function parameters. 

258 **kwargs: Throwaway arguments. 

259 

260 Returns: 

261 KSDT exchange-correlation energy density and potential. 

262 """ 

263 kwargs["zeta"] = np.zeros_like(n) 

264 exc, vxc, _ = lda_xc_ksdt_spin( 

265 n, 

266 T=T, 

267 zeta0_coeffs=zeta0_coeffs, 

268 zeta1_coeffs=zeta1_coeffs, 

269 phi_params=phi_params, 

270 **kwargs, 

271 ) 

272 return exc, np.array([vxc[0]]), None 

273 

274 

275def lda_xc_ksdt_spin( 

276 n, zeta, T=0, zeta0_coeffs=Zeta0Coeffs, zeta1_coeffs=Zeta1Coeffs, phi_params=PhiParams, **kwargs 

277): 

278 """KSDT exchange-correlation functional (spin-polarized). 

279 

280 Similar to the functional with the label LDA_XC_KSDT and ID 259 in Libxc, but the 

281 implementations differ: https://gitlab.com/libxc/libxc/-/issues/525 

282 Exchange and correlation cannot be separated. 

283 

284 Reference: Phys. Rev. Lett. 112, 076403. 

285 

286 Args: 

287 n: Real-space electronic density. 

288 zeta: Relative spin polarization. 

289 

290 Keyword Args: 

291 T: Temperature in Hartree. 

292 zeta0_coeffs: Coefficient class using the parameters for zeta=0. 

293 zeta1_coeffs: Coefficient class using the parameters for zeta=1. 

294 phi_params: Parameter class holding the spin-interpolation function parameters. 

295 **kwargs: Throwaway arguments. 

296 

297 Returns: 

298 KSDT exchange-correlation energy density and potential. 

299 """ 

300 # Calculate properties 

301 n_up = (1 + zeta) * n / 2 

302 rs = (3 / (4 * np.pi * n)) ** (1 / 3) 

303 theta = _get_theta(T, n, zeta) 

304 theta0 = _get_theta0(theta, zeta) 

305 theta1 = _get_theta1(theta, zeta) 

306 

307 # Initialize parameters 

308 # We need to calculate coefficients for specific theta 

309 # Create a coefficients object for each theta with its corresponding parameters 

310 phi_params = phi_params() 

311 zeta0theta = zeta0_coeffs(theta) 

312 zeta0theta0 = zeta0_coeffs(theta0) 

313 zeta1theta = zeta1_coeffs(theta) 

314 zeta1theta1 = zeta1_coeffs(theta1) 

315 

316 # Calculate fxc 

317 fxc0 = _get_fxc_zeta(rs, zeta0theta0) 

318 fxc1 = _get_fxc_zeta(rs, zeta1theta1) 

319 phi = _get_phi(rs, theta0, zeta, phi_params) 

320 fxc = fxc0 + (fxc1 - fxc0) * phi 

321 

322 # Generic derivatives 

323 drsdn = -(6 ** (1 / 3)) * (1 / n) ** (1 / 3) / (6 * np.pi ** (1 / 3) * n) 

324 dzetadn_up = -zeta / n**2 + 1 / n 

325 dzetadn_dw = -zeta / n**2 - 1 / n 

326 

327 # fxc derivatives 

328 dfxc0drs = _get_dfxc_zetadrs(rs, zeta0theta) 

329 dfxc1drs = _get_dfxc_zetadrs(rs, zeta1theta) 

330 dfxc0dtheta0 = _get_dfxc_zetadtheta(rs, zeta0theta0) 

331 dfxc1dtheta1 = _get_dfxc_zetadtheta(rs, zeta1theta1) 

332 

333 # phi derivatives 

334 dphidrs = _get_dphidrs(rs, theta0, zeta, phi_params) 

335 dphidtheta = _get_dphidtheta(rs, theta0, zeta, phi_params) 

336 dphidzeta = _get_dphidzeta(rs, theta0, zeta, phi_params) 

337 

338 # theta derivatives 

339 dthetadn_up = _get_dthetadn_up(T, n_up) 

340 dtheta0dtheta = _get_dtheta0dtheta(zeta) 

341 dtheta0dzeta = _get_dtheta0dzeta(theta0, zeta) 

342 dtheta1dtheta0 = _get_dtheta1dtheta0() 

343 

344 # Calculate vxc_up (using dndn_up=1) 

345 dfxc0a = dfxc0drs * drsdn # * dndn_up = 1 

346 dfxc1a = dfxc1drs * drsdn # * dndn_up = 1 

347 dfxc0b_up = dfxc0dtheta0 * (dtheta0dtheta * dthetadn_up + dtheta0dzeta * dzetadn_up) 

348 dfxc1b_up = ( 

349 dfxc1dtheta1 * dtheta1dtheta0 * (dtheta0dtheta * dthetadn_up + dtheta0dzeta * dzetadn_up) 

350 ) 

351 dphi_up = dphidtheta * dthetadn_up + dphidzeta * dzetadn_up + dphidrs * drsdn # * dndn_up = 1 

352 vxc_up = ( 

353 dfxc0a 

354 + dfxc0b_up 

355 - phi * (dfxc0a + dfxc0b_up - dfxc1a - dfxc1b_up) 

356 - (fxc0 - fxc1) * dphi_up 

357 ) 

358 

359 # Calculate vxc_dw (using dndn_dw=1 and dthetadn_dw=0) 

360 # dfxc0a and dfxc1a are identical for vxc_up and vxc_dw 

361 dfxc0b_dw = dfxc0dtheta0 * dtheta0dzeta * dzetadn_dw 

362 # dfxc0b += dfxc0dtheta0 * dtheta0dtheta * dthetadn_dw 

363 dfxc1b_dw = dfxc1dtheta1 * dtheta1dtheta0 * dtheta0dzeta * dzetadn_dw 

364 # dfxc1b += dfxc1dtheta1 * dtheta1dtheta0 * dtheta0dtheta * dthetadn_dw 

365 dphi_dw = dphidzeta * dzetadn_dw + dphidrs * drsdn # * dndn_dw = 1 

366 # dfxc1b += dphidtheta * dthetadn_dw 

367 vxc_dw = ( 

368 dfxc0a 

369 + dfxc0b_dw 

370 - phi * (dfxc0a + dfxc0b_dw - dfxc1a - dfxc1b_dw) 

371 - (fxc0 - fxc1) * dphi_dw 

372 ) 

373 

374 return fxc, fxc + np.array([vxc_up, vxc_dw]) * n, None 

375 

376 

377# ### Pade approximation and derivative ### 

378 

379 

380def _pade(x, n1, n2, n3, n4, d1, d2): 

381 """Pade approximation. 

382 

383 Not the general case but as needed for this functional. 

384 """ 

385 x2, x4 = x**2, x**4 

386 num = n1 + n2 * x2 + n3 * x**3 + n4 * x4 

387 denom = 1 + d1 * x2 + d2 * x4 

388 return num / denom 

389 

390 

391def _dpade(x, n1, n2, n3, n4, d1, d2): 

392 """Pade approximation and its derivative.""" 

393 x2, x3, x4 = x**2, x**3, x**4 

394 num = n1 + n2 * x2 + n3 * x3 + n4 * x4 

395 denom = 1 + d1 * x2 + d2 * x4 

396 dnum = 2 * n2 * x + 3 * n3 * x2 + 4 * n4 * x3 

397 ddenom = 2 * d1 * x + 4 * d2 * x3 

398 # df = (a'b - ab') / b^2 

399 return num / denom, (dnum * denom - num * ddenom) / denom**2 

400 

401 

402# ### theta and derivatives ### 

403 

404 

405def _get_theta(T, n, zeta): 

406 """Calculate the reduced temperature theta. 

407 

408 Reference: Phys. Rev. Lett. 119, 135001. 

409 Only mentioned in the arXiv version: https://arxiv.org/abs/1703.08074 

410 """ 

411 n_up = (1 + zeta) * n / 2 

412 T_fermi = (6 * np.pi**2 * n_up) ** (2 / 3) / 2 

413 return T / T_fermi 

414 

415 

416def _get_dthetadn_up(T, n_up): 

417 """Calculate dtheta / dn_up.""" 

418 return -4 / (3 * 6 ** (2 / 3)) * T / (np.pi ** (4 / 3) * n_up ** (5 / 3)) 

419 

420 

421def _get_theta0(theta, zeta): 

422 """Calculate theta0. 

423 

424 Reference: Phys. Rev. Lett. 119, 135001. 

425 """ 

426 return theta * (1 + zeta) ** (2 / 3) 

427 

428 

429def _get_dtheta0dtheta(zeta): 

430 """Calculate dtheta0 / dtheta.""" 

431 return (1 + zeta) ** (2 / 3) 

432 

433 

434def _get_dtheta0dzeta(theta, zeta): 

435 """Calculate dtheta0 / dzeta.""" 

436 return 2 * theta / (3 * (1 + zeta) ** (1 / 3)) 

437 

438 

439def _get_theta1(theta, zeta): 

440 """Calculate theta1. 

441 

442 Reference: Phys. Rev. Lett. 119, 135001. 

443 

444 It is not explicitly mentioned but introduced as used in Eq. (5). 

445 """ 

446 theta0 = _get_theta0(theta, zeta) 

447 return theta0 * 2 ** (-2 / 3) 

448 

449 

450def _get_dtheta1dtheta0(): 

451 """Calculate dtheta1 / dtheta0.""" 

452 return 2 ** (-2 / 3) 

453 

454 

455# ### fxc_zeta and derivatives ### 

456 

457 

458def _get_fxc_zeta(rs, p): 

459 """Calculate the Pade formula f_xc^zeta. 

460 

461 Reference: Phys. Rev. Lett. 112, 076403. 

462 """ 

463 num = p.a * p.omega + p.b * np.sqrt(rs) + p.c * rs 

464 denom = 1 + p.d * np.sqrt(rs) + p.e * rs 

465 return -1 / rs * num / denom 

466 

467 

468def _get_dfxc_zetadrs(rs, p): 

469 """Calculate dfxc_zeta / drs.""" 

470 num = p.a * p.omega + p.b * np.sqrt(rs) + p.c * rs 

471 denom = 1 + p.d * np.sqrt(rs) + p.e * rs 

472 tmp1 = (p.d / (2 * np.sqrt(rs)) + p.e) * num / denom**2 

473 tmp2 = (p.b / (2 * np.sqrt(rs)) + p.c) / denom 

474 return (tmp1 - tmp2) / rs + num / denom / rs**2 

475 

476 

477def _get_dfxc_zetadtheta(rs, p): 

478 """Calculate dfxc_zeta / dzeta.""" 

479 num = p.a * p.omega + p.b * np.sqrt(rs) + p.c * rs 

480 denom = 1 + p.d * np.sqrt(rs) + p.e * rs 

481 tmp1 = (p.dddtheta * np.sqrt(rs) + p.dedtheta * rs) * num / denom**2 

482 tmp2 = (p.dadtheta * p.omega + p.dbdtheta * np.sqrt(rs) + p.dcdtheta * rs) / denom 

483 return (tmp1 - tmp2) / rs 

484 

485 

486# ### phi and derivatives ### 

487 

488 

489def _get_phi(rs, theta, zeta, phi_params): 

490 """Calculate the interpolation function phi. 

491 

492 Reference: Phys. Rev. Lett. 112, 076403. 

493 """ 

494 alpha = _get_alpha(rs, theta, phi_params) 

495 return ((1 + zeta) ** alpha + (1 - zeta) ** alpha - 2) / (2**alpha - 2) 

496 

497 

498def _get_dphidrs(rs, theta, zeta, phi_params): 

499 """Calculate dphi / drs.""" 

500 alpha = _get_alpha(rs, theta, phi_params) 

501 dalphadrs = _get_dalphadrs(rs, theta, phi_params) 

502 tmp1 = (1 - zeta) ** alpha * np.log(1 - zeta, out=np.zeros_like(zeta), where=1 - zeta > 0) 

503 tmp2 = (1 + zeta) ** alpha * np.log(1 + zeta) 

504 duv = (tmp1 + tmp2) * (2**alpha - 2) 

505 udv = ((1 - zeta) ** alpha + (1 + zeta) ** alpha - 2) * 2**alpha * np.log(2) 

506 vv = (2**alpha - 2) ** 2 

507 return (duv - udv) * dalphadrs / vv 

508 

509 

510def _get_dphidtheta(rs, theta, zeta, phi_params): 

511 """Calculate dphi / dtheta.""" 

512 alpha = _get_alpha(rs, theta, phi_params) 

513 dalphadtheta = _get_dalphadtheta(rs, theta, phi_params) 

514 tmp1 = (1 - zeta) ** alpha * np.log(1 - zeta, out=np.zeros_like(zeta), where=1 - zeta > 0) 

515 tmp2 = (1 + zeta) ** alpha * np.log(1 + zeta) 

516 duv = (tmp1 + tmp2) * (2**alpha - 2) 

517 udv = ((1 - zeta) ** alpha + (1 + zeta) ** alpha - 2) * 2**alpha * np.log(2) 

518 vv = (2**alpha - 2) ** 2 

519 return (duv - udv) * dalphadtheta / vv 

520 

521 

522def _get_dphidzeta(rs, theta, zeta, phi_params): 

523 """Calculate dphi / dzeta.""" 

524 alpha = _get_alpha(rs, theta, phi_params) 

525 tmp1 = alpha * (1 + zeta) ** alpha / (1 + zeta) 

526 tmp2 = np.divide( 

527 alpha * (1 - zeta) ** alpha, 1 - zeta, out=np.zeros_like(zeta), where=1 - zeta > 0 

528 ) 

529 return (tmp1 - tmp2) / (2**alpha - 2) 

530 

531 

532# ### alpha and derivatives ### 

533 

534 

535def _get_alpha(rs, theta, phi_params): 

536 """Calculate alpha. 

537 

538 Reference: Phys. Rev. Lett. 112, 076403. 

539 """ 

540 g = _get_g(rs, phi_params) 

541 lamda = _get_lambda(rs, theta, phi_params) 

542 return 2 - g * np.exp(-theta * lamda) 

543 

544 

545def _get_dalphadrs(rs, theta, phi_params): 

546 """Calculate dalpha / drs.""" 

547 g = _get_g(rs, phi_params) 

548 lamda = _get_lambda(rs, theta, phi_params) 

549 dgdrs = _get_dgdrs(rs, phi_params) 

550 dlambdadrs = _get_dlambdadrs(rs, theta, phi_params) 

551 return -dgdrs * np.exp(-theta * lamda) + dlambdadrs * theta * g * np.exp(-theta * lamda) 

552 

553 

554def _get_dalphadtheta(rs, theta, phi_params): 

555 """Calculate dalpha / dtheta.""" 

556 g = _get_g(rs, phi_params) 

557 lamda = _get_lambda(rs, theta, phi_params) 

558 dlambdadtheta = _get_dlambdadtheta(rs, phi_params) 

559 return (dlambdadtheta * theta + lamda) * g * np.exp(-theta * lamda) 

560 

561 

562# ### g and derivative ### 

563 

564 

565def _get_g(rs, phi_params): 

566 """Calculate g. 

567 

568 Reference: Phys. Rev. Lett. 112, 076403. 

569 """ 

570 return (phi_params.g1 + phi_params.g2 * rs) / (1 + phi_params.g3 * rs) 

571 

572 

573def _get_dgdrs(rs, phi_params): 

574 """Calculate dg / drs.""" 

575 return ( 

576 phi_params.g2 / (phi_params.g3 * rs + 1) 

577 - phi_params.g3 * (phi_params.g2 * rs + phi_params.g1) / (phi_params.g3 * rs + 1) ** 2 

578 ) 

579 

580 

581# ### lambda and derivatives ### 

582 

583 

584def _get_lambda(rs, theta, phi_params): 

585 """Calculate lambda. 

586 

587 Reference: Phys. Rev. Lett. 112, 076403. 

588 """ 

589 return phi_params.lambda1 + phi_params.lambda2 * theta * rs ** (1 / 2) 

590 

591 

592def _get_dlambdadrs(rs, theta, phi_params): 

593 """Calculate dlambda / drs.""" 

594 return phi_params.lambda2 * theta / (2 * np.sqrt(rs)) 

595 

596 

597def _get_dlambdadtheta(rs, phi_params): 

598 """Calculate dlambda / dtheta.""" 

599 return phi_params.lambda2 * np.sqrt(rs)