Statistiques
| Révision :

root / ase / calculators / test.py @ 20

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

1 1 tkerber
from math import pi
2 1 tkerber
3 1 tkerber
import numpy as np
4 1 tkerber
5 1 tkerber
from ase.atoms import Atoms
6 1 tkerber
7 1 tkerber
8 1 tkerber
def make_test_dft_calculation():
9 1 tkerber
    a = b = 2.0
10 1 tkerber
    c = 6.0
11 1 tkerber
    atoms = Atoms(positions=[(0, 0, c / 2)],
12 1 tkerber
                  symbols='H',
13 1 tkerber
                  pbc=(1, 1, 0),
14 1 tkerber
                  cell=(a, b, c),
15 1 tkerber
                  calculator=TestCalculator())
16 1 tkerber
    return atoms
17 1 tkerber
18 1 tkerber
19 1 tkerber
class TestCalculator:
20 1 tkerber
    def __init__(self, nk=8):
21 1 tkerber
        assert nk % 2 == 0
22 1 tkerber
        bzk = []
23 1 tkerber
        weights = []
24 1 tkerber
        ibzk = []
25 1 tkerber
        w = 1.0 / nk**2
26 1 tkerber
        for i in range(-nk + 1, nk, 2):
27 1 tkerber
            for j in range(-nk + 1, nk, 2):
28 1 tkerber
                k = (0.5 * i / nk, 0.5 * j / nk, 0)
29 1 tkerber
                bzk.append(k)
30 1 tkerber
                if i >= j > 0:
31 1 tkerber
                    ibzk.append(k)
32 1 tkerber
                    if i == j:
33 1 tkerber
                        weights.append(4 * w)
34 1 tkerber
                    else:
35 1 tkerber
                        weights.append(8 * w)
36 1 tkerber
        assert abs(sum(weights) - 1.0) < 1e-12
37 1 tkerber
        self.bzk = np.array(bzk)
38 1 tkerber
        self.ibzk = np.array(ibzk)
39 1 tkerber
        self.weights = np.array(weights)
40 1 tkerber
41 1 tkerber
        # Calculate eigenvalues and wave functions:
42 1 tkerber
        self.init()
43 1 tkerber
44 1 tkerber
    def init(self):
45 1 tkerber
        nibzk = len(self.weights)
46 1 tkerber
        nbands = 1
47 1 tkerber
48 1 tkerber
        V = -1.0
49 1 tkerber
        self.eps = 2 * V * (np.cos(2 * pi * self.ibzk[:, 0]) +
50 1 tkerber
                            np.cos(2 * pi * self.ibzk[:, 1]))
51 1 tkerber
        self.eps.shape = (nibzk, nbands)
52 1 tkerber
53 1 tkerber
        self.psi = np.zeros((nibzk, 20, 20, 60), complex)
54 1 tkerber
        phi = np.empty((2, 2, 20, 20, 60))
55 1 tkerber
        z = np.linspace(-1.5, 1.5, 60, endpoint=False)
56 1 tkerber
        for i in range(2):
57 1 tkerber
            x = np.linspace(0, 1, 20, endpoint=False) - i
58 1 tkerber
            for j in range(2):
59 1 tkerber
                y = np.linspace(0, 1, 20, endpoint=False) - j
60 1 tkerber
                r = (((x[:, None]**2 +
61 1 tkerber
                       y**2)[:, :, None] +
62 1 tkerber
                      z**2)**0.5).clip(0, 1)
63 1 tkerber
                phi = 1.0 - r**2 * (3.0 - 2.0 * r)
64 1 tkerber
                phase = np.exp(pi * 2j * np.dot(self.ibzk, (i, j, 0)))
65 1 tkerber
                self.psi += phase[:, None, None, None] * phi
66 1 tkerber
67 1 tkerber
    def get_pseudo_wave_function(self, band=0, kpt=0, spin=0):
68 1 tkerber
        assert spin == 0 and band == 0
69 1 tkerber
        return self.psi[kpt]
70 1 tkerber
71 1 tkerber
    def get_eigenvalues(self, kpt=0, spin=0):
72 1 tkerber
        assert spin == 0
73 1 tkerber
        return self.eps[kpt]
74 1 tkerber
75 1 tkerber
    def get_number_of_bands(self):
76 1 tkerber
        return 1
77 1 tkerber
78 1 tkerber
    def get_k_point_weights(self):
79 1 tkerber
        return self.weights
80 1 tkerber
81 1 tkerber
    def get_number_of_spins(self):
82 1 tkerber
        return 1
83 1 tkerber
84 1 tkerber
    def get_fermi_level(self):
85 1 tkerber
        return 0.0
86 1 tkerber
87 1 tkerber
88 1 tkerber
class TestPotential:
89 1 tkerber
    def get_forces(self, atoms):
90 1 tkerber
        E = 0.0
91 1 tkerber
        R = atoms.positions
92 1 tkerber
        F = np.zeros_like(R)
93 1 tkerber
        for a, r in enumerate(R):
94 1 tkerber
            D = R - r
95 1 tkerber
            d = (D**2).sum(1)**0.5
96 1 tkerber
            x = d - 1.0
97 1 tkerber
            E += np.vdot(x, x)
98 1 tkerber
            d[a] = 1
99 1 tkerber
            F -= (x / d)[:, None] * D
100 1 tkerber
        self.energy = 0.25 * E
101 1 tkerber
        return F
102 1 tkerber
103 1 tkerber
    def get_potential_energy(self, atoms):
104 1 tkerber
        self.get_forces(atoms)
105 1 tkerber
        return self.energy
106 1 tkerber
107 1 tkerber
    def get_stress(self, atoms):
108 1 tkerber
        raise NotImplementedError
109 1 tkerber
110 1 tkerber
111 1 tkerber
def numeric_force(atoms, a, i, d=0.001):
112 1 tkerber
    """Evaluate force along i'th axis on a'th atom using finite difference.
113 1 tkerber

114 1 tkerber
    This will trigger two calls to get_potential_energy(), with atom a moved
115 1 tkerber
    plus/minus d in the i'th axial direction, respectively.
116 1 tkerber
    """
117 1 tkerber
    p0 = atoms.positions[a, i]
118 1 tkerber
    atoms.positions[a, i] += d
119 1 tkerber
    eplus = atoms.get_potential_energy()
120 1 tkerber
    atoms.positions[a, i] -= 2 * d
121 1 tkerber
    eminus = atoms.get_potential_energy()
122 1 tkerber
    atoms.positions[a, i] = p0
123 1 tkerber
    return (eminus - eplus) / (2 * d)
124 1 tkerber
125 1 tkerber
126 1 tkerber
def numeric_forces(atoms, indices=None, axes=(0, 1, 2), d=0.001):
127 1 tkerber
    """Evaluate finite-difference forces on several atoms.
128 1 tkerber

129 1 tkerber
    Returns an array of forces for each specified atomic index and
130 1 tkerber
    each specified axis, calculated using finite difference on each
131 1 tkerber
    atom and direction separately.  Array has same shape as if
132 1 tkerber
    returned from atoms.get_forces(); uncalculated elements are zero.
133 1 tkerber

134 1 tkerber
    Calculates all forces by default."""
135 1 tkerber
136 1 tkerber
    if indices is None:
137 1 tkerber
        indices = range(len(atoms))
138 1 tkerber
    F_ai = np.zeros_like(atoms.positions)
139 1 tkerber
    for a in indices:
140 1 tkerber
        for i in axes:
141 1 tkerber
            F_ai[a, i] = numeric_force(atoms, a, i, d)
142 1 tkerber
    return F_ai