|
21 | 21 | from .utils.mathematics import fnorm |
22 | 22 | from .quaternion import Quaternion |
23 | 23 | from .supercell import SuperCell, SuperCellChild |
24 | | -from .atom import Atom, Atoms |
| 24 | +from .atom import Atom, Atoms, PeriodicTable |
25 | 25 | from .shape import Shape, Sphere, Cube |
26 | 26 | from ._namedindex import NamedIndex |
27 | 27 |
|
@@ -2599,6 +2599,68 @@ def bond_correct(self, ia, atom, method='calc'): |
2599 | 2599 | raise NotImplementedError( |
2600 | 2600 | 'Changing bond-length dependent on several lacks implementation.') |
2601 | 2601 |
|
| 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 | + |
2602 | 2664 | def within(self, shapes, |
2603 | 2665 | idx=None, idx_xyz=None, |
2604 | 2666 | ret_xyz=False, ret_rij=False): |
|
0 commit comments