Coverage for gpaw/utilities/adjust_cell.py: 97%
39 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-14 00:18 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-07-14 00:18 +0000
1import numpy as np
3from ase import Atoms
5from gpaw.utilities import h2gpts
6from gpaw.grid_descriptor import GridDescriptor
9def adjust_cell(atoms: Atoms,
10 border: float,
11 h: float = 0.2,
12 idiv: int = 4) -> None:
13 """Adjust the cell such that
14 1. The vacuum around all atoms is at least border
15 in non-periodic directions
16 2. The grid spacing chosen by GPAW will be as similar
17 as possible to h in all directions
18 """
19 n_pbc = atoms.pbc.sum()
20 if n_pbc == 3:
21 return
23 pos_ac = atoms.get_positions()
24 lowest_c = np.minimum.reduce(pos_ac)
25 largest_c = np.maximum.reduce(pos_ac)
27 for i, v_c, in enumerate(atoms.cell):
28 if (v_c == 0).all():
29 assert not atoms.pbc[i] # pbc with zero cell size make no sense
30 atoms.cell[i, i] = 1
32 if n_pbc:
33 N_c = h2gpts(h, atoms.cell, idiv)
34 gd = GridDescriptor(N_c, atoms.cell, atoms.pbc)
35 h_c = gd.get_grid_spacings()
36 h = 0
37 for pbc, h1 in zip(atoms.pbc, h_c):
38 if pbc:
39 h += h1 / n_pbc
41 # the optimal h to be set to non-periodic directions
42 h_c = np.array([h, h, h])
44 shift_c = np.zeros(3)
46 # adjust each cell direction
47 for i in range(3):
48 if atoms.pbc[i]:
49 continue
51 # cell direction
52 u_c = atoms.cell[i] / np.linalg.norm(atoms.cell[i])
54 extension = (largest_c - lowest_c) * u_c
55 min_size = extension + 2 * border
57 h = h_c[i]
58 N = min_size / h
59 N = -(N // -idiv) * idiv # ceil div
60 size = N * h
62 atoms.cell[i] = size * u_c
64 # shift structure to the center
65 shift_c += (size - extension) / 2 * u_c
66 shift_c -= lowest_c * u_c
68 atoms.translate(shift_c)