Atomic and group contributions

One of the interesting features of Minimum-Distance distributions is that they can be naturally decomposed into the atomic or group contributions. Simply put, if a MDDF has a peak at a hydrogen-bonding distance, it is natural to decompose that peak into the contributions of each type of solute or solvent atom to that peak.

Tip

See also the section on contributions per residue for proteins and other macromolecules: 2D density map per residue.

To obtain the atomic contributions of an atom or group of atoms to the MDDF, the coordination number, or the site count at each distance, the contributions function is provided. For example, in a system composed of a protein and water, we would have defined the solute and solvent using:

using PDBTools, ComplexMixtures
atoms = readPDB("system.pdb")
protein = select(atoms,"protein")
water = select(atoms,"water")
solute = AtomSelection(protein,nmols=1)
solvent = AtomSelection(water,natomspermol=3)

The MDDF calculation is executed with:

trajectory = Trajectory("trajectory.dcd",solute,solvent)
results = mddf(trajectory, Options(bulk_range=(8.0, 12.0)))

Atomic contributions in the result data structure

The results data structure contains the decomposition of the MDDF into the contributions of every type of atom of the solute and the solvent. These contributions can be retrieved using the contributions function, with the SoluteGroup and SolventGroup selectors.

For example, if the MDDF of water (solvent) relative to a solute was computed, and water has atom names OH2, H1, H2, one can retrieve the contributions of the oxygen atom with:

OH2 = contributions(results, SolventGroup(["OH2"]))

or with, if OH2 is the first atom in the molecule,

OH2 = contributions(results, SolventGroup([1]))

The contributions of the hydrogen atoms can be obtained, similarly, with:

H = contributions(results, SolventGroup(["H1", "H2"]))

or with, if OH2 is the first atom in the molecule,

H = contributions(results, SolventGroup([2, 3]))

Each of these calls will return a vector of the constributions of these atoms to the total MDDF.

For example, here we plot the total MDDF and the Oxygen contributions:

using Plots
plot(results.d, results.mddf, label=["Total MDDF"], linewidth=2)
plot!(results.d, contributions(results, SolventGroup(["OH2"])), label=["OH2"], linewidth=2)
plot!(xlabel="Distance / Å", ylabel="MDDF")

Contributions to coordination numbers or site counts

The keyword type defines the return type of the contribution:

  • type=:mddf : the contribution of the group to the MDDF is returned (default).
  • type=:coordination_number : the contribution of the group to the coordination number, that is, the cumulative sum of counts at each distance, is returned.
  • type=:md_count : the contribution of the group to the site count at each distance is returned.

Example of the usage of the type option:

ca_contributions = contributions(results, SoluteGroup(["CA"]); type=:coordination_number)

Using PDBTools

If the solute is a protein, or other complex molecule, selections defined with PDBTools can be used. For example, this will retrieve the contribution of the acidic residues of a protein to total MDDF:

using PDBTools
atoms = readPDB("system.pdb")
acidic_residues = select(atoms, "acidic")
acidic_contributions = contributions(results, SoluteGroup(acidic_residues))

It is expected that for a protein most of the atoms do not contribute to the MDDF, and that all values are zero at very short distances, smaller than the radii of the atoms.

More interesting and general is to select atoms of a complex molecule, like a protein, using residue names, types, etc. Here we illustrate how this is done by providing selection strings to contributions to obtain the contributions to the MDDF of different types of residues of a protein to the total MDDF.

For example, if we want to split the contributions of the charged and neutral residues to the total MDDF distribution, we could use to following code. Here, solute refers to the protein.

charged_residues = PDBTools.select(atoms,"charged")
charged_contributions = contributions(results, SoluteGroup(charged_residues))

neutral_residues = PDBTools.select(atoms,"neutral")
neutral_contributions = contributions(atoms, SoluteGroup(neutral_residues))

The charged_contributions and neutral_contributions outputs are vectors containing the contributions of these residues to the total MDDF. The corresponding plot is:

plot(results.d,results.mddf,label="Total MDDF",linewidth=2)
plot!(results.d,charged_contributions,label="Charged residues",linewidth=2)
plot!(results.d,neutral_contributions,label="Neutral residues",linewidth=2)
plot!(xlabel="Distance / Å",ylabel="MDDF")

Resulting in:

Note here how charged residues contribute strongly to the peak at hydrogen-bonding distances, but much less in general. Of course all selection options could be used, to obtain the contributions of specific types of residues, atoms, the backbone, the side-chains, etc.

Reference functions

ComplexMixtures.contributionsFunction
contributions(R::Result, group::Union{SoluteGroup,SolventGroup}; type = :mddf)

Returns the contributions of the atoms of the solute or solvent to the MDDF, coordination number, or MD count.

Arguments

  • R::Result: The result of a calculation.
  • group::Union{SoluteGroup,SolventGroup}: The group of atoms to consider.
  • type::Symbol: The type of contributions to return. Can be :mddf (default), :coordination_number, or :md_count.

Examples

julia> using ComplexMixtures, PDBTools

julia> dir = ComplexMixtures.Testing.data_dir*"/Gromacs";

julia> atoms = readPDB(dir*"/system.pdb");

julia> protein = select(atoms, "protein");

julia> emim = select(atoms, "resname EMI"); 

julia> solute = AtomSelection(protein, nmols = 1)
AtomSelection 
    1231 atoms belonging to 1 molecule(s).
    Atoms per molecule: 1231
    Number of groups: 1231

julia> solvent = AtomSelection(emim, natomspermol = 20)
AtomSelection 
    5080 atoms belonging to 254 molecule(s).
    Atoms per molecule: 20
    Number of groups: 20

julia> results = load(dir*"/protein_EMI.json"); # load pre-calculated results

julia> ca_cb = contributions(results, SoluteGroup(["CA", "CB"])); # contribution of CA and CB atoms to the MDDF

julia> ca_cb = contributions(results, SoluteGroup(["CA", "CB"]); type=:coordination_number); # contribution of CA and CB atoms to the coordination number
source