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

1from ase.calculators.calculator import Calculator, all_changes 

2from ase.calculators.calculator import PropertyNotImplementedError 

3 

4 

5class LinearCombinationCalculator(Calculator): 

6 """LinearCombinationCalculator for weighted summation of multiple calculators. 

7 """ 

8 

9 def __init__(self, calcs, weights, atoms=None): 

10 """Implementation of sum of calculators. 

11 

12 calcs: list 

13 List of an arbitrary number of :mod:`ase.calculators` objects. 

14 weights: list of float 

15 Weights for each calculator in the list. 

16 atoms: Atoms object 

17 Optional :class:`~ase.Atoms` object to which the calculator will be attached. 

18 """ 

19 

20 super().__init__(atoms=atoms) 

21 

22 if len(calcs) == 0: 

23 raise ValueError('The value of the calcs must be a list of Calculators') 

24 

25 for calc in calcs: 

26 if not isinstance(calc, Calculator): 

27 raise ValueError('All the calculators should be inherited form the ase\'s Calculator class') 

28 

29 common_properties = set.intersection(*(set(calc.implemented_properties) for calc in calcs)) 

30 self.implemented_properties = list(common_properties) 

31 

32 if not self.implemented_properties: 

33 raise PropertyNotImplementedError('There are no common property implemented for the potentials!') 

34 

35 if len(weights) != len(calcs): 

36 raise ValueError('The length of the weights must be the same as the number of calculators!') 

37 

38 self.calcs = calcs 

39 self.weights = weights 

40 

41 def calculate(self, atoms=None, properties=['energy'], system_changes=all_changes): 

42 """ Calculates all the specific property for each calculator and returns with the summed value. 

43 """ 

44 

45 super().calculate(atoms, properties, system_changes) 

46 

47 if not set(properties).issubset(self.implemented_properties): 

48 raise PropertyNotImplementedError('Some of the requested property is not in the ' 

49 'list of supported properties ({})'.format(self.implemented_properties)) 

50 

51 for w, calc in zip(self.weights, self.calcs): 

52 if calc.calculation_required(atoms, properties): 

53 calc.calculate(atoms, properties, system_changes) 

54 

55 for k in properties: 

56 if k not in self.results: 

57 self.results[k] = w * calc.results[k] 

58 else: 

59 self.results[k] += w * calc.results[k] 

60 

61 def reset(self): 

62 """Clear all previous results recursively from all fo the calculators.""" 

63 super().reset() 

64 

65 for calc in self.calcs: 

66 calc.reset() 

67 

68 def __str__(self): 

69 calculators = ', '.join(calc.__class__.__name__ for calc in self.calcs) 

70 return '{}({})'.format(self.__class__.__name__, calculators) 

71 

72 

73class MixedCalculator(LinearCombinationCalculator): 

74 """ 

75 Mixing of two calculators with different weights 

76 

77 H = weight1 * H1 + weight2 * H2 

78 

79 Has functionality to get the energy contributions from each calculator 

80 

81 Parameters 

82 ---------- 

83 calc1 : ASE-calculator 

84 calc2 : ASE-calculator 

85 weight1 : float 

86 weight for calculator 1 

87 weight2 : float 

88 weight for calculator 2 

89 """ 

90 

91 def __init__(self, calc1, calc2, weight1, weight2): 

92 super().__init__([calc1, calc2], [weight1, weight2]) 

93 

94 def set_weights(self, w1, w2): 

95 self.weights[0] = w1 

96 self.weights[1] = w2 

97 

98 def calculate(self, atoms=None, properties=['energy'], system_changes=all_changes): 

99 """ Calculates all the specific property for each calculator and returns with the summed value. 

100 """ 

101 

102 super().calculate(atoms, properties, system_changes) 

103 if 'energy' in properties: 

104 energy1 = self.calcs[0].get_property('energy', atoms) 

105 energy2 = self.calcs[1].get_property('energy', atoms) 

106 self.results['energy_contributions'] = (energy1, energy2) 

107 

108 def get_energy_contributions(self, atoms=None): 

109 """ Return the potential energy from calc1 and calc2 respectively """ 

110 self.calculate(properties=['energy'], atoms=atoms) 

111 return self.results['energy_contributions'] 

112 

113 

114class SumCalculator(LinearCombinationCalculator): 

115 """SumCalculator for combining multiple calculators. 

116 

117 This calculator can be used when there are different calculators for the different chemical environment or 

118 for example during delta leaning. It works with a list of arbitrary calculators and evaluates them in sequence 

119 when it is required. 

120 The supported properties are the intersection of the implemented properties in each calculator. 

121 """ 

122 

123 def __init__(self, calcs, atoms=None): 

124 """Implementation of sum of calculators. 

125 

126 calcs: list 

127 List of an arbitrary number of :mod:`ase.calculators` objects. 

128 atoms: Atoms object 

129 Optional :class:`~ase.Atoms` object to which the calculator will be attached. 

130 """ 

131 

132 weights = [1.] * len(calcs) 

133 super().__init__(calcs, weights, atoms) 

134 

135 

136class AverageCalculator(LinearCombinationCalculator): 

137 """AverageCalculator for equal summation of multiple calculators (for thermodynamic purposes).. 

138 """ 

139 

140 def __init__(self, calcs, atoms=None): 

141 """Implementation of average of calculators. 

142 

143 calcs: list 

144 List of an arbitrary number of :mod:`ase.calculators` objects. 

145 atoms: Atoms object 

146 Optional :class:`~ase.Atoms` object to which the calculator will be attached. 

147 """ 

148 

149 n = len(calcs) 

150 

151 if n == 0: 

152 raise ValueError('The value of the calcs must be a list of Calculators') 

153 

154 weights = [1 / n] * n 

155 super().__init__(calcs, weights, atoms)