Coverage for gpaw/new/energies.py: 85%

55 statements  

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

1"""PAW-DFT energy-contributions.""" 

2 

3from ase.units import Ha 

4 

5# Contributions to free energy: 

6NAMES = ['kinetic', 'coulomb', 'zero', 'external', 'xc', 'entropy', 

7 'spinorbit'] 

8 

9# Other allowed names: 

10OTHERS = {'band', 'kinetic_correction', 'extrapolation', 

11 'hybrid_kinetic_correction', 'hybrid_xc'} 

12 

13 

14class DFTEnergies: 

15 def __init__(self, **energies: float): 

16 self._energies: dict[str, float] = {} 

17 self._total_free: float | None 

18 self.set(**energies) 

19 

20 def set(self, **energies: float) -> None: 

21 # assert energies.keys() <= set(NAMES) | OTHERS, energies 

22 self._energies.update(energies) 

23 self._total_free = None 

24 

25 @property 

26 def kinetic(self): 

27 e = self._energies.get('kinetic') 

28 if e is not None: 

29 return e 

30 # Use Kohn-Sham eq. to get kinetic energy as sum over 

31 # occupied eigenvalues + correction: 

32 return (self._energies['band'] + 

33 self._energies['kinetic_correction'] + 

34 self._energies.get('hybrid_kinetic_correction', 0.0)) 

35 

36 @property 

37 def total_free(self) -> float: 

38 if self._total_free is None: 

39 energies = self._energies.copy() 

40 energies['kinetic'] = self.kinetic 

41 if 'hybrid_xc' in energies: 

42 energies['xc'] += energies['hybrid_xc'] 

43 self._total_free = sum(energies.get(name, 0.0) for name in energies 

44 if name not in OTHERS) 

45 return self._total_free 

46 

47 @property 

48 def total_extrapolated(self) -> float: 

49 return self.total_free + self._energies['extrapolation'] 

50 

51 def __repr__(self) -> str: 

52 s = ', '.join(f'{k}={v}' for k, v in self._energies.items()) 

53 return f'DFTEnergies({s})' 

54 

55 @property 

56 def extensions_energies(self) -> list[tuple[str, float]]: 

57 return [(name, self._energies.get(name, 0.0)) 

58 for name in self._energies 

59 if name not in OTHERS and name not in NAMES] 

60 

61 def summary(self, log) -> None: 

62 for name in NAMES: 

63 if name in OTHERS: 

64 continue 

65 e = self._energies.get(name) 

66 if e is None: 

67 if name != 'kinetic': 

68 continue 

69 e = self.kinetic 

70 log(f'{name + ":":10} {e * Ha:14.6f}') 

71 extensions = self.extensions_energies 

72 if extensions: 

73 log('--------extensions:---------') 

74 for name, e in extensions: 

75 log(f'{name + ":":12} {e * Ha:14.6f}') 

76 log('----------------------------') 

77 log(f'Free energy: {self.total_free * Ha:14.6f}') 

78 log(f'Extrapolated:{self.total_extrapolated * Ha:14.6f}\n') 

79 

80 def write_to_gpw(self, writer): 

81 writer.write(**{name: e * Ha for name, e in self._energies.items()})