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
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-20 00:19 +0000
1"""PAW-DFT energy-contributions."""
3from ase.units import Ha
5# Contributions to free energy:
6NAMES = ['kinetic', 'coulomb', 'zero', 'external', 'xc', 'entropy',
7 'spinorbit']
9# Other allowed names:
10OTHERS = {'band', 'kinetic_correction', 'extrapolation',
11 'hybrid_kinetic_correction', 'hybrid_xc'}
14class DFTEnergies:
15 def __init__(self, **energies: float):
16 self._energies: dict[str, float] = {}
17 self._total_free: float | None
18 self.set(**energies)
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
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))
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
47 @property
48 def total_extrapolated(self) -> float:
49 return self.total_free + self._energies['extrapolation']
51 def __repr__(self) -> str:
52 s = ', '.join(f'{k}={v}' for k, v in self._energies.items())
53 return f'DFTEnergies({s})'
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]
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')
80 def write_to_gpw(self, writer):
81 writer.write(**{name: e * Ha for name, e in self._energies.items()})