Structures and unit cells
read_pdb, read_mmcif, read_xyz and wget return a Structure: a vector of atoms that also carries the metadata of the system: its unit cell, title, and connectivity. A Structure behaves as a vector of Atoms, such that all functions that operate on vectors of atoms also operate on structures.
PDBToolsBase.Structure — Type
Structure(atoms::AbstractVector{<:Atom}=Atom{Nothing}[]; unitcell=nothing)
Structure(atoms::AbstractVector{<:Atom}, metadata::MetaData)A Structure is the main data structure in PDBTools.jl representing a molecular structure. It behaves as a vector of Atom objects, and carries metadata (see PDBTools.MetaData), such as the unit cell of the system, which is accessible as a property: s.unitcell. The underlying vector of atoms is s.atoms.
Indexing with ranges, filter, copy and other functions that create new vectors of atoms return new Structures, with copies of the metadata, while view returns a Structure sharing the metadata with the original one.
Example
julia> using PDBTools
julia> s = Structure(read_pdb(PDBTools.test_file("small.pdb")); unitcell=UnitCell(10.0, 10.0, 10.0));
julia> s.unitcell
UnitCell(a=10.000, b=10.000, c=10.000, α=90.00, β=90.00, γ=90.00)
julia> s.unitcell = UnitCell(a=10.0, b=20.0, c=30.0, γ=120.0)
UnitCell(a=10.000, b=20.000, c=30.000, α=90.00, β=90.00, γ=120.00)
julia> length(s[1:10])
10
julia> s[1:10].unitcell == s.unitcell
truePDBToolsBase.MetaData — Type
MetaDataMetadata of a Structure. The fields of MetaData are accessible as properties of the structure (e.g. s.unitcell), and can be set in the Structure constructor.
Fields
unitcell::Union{Nothing,UnitCell}: The unit cell of the system (seeUnitCell), ornothingif the structure is not periodic. When setting it (s.unitcell = ...), values that are not aUnitCellare converted with theUnitCellconstructor.connectivity::Union{Nothing,Vector{Vector{Int32}}}: The bonds of the atoms, as read from theCONECTrecords of PDB files or the_geom_bondfields of mmCIF files:connectivity[i]contains the indices of the atoms bonded to the atom with indexi. The indices are the sequential indices of the atoms in the file (index(atom), which are not changed by selections or filtering). The bonds of PDB files are listed as in the file (they are not symmetrized), and repeated bonds, which indicate the bond order in PDB files (e.g. a double bond is listed twice), are kept.nothingif the connectivity is not available. When setting it, vectors of vectors of integers are converted toVector{Vector{Int32}}.title::Union{Nothing,String}: The title of the structure, as read from theTITLErecords of PDB files, the_struct.titlefield of mmCIF files, or the comment line of xyz files.nothingif the file does not define a title.
Metadata
The metadata fields are accessible as properties of the structure, and are nothing when not defined:
| Property | Read from | Written to |
|---|---|---|
unitcell | CRYST1 (PDB), _cell (mmCIF) | CRYST1 (PDB), _cell (mmCIF) |
title | TITLE (PDB), _struct.title (mmCIF), comment line (xyz) | the same fields |
connectivity | CONECT (PDB), _geom_bond (mmCIF) | CONECT (PDB), _geom_bond (mmCIF) |
The metadata can be set in the Structure constructor (e.g. Structure(atoms; title="My system")), or by assigning the properties (e.g. str.title = "My system").
Reading structures
The unit cell is read from the CRYST1 field of PDB files, or from the _cell fields of mmCIF files:
using PDBTools, LazyArtifacts
str = read_pdb(PDBTools.test_file("pbc.pdb")) Structure{Atom{Nothing}} with 130241 atoms - with unit cell
index name resname chain resnum residue x y z occup beta model segname index_pdb
1 N ALA P 1 1 103.848 97.435 20.875 1.00 0.00 1 PROT 1
2 HT1 ALA P 1 1 103.498 96.484 21.110 1.00 0.00 1 PROT 2
⋮
130240 O3 GLYC D 4302 26788 26.526 49.111 13.033 1.00 0.00 1 GLYC 130240
130241 H3 GLYC D 4302 26788 27.053 48.661 12.369 1.00 0.00 1 GLYC 130241str.unitcellUnitCell(a=107.845, b=107.845, c=107.845, α=90.00, β=90.00, γ=90.00)If the file does not define a unit cell (or defines the 1Å unit cube, which indicates that the structure is not crystallographic, as in NMR or cryo-EM structures), str.unitcell is nothing.
Title
The title is read from the TITLE records of PDB files, the _struct.title field of mmCIF files, or the comment line of xyz files:
ethanol = read_pdb(PDBTools.test_file("ethanol.pdb"))
ethanol.title"ETHANOL MOLECULE WITH EXPLICIT HYDROGENS"Connectivity
The bonds of the atoms are read from the CONECT records of PDB files, or from the _geom_bond fields of mmCIF files. The connectivity is a Vector{Vector{Int32}}, where connectivity[i] contains the indices of the atoms bonded to the atom with index i:
ethanol.connectivity9-element Vector{Vector{Int32}}:
[2, 4, 5, 6]
[1, 3, 7, 8]
[2, 9]
⋮
[2]
[3]The indices are the sequential indices of the atoms in the file, index(atom), which are not changed by selections, filtering, or reordering of the atoms. Thus, the connectivity remains valid for substructures. For example, the atoms bonded to the oxygen atom of ethanol are:
heavy = select(ethanol, "not element H")
O = heavy[findfirst(at -> name(at) == "O1", heavy)]
[ name(ethanol[j]) for j in ethanol.connectivity[index(O)] ]2-element Vector{InlineStrings.String15}:
"C2"
"H6"When writing, write_pdb and write_mmcif number the atoms sequentially in the file (1, 2, ...) and convert the connectivity to these numbers. Bonds to atoms that are not written are dropped:
tmpfile = tempname() * ".pdb"
write_pdb(tmpfile, heavy)
read_pdb(tmpfile).connectivity3-element Vector{Vector{Int32}}:
[2]
[1, 3]
[2]The connectivity cannot be written if two of the atoms written have the same index (for example, in the concatenation of two copies of a structure), because the bonds would be ambiguous. In this case, renumber the atoms (and their connectivity), or skip writing the connectivity with connectivity=false.
Indexing and iteration
A Structure can be indexed and iterated as a vector of atoms:
str[1] index name resname chain resnum residue x y z occup beta model segname index_pdb
1 N ALA P 1 1 103.848 97.435 20.875 1.00 0.00 1 PROT 1collect(eachchain(str))8-element Vector{Chain}[
Chain(P-3801 atoms)
Chain(A-29997 atoms)
⋮
Chain(E-106 atoms)
Chain(D-60228 atoms)
]Indexing with ranges, selections, filter, copy, and other functions that create new vectors of atoms return new Structures, with a copy of the metadata. Thus, the unit cell is preserved:
protein = select(str, "protein")
protein.unitcellUnitCell(a=107.845, b=107.845, c=107.845, α=90.00, β=90.00, γ=90.00)The underlying vector of atoms is available as str.atoms.
Unit cells
The unit cell is set with a UnitCell, which can be constructed from the lattice parameters, from the sides of an orthorhombic box, or from a matrix with the lattice vectors as columns:
str.unitcell = UnitCell(85.0, 85.0, 85.0)UnitCell(a=85.000, b=85.000, c=85.000, α=90.00, β=90.00, γ=90.00)str.unitcell = UnitCell(a=85.0, b=85.0, c=85.0, γ=120.0)UnitCell(a=85.000, b=85.000, c=85.000, α=90.00, β=90.00, γ=120.00)PDBToolsBase.UnitCell — Type
UnitCell(matrix::AbstractMatrix)
UnitCell(sides::AbstractVector)
UnitCell(a, b, c, α=90, β=90, γ=90)
UnitCell(; a, b, c, α=90, β=90, γ=90)
UnitCell(lattice::NamedTuple)Unit cell of a periodic system. It can be defined by:
- A 3×3 matrix, with the lattice vectors as columns.
- A vector with the lengths of the sides of an orthorhombic box.
- The lattice parameters: the lengths of the sides
a,b,c(in Å), and the anglesα,β,γ(in degrees), given as positional or keyword arguments, or as the named tuple returned bymatrix_to_lattice.
A UnitCell behaves as the 3×3 unit cell matrix (with the lattice vectors as columns), and can be used wherever a unit cell matrix is accepted. The unit cell of a Structure is set with s.unitcell = UnitCell(...).
Example
julia> using PDBTools
julia> uc = UnitCell(10.0, 20.0, 30.0)
UnitCell(a=10.000, b=20.000, c=30.000, α=90.00, β=90.00, γ=90.00)
julia> UnitCell([10.0, 20.0, 30.0]) == uc
true
julia> UnitCell(a=10.0, b=20.0, c=30.0, γ=120.0)
UnitCell(a=10.000, b=20.000, c=30.000, α=90.00, β=90.00, γ=120.00)
julia> matrix_to_lattice(uc)
(a = 10.0f0, b = 20.0f0, c = 30.0f0, α = 90.0f0, β = 90.0f0, γ = 90.0f0)Unit cells are written by write_pdb and write_mmcif.
Periodic boundary conditions
The functions that support periodic boundary conditions (for example, contact_map, hydrogen_bonds, sasa_particles, and visualize) accept the unitcell keyword argument as:
unitcell=false(default): no periodic boundary conditions.unitcell=true: use the unit cell of theStructure.unitcell=UnitCell(...): use the given unit cell.
str = read_pdb(PDBTools.test_file("pbc.pdb"), "protein")
sasa(sasa_particles(str; unitcell=true))10838.204f0