root / ase / calculators / test.py @ 2
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 |