diff --git a/cmake_support/PROMOD3.cmake b/cmake_support/PROMOD3.cmake
index 57f8c46bc8ffbec467955813213c24131a71f179..1d6d802dc853d703c8e37687e5630eeb6c272381 100644
--- a/cmake_support/PROMOD3.cmake
+++ b/cmake_support/PROMOD3.cmake
@@ -673,7 +673,9 @@ macro(pymod)
   #-----------------------------------------------------------------------------
   if(NOT DISABLE_DOCUMENTATION)
     add_doc_dependency(NAME ${_ARG_NAME} DEP "${_ARG_NAME}_pymod")
-    add_doc_dependency(NAME ${_ARG_NAME} DEP "${_ABS_PY_FILES}")
+    if(_ABS_PY_FILES)
+      add_doc_dependency(NAME ${_ARG_NAME} DEP "${_ABS_PY_FILES}")
+    endif()
     add_py_mod_src(MOD "${_ARG_NAME}_pymod")
   endif()
 endmacro(pymod)
diff --git a/cmake_support/doc/index.rst b/cmake_support/doc/index.rst
index e3a5805c3882f3e43d1ad981b579fe33ce94148d..231bde25827c1ae1378c5c312e9aa0b7030057b8 100644
--- a/cmake_support/doc/index.rst
+++ b/cmake_support/doc/index.rst
@@ -97,9 +97,9 @@ Default dependencies in a module ``NAME``:
                         [DEPENDS_ON dep1 dep2]
                         [NEED_CONFIG_HEADER])
 
-  Define the |python| interface of a |project| ProMod3 module from a set of
-  |C++| wrappers and/or Python files. This will define the following make
-  targets (where ``NAME`` is the provided module name):
+  Define the |python| interface of a |project| module from a set of |C++|
+  wrappers and/or Python files. This will define the following make targets
+  (where ``NAME`` is the provided module name):
 
   - ``_NAME``: builds library :file:`_NAME` for |python| wrapper around |C++|
   - ``NAME_pymod``: copies (and/or translates) all |python| files
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
index ea6e4d0de6e56467fdb18cddec367b9978d83422..add2325c131b41524ffc61902cefc3c7b91d1eca 100644
--- a/core/CMakeLists.txt
+++ b/core/CMakeLists.txt
@@ -1,3 +1,4 @@
+add_subdirectory(init)
 add_subdirectory(pymod)
 add_subdirectory(doc)
 add_subdirectory(tests)
diff --git a/core/doc/index.rst b/core/doc/index.rst
index 904e46a8b44899eccf980857b40fde819be59a33..408c2a874eeb0597744c27aecf9e5b50906936e9 100644
--- a/core/doc/index.rst
+++ b/core/doc/index.rst
@@ -7,11 +7,74 @@
 This module gathers functions and classes which are not devoted to homology
 modeling per se but cover standard programming issues.
 
+Submodules
+--------------------------------------------------------------------------------
+
 .. toctree:: 
   :maxdepth: 2
-
+  
   pm3argparse
-
   helper
 
-..  LocalWords:  promod se toctree maxdepth argcheck
+Geometry functions
+--------------------------------------------------------------------------------
+
+.. function:: ConstructAtomPos(A, B, C, bond_length, angle, dihedral)
+
+  Constructs position of atom "D" based on bond length (C-D), angle (B-C-D) and
+  dihedral (A-B-C-D).
+
+  :param A: Position of atom A
+  :type A:  :class:`~ost.geom.Vec3`
+  :param B: Position of atom B
+  :type B:  :class:`~ost.geom.Vec3`
+  :param C: Position of atom C
+  :type C:  :class:`~ost.geom.Vec3`
+  :param bond_length: Bond length (C-D)
+  :type bond_length:  :class:`float`
+  :param angle: Angle (B-C-D)
+  :type angle:  :class:`float`
+  :param dihedral: Dihedral (A-B-C-D)
+  :type dihedral:  :class:`float`
+  :return: Position of atom D
+  :rtype:  :class:`~ost.geom.Vec3`
+
+.. function:: ConstructCBetaPos(n_pos, ca_pos, c_pos)
+
+  Constructs position of C-beta atom given the positions of the backbone nitrogen,
+  C-alpha and c atoms.
+
+  :param n_pos: Position of nitrogen atom
+  :type n_pos:  :class:`~ost.geom.Vec3`
+  :param ca_pos: Position of C-alpha atom
+  :type ca_pos:  :class:`~ost.geom.Vec3`
+  :param c_pos: Position of C atom
+  :type c_pos:  :class:`~ost.geom.Vec3`
+  :return: Position of C-beta atom
+  :rtype:  :class:`~ost.geom.Vec3`
+
+.. function:: RotationAroundLine(axis, anchor, angle)
+
+  Creates a geometric transform leading to a rotation with specified `angle`
+  around a line defined by `axis` and `anchor`.
+
+  :param axis: Axis of rotation
+  :type axis:  :class:`~ost.geom.Vec3`
+  :param anchor: Anchor for rotation
+  :type anchor:  :class:`~ost.geom.Vec3`
+  :param angle: Angle (in radians in range [-pi,pi]) of rotation
+  :type angle:  :class:`float`
+  :return: Transformation matrix
+  :rtype:  :class:`~ost.geom.Mat4`
+
+.. function:: RotationAroundLine(axis, angle)
+
+  Creates a 3x3 matrix for a rotation by a specified `angle` around an `axis`
+  going through the origin.
+
+  :param axis: Axis of rotation
+  :type axis:  :class:`~ost.geom.Vec3`
+  :param angle: Angle (in radians in range [-pi,pi]) of rotation
+  :type angle:  :class:`float`
+  :return: Rotation matrix
+  :rtype:  :class:`~ost.geom.Mat3`
diff --git a/core/init/CMakeLists.txt b/core/init/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8a3078605b9ca1875800ecbe67db66a63a3e2b2c
--- /dev/null
+++ b/core/init/CMakeLists.txt
@@ -0,0 +1,10 @@
+# for translation of __init__.py
+set(_CRE_INIT_SUBST_DICT OST_COMPOUNDS_CHEMLIB_PATH="${OST_COMPOUNDS_CHEMLIB_PATH}"
+                         OST_ROOT=${OST_ROOT}
+                         PROMOD3_VERSION_STRING=${PROMOD3_VERSION_STRING}
+                         GIT_BRANCH=${GIT_BRANCH}
+                         GIT_COMMIT_HASH=${GIT_COMMIT_HASH})
+
+# top level PM3 init.py (Python only)
+pymod(NAME init PY __init__.py TRANSLATE ${_CRE_INIT_SUBST_DICT} END_TRANSLATE
+      OUTPUT_DIR "promod3")
diff --git a/core/pymod/__init__.py.in b/core/init/__init__.py.in
similarity index 100%
rename from core/pymod/__init__.py.in
rename to core/init/__init__.py.in
diff --git a/core/pymod/CMakeLists.txt b/core/pymod/CMakeLists.txt
index 9a176a9a245ee4fd38c0398252f8f73cf0aa64cd..e6167acb609458783aefda8db43d6e792872e473 100644
--- a/core/pymod/CMakeLists.txt
+++ b/core/pymod/CMakeLists.txt
@@ -1,12 +1,13 @@
-set(PROMOD3_CORE_FILES __init__.py helper.py pm3argparse.py)
+# core module
+set(CORE_CPP
+  export_geom.cc
+  wrap_core.cc
+)
 
-# for translation of __init__.py
-set(_CRE_INIT_SUBST_DICT OST_COMPOUNDS_CHEMLIB_PATH="${OST_COMPOUNDS_CHEMLIB_PATH}"
-                         OST_ROOT=${OST_ROOT}
-                         PROMOD3_VERSION_STRING=${PROMOD3_VERSION_STRING}
-                         GIT_BRANCH=${GIT_BRANCH}
-                         GIT_COMMIT_HASH=${GIT_COMMIT_HASH})
+set(CORE_PYMOD
+  __init__.py
+  helper.py
+  pm3argparse.py
+)
 
-pymod(NAME core PY ${PROMOD3_CORE_FILES} IN_DIR core
-      __init__.py TRANSLATE ${_CRE_INIT_SUBST_DICT} END_TRANSLATE
-      OUTPUT_DIR "promod3")
+pymod(NAME core CPP ${CORE_CPP} PY ${CORE_PYMOD})
diff --git a/core/pymod/__init__.py b/core/pymod/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..3acbe984704f1abb2d9f9f6c0b29ea14e53ee838
--- /dev/null
+++ b/core/pymod/__init__.py
@@ -0,0 +1 @@
+from _core import *
\ No newline at end of file
diff --git a/core/pymod/core/__init__.py b/core/pymod/core/__init__.py
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/core/pymod/export_geom.cc b/core/pymod/export_geom.cc
new file mode 100644
index 0000000000000000000000000000000000000000..f39d430de79fdbe59c9b05d5cac75f849591a317
--- /dev/null
+++ b/core/pymod/export_geom.cc
@@ -0,0 +1,34 @@
+#include <boost/python.hpp>
+#include <promod3/core/geom_base.hh>
+
+using namespace promod3::core;
+using namespace boost::python;
+
+namespace {
+geom::Vec3 WrapConstructAtomPos(const geom::Vec3& A, const geom::Vec3& B,
+                                const geom::Vec3& C, Real bond_length,
+                                Real angle, Real dihedral) {
+  geom::Vec3 D;
+  ConstructAtomPos(A, B, C, bond_length, angle, dihedral, D);
+  return D;
+}
+
+geom::Vec3 WrapConstructCBetaPos(const geom::Vec3& n_pos,
+                                 const geom::Vec3& ca_pos,
+                                 const geom::Vec3& c_pos) {
+  geom::Vec3 cb_pos;
+  ConstructCBetaPos(n_pos, ca_pos, c_pos, cb_pos);
+  return cb_pos;
+}
+} // anon ns
+
+void export_geom() {
+  def("ConstructAtomPos", WrapConstructAtomPos,
+      (arg("A"), arg("B"), arg("C"), arg("bond_length"), arg("angle"),
+       arg("dihedral")));
+  def("ConstructCBetaPos", WrapConstructCBetaPos,
+      (arg("n_pos"), arg("ca_pos"), arg("c_pos")));
+  def("RotationAroundLine", RotationAroundLine,
+      (arg("axis"), arg("anchor"), arg("angle")));
+  def("RotationAroundAxis", RotationAroundAxis, (arg("axis"), arg("angle")));
+}
diff --git a/core/pymod/core/helper.py b/core/pymod/helper.py
similarity index 100%
rename from core/pymod/core/helper.py
rename to core/pymod/helper.py
diff --git a/core/pymod/core/pm3argparse.py b/core/pymod/pm3argparse.py
similarity index 100%
rename from core/pymod/core/pm3argparse.py
rename to core/pymod/pm3argparse.py
diff --git a/core/pymod/wrap_core.cc b/core/pymod/wrap_core.cc
new file mode 100644
index 0000000000000000000000000000000000000000..9ae2b4694be04e5479c989008d91ebce931e0dca
--- /dev/null
+++ b/core/pymod/wrap_core.cc
@@ -0,0 +1,8 @@
+#include <boost/python.hpp>
+
+void export_geom();
+
+BOOST_PYTHON_MODULE(_core)
+{
+  export_geom();
+}