From 728ad1c9334ece304c0796c904ab650b3c59855c Mon Sep 17 00:00:00 2001
From: Gabriel Studer <gabriel.studer@unibas.ch>
Date: Fri, 5 Apr 2024 18:15:53 +0200
Subject: [PATCH] disable numpy support in C++ layer

Numpy support in C++ enabled features at two points:
Efficient way of setting positions in entity handles or setting meshes
in gfx.PrimList.

Support for newer numpy versions would've required an effort to implement.
As far as I know, no one uses these features (fingers crossed) so let's just
dump numpy alltogether to simplify the build system.
---
 CMakeLists.txt                           |  15 ---
 cmake_support/FindNumpy.cmake            |  31 ------
 modules/base/pymod/__init__.py.in        |   2 +-
 modules/base/pymod/wrap_base.cc          |   1 -
 modules/config/CMakeLists.txt            |   6 --
 modules/config/config.hh.in              |   1 -
 modules/doc/install.rst                  |   3 -
 modules/gfx/pymod/export_primlist.cc     | 110 +------------------
 modules/gfx/tests/test_gfx.py            |  41 -------
 modules/mol/base/doc/editors.rst         |  33 ------
 modules/mol/base/doc/entity.rst          |  19 ----
 modules/mol/base/pymod/export_editors.cc | 131 -----------------------
 modules/mol/base/pymod/export_entity.cc  |  71 ------------
 modules/mol/base/tests/CMakeLists.txt    |   4 -
 modules/mol/base/tests/test_numpy.py     |  75 -------------
 scripts/ost-nightly-build.sh             |   1 -
 16 files changed, 3 insertions(+), 541 deletions(-)
 delete mode 100644 cmake_support/FindNumpy.cmake
 delete mode 100644 modules/mol/base/tests/test_numpy.py

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9fd6b1c03..552aae0c8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -36,8 +36,6 @@ option(OPENGLPREFERENCE_LEGACY "whether to use the OpenGL Legacy GL implementati
        OFF)
 option(ENABLE_INFO "whether openstructure should be compiled with support for the info library"
        ON)
-option(USE_NUMPY "whether numpy support is added"
-      OFF)
 option(USE_DOUBLE_PRECISION "whether to compile in double precision" 
        OFF)
 option(ENABLE_SPNAV "whether 3DConnexion devices should be supported"
@@ -117,11 +115,6 @@ if (USE_SHADER)
 else()
   set(_SHADER OFF)
 endif()
-if (USE_NUMPY)
-  set(_NUMPY ON)
-else()
-  set(_NUMPY OFF)
-endif()
 if (COMPILE_TMTOOLS)
   set(_TM_TOOLS ON)
 else()
@@ -228,10 +221,6 @@ find_package(PNG REQUIRED)
 find_package(FFTW REQUIRED)
 find_package(TIFF REQUIRED)
 
-if(USE_NUMPY)
-  find_package(Numpy REQUIRED)
-endif()
-
 if(ENABLE_MM)
   find_package(OpenMM REQUIRED)
   set(_OPENMM_PLUGINS "${OPEN_MM_PLUGIN_DIR}")
@@ -302,9 +291,6 @@ include_directories(${Boost_INCLUDE_DIRS}
                     ${OPEN_MM_INCLUDE_DIRS}
                     ${SQLITE3_INCLUDE_DIRS}
                     )
-if(USE_NUMPY)
-include_directories(${PYTHON_NUMPY_INCLUDE_DIR})
-endif()
 
 if (UNIX)
   SET(CMAKE_SKIP_BUILD_RPATH  FALSE)
@@ -353,7 +339,6 @@ message(STATUS
         "   Graphical interface               (-DENABLE_GUI) : ${_UI}\n"
         "   OpenGL support                    (-DENABLE_GFX) : ${_OPENGL}\n"
         "   Shader support                    (-DUSE_SHADER) : ${_SHADER}\n"
-        "   Numpy support                      (-DUSE_NUMPY) : ${_NUMPY}\n"
         "   SpaceNav Device support         (-DENABLE_SPNAV) : ${_SPNAV}\n"
         "   OpenMM support                     (-DENABLE_MM) : ${_OPENMM}\n"
         "   OpenMM plugins            (-DOPEN_MM_PLUGIN_DIR) : ${_OPENMM_PLUGINS}\n"
diff --git a/cmake_support/FindNumpy.cmake b/cmake_support/FindNumpy.cmake
deleted file mode 100644
index 2f67a64ed..000000000
--- a/cmake_support/FindNumpy.cmake
+++ /dev/null
@@ -1,31 +0,0 @@
-if (PYTHON_NUMPY_INCLUDE_DIR)
-  # in cache already
-  set (PYTHON_NUMPY_FIND_QUIETLY TRUE)
-endif (PYTHON_NUMPY_INCLUDE_DIR)
-
-#INCLUDE(FindPython)
-
-IF(Python_EXECUTABLE)
-    EXEC_PROGRAM ("${Python_EXECUTABLE}"
-      ARGS "-c 'import numpy; print(numpy.get_include())'"
-      OUTPUT_VARIABLE PYTHON_NUMPY_INCLUDE_DIR
-      RETURN_VALUE PYTHON_NUMPY_NOT_FOUND)
-    if (PYTHON_NUMPY_NOT_FOUND)
-      set(PYTHON_NUMPY_FOUND FALSE)
-    else (PYTHON_NUMPY_NOT_FOUND)
-      set (PYTHON_NUMPY_FOUND TRUE)
-      set (PYTHON_NUMPY_INCLUDE_DIR ${PYTHON_NUMPY_INCLUDE_DIR} CACHE STRING "Numpy include path")
-    endif (PYTHON_NUMPY_NOT_FOUND)
-ENDIF(Python_EXECUTABLE)
-
-if (PYTHON_NUMPY_FOUND)
-  if (NOT PYTHON_NUMPY_FIND_QUIETLY)
-    message (STATUS "Numpy headers found")
-  endif (NOT PYTHON_NUMPY_FIND_QUIETLY)
-else (PYTHON_NUMPY_FOUND)
-  if (Numpy_FIND_REQUIRED)
-    message (FATAL_ERROR "Numpy headers missing")
-  endif (Numpy_FIND_REQUIRED)
-endif (PYTHON_NUMPY_FOUND)
-
-MARK_AS_ADVANCED (PYTHON_NUMPY_INCLUDE_DIR)
diff --git a/modules/base/pymod/__init__.py.in b/modules/base/pymod/__init__.py.in
index 4237d6b95..45c3e6000 100644
--- a/modules/base/pymod/__init__.py.in
+++ b/modules/base/pymod/__init__.py.in
@@ -18,7 +18,7 @@
 #------------------------------------------------------------------------------
 import os
 
-__all__=['CharList','Correl', 'FileLogSink', 'FloatList', 'FloatMatrix', 'FloatMatrix3', 'FloatMatrix4', 'GetCurrentLogSink', 'GetPrefixPath', 'GetSharedDataPath', 'GetVerbosityLevel', 'Histogram', 'IntList', 'LogDebug', 'LogError', 'LogInfo', 'LogScript', 'LogSink', 'LogTrace', 'LogVerbose', 'LogWarning', 'Max', 'Mean', 'Median', 'Min', 'MultiLogSink', 'PopLogSink', 'PopVerbosityLevel', 'PushLogSink', 'PushVerbosityLevel', 'Range', 'SetPrefixPath', 'StdDev', 'StreamLogSink', 'StringList', 'StringLogSink', 'Units', 'VERSION', 'VERSION_MAJOR', 'VERSION_MINOR', 'VERSION_PATCH', 'WITH_NUMPY', 'conop', 'geom', 'io', 'mol', 'seq', 'stutil' @ALL_ADDITIONAL_MODULES@]
+__all__=['CharList','Correl', 'FileLogSink', 'FloatList', 'FloatMatrix', 'FloatMatrix3', 'FloatMatrix4', 'GetCurrentLogSink', 'GetPrefixPath', 'GetSharedDataPath', 'GetVerbosityLevel', 'Histogram', 'IntList', 'LogDebug', 'LogError', 'LogInfo', 'LogScript', 'LogSink', 'LogTrace', 'LogVerbose', 'LogWarning', 'Max', 'Mean', 'Median', 'Min', 'MultiLogSink', 'PopLogSink', 'PopVerbosityLevel', 'PushLogSink', 'PushVerbosityLevel', 'Range', 'SetPrefixPath', 'StdDev', 'StreamLogSink', 'StringList', 'StringLogSink', 'Units', 'VERSION', 'VERSION_MAJOR', 'VERSION_MINOR', 'VERSION_PATCH', 'conop', 'geom', 'io', 'mol', 'seq', 'stutil' @ALL_ADDITIONAL_MODULES@]
 
 from ._ost_base import *
 from .stutil import *
diff --git a/modules/base/pymod/wrap_base.cc b/modules/base/pymod/wrap_base.cc
index 2c4877911..7f2d8b114 100644
--- a/modules/base/pymod/wrap_base.cc
+++ b/modules/base/pymod/wrap_base.cc
@@ -97,7 +97,6 @@ BOOST_PYTHON_MODULE(_ost_base)
   scope().attr("VERSION_MAJOR")=OST_VERSION_MAJOR;
   scope().attr("VERSION_MINOR")=OST_VERSION_MINOR;  
   scope().attr("VERSION_PATCH")=OST_VERSION_PATCH;
-  scope().attr("WITH_NUMPY")= OST_NUMPY_SUPPORT_ENABLED;
   export_Logger();
   export_Range();
   export_Units();
diff --git a/modules/config/CMakeLists.txt b/modules/config/CMakeLists.txt
index 60c1c38e2..826de455f 100644
--- a/modules/config/CMakeLists.txt
+++ b/modules/config/CMakeLists.txt
@@ -15,12 +15,6 @@ if (USE_SHADER)
 else()
   set(shader_support 0)
 endif()
-
-if (USE_NUMPY)
-  set(numpy_support 1)
-else()
-  set(numpy_support 0)
-endif()
 if (PROFILE)
   set(profiling_enabled 1)
 else()
diff --git a/modules/config/config.hh.in b/modules/config/config.hh.in
index e69421653..e48f750d4 100644
--- a/modules/config/config.hh.in
+++ b/modules/config/config.hh.in
@@ -29,7 +29,6 @@
 #define OST_DOUBLE_PRECISION @double_prec@
 #define OST_STATIC_PROPERTY_WORKAROUND @static_props@
 #define OST_FFT_USE_THREADS @fftw_use_threads@
-#define OST_NUMPY_SUPPORT_ENABLED @numpy_support@
 #define OST_UBUNTU_LAYOUT @ubuntu_layout@
 #define OST_INFO_ENABLED @info_enabled@
 
diff --git a/modules/doc/install.rst b/modules/doc/install.rst
index 2f5470c56..1fc703dd9 100644
--- a/modules/doc/install.rst
+++ b/modules/doc/install.rst
@@ -178,9 +178,6 @@ can influence it.
   then available at python level. This option requires a Fortran compiler. 
   By default, this option is switched off.
 
-* `USE_NUMPY` allows OpenStructure to pass back data in NumPy format. By 
-  default, this is switched off.
-
 * `ENABLE_MM` controls whether the molecular mechanics module is enabled. By
   default, this is switched off. If it is turned on, you should also set the
   paths to your local OpenMM installation:
diff --git a/modules/gfx/pymod/export_primlist.cc b/modules/gfx/pymod/export_primlist.cc
index 4538f366e..e0d21eb81 100644
--- a/modules/gfx/pymod/export_primlist.cc
+++ b/modules/gfx/pymod/export_primlist.cc
@@ -26,122 +26,16 @@ using namespace boost::python;
 using namespace ost;
 using namespace ost::gfx;
 
-/* The following #include triggers a deprecation warning upon compilation:
-
-In file included from /unibas/lcs-software/software/Python/2.7.11-goolf-1.7.20/lib/python2.7/site-packages/numpy/core/include/numpy/ndarraytypes.h:1781:0,
-                 from /unibas/lcs-software/software/Python/2.7.11-goolf-1.7.20/lib/python2.7/site-packages/numpy/core/include/numpy/ndarrayobject.h:18,
-                 from /unibas/lcs-software/software/Python/2.7.11-goolf-1.7.20/lib/python2.7/site-packages/numpy/core/include/numpy/arrayobject.h:4,
-                 from /home/zohixe92/build/ost-develop/modules/gfx/pymod/export_primlist.cc:30:
-/unibas/lcs-software/software/Python/2.7.11-goolf-1.7.20/lib/python2.7/site-packages/numpy/core/include/numpy/npy_1_7_deprecated_api.h:15:2: warning: #warning "Using deprecated NumPy API, disable it by " "#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-Wcpp]
- #warning "Using deprecated NumPy API, disable it by " \
-  ^
-
-It looks like just including <numpy/arrayobject.h>, without actually using anything from it, already triggers the
-warning. This could be a side effect of other includes in export_primlist.cc though, such as boost.
-
-The Numpy C API documentation <https://docs.scipy.org/doc/numpy-1.15.1/reference/c-api.deprecations.html> is very
-unclear about what is deprecated exactly (the whole API or only direct data access?) The Array API doc
-<https://docs.scipy.org/doc/numpy-1.16.0/reference/c-api.array.html> doesn't clearly state what to import instead,
-and while some functions are marked as deprecated I couldn't see that we are using any of them. Last, the migration sed
-script <https://github.com/numpy/numpy/blob/master/tools/replace_old_macros.sed> didn't trigger any changes.
-
-The warnings appear to be safe though, behavior has been checked in <https://jira.biozentrum.unibas.ch/browse/SCHWED-3149>
-and Numpy guarantees to maintain them until the next major release (2.0). So it is safe to ignore them for now.
-They can be silenced with the following #define, however it was decided to keep them for now as functionality *will*
-disappear in the future.
-
-#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
-
-In the future it might be desirable to move to the newer API in Boost::Python::NumPy
-which uses modern C++ instead of old-style C macros.
-<https://www.boost.org/doc/libs/1_64_0/libs/python/doc/html/numpy/reference/ndarray.html>
-*/
-#if OST_NUMPY_SUPPORT_ENABLED
-#include <numpy/arrayobject.h>
-#endif
-
 namespace {
+  // used numpy support that has been deprecated...
   void add_mesh(PrimList& p, object ova, object ona, object oca, object oia)
   {
-#if OST_NUMPY_SUPPORT_ENABLED
-    if(!PyArray_Check(ova.ptr())) {
-      throw Error("ova is not a numpy array");
-    }
-    PyArrayObject* va=reinterpret_cast<PyArrayObject*>(ova.ptr());
-    if(!PyArray_ISCONTIGUOUS(va)) {
-      throw Error("expected vertex array to be contiguous");
-    }
-    if(PyArray_TYPE(va)!=NPY_FLOAT) {
-      throw Error("expected vertex array to be of dtype=float32");
-    }
-    size_t v_size=PyArray_SIZE(va);
-    if(v_size%3!=0) {
-      throw Error("expected vertex array size to be divisible by 3");
-    }
-    size_t v_count=v_size/3;
-    float* vp=reinterpret_cast<float*>(PyArray_DATA(va));
-    float* np=0;
-    float* cp=0;
-    if(!ona.is_none()) {
-      if(!PyArray_Check(ona.ptr())) {
-        throw Error("ona is not a numpy array");
-      }
-      PyArrayObject* na=reinterpret_cast<PyArrayObject*>(ona.ptr());
-      if(!PyArray_ISCONTIGUOUS(na)) {
-        throw Error("expected normal array to be contiguous");
-      }
-      if(PyArray_TYPE(na)!=NPY_FLOAT) {
-        throw Error("expected normal array to be of dtype=float32");
-      }
-      if((size_t)PyArray_SIZE(na)!=v_size) {
-        throw Error("expected normal array size to match vertex array size");
-      }
-      np=reinterpret_cast<float*>(PyArray_DATA(na));
-    }
-    if(!oca.is_none()) {
-      if(!PyArray_Check(oca.ptr())) {
-        throw Error("oca is not a numpy array");
-      }
-      PyArrayObject* ca=reinterpret_cast<PyArrayObject*>(oca.ptr());
-      if(!PyArray_ISCONTIGUOUS(ca)) {
-        throw Error("expected color array to be contiguous");
-      }
-      if(PyArray_TYPE(ca)!=NPY_FLOAT) {
-        throw Error("expected color array to be of dtype=float32");
-      }
-      if((size_t)PyArray_SIZE(ca)!=v_count*4) {
-        throw Error("expected color array size to equal vertex-count x 4");
-      }
-      cp=reinterpret_cast<float*>(PyArray_DATA(ca));
-    }
-    if(!PyArray_Check(oia.ptr())) {
-      throw Error("oia is not a numpy array");
-    }
-    PyArrayObject* ia=reinterpret_cast<PyArrayObject*>(oia.ptr());
-    if(!PyArray_ISCONTIGUOUS(ia)) {
-      throw Error("expected vertex array to be contiguous");
-    }
-    if(PyArray_TYPE(ia)!=NPY_UINT) {
-      throw Error("expected vertex array to be of dtype=uint32");
-    }
-    size_t i_size=PyArray_SIZE(ia);
-    unsigned int* ip=reinterpret_cast<unsigned int*>(PyArray_DATA(ia));
-
-    p.AddMesh(vp,np,cp,v_count,ip,i_size/3);
-#else
-    throw Error("AddMesh requires compiled-in numpy support");
-#endif
+    throw Error("AddMesh requires compiled-in numpy support and that has been deprecated");
   }
 }
 
 void export_primlist()
 {
-#if OST_NUMPY_SUPPORT_ENABLED
-  // The following define enforces no return value when calling import_array
-  #define NUMPY_IMPORT_ARRAY_RETVAL
-  import_array(); // magic handshake for numpy module
-#endif
-
   class_<PrimList, bases<GfxObj>, boost::shared_ptr<PrimList>, boost::noncopyable>("PrimList", init<const String& >())
     .def("Clear",&PrimList::Clear)
     .def("_add_line",&PrimList::AddLine)
diff --git a/modules/gfx/tests/test_gfx.py b/modules/gfx/tests/test_gfx.py
index 2baf689d8..d4635ca18 100644
--- a/modules/gfx/tests/test_gfx.py
+++ b/modules/gfx/tests/test_gfx.py
@@ -28,15 +28,6 @@ import ost.mol as mol
 import ost.gfx as gfx
 import ost.geom as geom
 
-if ost.WITH_NUMPY:
-  has_numpy=True
-  try:
-    import numpy
-  except ImportError as e:
-    has_numpy=False
-else:
-  has_numpy=False
-
 def col_delta(c1,c2):
   return geom.Distance(geom.Vec3(c1[0],c1[1],c1[2]),geom.Vec3(c2[0],c2[1],c2[2]))
 
@@ -120,38 +111,6 @@ class TestGfx(unittest.TestCase):
     pl.AddCyl(geom.Vec3(0,0,0),geom.Vec3(1,2,3),radius1=0.5,radius2=0.1,color1=gfx.BLUE,color2=gfx.GREEN)
     pl.AddText("foo",[0,2,3])
     pl.AddText("bar",[-2,0,0],color=gfx.WHITE,point_size=8)
-    if has_numpy:
-      pl.AddMesh(numpy.zeros((5,3),dtype=numpy.float32),
-                 numpy.zeros((5,3),dtype=numpy.float32),
-                 numpy.zeros((5,4),dtype=numpy.float32),
-                 numpy.zeros((2,3),dtype=numpy.uint32))
-      pl.AddMesh(numpy.zeros((7,3),dtype=numpy.float32),
-                 None,
-                 None,
-                 numpy.zeros((4,3),dtype=numpy.uint32))
-
-      # Passing wrong data type should fail
-      with self.assertRaises(Exception):
-        pl.AddMesh(numpy.zeros((5, 3), dtype=numpy.uint32),
-                   numpy.zeros((5, 3), dtype=numpy.float32),
-                   numpy.zeros((5, 4), dtype=numpy.float32),
-                   numpy.zeros((2, 3), dtype=numpy.uint32))
-      with self.assertRaises(Exception):
-        pl.AddMesh(numpy.zeros((5, 3), dtype=numpy.float32),
-                   numpy.zeros((5, 3), dtype=numpy.uint32),
-                   numpy.zeros((5, 4), dtype=numpy.float32),
-                   numpy.zeros((2, 3), dtype=numpy.uint32))
-      with self.assertRaises(Exception):
-        pl.AddMesh(numpy.zeros((5, 3), dtype=numpy.float32),
-                   numpy.zeros((5, 3), dtype=numpy.float32),
-                   numpy.zeros((5, 4), dtype=numpy.uint32),
-                   numpy.zeros((2, 3), dtype=numpy.uint32))
-      with self.assertRaises(Exception):
-        pl.AddMesh(numpy.zeros((5, 3), dtype=numpy.float32),
-                   numpy.zeros((5, 3), dtype=numpy.float32),
-                   numpy.zeros((5, 4), dtype=numpy.float32),
-                   numpy.zeros((2, 3), dtype=numpy.float32))
-                 
 
 if __name__== '__main__':
   from ost import testutils
diff --git a/modules/mol/base/doc/editors.rst b/modules/mol/base/doc/editors.rst
index 24162f9fa..01214c4b3 100644
--- a/modules/mol/base/doc/editors.rst
+++ b/modules/mol/base/doc/editors.rst
@@ -439,39 +439,6 @@ Euclidian space.
   
      Set the transformed position of atoms. This method will also update the
      original position of atoms by applying the inverse of the entity transform.
-
-     Setting all positions at once is by far faster than call the function for
-     each atom, but it is only available if OpenStructure was compiled with an
-     enabled ``USE_NUMPY`` flag (see :ref:`here <cmake-flags>` for details). The
-     fastest option to work with all atom positions externally is to extract the
-     list of :attr:`~ost.mol.EntityHandle.atoms` with
-     :meth:`ost.mol.EntityHandle.GetPositions` (with *sort_by_index = False*).
-     Then extract a buffered editor and use the same list of atoms with a
-     modified numpy array as input to this function. Example:
-
-     .. code-block:: python
-
-       # get atom list and positions
-       atom_list = ent.atoms
-       positions = ent.GetPositions(False)
-       # modify positions but keep ent and atom_list unchanged
-       # ...
-       # apply changes to entity all at once
-       edi = ent.EditXCS(mol.BUFFERED_EDIT)
-       edi.SetAtomPos(atom_list, positions)
-       edi.UpdateICS()
-     
-     :param atom: A valid atom handle
-     :type  atom: :class:`ost.mol.AtomHandle`
-     :param atom_list: A valid atom handle list or a list of atom :attr:`indices
-                       <ost.mol.AtomHandle.index>`.
-     :type  atom_list: :class:`ost.mol.AtomHandleList` or :class:`list` of
-                       :class:`int`
-     :param pos: The new position
-     :type  pos: :class:`~ost.geom.Vec3`
-     :param pos_list: An array of positions (shape [*len(atom_list)*, 3],
-                      preferably contiguous array in memory (C order)).
-     :type  pos_list: :class:`numpy.array`
     
   .. method:: SetAtomOriginalPos(atom, pos)
               SetAtomOriginalPos(atom_list, pos_list)
diff --git a/modules/mol/base/doc/entity.rst b/modules/mol/base/doc/entity.rst
index 4238bfbce..6d8f4ea10 100644
--- a/modules/mol/base/doc/entity.rst
+++ b/modules/mol/base/doc/entity.rst
@@ -131,14 +131,6 @@ Entity Handle
 
     :type: Vec3
 
-  .. attribute:: positions
-
-    Equivalent to calling :meth:`GetPositions` with *sort_by_index = True*. This
-    property is read-only and only available if OpenStructure was compiled with
-    an enabled ``USE_NUMPY`` flag (see :ref:`here <cmake-flags>` for details).
-
-    :type: :class:`numpy.array`
-
   .. attribute:: valid
 
     Validity of handle.
@@ -321,17 +313,6 @@ Entity Handle
   .. method:: GetGeometricCenter()
 
     See :attr:`geometric_center`
-
-  .. method:: GetPositions(sort_by_index=True)
-
-    :return: Array of atom positions for this entity.
-    :rtype:  :class:`numpy.array` (shape [:attr:`atom_count`, 3])
-    :param sort_by_index: If True, the atoms are sorted by their
-                          :attr:`~AtomHandle.index`. Otherwise, they are sorted
-                          as they appear in the :attr:`atoms` list.
-
-    This method is only available if OpenStructure was compiled with an enabled
-    ``USE_NUMPY`` flag (see :ref:`here <cmake-flags>` for details).
     
   .. method:: FindWithin(pos, radius)
   
diff --git a/modules/mol/base/pymod/export_editors.cc b/modules/mol/base/pymod/export_editors.cc
index e20ee4d4e..e2cd89b9b 100644
--- a/modules/mol/base/pymod/export_editors.cc
+++ b/modules/mol/base/pymod/export_editors.cc
@@ -29,18 +29,6 @@ using namespace boost::python;
 using namespace ost;
 using namespace ost::mol;
 
-/* Including NumPy headers produces compiler warnings. The ones about "Using
-   deprecated NumPy API..." we can not get rid of. The highest NumPy version we
-   support is 1.6 while the non-deprecated API starts with version 1.7.
-   Also see the comment in modules/gfx/pymod/export_primlist.cc for further
-   information.
-*/
-#if OST_NUMPY_SUPPORT_ENABLED
-#include <numpy/numpyconfig.h>
-#define NPY_NO_DEPRECATED_API NPY_1_6_API_VERSION
-#include <numpy/arrayobject.h>
-#endif
-
 namespace {
 
 BondHandle (EditorBase::*connect_a)(const AtomHandle&, 
@@ -93,74 +81,6 @@ void (ICSEditor::*rotate_torsion_b)(const AtomHandle&, const AtomHandle&,
 
 void (EditorBase::*renumber_chain_a)(ChainHandle,const ResNumList&)=&EditorBase::RenumberChain;
 void (EditorBase::*renumber_chain_b)(const ChainHandle&,int, bool)=&EditorBase::RenumberChain;
-#if OST_NUMPY_SUPPORT_ENABLED
-template<typename T, bool O>
-void set_pos2_nc_t(XCSEditor& e, const AtomHandleList& alist, PyArrayObject* na)
-{
-  size_t count=0;
-  for(AtomHandleList::const_iterator ait=alist.begin();ait!=alist.end();++ait,++count) {
-    if(O) {
-      e.SetAtomOriginalPos(*ait,geom::Vec3(static_cast<Real>(*reinterpret_cast<T*>(PyArray_GETPTR2(na,count,0))),
-                                           static_cast<Real>(*reinterpret_cast<T*>(PyArray_GETPTR2(na,count,1))),
-                                           static_cast<Real>(*reinterpret_cast<T*>(PyArray_GETPTR2(na,count,2)))));
-    } else {
-      e.SetAtomTransformedPos(*ait,geom::Vec3(static_cast<Real>(*reinterpret_cast<T*>(PyArray_GETPTR2(na,count,0))),
-                                              static_cast<Real>(*reinterpret_cast<T*>(PyArray_GETPTR2(na,count,1))),
-                                              static_cast<Real>(*reinterpret_cast<T*>(PyArray_GETPTR2(na,count,2)))));
-    }
-  }
-}
-
-template<bool O>
-void set_pos2_t(XCSEditor& e, const AtomHandleList& alist, object pyobj)
-{
-  size_t acount = alist.size();
-  
-  if(!PyArray_Check(pyobj.ptr())) {
-    throw Error("expected a numpy array");
-    return;
-  }
-  PyArrayObject* na=reinterpret_cast<PyArrayObject*>(pyobj.ptr());
-  
-  if(PyArray_NDIM(na)!=2 || PyArray_DIM(na,0)!=int(acount) || PyArray_DIM(na,1)!=3) {
-    throw Error("expected a numpy array of shape (NAtoms, 3)");
-    return;
-  }
-  
-  if(PyArray_ISCONTIGUOUS(na)) {
-    if(PyArray_TYPE(na)==NPY_FLOAT) {
-      if(O) {
-        e.SetAtomOriginalPos(alist,reinterpret_cast<float*>(PyArray_DATA(na)));
-      } else {
-        e.SetAtomTransformedPos(alist,reinterpret_cast<float*>(PyArray_DATA(na)));
-      }
-    } else if(PyArray_TYPE(na)==NPY_DOUBLE) {
-      if(O) {
-        e.SetAtomOriginalPos(alist,reinterpret_cast<double*>(PyArray_DATA(na)));
-      } else {
-        e.SetAtomTransformedPos(alist,reinterpret_cast<double*>(PyArray_DATA(na)));
-      }
-    } else {
-      throw Error("expected a numpy array of type float or double");
-      return;
-    }
-  } else {
-    // non-contiguous
-#if 0
-    throw Error("expected contiguous numpy array");
-#else
-    if(PyArray_TYPE(na)==NPY_FLOAT) {
-      set_pos2_nc_t<float,O>(e,alist,na);
-    } else if(PyArray_TYPE(na)==NPY_DOUBLE) {
-      set_pos2_nc_t<double,O>(e,alist,na);
-    } else {
-      throw Error("expected a numpy array of type float or double");
-      return;
-    }
-#endif
-  }
-}
-#endif
 
 void set_pos(XCSEditor& e, object o1, object o2, bool trans)
 {
@@ -174,50 +94,7 @@ void set_pos(XCSEditor& e, object o1, object o2, bool trans)
     }
     return;
   }
-
-#if OST_NUMPY_SUPPORT_ENABLED
-
-  extract<AtomHandleList> eal(o1);
-  if(eal.check()) {
-    if(trans) {
-      set_pos2_t<false>(e,eal(),o2);
-    } else {
-      set_pos2_t<true>(e,eal(),o2);
-    }
-    return;
-  }
-
-  std::map<unsigned long,AtomHandle> amap;
-  impl::EntityImplPtr ei=e.GetEntity().Impl();
-  for(impl::ChainImplList::iterator cit=ei->GetChainList().begin();
-      cit!=ei->GetChainList().end();++cit) {
-    for (impl::ResidueImplList::iterator rit = (*cit)->GetResidueList().begin(),
-         ret = (*cit)->GetResidueList().end(); rit != ret; ++rit) {
-           
-      for (impl::AtomImplList::iterator ait = (*rit)->GetAtomList().begin(), 
-           aet = (*rit)->GetAtomList().end(); ait != aet; ++ait) {
-
-        amap[(*ait)->GetIndex()]=*ait;
-      }
-    }
-  }
-
-  AtomHandleList alist;
-  for(int i=0;i<len(o1);++i) {
-    int gid = extract<int>(o1[i]);
-    std::map<unsigned long,AtomHandle>::iterator ait=amap.find(static_cast<unsigned long>(gid));
-    alist.push_back(ait==amap.end() ? AtomHandle() : ait->second);
-  }
-
-  if(trans) {
-    set_pos2_t<false>(e,alist,o2);
-  } else {
-    set_pos2_t<true>(e,alist,o2);
-  }
-
-#else
   throw Error("SetAtom*Pos(...,ndarray) not available, because numpy support not compiled in");
-#endif
 }
 
 void set_o_pos(XCSEditor& e, object o1, object o2)
@@ -234,14 +111,6 @@ void set_t_pos(XCSEditor& e, object o1, object o2)
 
 void export_Editors()
 {
-#if OST_NUMPY_SUPPORT_ENABLED
-  // The following define enforces no return value when calling import_array
-  #undef NUMPY_IMPORT_ARRAY_RETVAL
-  #define NUMPY_IMPORT_ARRAY_RETVAL
-  import_array();
-#endif
-
-
   class_<EditorBase>("EditorBase", no_init)
     .def("InsertChain", insert_chain_a)
     .def("InsertChain", insert_chain_b,(arg("chain_name"),arg("chain"), arg("deep")=false))
diff --git a/modules/mol/base/pymod/export_entity.cc b/modules/mol/base/pymod/export_entity.cc
index bd2e97248..b12feb7bc 100644
--- a/modules/mol/base/pymod/export_entity.cc
+++ b/modules/mol/base/pymod/export_entity.cc
@@ -35,18 +35,6 @@ using namespace ost::mol;
 
 #include <ost/export_helper/generic_property_def.hh>
 
-/* Including NumPy headers produces compiler warnings. The ones about "Using
-   deprecated NumPy API..." we can not get rid of. The highest NumPy version we
-   support is 1.6 while the non-deprecated API starts with version 1.7.
-   Also see the comment in modules/gfx/pymod/export_primlist.cc for further
-   information.
-*/
-#if OST_NUMPY_SUPPORT_ENABLED
-#include <numpy/numpyconfig.h>
-#define NPY_NO_DEPRECATED_API NPY_1_6_API_VERSION
-#include <numpy/arrayobject.h>
-#endif
-
 namespace {
 EntityHandle create1() {  return CreateEntity(); }
 
@@ -76,53 +64,6 @@ ICSEditor depr_request_ics_editor(EntityHandle e, EditMode m)
   return e.EditICS(m);
 }
 
-
-#if OST_NUMPY_SUPPORT_ENABLED
-
-bool less_index(const mol::AtomHandle& a1, const mol::AtomHandle& a2)
-{
-  return a1.GetIndex()<a2.GetIndex();
-}
-PyObject* get_pos2(EntityHandle& entity, bool id_sorted)
-{
-  npy_intp dims[]={entity.GetAtomCount(),3};
-  PyObject* na = PyArray_SimpleNew(2,dims,NPY_FLOAT);
-  npy_float* nad = reinterpret_cast<npy_float*>(PyArray_DATA(na));
-  if(id_sorted) {
-    AtomHandleList alist = entity.GetAtomList();
-    std::sort(alist.begin(),alist.end(),less_index);
-    for(AtomHandleList::const_iterator it=alist.begin();it!=alist.end();++it,nad+=3) {
-      geom::Vec3 pos=(*it).GetPos();
-      nad[0]=static_cast<npy_float>(pos[0]);
-      nad[1]=static_cast<npy_float>(pos[1]);
-      nad[2]=static_cast<npy_float>(pos[2]);
-    }
-  } else {
-    impl::EntityImplPtr ei=entity.Impl();
-    for(impl::ChainImplList::iterator cit=ei->GetChainList().begin();
-        cit!=ei->GetChainList().end();++cit) {
-      for (impl::ResidueImplList::iterator rit = (*cit)->GetResidueList().begin(),
-          ret = (*cit)->GetResidueList().end(); rit != ret; ++rit) {
-            
-        for (impl::AtomImplList::iterator ait = (*rit)->GetAtomList().begin(), 
-            aet = (*rit)->GetAtomList().end(); ait != aet; ++ait, nad+=3) {
-
-          geom::Vec3 pos=(*ait)->TransformedPos();
-          nad[0]=static_cast<npy_float>(pos[0]);
-          nad[1]=static_cast<npy_float>(pos[1]);
-          nad[2]=static_cast<npy_float>(pos[2]);
-    }}}
-  }
-  return na;
-}
-
-PyObject* get_pos1(EntityHandle& entity)
-{
-  return get_pos2(entity,true);
-}
-
-#endif
-
 geom::Mat4 depr_get_transformation_matrix(const EntityHandle& eh)
 {
   return eh.GetTransformationMatrix();
@@ -137,13 +78,6 @@ bool depr_is_transformation_identity(const EntityHandle& eh)
 
 void export_Entity()
 {
-#if OST_NUMPY_SUPPORT_ENABLED
-  // The following define enforces no return value when calling import_array
-  #undef NUMPY_IMPORT_ARRAY_RETVAL
-  #define NUMPY_IMPORT_ARRAY_RETVAL
-  import_array();
-#endif
-
   class_<EntityBase> ent_base("EntityBase", no_init);
   ent_base
     .def(self_ns::str(self))
@@ -229,11 +163,6 @@ void export_Entity()
     .def("GetHashCode", &EntityHandle::GetHashCode) 
     .def(self==self)
     .def(self!=self)
-#if OST_NUMPY_SUPPORT_ENABLED
-    .def("GetPositions",get_pos1)
-    .def("GetPositions",get_pos2)
-    .add_property("positions",get_pos1)
-#endif
   ;
 
   def("CreateEntity",create1);
diff --git a/modules/mol/base/tests/CMakeLists.txt b/modules/mol/base/tests/CMakeLists.txt
index 591eadd86..8a97c347e 100644
--- a/modules/mol/base/tests/CMakeLists.txt
+++ b/modules/mol/base/tests/CMakeLists.txt
@@ -17,10 +17,6 @@ set(OST_MOL_BASE_UNIT_TESTS
   test_invalid.py
 )
 
-if (USE_NUMPY)
-  list(APPEND OST_MOL_BASE_UNIT_TESTS test_numpy.py)
-endif (USE_NUMPY)
-
 ost_unittest(MODULE mol SOURCES "${OST_MOL_BASE_UNIT_TESTS}")
 
 # for valgrind debugging
diff --git a/modules/mol/base/tests/test_numpy.py b/modules/mol/base/tests/test_numpy.py
deleted file mode 100644
index fb69b9afe..000000000
--- a/modules/mol/base/tests/test_numpy.py
+++ /dev/null
@@ -1,75 +0,0 @@
-import unittest
-if __name__== '__main__':
-  import sys
-  sys.path.insert(0,"../../../../stage/lib64/openstructure/")
-  sys.path.insert(0,"../../../../stage/lib/openstructure/")
-  
-import ost
-from ost import geom, mol
-
-if ost.WITH_NUMPY:
-  has_numpy=True
-  try:
-    import numpy
-  except ImportError as e:
-    has_numpy=False
-else:
-  has_numpy=False
-
-def v2v(v):
-  return geom.Vec3(float(v[0]),float(v[1]),float(v[2]))
-
-def dd(v1,v2):
-  return geom.Distance(v1,v2)<1e-8
-
-class TestNumpy(unittest.TestCase):
-  def setUp(self):
-    pass
-
-  def test_(self):
-    if not has_numpy:
-      return
-    entity=mol.CreateEntity()
-    ed=entity.EditXCS()
-    ch=ed.InsertChain("X")
-    re=ed.AppendResidue(ch,"ALA")
-    a0=ed.InsertAtom(re,"A",geom.Vec3(0,0,0))
-    self.assertEqual(a0.GetIndex(),0)
-    a1=ed.InsertAtom(re,"B",geom.Vec3(1,0,0))
-    self.assertEqual(a1.GetIndex(),1)
-    a2=ed.InsertAtom(re,"C",geom.Vec3(2,0,0))
-    self.assertEqual(a2.GetIndex(),2)
-    a3=ed.InsertAtom(re,"D",geom.Vec3(3,0,0))
-    self.assertEqual(a3.GetIndex(),3)
-
-    self.assertTrue(dd(a0.pos,geom.Vec3(0,0,0)))
-    self.assertTrue(dd(a1.pos,geom.Vec3(1,0,0)))
-    self.assertTrue(dd(a2.pos,geom.Vec3(2,0,0)))
-    self.assertTrue(dd(a3.pos,geom.Vec3(3,0,0)))
-
-    ed.SetAtomTransformedPos(entity.GetAtomList(),
-                             numpy.array([[0,1,0],[0,2,0],[0,3,0],[0,4,0]], dtype=numpy.float32))
-
-    self.assertTrue(dd(a0.pos,geom.Vec3(0,1,0)))
-    self.assertTrue(dd(a1.pos,geom.Vec3(0,2,0)))
-    self.assertTrue(dd(a2.pos,geom.Vec3(0,3,0)))
-    self.assertTrue(dd(a3.pos,geom.Vec3(0,4,0)))
-
-    na=entity.positions
-
-    self.assertTrue(dd(v2v(na[0]),geom.Vec3(0,1,0)))
-    self.assertTrue(dd(v2v(na[1]),geom.Vec3(0,2,0)))
-    self.assertTrue(dd(v2v(na[2]),geom.Vec3(0,3,0)))
-    self.assertTrue(dd(v2v(na[3]),geom.Vec3(0,4,0)))
-
-    ed.SetAtomTransformedPos([3,99,2],
-                             numpy.array([[0,0,-3],[-1,-1,-1],[0,0,-2]], dtype=numpy.float32))
-
-    self.assertTrue(dd(a0.pos,geom.Vec3(0,1,0)))
-    self.assertTrue(dd(a1.pos,geom.Vec3(0,2,0)))
-    self.assertTrue(dd(a2.pos,geom.Vec3(0,0,-2)))
-    self.assertTrue(dd(a3.pos,geom.Vec3(0,0,-3)))
-
-if __name__== '__main__':
-    unittest.main()
-
diff --git a/scripts/ost-nightly-build.sh b/scripts/ost-nightly-build.sh
index 653b9142a..4b6fbab30 100644
--- a/scripts/ost-nightly-build.sh
+++ b/scripts/ost-nightly-build.sh
@@ -134,7 +134,6 @@ dependencies = [
     ('FFTW', '3.3.3', '-dynamic', ('gompi', '1.4.10')), 
 ]
 
-configopts = " -DOPTIMIZE=1 -DCOMPILE_TMTOOLS=1 -DENABLE_GFX=OFF -DENABLE_GUI=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS_RELEASE='-O3 -DNDEBUG -Wno-unused-local-typedefs' -DUSE_NUMPY=1 -DUSE_RPATH=1"
 
 configopts += " -DCOMPOUND_LIB=/scicore/home/schwede/GROUP/OpenStructure/ChemLib/1.6/compounds.chemlib"
 
-- 
GitLab