Coverage for /builds/ase/ase/ase/ga/relax_attaches.py: 22.22%

36 statements  

« prev     ^ index     » next       coverage.py v7.5.3, created at 2025-08-02 00:12 +0000

1# fmt: off 

2 

3""" An object which can be associated with a local relaxation in order 

4to make the relaxations run more smoothly.""" 

5from math import sqrt 

6 

7import numpy as np 

8 

9 

10class VariansBreak: 

11 

12 """ Helper class which can be attached to a structure optimization, 

13 in order to terminale stalling calculations. 

14 

15 Parameters: 

16 

17 atoms: Atoms object being optimized 

18 dyn: The relaxation object being used 

19 min_stdev: The limiting std. deviation in forces to terminate at 

20 N: The number of steps used to calculate the st. dev. 

21 """ 

22 

23 def __init__(self, atoms, dyn, min_stdev=0.005, N=15): 

24 self.atoms = atoms 

25 self.dyn = dyn 

26 self.N = N 

27 self.forces = [] 

28 self.min_stdev = min_stdev 

29 

30 def write(self): 

31 """ The method called by the optimizer in each step. """ 

32 if len(self.forces) >= self.N: 

33 self.forces.pop(0) 

34 fmax = (self.atoms.get_forces()**2).sum(axis=1).max()**0.5 

35 self.forces.append(fmax) 

36 

37 m = sum(self.forces) / float(len(self.forces)) 

38 

39 stdev = sqrt( 

40 (sum((c - m)**2 for c in self.forces) / float(len(self.forces)))) 

41 

42 if len(self.forces) >= self.N and stdev < self.min_stdev: 

43 self.dyn.converged = lambda x: True 

44 

45 

46class DivergenceBreak: 

47 

48 """ Helper class which can be attached to a structure optimization, 

49 in order to terminate diverging calculations. 

50 

51 Parameters: 

52 

53 atoms: Atoms object being optimized 

54 dyn: The relaxation object being used 

55 N: The maximum number of recent steps to be included in the 

56 evaluation of the slope 

57 Nmin: The minimal amount of steps required before evaluating 

58 the slope 

59 """ 

60 

61 def __init__(self, atoms, dyn, N=15, Nmin=5): 

62 self.atoms = atoms 

63 self.dyn = dyn 

64 self.N = N 

65 self.Nmin = 5 

66 self.energies = [] 

67 

68 def write(self): 

69 """ The method called by the optimizer in each step. """ 

70 

71 if len(self.energies) >= self.N: 

72 self.energies.pop(0) 

73 self.energies.append(self.atoms.get_potential_energy()) 

74 

75 if len(self.energies) > self.Nmin: 

76 x = np.array(range(len(self.energies))) 

77 y = np.array(self.energies) 

78 A = np.vstack([x, np.ones(len(x))]).T 

79 slope, _intersect = np.linalg.lstsq(A, y)[0] 

80 

81 if len(self.energies) >= self.N and slope > 0: 

82 self.dyn.converged = lambda x: True