Skip to content

bond_orders

Bond order perception from molecular geometry.

Assigns bond orders (single, double, triple, aromatic) based on: 1. Bond length heuristics 2. Valence constraints 3. Aromaticity information

get_bond_order(graph, atom_i, atom_j)

Get the perceived bond order between two atoms.

Parameters:

Name Type Description Default
graph MolecularGraph

A MolecularGraph.

required
atom_i int

First atom index.

required
atom_j int

Second atom index.

required

Returns:

Type Description
float

Bond order (1, 1.5, 2, or 3), or 0 if no bond.

Source code in chmpy/graph/bond_orders.py
def get_bond_order(graph: "MolecularGraph", atom_i: int, atom_j: int) -> float:
    """
    Get the perceived bond order between two atoms.

    Args:
        graph: A MolecularGraph.
        atom_i: First atom index.
        atom_j: Second atom index.

    Returns:
        Bond order (1, 1.5, 2, or 3), or 0 if no bond.
    """
    if not graph.has_bond(atom_i, atom_j):
        return 0.0

    # Lazily perceive bond orders for the whole graph (with valence-constraint
    # correction) and cache the result. The bond-length heuristic alone gets
    # carboxylate-like sp2 carbons wrong because both C-O lengths are short
    # enough to be flagged as double; the valence pass in perceive_bond_orders
    # fixes that.
    if graph.bond_orders is None:
        graph.bond_orders = perceive_bond_orders(graph)

    order = graph.bond_orders[atom_i, atom_j]
    if order > 0:
        return float(order)

    return _bond_length_heuristic(graph, atom_i, atom_j)

hydrogen_count(graph, atom_idx)

Count explicit hydrogens bonded to an atom.

Parameters:

Name Type Description Default
graph MolecularGraph

A MolecularGraph.

required
atom_idx int

Index of the atom.

required

Returns:

Type Description
int

Number of hydrogen atoms bonded to this atom.

Source code in chmpy/graph/bond_orders.py
def hydrogen_count(graph: "MolecularGraph", atom_idx: int) -> int:
    """
    Count explicit hydrogens bonded to an atom.

    Args:
        graph: A MolecularGraph.
        atom_idx: Index of the atom.

    Returns:
        Number of hydrogen atoms bonded to this atom.
    """
    neighbors = graph.neighbors(atom_idx)
    return sum(1 for n in neighbors if graph.atomic_numbers[n] == 1)

implicit_hydrogen_count(graph, atom_idx)

Calculate implicit hydrogen count for an atom.

Based on standard valence minus current bond order sum.

Parameters:

Name Type Description Default
graph MolecularGraph

A MolecularGraph.

required
atom_idx int

Index of the atom.

required

Returns:

Type Description
int

Number of implicit hydrogens.

Source code in chmpy/graph/bond_orders.py
def implicit_hydrogen_count(graph: "MolecularGraph", atom_idx: int) -> int:
    """
    Calculate implicit hydrogen count for an atom.

    Based on standard valence minus current bond order sum.

    Args:
        graph: A MolecularGraph.
        atom_idx: Index of the atom.

    Returns:
        Number of implicit hydrogens.
    """
    z = graph.atomic_numbers[atom_idx]
    if z not in STANDARD_VALENCES:
        return 0

    max_valence = max(STANDARD_VALENCES[z])
    current = total_bond_order(graph, atom_idx)

    implicit = int(max_valence - current)
    return max(0, implicit)

is_double_bond(graph, atom_i, atom_j)

Check if a bond is a double bond.

Source code in chmpy/graph/bond_orders.py
def is_double_bond(graph: "MolecularGraph", atom_i: int, atom_j: int) -> bool:
    """Check if a bond is a double bond."""
    order = get_bond_order(graph, atom_i, atom_j)
    return 1.9 <= order <= 2.1

is_single_bond(graph, atom_i, atom_j)

Check if a bond is a single bond.

Source code in chmpy/graph/bond_orders.py
def is_single_bond(graph: "MolecularGraph", atom_i: int, atom_j: int) -> bool:
    """Check if a bond is a single bond."""
    order = get_bond_order(graph, atom_i, atom_j)
    return 0.9 <= order <= 1.1

is_triple_bond(graph, atom_i, atom_j)

Check if a bond is a triple bond.

Source code in chmpy/graph/bond_orders.py
def is_triple_bond(graph: "MolecularGraph", atom_i: int, atom_j: int) -> bool:
    """Check if a bond is a triple bond."""
    order = get_bond_order(graph, atom_i, atom_j)
    return 2.9 <= order <= 3.1

perceive_bond_orders(graph)

Perceive bond orders from molecular geometry.

Uses a multi-step approach: 1. Initial assignment from bond lengths 2. Aromatic ring detection and assignment 3. Valence constraint propagation

Parameters:

Name Type Description Default
graph MolecularGraph

A MolecularGraph with bond distance information.

required

Returns:

Type Description
ndarray

Sparse matrix of bond orders (N, N).

Source code in chmpy/graph/bond_orders.py
def perceive_bond_orders(graph: "MolecularGraph") -> np.ndarray:
    """
    Perceive bond orders from molecular geometry.

    Uses a multi-step approach:
    1. Initial assignment from bond lengths
    2. Aromatic ring detection and assignment
    3. Valence constraint propagation

    Args:
        graph: A MolecularGraph with bond distance information.

    Returns:
        Sparse matrix of bond orders (N, N).
    """
    n = graph.n_atoms
    bond_orders = dok_matrix((n, n), dtype=np.float32)

    # Get edges
    edges = graph.edges()

    # Step 1: Initial assignment from bond lengths
    for i, j in edges:
        order = _bond_length_heuristic(graph, i, j)
        bond_orders[i, j] = order
        bond_orders[j, i] = order

    # Step 2: Detect and assign aromatic bonds
    aromatic_atoms, aromatic_bonds = perceive_aromaticity(graph)
    for i, j in aromatic_bonds:
        bond_orders[i, j] = 1.5
        bond_orders[j, i] = 1.5

    # Step 3: Valence constraint propagation
    bond_orders = _valence_propagation(graph, bond_orders)

    return bond_orders

total_bond_order(graph, atom_idx)

Calculate the total bond order (valence) for an atom.

Parameters:

Name Type Description Default
graph MolecularGraph

A MolecularGraph.

required
atom_idx int

Index of the atom.

required

Returns:

Type Description
float

Sum of bond orders for all bonds to this atom.

Source code in chmpy/graph/bond_orders.py
def total_bond_order(graph: "MolecularGraph", atom_idx: int) -> float:
    """
    Calculate the total bond order (valence) for an atom.

    Args:
        graph: A MolecularGraph.
        atom_idx: Index of the atom.

    Returns:
        Sum of bond orders for all bonds to this atom.
    """
    neighbors = graph.neighbors(atom_idx)
    return sum(get_bond_order(graph, atom_idx, n) for n in neighbors)