Skip to content

Commit 98f44d2

Browse files
committed
enh: initial code for bond completion (bond saturation)
1 parent 07fa7aa commit 98f44d2

File tree

1 file changed

+63
-1
lines changed

1 file changed

+63
-1
lines changed

sisl/geometry.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from .utils.mathematics import fnorm
2424
from .quaternion import Quaternion
2525
from .supercell import SuperCell, SuperCellChild
26-
from .atom import Atom, Atoms
26+
from .atom import Atom, Atoms, PeriodicTable
2727
from .shape import Shape, Sphere, Cube
2828
from ._namedindex import NamedIndex
2929

@@ -3066,6 +3066,68 @@ def bond_correct(self, ia, atom, method='calc'):
30663066
raise NotImplementedError(
30673067
'Changing bond-length dependent on several lacks implementation.')
30683068

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+
30693131
def within(self, shapes,
30703132
idx=None, idx_xyz=None,
30713133
ret_xyz=False, ret_rij=False):

0 commit comments

Comments
 (0)