/mmtf-cpp

The pure c++ implementation of the MMTF API, decoder and encoder.

Primary LanguageC++MIT LicenseMIT

Release License Build Status (Travis)

The macromolecular transmission format (MMTF) is a binary encoding of biological structures.

This repository holds the C++-03 compatible API, encoding and decoding libraries. The MMTF specification can be found here.

Prerequisites for using MMTF in C++

You need the headers of the MessagePack C++ library (version 2.1.5 or newer). If you do not have them on your machine already, you can download the "include" directory from the MessagePack GitHub repository.

How to use MMTF

You only need to include the mmtf.hpp header in your code to use MMTF. For instance a minimal example to load an MMTF file looks as follows:

#include <mmtf.hpp>

int main(int argc, char** argv) {
    mmtf::StructureData data;
    mmtf::decodeFromFile(data, "test.mmtf");
    return 0;
}

The C++ MMTF library is header only so you do not need to compile it. If you have a source file named demo.cpp (e.g. including the code above), you can generate an executable demo.exe as follows:

g++ -I<MSGPACK_INCLUDE_PATH> -I<MMTF_INCLUDE_PATH> demo.cpp -o demo.exe

Here, <MSGPACK_INCLUDE_PATH> and <MMTF_INCLUDE_PATH> are the paths to the "include" directories of MessagePack and this library respectively.

For your more complicated projects, a CMakeLists.txt is included for you.

Python bindings

The C++ MMTF library now can build python bindings using pybind11. To use them you must have A) a c++11 compatible compiler and B) python >= 3.6

to install, it is as simple as pip install .

(in the future possible pip install mmtf-cppy)

from mmtf_cppy import StructureData
import numpy as np
import math


def rotation_matrix(axis, theta):
    """
    Return the rotation matrix associated with counterclockwise rotation about
    the given axis by theta radians.
    from https://stackoverflow.com/a/6802723
    """
    axis = np.asarray(axis)
    axis = axis / math.sqrt(np.dot(axis, axis))
    a = math.cos(theta / 2.0)
    b, c, d = -axis * math.sin(theta / 2.0)
    aa, bb, cc, dd = a * a, b * b, c * c, d * d
    bc, ad, ac, ab, bd, cd = b * c, a * d, a * c, a * b, b * d, c * d
    return np.array([[aa + bb - cc - dd, 2 * (bc + ad), 2 * (bd - ac)],
                     [2 * (bc - ad), aa + cc - bb - dd, 2 * (cd + ab)],
                     [2 * (bd + ac), 2 * (cd - ab), aa + dd - bb - cc]])


theta = 1.2
axis = [0, 0, 1]

sd = StructureData("my_favorite_structure.mmtf")
sd.atomProperties["pymol_colorList"] = [1 if x % 2 == 0 else 5 for x in sd.xCoordList]
xyz = np.column_stack((sd.xCoordList, sd.yCoordList, sd.zCoordList))
xyz_rot = rotation_matrix(axis, theta).dot(xyz.T).T
sd.xCoordList, sd.yCoordList, sd.zCoordList = np.hsplit(xyz_rot, 3)
sd.write_to_file("my_favorite_structure_rot.mmtf")

Installation

You can also perform a system wide installation with cmake and ninja (or make).
To do so:

mkdir build
cd build
cmake -G Ninja ..
sudo ninja install

cmake automatically sets the installation directory to /usr/local/include, if you want to install it to another *include/ directory run cmake with the command:

cmake -G Ninja -DCMAKE_INSTALL_PREFIX=/home/me/local ..

Be aware that /include is added to the end of DCMAKE_INSTALL_PREFIX and that is where your files are installed (i.e. the above would install at /home/me/local/include/).

Examples and tests

To build the tests + examples we recommend using the following lines:

# download Catch2 testing framework, msgpack-c, and the mmtf-spec test-dataset
git submodule update --init --recursive
mkdir build
cd build
cmake -G Ninja -DBUILD_TESTS=ON  -Dmmtf_build_examples=ON ..
ninja
chmod +x ./tests/mmtf_tests
./tests/mmtf_tests

Example codes:

  • mmtf_demo.cpp: Loads an MMTF file and checks internal consistency using mmtf::StructureData::hasConsistentData.
./examples/mmtf_demo ../submodules/mmtf_spec/test-suite/mmtf/173D.mmtf
  • traverse.cpp: Loads an MMTF file and dumps it in human-readable forms.
./examples/traverse ../submodules/mmtf_spec/test-suite/mmtf/173D.mmtf
./examples/traverse ../submodules/mmtf_spec/test-suite/mmtf/173D.mmtf json
./examples/traverse ../submodules/mmtf_spec/test-suite/mmtf/173D.mmtf print
  • print_as_pdb.cpp: Loads an MMTF file and prints it in pdb format.
./examples/print_as_pdb ../submodules/mmtf_spec/test-suite/mmtf/173D.mmtf

Benchmark

Using the following simple code:

#include <mmtf.hpp>


int main(int argc, char** argv)
{
        for (int i=1; i<argc; ++i) {
                mmtf::StructureData sd;
                mmtf::decodeFromFile(sd, argv[i]);
        }
}

compiled via:

g++ -Ofast -Immtf/include  -Imsgpack/include  decode_all_mmtf.cpp

We are able to load 153,987 mmtf files (current size of the pdb) or 14.3GB from an SSD in 211.3 seconds (averaged over 4 runs with minimal differences between the runs).

Code documentation

You can generate a doxygen based documentation of the library by calling doxygen in the docs folder. You will need doxygen 1.8.11 or later for that. Open docs/html/index.html to see the generated documentation.