schrodinger.structutils.assignbondorders module

A module to assign bond orders based on molecular geometry.

Assigns double and triple bonds to structures based on molecular geometry (bond length, bond angles, and dihedral angles). Useful when importing ligands from PDBs into Maestro. Please check the output structure for errors and compare it to the molecular formula. If this script assigns bond orders incorrectly to a reasonable structure, please email the maestro file of the structure to

There is a single public function:

assignbondorders.assign_st(input_st, atoms=None, neutralize=False,
                           problem_only=False, skip_assigned_residues=True,

Assigns bond orders to atom list [atoms] of structure input_st and returns a list of bonds that were adjusted. Bond orders are assigned for all atoms if the atoms list is empty or not specified.

Copyright (c) Schrodinger, LLC. All rights reserved.


For general debug messages


For debugging group bond assignments


For debugging aromatic ring assignments


For debugging code that calculates bond “scores”

schrodinger.structutils.assignbondorders.get_single_bond_length(a1, a2)

Returns ideal length of a single-order bond between specified atoms. If either of the atoms is non-common, returns 0.0.

schrodinger.structutils.assignbondorders.get_neighbors(st, atom)

Returns a list of atoms that <atom> is bound to.

schrodinger.structutils.assignbondorders.calculate_average_angle(st, atom_num)

Calculates the average of all bond angles around the input atom. Returns 0 if the angle can not be calculated. Close to 109 degrees = tetrahedral Close to 120 degrees = planar Close to 180 degrees = linear

schrodinger.structutils.assignbondorders.calculate_dihedral(st, a1, a2)

Calculates the average dihedral angle of the bond between the specified atoms. Close to 0 (zero) is likely to be double bond.

schrodinger.structutils.assignbondorders.order_ring_or_chain(st, atoms)

This function orders the atoms in the ring or chain by bonding order.

schrodinger.structutils.assignbondorders.do_rings_share_atoms(r1, r2)
schrodinger.structutils.assignbondorders.get_rings_in_group(ring, rings_to_check)
class schrodinger.structutils.assignbondorders.AssignBondOrders(st, atoms, neutralize)

Bases: object

__init__(st, atoms, neutralize)

This is a private class; use assign_st() function instead.


Force assignment of known functional groups by SMARTS


Returns False if atom has double or triple bonds.


Returns a list of atoms that <atomnum> is bound to.


Returns a list of atoms that <atomnum> is bound to.


Returns a the number of atoms that <atom> is bound to. EXCLUDING zero-order bonds


Adjusts the formal charge so that it is valid for number of bonds and bond orders.

setFormalCharge(atom, charge)
setBondOrder(atom1, atom2, bond_order)

Sets the bond order between atom1 and atom2 to bond_order.


Return a list of rings that this atom is part of.


Returns 1 if atom_num is a ring with 3, 4, or 5 members.

getExtracyclicAtom(ring, a)

Given an atom of a ring, return the extra-cyclic atom that is bound to this atom.


Iterates over (atom1, atom2) in the given ring

calcBondScore(a1, a2, distance_weight=1.0, ring_angle_weight=0.0)

Calculates the probability that the two atoms are double bonded to each other.

getBestDoubleBond(a1, a2, a3)

Returns a list of two atoms that are the best candidates. Returns [] if neither bond is potential double bond.


This function sorts the atoms in the group so that the 3 (or 4) atoms that need to be worked on the first will be listed first.


Assign a double bond to “best” bond pair in the set. If any bond score is under the double bond threshold and is also “terminal”, remove it from further consideration for double bonding.

Input atom list must be sorted: the first atom in the list must be central, and the three next atoms are bonded to it in a star-like arrangement.

If all three neighbors have bonds scores above the threshold, the one with the highest score is turned into a double bond. Else, the one with the lowest score is removed from the set to avoid infinite recursion.

In case of symmetrical inputs, 2 or more bonds may have the same length, etc, and ties may happen. We need a non-geometrical criterion to resolve ties in a reproducible manner. For this reason, use atom indexes as a secondary criterion.


Assigns double bonds where appropriate for the atoms in the supplied group.


Identifies groups and sets bond orders appropriately.


Returns a list of all rings in the st within the atoms range.


Returns a boolean - whether the specified ring is aromatic or not. Aromatic ring is defined in this context as a 5 or 6 membered ring that is likely, based on bond lengths and angles, etc. to be an aromatic ring.

ringatoms are assumed to be in connectivity order.


Returns a list of aromatic rings in st within all_rings.


Returns True if the given atom is part of an aromatic ring

areAtomsOrtho(ring, atom1, atom2)
isBondRingEdge(a1, a2, rings=None)

Returns True if this atom is bound to two rings, but is not part of a ring itself. Like this: Ring-X-Ring. Such an atom may get a double bond to one of the rings if needed.


Returns True if at least one of atoms bound to it is a member of an aromatic ring.

assignAromaticBonders(ring, bonders)

Assigns bond orders for the supplied 5 or 6-membered aromatic ring. Returns True if successful, False if not.

<bonders> is a list of atoms that MUST get double-bonded.

determineAromaticAtomType(ring, a, ring_group_atoms)

Determines the type of the atom in the aromatic ring.

areCOsPara(ring, c1, c2)
determineAromaticAtomTypes(ring, ring_group_atoms)

Goes through every atom in the supplied aromatic ring, and determines what type of atom it is, then adds the atom to that category. It returns a dictionary (list) of atoms in different groups.


Assigns triple bonds as appripriateley to the atoms in the supplied group. Returns a list of atoms which now have assigned bond orders.

assignAromaticRing(ring, ring_group_atoms)

Returns ASSIGNED_AROMATIC if everything is okay. Returns NOT_AROMATIC if the ring is not aromatic. Returns NOT_ASSIGNED if this ring should be considered later.

findAromaticBonders(ring, ringatomtypes_dict)

Returns a list of suggested bonding atoms in the specified aromatic ring. Returns [] if no bonds should be made.

If “required_only” is set, return only the REQUIRED BONDERS and REQUIRED NON-BONDERS

Raises RuntimeError(“Not aromatic”) if the ring is not aromatic. Raises RuntimeError(“Not assigned”) if the ring could not be assigned.

getNeighboringRings(ring, rings)

Return a list of rings that share atoms with the specified ring.


Assigns bond orders of aromatic rings (5 & 6 membered) which are arranged in a group (multi-cyclic systems).


Assign all aromatic rings


This function adds double bonds to ketones and aldehydes when necesary. It should be run only after ALL other bond orders have been assigned.


Sets the macromodel atom type of Positively Charged Nitrognes to N4(31/sp2) or N5(32/sp3).


Takes the list of input atoms, and puts them into groups, and returns a list of those groups. Atoms are considerred in the same group if they are bonded together (in the same chain).


Returns a list of atoms that can potentially triple-bond.


Returns a list of atoms that can potentially double bond. Only bond angles are considered.

schrodinger.structutils.assignbondorders.get_ring_atom_coords(st, ring_atoms)

Get the coordinates of the ring atoms as a numpy array.

If st has periodic boundary conditions (PBC), the coordinates returned will all be in the frame of reference of the first atom in ring_atoms.


Get vectors normal to the planes described by each ring-edge and the center of the ring.

Assumes that atoms are in order.

schrodinger.structutils.assignbondorders.calculate_planarity(st, ring_atoms)

Calculate the ring planarity.

Very planar rings have a planarity of < 1.

Assumes that atoms are in order.

schrodinger.structutils.assignbondorders.assign_st(st, atoms=None, neutralize=False, problem_only=False, skip_assigned_residues=True, use_ccd=False, _logger=None)

Perform the assign-bond-order algorithm on the supplied structure. If the atom list is specified, only those atoms are fixed.

  • st (L{structure.Structure)) – Structure to assign bond orders in

  • atoms (list of ints) – List of atoms to assign. By default all atoms as assigned.

  • neutralize (bool) – Whether to protonate carboxylic acids.

  • problem_only (bool) – Whether to assign only to atoms with PDB convert problem of 4 (orange atoms). Not compatible with <atoms> argument.

  • skip_assigned_residues (bool) – If True, bond orders are not assigned to residues that have double or triple bonds, even if that residue’s atoms are in <atoms>. Not compatible with <problem_only> option.

  • use_ccd (bool) – Whether to use the Chemical Component Dictionary for hets that have records there. Not supported for covalent ligands. NOTE: if set to True, then all existing bond orders and charges (if present) will be overwritten (for residues with CCD entries). If False (or if residue can’t be assigned by CCD), formal charges are not adjusted, and existing bond orders will never be reduced.

  • _logger (logger) – logger to send messages to


List of (atom1, atom2, order) for every bond whose order was altered.

Return type

list of (int, int, int)

schrodinger.structutils.assignbondorders.orders_assigned(st, atoms=None, all=False)

Returns True if all bond orders are OK in the specified structure. Can be given a list of atoms to check bond orders of. If not list is specified and all flag is set to True, all atoms are checked; otherwise only atoms with a PDB convert error (appear orange in Maestro) are checked. NOTE: atoms and all options are mutually exclusinve.