Statistiques
| Révision :

root / ase / md / langevin.py @ 1

Historique | Voir | Annoter | Télécharger (4,21 ko)

1
"""Langevin dynamics class."""
2

    
3

    
4
import sys
5
import numpy as np
6
from numpy.random import standard_normal
7
from ase.md.md import MolecularDynamics
8

    
9
# For parallel GPAW simulations, the random forces should be distributed.
10
if '_gpaw' in sys.modules:
11
    # http://wiki.fysik.dtu.dk/gpaw
12
    from gpaw.mpi import world as gpaw_world
13
else:
14
    gpaw_world = None
15

    
16
class Langevin(MolecularDynamics):
17
    """Langevin (constant N, V, T) molecular dynamics.
18

19
    Usage: Langevin(atoms, dt, temperature, friction)
20

21
    atoms
22
        The list of atoms.
23
        
24
    dt
25
        The time step.
26

27
    temperature
28
        The desired temperature, in energy units.
29

30
    friction
31
        A friction coefficient, typically 1e-4 to 1e-2.
32

33
    fixcm
34
        If True, the position and momentum of the center of mass is
35
        kept unperturbed.  Default: True.
36

37
    The temperature and friction are normally scalars, but in principle one
38
    quantity per atom could be specified by giving an array.
39

40
    This dynamics accesses the atoms using Cartesian coordinates."""
41
    
42
    def __init__(self, atoms, timestep, temperature, friction, fixcm=True,
43
                 trajectory=None, logfile=None, loginterval=1,
44
                 communicator=gpaw_world):
45
        MolecularDynamics.__init__(self, atoms, timestep, trajectory,
46
                                   logfile, loginterval)
47
        self.temp = temperature
48
        self.frict = friction
49
        self.fixcm = fixcm  # will the center of mass be held fixed?
50
        self.communicator = communicator
51
        self.updatevars()
52
        
53
    def set_temperature(self, temperature):
54
        self.temp = temperature
55
        self.updatevars()
56

    
57
    def set_friction(self, friction):
58
        self.frict = friction
59
        self.updatevars()
60

    
61
    def set_timestep(self, timestep):
62
        self.dt = timestep
63
        self.updatevars()
64

    
65
    def updatevars(self):
66
        dt = self.dt
67
        # If the friction is an array some other constants must be arrays too.
68
        self._localfrict = hasattr(self.frict, 'shape')
69
        lt = self.frict * dt
70
        masses = self.masses
71
        sdpos = dt * np.sqrt(self.temp / masses * (2.0/3.0 - 0.5 * lt) * lt)
72
        sdpos.shape = (-1, 1)
73
        sdmom = np.sqrt(self.temp * masses * 2.0 * (1.0 - lt) * lt)
74
        sdmom.shape = (-1, 1)
75
        pmcor = np.sqrt(3.0)/2.0 * (1.0 - 0.125 * lt)
76
        cnst = np.sqrt((1.0 - pmcor) * (1.0 + pmcor))
77

    
78
        act0 = 1.0 - lt + 0.5 * lt * lt
79
        act1 = (1.0 - 0.5 * lt + (1.0/6.0) * lt * lt)
80
        act2 = 0.5 - (1.0/6.0) * lt + (1.0/24.0) * lt * lt
81
        c1 = act1 * dt / masses
82
        c1.shape = (-1, 1)
83
        c2 = act2 * dt * dt / masses
84
        c2.shape = (-1, 1)
85
        c3 = (act1 - act2) * dt
86
        c4 = act2 * dt
87
        del act1, act2
88
        if self._localfrict:
89
            # If the friction is an array, so are these
90
            act0.shape = (-1, 1)
91
            c3.shape = (-1, 1)
92
            c4.shape = (-1, 1)
93
            pmcor.shape = (-1, 1)
94
            cnst.shape = (-1, 1)
95
        self.sdpos = sdpos
96
        self.sdmom = sdmom
97
        self.c1 = c1
98
        self.c2 = c2
99
        self.act0 = act0
100
        self.c3 = c3
101
        self.c4 = c4
102
        self.pmcor = pmcor
103
        self.cnst = cnst
104

    
105
    def step(self, f):
106
        atoms = self.atoms
107
        p = self.atoms.get_momenta()
108

    
109
        random1 = standard_normal(size=(len(atoms), 3))
110
        random2 = standard_normal(size=(len(atoms), 3))
111

    
112
        if self.communicator is not None:
113
            self.communicator.broadcast(random1, 0)
114
            self.communicator.broadcast(random2, 0)
115
        
116
        rrnd = self.sdpos * random1
117
        prnd = (self.sdmom * self.pmcor * random1 +
118
                self.sdmom * self.cnst * random2)
119

    
120
        if self.fixcm:
121
            rrnd = rrnd - np.sum(rrnd, 0) / len(atoms)
122
            prnd = prnd - np.sum(prnd, 0) / len(atoms)
123
            n = len(atoms)
124
            rrnd *= np.sqrt(n / (n - 1.0))
125
            prnd *= np.sqrt(n / (n - 1.0))
126

    
127
        atoms.set_positions(atoms.get_positions() +
128
                            self.c1 * p +
129
                            self.c2 * f + rrnd)
130
        p *= self.act0
131
        p += self.c3 * f + prnd
132
        atoms.set_momenta(p)
133
                      
134
        f = atoms.get_forces()
135
        atoms.set_momenta(p + self.c4 * f)
136
        return f