|
23 | 23 | from .utils.mathematics import fnorm |
24 | 24 | from .quaternion import Quaternion |
25 | 25 | from .supercell import SuperCell, SuperCellChild |
26 | | -from .atom import Atom, Atoms |
| 26 | +from .atom import Atom, Atoms, PeriodicTable |
27 | 27 | from .shape import Shape, Sphere, Cube |
28 | 28 | from ._namedindex import NamedIndex |
29 | 29 |
|
@@ -3066,6 +3066,68 @@ def bond_correct(self, ia, atom, method='calc'): |
3066 | 3066 | raise NotImplementedError( |
3067 | 3067 | 'Changing bond-length dependent on several lacks implementation.') |
3068 | 3068 |
|
| 3069 | + def bond_completion(self, nbonds, atom=None, bond=None, idx=None): |
| 3070 | + """ Return a new geometry with additional atoms added to complete the number of bonds |
| 3071 | +
|
| 3072 | + This function may be useful to saturate dangling bonds at edges in sp2-carbon structures, |
| 3073 | + e.g., with H-atoms. |
| 3074 | +
|
| 3075 | + Parameters |
| 3076 | + ---------- |
| 3077 | + nbonds : int |
| 3078 | + number of bonds requested |
| 3079 | + atom : `Atom`, optional |
| 3080 | + the kind of atom to be added, where missing. Defaults to atoms of the same type. |
| 3081 | + bond, float, optional |
| 3082 | + bond length to the extra atoms. Defaults to value from `PeriodicTable` |
| 3083 | + idx : array_like, optional |
| 3084 | + List of indices for atoms that are to be considered |
| 3085 | +
|
| 3086 | + Examples |
| 3087 | + -------- |
| 3088 | + >>> g = geom.graphene(orthogonal=True).tile(3, 0).tile(4, 1) |
| 3089 | + >>> g.cell[0] *= 2 |
| 3090 | + >>> g.bond_completion(3, atom=Atom(1), bond=1.09) |
| 3091 | + """ |
| 3092 | + |
| 3093 | + if idx is not None: |
| 3094 | + if not isndarray(idx): |
| 3095 | + selection = _a.asarrayi(idx).ravel() |
| 3096 | + else: |
| 3097 | + selection = range(len(self)) |
| 3098 | + |
| 3099 | + new_xyz = [] |
| 3100 | + new_atom = [] |
| 3101 | + |
| 3102 | + PT = PeriodicTable() |
| 3103 | + |
| 3104 | + for ia in selection: |
| 3105 | + iaZ = self.atoms[ia].Z |
| 3106 | + ria = PT.radius(iaZ) |
| 3107 | + idx = self.close(ia, R=(0.1, 0.1 + 2 * ria))[1] |
| 3108 | + if len(idx) == nbonds - 1: |
| 3109 | + # Add one bond |
| 3110 | + if atom is None: |
| 3111 | + atom = Atom(iaZ, R=self.atoms[ia].R) |
| 3112 | + if bond is None: |
| 3113 | + bond_length = ria + PT.radius(atom.Z) |
| 3114 | + else: |
| 3115 | + bond_length = bond |
| 3116 | + # Compute bond vector |
| 3117 | + bvec = len(idx) * self.xyz[ia] |
| 3118 | + for jdx in idx: |
| 3119 | + bvec -= self.axyz(jdx) |
| 3120 | + bnorm = bvec.dot(bvec) ** .5 |
| 3121 | + if bnorm > 0.1: |
| 3122 | + # only add to geometry if new position is away from ia-atom |
| 3123 | + bvec *= bond_length / bnorm |
| 3124 | + new_xyz.append(self.xyz[ia] + bvec) |
| 3125 | + new_atom.append(atom) |
| 3126 | + if len(new_xyz) > 0: |
| 3127 | + return self.add(self.__class__(new_xyz, new_atom)) |
| 3128 | + else: |
| 3129 | + return self.copy() |
| 3130 | + |
3069 | 3131 | def within(self, shapes, |
3070 | 3132 | idx=None, idx_xyz=None, |
3071 | 3133 | ret_xyz=False, ret_rij=False): |
|
0 commit comments