File: relax_attaches.py

package info (click to toggle)
python-ase 3.26.0-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 15,484 kB
  • sloc: python: 148,112; xml: 2,728; makefile: 110; javascript: 47
file content (82 lines) | stat: -rw-r--r-- 2,510 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# fmt: off

""" An object which can be associated with a local relaxation in order
to make the relaxations run more smoothly."""
from math import sqrt

import numpy as np


class VariansBreak:

    """ Helper class which can be attached to a structure optimization,
        in order to terminale stalling calculations.

        Parameters:

        atoms: Atoms object being optimized
        dyn: The relaxation object being used
        min_stdev: The limiting std. deviation in forces to terminate at
        N: The number of steps used to calculate the st. dev.
    """

    def __init__(self, atoms, dyn, min_stdev=0.005, N=15):
        self.atoms = atoms
        self.dyn = dyn
        self.N = N
        self.forces = []
        self.min_stdev = min_stdev

    def write(self):
        """ The method called by the optimizer in each step. """
        if len(self.forces) >= self.N:
            self.forces.pop(0)
        fmax = (self.atoms.get_forces()**2).sum(axis=1).max()**0.5
        self.forces.append(fmax)

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

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

        if len(self.forces) >= self.N and stdev < self.min_stdev:
            self.dyn.converged = lambda x: True


class DivergenceBreak:

    """ Helper class which can be attached to a structure optimization,
        in order to terminate diverging calculations.

        Parameters:

        atoms: Atoms object being optimized
        dyn: The relaxation object being used
        N: The maximum number of recent steps to be included in the
           evaluation of the slope
        Nmin: The minimal amount of steps required before evaluating
              the slope
    """

    def __init__(self, atoms, dyn, N=15, Nmin=5):
        self.atoms = atoms
        self.dyn = dyn
        self.N = N
        self.Nmin = 5
        self.energies = []

    def write(self):
        """ The method called by the optimizer in each step. """

        if len(self.energies) >= self.N:
            self.energies.pop(0)
        self.energies.append(self.atoms.get_potential_energy())

        if len(self.energies) > self.Nmin:
            x = np.array(range(len(self.energies)))
            y = np.array(self.energies)
            A = np.vstack([x, np.ones(len(x))]).T
            slope, _intersect = np.linalg.lstsq(A, y)[0]

            if len(self.energies) >= self.N and slope > 0:
                self.dyn.converged = lambda x: True