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
5class LinearCombinationCalculator(Calculator):
6 """LinearCombinationCalculator for weighted summation of multiple calculators.
7 """
9 def __init__(self, calcs, weights, atoms=None):
10 """Implementation of sum of calculators.
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 """
20 super().__init__(atoms=atoms)
22 if len(calcs) == 0:
23 raise ValueError('The value of the calcs must be a list of Calculators')
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')
29 common_properties = set.intersection(*(set(calc.implemented_properties) for calc in calcs))
30 self.implemented_properties = list(common_properties)
32 if not self.implemented_properties:
33 raise PropertyNotImplementedError('There are no common property implemented for the potentials!')
35 if len(weights) != len(calcs):
36 raise ValueError('The length of the weights must be the same as the number of calculators!')
38 self.calcs = calcs
39 self.weights = weights
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 """
45 super().calculate(atoms, properties, system_changes)
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))
51 for w, calc in zip(self.weights, self.calcs):
52 if calc.calculation_required(atoms, properties):
53 calc.calculate(atoms, properties, system_changes)
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]
61 def reset(self):
62 """Clear all previous results recursively from all fo the calculators."""
63 super().reset()
65 for calc in self.calcs:
66 calc.reset()
68 def __str__(self):
69 calculators = ', '.join(calc.__class__.__name__ for calc in self.calcs)
70 return '{}({})'.format(self.__class__.__name__, calculators)
73class MixedCalculator(LinearCombinationCalculator):
74 """
75 Mixing of two calculators with different weights
77 H = weight1 * H1 + weight2 * H2
79 Has functionality to get the energy contributions from each calculator
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 """
91 def __init__(self, calc1, calc2, weight1, weight2):
92 super().__init__([calc1, calc2], [weight1, weight2])
94 def set_weights(self, w1, w2):
95 self.weights[0] = w1
96 self.weights[1] = w2
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 """
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)
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']
114class SumCalculator(LinearCombinationCalculator):
115 """SumCalculator for combining multiple calculators.
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 """
123 def __init__(self, calcs, atoms=None):
124 """Implementation of sum of calculators.
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 """
132 weights = [1.] * len(calcs)
133 super().__init__(calcs, weights, atoms)
136class AverageCalculator(LinearCombinationCalculator):
137 """AverageCalculator for equal summation of multiple calculators (for thermodynamic purposes)..
138 """
140 def __init__(self, calcs, atoms=None):
141 """Implementation of average of calculators.
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 """
149 n = len(calcs)
151 if n == 0:
152 raise ValueError('The value of the calcs must be a list of Calculators')
154 weights = [1 / n] * n
155 super().__init__(calcs, weights, atoms)