Bond symmetry is the symmetry operations that keep the symmetry
    of the cell containing two fixed atoms.
973040
def get_bond_symmetry(site_symmetry,
                      lattice,
                      positions,
                      atom_center,
                      atom_disp,
                      symprec=1e-5):
    
    bond_sym = []
    pos = positions
    for rot in site_symmetry:
        rot_pos = (np.dot(pos[atom_disp] - pos[atom_center], rot.T) +
                   pos[atom_center])
        diff = pos[atom_disp] - rot_pos
        diff -= np.rint(diff)
        dist = np.linalg.norm(np.dot(lattice, diff))
        if dist < symprec:
            bond_sym.append(rot)

    return np.array(bond_sym)
114136
private long[] refine(long[] invariants, boolean[] hydrogens) {

        int ord = g.length;

        InvariantRanker ranker = new InvariantRanker(ord);

        // current/next vertices, these only hold the vertices which are
        // equivalent
        int[] currVs = new int[ord];
        int[] nextVs = new int[ord];

        // fill with identity (also set number of non-unique)
        int nnu = ord;
        for (int i = 0; i < ord; i++)
            currVs[i] = i;

        long[] prev = invariants;
        long[] curr = Arrays.copyOf(invariants, ord);

        // initially all labels are 1, the input invariants are then used to
        // refine this coarse partition
        Arrays.fill(prev, 1L);

        // number of ranks
        int n = 0, m = 0;

        // storage of symmetry classes
        long[] symmetry = null;

        while (n < ord) {

            // refine the initial invariants using product of primes from
            // adjacent ranks
            while ((n = ranker.rank(currVs, nextVs, nnu, curr, prev)) > m && n < ord) {
                nnu = 0;
                for (int i = 0; i < ord && nextVs[i] >= 0; i++) {
                    int v = nextVs[i];
                    currVs[nnu++] = v;
                    curr[v] = hydrogens[v] ? prev[v] : primeProduct(g[v], prev, hydrogens);
                }
                m = n;
            }

            if (symmetry == null) {

                // After symmetry classes have been found without hydrogens we add
                // back in the hydrogens and assign ranks. We don't refine the
                // partition until the next time round the while loop to avoid
                // artificially splitting due to hydrogen representation, for example
                // the two hydrogens are equivalent in this SMILES for ethane '[H]CC'
                for (int i = 0; i < g.length; i++) {
                    if (hydrogens[i]) {
                        curr[i] = prev[g[i][0]];
                        hydrogens[i] = false;
                    }
                }
                n = ranker.rank(currVs, nextVs, nnu, curr, prev);
                symmetry = Arrays.copyOf(prev, ord);

                // Update the buffer of non-unique vertices as hydrogens next
                // to discrete heavy atoms are also discrete (and removed from
                // 'nextVs' during ranking.
                nnu = 0;
                for (int i = 0; i < ord && nextVs[i] >= 0; i++) {
                    currVs[nnu++] = nextVs[i];
                }
            }

            // partition is discrete or only symmetry classes are needed
            if (symOnly || n == ord) return symmetry;

            // artificially split the lowest cell, we perturb the value
            // of all vertices with equivalent rank to the lowest non-unique
            // vertex
            int lo = nextVs[0];
            for (int i = 1; i < ord && nextVs[i] >= 0 && prev[nextVs[i]] == prev[lo]; i++)
                prev[nextVs[i]]++;

            // could also swap but this is cleaner
            System.arraycopy(nextVs, 0, currVs, 0, nnu);
        }

        return symmetry;
    }
680757
@Override
    public double getBondOrderSum(IAtom atom) {
        double count = 0;
        for (int i = 0; i < bondCount; i++) {
            if (bonds[i].contains(atom)) {
                if (bonds[i].getOrder() == IBond.Order.SINGLE) {
                    count += 1;
                } else if (bonds[i].getOrder() == IBond.Order.DOUBLE) {
                    count += 2;
                } else if (bonds[i].getOrder() == IBond.Order.TRIPLE) {
                    count += 3;
                } else if (bonds[i].getOrder() == IBond.Order.QUADRUPLE) {
                    count += 4;
                }
            }
        }
        return count;
    }
784468
private boolean getIfBondIsNotRotatable(IAtomContainer mol, IBond bond, IAtomContainer detected) {
        boolean isBondNotRotatable = false;
        int counter = 0;
        IAtom atom0 = bond.getBegin();
        IAtom atom1 = bond.getEnd();
        if (detected != null) {
            if (detected.contains(bond)) counter += 1;
        }
        if (atom0.getFlag(CDKConstants.ISINRING)) {
            if (atom1.getFlag(CDKConstants.ISINRING)) {
                counter += 1;
            } else {
                if (atom1.getSymbol().equals("H"))
                    counter += 1;
                else
                    counter += 0;
            }
        }
        if (atom0.getSymbol().equals("N") && atom1.getSymbol().equals("C")) {
            if (getIfACarbonIsDoubleBondedToAnOxygen(mol, atom1)) counter += 1;
        }
        if (atom0.getSymbol().equals("C") && atom1.getSymbol().equals("N")) {
            if (getIfACarbonIsDoubleBondedToAnOxygen(mol, atom0)) counter += 1;
        }
        if (counter > 0) isBondNotRotatable = true;
        return isBondNotRotatable;
    }
987272
private void reflect(int v, IBond bond) {
        visited[v] = true;
        IAtom atom = container.getAtom(v);
        atom.setPoint2d(reflect(atom.getPoint2d(), bond));
        for (int w : graph[v]) {
            if (!visited[w]) reflect(w, bond);
        }
    }
13618
private boolean getPresenceOfNitro(IAtomContainer ac, IAtom atom) {
        List neighbours = ac.getConnectedAtomsList(atom);
        List second = null;
        IBond bond = null;
        //int counter = 0;
        for (int i = 0; i < neighbours.size(); i++) {
            IAtom neighbour = (IAtom) neighbours.get(i);
            if (neighbour.getSymbol().equals("N")) {
                second = ac.getConnectedAtomsList(neighbour);
                for (int b = 0; b < second.size(); b++) {
                    IAtom conAtom = (IAtom) second.get(b);
                    if (conAtom.getSymbol().equals("O")) {
                        bond = ac.getBond(neighbour, conAtom);
                        if (bond.getOrder() == IBond.Order.DOUBLE) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }
1348596
private IRing toRing(IAtomContainer container, EdgeToBondMap edges, int[] cycle) {
        IRing ring = container.getBuilder().newInstance(IRing.class, 0);

        int len = cycle.length - 1;

        IAtom[] atoms = new IAtom[len];
        IBond[] bonds = new IBond[len];

        for (int i = 0; i < len; i++) {
            atoms[i] = container.getAtom(cycle[i]);
            bonds[i] = edges.get(cycle[i], cycle[i + 1]);
            atoms[i].setFlag(CDKConstants.ISINRING, true);
        }

        ring.setAtoms(atoms);
        ring.setBonds(bonds);

        return ring;
    }
104383
private void addDoubleBondStereochemistry(Graph g, IAtomContainer ac) {

        for (final Edge e : g.edges()) {

            if (e.bond() != Bond.DOUBLE) continue;

            int u = e.either();
            int v = e.other(u);

            // find a directional bond for either end
            Edge first  = null;
            Edge second = null;

            // if either atom is not incident to a directional label there
            // is no configuration
            if ((first = findDirectionalEdge(g, u)) != null) {
                if ((second = findDirectionalEdge(g, v)) != null) {

                    // if the directions (relative to the double bond) are the
                    // same then they are on the same side - otherwise they
                    // are opposite
                    Conformation conformation = first.bond(u) == second.bond(v) ?
                                                Conformation.TOGETHER : Conformation.OPPOSITE;

                    // get the stereo bond and build up the ligands for the
                    // stereo-element - linear search could be improved with
                    // map or API change to double bond element
                    IBond db = ac.getBond(ac.getAtom(u), ac.getAtom(v));

                    IBond[] ligands = new IBond[]{
                        ac.getBond(ac.getAtom(u), ac.getAtom(first.other(u))),
                        ac.getBond(ac.getAtom(v), ac.getAtom(second.other(v)))};

                    ac.addStereoElement(new DoubleBondStereochemistry(db, ligands, conformation));
                } else if (g.degree(v) == 2) {
                    List<Edge> edges = new ArrayList<>();
                    edges.add(e);
                    Edge f = findCumulatedEdge(g, v, e);
                    while (f != null) {
                        edges.add(f);
                        v = f.other(v);
                        f = findCumulatedEdge(g, v, f);
                    }
                    // only odd number of cumulated bonds here, otherwise is
                    // extended tetrahedral
                    if ((edges.size() & 0x1) == 0)
                        continue;
                    second = findDirectionalEdge(g, v);
                    if (second != null) {
                        int   cfg        = first.bond(u) == second.bond(v)
                                           ? IStereoElement.TOGETHER
                                           : IStereoElement.OPPOSITE;
                        Edge  middleEdge = edges.get(edges.size()/2);
                        IBond middleBond = ac.getBond(ac.getAtom(middleEdge.either()),
                                                      ac.getAtom(middleEdge.other(middleEdge.either())));
                        IBond[] ligands = new IBond[]{
                            ac.getBond(ac.getAtom(u), ac.getAtom(first.other(u))),
                            ac.getBond(ac.getAtom(v), ac.getAtom(second.other(v)))};

                        ac.addStereoElement(new ExtendedCisTrans(middleBond, ligands, cfg));
                    }
                }
            }
            // extension F[C@]=[C@@]F
            else {
                Configuration uConf = g.configurationOf(u);
                Configuration vConf = g.configurationOf(v);
                if (uConf.type() == Configuration.Type.DoubleBond &&
                    vConf.type() == Configuration.Type.DoubleBond) {

                    int[] nbrs = new int[6];
                    int[] uNbrs = g.neighbors(u);
                    int[] vNbrs = g.neighbors(v);

                    if (uNbrs.length < 2 || uNbrs.length > 3)
                        continue;
                    if (vNbrs.length < 2 || vNbrs.length > 3)
                        continue;

                    int idx   = 0;
                    System.arraycopy(uNbrs, 0, nbrs, idx, uNbrs.length);
                    idx += uNbrs.length;
                    if (uNbrs.length == 2) nbrs[idx++] = u;
                    System.arraycopy(vNbrs, 0, nbrs, idx, vNbrs.length);
                    idx += vNbrs.length;
                    if (vNbrs.length == 2) nbrs[idx] = v;
                    Arrays.sort(nbrs, 0, 3);
                    Arrays.sort(nbrs, 3, 6);

                    int vPos = Arrays.binarySearch(nbrs, 0, 3, v);
                    int uPos = Arrays.binarySearch(nbrs, 3, 6, u);

                    int uhi = 0, ulo = 0;
                    int vhi = 0, vlo = 0;

                    uhi = nbrs[(vPos + 1) % 3];
                    ulo = nbrs[(vPos + 2) % 3];
                    vhi = nbrs[3 + ((uPos + 1) % 3)];
                    vlo = nbrs[3 + ((uPos + 2) % 3)];

                    if (uConf.shorthand() == Configuration.CLOCKWISE) {
                        int tmp = uhi;
                        uhi = ulo;
                        ulo = tmp;
                    }
                    if (vConf.shorthand() == Configuration.ANTI_CLOCKWISE) {
                        int tmp = vhi;
                        vhi = vlo;
                        vlo = tmp;
                    }

                    DoubleBondStereochemistry.Conformation conf = null;
                    IBond[] bonds = new IBond[2];

                    if (uhi != u) {
                        bonds[0] = ac.getBond(ac.getAtom(u), ac.getAtom(uhi));
                        if (vhi != v) {
                            // System.err.println(uhi + "\\=/" + vhi);
                            conf = Conformation.TOGETHER;
                            bonds[1] = ac.getBond(ac.getAtom(v), ac.getAtom(vhi));
                        } else if (vlo != v) {
                            // System.err.println(uhi + "\\=\\" + vlo);
                            conf = Conformation.OPPOSITE;
                            bonds[1] = ac.getBond(ac.getAtom(v), ac.getAtom(vlo));
                        }
                    } else if (ulo != u) {
                        bonds[0] = ac.getBond(ac.getAtom(u), ac.getAtom(ulo));
                        if (vhi != v) {
                            // System.err.println(ulo + "/=/" + vhi);
                            conf = Conformation.OPPOSITE;
                            bonds[1] = ac.getBond(ac.getAtom(v), ac.getAtom(vhi));
                        } else if (vlo != v) {
                            // System.err.println(ulo + "/=\\" + vlo);
                            conf = Conformation.TOGETHER;
                            bonds[1] = ac.getBond(ac.getAtom(v), ac.getAtom(vlo));
                        }
                    }

                    ac.addStereoElement(new DoubleBondStereochemistry(ac.getBond(ac.getAtom(u), ac.getAtom(v)),
                                                                      bonds,
                                                                      conf));
                }
            }
        }
    }
430688
def equalize_terminal_double_bond(mol):
    
    for i, a in mol.atoms_iter():
        if mol.neighbor_count(i) == 1:
            nb = list(mol.neighbors(i).values())[0]
            if nb.order == 2:
                nb.type = 2
394538
private static int countAlignedBonds(IAtomContainer mol) {
        final double ref = Math.toRadians(30);
        final double diff = Math.toRadians(1);
        int count = 0;
        for (IBond bond : mol.bonds()) {
            Point2d beg = bond.getBegin().getPoint2d();
            Point2d end = bond.getEnd().getPoint2d();
            if (beg.x > end.x) {
                Point2d tmp = beg;
                beg = end;
                end = tmp;
            }
            Vector2d vec = new Vector2d(end.x - beg.x, end.y - beg.y);
            double angle = Math.atan2(vec.y, vec.x);

            if (Math.abs(angle) - ref < diff) {
                count++;
            }
        }
        return count;
    }
773840
private void adjust(ExtendedCisTrans elem) {

        IBond   middle = elem.getFocus();
        IAtom[] ends   = ExtendedCisTrans.findTerminalAtoms(container, middle);
        IBond[] bonds  = elem.getCarriers().toArray(new IBond[2]);

        IAtom left  = ends[0];
        IAtom right = ends[1];

        int p = parity(elem);
        int q = parity(getAtoms(left, bonds[0].getOther(left), right))
                * parity(getAtoms(right, bonds[1].getOther(right), left));

        // configuration is unspecified? then we add an unspecified bond.
        // note: IDoubleBondStereochemistry doesn't indicate this yet
        if (p == 0) {
            for (IBond bond : container.getConnectedBondsList(left))
                bond.setStereo(IBond.Stereo.NONE);
            for (IBond bond : container.getConnectedBondsList(right))
                bond.setStereo(IBond.Stereo.NONE);
            bonds[0].setStereo(IBond.Stereo.UP_OR_DOWN);
            return;
        }

        // configuration is already correct
        if (p == q) return;

        Arrays.fill(visited, false);
        visited[atomToIndex.get(left)] = true;

        if (ringSearch.cyclic(atomToIndex.get(middle.getBegin()),
                              atomToIndex.get(middle.getEnd()))) {
            return;
        }

        for (int w : graph[atomToIndex.get(right)]) {
            if (!visited[w]) reflect(w, middle);
        }
    }
1063711
private Point2d reflect(Point2d p, IBond bond) {
        IAtom a = bond.getBegin();
        IAtom b = bond.getEnd();
        return reflect(p, a.getPoint2d().x, a.getPoint2d().y, b.getPoint2d().x, b.getPoint2d().y);
    }
896878
def iter_halfs_bond(graph):
    """"""
    for atom1, atom2 in graph.edges:
        try:
            affected_atoms1, affected_atoms2 = graph.get_halfs(atom1, atom2)
            yield affected_atoms1, affected_atoms2, (atom1, atom2)
        except GraphError:
            # just try again
            continue
1367916
@Override
    public DescriptorValue calculate(IBond bond, IAtomContainer atomContainer) {
        double value = 0;
        // FIXME: for now I'll cache a few modified atomic properties, and restore them at the end of this method
        String originalAtomtypeName1 = bond.getBegin().getAtomTypeName();
        Integer originalNeighborCount1 = bond.getBegin().getFormalNeighbourCount();
        IAtomType.Hybridization originalHybridization1 = bond.getBegin().getHybridization();
        Integer originalValency1 = bond.getBegin().getValency();
        String originalAtomtypeName2 = bond.getEnd().getAtomTypeName();
        Integer originalNeighborCount2 = bond.getEnd().getFormalNeighbourCount();
        IAtomType.Hybridization originalHybridization2 = bond.getEnd().getHybridization();
        Integer originalValency2 = bond.getEnd().getValency();
        Double originalBondOrderSum1 = bond.getBegin().getBondOrderSum();
        Order originalMaxBondOrder1 = bond.getBegin().getMaxBondOrder();
        Double originalBondOrderSum2 = bond.getEnd().getBondOrderSum();
        Order originalMaxBondOrder2 = bond.getEnd().getMaxBondOrder();

        if (!isCachedAtomContainer(atomContainer)) {
            try {
                AtomContainerManipulator.percieveAtomTypesAndConfigureAtoms(atomContainer);
                LonePairElectronChecker lpcheck = new LonePairElectronChecker();
                lpcheck.saturate(atomContainer);
            } catch (CDKException e) {
                return getDummyDescriptorValue(e);
            }

        }
        if (!bond.getOrder().equals(IBond.Order.SINGLE)) {
            try {
                value = IonizationPotentialTool.predictIP(atomContainer, bond);
            } catch (CDKException e) {
                return getDummyDescriptorValue(e);
            }
        }
        bond.getBegin().setAtomTypeName(originalAtomtypeName1);
        bond.getBegin().setHybridization(originalHybridization1);
        bond.getBegin().setValency(originalValency1);
        bond.getBegin().setFormalNeighbourCount(originalNeighborCount1);
        bond.getEnd().setAtomTypeName(originalAtomtypeName2);
        bond.getEnd().setHybridization(originalHybridization2);
        bond.getEnd().setValency(originalValency2);
        bond.getEnd().setFormalNeighbourCount(originalNeighborCount2);
        bond.getBegin().setMaxBondOrder(originalMaxBondOrder1);
        bond.getBegin().setBondOrderSum(originalBondOrderSum1);
        bond.getEnd().setMaxBondOrder(originalMaxBondOrder2);
        bond.getEnd().setBondOrderSum(originalBondOrderSum2);

        return new DescriptorValue(getSpecification(), getParameterNames(), getParameters(), new DoubleResult(value),
                DESCRIPTOR_NAMES);
    }
125924
def assign_rotatable(mol):
    """"""
    mol.require("Valence")
    mol.require("Topology")
    bs = set([(u, v) for u, v, _ in mol.bonds_iter()])
    for r in mol.rings:
        for a, b in iterator.consecutive(r + [r[0]], 2):
            bs -= {(a, b)}
            bs -= {(b, a)}
    for u, v in bs:
        unc = mol.neighbor_count(u)
        vnc = mol.neighbor_count(v)
        bc = mol.bond(u, v).order
        if bc == 1 and (unc > 1 and vnc > 1):
            mol.bond(u, v).rotatable = True
    mol.descriptors.add("Rotatable")
1312611
private boolean getPresenceOfSulfat(IAtomContainer ac, IAtom atom) {
        List<IAtom> neighbours = ac.getConnectedAtomsList(atom);
        //org.openscience.cdk.interfaces.IAtom[] second = null;
        //IBond bond = null;
        //int counter = 0;
        for (IAtom neighbour : neighbours) {
            if (neighbour.getSymbol().equals("S") && getOxygenCount(ac, neighbour) >= 2
                    && ac.getConnectedBondsCount(neighbour) == 4) {
                return true;
            }
        }
        return false;
    }
406492
private IBond getNextBondWithUnplacedRingAtom() {
        for (IBond bond : molecule.bonds()) {
            IAtom beg = bond.getBegin();
            IAtom end = bond.getEnd();
            if (beg.getPoint2d() != null && end.getPoint2d() != null) {
                if (end.getFlag(CDKConstants.ISPLACED) && !beg.getFlag(CDKConstants.ISPLACED) && beg.isInRing()) {
                    return bond;
                }
                if (beg.getFlag(CDKConstants.ISPLACED) && !end.getFlag(CDKConstants.ISPLACED) && end.isInRing()) {
                    return bond;
                }
            }
        }
        return null;
    }