Coverage for /builds/ase/ase/ase/cluster/cluster.py: 41.18%
51 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 math
5import numpy as np
7from ase import Atoms
8from ase.cluster.base import ClusterBase
11class Cluster(Atoms, ClusterBase):
12 symmetry = None
13 surfaces = None
14 lattice_basis = None
15 resiproc_basis = None
16 atomic_basis = None
18 def copy(self):
19 cluster = Atoms.copy(self)
20 cluster.symmetry = self.symmetry
21 cluster.surfaces = self.surfaces.copy()
22 cluster.lattice_basis = self.lattice_basis.copy()
23 cluster.atomic_basis = self.atomic_basis.copy()
24 cluster.resiproc_basis = self.resiproc_basis.copy()
25 return cluster
27 def get_surfaces(self):
28 """Returns the miller indexs of the stored surfaces of the cluster."""
29 if self.surfaces is not None:
30 return self.surfaces.copy()
31 else:
32 return None
34 def get_layers(self):
35 """Return number of atomic layers in stored surfaces directions."""
37 layers = []
39 for s in self.surfaces:
40 n = self.miller_to_direction(s)
41 c = self.get_positions().mean(axis=0)
42 r = np.dot(self.get_positions() - c, n).max()
43 d = self.get_layer_distance(s, 2)
44 l_ = 2 * np.round(r / d).astype(int)
46 ls = np.arange(l_ - 1, l_ + 2)
47 ds = np.array([self.get_layer_distance(s, i) for i in ls])
49 mask = (np.abs(ds - r) < 1e-10)
51 layers.append(ls[mask][0])
53 return np.array(layers, int)
55 def get_diameter(self, method='volume'):
56 """Returns an estimate of the cluster diameter based on two different
57 methods.
59 Parameters
60 ----------
61 method : {'volume', 'shape'}
62 'volume' (default) returns the diameter of a sphere with the same
63 volume as the atoms. 'shape' returns the averaged diameter
64 calculated from the directions given by the defined surfaces.
65 """
67 if method == 'shape':
68 cen = self.get_positions().mean(axis=0)
69 pos = self.get_positions() - cen
70 d = 0.0
71 for s in self.surfaces:
72 n = self.miller_to_direction(s)
73 r = np.dot(pos, n)
74 d += r.max() - r.min()
75 return d / len(self.surfaces)
76 elif method == 'volume':
77 V_cell = np.abs(np.linalg.det(self.lattice_basis))
78 N_cell = len(self.atomic_basis)
79 N = len(self)
80 return 2.0 * (3.0 * N * V_cell /
81 (4.0 * math.pi * N_cell)) ** (1.0 / 3.0)
82 else:
83 return 0.0