Skip to content

Commit cf8bde5

Browse files
committed
enh: initial code for bond completion (bond saturation)
1 parent a0da8c8 commit cf8bde5

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
@@ -21,7 +21,7 @@
2121
from .utils.mathematics import fnorm
2222
from .quaternion import Quaternion
2323
from .supercell import SuperCell, SuperCellChild
24-
from .atom import Atom, Atoms
24+
from .atom import Atom, Atoms, PeriodicTable
2525
from .shape import Shape, Sphere, Cube
2626
from ._namedindex import NamedIndex
2727

@@ -2599,6 +2599,68 @@ def bond_correct(self, ia, atom, method='calc'):
25992599
raise NotImplementedError(
26002600
'Changing bond-length dependent on several lacks implementation.')
26012601

2602+
def bond_completion(self, nbonds, atom=None, bond=None, idx=None):
2603+
""" Return a new geometry with additional atoms added to complete the number of bonds
2604+
2605+
This function may be useful to saturate dangling bonds at edges in sp2-carbon structures,
2606+
e.g., with H-atoms.
2607+
2608+
Parameters
2609+
----------
2610+
nbonds : int
2611+
number of bonds requested
2612+
atom : `Atom`, optional
2613+
the kind of atom to be added, where missing. Defaults to atoms of the same type.
2614+
bond, float, optional
2615+
bond length to the extra atoms. Defaults to value from `PeriodicTable`
2616+
idx : array_like, optional
2617+
List of indices for atoms that are to be considered
2618+
2619+
Examples
2620+
--------
2621+
>>> g = geom.graphene(orthogonal=True).tile(3, 0).tile(4, 1)
2622+
>>> g.cell[0] *= 2
2623+
>>> g.bond_completion(3, atom=Atom(1), bond=1.09)
2624+
"""
2625+
2626+
if idx is not None:
2627+
if not isndarray(idx):
2628+
selection = _a.asarrayi(idx).ravel()
2629+
else:
2630+
selection = range(len(self))
2631+
2632+
new_xyz = []
2633+
new_atom = []
2634+
2635+
PT = PeriodicTable()
2636+
2637+
for ia in selection:
2638+
iaZ = self.atoms[ia].Z
2639+
ria = PT.radius(iaZ)
2640+
idx = self.close(ia, R=(0.1, 0.1 + 2 * ria))[1]
2641+
if len(idx) == nbonds - 1:
2642+
# Add one bond
2643+
if atom is None:
2644+
atom = Atom(iaZ, R=self.atoms[ia].R)
2645+
if bond is None:
2646+
bond_length = ria + PT.radius(atom.Z)
2647+
else:
2648+
bond_length = bond
2649+
# Compute bond vector
2650+
bvec = len(idx) * self.xyz[ia]
2651+
for jdx in idx:
2652+
bvec -= self.axyz(jdx)
2653+
bnorm = bvec.dot(bvec) ** .5
2654+
if bnorm > 0.1:
2655+
# only add to geometry if new position is away from ia-atom
2656+
bvec *= bond_length / bnorm
2657+
new_xyz.append(self.xyz[ia] + bvec)
2658+
new_atom.append(atom)
2659+
if len(new_xyz) > 0:
2660+
return self.add(self.__class__(new_xyz, new_atom))
2661+
else:
2662+
return self.copy()
2663+
26022664
def within(self, shapes,
26032665
idx=None, idx_xyz=None,
26042666
ret_xyz=False, ret_rij=False):

0 commit comments

Comments
 (0)