Statistiques
| Révision :

root / ase / md / logger.py @ 20

Historique | Voir | Annoter | Télécharger (3,17 ko)

1
"""Logging for molecular dynamics."""
2

    
3
import weakref
4
import sys
5
import ase.units as units
6
# ase.parallel imported in __init__
7

    
8
class MDLogger:
9
    """Class for logging molecular dynamics simulations.
10

11
    Parameters:
12
    dyn:           The dynamics.  Only a weak reference is kept.
13

14
    atoms:         The atoms.
15

16
    logfile:       File name or open file, "-" meaning standart output.
17

18
    stress=False:  Include stress in log.
19

20
    peratom=False: Write energies per atom.
21

22
    mode="a":      How the file is opened if logfile is a filename.
23
    """
24
    def __init__(self, dyn, atoms, logfile, header=True, stress=False,
25
                 peratom=False, mode="a"):
26
        import ase.parallel
27
        if ase.parallel.rank > 0:
28
            logfile="/dev/null"  # Only log on master
29
        if hasattr(dyn, "get_time"):
30
            self.dyn = weakref.proxy(dyn)
31
        else:
32
            self.dyn = None
33
        self.atoms = atoms
34
        self.natoms = atoms.get_number_of_atoms()
35
        if logfile == "-":
36
            self.logfile = sys.stdout
37
            self.ownlogfile = False
38
        elif hasattr(logfile, "write"):
39
            self.logfile = logfile
40
            self.ownlogfile = False
41
        else:
42
            self.logfile = open(logfile, mode)
43
            self.ownlogfile = True
44
        self.stress = stress
45
        self.peratom = peratom
46
        if self.dyn is not None:
47
            self.hdr = "%-8s " % ("Time[ps]",)
48
            self.fmt = "%-8.2f "
49
        else:
50
            self.hdr = ""
51
            self.fmt = ""
52
        if self.peratom:
53
            self.hdr += "%12s %12s %12s  %6s" % ("Etot/N[eV]", "Epot/N[eV]",
54
                                                 "Ekin/N[eV]", "T[K]")
55
            self.fmt += "%12.4f %12.4f %12.4f  %6.1f"
56
        else:
57
            self.hdr += "%12s %12s %12s  %6s" % ("Etot[eV]", "Epot[eV]",
58
                                                 "Ekin[eV]", "T[K]")
59
            # Choose a sensible number of decimals
60
            if self.natoms <= 10:
61
                digits = 4
62
            elif self.natoms <= 100:
63
                digits = 3
64
            elif self.natoms <= 1000:
65
                digits = 2
66
            else:
67
                digits = 1
68
            self.fmt += 3*("%%12.%df " % (digits,)) + " %6.1f"
69
        if self.stress:
70
            self.hdr += "---------------- stress [GPa] -----------------"
71
            self.fmt += 6*" %10.3f"
72
        self.fmt += "\n"
73
        if header:
74
            self.logfile.write(self.hdr+"\n")
75
            
76
    def __del__(self):
77
        self.close()
78

    
79
    def close(self):
80
        if self.ownlogfile:
81
            self.logfile.close()
82

    
83
    def __call__(self):
84
        epot = self.atoms.get_potential_energy()
85
        ekin = self.atoms.get_kinetic_energy()
86
        temp = ekin / (1.5 * units.kB * self.natoms)
87
        if self.peratom:
88
            epot /= self.natoms
89
            ekin /= self.natoms
90
        if self.dyn is not None:
91
            t = self.dyn.get_time() / (1000*units.fs)
92
            dat = (t,)
93
        else:
94
            dat = ()
95
        dat += (epot+ekin, epot, ekin, temp)
96
        if self.stress:
97
            dat += tuple(self.atoms.get_stress() / units.GPa)
98
        self.logfile.write(self.fmt % dat)
99
        self.logfile.flush()
100