Coverage for /builds/ase/ase/ase/cluster/icosahedron.py: 98.25%
57 statements
« prev ^ index » next coverage.py v7.5.3, created at 2025-08-02 00:12 +0000
« prev ^ index » next coverage.py v7.5.3, created at 2025-08-02 00:12 +0000
1# fmt: off
3import numpy as np
5from ase import Atoms
6from ase.cluster.util import get_element_info
9def Icosahedron(symbol, noshells, latticeconstant=None):
10 """
11 Returns a cluster with the icosahedra symmetry.
13 Parameters
14 ----------
15 symbol : str or int
16 The chemical symbol (or atomic number) of the element.
18 noshells : int
19 The number of shells (>= 1).
21 latticeconstant : float, optional
22 The lattice constant. If not given, then it is extracted from
23 `ase.data`.
24 """
26 symbol, atomic_number, latticeconstant = get_element_info(
27 symbol, latticeconstant)
29 # Interpret noshells
30 if noshells < 1:
31 raise ValueError(
32 "The number of shells must be equal to or greater than one.")
34 t = 0.5 + np.sqrt(5) / 2.0
36 verticies = np.array([[t, 0., 1.],
37 [t, 0., -1.],
38 [-t, 0., 1.],
39 [-t, 0., -1.],
40 [1., t, 0.],
41 [-1., t, 0.],
42 [1., -t, 0.],
43 [-1., -t, 0.],
44 [0., 1., t],
45 [0., -1., t],
46 [0., 1., -t],
47 [0., -1., -t]])
49 positions = []
50 tags = []
51 positions.append(np.zeros(3))
52 tags.append(1)
54 for n in range(1, noshells):
55 # Construct square edges (6)
56 for k in range(0, 12, 2):
57 v1 = verticies[k]
58 v2 = verticies[k + 1]
59 for i in range(n + 1):
60 pos = i * v1 + (n - i) * v2
61 positions.append(pos)
62 tags.append(n + 1)
64 # Construct triangle planes (12)
65 if n > 1:
66 map = {0: (8, 9), 1: (10, 11),
67 2: (8, 9), 3: (10, 11),
68 4: (0, 1), 5: (2, 3),
69 6: (0, 1), 7: (2, 3),
70 8: (4, 5), 9: (6, 7),
71 10: (4, 5), 11: (6, 7)}
73 for k in range(12):
74 v0 = n * verticies[k]
75 v1 = (verticies[map[k][0]] - verticies[k])
76 v2 = (verticies[map[k][1]] - verticies[k])
77 for i in range(n):
78 for j in range(n - i):
79 if i == 0 and j == 0:
80 continue
81 pos = v0 + i * v1 + j * v2
82 positions.append(pos)
83 tags.append(n + 1)
85 # Fill missing triangle planes (8)
86 if n > 2:
87 map = {0: (9, 6, 8, 4,),
88 1: (11, 6, 10, 4),
89 2: (9, 7, 8, 5,),
90 3: (11, 7, 10, 5)}
92 for k in range(4):
93 v0 = n * verticies[k]
94 v1 = (verticies[map[k][0]] - verticies[k])
95 v2 = (verticies[map[k][1]] - verticies[k])
96 v3 = (verticies[map[k][2]] - verticies[k])
97 v4 = (verticies[map[k][3]] - verticies[k])
98 for i in range(1, n):
99 for j in range(1, n - i):
100 pos = v0 + i * v1 + j * v2
101 positions.append(pos)
102 tags.append(n + 1)
103 pos = v0 + i * v3 + j * v4
104 positions.append(pos)
105 tags.append(n + 1)
107 # Scale the positions
108 scaling_factor = latticeconstant / np.sqrt(2 * (1 + t**2))
109 positions = np.array(positions) * scaling_factor
111 symbols = [atomic_number] * len(positions)
112 atoms = Atoms(symbols=symbols, positions=positions, tags=tags)
113 atoms.center(about=(0, 0, 0))
114 atoms.cell[:] = 0
115 return atoms