Spruce TK is used to process PDB or mmCIF files containing the structures, resulting from X-ray crystallography, Nuclear Magnetic Resonance (NMR) spectroscopy, or electron microscopy (EM) experiments. into molecules usable for molecular modeling. Due to the nature of the experiments and data, some processing is required before use in modeling.

Spruce TK provides an end-to-end preparation workflow using the OEMakeDesignUnits API. Options (see OEMakeDesignUnitOptions and associated options classes) are available to control for the desired behavior. Metadata (see OEStructureMetadata) can be supplied to infuse experimental data, like the proper variant sequence and also fix common problems reading from PDB files (e.g. bond order perception). Spruce has a built-in Chemical Components Dictionary matching 3-letter residue codes to SMILES, derived from the corresponding one at the RCSB, but curated to fix improper SMILES. The workflow automatically runs through the following steps to produce OEDesignUnit objects:

  1. Biological unit extraction (see OEExtractBioUnits)

  2. If structure is from X-ray, it will also generate packing residues for visualization of crystal contacts

  3. Alternate location assignment or enumeration (see the OEAlternateLocationOption namespace)

  4. Splits the system into components, e.g. identifying ligands, cofactors, excipients.

  5. Building missing side-chains, modeling loops, and capping chain breaks (see OEBuildSidechains, OEBuildLoops, and OECapTermini)

  6. Hydrogen placement and optimization, including searching ligand tautomer states (see OEProtonateDesignUnit)

  7. Assignment of partial charges to the entire system (see OEDesignUnitCharges)

  8. Superposition to a common reference frame (see OEStructuralSuperposition and OESecondaryStructureSuperposition)

  9. An OEInteractionHintContainer encoded for visualization and more

  10. An estimate of the model quality using Iridium [Warren-2012] stored in OEIridiumData.


Multiple design units are often produced. This results from multiple biological units generated during step 1, and further expanding that set when enumerating the alternate locations in step 3. The Iridium categorization (see Categorization) should be helpful in choosing which (if not all) of the produced units to use in downstream modeling tasks. We find that the Iridium categories are also helpful for managing modeling expectations, having a quality measure of the input data for modeling.


Included with Spruce TK is a large database of loop templates generated by parsing the structures in the public PDB repository pulled from the RCSB. This database is available from db-downloads. in a platform-independent format. The SPRUCE loop database is large (~13G) and will take time to download with a good internet connection. When the download is complete, move the file to a convenient location, a network drive is not recommended for performance.

To use it during prep (OEMakeDesignUnits), set the path in SetLoopDBFilename method on the OELoopBuilderOptions class.

The database can be appended to (updated) using the LoopDB_Builder utility app, that ships with the SPRUCE apps. This would be in the event that the user has a collection of internal/proprietary structures, or if specific structures are released to the public PDB between OpenEye updates of the database that are crucial for a given target that is less well described by the existing templates.


  1. Biological Unit (BU) - the biologically relevant unit for a protein to use in modeling. For example, in Trypsin the BU is a monomer, in HIV Protease the BU is a homo-dimer. See Biological Unit below.

  2. Asymmetric Unit (ASU) - the contents of a PDB or mmCIF file from X-ray contain an asymmetric unit as the output of the experiment. This is sometimes equivalent to the BU, but often requires manipulation to create a correct BU.

  3. Design Unit (DU) - the result of preparation in Spruce is a collection of molecules from a single BU, extracted and ready to use for modeling tasks. See Design Unit below for more details.

  4. Alternate locations (alt locs) - X-ray experiments can often contain results with atoms occupying more than one location. Crystallographers denote this with a measure of the amount of time an atom occupies a given set of coordinates. A well resolved atom will have an occupancy of 1.0, meaning that 100% of the time it is in that location. Sometimes, the atom exists in two positions, alternate locations, and these appear in the input file with single letter designations and with occupancy < 1.0.

Biological Unit

In short, the biological unit (BU) is an object that contains the biologically relevant parts of an ASU, which have not been split into various molecular components and are not yet prepped for modeling. For a more detailed explanation of BUs, refer to Introduction to Biological Assemblies and the PDB Archive hosted at the RCSB.

A BU can be constructed from a single PDB from the PDB’s own header remarks, or by using a sequence alignment to an input reference protein. To extract a BU or set of BUs from a PDB, one should use the helper function in Spruce TK called OEExtractBioUnits. The following example shows how to extract BUs from the PDB remarks:

    biounits = oespruce.OEExtractBioUnits(extract_prot, opts)

Using the same function, one can also extract BUs from a PDB using an input reference protein. The following example shows how to use OEExtractBioUnits to extract BUs from a given reference:

    biounits = oespruce.OEExtractBioUnits(extract_prot, ref_prot, opts)

Design Unit

The design unit (DU) is an object that contains the extracted and prepared parts of a single BU, ready for modeling. The parts include:

  1. Protein

  2. Ligand (not always, an apo DU will not contain a ligand)

  3. Site residues

  4. Packing residues (if any exist near the site)

  5. Excipients (if any exist near the site)

One can interact with each part of the DU through APIs. The APIs are listed here OEDesignUnit.

Proton Placement and Optimization

Traditionally, most biomolecular structures have been generated with either no explicit hydrogens or only polar hydrogens. However, having all atoms explicitly represented and positioned to make appropriate hydrogen bonds is sometimes necessary. The function OEPlaceHydrogens does this by adding and placing hydrogens and by “flipping” certain functional groups (e.g., sidechain amides and imidazoles) as required for an optimal hydrogen bonding network. Spruce TK leverages this functionality, but builds on top of this by taking the ligand protomer and tautomer states into account in the OEProtonateDesignUnit function. The function identifies the heterogens (ligands, cofactors, etc.) in the structure and enumerates their states using the OEGetReasonableTautomers function or by using user supplied states. The hydrogen bonding network of the biomolecule is then optimized in the presence of each state independently and the most favorable state of the complex is chosen based on interaction energies. If a binding site holds two heterogens, e.g. a ligand and a cofactor and each have multiple tautomer states, the combinatorial number of states are optimized and evaluated. To do this efficiently only the binding site(s) are initially optimized. After selecting the appropriate states of each of the binding sites the remaining parts of the system is optimized keeping these states fixed.

Protein Sidechain Modeling

Amino acid sidechains are sometimes missing in protein structures due to low or missing density from X-ray diffraction crystallography experiments. This can be due to e.g. high flexibility making assignment of a specific location of the atoms difficult. However, most molecule simulation software requires a position of these atoms, and the lack of them can cause incorrect results. Partial sidechains are identified with OEGetPartialResidues. Using OEBuildSidechains these residues are then divided into groups based on proximity and side-chain orientation. The groups are independently optimized taking into account their local environment. In each group the sidechains are built out and a standard rotamer library from the OERotamerLibrary namespace is used. For each side-chain the set of rotamers are evaluated based on an interaction energy with the nearest environment and the most favorable state is chosen. In the case where multiple residues are being built in a group, an iterative procedure attempts to find the optimal energy for the entire set of residues. In the event a sidechain cannot be built due to poor input geometry causing clashes the entire cluster is skipped. Water locations that block side-chain rotamers result in those water molecules being deleted (optional) since their placement is most likely an artifact.

Protein Loop Modeling

Similarly to missing side-chains above there are sometimes gaps in protein structures, where the position of the entire amino acid residues could not be resolved based on the experimental data. The function OEBuildLoops is able to build missing gaps (loops). The workflow is illustrated by the figure below. The function identifies missing loops, by comparing the SEQRES section of the PDB header with the structure using a sequence alignment. The user can optionally input their own sequence using OESequenceMetadata if the SEQRES in the header is incorrect or missing. With the gaps identified, the function loops for templates matching the gap, filters them based on the ability to fit the gap without clashing, and eventually does an optimization of the top candidates in the local environment before picking the most favorable conformation. If multiple results are desired, these can be retrieved using OEBuildSingleLoop.

*OEBuildLoops* Workflow

OEBuildLoops: Gaps are searched, filtered, inserted and evaluated for best fit.

The loop template database is built using all the structures in the PDB downloaded from the RCSB, and can be downloaded from db-downloads.

*OEBuildLoops* Database Construction

Loop template database Loops are extracted from the RCSB PDB, deduplicated, compressed and indexed for easy retrieval.

Protein Superposition

A protein can be structurally superimposed on to a reference protein structure using the OESpruce TK. Proteins can be superimposed with either atomic coordinates in the OEStructuralSuperposition class, or with secondary structure elements using the OESecondaryStructureSuperposition class.

The OEStructuralSuperposition class can superimpose proteins using any of the following four methods:

  1. The global method (default for OEStructuralSuperposition). This method uses all matching heavy atoms from the reference and fit proteins as the region for performing the superposition calculation (see OESuperpositionType_Global).

  2. The Difference Distance Matrix method. This method calculates the pairwise distance matrix of C-alpha atoms for both the reference and fit proteins, then takes the difference of these two matrices to find the difference distance matrix (DDM).

    For a given conformation a, the elements of the distance matrix \(D_{ij}^a\) are the distances between atoms i and j in a molecule,

    \[D_{ij}^a = |r_i - r_j|\]

    where \(r_i\) and \(r_j\) are the Cartesian coordinate vectors of atoms i and j. The elements \(\Delta_{ij}^{ab}\) of the difference-distance matrix for two conformations a and b are

    \[\Delta_{ij}^{ab} = D_{ij}^a - D_{ij}^b.\]

    If \(\Delta_{ij}^{ab}\) is positive, the interatomic vector between between i and j in conformation b is contracted with respect to a. Conversely, negative elements of the DDM indicate an expansion of the interatomic vector.

    The longest contiguous region of the resulting difference distance matrix (DDM) is used for the structural superposition calculation (see OESuperpositionType_DDM).

  3. The weighted-DDM method. This method uses the DDM matrix, and calculates Gaussian weighting factors for all matching C-alpha atoms. These Gaussian weights are used as a weighting function in the superposition calculation (see OESuperpositionType_Weighted).

  4. The site residue method. This method uses a set of site residues (given as a set of unique residue strings) as a constraint on the protein superposition. Site residues must be set with the SetSiteResidues member function of the OESuperpositionOptions class (see OESuperpositionType_Site).

The OESecondaryStructureSuperposition class can superimpose proteins using the following method:

  1. The secondary structure superposition method. This method takes two proteins and performs a structural superposition on them based on the shape overlap of the secondary structure elements of the two proteins.


All structural superposition methods in the OEStructuralSuperposition class have a corresponding score from the sequence alignment that was used to find the matching atoms of both proteins. This score comes from the output of the OESequenceAlignment class, where a larger score indicates a better sequence alignment, and scores below a small threshold (around 200) should be considered a bad alignment.


All structural superposition methods in the OEStructuralSuperposition class have a corresponding RMSD value for superposition that can be loosely associated with the quality of the superposition. The OESecondaryStructureSuperposition class does not have an RMSD value, but instead uses the Tanimoto score from the underlying shape overlap calculation.

How to Correctly Read a PDB File

Reading a PDB file correctly for use in subsequent modeling tasks can be challenging. To correctly read a PDB, one must be aware that PDB header information as well as information about alternate location codes within the PDB file will be lost unless a specific combination of PDB-centric OEIFlavor’s are used. Furthermore, the protein itself must be processed by OEAltLocationFactory in order to create a molecule with all alternate location atoms retained. Spruce handles this for the user, so they are not handled by this reader. However, for uses other than Spruce the user needs to either, enumerate the different alternate locations, or pick a specific location. With that in mind, we recommend reading PDB files for use in OESpruce TK using the following pattern as shown in ReadProteinFromPDB below:

        ifs = oechem.oemolistream()
        ifs.SetFlavor(oechem.OEFormat_PDB, oechem.OEIFlavor_PDB_Default | oechem.OEIFlavor_PDB_DATA | oechem.OEIFlavor_PDB_ALTLOC)  # noqa        
        if not
            oechem.OEThrow.Fatal("Unable to open %s for reading" % ifilename)
        mol = oechem.OEGraphMol()
        if not oechem.OEReadMolecule(ifs, mol):
            oechem.OEThrow.Fatal("Unable to read molecule from %s" % ifilename)


The mmCIF reader was designed to read all the necessary input by default, and therefore no specific OEIFlavor’s are necessary to read them.