Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2This module defines abstract helper classes with the objective of reducing 

3boilerplace method definitions (i.e. duplication) in calculators. 

4""" 

5 

6from abc import ABC, abstractmethod 

7from typing import Mapping, Any 

8 

9 

10class GetPropertiesMixin(ABC): 

11 """Mixin class which provides get_forces(), get_stress() and so on. 

12 

13 Inheriting class must implement get_property().""" 

14 

15 @abstractmethod 

16 def get_property(self, name, atoms=None, allow_calculation=True): 

17 """Get the named property.""" 

18 

19 def get_potential_energy(self, atoms=None, force_consistent=False): 

20 if force_consistent: 

21 name = 'free_energy' 

22 else: 

23 name = 'energy' 

24 return self.get_property(name, atoms) 

25 

26 def get_potential_energies(self, atoms=None): 

27 return self.get_property('energies', atoms) 

28 

29 def get_forces(self, atoms=None): 

30 return self.get_property('forces', atoms) 

31 

32 def get_stress(self, atoms=None): 

33 return self.get_property('stress', atoms) 

34 

35 def get_stresses(self, atoms=None): 

36 """the calculator should return intensive stresses, i.e., such that 

37 stresses.sum(axis=0) == stress 

38 """ 

39 return self.get_property('stresses', atoms) 

40 

41 def get_dipole_moment(self, atoms=None): 

42 return self.get_property('dipole', atoms) 

43 

44 def get_charges(self, atoms=None): 

45 return self.get_property('charges', atoms) 

46 

47 def get_magnetic_moment(self, atoms=None): 

48 return self.get_property('magmom', atoms) 

49 

50 def get_magnetic_moments(self, atoms=None): 

51 """Calculate magnetic moments projected onto atoms.""" 

52 return self.get_property('magmoms', atoms) 

53 

54 

55class GetOutputsMixin(ABC): 

56 """Mixin class for providing get_fermi_level() and others. 

57 

58 Effectively this class expresses data in calc.results as 

59 methods such as get_fermi_level(). 

60 

61 Inheriting class must implement _outputmixin_get_results(), 

62 typically returning self.results, which must be a mapping 

63 using the naming defined in ase.outputs.Properties. 

64 """ 

65 @abstractmethod 

66 def _outputmixin_get_results(self) -> Mapping[str, Any]: 

67 """Return Mapping of names to result value. 

68 

69 This may be called many times and should hence not be 

70 expensive (except possibly the first time).""" 

71 

72 def _get(self, name): 

73 # Cyclic import, should restructure. 

74 from ase.calculators.calculator import PropertyNotPresent 

75 dct = self._outputmixin_get_results() 

76 try: 

77 return dct[name] 

78 except KeyError: 

79 raise PropertyNotPresent(name) 

80 

81 def get_fermi_level(self): 

82 return self._get('fermi_level') 

83 

84 def get_ibz_k_points(self): 

85 return self._get('ibz_kpoints') 

86 

87 def get_k_point_weights(self): 

88 return self._get('kpoint_weights') 

89 

90 def get_eigenvalues(self, kpt=0, spin=0): 

91 eigs = self._get('eigenvalues') 

92 return eigs[kpt, spin] 

93 

94 def _eigshape(self): 

95 # We don't need this if we already have a Properties object. 

96 return self._get('eigenvalues').shape 

97 

98 def get_occupation_numbers(self, kpt=0, spin=0): 

99 occs = self._get('occupations') 

100 return occs[kpt, spin] 

101 

102 def get_number_of_bands(self): 

103 return self._eigshape()[2] 

104 

105 def get_number_of_spins(self): 

106 nspins = self._eigshape()[0] 

107 assert nspins in [1, 2] 

108 return nspins 

109 

110 def get_spin_polarized(self): 

111 return self.get_number_of_spins() == 2